feat(ownership): complete ownership intelligence module

Sprints 0-8: Types, schema, KSEI parser, entity resolution, DB CRUD,
Bing API client, import pipeline, query commands, graph traversal,
changes diff, entity resolution CLI, FTS5 search.

- KSEI PDF parser (mutool stext + quick-xml, 99.2% accuracy)
- 7 query commands: ticker, entity, search, cross-holders, concentration, flow, releases
- Ownership graph with recursive CTE (ASCII tree + Graphviz DOT)
- Release diff/changes between KSEI snapshots
- Entity resolution CLI: unresolved, map, merge
- FTS5 trigram search on entity names
- Feature-gated under 'ownership' (default-on)
- 82 tests passing
This commit is contained in:
Ciphercat 2026-03-07 17:31:04 +00:00
commit 6671e22976
23 changed files with 5351 additions and 47 deletions

View file

@ -1,78 +1,78 @@
# AGENTS.md
## Project
`idx-cli` — CLI tool for Indonesian stock market (IDX) analysis. Built in Rust for humans and AI agents. Single binary, zero runtime deps.
`idx-cli` — CLI tool for Indonesian stock market (IDX) analysis. Built in Rust for humans and AI agents. Single binary, schema-driven, functional architecture.
## Stack
- **Language:** Rust (stable, via rust-overlay)
- **CLI:** clap 4 (derive)
- **HTTP:** ureq 3 (sync, no async runtime)
- **Output:** comfy-table, owo-colors
- **DB:** rusqlite (bundled SQLite, FTS5) — ownership module
- **Config:** TOML (`~/.config/idx/config.toml`)
- **Cache:** JSON file-based (`~/.cache/idx/`)
- **Testing:** cargo nextest, assert_cmd, predicates
- **Testing:** cargo test, assert_cmd, predicates
- **Hooks:** prek (pre-commit: fmt+clippy, pre-push: test)
- **VCS:** jj (Jujutsu, colocated with git)
## Structure
```
src/
├── main.rs # Entry point, clap setup, command dispatch
├── cli/ # Command definitions (clap structs + handlers)
│ ├── stocks.rs # stocks quote, history commands
├── main.rs # Entry point, command dispatch
├── cli/ # Command handlers (clap derive structs)
│ ├── stocks.rs # stocks quote/history/technical/fundamental/...
│ ├── config.rs # config get/set/init/path
│ └── cache.rs # cache info/clear
├── api/ # Data provider abstraction + implementations
│ ├── mod.rs # MarketDataProvider trait
│ ├── yahoo.rs # Yahoo Finance provider (query2 endpoint)
│ └── types.rs # Quote, OHLC, Period, Interval types
├── output/ # Rendering layer (table, json)
│ ├── table.rs # comfy-table + owo-colors
│ └── json.rs # serde_json pretty print
├── api/ # Data providers (trait-based abstraction)
│ ├── mod.rs # MarketDataProvider trait + factory functions
│ ├── types.rs # All domain types (Quote, Ohlc, Fundamentals, ...)
│ ├── yahoo/ # Yahoo Finance provider (history/OHLCV)
│ └── msn/ # MSN Finance provider (quotes, fundamentals, ++)
├── analysis/ # Technical & fundamental analysis (pure functions)
├── ownership/ # Ownership intelligence module (SQLite-backed)
│ ├── types.rs # Ownership domain types
│ └── db.rs # Schema, migrations, queries
├── output/ # Rendering (table, json)
├── cache.rs # File-based TTL cache
├── config.rs # Config loading + merge (flags > env > file > defaults)
├── config.rs # Config loading (flags > env > file > defaults)
└── error.rs # IdxError enum (thiserror)
tests/
├── cli.rs # Integration tests (assert_cmd, mock provider)
docs-internal/ # (gitignored) Specs, research, business strategy
```
## Providers
- **MSN** = default provider (quotes, fundamentals, profile, earnings, financials, sentiment, insights, news, screener)
- **Yahoo** = automatic fallback for history/OHLCV (MSN doesn't support IDX history)
- Configurable: `IDX_PROVIDER=msn|yahoo`, `IDX_HISTORY_PROVIDER=auto|yahoo|msn`
## Development
```bash
# Enter dev shell (requires Nix + direnv)
direnv allow # or: nix develop
# Build
cargo build
# Run
cargo run -- stocks quote BBCA
cargo run -- -o json stocks quote BBCA,BBRI
cargo run -- stocks history BBCA --period 3mo
# Test
cargo nextest run # or: cargo test
# Lint
cargo fmt --check
cargo clippy -- -D warnings
nix develop # enter dev shell
cargo build # build
cargo run -- stocks quote BBCA # run
cargo run -- -o json stocks history BBCA # JSON output
cargo test # test
cargo fmt --check && cargo clippy -- -D warnings # lint
```
## Docs
- `docs-internal/SPEC.md` — system design, command tree, milestones (gitignored)
- `docs-internal/TODO.md` — task breakdown with checklist (gitignored)
- `docs-internal/OWNERSHIP_FEATURE_DESIGN.md` — ownership intelligence feature design (gitignored)
## Verification
```bash
cargo build # must compile
cargo clippy -- -D warnings # zero warnings
cargo nextest run # all tests pass
cargo test # all tests pass
```
Hooks enforce this: prek runs fmt+clippy on commit, tests on push.
## Rules
1. **Provider abstraction** — all data access goes through `MarketDataProvider` trait, never call Yahoo directly from commands
2. **Sync only** — no tokio/async, this is a CLI tool using ureq
3. **Test with fixtures** — never hit live APIs in tests, use mock provider + fixture JSON
4. **Output contract** — table mode to stdout for humans, `--json` for machines, errors to stderr
5. **Symbol resolution** — always normalize symbols (`BBCA``BBCA.JK`) before API calls
## Principles
1. **Schema-driven** — define types first, build logic around them. Types are the spec.
2. **Functional approach** — pure parse/transform functions (`parse_*`, `normalize_*`), no hidden state.
3. **Data types heavy** — rich enums, newtypes, composite structs. Precision via integer representations (basis points for %, i64 for shares).
4. **Provider abstraction** — all data access through traits, never call Yahoo/MSN directly from commands.
5. **Sync only** — no tokio/async. CLI tool, ureq is sufficient.
6. **Test with fixtures** — never hit live APIs in tests. Mock provider + fixture JSON.
7. **Output contract** — table to stdout (humans), `--output json` (machines), errors to stderr.
8. **Feature-gated modules**`ownership` feature for SQLite dep, keeps base binary lean.
## Docs
Detailed specs live in `docs-internal/` (gitignored — internal strategy):
- `docs-internal/SPEC.md` — system design, command tree, milestones
- `docs-internal/TODO.md` — sprint breakdown
- `docs-internal/ownership/SPEC.md` — ownership module architecture
- `docs-internal/ownership/TODO.md` — ownership sprint plan