fix(wake): three-valued grep verdicts — has_match/count_lines across all ten suites (closes #973) (#983)
ci/woodpecker/push/publish Pipeline was successful
ci/woodpecker/push/ci Pipeline was successful

This commit was merged in pull request #983.
This commit is contained in:
Mos
2026-07-31 08:39:04 +00:00
parent 089615f63b
commit 4fb44f6345
18 changed files with 4855 additions and 262 deletions
@@ -191,3 +191,177 @@ _wake_init_dir() {
[ -f "$dir/pending.jsonl" ] || printf '' | _atomic_write "$dir/pending.jsonl"
[ -f "$dir/ack-ledger.jsonl" ] || printf '' | _atomic_write "$dir/ack-ledger.jsonl"
}
# ---------------------------------------------------------------------------
# #973 — three-valued grep assertion helpers for the wake test suites.
#
# grep's exit contract is three-valued: 0 = match, 1 = no match, >1 = ERROR
# (bad file, bad pattern, resource failure). Every wake-suite assertion used
# to read all non-zero as "absent", so a grep that COULD NOT LOOK wore the
# colour of a verdict: OR-polarity sites (`|| fail`) went falsely red,
# AND-polarity sites (`&& fail` — including the credential canaries) went
# falsely green. The repair is to refuse to answer: 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.
#
# Production tools (store.sh, ack.sh) source this file but call none of the
# helpers below; they are inert outside the suites.
#
# Suite integration contract:
# - Call `wake_assert_init` ONCE at suite top level, right after sourcing.
# It dups the suite's real stderr to a saved fd BEFORE any call-site
# redirect exists, so an abort stays loud even at sites that append
# `2>/dev/null` (the preimage credential canaries pre-swallow stderr —
# exactly where a silent abort would recreate the defect being fixed).
# - Assertion sites live inside `( ... ) && ok` subshell blocks, pipelines,
# and `$(...)` substitutions, where a plain `exit` dies one layer deep and
# the suite would carry on to emit a verdict. The abort therefore signals
# the suite's MAIN shell ($$ is the main PID in every subshell) and then
# exits the current context: the suite dies by signal, non-zero, with NO
# verdict line emitted.
#
# Validation instrumentation (#973 evidence, not part of the assertion fix):
# - WAKE_ASSERT_LEDGER=<file>: every helper call appends
# "<helper> <caller-file>:<caller-line>" to <file>. That is the ONLY
# divergence from production behaviour — the suite otherwise runs its
# normal arms, so a validate run exercises exactly the shipped paths.
# - WAKE_ASSERT_FORCE_GREP_ERROR_AT=<caller-file>:<caller-line>: at exactly
# that call site, the invocation is routed through a REAL grep driven onto
# its real error path (unknown option -> rc 2) — a genuinely executed
# failing process, not a stubbed return — to prove per-site that the abort
# fires. Unset in production; matching no site is a no-op.
# ---------------------------------------------------------------------------
# wake_assert_init — dup the suite's real stderr once, for abort loudness.
# MUST be called at suite TOP LEVEL, immediately after sourcing and before any
# test block: a lazy (first-call) dup could capture an already-redirected
# stderr if the first executed helper call sat under a call-site 2>/dev/null,
# silencing every abort thereafter. The fd is allocated dynamically (>= 10),
# so it cannot collide with the wake lock fds (8) or the detector run-loop
# lock (9).
#
# Init also PINS the BASH_LINENO convention the site coordinates depend on:
# a helper call written across a backslash continuation must report at its
# FIRST physical line (the denominator artifact's convention). That was
# measured on a developer bash (5.3.x); CI runs whatever bash its base image
# baked in, and that version floats silently between image rebuilds. A bash
# that disagrees would shift every continuation-site coordinate by one line
# UNDER the validation instead of in front of it — so the convention is
# asserted at runtime, in the same bash binary that runs the suite, and a
# disagreeing bash aborts the suite loudly instead of skewing coordinates.
_wake_assert_lineno_pin() {
local _wa_pin_tmp _wa_pin_got
_wa_pin_tmp="$(mktemp)" || {
_wake_assert_err_note "WAKE-ASSERT INIT ABORT: mktemp failed; cannot pin the BASH_LINENO convention — a pin that silently does not run is not a pin (#973)"
exit 97
}
cat >"$_wa_pin_tmp" <<'WAKE_ASSERT_PIN'
_wap() { printf '%s\n' "${BASH_LINENO[0]}"; }
(
_wap simple
_wap \
continuation
)
WAKE_ASSERT_PIN
# WAKE_ASSERT_PIN_BASH: test-only interpreter override so the pin's abort
# arm can be PROVEN to fire (microtest C10) — bash resets $BASH at startup,
# so the real probe interpreter cannot be spoofed from the environment.
_wa_pin_got="$("${WAKE_ASSERT_PIN_BASH:-${BASH:-bash}}" "$_wa_pin_tmp" 2>/dev/null)"
rm -f "$_wa_pin_tmp"
if [ "$_wa_pin_got" != "$(printf '3\n4')" ]; then
_wake_assert_err_note "WAKE-ASSERT INIT ABORT: BASH_LINENO convention violated on bash ${BASH_VERSION}: probe reported [${_wa_pin_got:-<no output>}], expected [3 4] (simple call at own line, continuation call at FIRST physical line) — site coordinates are untrustworthy on this bash (#973)"
exit 97
fi
}
wake_assert_init() {
if [ -z "${_wake_assert_err_fd:-}" ]; then
exec {_wake_assert_err_fd}>&2
_wake_assert_lineno_pin
fi
}
# _wake_assert_err_note MSG — write MSG to the saved real-stderr fd, falling
# back to the current stderr if init was never called.
_wake_assert_err_note() {
if [ -n "${_wake_assert_err_fd:-}" ]; then
printf '%s\n' "$1" >&"$_wake_assert_err_fd" 2>/dev/null ||
printf '%s\n' "$1" >&2
else
printf '%s\n' "$1" >&2
fi
}
# _wake_assert_abort HELPER SITE RC ARGS... — refuse to answer, loudly.
# Writes the named reason to the saved real-stderr fd (falling back to the
# current stderr), signals the suite's main shell, and exits this context.
_wake_assert_abort() {
local _wa_helper="$1" _wa_where="$2" _wa_code="$3"
shift 3
_wake_assert_err_note "WAKE-ASSERT ABORT: ${_wa_helper} at ${_wa_where}: grep exit ${_wa_code} is an error, not a verdict (args: $*) — refusing to answer (#973)"
if [ -n "${BASHPID:-}" ] && [ "$BASHPID" != "$$" ]; then
kill -TERM "$$" 2>/dev/null || true
fi
exit 97
}
# _wake_assert_armed SITE — true iff the forced-error arm targets SITE; on a
# match it emits a positive confirmation FIRST, so "site did not abort" can
# never conflate SITE NOT CONVERTED with ARM NEVER REACHED IT: an armed run
# with no ARMED line means the arm matched nothing (typo/renumber/drift), and
# an ARMED line with no abort means the site's error path is broken. The two
# defects are separable on stderr alone.
_wake_assert_armed() {
[ "${WAKE_ASSERT_FORCE_GREP_ERROR_AT:-}" = "$1" ] || return 1
_wake_assert_err_note "WAKE-ASSERT ARMED: forcing real grep error at $1 (#973)"
return 0
}
# has_match GREP_ARGS... — three-valued grep verdict.
# Drop-in for verdict-bearing `grep` calls (flags, files, stdin all pass
# through; stdout is not captured, so extract-form call sites may use it
# inside a substitution). Returns 0 on match, 1 on no-match; any other grep
# exit aborts the suite via _wake_assert_abort.
has_match() {
local _wa_site="${BASH_SOURCE[1]##*/}:${BASH_LINENO[0]}" _wa_rc=0
if [ -n "${WAKE_ASSERT_LEDGER:-}" ]; then
printf 'has_match %s\n' "$_wa_site" >>"$WAKE_ASSERT_LEDGER"
fi
if _wake_assert_armed "$_wa_site"; then
command grep --wake-assert-forced-error -- /dev/null
_wa_rc=$?
else
command grep "$@"
_wa_rc=$?
fi
case "$_wa_rc" in
0) return 0 ;;
1) return 1 ;;
*) _wake_assert_abort has_match "$_wa_site" "$_wa_rc" "$@" ;;
esac
}
# count_lines GREP_ARGS... — `grep -c` with the same three-way discipline.
# Call sites drop their `-c` (the helper supplies it) and keep every other
# argument. Prints the count on rc 0 AND rc 1 (rc 1 is grep's "count is 0" —
# a valid measurement, not an error); any other exit aborts. The abort still
# kills the suite from inside a `$(...)` capture: the substitution subshell
# cannot exit the suite, but the signal to the main shell can — a count from
# a failed measurement is never printed.
count_lines() {
local _wa_site="${BASH_SOURCE[1]##*/}:${BASH_LINENO[0]}" _wa_rc=0 _wa_out=""
if [ -n "${WAKE_ASSERT_LEDGER:-}" ]; then
printf 'count_lines %s\n' "$_wa_site" >>"$WAKE_ASSERT_LEDGER"
fi
if _wake_assert_armed "$_wa_site"; then
_wa_out="$(command grep --wake-assert-forced-error -c -- /dev/null)"
_wa_rc=$?
else
_wa_out="$(command grep -c "$@")"
_wa_rc=$?
fi
case "$_wa_rc" in
0 | 1) printf '%s\n' "$_wa_out" ;;
*) _wake_assert_abort count_lines "$_wa_site" "$_wa_rc" "$@" ;;
esac
}