Skip to content

Reaping a worktree on a merged PR is not enough: verify @{u}..HEAD is empty AND that the content reached main #1130

Description

@localai-bot

A merged pull request is necessary before removing a worktree. It is not
sufficient. The worktree for PR #1035 was reaped while its branch carried two
commits that were on neither main nor its own remote branch, and only a rescue
ref preserved the SHAs.

The rule

Before git worktree remove, both of these must hold:

  1. git log --oneline @{u}..HEAD is EMPTY, so nothing local is unpushed.
  2. The content reached main, checked by content rather than by ancestry.

Either one alone gives the wrong answer. Section "The four instruments
disagreed" below measures that rather than asserts it.

Why ancestry cannot answer this

main is squash-only. A squash writes a NEW commit whose tree matches the
branch tip and whose parent is main, so no commit from the branch is ever an
ancestor of main, and no patch-id from the branch survives either.
git merge-base --is-ancestor therefore returns false for work that landed
perfectly, and git cherry origin/main marks landed commits +. Neither
instrument distinguishes "landed via squash" from "never pushed".

The four instruments disagreed, measured on the #1035 case

PR #1035 (row/ENG-EXPERT-STREAM-CUDA-GROUPED-LINEAR) merged 2026-08-16T21:09:11Z
as squash b493f4981 on main. The rescue ref
rescue/es-cuda-grouped-unpushed holds the reaped worktree's branch at
3ca7c23d8, three commits above ff264cb82:

3ca7c23d8 record(ENG-EXPERT-STREAM): re-derive the codebook-coverage figure instead of quoting it
c2acaac91 fix(ENG-EXPERT-STREAM): bind the captured case name so it cannot dangle at failure time
5bc299f08 fix(ENG-EXPERT-STREAM): the grouped CUDA dispatch launched nothing and called it success
Instrument Answer Correct?
git merge-base --is-ancestor <c> origin/main all three NOT on main no, squash
git cherry -v origin/main 3ca7c23d8 all three +, meaning missing upstream no, squash changes the patch-id
git cherry -v <remote branch> 3ca7c23d8 5bc299f08 +, the other two - misleading, 5bc299f08 is the same change on a different base
git log --oneline <remote branch>..3ca7c23d8 all three unpushed by SHA yes, and it is the guard that would have fired

The remote branch row/ENG-EXPERT-STREAM-CUDA-GROUPED-LINEAR sits at 9e34cc841
and carries the SAME three subjects at DIFFERENT SHAs (c3540e4e2, 604677db1,
9e34cc841). So the local commits were never the pushed commits, and step 1
above would have refused the reap.

What was actually at risk, stated honestly

Step 2 passes on this case. The content of all three commits IS on origin/main
at b493f4981, verified two ways:

  • git diff c2acaac91 origin/main -- tests/vt/test_cuda_quant_dot.cpp is empty.
  • git log -S're-derived here rather than quoted' origin/main -- .agents/specs/expert-streaming.md names b493f4981.

So the reap lost nothing, and the rescue ref preserved SHAs that were already
redundant. That is the strongest argument for the two-part rule rather than a
weaker one. Step 1 alone would have blocked a safe reap. Step 2 alone would have
allowed it. Only running both says which of the two situations you are in, and
the reaper had no way to tell them apart at the time.

The rescue ref

rescue/es-cuda-grouped-unpushed, tip 3ca7c23d8. Named here so the owner can
recover the work if the content check is ever found wrong. Delete it when the
owner confirms it is redundant. Two sibling refs exist from earlier incidents,
rescue/cuda-breadth-sm75-audit (fe4d91aa6) and rescue/fp8-native
(1d919db19), and neither has been adjudicated.

Scope

This asks for the rule to be recorded where a reaper reads it, and for the
two-part check to be executable rather than remembered. It does not ask for a
gate that runs on every pull request: reaping is not a pull-request event, and a
checker that must query the remote cannot run here.

Related: #788 records the opposite direction, where an UNdeleted branch reads
IN-FLIGHT forever on a squash-only main. Both are the same root cause: on a
squash-only main, ancestry carries no information about a branch.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions