mirror of
https://github.com/0xrsydn/idx-cli.git
synced 2026-11-07 09:45:36 +00:00
fix(core): reject broker and trading pages that would misreport a session
From the 0.4.0 release review (Codex): - IPOT pages with a short row, a rank out of order or a broker after a blank row are parse errors; skipping a row shifted later brokers up a rank and could flip a bandar reading (-2425 bps to -66 bps). - A tbody end before its start is a parse error, not a panic. - An IPOT page that echoes other dates than requested is rejected before it is cached, so one session's figures never pass as another's. - An IDX trading summary with rows for other days only is an error, not an empty session cached for 30 days. - Empty sessions count toward a flow's fetched_at and stale. - The bandar imbalance uses checked i128 arithmetic: past i128 there is no reading instead of a wrapped one. - The bandar table prints "No trades." only when no broker traded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
This commit is contained in:
parent
8b507d78e2
commit
d82f7c6be9
6 changed files with 137 additions and 19 deletions
|
|
@ -114,7 +114,11 @@ impl Broker<'_> {
|
|||
source: SOURCE,
|
||||
},
|
||||
policy,
|
||||
|| provider.broker_summary(&code, query),
|
||||
|| {
|
||||
provider
|
||||
.broker_summary(&code, query)
|
||||
.and_then(|raw| check_echoed_dates(query, raw))
|
||||
},
|
||||
|raw| Ok(summary_from_raw(&resolved, query, raw)),
|
||||
)
|
||||
}
|
||||
|
|
@ -207,6 +211,25 @@ pub(crate) fn summary_from_raw(
|
|||
summary
|
||||
}
|
||||
|
||||
/// The page echoes the dates it covers; another range's figures must not be
|
||||
/// cached or reported as the requested one's.
|
||||
fn check_echoed_dates(
|
||||
query: &BrokerQuery,
|
||||
raw: BrokerSummaryRaw,
|
||||
) -> Result<BrokerSummaryRaw, IdxError> {
|
||||
if raw.from == Some(query.from) && raw.to == Some(query.to) {
|
||||
return Ok(raw);
|
||||
}
|
||||
let echoed = |date: Option<NaiveDate>| date.map_or("none".to_string(), |date| date.to_string());
|
||||
Err(IdxError::ParseError(format!(
|
||||
"ipot broker summary: asked for {} to {}, the page covers {} to {}",
|
||||
query.from,
|
||||
query.to,
|
||||
echoed(raw.from),
|
||||
echoed(raw.to)
|
||||
)))
|
||||
}
|
||||
|
||||
fn check_range(query: &BrokerQuery, today: NaiveDate) -> Result<(), IdxError> {
|
||||
if query.from > query.to {
|
||||
return Err(IdxError::InvalidInput(format!(
|
||||
|
|
@ -381,4 +404,29 @@ mod tests {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check_echoed_dates_rejects_another_sessions_page() {
|
||||
let friday = date(2026, 10, 16);
|
||||
let page = || BrokerSummaryRaw {
|
||||
from: Some(friday),
|
||||
to: Some(friday),
|
||||
..BrokerSummaryRaw::default()
|
||||
};
|
||||
assert!(check_echoed_dates(&query(friday, friday), page()).is_ok());
|
||||
let thursday = date(2026, 10, 15);
|
||||
for (asked, raw) in [
|
||||
(query(thursday, thursday), page()),
|
||||
(query(thursday, friday), page()),
|
||||
(query(friday, friday), BrokerSummaryRaw::default()),
|
||||
] {
|
||||
assert!(
|
||||
matches!(
|
||||
check_echoed_dates(&asked, raw),
|
||||
Err(IdxError::ParseError(_))
|
||||
),
|
||||
"{asked:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue