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
This commit is contained in:
Rasyidan Akbar F. 2026-11-04 20:44:51 +07:00
commit 8f5c56e464
2 changed files with 14 additions and 5 deletions

View file

@ -39,7 +39,12 @@ const REFRESH_PATH: &str = "/login/refresh";
/// withdraws cash and changes the PIN; a path outside these fails before any /// 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 /// request (or token refresh) leaves the process. A feature that reads a new
/// endpoint adds its prefix here. /// 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: /// 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 /// `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`, /// 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", "/company-price-feed/v2/orderbook/companies/BBCA",
"/charts/BBCA/daily?timeframe=1y&chart_type=PRICE_CHART_TYPE_CANDLE", "/charts/BBCA/daily?timeframe=1y&chart_type=PRICE_CHART_TYPE_CANDLE",
"/corpaction/dividend?symbol=BBCA", "/corpaction/dividend?symbol=BBCA",
"/insider/company/majorholder?page=1&symbol=BBCA",
] { ] {
assert!(is_read_path(path), "{path}"); assert!(is_read_path(path), "{path}");
} }
@ -532,6 +538,7 @@ mod tests {
"/order/buy", "/order/buy",
"/login/refresh", "/login/refresh",
"/corpaction/../order/buy", "/corpaction/../order/buy",
"/insider/company/majorholder/../../order",
"/charts", "/charts",
"", "",
] { ] {

View file

@ -304,10 +304,12 @@ WIB as the fallback.
- Shareholder movements (`movements`, `api/stockbit/movement.rs`) read - Shareholder movements (`movements`, `api/stockbit/movement.rs`) read
`/insider/company/majorholder`: IDX insider disclosures and KSEI 5% holder `/insider/company/majorholder`: IDX insider disclosures and KSEI 5% holder
changes, 50 rows a page, filtered by Stockbit (`symbol`, `date_start`, changes, 50 rows a page, filtered by Stockbit (`symbol`, `date_start`,
`date_end`, `insider` (holder id), `action_type`, `source_type`). Each page `date_end`, `insider` (holder id), `action_type`, `source_type`).
is cached an hour under `stockbit-movements`, keyed by every filter and the `ownership movements` and `get_shareholder_movements` read up to 10 pages
page. `ownership movements` and `get_shareholder_movements` read up to 10 as one answer, cached an hour under `stockbit-movements`, keyed by every
pages; the KSEI register in SQLite is not involved. 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 ### Capability Gating
``` ```