fix(coord): claim.ps1 warned about the release rule at claim time and went silent at release time (BACKLOG #1358) - #652
Merged
Conversation
… went silent at release time (BACKLOG #1358)
`claim.ps1` anchors `$repo` on `$PSScriptRoot`, so a release is recorded against the tree the
SCRIPT COPY lives in and ownership is judged there too. That anchoring is correct and deliberate
(BACKLOG #1060): only the tool can be invoked from somewhere else, and the commit hook that reads
cwd is right to, because for a hook cwd IS the committing worktree.
THE DEFECT IS NOT THE ANCHORING. IT IS THAT THE WARNING ABOUT IT WAS UNREACHABLE FROM `-Release`.
The divergence note existed and named the exact rule -- "-Release must be run against that same
worktree" -- but it was written inline at the END of the script, after the `-Take` success block.
`-Release` exits some 170 lines earlier. So the one sentence telling an operator that a release
belongs to a particular tree was shown to them when they CLAIMED and withheld when they RELEASED.
The failure is silent in the worst direction: the release SUCCEEDS, and `released_by` records a
tree the operator was never standing in.
Extracted the note into `Write-DivergenceNote` -- one divergence test, three call sites. Only the
trailing sentence varies, because the true statement differs per path: a take is recorded to
`$repo`, whereas a release is both recorded to it AND adjudicated against it. It reads `$repo` from
script scope at call time rather than taking it as a parameter, since a second copy of "which tree
is this" is precisely the drift the note exists to report.
THE THIRD CALL SITE EARNS THE MOST AND WAS NOT IN THE ITEM. The refusal path prints "it is held by
another worktree". Under divergence the ownership test ran against the SCRIPT's tree, so "another
worktree" can be the operator's OWN, with the foreign thing being the copy of the script they
invoked. Unwarned, that reads as a real cross-session collision and invites a `-Force` -- the one
action that whole block exists to talk them out of.
Verified, with the scope stated. `ruff check` + `ruff format --check` clean on the changed test;
`mypy` strict clean over 267 engine sources; 96 tests pass across every suite that drives
claim.ps1 (test_script_root_anchoring, test_coord_claim_{release_history,liveness,reconcile,
refresh,adjudicate}, test_claim_check), run with the lane venv whose interpreter resolves into this
checkout.
RED-FIRST, AND THE POSITIVE CONTROL IS PART OF THE CHANGE RATHER THAN A NOTE ABOUT IT. Asserting
only that `-Release` prints nothing cannot separate "this path is silent" from "the note never
fires anywhere" -- an absent feature and a broken assertion render the same empty string. So the
new pair pins BOTH: that the note fires on `-Take` from a foreign cwd, and that it now also fires
on `-Release` from one. Before the fix the control passed and the sibling failed.
Three mutants, all killed, each with a DISTINCT red set, and each scored only after a sha256 check
that it actually changed the file: dropping the `-Release` note reds the sibling while the control
still passes; dropping the `-Take` note reds the control while the sibling still passes; inverting
the divergence test reds both. The first two failing on OPPOSITE tests is what shows these are two
cases rather than one wearing two names.
No ledger row added: #1358 already exists on origin/main at docs/BACKLOG.md, and its banner is not
mine to flip.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Aug 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Authored by Builder 2; pushed and opened by the LANDER. Two files, +106/-9.
The warning existed, stated the rule exactly, and was unreachable from the path that needed it
claim.ps1 -Releaserecords the release against the tree the script copy lives in, and judges ownership there too. The anchoring is deliberate and correct. What was wrong is placement:-Takesuccess block-Releaseexits ~170 lines earlierSo the script told you the release rule when you claimed, and said nothing when you released. Present, correct, and unreachable — the same shape as several other findings this week.
The call site that was not in the item
The refusal path prints "it is held by another worktree". Under divergence the ownership test ran against the script's tree — so "another worktree" can be your own, with the foreign thing being the script copy you invoked. Unwarned, that reads as a genuine collision and invites a
-Force.A gate whose error message argues for the dangerous action. That is worth more than the ordering bug it arrived with.
Verification
3c62df3c2: 13959 passed. Its two installed-parity failures were confirmed as the pre-install state by a post-install re-run — attribution by control, not by assertion.git merge-tree --write-tree 302e2ea8f <branch>→ tree730377e24, no conflict block, matching the author's hash exactlygit diff --name-only 8b6f8a088 302e2ea8f -- scripts/coord/claim.ps1 tests/test_script_root_anchoring.py→ empty, so main has not touched either file since the tested base8b6f8a088..origin/mainis non-empty, so the empty result is not two identical refs--write-tree, never the three-arg form — that exits 0 on a conflicting branch and a clean one alike.The branch existed only on a private rescue tag before this push.