Skip to content

Token budget charges cached prompt reads at full weight; 98% of counted spend is cache #831

Description

@drewstone

Measurement

Across a 299-run research fleet, on the 122 runs whose result.json carries a fresh/cache split, spentTotal.tokens.input equals freshInput + cacheRead in 122 of 122 cases, and cache dominates it:

  • fleet totals on those runs: 7,070,863 fresh input vs 392,633,152 cacheRead — 98.23% cache
  • single example (arena-v9c1-q36-structure-b): input: 4,012,893 = freshInput: 79,453 + cacheRead: 3,933,44098.02% cache

maxTokens is enforced against that rolled-up input, so a 2,000,000 cap stops a run that has consumed roughly 40,000 tokens of new prompt.

Cost, measured

  • 88 of 226 capped runs exceeded their cap. Zero of the 88 became winners.
  • Those 88 hold 379 of the fleet's 786 verified claims (48%) — the cap preferentially kills the runs producing the science.
  • The 85 budget-exhausted runs with usable timing forfeited 39.3 h of 125.3 h total fleet wall-clock (31%), terminating at a median 35% of their allotted deadline.
  • The same counter drains the delegation pool: leads were refused child spawns while holding most of their real budget.

The question I cannot answer from our artifacts, which is itself a gap

Whether full-weight charging is wrong depends on what the provider bills. I could not determine that here: no run journal in this fleet contains a promptCache object at all. The field exists in the type (PromptCacheUsage, whose validator was fixed in #818) but nothing on the bridge path populates it. Runtime is enforcing a cap against a composition whose price it cannot observe.

I am deliberately not proposing a specific weight, because guessing one would be as wrong as the current behavior. The pricing has to come from the provider.

Suggested shape

  1. Charge from the components — freshInput + output + cacheWrite + w*cacheRead — with w configurable and recorded in the run manifest so the weight is auditable, rather than summing the rolled-up input.
  2. Emit spentTotal.tokens as {freshInput, cacheRead, cacheWrite, output} on every harness, and treat an unknown breakdown as a refusal to enforce rather than a silent full-weight charge.
  3. Populate promptCache on the bridge path so the provider's own accounting is visible to the budget.
  4. Apply the same formula to worker-pool ticket reservation, which today refuses spawns on the same inflated number.

Correction to a related claim

An automated pass reported that some harnesses exclude cacheRead from input, making cross-arm comparisons invalid. I could not reproduce that — 122 of 122 testable runs fold it in consistently. Reporting it so nobody chases it.

Journals, the per-run table, or a PR available once the pricing question is settled.

Measured on runtime 0.133.3–0.133.5, bridge executor, pi and claude-code harnesses.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions