Skip to content

fix: report what the repair took, and fold case on root instruction files - #34

Merged
rmyndharis merged 1 commit into
mainfrom
fix/repair-and-rule-coverage
Aug 12, 2026
Merged

fix: report what the repair took, and fold case on root instruction files#34
rmyndharis merged 1 commit into
mainfrom
fix/repair-and-rule-coverage

Conversation

@rmyndharis

Copy link
Copy Markdown
Owner

The repair took staged work and said nothing

When automatic repair unstages a blocked path, stagedRenameSources also
restores any staged deletion it cannot rule out as the source of a rename Git
did not detect. That sweep is deliberate — the comment at src/gitx.mjs:296
sets out the trade-off, and tests/cli.test.mjs pins the zero-similarity case —
and it stays.

What was missing is that the tool never said so. The summary named only the
blocked paths, and when the index ended up empty it added "nothing else was
staged". That clause was printed on runs where something else had in fact been
staged and had just been taken.

The sharpest shape is git rm --cached legacy.txt alongside a blocked artifact.
Restoring the index entry makes it match HEAD, so git status afterwards is
empty, the file is still tracked, and the developer commits a message describing
an untracking the commit does not carry.

repairStagedBlocks now returns { emptied, collateral }. emptied keeps its
meaning and its derivation. collateral is everything the repair took beyond
the blocked paths. cmdPrecommit names those paths, says why they were taken,
and gives the command to stage the removal again. The empty-index clause no
longer claims nothing else was staged when something was.

Narrowing the sweep itself was considered and dropped. Pairing on blob oid adds
nothing that --find-renames=1% does not already pair, and removing the breadth
reintroduces the committed half-rename the sweep exists to prevent.

Two existing tests asserted the old clause on runs that did have collateral.
They now assert what the run actually did, including the path it restored.

Root instruction files matched case-sensitively

generic.agent-instructions was the only path rule in rules/paths.json
without case folding. On APFS and NTFS claude.md is the same file as
CLAUDE.md, and Git records the case the caller typed, so the guarded spelling
was one keystroke from being skipped — a lost review on clean, a defeated hard
block on strict and compliance.

The root patterns now carry case classes ([Cc][Ll][Aa][Uu][Dd][Ee].[Mm][Dd]
and the rest). globToRegExp already supports character classes, and . is a
literal token, so agentsxmd does not match.

Splitting the rule in two — one case-sensitive, one folded — was the obvious
shape and does not work. Rule ids must be unique, so a split forces a second id,
and reviews bind to exactly one id: aimhooman review AGENTS.md would stop
clearing the block and root instruction files would become unshippable under
strict. Keeping one id keeps the escape hatch.

Patterns deeper in the tree stay case-sensitive. docs/claude.md and
website/content/blog/agents.md are ordinary documentation and keep committing
freely; the near-miss control test covers them.

Tests

The case test now covers four root spellings plus .github/Copilot-Instructions.md,
and adds agentsxmd to the near-misses. A new precommit test stages a
git rm --cached alongside a blocked artifact and asserts the report names the
restored path.

Full suite green, npm run check green.

@rmyndharis rmyndharis changed the title Report what the repair took, and fold case on root instruction files fix: report what the repair took, and fold case on root instruction files Aug 12, 2026
…iles

Automatic repair restores staged deletions it cannot rule out as the source of a
rename Git did not detect. That sweep is deliberate and stays. What was missing
is that it never said so: the summary named only the blocked paths, and when the
index ended up empty it claimed nothing else had been staged. A developer who
had run `git rm --cached legacy.txt` got a clean `git status` afterwards, the
file still tracked, and a commit message describing an untracking the commit did
not carry. The repair now returns what it took beyond the blocked paths, names
those paths with the reason, and gives the command to stage the removal again.
Two tests asserted the old claim on runs that did have collateral; they now
assert what the run actually did.

Root instruction files also matched case-sensitively while every sibling path
rule folds case. On APFS and NTFS `claude.md` is the same file as `CLAUDE.md`,
so the guarded spelling was one keystroke from being skipped. The root patterns
now carry case classes. Paths deeper in the tree stay case-sensitive, where
these names are ordinary documentation.
@rmyndharis
rmyndharis force-pushed the fix/repair-and-rule-coverage branch from c5aff1c to b447d6f Compare August 12, 2026 09:40
@rmyndharis
rmyndharis merged commit 4fc28f3 into main Aug 12, 2026
8 checks passed
@rmyndharis
rmyndharis deleted the fix/repair-and-rule-coverage branch August 12, 2026 10:01
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