fix(bin): refuse to hand out or release a worktree another task owns - #3519
fix(bin): refuse to hand out or release a worktree another task owns#3519jericho1050 wants to merge 1 commit into
Conversation
Confidence Score: 5/5The PR appears safe to merge, with no concrete changed-code failure identified. The new checks stop before mutation, preserve ordinary free-worktree and own-branch behavior, and operate within the existing serialized spawn lifecycle. Reviews (1): Last reviewed commit: "Guard worktree ownership during spawn an..." | Re-trigger Greptile |
|
Speaking as Kun's firstmate: full-thread + full-diff review of #3519 (jericho1050). Author is not on the blocked list. Attestation: MISSING. PR body has no First-time fork CI this pass: after safe diff review (zero Contract-class: new-default. Unconfigured spawn now always runs VISION.md per-rule (inspected
Security: clean — refusals only; no workflow/RCE/credential surface; no ownership bypass. Not Firstmate-flagging. Overlap note (not a hold): open #3246 (jleemcf, already stamped waiting-author new-default) also refuses stale pooled worktree ownership via always-on Waiting on author for attestation (NM green) and green CI. Not escalating; not merging. |
Why
A task that has FINISHED but whose PR is UNMERGED is correctly never torn down, because teardown requires confirmed landing. Its worker stops, its pane closes, and its recorded worktree stays claimed while looking idle to everything except its own
state/<id>.meta. The pool allocator then hands that same directory to the next spawn.This happened FOUR times in one day. The sharpest instance: a cost investigation was handed the exact copy another task was mid-merge in, with two unresolved files and a staged conflict resolution that existed nowhere else. It was caught by attention, not by anything structural.
No work was lost on any occasion, because each finished task's branch was already on the server. But the hazard is asymmetric: tearing down the finished task would return the directory from under a live worker mid-run.
What this does
Two refusals, never repairs. Neither guard releases, reassigns, switches a branch, or cleans anything up - a guard that acts is a guard that can destroy.
fm-spawn.shrefuses to record a worktree another livestate/*.metaalready names, and says which task holds it.fm-teardown.shrefuses when the recorded copy is checked out on a different task's branch, naming that branch and task.Tests
tests/fm-worktree-ownership.test.sh, 4 cases, all passing:The two controls are load-bearing: without them, "correctly refuses collisions" and "refuses everything" are indistinguishable.
Disclosure
The authoring worker went unreachable after committing - its composer wedged, so it could neither push nor open this PR. Firstmate ran the test suite itself to verify what it was preserving, then pushed the branch and opened this PR by hand. No code was changed after the worker's commit.
Consequently the "PR must be raised via no-mistakes" check will fail, and that failure is honest rather than incidental: this PR genuinely was not raised through that pipeline.