On macOS /dev/tty always exists, so '[ -e /dev/tty ]' passed even in agent
harnesses/CI with no controlling terminal — the subsequent read then died
with ENXIO ('Device not configured') and blocked the commit instead of taking
the hook's own non-interactive branch. Probe with '( : < /dev/tty )' — the
exact operation that fails. Both prompt sites fixed; the deliberate asymmetry
preserved (debug keywords warn-and-proceed; secrets fail closed). Verified
both paths from a non-TTY context. Surfaced via the be a11y-gate commit
bypass logged in today's ledger.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The four hooks (post-checkout, post-commit, post-merge, pre-push)
were generic git-lfs boilerplate that called 'git lfs <action>' for
each event. Under the global core.hooksPath, they required git-lfs
on PATH at every git invocation — which broke under launchd's
stripped PATH (discovered 2026-04-16 while fixing gitvault).
A repo that actually uses LFS can install its local hooks via
'git lfs install' within the repo (.git/hooks/*). The global
hookspath shouldn't require LFS to be present.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The prior hook piped staged filenames through xargs grep, scanning the
entire current file content. This produced false positives whenever a
modified file contained pre-existing TODO/FIXME/XXX markers anywhere —
even if the staged change did not touch those lines. Six --no-verify
bypasses accumulated in two days as a result: the commits were not
introducing any new TODO markers; they simply modified files that had
template or documentary use of those tokens.
Fix:
- Collect added lines from the staged diff once (git diff --cached -U0,
filtered to lines starting with + and excluding +++ file headers)
- Scan that set for debugging-keyword and secret patterns
- Pre-existing content in modified files no longer triggers the hook
Also:
- Show the matched lines when warning (previously the hook said
"Found debugging keywords" without indicating which)
- Read from /dev/tty explicitly so interactive prompts work even when
stdin is closed by the commit driver
- Non-interactive contexts: proceed on TODO warnings (least invasive);
block on secret matches (most invasive); in both cases state clearly
what's happening
--no-verify is used on this commit only because the hook file itself
contains the literal scan patterns (TODO:, FIXME:, XXX:) inside its
grep regex. The new hook's scan of added lines therefore matches its
own source at commit time — a one-time bootstrap issue. This should be
the LAST --no-verify in this pattern. Future commits with legitimate
no-TODO-marker changes will pass cleanly; future commits that genuinely
introduce new TODO markers will correctly prompt for confirmation.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>