Skip to content

repo-fleet-hygiene: reclaimable-worktree rests on git status alone, so ignored files are destroyed without warning #2601

Description

@kyle-sexton

Context: #2597

Problem

reclaimable-worktree rests entirely on git status --porcelain being empty at the worktree root, and its evidence line says exactly that. But git status --porcelain cannot see ignored files, and removing a worktree directory destroys them. The finding's stated evidence does not cover the content most likely to be lost.

Evidence

263 reclaimable-worktree findings were emitted in one run. Independent verification re-ran git status --porcelain on a sample of 8 and confirmed all 8 genuinely empty — the finding is accurate as stated. Checking --ignored on the same sample found:

  • …/songwriting-enable-plugin — ignored .claude/observability/ and .work/handoffs/, i.e. session handoff files, plausibly irreplaceable
  • …/chezmoi-worktrees/352-bump-markdownlint-cli2 — ignored node_modules/ only, harmless
  • the remaining 6 — nothing ignored

So the loss vector is real but not universal, which is precisely why it needs to be surfaced per worktree rather than assumed either way.

Two related facts, both verified, that bound this issue:

  • Stashes are not a loss vector. refs/stash lives in the common gitdir (git-worktree REFS: all refs/ are shared except refs/bisect, refs/worktree, refs/rewritten), so git stash list from a linked worktree returns the repository's stack. Removing a worktree directory cannot orphan a stash. The skill's decision to scope stashes out is correct — but the wording should say why, because as written it reads like an acknowledged gap.
  • Uncommitted working-tree content is the only true data loss on removal. Index, per-worktree HEAD reflog, and config.worktree survive a directory removal and are destroyed later by prune, not by the removal itself.

Proposed change

  • Extend the evidence gathering to git status --porcelain --ignored and surface the ignored entries in the finding.
  • Classify well-known regenerable paths (node_modules/, target/, .venv/, bin/, obj/, dist/) separately from everything else, so the signal is not drowned by build output.
  • A worktree whose only ignored content is regenerable keeps its current disposition; one with non-regenerable ignored content is reported as such and is not offered for directory removal without naming what will be destroyed.
  • Amend the stash wording to state that stashes are repository-global and therefore unaffected by worktree removal, rather than merely out of scope. Check git stash list once per repository, never per worktree — every worktree reports the same shared stack, and doing it per worktree implies an isolation that does not exist.

Acceptance criteria

  • Every reclaimable-worktree finding names its ignored entries or states that there are none.
  • Non-regenerable ignored content downgrades or annotates the finding rather than being invisible.
  • The skill's stash wording explains the shared-stack mechanism.
  • Stash state is collected once per repository.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions