refactor: split into idx-core library and idx-cli binary workspace

Phase 2 of docs/DESIGN.md, no behavior change:

- crates/idx-core (library): api, analysis, cache, config file handling
  and provider selection, curl_impersonate, error, ownership, runtime,
  plus the shared test fixtures. clap derives are behind an optional
  `clap` feature so the library does not require clap.
- crates/idx-cli (binary `idx`): cli/, output/, and IdxConfig (output
  format and color resolution). Package and binary names are unchanged.
- config.rs is split: file read/write and validation move to core; a
  CLI test keeps core's OUTPUT_VALUES in sync with OutputSetting.
- ownership::db::open_db/db_path drop their unused IdxConfig argument.
- One workspace version; shared dependency versions; no third-party
  version changes in Cargo.lock. LICENSE is symlinked into each crate.
- flake: workspace version, new source paths, and a per-crate package
  check (idx-cli is built from its tarball against packaged idx-core,
  since idx-core is not on crates.io yet). CI cache key, release path
  filter, and the golden whitespace-hook exclusion follow the new layout.

Parity: all 143 golden outputs match byte for byte without
regeneration; 157 core + 17 CLI unit tests (173 before plus the new
OUTPUT_VALUES sync test), 62 CLI tests pass. Live A/B against main:
16/16 stocks cases identical; ownership discover got IDX 403 on both
(exit 4 vs 1 is the phase 1 exit-code change).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
hermes 2026-10-14 09:13:46 +00:00
commit 15947de51a
238 changed files with 544 additions and 375 deletions

View file

@ -1,10 +1,25 @@
# Architecture
## Crates
The repo is a Cargo workspace with one shared version:
- `crates/idx-core` (library): providers (`api/`), `analysis/`, `cache`, config
file handling and provider selection (`config`), `ownership/` (SQLite, parsers,
discovery, snapshot sync), `error`, and `runtime` (quiet/info/warn). It owns the
shared test fixtures in `tests/fixtures/`.
- `crates/idx-cli` (binary `idx`): clap commands (`cli/`), output format and
color resolution (`config.rs`, `IdxConfig`), and rendering (`output/`). Its
`tests/` hold the CLI integration and golden output suites.
Some fetch/cache orchestration still lives in `crates/idx-cli/src/cli/` until
phase 3 of `docs/DESIGN.md` moves it into idx-core.
## Domain Map
```
┌─────────────────────────────────────────────────────────┐
│ CLI Layer │
│ CLI Layer (idx-cli) │
│ main.rs → cli/stocks.rs, cli/ownership.rs, cli/... │
│ Clap derive structs, command dispatch, arg validation │
└──────────────────────┬──────────────────────────────────┘
@ -39,7 +54,7 @@
sentiment, screener
- `https://api.msn.com/msn/v0/pages/finance/`: key ratios, insights, news feed
The public API key embedded in MSN Money lives in `src/api/msn/client.rs`.
The public API key embedded in MSN Money lives in `crates/idx-core/src/api/msn/client.rs`.
### Hybrid History Strategy
When `history_provider = auto` (default):
@ -89,7 +104,7 @@ Unlike the `stocks` module (live-fetch), ownership is **import-then-query**:
- **KSEI** — official ≥1% shareholder registry, published monthly by IDX. Through May 2026 it was a PDF announcement; from the 2026-05-29 report onward it is an XLSX workbook on the IDX "Data Kepemilikan Saham" page
- **KSEI archive** — monthly ZIP/TXT balance-position matrix, used as a local fallback/backstop import path
- **Bing Finance** — global institutional ownership. The schema, `--source bing`
queries, and `src/api/msn/bing.rs` exist, but `ownership import --fetch-bing`
queries, and `crates/idx-core/src/api/msn/bing.rs` exist, but `ownership import --fetch-bing`
is intentionally unsupported, so no ingest path populates Bing rows today
### Discovery

View file

@ -1,6 +1,6 @@
# System Design: idx-core and its frontends
**Status:** Accepted 2026-10-14. Implementation on `refactor/idx-core`; phases 0-1 done.
**Status:** Accepted 2026-10-14. Implementation on `refactor/idx-core`; phases 0-2 done.
## Goal
@ -99,7 +99,7 @@ Key decisions:
- **Typed inputs.** Screener filters, regions, statement and earnings filters
become enums with `FromStr`, so validation is identical across frontends.
## What Moves Out of `src/cli/`
## What Moves Out of `crates/idx-cli/src/cli/`
| From | To |
| --- | --- |