Skip to content

fix(claude): keep cost available for resumed sessions' zeroed copies - #141

Merged
bhavsarpratik merged 2 commits into
mainfrom
fix/zero-token-cache-split
Nov 6, 2026
Merged

bhavsarpratik merged 2 commits into
mainfrom
fix/zero-token-cache-split

Conversation

@bhavsarpratik

Copy link
Copy Markdown
Member

Summary

Claude Code sessions that were resumed or forked could show their main-session cost as unavailable ("--"). This happened when the original parent transcript no longer existed.

This change treats a usage row as an unbilled copy when all four token totals (input, output, cache_read, cache_creation_input_tokens) are present and reported as 0. The row's stale cache_creation 5m/1h split is ignored. A row with any nonzero total, or with a missing total, and an inconsistent split still fails closed. The change is in _normalized_usage in token_meter/runtimes/claude.py.

Why

When Claude Code resumes or forks a session, it copies earlier messages into the new transcript. The copies have all four token totals set to 0, but they keep the original cache_creation 5m/1h split. Fork lineage normally drops these copies when the parent transcript exists.

When the parent transcript has been cleaned up, the copy reaches pricing. Its split no longer sums to its total, so billing_available becomes False. One such row marks the whole session's cost unavailable, even though its subagents still price correctly.

In local data, 65 such rows appeared across 11 sessions. Each was a copy of a message billed with matching numbers in another session file.

I considered pricing the stale split instead, and rejected it because it double-counts. One local session went from $288 to $486.

Known behavior: a zeroed copy that still carries server_tool_use.web_search_requests is priced for web search. This matches existing behavior for copies with a consistent split. No local copy carries one.

Testing

On head 68d1efc:

  • Full suite: 2556 tests OK (21 skipped).
  • Focused tests: 56 OK. The new tests fail on the old code.
  • git diff --check and py_compile are clean.
  • Real-data reproduction with the parent transcript removed: on the base, cost is unavailable. On this head, cost is available and the dollar amount is identical to the parent-present case.
  • Before/after comparison over about 930 local sessions with parents present: no changes to cost, availability, or tokens beyond live drift.
  • Independent gates: one tester and two reviewers (pricing correctness; regressions and consumers), plus a delta review of the second commit. All approved.

Not verified

  • The installed runtime has not been checked (./scripts/install, /health, /menubar, source/runtime parity).
  • The reporter's own session has not been checked. The link between their session and missing parent transcripts is inferred from the local reproduction, not confirmed on their machine.

🤖 Generated with Claude Code

bhavsarpratik and others added 2 commits November 6, 2026 09:51
…copies

Resumed and forked Claude Code transcripts copy earlier messages with all four
token totals zeroed but the original cache_creation split left in place. When
the parent transcript is gone, those copies reached pricing, failed the split
consistency check, and marked the whole session's cost unavailable. Treat a
row whose four totals are all reported zero as an unbilled copy and ignore its
stale split; any nonzero total with an inconsistent split still fails closed.

Co-Authored-By: Claude Code <noreply@anthropic.com>
…d copy

A row that omits a cache total must still fail the split consistency check
instead of being priced as an unbilled copy.

Co-Authored-By: Claude Code <noreply@anthropic.com>
@bhavsarpratik
bhavsarpratik merged commit ead77f8 into main Nov 6, 2026
10 checks passed
@bhavsarpratik
bhavsarpratik deleted the fix/zero-token-cache-split branch November 6, 2026 10:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant