Skip to content

A staged rename of a decision file clears the commit gate: -U0 with a pinned pathspec renders it as a whole-file add #335

Description

@thrillmot

gitcli.DiffCachedAddedHunks runs git diff --cached -U0 -- <path>. With the pathspec pinned to one side, git renders a rename as a whole-file add — so every pre-existing entry in the renamed file reads as newly added, and the gate sees a well-formed decision that this change did not write.

Measured

Binary built from feat/collapse-decision-layout, hook installed, built binary first on PATH:

git mv docs/decisions-branches/feat__rn.md docs/decisions-branches/feat__renamed.md
+ 401 lines of new Go
guard-commit --layer git-hook  →  exit 0   ✓ allowed (decision-recorded)

Control, same tree without the rename → exit 65.

Not a regression

git show main:internal/guardcommit/guardcommit.go:177-179 allowed on the staged path alone, so main passes this too. The hunk-based predicate that replaced it did not introduce the hole; it inherited it from the reader beneath. Filing rather than fixing in the PR that found it, because the PR's own change is verified correct and this is a layer down.

Why it is worth fixing anyway

The gate already ships two documented one-line bypasses — [skip-logmind] and LOGMIND_ALLOW_GIT_COMMIT=1. Both are deliberate, scoped to one commit, and visible in the log. This one is none of those: it is silent, it looks like ordinary refactoring, and renaming a decision file is a plausible thing to do while making a substantive change.

It also interacts with the zero-conflict invariant: branch decision files are named after the branch, so a branch rename is exactly when a decision file gets renamed.

Done when

  • A staged rename does not present the renamed file's pre-existing content as added.
  • The fix is in the reader, not in each caller — DiffCachedAddedHunks and DiffRangeAddedHunks share this.
  • Mutation-tested: the rename case blocks, and a genuine entry added in the same commit as a rename still passes.
  • Control the fix against a plain add and a plain modify so the reader has not simply become blind.

Found by the round-17 adversarial panel on #301, which returned MERGE on everything the PR itself changed.

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

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions