Skip to content

repo-fleet-hygiene:audit canonical resolution can select a linked worktree, pointing every handoff at the wrong path #1797

Description

@kyle-sexton

Severity: IMPORTANT (assigned by an audit agent; uncalibrated — not re-graded by a human).

Summary

Repository discovery can select a linked worktree as the "Canonical" checkout for a repository,
dropping the real canonical repo from the audit and pointing every emitted handoff at the worktree
path instead.

Mechanism

Discovery walks a root, and when several directories share one Git common directory it deduplicates
them — but the winner is decided by glob order (first wins) with no preference for the main
worktree.

  • skills/audit/scripts/audit-fleet.sh:460-467 — recursive discovery, first-hit-wins per common dir.
  • :433-437 — the dedup keyed on --git-common-dir, no main-worktree test.
  • :1069 — the canonical path emitted into findings and handoffs.

In a ghq layout, sibling worktrees live next to the canonical checkout, so both are reached by the
same glob and both map to the same common-dir key. Whichever the glob reaches first wins.

This is a latent defect, not one observed firing — stated precisely so nobody wastes time on a bad
repro.
In the audited fleet it did not trigger: every sibling was named <canonical>-<suffix>
(ci-workflows-pr281, claude-code-plugins-1285-argparse, standards-pr-223), and a
prefix sorts before its own extensions, so the canonical directory always won. Verified over the real
run: every Canonical: line equalled its discovered path, with Canonical resolution: git-native.

The trigger is a discovered sibling worktree whose directory name sorts before the canonical
directory name under LC_ALL=C. That naming is already in use in this fleet — ccp-1269,
drive-1503-v2, 609, 848-sigfix all sort before claude-code-plugins — they simply live under
~/.claude-loop-worktrees, outside the configured discovery root. Point a --root at a directory
holding worktrees named that way, or adopt a non-prefixed naming scheme, and the canonical checkout is
silently replaced.

The skill's own evidence rule 1 says canonical resolution is "explicit remote-keyed override →
configured remote-keyed override → git rev-parse --show-toplevel". Inside a linked worktree,
--show-toplevel returns the worktree's root, which is exactly the wrong answer — the rule as
written cannot distinguish them.

Why it matters

Every handoff the audit emits carries the canonical path: Run /repo-hygiene:clean git in <path> and
Run /source-control:worktree cleanup --dry-run in <path>. Pointed at a worktree, those handoffs
send a cleanup tool into a checkout that is not the repository of record. git worktree operations
run from a linked worktree affect the shared administrative directory, so this is not merely cosmetic.

It also silently changes what gets audited: the true canonical checkout is deduplicated away, so its
own state is never reported.

Detection

git worktree list --porcelain returns the main worktree first (index 0). That is the
authoritative signal and the collector already calls this command elsewhere, so the fix needs no new
probe.

An equivalent local test: the main worktree has a .git directory; a linked worktree has a .git
file.

Suggested fix

  1. In the dedup, prefer the main worktree — porcelain index 0 — as canonical, rather than first-glob.
  2. Add an eval that constructs a repo whose sibling worktree sorts before the canonical directory and
    asserts the canonical path in the output.
  3. Correct evidence rule 1 in SKILL.md: --show-toplevel alone does not identify a canonical
    checkout.

Blindspot this exposes in how the component is verified

The audit's own reported count was correct (11 repositories, matching 10 .git directories plus one
dotdir), and a count check is what a consumer naturally performs. Cardinality being right is not
identity being right
— nothing in the report or the evals checks which member of a dedup group
won. This defect is invisible to a count-based verification.

Environment

  • repo-fleet-hygiene 0.7.0, marketplace install melodic-software
  • ghq layout, 11 canonical checkouts with 47 sibling worktrees adjacent to them
  • Git 2.54.0.windows.1, Claude Code on Windows 11 Pro 10.0.26200
  • Observed 2026-07-30

Activity

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions