From 96a900e0b883e034707cf36ddddaaf7b1310a06e Mon Sep 17 00:00:00 2001 From: 0xrsydn Date: Wed, 4 Nov 2026 21:04:24 +0700 Subject: [PATCH 1/2] fix(calendar): say when the table holds offers opened before --from Open offers are listed by the day they opened, so "from 2026-11-03 to 2026-11-12" sat above tenders dated in October (Pullfrog on #78). The title adds "with offers opened earlier and still open" when such rows are there. Claude-Session: https://claude.ai/code/session_01RqPPVeVDrnLoP7NUZmLRxY --- crates/idx-cli/src/output/table.rs | 10 +++++++++- .../tests/golden/stockbit-calendar.table.golden | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/crates/idx-cli/src/output/table.rs b/crates/idx-cli/src/output/table.rs index 45ecc93..945f731 100644 --- a/crates/idx-cli/src/output/table.rs +++ b/crates/idx-cli/src/output/table.rs @@ -1864,10 +1864,18 @@ pub fn print_corporate_calendar( range: &CalendarRange, actions: &[CorporateAction], ) -> Result<(), IdxError> { + // Offers still open are listed by the day they opened, which can be + // before `from`; the title says so rather than claim the range bounds + // every row. + let earlier = if actions.iter().any(|a| a.date < range.from) { + ", with offers opened earlier and still open" + } else { + "" + }; println!( "{}", format!( - "Corporate actions from {} to {} ({})", + "Corporate actions from {} to {}{earlier} ({})", range.from, range.to, actions.len() diff --git a/crates/idx-cli/tests/golden/stockbit-calendar.table.golden b/crates/idx-cli/tests/golden/stockbit-calendar.table.golden index 9ddb54e..7376ced 100644 --- a/crates/idx-cli/tests/golden/stockbit-calendar.table.golden +++ b/crates/idx-cli/tests/golden/stockbit-calendar.table.golden @@ -1,6 +1,6 @@ exit: 0 --- stdout -Corporate actions from 2026-11-03 to 2026-11-12 (17) +Corporate actions from 2026-11-03 to 2026-11-12, with offers opened earlier and still open (17) ┌────────────┬────────┬──────────────┬────────────┬──────────────────────────────────────────────────────────────────────────┐ │ DATE ┆ SYMBOL ┆ KIND ┆ EX ┆ DETAIL │ ╞════════════╪════════╪══════════════╪════════════╪══════════════════════════════════════════════════════════════════════════╡ From 9373be222a35e16998b39f16fb2bc698376830c5 Mon Sep 17 00:00:00 2001 From: 0xrsydn Date: Wed, 4 Nov 2026 21:05:01 +0700 Subject: [PATCH 2/2] test(movements): check the allowlist against the real movements path builder The read-path test listed a hand-written movements path; it now also builds paths with movement::request_path, so the test fails offline if the allowlist and the builder drift apart (Pullfrog on #80). Claude-Session: https://claude.ai/code/session_01RqPPVeVDrnLoP7NUZmLRxY --- crates/idx-core/src/api/stockbit/exodus.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/crates/idx-core/src/api/stockbit/exodus.rs b/crates/idx-core/src/api/stockbit/exodus.rs index 8948347..8e3e60b 100644 --- a/crates/idx-core/src/api/stockbit/exodus.rs +++ b/crates/idx-core/src/api/stockbit/exodus.rs @@ -534,6 +534,15 @@ mod tests { ] { assert!(is_read_path(path), "{path}"); } + // Paths another module builds come from its own builder, so the + // allowlist cannot drift from them. + let query = MovementQuery::default(); + for path in [ + movement::request_path(&query, None, 1), + movement::request_path(&query, Some("BBCA"), 3), + ] { + assert!(is_read_path(&path), "{path}"); + } for path in [ "/order/buy", "/login/refresh",