has_match/count_lines in _wake-common.sh: rc 0 -> match, rc 1 -> no-match,
anything else -> loud abort naming the call site, the raw exit code, and the
arguments — an error never becomes a verdict. The abort escapes subshells,
pipelines, and $() substitutions by signalling the suite's main shell, so
the suite dies verdict-less; loudness survives call-site 2>/dev/null via a
wake_assert_init-saved stderr fd (dynamically allocated >= 10, no collision
with the wake lock fd 8 or detector run-loop fd 9).
Validate instrumentation (evidence only, inert in production):
WAKE_ASSERT_LEDGER appends "<helper> <file>:<line>" BEFORE the grep runs, so
an aborting site's row has already landed and the counted ledger can never
go quiet in the one condition it exists to report.
WAKE_ASSERT_FORCE_GREP_ERROR_AT=<file>:<line> routes exactly that call site
through a REAL grep driven onto its real error path (rc 2) and emits a
positive ARMED confirmation first, so arm-never-matched (no ARMED line) and
error-path-broken (ARMED line, no abort) are separable on stderr alone.
validate-973/microtest-wake-assert.sh: nine checks (C1..C9) proving the
instrument before any conversion trusts it — ledger set equality across two
files, truncation detection behind an early exit, per-shape abort proofs
(subshell, 2>/dev/null canary shape, $() count capture, pipeline tail),
count-of-zero on grep rc 1, env-prefix reaching the grep child, and a
no-match arm loud by omission. All nine pass; C1 pins BASH_LINENO's
first-physical-line convention for backslash continuations, matching the
denominator artifact's coordinates.
Production tools (store.sh, ack.sh) source this file but call none of the
new helpers.
Written-by: pepper (sb-it-1-dt)
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NsKce8iZuSuRnu3gVMCBKB