How a scratch file turned 171 hooks into 150

count-hooks.sh redirected grep's stderr into a file from a bare mktemp. Deny that one write and the count silently shrinks. Toggle the two conditions to walk the chain.

conditions

Why rc=1 is the trap

The function must treat "no match" as zero, because zero agent-scoped hooks is a legitimate state since #3461 removed all 45 of them:

if [ "$rc" -ge 2 ]; then   # real error, fail loudly
    ...
fi
# rc of 0 or 1 falls through and counts

A failed redirect also produces rc=1. So the one code path deliberately kept quiet is the exact path a broken scratch file lands on. The guard was correct; the thing it depended on was not guarded.

Verification note

The obvious repro reports success and hides the bug:

$ TMPDIR=/unwritable mktemp
/var/folders/7v/.../T/tmp.iGOVlVqii5   <-- TMPDIR ignored

macOS mktemp with no template ignores TMPDIR. Driving this needs a real denial of /var/folders or a PATH shim, which is what the regression test uses.

Measured

scriptmktempoutput
origin/mainhealthyGLOBAL=150 AGENT=0 SKILL=21 TOTAL=171
origin/maindeniedGLOBAL=150 AGENT=0 SKILL=0 TOTAL=150
fixeddeniedGLOBAL=150 AGENT=0 SKILL=21 TOTAL=171
The scratch file only ever carried an error message. It now degrades to "stderr not captured" instead of taking the count with it, and tests/ci/test-count-hooks-temp-failure.sh asserts the counts are identical with and without a writable temp dir. Issue #3564.