Skip to content

test(strategy): prove dangling checkpoint trailer for IDLE + empty FilesTouched#1704

Draft
Soph wants to merge 1 commit into
mainfrom
soph/idle-empty-filestouched-dangling-trailer
Draft

test(strategy): prove dangling checkpoint trailer for IDLE + empty FilesTouched#1704
Soph wants to merge 1 commit into
mainfrom
soph/idle-empty-filestouched-dangling-trailer

Conversation

@Soph

@Soph Soph commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

What

Adds a RED regression test that reproduces and proves a silent prepare-commit-msg / post-commit mismatch: a commit can end up carrying an Entire-Checkpoint trailer that points at a checkpoint that was never materialized locally (a dangling trailer).

This is a test-only, TDD-first PR — the test is intentionally failing and documents the invariant a follow-up fix must restore. CI will be red until the fix lands.

New file: cmd/entire/cli/strategy/phase_postcommit_dangling_trailer_test.goTestPostCommit_IdleSession_NewLiveTranscriptEdits_DanglingTrailer.

Scenario (reconstructed from a real Pi session)

  1. A session is condensed (clears state.FilesTouched, stamps LastCheckpointID), then goes IDLE.
  2. A new turn arrives without a TurnStart (rapidly submitted prompt), so the session stays IDLE and SaveStep never repopulates FilesTouched. No shadow branch exists for the new edits yet.
  3. The agent edits files and commits them.

Root cause

  • PrepareCommitMsg re-extracts the edited files from the live transcript (sessionHasNewContentFromLiveTranscript), overlaps them with the staged files, and adds the trailer.
  • PostCommit computes filesTouchedBefore only from persisted state.FilesTouched for non-ACTIVE sessions (the active-only fallback in manual_commit_hooks.go:1246-1252) and never passes the committed files as an overlap signal. With FilesTouched empty and no staged files, hasNew collapses to false and/or the guard in shouldCondenseWithOverlapCheck (len(filesTouchedBefore)==0 → return false) rejects condensation.

Net: the commit keeps the trailer, but no checkpoint is ever written for it.

What the test proves

  • Premise passesPrepareCommitMsg adds the trailer purely from the live transcript (log: prepare-commit-msg: trailer added ... checkpoint_id=...).
  • Invariant fails — after commit + PostCommit, entire/checkpoints/v1 does not exist and LastCheckpointID stays pinned to the prior checkpoint. The trailer dangles.

Notes for the fix (out of scope here)

  • TestPostCommit_IdleSession_NoTranscriptFallbackForCarryForward explicitly asserts IDLE sessions must NOT re-extract from the transcript (it guards an earlier carry-forward + 3s sentinel-wait regression). A naive "always re-extract for IDLE" fix would re-break it.
  • Safer direction: persist the positive prepare-hook file association, and log a warning whenever a commit carries a trailer with no materialized checkpoint.
  • Separately worth investigating: why Pi emitted no TurnStart for that rapidly-submitted third turn.

Verification

  • mise run fmt / mise run lint → clean (0 issues).
  • New test fails only at the invariant; premise and the two related existing IDLE tests pass.

🤖 Generated with Claude Code


Note

Low Risk
Test-only addition with no production or hook behavior changes; CI failure is intentional until a separate fix.

Overview
Adds an intentionally failing regression test in phase_postcommit_dangling_trailer_test.go that locks in the invariant: if PrepareCommitMsg adds an Entire-Checkpoint trailer, PostCommit must materialize that checkpoint.

The test simulates an IDLE session after condensation (FilesTouched cleared, prior LastCheckpointID set) where new edits exist only in the live Gemini transcript (no TurnStart, no shadow branch). PrepareCommitMsg still adds the trailer via live-transcript overlap with staged files; PostCommit currently skips condensation, so entire/checkpoints/v1 is never created and LastCheckpointID stays on the old ID—a dangling trailer. Comments point at a follow-up fix (e.g. persist prepare-hook association) without naively re-breaking TestPostCommit_IdleSession_NoTranscriptFallbackForCarryForward.

Test-only change; CI is expected to stay red until the behavior fix lands.

Reviewed by Cursor Bugbot for commit c511f36. Configure here.

…lesTouched

Add a failing (RED) regression test reproducing the silent prepare/post-commit
mismatch: when a turn arrives without a TurnStart, the session stays IDLE with
empty persisted FilesTouched and no shadow branch. PrepareCommitMsg still adds an
Entire-Checkpoint trailer (it re-extracts edited files from the live transcript and
overlaps them with staged files), but PostCommit computes filesTouchedBefore only
from persisted FilesTouched for non-ACTIVE sessions and never feeds committed files
into the overlap check. hasNew collapses to false and/or the overlap guard rejects
condensation, so no checkpoint is materialized — the commit keeps a trailer pointing
at nothing (dangling trailer).

The test asserts the invariant the fix must restore: every trailer PrepareCommitMsg
writes must correspond to a materialized checkpoint after PostCommit. It fails at
that invariant on current code; the premise (trailer added via live transcript) and
the two related existing IDLE tests still pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 01KX6BJH6R8KQAAWRCDJC0V8GZ
Copilot AI review requested due to automatic review settings July 10, 2026 15:51

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.

Pull request overview

Adds a new strategy-layer regression test that reproduces a prepare-commit-msg vs post-commit mismatch where a commit can gain an Entire-Checkpoint trailer that points to a checkpoint that is never materialized locally (dangling trailer), particularly for IDLE sessions with empty FilesTouched.

Changes:

  • Introduces a new (currently failing) regression test that sets up an IDLE session with no shadow branch and relies on live-transcript file extraction to trigger trailer insertion.
  • Asserts the invariant that if PrepareCommitMsg writes an Entire-Checkpoint trailer, PostCommit must materialize the corresponding checkpoint and metadata branch.

Comment on lines +55 to +57
func TestPostCommit_IdleSession_NewLiveTranscriptEdits_DanglingTrailer(t *testing.T) {
dir := setupGitRepo(t)
t.Chdir(dir)
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