Cost modes: reconcile displayed cost with the source's own reported cost (auto/calculate/display)
Motivation
CodeBurn derives every cost from tokens times model pricing. But several sources write their own cost into the log, and where they do, we currently ignore it, so our headline can disagree with what the user sees in the tool itself.
- Claude Code writes a per-message
costUSD;claude.tsnever reads it and computes instead. - crush, codewhale, openclaw, the sqlite-based sources, cline and session-message already read a reported cost, but only as a zero-fallback (used only when our computed value is 0).
There is no way for a user to say "trust the source's own number" or "always recompute", and no provenance in the output distinguishing a computed cost from a reported one. This adds an explicit cost mode, so the displayed number can match the source of truth when one exists.
Semantics
A --cost-mode selector, mirrored in config and JSON:
calculate- always compute from tokens times pricing (today's behaviour).display- prefer the source's own reported cost where the log carries one; a source with no reported cost is shown as a computed estimate, never a silent 0.auto(default) - use the reported cost when it is present AND the source is on the known-reliable list, otherwise compute. Conservative: numbers only move where we have a trustworthy reported cost.
Non-goals (be honest)
- This does NOT fix the assumed-model divergence for sources that carry no cost field (Cursor computes against an assumed model and its data has no dollar figure to read). That is a separate discovery and pricing accuracy track.
- No new network calls. Reconciliation against a billing API is out of scope here (it overlaps #725 Part 5).
Architecture
Cost is baked in at parse time and stored in the daily cache, so the mode has to be applied at read time, which means storing both numbers.
- Add
reportedCostUsd?: numberto the parsed-call type, distinct from the computedcostUSD. Populate it in the sources that read a reported cost (promote the existing zero-fallback reads to always capture it) and add Claude Code's per-messagecostUSD. - Carry both computed and reported cost through the daily rollup (
day-aggregator), which is aDAILY_CACHE_VERSIONbump (16 -> 17) riding the existing carry-forward so old days are preserved, not dropped. Same discipline as the recent structural-discovery bump. - One shared read-time selector applies the mode when a report is rendered, so the CLI, TUI, JSON and menubar can never disagree about which number they show.
- Provenance: mark reported vs computed in the output (extend the existing estimated-cost signal), and in
--jsonemit the selectedcostUSDpluscomputedCostUsd,reportedCostUsd, andcostModeso downstream tools can reconcile. --cost-mode <auto|calculate|display>on the reporting commands, plus a persisted default in config.
Scope and phasing
- Phase 1 (first PR): the
reportedCostUsdfield and its capture in the sources that carry a cost plus Claude Code; the daily-cache schema bump and carry-forward; the read-time selector;--cost-modeon the core CLI and--jsonwithauto(conservative) as the default; provenance in JSON and the TUI; tests and an adversarial pass on the money path. - Follow-ups: menubar and web toggle; per-source reliability tuning; billing reconciliation (with #725 Part 5).
Evidence gate
Money path, so: conservation holds under every mode; a computed number is never rendered as reported nor the reverse; the cache bump is lossless (carry-forward pinned by a test); the mode selector is mutation-verified; adversarial review before merge.
Source: getagentseal/codeburn