fix: protect shared worktrees during task teardown - #25
Merged
Merged
Conversation
A pool path outlives the record that named it. On 2026-09-08 a stale task record still carried worktree=<path> after the pool had handed that exact path to a live task; tearing the stale record down ran the pool return on that path, reset it to the default branch, and killed the live agent. Add a metadata-only preflight that runs before any pool return, branch delete, worktree reset, process reap, bridge sweep, or run abort: if any other task record in the same FM_HOME carries an identical worktree= value, teardown refuses, names the other task and the path, changes nothing, and prints the records-only alternative. --force does not bypass it, because --force authorizes discarding this task's own work, not another task's. Add --release-shared-record for exactly that stale-record case: it retires only the calling task's own records (endpoint, meta, status presentation, steering inbox, check and PR poll artifacts, busy state, per-task temp root, backlog close) and touches the shared worktree in no way at all. It is accepted only while another record still names the worktree, never for kind=secondmate, and is mutually exclusive with --force. Every existing refusal (dirty worktree, unlanded work, scout report, public follow-up, --force semantics) is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RwpKERxmGp8xMZ9A3tqZwt
…o use --release-shared-record when the new shared-worktree guard refuses forced teardown. Syntax and diff checks pass
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.
Intent
Add a preflight guard to bin/fm-teardown.sh so it refuses to return or reset a worktree that another live task still references, and add a --release-shared-record flag for the stale-record case.
Why: a treehouse pool path outlives the record that named it. Measured 2026-09-08 02:05, state/fm-scout-compliance-reaudit.meta still recorded worktree=~/.treehouse/scout-43588a/3/scout after the pool had handed that same path to fm-scout-ci-caching, whose own meta carried the identical worktree= line and a live window. Tearing down the stale record ran the pool return on that path, reset it to the default branch, and killed the live agent.
Required behaviour the captain asked for, all deliberate:
Deliberate design decisions made while implementing, so they are not mistakes:
Already verified locally before this run: bin/fm-test-run.sh tests/fm-teardown.test.sh (total=1 failed=0), bin/fm-test-run.sh --changed (total=41 failed=0), bin/fm-lint.sh clean, bin/fm-doc-audience-check.sh ok.
Delivery: this is a PR on the firstmate repo; the firstmate CI requires the no-mistakes attestation, so this run must push and attach it (PR 25 already exists for this branch).
What Changed
--forceis used.--release-shared-recordto remove only the stale task's records and backlog item while preserving the shared worktree.Risk Assessment
✅ Low: The change is bounded to teardown protection, records-only cleanup, documentation, and behavioral tests, with no source-verifiable correctness issues found.
Testing
The teardown test family passed after rerunning with a sufficient timeout; shared-worktree behavior was exercised end-to-end through the executable, including refusal output, preservation of the worktree, and records-only cleanup.
Evidence: Shared-worktree behavior transcript
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
✅ **Review** - passed
✅ No issues found.
✅ **Test** - passed
✅ No issues found.
bin/fm-test-run.sh tests/fm-teardown.test.shShared-worktree refusal, --force refusal, records-only release, and unshared release refusal cases✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.