The trace does not price a run: join burnrate instead of rebuilding token accounting #198

Closed
opened 2026-08-16 17:16:05 +00:00 by john · 1 comment
Owner

The problem

.planning/trace.jsonl does not price a run, and it is the only thing
/cad-report and /cad-suggest read.

Measured on this repo, 2026-08-16: the trace recorded 795,845 tokens for the
whole v3.5.2 milestone across 6 dispatches. burnrate, reading the same day's
transcripts, recorded 16,261,487 billed-equivalent for the project on that
one day. Roughly 20x, and the gap is structural rather than a bug:

  • The trace records the figure on a subagent return only. The orchestrator
    contributes zero to it and 59% of actual spend (154,625,939 against the
    subagents' 105,743,431 over the last 7 days).
  • The trace has no cache fields at all. I checked every key across all 833
    events: no cache_read, no cache_creation, nothing. Cache-read is 62.5% of
    the real bill and the record cannot see any of it.
  • The trace has no window size and no turn count, which are the two terms
    that actually multiply out to the cost.

So /cad-suggest prices a configuration off a number that is wrong by an order
of magnitude and blind to the dominant term.

What burnrate already has

/data/code/burnrate parses every transcript ONCE into a per-message cache
(gzipped, under $XDG_CACHE_HOME/burnrate) and re-parses only changed sessions.
Per day x project x command x model x effort x main|agent it carries:

  • input, cache_write split 5m/1h, cache_read, output, message count
  • billed_equivalent = input + 1.25*cw5m + 2*cw1h + 0.10*cr
  • context footprint = input + cache_write + cache_read (the live window)
  • per-session peak_ctx, compactions, interrupts, agent counts
  • attribution by <command-name> and by "skill":"..." tool call, so
    cadence:cad-execute is already a first-class row

That is every quantity Cadence's own record is missing, keyed the way Cadence
would key it, and it exists.

The proposal

/cad-report and /cad-suggest read burnrate's cache for spend, and
trace.jsonl keeps what it is actually good at: WHAT happened (routing
decisions, gate fires, adjudications, brackets, outcomes). Two records, two
jobs, no reimplementation.

  • Cadence never becomes a token accountant. It joins one.
  • The join is read-only and degrades to today's behaviour when burnrate is
    absent, exactly like the recall backend degrades.
  • The trace's per-role bracket stays as the correlation key: a bracket says
    which worker ran, burnrate says what the window around it cost.

The obvious objection

This adds a dependency on a tool outside the plugin, and Cadence ships zero-dep
by design. Two answers worth weighing rather than assuming: the join could read
the cache file format rather than shell out (no dependency, just a reader), or
it stays opt-in behind a config key and the absent case is the default. If
neither is acceptable the honest outcome is to stop claiming the trace prices a
run and delete the token figures from /cad-suggest rather than keep reporting
a number that is 20x low.

Open question, not part of the proposal

5-minute cache writes are 21% of the weekly bill (48,704,671 raw tokens against
23,900,093 at the 1-hour TTL). I do not know whether the TTL is selectable from
Claude Code or fixed by the harness. Worth confirming before anyone treats it as
a lever.

## The problem `.planning/trace.jsonl` does not price a run, and it is the only thing `/cad-report` and `/cad-suggest` read. Measured on this repo, 2026-08-16: the trace recorded **795,845 tokens** for the whole `v3.5.2` milestone across 6 dispatches. burnrate, reading the same day's transcripts, recorded **16,261,487 billed-equivalent** for the project on that one day. Roughly 20x, and the gap is structural rather than a bug: - The trace records the figure on a **subagent return** only. The orchestrator contributes zero to it and 59% of actual spend (154,625,939 against the subagents' 105,743,431 over the last 7 days). - The trace has **no cache fields at all**. I checked every key across all 833 events: no `cache_read`, no `cache_creation`, nothing. Cache-read is 62.5% of the real bill and the record cannot see any of it. - The trace has **no window size and no turn count**, which are the two terms that actually multiply out to the cost. So `/cad-suggest` prices a configuration off a number that is wrong by an order of magnitude and blind to the dominant term. ## What burnrate already has `/data/code/burnrate` parses every transcript ONCE into a per-message cache (gzipped, under `$XDG_CACHE_HOME/burnrate`) and re-parses only changed sessions. Per day x project x command x model x effort x main|agent it carries: - `input`, `cache_write` split 5m/1h, `cache_read`, `output`, message count - `billed_equivalent = input + 1.25*cw5m + 2*cw1h + 0.10*cr` - `context footprint = input + cache_write + cache_read` (the live window) - per-session `peak_ctx`, compactions, interrupts, agent counts - attribution by `<command-name>` and by `"skill":"..."` tool call, so `cadence:cad-execute` is already a first-class row That is every quantity Cadence's own record is missing, keyed the way Cadence would key it, and it exists. ## The proposal `/cad-report` and `/cad-suggest` read burnrate's cache for spend, and `trace.jsonl` keeps what it is actually good at: WHAT happened (routing decisions, gate fires, adjudications, brackets, outcomes). Two records, two jobs, no reimplementation. - Cadence never becomes a token accountant. It joins one. - The join is read-only and degrades to today's behaviour when burnrate is absent, exactly like the recall backend degrades. - The trace's per-role bracket stays as the correlation key: a bracket says which worker ran, burnrate says what the window around it cost. ## The obvious objection This adds a dependency on a tool outside the plugin, and Cadence ships zero-dep by design. Two answers worth weighing rather than assuming: the join could read the cache file format rather than shell out (no dependency, just a reader), or it stays opt-in behind a config key and the absent case is the default. If neither is acceptable the honest outcome is to stop claiming the trace prices a run and delete the token figures from `/cad-suggest` rather than keep reporting a number that is 20x low. ## Open question, not part of the proposal 5-minute cache writes are 21% of the weekly bill (48,704,671 raw tokens against 23,900,093 at the 1-hour TTL). I do not know whether the TTL is selectable from Claude Code or fixed by the harness. Worth confirming before anyone treats it as a lever.
john added this to the v3.5.3 milestone 2026-08-16 17:17:43 +00:00
Author
Owner

Decided in Phase 2 (MSR-02) on cadence/v3.5.3, not yet merged to main. Answered NO to the join: Cadence does not import burnrate's accounting and stores no multiplier. Instead the spend receipt names what its figure excludes, and the gap prints as its TERMS - dispatches, turns, per-dispatch window as a stated proxy, and the unmeasured count - with burnrate left as a comparator the user runs. Commits 6c4e8ac, 8e2ee9f, 059493f; SPEND_EXCLUDES is the single frozen export both readers take, watched failing at 4b1d659. Closing as decided; the code lands with v3.5.3.

Decided in Phase 2 (MSR-02) on `cadence/v3.5.3`, not yet merged to main. Answered NO to the join: Cadence does not import burnrate's accounting and stores no multiplier. Instead the spend receipt names what its figure excludes, and the gap prints as its TERMS - dispatches, turns, per-dispatch window as a stated proxy, and the unmeasured count - with burnrate left as a comparator the user runs. Commits `6c4e8ac`, `8e2ee9f`, `059493f`; `SPEND_EXCLUDES` is the single frozen export both readers take, watched failing at `4b1d659`. Closing as decided; the code lands with v3.5.3.
john closed this issue 2026-08-18 00:23:34 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: crenshawdev/cadence-archived#198
No description provided.