fix(core): version the broker summary cache bucket

The cache stores normalized summaries, so one written before buy_value and
sell_value existed read back without them: bandar gave null readings (the
table said "No trades.") for a week, and an investor-filtered entry lacked
its totals. Summaries now cache under ipot-broker-v2, so an old-shape entry
is never served; offline it is a cache miss, online it is fetched again. A
CLI test seeds an old entry and checks both, in JSON and table output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
This commit is contained in:
hermes 2026-10-18 06:40:15 +00:00
commit b137dbf540
2 changed files with 73 additions and 2 deletions

View file

@ -15,6 +15,11 @@ use crate::error::IdxError;
use types::{BrokerBoard, BrokerInvestor, BrokerQuery, BrokerRange, BrokerSummary};
const SOURCE: &str = "ipot";
/// Cache bucket for normalized summaries, versioned with their shape: a
/// summary cached before `buy_value`/`sell_value` existed would read back
/// without them (and an investor-filtered one without its totals), so a new
/// shape gets a new bucket rather than serving such entries.
const CACHE_BUCKET: &str = "ipot-broker-v2";
/// Longest range one summary may cover.
pub const MAX_RANGE_DAYS: i64 = 366;
/// Calendar days searched back for the latest session with trades.
@ -98,7 +103,7 @@ impl Broker<'_> {
cached_fetch(
&self.idx.cache,
CacheSpec {
bucket: "ipot-broker",
bucket: CACHE_BUCKET,
key: &key,
ttl_secs: if query.to < today {
TTL_CLOSED_SECS
@ -146,7 +151,7 @@ impl Broker<'_> {
}
if policy == CachePolicy::Offline {
return Err(IdxError::CacheMiss(format!(
"ipot-broker/{resolved} (no cached session in the last {LATEST_LOOKBACK_DAYS} days)"
"{CACHE_BUCKET}/{resolved} (no cached session in the last {LATEST_LOOKBACK_DAYS} days)"
)));
}
Err(IdxError::NoMarketData(format!(