Skip to content

fix(teardown): remove the scout worktree-safety exemption - #1160

Open
ICGNU3 wants to merge 1 commit into
kunchenguid:mainfrom
ICGNU3:claude/teardown-scout-exemption-upstream
Open

fix(teardown): remove the scout worktree-safety exemption#1160
ICGNU3 wants to merge 1 commit into
kunchenguid:mainfrom
ICGNU3:claude/teardown-scout-exemption-upstream

Conversation

@ICGNU3

@ICGNU3 ICGNU3 commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What

validate_worktree_teardown_safety() returns 0 before any check runs when KIND is secondmate or scout:

[ "$FORCE" != "--force" ] || return 0
case "$KIND" in
  secondmate|scout) return 0 ;;   # skips dirty / unpushed / unmerged
esac

This removes the scout half and keeps secondmate.

Why

A teardown sweep across 104 worktrees hit 11 that held uncommitted work and destroyed 46 files. They were untracked and unstaged, so they had never entered git's object store and were unrecoverable. Branches survived, so committed history was fine; the uncommitted deltas were not.

The safety function itself is well built (checks dirty, unpushed, unmerged; refuses on any). It simply never ran.

Why scout goes

A scout's worktree is a real git worktree, so every check below the exemption applies to it. The stated rationale, that scouts leave scratch behind, is already covered by the dirty filter's .claude/ and .fm-*-turnend exclusions.

The premise that scouts are read-only is false in practice: a scout lane in our fleet authored an ADR and a guard script, both lost.

Why secondmate stays

This half is load-bearing rather than redundant, and worth stating explicitly so it is not "cleaned up" later.

A secondmate home is a plain directory carrying a .fm-secondmate-home marker, not a git worktree. Every check in the function shells out to git -C "$WT", which fails on a non-repo and correctly fail-safes to REFUSED. Removing this exemption makes every secondmate teardown impossible. tests/fm-secondmate-safety.test.sh catches it immediately ("teardown failed for empty secondmate home").

There is no uncommitted git state there for these checks to protect.

Also

The same exemption guarded post_lock_cleanup_check, the recheck that catches work written between the first safety check and the treehouse return that resets the worktree. Leaving it would have kept the hole open on the lock path. secondmate never reaches that branch, since the elif above it already excludes it, so no exemption is needed there.

--force remains the explicit escape hatch in both places.

Tests

The exemption survived because it was never tested: tests/fm-teardown.test.sh was 1,405 lines with zero occurrences of scout or secondmate.

  • test_scout_dirty_worktree_refuses reproduces the incident against the old code exactly: exit 0, empty stderr, worktree torn down with an uncommitted edit present.
  • test_scout_scratch_only_worktree_tears_down pins the exemption's original rationale, so a scout holding only agent scratch still tears down clean.

Reaching the dirty check as a scout means satisfying two earlier scout gates first (data/<id>/report.md, and decisions_reviewed=1). Those are about the work product, not the worktree, which is why they are not a substitute for this check.

There is deliberately no secondmate twin: a secondmate refuses earlier on the seeded-home check, so such a case would pass with or without the exemption and would only look like coverage.

tests/fm-teardown.test.sh: 34/34, up from 32.

Full suite on this branch shows no new failures. Note that tests/fm-secondmate-safety.test.sh currently fails on macOS at origin/main for an unrelated reason: bin/fm-brief.sh has not parsed under bash 3.2 since #945, which I am happy to send as a separate PR.

validate_worktree_teardown_safety() returned 0 before any check ran for
KIND=secondmate|scout. On 2026-07-26 a teardown sweep across 104 worktrees
hit 11 that held uncommitted work and destroyed 46 files. The files were
untracked and unstaged, so they were never in git's object store and are
unrecoverable.

Drop the scout half. A scout's worktree is a real git worktree, so every
check applies to it, and the exemption's stated rationale (scouts leave
scratch behind) is already covered by the dirty filter's .claude/ and
.fm-*-turnend exclusions. The premise that scouts are read-only was false
in practice: a scout lane authored ADR 0058 and a guard script.

Keep the secondmate half. It is load-bearing, not redundant: a secondmate
home is a plain directory with a .fm-secondmate-home marker rather than a
git worktree, so the git-based checks fail on it and fail-safe to REFUSED.
Removing it makes every secondmate teardown impossible.

Also drop the same exemption from the post-lock-cleanup recheck, which is
what catches work written between the first safety check and the treehouse
return that resets the worktree. secondmate never reaches that branch.

--force remains the escape hatch in both places.

The exemption survived because it was never tested: fm-teardown.test.sh
had 1,405 lines and zero occurrences of scout or secondmate. Against the
old code the new test reproduces the incident exactly, exit 0 with empty
stderr. A companion case pins the original rationale so scratch-only
scouts still tear down clean. There is deliberately no secondmate twin: a
secondmate refuses earlier on the seeded-home check, so such a case would
pass with or without the exemption and would only look like coverage.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V5bvMEeW6SqECT3kg4Utry

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8fbbe9087c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread bin/fm-teardown.sh
# --force remains the explicit escape hatch.
case "$KIND" in
secondmate|scout) return 0 ;;
secondmate) return 0 ;;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the landed-work exemption for scout commits

Captain, when a completed scout has clean local scratch commits but no remote branch or merged PR, removing scout from this return sends it through the unpushed/landed checks and refuses cleanup even after its report and decision gate are complete. Scout worktrees are explicitly disposable after those gates, and promotion is expected to leave scratch commits behind, so run the dirty-state check for scouts but return before applying ship-style commit landing checks.

AGENTS.md reference: AGENTS.md:L324-L328

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant