From 8f5c56e464ad5be1bd21d62229a8bedaf506aefb Mon Sep 17 00:00:00 2001 From: 0xrsydn Date: Wed, 4 Nov 2026 20:44:51 +0700 Subject: [PATCH] fix(movements): allow the movements path, and describe its one cache entry - The session client's new read-path allowlist (#78) gains `/insider/company/majorholder?`, the one endpoint movements reads; without it every live movements query would fail before leaving the process. The mock does not go through the client, so its tests could not show this. - docs/ARCHITECTURE.md described one cache entry per page: a query's pages are read and cached together, keyed by the page count, and a failed later page returns the rows before it with `incomplete` (Pullfrog on #80). Claude-Session: https://claude.ai/code/session_01RqPPVeVDrnLoP7NUZmLRxY --- crates/idx-core/src/api/stockbit/exodus.rs | 9 ++++++++- docs/ARCHITECTURE.md | 10 ++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/crates/idx-core/src/api/stockbit/exodus.rs b/crates/idx-core/src/api/stockbit/exodus.rs index 3d832b9..8948347 100644 --- a/crates/idx-core/src/api/stockbit/exodus.rs +++ b/crates/idx-core/src/api/stockbit/exodus.rs @@ -39,7 +39,12 @@ const REFRESH_PATH: &str = "/login/refresh"; /// withdraws cash and changes the PIN; a path outside these fails before any /// request (or token refresh) leaves the process. A feature that reads a new /// endpoint adds its prefix here. -const READ_PATHS: &[&str] = &["/company-price-feed/", "/charts/", "/corpaction/"]; +const READ_PATHS: &[&str] = &[ + "/company-price-feed/", + "/charts/", + "/corpaction/", + "/insider/company/majorholder?", +]; /// The prefix of the states in which the regular market trades: /// `STATE_NAME_SESSION_2` was recorded on 2026-11-03 from 13:30; session 1 is /// assumed to follow the same naming. Every other state (`STATE_NAME_BREAK`, @@ -525,6 +530,7 @@ mod tests { "/company-price-feed/v2/orderbook/companies/BBCA", "/charts/BBCA/daily?timeframe=1y&chart_type=PRICE_CHART_TYPE_CANDLE", "/corpaction/dividend?symbol=BBCA", + "/insider/company/majorholder?page=1&symbol=BBCA", ] { assert!(is_read_path(path), "{path}"); } @@ -532,6 +538,7 @@ mod tests { "/order/buy", "/login/refresh", "/corpaction/../order/buy", + "/insider/company/majorholder/../../order", "/charts", "", ] { diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index e724e59..edfd44a 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -304,10 +304,12 @@ WIB as the fallback. - Shareholder movements (`movements`, `api/stockbit/movement.rs`) read `/insider/company/majorholder`: IDX insider disclosures and KSEI 5% holder changes, 50 rows a page, filtered by Stockbit (`symbol`, `date_start`, - `date_end`, `insider` (holder id), `action_type`, `source_type`). Each page - is cached an hour under `stockbit-movements`, keyed by every filter and the - page. `ownership movements` and `get_shareholder_movements` read up to 10 - pages; the KSEI register in SQLite is not involved. + `date_end`, `insider` (holder id), `action_type`, `source_type`). + `ownership movements` and `get_shareholder_movements` read up to 10 pages + as one answer, cached an hour under `stockbit-movements`, keyed by every + filter and the page count. If a page after the first fails, the rows read + before it come back with `incomplete` set and nothing is cached. The KSEI + register in SQLite is not involved. ### Capability Gating ```