fix(coord): count a session in a deregistered checkout as unplaceable - #1243
Merged
Merged
Conversation
occupancy.ps1 dropped a record whose cwd matched no registered worktree on a
bare `continue`, so it reached no counter. RecordsUnplaceable could not rise
past the two shapes the matcher already counted, Available could not go false
for a third, and a session left behind by a worktree git had stopped listing
was INVISIBLE rather than UNPLACEABLE.
That is a fence that cannot fail, so its green light measured nothing -- and
prune-merged.ps1 and claim.ps1 both gate on it.
The boundary is the whole of the change and it cuts both ways. Another
repository's session must not cost a refusal, because most records on this host
are exactly that, so a fault needs evidence the cwd is a checkout of THIS repo:
* the directory is still there -- read its own .git pointer and compare git
directories. That survives deregistration where `git rev-parse` does not,
and a plain `<primary>-*` lookalike fails it;
* the directory is gone -- nothing on disk can say whose it was, so the
`<primary>-<slug>` naming new.ps1 builds is the only evidence left. The name
test is admitted on this branch only, never on a path that exists.
Placement moves ahead of the availability verdict: while the verdict was
computed first, a failed placement had nowhere to go.
tests/test_coord_occupancy_unplaceable.py asserts BOTH directions, because a
test that only proves refusal passes against a fence wired shut. Against the
unpatched script the two fault tests FAIL and the two availability tests pass;
patched, all four pass.
Measured on this host with the patch applied: 6 config roots, 7 records, 0
unplaceable, 110 worktrees, 3 sessions placed -- so the new fault does not
disable the live fence.
tests/test_coord_occupancy_unplaceable.py imports no engine module, so nothing decided which CI legs run it and test_tooling_partition.py failed the required ubuntu leg. That test's own message requires the entry to land in the same pull request as the file. Classified (a) HARNESS rather than the ambiguous (b): the subject is scripts/coord/occupancy.ps1, and the manifest header names the coordination harness as this tier. Twenty-six sibling test_coord_*.py files already sit here. Placed among those siblings rather than appended at end-of-file. Nothing enforces an order, only test_manifest_has_no_duplicates, and an EOF append is the one position that collides with every other pull request adding a line. Added by the Lander, not the authoring session, because the branch had been quiet for four hours with no claim on it and a third session is blocked until this commit is reachable from main. The head SHA was pinned before the write and the push refuses if it moved.
…S.md occupancy.ps1:30 changed from "Two shapes qualify" to "Three" on this branch; docs/WORKTREES.md still enumerated two, so a documented claim stopped matching its code. No test asserts it either way. The enumeration, not just the numeral. The third shape is a record whose cwd is a checkout of this repo that `git worktree list` no longer carries. Taken from Get-UnplaceableCwdReason, not the script header: that function admits two evidence branches -- the owning git common dir when the path exists, the `<primary>-` name when it does not -- and the header covers only the first. Hence "still on disk or gone". Agreement words that moved with the count: "and one that parses" -> "a record that parses", "both used to be" -> "Each used to be", "Neither can be placed" -> "None can be placed". The "two independent signals" and "Both are re-read" above count signals, not shapes, and stand. An older copy in prune-merged.ps1:84 names only the unparseable shape. Left untouched -- another session owns that header.
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.
The occupancy fence could not refuse on the one ground that matters. A session record whose cwd lies
inside this repo family but matches no registered worktree was dropped with a bare
continueandnever reached
$faults, soRecordsUnplaceablecould not rise andAvailablecould not go falsebecause of it.
That is the manufactured-evidence shape.
Available: truewas unfalsifiable on that ground, so itproved nothing, and two proposed reapers are gated on it.
The control fired first
Against the unpatched script at
b8421ca53, with only the new test added:That receipt is the defect stated in its own output: the record existed, parsed, and reached no
counter. Patched:
Neighbours, same venv, unpiped, exit echoed separately: 98 passed in 151.06s across
test_coord_presence,test_coord_claim_liveness,test_coord_box_activity,test_coord_recoverable,test_coord_overlap_attribution,test_coord_handoff_report,test_session_context_presenceandtest_worktree_remove.test_worktree_prune_merged.py: 79 passed in 247.29s.ruff format --check,ruff checkandmypyclean. HEAD wasb8421ca53before and after every run, so no run measured amoving tree.
The boundary, and why it is drawn there
A cwd OUTSIDE the repo family is not a fault -- it is another repository's session. The fault is a cwd
INSIDE the family that matches no registered worktree.
.gitpointer resolves to THIS repo's common dir<primary>-<slug>new.ps1builds is the only evidence leftThe name test is admitted ONLY when the directory is absent. A name match on a directory that exists
is the sibling-prefix trap that
test_coord_presence.py::test_sibling_prefix_directory_is_not_treated_as_inside_the_repoalready pins, and
MessageFoundry-vaultsits beside the primary on this machine. Faulting it wouldleave the fence permanently unavailable, which disarms every caller as thoroughly as never refusing.
Get-OwningGitCommonDirwalks the filesystem rather than asking git, deliberately:git -C <path> rev-parsefails outright once a worktree's admin entry is pruned, which is precisely the state beingasked about.
Callers
All four already fail closed, so this can only move them toward refusal.
prune-merged.ps1EXIT_REFUSED; every candidate becomes SKIP. The fence is re-read once before the apply loop, not per candidate.presence.ps1[]; the UNAVAILABLE receipt goes to stderr. JSON contract untouched.claim.ps1Get-OccupancyOncereturns false, so a holder stayspresent, which already refuses.remove.ps1,box-activity.ps1Available. Unaffected.No field or signature was removed.
Live reading, patched
6 config roots, 7 records, 0 unplaceable, 110 registered worktrees, 3 sessions placed,
Available: True.The new fault does not disable today's fence. That zero is reportable because the planted controls in
the test fire.
Two corrections to the brief behind this commit
The brief asked for a plant pointing at a deleted
.claude/worktreespath. Those sit under aREGISTERED worktree, so such a record always matches an ancestor and is placed. That plant would have
gone green against the unpatched script and proved nothing. The path has to be under a checkout git no
longer lists.
The brief also said
Availablecould never go false. Too strong: three paths already set it false --no config root, an unreadable registry, and zero readable records. All three mean "I could not look at
all". What could not happen was
Availablegoing false because a session could not be PLACED, which isthe only one that refuses on positive evidence.
Known follow-up, deliberately not in this branch
scripts/worktree/prune-merged.ps1's FENCE UNAVAILABLE header paragraph is an incomplete enumeration.It omitted the cwd-less shape before this change and omits two of three after it. A separate session is
holding a patch for it, derived from
Get-WorktreeOccupancyrather than from any prior comment, and iswaiting on this branch to land.