Two silent gates

Both shipped green. Both were invisible to the test suite that covered them.

Bug 1 · mapfile in a #!/bin/bash script

bin/git-hooks/pre-push:242 · introduced by d45e560d0

mapfile is a bash 4+ builtin. The shebang is #!/bin/bash, which on macOS is the bundled 3.2.57. Pick the interpreter:

The early branch-prefix check exits 0 for docs|chore|ci|style|test|feat|fix|perf|refactor|issue|bug, so those branches never reach line 242. Only feature/, release/, hotfix/ and bare names were blocked. That narrow blast radius is why it survived.

Bug 2 · a typo'd hook key read as allow

tests/fixtures/test-helpers.sh:327 · introduced by 7c4d56b62

The docstring promised a misnamed key surfaces as ERROR. Try a key:

assert_hook_registered() already detected this correctly. It was simply never called. The fix wires it into hook_decision(), so expect_decision() inherits it. Impact today is zero (no callers yet), which is exactly why it would have bitten the next contributor instead.

Why the existing tests missed both

TestAssertsCatches bug 1?
1 run_with_timeout exit codesexit-code passthroughno
2 CHANGELOG capturevariable captureno
3 args with spacesquotingno
4 skip-regex parityhook vs ci.yml regexno
5a no bash-4 builtins (new)static scan of the fileYES
5b /bin/bash -n parses (new)syntax onlyno *
5c discovery yields > 0 (new)environment checkno *

* Honest: 5b passes on the buggy file because mapfile is a runtime failure, not a syntax error. 5c re-implements the loop rather than executing the hook's own block. 5a is the only load-bearing assertion.

with fix .....  11 passed, 0 failed
with bug .....  10 passed, 1 failed   <-- 5a
restored .....  11 passed, 0 failed

Verification actually run

/bin/bash --version        GNU bash, version 3.2.57(1)-release (arm64-apple-darwin25)
git config core.hooksPath  bin/git-hooks          (this IS the live hook)
mapfile under 3.2          command not found, count=0
discovery after fix        60 files, bash 3.2
/bin/bash -n pre-push      syntax OK
hook_decision fake key     before: allow    after: ERROR
hook_decision real key     after:  allow    (unchanged)
shellcheck -S error        clean
npm test                   24 categories passed, 0 failed, exit 0
advisory warnings          267 (baseline 267)