Add --bucket time-series to summary and compare
Summary
Adds --bucket <DURATION> to the read verbs that take --since, turning a single windowed total into a time-series: the verb's report computed per fixed-width time bucket. Built for a live spend chart that needs selectable ranges (last 5m / 1h / 12h / 1d / 7d) sourced from one indexed query rather than N client-side round-trips.
JSON shape (both verbs): { "bucketSeconds": N, "buckets": [ { "start": ISO, "end": ISO, ...the verb's normal report... } ] }.
What's included
- Shared primitive (
query_verbs/mod.rs):parse_bucket(grammar30s/5m/1h/12h/1d/7d),iso_z_to_epoch_secs, and aBucketspartition anchored on the normalized--since(or the earliest turn), with aMAX_BUCKETSguard. Reuses the existing fetch (query_turns+idx_turns_ts),cost_for_turn,load_pricing, andprovider_for. - summary:
summary_timeseries— turn-level partition (the grouped model/provider/tag path is a pure per-turn fold). Rejected with a clear error for the--by-tool/subagent/relationship attribution modes. - compare:
compare_timeseries— per-bucket compare table. - CLI:
--bucketonsummaryandcompare; JSON emits the series, human output prints a per-bucket line. - Tests (5): parser grammar, ISO↔epoch round-trip,
Bucketsedges/indices,summary_timeseriesplacement reconciling exactly to the un-bucketed total, attribution-mode rejection.
Note: m = minutes for --bucket
--since treats m as month, but month-sized buckets are meaningless and the consumer wants minute buckets ("last 5 minutes"). So --bucket uses m = minutes and adds s = seconds. Documented in the flag help and code.
Deferred: hotspots / overhead
Both also take --since, but their aggregation isn't a pure per-turn fold — hotspots attributes turn N's cost to turn N−1's tool_use (ordering/cross-turn + session-scoped side queries) and overhead computes window-amortized per-session denominators (and does filesystem work). Correct bucketing for these needs session-granular partitioning (assign whole sessions to a bucket by earliest ts). Rather than ship incorrect attribution, --bucket is simply absent on those two; it's a clean follow-up.
Verification
cargo build --workspace ✅ · cargo test --workspace ✅ (all suites pass; 5 new). Smoke vs a real ledger: summary --provider anthropic --since 1h --bucket 5m --json → bucketSeconds=300, 12 buckets, and bucket-sum tokens == the plain --since 1h total exactly.
🤖 Generated with Claude Code