Fix Integration Test Checkpoint Metadata Rename

I've reviewed PR #1263 thoroughly — read the full diff, traced the logic against main, and tested the merge. Here's my assessment.
Review: PR #1263 — Fix Cursor hook misattribution + token usage
Verdict: Sound design, well-tested, but has one merge blocker. The author's "rebased latest main" claim is now stale — main has moved and the branch no longer merges cleanly.
What it does (two independent fixes)
- Cross-agent hook guard (#1262) —
shouldSkipForwardedHook()short-circuitsexecuteAgentHookwhen a hook fires for agent X but the payload'stranscript_pathbelongs to agent Y's session dir (Cursor IDE firing Claude Code hooks when only.claude/settings.jsonis installed). - Cursor token usage (#1264) — parses token fields from Cursor's
stophook (the only authoritative source — Cursor's JSONL has no usage data), threads them throughevent.TokenUsage, and adds per-checkpoint scoping viaSessionState.CheckpointTokenUsage.
Correctness — looks right
I traced the token-scoping flow against main:
SaveStepaccumulates into bothTokenUsage(session-wide, forentire status) andCheckpointTokenUsage(pending delta). ✓CondenseSessionbackfillssessionData.TokenUsagefromCheckpointTokenUsageonly when transcript-derived usage is empty (hasTokenUsageDataguard) — correct for Cursor, no-op for agents with real transcript usage. ✓- All three callers of
CondenseSession(condenseAndUpdateState,CondenseSessionByID,CondenseAndMarkFullyCondensed) resetCheckpointTokenUsage = nilafter condensing — so checkpoint N+1 gets only its own delta, not the cumulative total. ThePerCheckpointScopingintegration test asserts exactly this (500, not 700). ✓ - The negative-clamp and nil-vs-zero ("no data" vs "all zeros") semantics in
tokenUsageFromStopare thoughtful and tested.
The guard fails open in every ambiguous case (no SessionRef, unattributable path, unresolvable repo root) — the safe default. .cursor/hooks.json correctly matches the existing committed .codex/hooks.json / .gemini/settings.json dogfooding convention (go run main.go), so that's not a stray file.
🔴 Blocker: merge conflict
mergeable: CONFLICTING. A real textual conflict exists in cmd/entire/cli/lifecycle_test.go (3 hunks, ~lines 1144–1262) — both main and this branch added adjacent test helpers/functions. It's mechanical (keep-both), not logical. Everything else auto-merges. The author needs to rebase/merge main again and resolve it.
🟡 Minor notes (non-blocking)
- Scope creep: two unrelated edits ride along —
telemetry/detached_test.go(adds a redundantreturnaftert.Fatal, presumably to silence a nil-deref linter) andinternal/coreapi/UPSTREAM.md(drops a trailing newline). Harmless, but worth asking the author to drop them or call them out. - Subagent tokens for Cursor:
handleLifecycleTurnEndnow prefersevent.TokenUsageand skipsCalculateTokenUsage, which is whereSubagentAwareExtractoradds subagent tokens. Since.cursor/hooks.jsonregisterssubagentStart/subagentStop, if Cursor'sstoppayload doesn't already fold in subagent usage, those tokens are lost. Likely acceptable (the alternative was zero), but worth a one-line confirmation from the author. - CI: no checks ran — it's a fork PR, so CI is gated. Can't independently confirm the "full suite + lint pass" claim without running it on the merged tree.
Suggested reply to the contributor
Thanks for the follow-up. The token-scoping design is correct and the test coverage (condensation survival + per-checkpoint scoping) is exactly what I wanted. One blocker before I can merge: the branch conflicts with current
main— there's a content conflict incmd/entire/cli/lifecycle_test.go(both sides added test helpers in the same spot; keep-both resolves it). Please merge/rebasemainagain and push. Two small asks: (1) drop the unrelatedtelemetry/detached_test.goandinternal/coreapi/UPSTREAM.mdchanges (or note why they're here), and (2) confirm whether Cursor'sstoppayload includes subagent tokens — since we now skip the transcript-based subagent extractor for Cursor turns.
Want me to post this as a PR comment, or draft inline review comments on the specific lines?
Done. The merge conflict is resolved and pushed.
Summary
mergeable flipped from CONFLICTING → MERGEABLE. (mergeStateStatus: BLOCKED just reflects the still-pending maintainer review/CI approval — not a conflict.)
What I did:
- Fetched the fork branch (
SnowingFox/cli@3f25b2c2) and merged currentorigin/maininto it. - Resolved the sole conflict in
cmd/entire/cli/lifecycle_test.go— an interleaved "both sides added adjacent code" conflict. Kept both independent additions intact:- PR's
TestHandleLifecycleTurnEnd_PrefersEventTokenUsage main'smockContextInjectorAgenttype,addGitHubOriginForLifecycleTesthelper, and the twoContextInjectiontests
- PR's
- Verified:
go build✓,go vet✓, the three affected tests pass ✓,mise run fmt(no changes) ✓,mise run lint→ 0 issues ✓. - Pushed the merge commit (
950f947b9) to the PR branch viamaintainerCanModify.
Your working tree is back on a clean main; the temporary pr1263-merge branch is deleted.
The remaining items from my earlier review are unchanged (non-blocking): the unrelated telemetry/detached_test.go + UPSTREAM.md edits, and the open question about whether Cursor's stop payload folds in subagent tokens. Want me to post either of those as a PR comment?
You were right — the textual merge was clean, but there was a semantic conflict it couldn't catch.
Root cause
The PR's new integration test (cursor_token_condensation_test.go) referenced checkpoint.CommittedMetadata, but main has since renamed that type to checkpoint.Metadata (now an alias for apicheckpoint.Metadata — part of the api/checkpoint refactor). That file sits behind the //go:build integration tag, so the normal build, go vet, lint, and the canary all passed — only the integration shards compile it, and all three failed with undefined: checkpoint.CommittedMetadata.
Fix
Renamed the two references to checkpoint.Metadata. The field is identical (TokenUsage *types.TokenUsage, same JSON tag) and agent.TokenUsage is a type alias for types.TokenUsage, so the test logic is unchanged.
Verified before pushing:
- Integration package compiles under the build tag ✓
- Both new tests pass locally:
TestCursorTokenUsage_SurvivesCondensationandTestCursorTokenUsage_PerCheckpointScoping✓ mise run fmt(no changes) +mise run lint→ 0 issues ✓
Pushed as fa112bcf4; PR is back to MERGEABLE. The integration shards should pass on the new run.
Want me to watch the CI run and confirm it goes green? (Integration takes a few minutes.)