fix(git): push-guard — resolve re-review blockers; mutation table now generated
ci/woodpecker/pr/ci Pipeline was successful

Authored by installer-7; committed by mos-claude (no credential for this remote).

BLOCKER 1 — verify-clean-clone.sh had B1's own defect: it copied WORKING-TREE files into a
  scratch repo and asserted the SCRATCH index, so a stale local exec bit was laundered in and it
  reported success while the committed artifact was still 100644. v2 reads mode from 'git ls-tree'
  of the SOURCE COMMIT and runs from 'git clone --no-local --no-hardlinks' of that commit; there is
  no 'cp' in the file. Proven by A/B against one laundered repo: v1 EXIT=0, v2 EXIT=1 (both observed,
  not asserted). New test-verify-clean-clone.sh 6/6, incl. a fixture that first proves it really is
  git=100644 disk=755 before testing it.
BLOCKER 2 — empty-merge needle + non-empty-merge control, both asserting on OUTPUT; the fixture
  first proves it IS a merge with a tree identical to both parents.

The 'non-blocking' README item was not documentation: regenerating its mutation table (now generated
by mutate-push-guard.sh, not hand-numbered) found TWO genuinely surviving mutants against a 46/46
green suite — staged-but-uncommitted opt-out honoured, and unparseable committed config ignored.
Both still exit 6 under mutation because control falls to a SIBLING refusal, so an exit-code-only
assertion would have been satisfied by the wrong branch. It also found a live instance of the
substring-anchor defect already in the suite: three branches print 'OPT-OUT IS NOT REVIEWABLE', so
deleting one let the needle RE-POINT to a sibling instead of failing. Re-anchored.
Suite 44 -> 46. Verifier 6/6. 13 mutants, 0 survived.

Also: README reformatted to satisfy 'pnpm format:check' (prettier), which was failing CI at both
prior heads — a gate neither author nor reviewer had exercised.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YKj59Qadrb2WBLaePvkM7H
This commit is contained in:
installer-7
2026-07-30 21:06:55 -05:00
co-authored by Claude Opus 5
parent b0fb208b89
commit 8310075d33
5 changed files with 497 additions and 107 deletions
@@ -508,8 +508,44 @@ R="$(new_repo e2)"
write_config_untracked "$R" '{"json_check": "none", "reason": "local unreviewed bypass"}'
mkdir -p "$R/data"; printf '{ not json' > "$R/data/bad.json"
git -C "$R" add -f data/bad.json
# The anchor is the DISTINGUISHING clause, not the shared headline. Three
# separate branches print "OPT-OUT IS NOT REVIEWABLE" — untracked, staged-not-
# committed, and symlink. Anchoring on the headline means this needle stays green
# if the untracked branch is deleted and control falls through to a SIBLING that
# prints the same words: a substring anchor does not fail when its subject is
# removed, IT RE-POINTS. Anchor on the clause only this branch can produce.
expect NEEDLE 6 "an UNTRACKED opt-out is refused as unreviewable" \
--out "OPT-OUT IS NOT REVIEWABLE" -- \
--out "is not tracked in git" -- \
bash -c "cd '$R' && '$GUARD' check-staged"
# STAGED BUT NOT COMMITTED. Found by mutation, not by review: `if [[ -z "$cmode" ]]`
# survived `if false` against a 44/44 green suite, because no case ever built this
# state. Note the mutant still exits 6 — control falls to the LOCAL-ONLY branch
# below and refuses for a different reason. An exit-code-only assertion here would
# be satisfied by the wrong branch, which is why --out carries the distinguishing
# clause. `git add` puts the file in the index, so ls-files matches while HEAD
# does not: staged review is not review.
R="$(new_repo e2b)"
write_config_untracked "$R" '{"json_check": "none", "reason": "staged, never committed"}'
git -C "$R" add .push-guard.json
mkdir -p "$R/data"; printf '{ not json' > "$R/data/bad.json"
git -C "$R" add -f data/bad.json
expect NEEDLE 6 "a STAGED-but-uncommitted opt-out is refused" \
--out "staged but not yet in HEAD" -- \
bash -c "cd '$R' && '$GUARD' check-staged"
# COMMITTED CONFIG DOES NOT PARSE while the working tree opts out cleanly. Also a
# mutation survivor. The working-tree config is valid, so the early config check
# passes and we reach the re-read; the committed object is what fails. Without
# this branch an opt-out could be honoured on the strength of a HEAD blob nobody
# can actually read a decision out of.
R="$(new_repo e2c)"
write_config "$R" '{ this is not json'
printf '%s\n' '{"json_check": "none", "reason": "valid here, broken in HEAD"}' > "$R/.push-guard.json"
mkdir -p "$R/data"; printf '{ not json' > "$R/data/bad.json"
git -C "$R" add -f data/bad.json
expect NEEDLE 6 "an UNPARSEABLE committed config cannot authorise an opt-out" \
--out "is INVALID" -- \
bash -c "cd '$R' && '$GUARD' check-staged"
# A committed ON silently flipped OFF in the working tree is the same bypass.
@@ -580,6 +616,44 @@ expect CONTROL 0 "a NON-empty root commit still pushes" \
--out "non-empty root commit" -- \
bash -c "cd '$R' && '$GUARD' push --remote origin --branch fresh2"
# THE MERGE BRANCH HAD NO NEEDLE AT ALL. It was defined, hand-verified, and
# shipped -- and deleting the refusal left the suite at 41/41 green. Defining
# semantics is not testing them, and an untested branch is indistinguishable
# from an absent one to everyone downstream.
# EMPTY MERGE: two branches that each change nothing, merged. The merge tree is
# then identical to EVERY parent -- it integrates nothing and introduces nothing.
R="$(new_repo e9)"
git -C "$R" checkout -q -b mx
git -C "$R" commit -q --allow-empty -m "x: no tree change"
git -C "$R" checkout -q -b my HEAD~1 2>/dev/null || git -C "$R" checkout -q -b my
git -C "$R" commit -q --allow-empty -m "y: no tree change"
git -C "$R" checkout -q mx
git -C "$R" merge -q --no-ff --no-edit my
# PROVE THE FIXTURE IS ACTUALLY AN EMPTY MERGE before asserting on it, or the
# needle passes for the wrong reason on a repo that never made a merge at all.
np="$(git -C "$R" rev-list --parents -n 1 HEAD | wc -w)"
if (( np > 2 )) && git -C "$R" diff --quiet HEAD^1 HEAD && git -C "$R" diff --quiet HEAD^2 HEAD; then
printf ' ok [%-14s] fixture is a merge (%d fields) with tree identical to both parents\n' "e9-fixture" "$np"; PASS=$(( PASS + 1 ))
else
printf ' FAIL [%-14s] fixture is not an empty merge -- needle would be vacuous\n' "e9-fixture"; FAIL=$(( FAIL + 1 ))
fi
expect NEEDLE 5 "an EMPTY MERGE is refused, not exempted" \
--out "EMPTY MERGE" -- \
bash -c "cd '$R' && '$GUARD' push --remote origin --branch mx"
# CONTROL: a merge that really integrates must still push. Both sides add a
# distinct file, so the merge tree differs from BOTH parents.
R="$(new_repo e10)"
git -C "$R" checkout -q -b nx
printf 'from x\n' > "$R/x.txt"; git -C "$R" add x.txt; git -C "$R" commit -q -m "x adds a file"
git -C "$R" checkout -q -b ny HEAD~1
printf 'from y\n' > "$R/y.txt"; git -C "$R" add y.txt; git -C "$R" commit -q -m "y adds a file"
git -C "$R" checkout -q nx
git -C "$R" merge -q --no-ff --no-edit ny
expect CONTROL 0 "a NON-empty merge commit still pushes" \
--out "non-empty merge commit" -- \
bash -c "cd '$R' && '$GUARD' push --remote origin --branch nx"
echo
printf 'push-guard needles: %d passed, %d failed\n' "$PASS" "$FAIL"
(( FAIL == 0 )) || exit 1