Skip to content

lifecycle: keep a no-change turn's tokens for every agent - #2722

Open
peyton-alt wants to merge 2 commits into
mainfrom
peyton/stop-hook-tokens-no-changes
Open

peyton-alt wants to merge 2 commits into
mainfrom
peyton/stop-hook-tokens-no-changes

Conversation

@peyton-alt

@peyton-alt peyton-alt commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Bug. When a turn changes no files, turn-end skips SaveStep. That path recorded only out-of-band usage (Antigravity), which caused two losses:

  • Cursor: the stop payload's event.TokenUsage was dropped. Cursor's transcript has no usage fields, so the turn was missing from both the session total and the next checkpoint.
  • Claude Code, Codex and other agents that keep usage in their transcripts: the turn never reached the session total (entire status). Their checkpoints were unaffected, because condensation recomputes them from the transcript slice.

Fix.

  • resolveTurnTokenUsage is now the single resolver for both turn-end paths. Precedence: hook-reported, then Codex's subagent ledger, then the transcript from the turn's start offset, then out-of-band.
  • SaveStep's accounting is extracted as applyTurnTokenUsage. It covers the session total, the pending checkpoint usage, the subagent baseline rescoping, and dropping a child snapshot computed against a stale Codex ledger version. SaveStep and AccumulateSessionTokenUsage both use it.
  • Droid Worker sessions are skipped on this path, because SaveStep never runs for them either and recording would count their tokens twice.

No checkpoint double-counts the turn. For transcript agents, condensation still takes the main counters from the transcript slice, and the pending checkpoint usage is only a fallback.

Tests.

  • Integration tests for Cursor, Claude Code and Codex drive the real hooks: a file-changing turn, a no-change turn, a commit, then one more turn and commit. They assert each turn lands once in the session total and once in a checkpoint. All three fail on main.
  • A strategy unit test covers subagent rescoping and a stale ledger version on the no-change path.

🤖 Generated with Claude Code

A turn-end that changes no files skips SaveStep, and that branch only
recorded out-of-band usage (Antigravity). The hook-reported usage on
the event (Cursor's stop payload) was dropped. Cursor's transcript has
no usage fields, so condensation could not recover it either: the turn
was lost from the session total and from the next checkpoint.

Record event.TokenUsage on that branch, falling back to out-of-band
usage only when the hook reported none, the same precedence the
SaveStep path uses, so no turn is counted twice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M4HPW4188RCPJJK89HX2XPNM
@peyton-alt
peyton-alt requested a review from a team as a code owner October 10, 2026 01:32
Copilot AI balanced review requested due to automatic review settings October 10, 2026 01:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The fix matches existing token-source precedence and is covered by focused end-to-end regression testing.

0 open findings

What changed in this PR

Fixes lost Cursor token usage when a turn changes no files by preserving hook-reported usage in session and checkpoint accounting.

Changes:

  • Uses hook-reported usage before out-of-band fallback on checkpoint-less turns.
  • Adds integration coverage for session totals and checkpoint scoping across three turns.
File Description
cmd/​entire/​cli/​lifecycle.go Preserves token usage when SaveStep is skipped.
cmd/​entire/​cli/​integration_test/​cursor_token_condensation_test.go Verifies no-change turn accounting and checkpoint isolation.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

…files

The checkpoint-less turn-end path recorded only hook-reported and
out-of-band usage, so for Claude Code, Codex and the other agents
whose usage lives in the transcript, a turn that changed no files
never reached the session total that `entire status` shows. (The next
checkpoint was unaffected: condensation recomputes it from the
transcript slice.)

Resolve the turn's usage on that path exactly as SaveStep does, with
one helper (resolveTurnTokenUsage: hook, Codex child ledger,
transcript from the turn's start offset, out-of-band), and record it
through the same accounting SaveStep uses, now extracted as
applyTurnTokenUsage: the session total, the pending checkpoint
window, the subagent baseline rescoping, and dropping a child
snapshot computed against a stale Codex ledger version. Subagent
sessions of their own (Droid Workers) are skipped, as SaveStep never
runs for them either.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@peyton-alt peyton-alt changed the title lifecycle: keep hook-reported tokens for turns that change no files lifecycle: keep a no-change turn's tokens for every agent Oct 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants