diff --git a/packages/mosaic/framework/tools/wake/_wake-common.sh b/packages/mosaic/framework/tools/wake/_wake-common.sh index 5bdb16c7..ad7b2342 100755 --- a/packages/mosaic/framework/tools/wake/_wake-common.sh +++ b/packages/mosaic/framework/tools/wake/_wake-common.sh @@ -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=: every helper call appends +# " :" to . 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=:: 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:-}], 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 +} diff --git a/packages/mosaic/framework/tools/wake/manifest.txt b/packages/mosaic/framework/tools/wake/manifest.txt index 557772b6..2cc8e37f 100644 --- a/packages/mosaic/framework/tools/wake/manifest.txt +++ b/packages/mosaic/framework/tools/wake/manifest.txt @@ -465,8 +465,26 @@ # never a hand-built flat dead-letter row, which would make the # audit's correct non-conviction look exactly like the defect # under hunt (the #951 review's false-defect near-miss). +# 0.7.2 #973 three-valued grep verdicts across ALL TEN wake test suites. +# grep's exit contract is three-valued (0 match / 1 no-match / +# >=2 ERROR); every suite assertion read non-zero as "absent", +# so a grep that COULD NOT LOOK wore the colour of a verdict — +# OR-polarity sites failed falsely RED, AND-polarity sites +# (including all 19 credential canaries) failed falsely GREEN +# under load. _wake-common.sh gains has_match/count_lines +# (rc 0/1 pass through; anything else LOUDLY ABORTS the whole +# suite naming file:line + raw rc — an error is never a +# verdict), wake_assert_init (saved-fd abort loudness that +# survives call-site 2>/dev/null + a runtime pin of the +# BASH_LINENO coordinate convention against CI bash drift), +# and 261 call sites converted mechanically from a frozen +# denominator artifact. Production tools source but never call +# the helpers; suite verdict semantics on rc 0/1 are UNCHANGED. +# Evidence chain in validate-973/ (microtest C1-C11, expected/ +# static/trace set arithmetic, 21 forced-error arms, residual +# sweep with per-form plants). component=wake -version=0.7.1 +version=0.7.2 # Watch-list schema this component consumes, and the INCLUSIVE range of # schema_version values it supports. A wake-watch-list.json whose schema_version diff --git a/packages/mosaic/framework/tools/wake/test-wake-beacon.sh b/packages/mosaic/framework/tools/wake/test-wake-beacon.sh index c707acee..69da67cf 100755 --- a/packages/mosaic/framework/tools/wake/test-wake-beacon.sh +++ b/packages/mosaic/framework/tools/wake/test-wake-beacon.sh @@ -31,6 +31,9 @@ set -uo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness. +# shellcheck disable=SC1091 +. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init BEACON="$SCRIPT_DIR/beacon.sh" command -v jq >/dev/null 2>&1 || { @@ -129,7 +132,7 @@ echo "== B2: beacon ABSENCE past SLO -> alarm FIRES + ROUTES ==" out="$("$BEACON" check --slo-seconds 5 2>&1)" rc=$? [ "$rc" -eq 1 ] || fail_msg "B2: a stale-past-SLO beacon must FIRE the absence alarm (exit 1); got $rc [$out]" - echo "$out" | grep -qi 'ALARM FIRED' || fail_msg "B2: absence must announce the alarm fired [$out]" + echo "$out" | has_match -qi 'ALARM FIRED' || fail_msg "B2: absence must announce the alarm fired [$out]" [ -s "$ALARM_OUT" ] || fail_msg "B2: the alarm must actually ROUTE to the sink (payload not written)" jq -e '.kind == "beacon-absence-alarm"' "$ALARM_OUT" >/dev/null 2>&1 || fail_msg "B2: routed payload must be a beacon-absence-alarm [$(cat "$ALARM_OUT" 2>/dev/null)]" # NEVER-received is also an absence (depends on nothing the dying host does). @@ -150,13 +153,13 @@ echo "== B3: unconfigured OR unreachable ALARM target -> FAIL LOUD ==" out="$("$BEACON" check --slo-seconds 5 2>&1)" rc=$? [ "$rc" -eq 3 ] || fail_msg "B3a: unconfigured alarm target must FAIL LOUD (exit 3); got $rc [$out]" - echo "$out" | grep -qi 'silent no-alarm host' || fail_msg "B3a: the failure must name the silent-no-alarm-host hazard [$out]" + echo "$out" | has_match -qi 'silent no-alarm host' || fail_msg "B3a: the failure must name the silent-no-alarm-host hazard [$out]" # (b) UNREACHABLE alarm sink (non-zero exit). export WAKE_ALARM_SINK_CMD="false" out2="$("$BEACON" check --slo-seconds 5 2>&1)" rc2=$? [ "$rc2" -eq 3 ] || fail_msg "B3b: unreachable alarm target must FAIL LOUD (exit 3); got $rc2 [$out2]" - echo "$out2" | grep -qi 'UNREACHABLE' || fail_msg "B3b: the failure must name the unreachable target [$out2]" + echo "$out2" | has_match -qi 'UNREACHABLE' || fail_msg "B3b: the failure must name the unreachable target [$out2]" ) && ok echo "== B4: isolated host -> DEGRADED different-supervision-root beacon FLAGGED ==" @@ -169,8 +172,8 @@ echo "== B4: isolated host -> DEGRADED different-supervision-root beacon FLAGGED rc=$? err="$(cat "$TMP_ROOT/b4.err")" [ "$rc" -eq 0 ] || fail_msg "B4: a different-supervision-root emit must still succeed (exit 0); got $rc [$out][$err]" - echo "$err" | grep -qi 'DEGRADED' || fail_msg "B4: a different-supervision-root beacon must be FLAGGED degraded on stderr [$err]" - echo "$out" | grep -q 'degraded=true' || fail_msg "B4: emit must NOT silently present a degraded beacon as healthy (degraded=true expected) [$out]" + echo "$err" | has_match -qi 'DEGRADED' || fail_msg "B4: a different-supervision-root beacon must be FLAGGED degraded on stderr [$err]" + echo "$out" | has_match -q 'degraded=true' || fail_msg "B4: emit must NOT silently present a degraded beacon as healthy (degraded=true expected) [$out]" ) && ok echo "== B5: same-host-sibling -> REJECTED as non-independent, seq NOT advanced ==" @@ -182,7 +185,7 @@ echo "== B5: same-host-sibling -> REJECTED as non-independent, seq NOT advanced out="$("$BEACON" emit 2>&1)" rc=$? [ "$rc" -ne 0 ] || fail_msg "B5: a same-host-sibling beacon must be REJECTED (non-zero exit) [$out]" - echo "$out" | grep -qi 'not an independent' || fail_msg "B5: the rejection must explain it is NOT an independent leg [$out]" + echo "$out" | has_match -qi 'not an independent' || fail_msg "B5: the rejection must explain it is NOT an independent leg [$out]" # A rejected emit must not have minted a seq (rejection precedes counter bump). seq_after="$("$BEACON" status 2>/dev/null | sed -n 's/^beacon_emitter_seq=//p')" [ "${seq_after:-0}" -eq 0 ] || fail_msg "B5: a rejected emit must NOT advance the monotonic seq (got $seq_after)" @@ -201,10 +204,10 @@ echo "== B6: alarm target resolved BY NAME; beacon.sh inlines no endpoint/secret out="$("$BEACON" check --slo-seconds 5 2>&1)" rc=$? [ "$rc" -eq 1 ] || fail_msg "B6: absence via a by-name alarm adapter must fire (exit 1); got $rc [$out]" - head -n1 "$ALARM_OUT" 2>/dev/null | grep -qF "$SECRET_TARGET" || fail_msg "B6: the adapter must resolve+route to the BY-NAME target [$(cat "$ALARM_OUT" 2>/dev/null)]" + head -n1 "$ALARM_OUT" 2>/dev/null | has_match -qF "$SECRET_TARGET" || fail_msg "B6: the adapter must resolve+route to the BY-NAME target [$(cat "$ALARM_OUT" 2>/dev/null)]" # The framework file must NOT inline the endpoint/secret: it only knows a NAME. - grep -qF "$SECRET_TARGET" "$BEACON" && fail_msg "B6: beacon.sh must NOT inline the target endpoint/secret" - grep -qF "$SECRET_TARGET" "$WAKE_ALARM_SINK_CMD" && fail_msg "B6: even the adapter must resolve by-name, not inline the secret" + has_match -qF "$SECRET_TARGET" "$BEACON" && fail_msg "B6: beacon.sh must NOT inline the target endpoint/secret" + has_match -qF "$SECRET_TARGET" "$WAKE_ALARM_SINK_CMD" && fail_msg "B6: even the adapter must resolve by-name, not inline the secret" true ) && ok @@ -218,7 +221,7 @@ echo "== B7: unconfigured OR unreachable BEACON sink on emit -> FAIL LOUD ==" out="$("$BEACON" emit 2>&1)" rc=$? [ "$rc" -eq 3 ] || fail_msg "B7a: unconfigured beacon sink must FAIL LOUD (exit 3); got $rc [$out]" - echo "$out" | grep -qi 'silent no-alarm host' || fail_msg "B7a: the failure must name the silent-no-alarm-host hazard [$out]" + echo "$out" | has_match -qi 'silent no-alarm host' || fail_msg "B7a: the failure must name the silent-no-alarm-host hazard [$out]" # A refused emit (no sink) must not have minted a seq. seq_after="$("$BEACON" status 2>/dev/null | sed -n 's/^beacon_emitter_seq=//p')" [ "${seq_after:-0}" -eq 0 ] || fail_msg "B7a: an unconfigured-sink emit must NOT advance the seq (got $seq_after)" @@ -227,7 +230,7 @@ echo "== B7: unconfigured OR unreachable BEACON sink on emit -> FAIL LOUD ==" out2="$("$BEACON" emit 2>&1)" rc2=$? [ "$rc2" -eq 1 ] || fail_msg "B7b: unreachable beacon sink must FAIL LOUD (exit 1); got $rc2 [$out2]" - echo "$out2" | grep -qi 'UNREACHABLE' || fail_msg "B7b: the failure must name the unreachable sink [$out2]" + echo "$out2" | has_match -qi 'UNREACHABLE' || fail_msg "B7b: the failure must name the unreachable sink [$out2]" ) && ok echo "== B8: no invented SLO -> check --slo-seconds is REQUIRED (fail-loud) ==" @@ -238,7 +241,7 @@ echo "== B8: no invented SLO -> check --slo-seconds is REQUIRED (fail-loud) ==" out="$("$BEACON" check 2>&1)" rc=$? [ "$rc" -eq 3 ] || fail_msg "B8: check without an SLO must fail loud (exit 3); got $rc [$out]" - echo "$out" | grep -qi 'slo' || fail_msg "B8: the usage error must name the missing SLO [$out]" + echo "$out" | has_match -qi 'slo' || fail_msg "B8: the usage error must name the missing SLO [$out]" ) && ok echo "== B9: capture-pane hint is a liveness HINT ONLY (does NOT suppress absence) ==" @@ -267,7 +270,7 @@ echo "== B10: fresh beacon within SLO -> ALIVE (exit 0, no alarm) ==" out="$("$BEACON" check --slo-seconds 60 2>&1)" rc=$? [ "$rc" -eq 0 ] || fail_msg "B10: a fresh beacon within SLO must be ALIVE (exit 0); got $rc [$out]" - echo "$out" | grep -qi 'ALIVE' || fail_msg "B10: a fresh beacon must report ALIVE [$out]" + echo "$out" | has_match -qi 'ALIVE' || fail_msg "B10: a fresh beacon must report ALIVE [$out]" [ ! -s "$ALARM_OUT" ] || fail_msg "B10: a fresh beacon must NOT fire an alarm" ) && ok @@ -291,7 +294,7 @@ echo "== B11: staleness from monitor ingested_ts -> a far-future emit_ts STILL g jq -c --argjson ing "$((now - 100))" '.ingested_ts = $ing' "$WAKE_BEACON_RECEIVED" >"$H/tmp" && mv "$H/tmp" "$WAKE_BEACON_RECEIVED" out="$("$BEACON" check --slo-seconds 5 2>&1)"; rc=$? [ "$rc" -eq 1 ] || fail_msg "B11: a far-future emit_ts must NOT defer staleness — receive-time governs (expected absence exit 1); got $rc [$out]" - echo "$out" | grep -qi 'ALARM FIRED' || fail_msg "B11: the receive-time-stale beacon must fire the absence alarm [$out]" + echo "$out" | has_match -qi 'ALARM FIRED' || fail_msg "B11: the receive-time-stale beacon must fire the absence alarm [$out]" jq -e '.age_seconds >= 100' "$ALARM_OUT" >/dev/null 2>&1 || fail_msg "B11: staleness age must be measured from ingested_ts (>=100s), not emit_ts [$(cat "$ALARM_OUT" 2>/dev/null)]" ) && ok @@ -329,7 +332,7 @@ else jq -c '.beacon_seq = 99999 | .host_id = "attacker"' "$SHIPPED" >"$spoof" out="$("$BEACON" record <"$spoof" 2>&1)"; rc=$? [ "$rc" -ne 0 ] || fail_msg "B12: a spoofed beacon (altered fields) must be REJECTED at record; got rc=$rc [$out]" - echo "$out" | grep -qi 'spoofed beacon' || fail_msg "B12: the rejection must name the spoof [$out]" + echo "$out" | has_match -qi 'spoofed beacon' || fail_msg "B12: the rejection must name the spoof [$out]" [ ! -s "$WAKE_BEACON_RECEIVED" ] || fail_msg "B12: a rejected spoof must NOT be stored (dead-man clock not advanced)" # (c) an UNSIGNED beacon is rejected when signing is configured. unsigned="$H/unsigned.json" @@ -337,14 +340,14 @@ else out2="$("$BEACON" record <"$unsigned" 2>&1)"; rc2=$? [ "$rc2" -ne 0 ] || fail_msg "B12: an unsigned beacon must be REJECTED when signing is configured; got rc=$rc2 [$out2]" # beacon.sh must not inline the key material. - grep -qF "test-beacon-hmac-key-do-not-echo" "$BEACON" && fail_msg "B12: beacon.sh must NOT inline the HMAC key" + has_match -qF "test-beacon-hmac-key-do-not-echo" "$BEACON" && fail_msg "B12: beacon.sh must NOT inline the HMAC key" true ) && ok fi echo if [ -s "$FAILFILE" ]; then - echo "wake beacon harness: FAILED ($(grep -c . "$FAILFILE") assertion(s))" >&2 + echo "wake beacon harness: FAILED ($(count_lines . "$FAILFILE") assertion(s))" >&2 exit 1 fi echo "wake beacon harness: all invariants passed ($pass groups)" diff --git a/packages/mosaic/framework/tools/wake/test-wake-detector.sh b/packages/mosaic/framework/tools/wake/test-wake-detector.sh index 176464a9..41de2668 100755 --- a/packages/mosaic/framework/tools/wake/test-wake-detector.sh +++ b/packages/mosaic/framework/tools/wake/test-wake-detector.sh @@ -29,6 +29,9 @@ set -uo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness. +# shellcheck disable=SC1091 +. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init DET="$SCRIPT_DIR/detector.sh" STORE="$SCRIPT_DIR/store.sh" @@ -253,8 +256,8 @@ echo "== D5: watch-list schema_version out of manifest range -> FAIL LOUD ==" err="$("$DET" poll-once 2>&1)" rc=$? [ "$rc" -ne 0 ] || fail_msg "D5: an out-of-range schema_version must FAIL LOUD (non-zero exit)" - echo "$err" | grep -qi 'schema_version' || fail_msg "D5: the failure must name schema_version [$err]" - echo "$err" | grep -qi 'range' || fail_msg "D5: the failure must state it is out of the supported range [$err]" + echo "$err" | has_match -qi 'schema_version' || fail_msg "D5: the failure must name schema_version [$err]" + echo "$err" | has_match -qi 'range' || fail_msg "D5: the failure must state it is out of the supported range [$err]" # And nothing was enqueued / no cursor advance under a rejected watch-list. [ "$(depth)" = "0" ] || fail_msg "D5: a rejected watch-list must not enqueue, got depth $(depth)" [ "$(det_seq)" = "0" ] || fail_msg "D5: a rejected watch-list must not advance observed_seq, got $(det_seq)" @@ -287,7 +290,7 @@ echo "== D6: source error / ambiguous-empty -> FAIL LOUD, observed_seq NOT advan err="$("$DET" poll-once 2>&1)" rc=$? [ "$rc" -ne 0 ] || fail_msg "D6: a source error must FAIL LOUD (non-zero exit)" - echo "$err" | grep -qi 'FAIL LOUD' || fail_msg "D6: the source error must be loud [$err]" + echo "$err" | has_match -qi 'FAIL LOUD' || fail_msg "D6: the source error must be loud [$err]" [ "$(det_seq)" = "$seq_before" ] || fail_msg "D6: a source error must NOT advance observed_seq (got $(det_seq), was $seq_before)" [ "$(depth)" = "0" ] || fail_msg "D6: a source error must NOT enqueue, got depth $(depth)" @@ -298,7 +301,7 @@ echo "== D6: source error / ambiguous-empty -> FAIL LOUD, observed_seq NOT advan err="$("$DET" poll-once 2>&1)" rc=$? [ "$rc" -ne 0 ] || fail_msg "D6: an ambiguous-empty response must FAIL LOUD (non-zero exit)" - echo "$err" | grep -qi 'AMBIGUOUS-EMPTY' || fail_msg "D6: ambiguous-empty must be named in the loud failure [$err]" + echo "$err" | has_match -qi 'AMBIGUOUS-EMPTY' || fail_msg "D6: ambiguous-empty must be named in the loud failure [$err]" [ "$(det_seq)" = "$seq_before" ] || fail_msg "D6: ambiguous-empty must NOT advance observed_seq (got $(det_seq))" [ "$(depth)" = "0" ] || fail_msg "D6: ambiguous-empty must NOT enqueue, got depth $(depth)" @@ -442,7 +445,7 @@ EOF write_fc_watchlist "$wl" 999 err="$("$DET" poll-once 2>&1)"; rc=$? [ "$rc" -ne 0 ] || fail_msg "D9: the new field must NOT weaken Gate B — an out-of-range schema_version must still FAIL LOUD (rc=$rc)" - echo "$err" | grep -qi 'range' || fail_msg "D9: the out-of-range failure must still state it is out of the supported range [$err]" + echo "$err" | has_match -qi 'range' || fail_msg "D9: the out-of-range failure must still state it is out of the supported range [$err]" ) && ok echo "== D10: snapshot metadata (fd 3, #940) — adapter-attested sha/ts land in the enqueued locators ==" @@ -513,7 +516,7 @@ EOF printf 'SHA-BBB\n' >"$stub/repo_r1" err="$("$DET" poll-once 2>&1 >/dev/null)"; rc=$? [ "$rc" -eq 0 ] || fail_msg "D11: malformed metadata must NEVER fail the poll (rc=$rc)" - echo "$err" | grep -qi 'snapshot' || fail_msg "D11: dropping malformed metadata must be LOUD on stderr [$err]" + echo "$err" | has_match -qi 'snapshot' || fail_msg "D11: dropping malformed metadata must be LOUD on stderr [$err]" entry="$("$STORE" drain | tail -1)" echo "$entry" | jq -e '.locators | has("snapshot_sha") or has("snapshot_ts")' >/dev/null 2>&1 \ && fail_msg "D11: malformed metadata must emit NO snapshot fields [$entry]" @@ -522,7 +525,7 @@ EOF printf 'SHA-CCC\n' >"$stub/repo_r1" err="$("$DET" poll-once 2>&1 >/dev/null)"; rc=$? [ "$rc" -eq 0 ] || fail_msg "D11: rejected snapshot_sha must NEVER fail the poll (rc=$rc)" - echo "$err" | grep -qi 'snapshot' || fail_msg "D11: rejecting a bad snapshot_sha must be LOUD on stderr [$err]" + echo "$err" | has_match -qi 'snapshot' || fail_msg "D11: rejecting a bad snapshot_sha must be LOUD on stderr [$err]" entry="$("$STORE" drain | tail -1)" echo "$entry" | jq -e '.locators | has("snapshot_sha") or has("snapshot_ts")' >/dev/null 2>&1 \ && fail_msg "D11: rejected metadata must emit NO snapshot fields [$entry]" @@ -560,7 +563,7 @@ EOF printf 'SHA-BBB\n' >"$stub/repo_r1" err="$("$DET" poll-once 2>&1 >/dev/null)"; rc=$? [ "$rc" -eq 0 ] || fail_msg "D12: ts-without-sha must NEVER fail the poll (rc=$rc)" - echo "$err" | grep -qi 'without a valid snapshot_sha' || fail_msg "D12: dropping ts-without-sha must be LOUD on stderr [$err]" + echo "$err" | has_match -qi 'without a valid snapshot_sha' || fail_msg "D12: dropping ts-without-sha must be LOUD on stderr [$err]" entry="$("$STORE" drain | tail -1)" echo "$entry" | jq -e '.locators | has("snapshot_sha") or has("snapshot_ts")' >/dev/null 2>&1 \ && fail_msg "D12: ts-without-sha must emit NO snapshot fields [$entry]" @@ -571,7 +574,7 @@ EOF printf 'SHA-CCC\n' >"$stub/repo_r1" err="$("$DET" poll-once 2>&1 >/dev/null)"; rc=$? [ "$rc" -eq 0 ] || fail_msg "D12: future ts must NEVER fail the poll (rc=$rc)" - echo "$err" | grep -qi 'future-skew' || fail_msg "D12: dropping a future ts must be LOUD on stderr [$err]" + echo "$err" | has_match -qi 'future-skew' || fail_msg "D12: dropping a future ts must be LOUD on stderr [$err]" entry="$("$STORE" drain | tail -1)" echo "$entry" | jq -e --arg s "$goodsha" 'select(.locators.snapshot_sha==$s) | .locators | has("snapshot_ts") | not' >/dev/null 2>&1 \ || fail_msg "D12: future ts must drop ts but KEEP the sha [$entry]" @@ -581,7 +584,7 @@ EOF printf 'SHA-DDD\n' >"$stub/repo_r1" err="$("$DET" poll-once 2>&1 >/dev/null)"; rc=$? [ "$rc" -eq 0 ] || fail_msg "D12: absurd ts must NEVER fail the poll (rc=$rc)" - echo "$err" | grep -qi 'sane positive epoch' || fail_msg "D12: rejecting an absurd ts must be LOUD on stderr [$err]" + echo "$err" | has_match -qi 'sane positive epoch' || fail_msg "D12: rejecting an absurd ts must be LOUD on stderr [$err]" entry="$("$STORE" drain | tail -1)" echo "$entry" | jq -e --arg s "$goodsha" 'select(.locators.snapshot_sha==$s) | .locators | has("snapshot_ts") | not' >/dev/null 2>&1 \ || fail_msg "D12: absurd ts must drop ts but KEEP the sha [$entry]" @@ -621,7 +624,7 @@ EOF printf 'SHA-BBB\n' >"$stub/repo_r1" err="$(WAKE_SNAPSHOT_TS_FUTURE_SLACK='300s' "$DET" poll-once 2>&1 >/dev/null)"; rc=$? [ "$rc" -eq 0 ] || fail_msg "D13: SLACK='300s' must NEVER fail the poll (rc=$rc)" - echo "$err" | grep -qi 'falling back to 300' || fail_msg "D13: malformed slack must be LOUD on stderr [$err]" + echo "$err" | has_match -qi 'falling back to 300' || fail_msg "D13: malformed slack must be LOUD on stderr [$err]" entry="$("$STORE" drain | tail -1)" echo "$entry" | jq -e --arg s "$goodsha" 'select(.locators.snapshot_sha==$s) | .locators | has("snapshot_ts")' >/dev/null 2>&1 \ || fail_msg "D13: valid metadata must SURVIVE a malformed knob (fallback, not drop) [$entry]" @@ -630,7 +633,7 @@ EOF printf 'SHA-CCC\n' >"$stub/repo_r1" err="$(WAKE_SNAPSHOT_TS_FUTURE_SLACK='abc' "$DET" poll-once 2>&1 >/dev/null)"; rc=$? [ "$rc" -eq 0 ] || fail_msg "D13: SLACK='abc' must NEVER fail the poll (rc=$rc)" - echo "$err" | grep -qi 'falling back to 300' || fail_msg "D13: non-numeric slack must be LOUD on stderr [$err]" + echo "$err" | has_match -qi 'falling back to 300' || fail_msg "D13: non-numeric slack must be LOUD on stderr [$err]" entry="$("$STORE" drain | tail -1)" echo "$entry" | jq -e --arg s "$goodsha" 'select(.locators.snapshot_sha==$s) | .locators | has("snapshot_ts")' >/dev/null 2>&1 \ || fail_msg "D13: valid metadata must SURVIVE a non-numeric knob [$entry]" @@ -640,7 +643,7 @@ EOF printf 'SHA-DDD\n' >"$stub/repo_r1" err="$(WAKE_SNAPSHOT_TS_FUTURE_SLACK='-99999999' "$DET" poll-once 2>&1 >/dev/null)"; rc=$? [ "$rc" -eq 0 ] || fail_msg "D13: negative SLACK must NEVER fail the poll (rc=$rc)" - echo "$err" | grep -qi 'falling back to 300' || fail_msg "D13: negative slack must be LOUD on stderr [$err]" + echo "$err" | has_match -qi 'falling back to 300' || fail_msg "D13: negative slack must be LOUD on stderr [$err]" entry="$("$STORE" drain | tail -1)" echo "$entry" | jq -e --arg s "$goodsha" 'select(.locators.snapshot_sha==$s) | .locators | has("snapshot_ts")' >/dev/null 2>&1 \ || fail_msg "D13: negative slack must NOT invert the guard into deny-all [$entry]" @@ -652,7 +655,7 @@ EOF printf 'SHA-CC2\n' >"$stub/repo_r1" err="$(WAKE_SNAPSHOT_TS_FUTURE_SLACK=$'300\n8' "$DET" poll-once 2>&1 >/dev/null)"; rc=$? [ "$rc" -eq 0 ] || fail_msg "D13: multi-line SLACK (300\\n8) must NEVER fail the poll (rc=$rc) [$err]" - echo "$err" | grep -qi 'falling back to 300' || fail_msg "D13: multi-line slack must be LOUD on stderr [$err]" + echo "$err" | has_match -qi 'falling back to 300' || fail_msg "D13: multi-line slack must be LOUD on stderr [$err]" entry="$("$STORE" drain | tail -1)" echo "$entry" | jq -e --arg s "$goodsha" 'select(.locators.snapshot_sha==$s) | .locators | has("snapshot_ts")' >/dev/null 2>&1 \ || fail_msg "D13: valid metadata must SURVIVE a multi-line knob [$entry]" @@ -660,7 +663,7 @@ EOF printf 'SHA-CC3\n' >"$stub/repo_r1" err="$(WAKE_SNAPSHOT_TS_FUTURE_SLACK=$'300\nabc' "$DET" poll-once 2>&1 >/dev/null)"; rc=$? [ "$rc" -eq 0 ] || fail_msg "D13: multi-line SLACK (300\\nabc) must NEVER fail the poll (rc=$rc) [$err]" - echo "$err" | grep -qi 'falling back to 300' || fail_msg "D13: multi-line non-numeric slack must be LOUD on stderr [$err]" + echo "$err" | has_match -qi 'falling back to 300' || fail_msg "D13: multi-line non-numeric slack must be LOUD on stderr [$err]" entry="$("$STORE" drain | tail -1)" echo "$entry" | jq -e --arg s "$goodsha" 'select(.locators.snapshot_sha==$s) | .locators | has("snapshot_ts")' >/dev/null 2>&1 \ || fail_msg "D13: valid metadata must SURVIVE a multi-line non-numeric knob [$entry]" @@ -687,7 +690,7 @@ EOF printf 'SHA-EEE\n' >"$stub/repo_r1" err="$(WAKE_SNAPSHOT_TS_FUTURE_SLACK='0' "$DET" poll-once 2>&1 >/dev/null)"; rc=$? [ "$rc" -eq 0 ] || fail_msg "D13: valid SLACK=0 must not fail the poll (rc=$rc)" - echo "$err" | grep -qi 'future-skew' || fail_msg "D13: a valid tightened slack must still reject a future ts [$err]" + echo "$err" | has_match -qi 'future-skew' || fail_msg "D13: a valid tightened slack must still reject a future ts [$err]" entry="$("$STORE" drain | tail -1)" echo "$entry" | jq -e --arg s "$goodsha" 'select(.locators.snapshot_sha==$s) | .locators | has("snapshot_ts") | not' >/dev/null 2>&1 \ || fail_msg "D13: valid SLACK=0 must drop the future ts but keep the sha [$entry]" @@ -696,7 +699,7 @@ EOF echo if [ -s "$FAILFILE" ]; then - echo "wake detector harness: FAILED ($(grep -c . "$FAILFILE") assertion(s))" >&2 + echo "wake detector harness: FAILED ($(count_lines . "$FAILFILE") assertion(s))" >&2 exit 1 fi echo "wake detector harness: all invariants passed ($pass groups)" diff --git a/packages/mosaic/framework/tools/wake/test-wake-digest-hmac.sh b/packages/mosaic/framework/tools/wake/test-wake-digest-hmac.sh index 40208181..803118b9 100755 --- a/packages/mosaic/framework/tools/wake/test-wake-digest-hmac.sh +++ b/packages/mosaic/framework/tools/wake/test-wake-digest-hmac.sh @@ -35,6 +35,9 @@ set -uo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness. +# shellcheck disable=SC1091 +. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init STORE="$SCRIPT_DIR/store.sh" DIGEST="$SCRIPT_DIR/digest.sh" SIGN="$SCRIPT_DIR/sign.sh" @@ -102,13 +105,13 @@ echo "== D1: CUMULATIVE-STATE — two pending changes BOTH render (not just late "$STORE" enqueue --seq 1 --class actionable --locators '{"repo":"r","issue":11}' >/dev/null "$STORE" enqueue --seq 2 --class actionable --locators '{"repo":"r","issue":22}' >/dev/null out="$("$DIGEST" render)" || fail_msg "D1: render exited non-zero" - echo "$out" | grep -q 'issue=#11' || fail_msg "D1: OLDER change (issue #11) dropped — digest is a delta, not cumulative state" - echo "$out" | grep -q 'issue=#22' || fail_msg "D1: newer change (issue #22) missing" - echo "$out" | grep -q 'seq 1' || fail_msg "D1: seq 1 not listed in cumulative set" - echo "$out" | grep -q 'seq 2' || fail_msg "D1: seq 2 not listed in cumulative set" + echo "$out" | has_match -q 'issue=#11' || fail_msg "D1: OLDER change (issue #11) dropped — digest is a delta, not cumulative state" + echo "$out" | has_match -q 'issue=#22' || fail_msg "D1: newer change (issue #22) missing" + echo "$out" | has_match -q 'seq 1' || fail_msg "D1: seq 1 not listed in cumulative set" + echo "$out" | has_match -q 'seq 2' || fail_msg "D1: seq 2 not listed in cumulative set" # A coalescing digest-class entry is STATE (full), not a delta: a later digest # subsumes the earlier, but the cumulative unacked set (both actionables) stays. - echo "$out" | grep -q 'pending=2' || fail_msg "D1: cumulative pending count wrong (expected 2)" + echo "$out" | has_match -q 'pending=2' || fail_msg "D1: cumulative pending count wrong (expected 2)" ) && ok echo "== D2: HARD-LOCATOR enforcement — a malformed actionable claim is QUARANTINED (fail-loud PER-ENTRY, #920); never delivered as valid ==" @@ -127,9 +130,9 @@ echo "== D2: HARD-LOCATOR enforcement — a malformed actionable claim is QUARAN # but the unlocated claim is NEVER delivered as a valid CLAIM (fail-loud is # preserved, now per-entry). The old exit-4 wedged the entire drain (#920). [ "$rc" -eq 0 ] || fail_msg "D2: a malformed actionable must be quarantined (render exit 0, #920), got $rc" - printf '%s' "$out" | grep -q 'mergeable=true' && fail_msg "D2: an unlocated actionable claim must NOT be delivered as a valid CLAIM" - grep -q 'mergeable=true' "$h/default/dead-letter.jsonl" 2>/dev/null || fail_msg "D2: the malformed claim must be DEAD-LETTERED (fail-loud preserved, per-entry)" - grep -qi 'QUARANTINE' "$err" || fail_msg "D2: a LOUD per-entry alarm must fire for the malformed claim" + printf '%s' "$out" | has_match -q 'mergeable=true' && fail_msg "D2: an unlocated actionable claim must NOT be delivered as a valid CLAIM" + has_match -q 'mergeable=true' "$h/default/dead-letter.jsonl" 2>/dev/null || fail_msg "D2: the malformed claim must be DEAD-LETTERED (fail-loud preserved, per-entry)" + has_match -qi 'QUARANTINE' "$err" || fail_msg "D2: a LOUD per-entry alarm must fire for the malformed claim" # A present-but-imprecise sha (not 40 hex) does NOT satisfy the hard locator -> # quarantined, not delivered. @@ -140,8 +143,8 @@ echo "== D2: HARD-LOCATOR enforcement — a malformed actionable claim is QUARAN rc=0 out="$("$DIGEST" render 2>/dev/null)" || rc=$? [ "$rc" -eq 0 ] || fail_msg "D2: imprecise-sha entry must be quarantined (render exit 0), got $rc" - printf '%s' "$out" | grep -q 'ci=green' && fail_msg "D2: imprecise sha (not 40-hex) must not satisfy the hard-locator gate (claim must not deliver)" - grep -q 'ci=green' "$h/default/dead-letter.jsonl" 2>/dev/null || fail_msg "D2: imprecise-sha claim must be dead-lettered" + printf '%s' "$out" | has_match -q 'ci=green' && fail_msg "D2: imprecise sha (not 40-hex) must not satisfy the hard-locator gate (claim must not deliver)" + has_match -q 'ci=green' "$h/default/dead-letter.jsonl" 2>/dev/null || fail_msg "D2: imprecise-sha claim must be dead-lettered" # The SAME claim WITH a precise 40-hex sha renders fine (delivered, not quarantined). h="$(fresh_state d2c)" @@ -149,7 +152,7 @@ echo "== D2: HARD-LOCATOR enforcement — a malformed actionable claim is QUARAN export WAKE_STATE_HOME "$STORE" enqueue --seq 1 --class actionable --locators "$(jq -cn --arg s "$SHA40" '{claim:"ci=green",sha:$s}')" >/dev/null out="$("$DIGEST" render 2>/dev/null)" || fail_msg "D2: a well-located actionable claim must render" - printf '%s' "$out" | grep -q "$SHA40" || fail_msg "D2: a well-located actionable claim must be DELIVERED" + printf '%s' "$out" | has_match -q "$SHA40" || fail_msg "D2: a well-located actionable claim must be DELIVERED" [ -s "$h/default/dead-letter.jsonl" ] && fail_msg "D2: a well-located claim must NOT be quarantined" # --- #905 bypass-prevention (STILL enforced, now via quarantine): a NON- # CANONICAL entry with a TOP-LEVEL `.claim` (store.sh never emits this shape; @@ -164,8 +167,8 @@ echo "== D2: HARD-LOCATOR enforcement — a malformed actionable claim is QUARAN rc=0 out="$(printf '%s\n' "$toplevel_claim_entry" | "$DIGEST" render --stdin 2>/dev/null)" || rc=$? [ "$rc" -eq 0 ] || fail_msg "D2(#905): top-level .claim must be quarantined via --stdin (exit 0), got $rc" - printf '%s' "$out" | grep -q 'mergeable=true' && fail_msg "D2(#905): --stdin top-level-.claim must NOT be delivered (gate not bypassed)" - grep -q 'mergeable=true' "$h/default/dead-letter.jsonl" 2>/dev/null || fail_msg "D2(#905): --stdin top-level .claim must be dead-lettered (gate enforced)" + printf '%s' "$out" | has_match -q 'mergeable=true' && fail_msg "D2(#905): --stdin top-level-.claim must NOT be delivered (gate not bypassed)" + has_match -q 'mergeable=true' "$h/default/dead-letter.jsonl" 2>/dev/null || fail_msg "D2(#905): --stdin top-level .claim must be dead-lettered (gate enforced)" ff="$TMP_ROOT/d2d-entry.jsonl" printf '%s\n' "$toplevel_claim_entry" >"$ff" h="$(fresh_state d2e)" @@ -174,8 +177,8 @@ echo "== D2: HARD-LOCATOR enforcement — a malformed actionable claim is QUARAN rc=0 out2="$("$DIGEST" render --from-file "$ff" 2>/dev/null)" || rc=$? [ "$rc" -eq 0 ] || fail_msg "D2(#905): top-level .claim must be quarantined via --from-file (exit 0), got $rc" - printf '%s' "$out2" | grep -q 'mergeable=true' && fail_msg "D2(#905): --from-file top-level-.claim must NOT be delivered (gate not bypassed)" - grep -q 'mergeable=true' "$h/default/dead-letter.jsonl" 2>/dev/null || fail_msg "D2(#905): --from-file top-level .claim must be dead-lettered (gate enforced)" + printf '%s' "$out2" | has_match -q 'mergeable=true' && fail_msg "D2(#905): --from-file top-level-.claim must NOT be delivered (gate not bypassed)" + has_match -q 'mergeable=true' "$h/default/dead-letter.jsonl" 2>/dev/null || fail_msg "D2(#905): --from-file top-level .claim must be dead-lettered (gate enforced)" ) && ok echo "== D3: TWO-TIER — orientation no-op with ZERO tool calls; actionable = claim-to-verify ==" @@ -197,7 +200,7 @@ echo "== D3: TWO-TIER — orientation no-op with ZERO tool calls; actionable = c done # No pending obligations => no-op common case. out="$(PATH="$bin:$PATH" "$DIGEST" render --lane build)" || fail_msg "D3: no-op render failed" - echo "$out" | grep -q 'NO-OP' || fail_msg "D3: empty inbox must render an explicit NO-OP orientation" + echo "$out" | has_match -q 'NO-OP' || fail_msg "D3: empty inbox must render an explicit NO-OP orientation" [ -e "$WAKE_STATE_HOME/TOOL_CALLED" ] && fail_msg "D3: orientation no-op made a live tool call (must be ZERO)" # Now an actionable, consequential fact. It must be a CLAIM-TO-VERIFY, never # rendered as a trusted assertion or an auto-action. @@ -206,14 +209,14 @@ echo "== D3: TWO-TIER — orientation no-op with ZERO tool calls; actionable = c out2="$(PATH="$bin:$PATH" "$DIGEST" render)" || fail_msg "D3: actionable render failed" # Rendering itself still makes ZERO live calls (it only lays out claims). [ -e "$WAKE_STATE_HOME/TOOL_CALLED" ] && fail_msg "D3: rendering an actionable claim made a live call (must defer to the consumer's gate)" - echo "$out2" | grep -q 'CLAIM@seq' || fail_msg "D3: consequential fact not framed as CLAIM@seq" - echo "$out2" | grep -qi 'VERIFY LIVE' || fail_msg "D3: claim not marked for live verification" - echo "$out2" | grep -qi 'do NOT act on this line' || fail_msg "D3: claim missing do-not-auto-action framing" + echo "$out2" | has_match -q 'CLAIM@seq' || fail_msg "D3: consequential fact not framed as CLAIM@seq" + echo "$out2" | has_match -qi 'VERIFY LIVE' || fail_msg "D3: claim not marked for live verification" + echo "$out2" | has_match -qi 'do NOT act on this line' || fail_msg "D3: claim missing do-not-auto-action framing" # The consequential fact must NOT appear as a bare trusted directive. - echo "$out2" | grep -qiE 'merge now|go ahead and (merge|deploy)|safe to merge' && + echo "$out2" | has_match -qiE 'merge now|go ahead and (merge|deploy)|safe to merge' && fail_msg "D3: digest auto-actioned a consequential fact (imperative present)" # And its hard locator + one-call re-verify hint are present. - echo "$out2" | grep -q "re-verify (ONE call)" || fail_msg "D3: actionable claim missing one-call re-verify locator" + echo "$out2" | has_match -q "re-verify (ONE call)" || fail_msg "D3: actionable claim missing one-call re-verify locator" true ) && ok @@ -229,7 +232,7 @@ echo "== D4: SCRUB — secret-canary + ANSI/bidi/zero-width in source free-text "$STORE" enqueue --seq 1 --class actionable --locators "$loc" >/dev/null out="$("$DIGEST" render)" || fail_msg "D4: render failed" # ANSI escape / CSI must be gone. - printf '%s' "$out" | LC_ALL=C grep -q "$(printf '\x1b')" && fail_msg "D4: ANSI ESC survived the scrub" + printf '%s' "$out" | LC_ALL=C has_match -q "$(printf '\x1b')" && fail_msg "D4: ANSI ESC survived the scrub" # bidi/zero-width/BOM UTF-8 sequences must be gone. # #912: patterns are LITERAL bytes + `grep -E`, NOT PCRE `grep -P`. BusyBox # grep (Alpine/musl CI) has no `-P` — a `grep -qP` there errors @@ -244,21 +247,21 @@ echo "== D4: SCRUB — secret-canary + ANSI/bidi/zero-width in source free-text _b8b="$(printf '%b' '\x8b')"; _b8f="$(printf '%b' '\x8f')" _baa="$(printf '%b' '\xaa')"; _bae="$(printf '%b' '\xae')" _bbom="$(printf '%b' '\xef\xbb\xbf')" - printf '%s' "$out" | LC_ALL=C grep -qE "${_b280}[${_b8b}-${_b8f}${_baa}-${_bae}]|${_bbom}" && + printf '%s' "$out" | LC_ALL=C has_match -qE "${_b280}[${_b8b}-${_b8f}${_baa}-${_bae}]|${_bbom}" && fail_msg "D4: bidi/zero-width/BOM survived the scrub" # C0 control bytes (except tab/newline) must be gone. _c00="$(printf '%b' '\x01')"; _c08="$(printf '%b' '\x08')" _c0e="$(printf '%b' '\x0e')"; _c1f="$(printf '%b' '\x1f')"; _c7f="$(printf '%b' '\x7f')" - printf '%s' "$out" | LC_ALL=C grep -qE "[${_c00}-${_c08}${_c0e}-${_c1f}${_c7f}]" && + printf '%s' "$out" | LC_ALL=C has_match -qE "[${_c00}-${_c08}${_c0e}-${_c1f}${_c7f}]" && fail_msg "D4: a C0 control byte survived the scrub" # Secret canaries must be redacted, never inlined. - printf '%s' "$out" | grep -q 'ghp_0123456789' && fail_msg "D4: GitHub-token canary LEAKED into the digest" - printf '%s' "$out" | grep -q 'AKIAIOSFODNN7EXAMPLE' && fail_msg "D4: AWS-key canary LEAKED into the digest" - printf '%s' "$out" | grep -q 'REDACTED-SECRET' || fail_msg "D4: secret redaction marker absent — canary may not have been scrubbed" + printf '%s' "$out" | has_match -q 'ghp_0123456789' && fail_msg "D4: GitHub-token canary LEAKED into the digest" + printf '%s' "$out" | has_match -q 'AKIAIOSFODNN7EXAMPLE' && fail_msg "D4: AWS-key canary LEAKED into the digest" + printf '%s' "$out" | has_match -q 'REDACTED-SECRET' || fail_msg "D4: secret redaction marker absent — canary may not have been scrubbed" # Free-text is quoted inside a DELIMITED untrusted block, framed as NOT instructions. - printf '%s' "$out" | grep -q 'BEGIN UNTRUSTED DATA' || fail_msg "D4: source free-text not placed in a delimited untrusted block" + printf '%s' "$out" | has_match -q 'BEGIN UNTRUSTED DATA' || fail_msg "D4: source free-text not placed in a delimited untrusted block" # The 40-hex git SHA locator must NOT be mangled by the secret scrubber. - printf '%s' "$out" | grep -q "$SHA40" || fail_msg "D4: legitimate 40-hex SHA locator was wrongly scrubbed" + printf '%s' "$out" | has_match -q "$SHA40" || fail_msg "D4: legitimate 40-hex SHA locator was wrongly scrubbed" true ) && ok @@ -323,11 +326,11 @@ echo "== H2: KEY BY-NAME, never inline; no key leak; same-uid boundary documente fail_msg "H2: by-name key resolution failed" echo "$env1" | jq -e .wake_mac >/dev/null || fail_msg "H2: no MAC produced from by-name key" # The key VALUE must never appear in the signed output. - echo "$env1" | grep -q 'SUPERSECRET-KEYVALUE-XYZ' && fail_msg "H2: key material LEAKED into the signed envelope" + echo "$env1" | has_match -q 'SUPERSECRET-KEYVALUE-XYZ' && fail_msg "H2: key material LEAKED into the signed envelope" # A signed store-entry (hmac placeholder filled) must not leak the key either. entry="$(printf '{"observed_seq":1,"locators":{"repo":"r","issue":1},"class":"actionable","emit_ts":1700000000,"hmac":""}' | WAKE_HMAC_KEY_NAME=signing-key "$SIGN" sign-entry)" - echo "$entry" | grep -q 'SUPERSECRET-KEYVALUE-XYZ' && fail_msg "H2: key material LEAKED into the signed entry" + echo "$entry" | has_match -q 'SUPERSECRET-KEYVALUE-XYZ' && fail_msg "H2: key material LEAKED into the signed entry" echo "$entry" | jq -e '.hmac != "" and .hmac != null' >/dev/null || fail_msg "H2: sign-entry did not fill the hmac placeholder" # No flag may accept key MATERIAL inline — only a key NAME. An attempt to pass # a literal key must be rejected as an unknown option (never silently honored). @@ -341,8 +344,8 @@ echo "== H2: KEY BY-NAME, never inline; no key leak; same-uid boundary documente fail_msg "H2: signing with an unresolvable key name must FAIL LOUD" fi # The same-uid threat boundary + off-uid follow-up must be DOCUMENTED in the tool. - grep -qi 'same-uid' "$SIGN" || fail_msg "H2: same-uid threat boundary not documented in sign.sh" - grep -qi 'off-uid' "$SIGN" || fail_msg "H2: off-uid future signer not named in sign.sh" + has_match -qi 'same-uid' "$SIGN" || fail_msg "H2: same-uid threat boundary not documented in sign.sh" + has_match -qi 'off-uid' "$SIGN" || fail_msg "H2: off-uid future signer not named in sign.sh" ) && ok echo "== D5 (#914a): EMBEDDED ACK NAMESPACE — env-less copy-run targets the RENDER-TIME agent, not 'default' ==" @@ -355,7 +358,7 @@ echo "== D5 (#914a): EMBEDDED ACK NAMESPACE — env-less copy-run targets the RE out="$(WAKE_AGENT=someagent "$DIGEST" render)" || fail_msg "D5: render (WAKE_AGENT=someagent) failed" ack_line="$(printf '%s\n' "$out" | awk '/^-- ACK/{f=1;next} f && NF {print; exit}')" [ -n "$ack_line" ] || fail_msg "D5: no embedded ack line extracted from the digest" - printf '%s' "$ack_line" | grep -q 'WAKE_AGENT=someagent' || + printf '%s' "$ack_line" | has_match -q 'WAKE_AGENT=someagent' || fail_msg "D5: embedded ack line has no explicit WAKE_AGENT=someagent prefix — an env-less copy-run silently resolves to 'default' [$ack_line]" # Actually RUN it with NO WAKE_AGENT in the environment (the real failure # mode: a consumer copy-pastes the line into a fresh shell). @@ -401,12 +404,12 @@ echo "== D6 (#914b): DIGEST-CLASS LOCATOR THREADING — ORIENTATION pointer carr loc="$(jq -cn '{kind:"repo", id:"r1", observed_hash:"deadbeefcafe0123456789abcdef0123456789abcdef0123456789abcdef01", remote:"example/repo"}')" "$STORE" enqueue --seq 1 --class digest --locators "$loc" >/dev/null out="$("$DIGEST" render)" || fail_msg "D6: render failed" - orientline="$(printf '%s\n' "$out" | grep -E '^\s*\* seq 1 \[digest\]')" + orientline="$(printf '%s\n' "$out" | has_match -E '^\s*\* seq 1 \[digest\]')" [ -n "$orientline" ] || fail_msg "D6: no ORIENTATION line found for seq 1" - printf '%s' "$orientline" | grep -qE 'locator: *$' && + printf '%s' "$orientline" | has_match -qE 'locator: *$' && fail_msg "D6: digest-class ORIENTATION pointer rendered an EMPTY locator despite a populated .locators field [$orientline]" # Must surface something a consumer can act on to re-verify. - printf '%s' "$orientline" | grep -qE 'remote=example/repo|id=r1|kind=repo' || + printf '%s' "$orientline" | has_match -qE 'remote=example/repo|id=r1|kind=repo' || fail_msg "D6: digest-class ORIENTATION pointer does not carry a usable locator [$orientline]" # --- ACTIONABLE-tier hard-locator FAIL-LOUD must be PRESERVED (now PER-ENTRY @@ -421,14 +424,14 @@ echo "== D6 (#914b): DIGEST-CLASS LOCATOR THREADING — ORIENTATION pointer carr rc=0 out="$("$DIGEST" render 2>"$err")" || rc=$? [ "$rc" -eq 0 ] || fail_msg "D6: a malformed actionable is now per-entry quarantined (render exit 0, #920), got $rc" - printf '%s' "$out" | grep -q 'mergeable=true' && fail_msg "D6: a malformed actionable claim must NOT be delivered as valid (fail-loud preserved)" - grep -q 'mergeable=true' "$h/default/dead-letter.jsonl" 2>/dev/null || fail_msg "D6: a malformed actionable must be DEAD-LETTERED (fail-loud preserved, per-entry)" - grep -qi 'QUARANTINE' "$err" || fail_msg "D6: a malformed actionable must raise a loud per-entry alarm" + printf '%s' "$out" | has_match -q 'mergeable=true' && fail_msg "D6: a malformed actionable claim must NOT be delivered as valid (fail-loud preserved)" + has_match -q 'mergeable=true' "$h/default/dead-letter.jsonl" 2>/dev/null || fail_msg "D6: a malformed actionable must be DEAD-LETTERED (fail-loud preserved, per-entry)" + has_match -qi 'QUARANTINE' "$err" || fail_msg "D6: a malformed actionable must raise a loud per-entry alarm" ) && ok echo if [ -s "$FAILFILE" ]; then - echo "wake digest/hmac harness: FAILED ($(grep -c . "$FAILFILE") assertion(s))" >&2 + echo "wake digest/hmac harness: FAILED ($(count_lines . "$FAILFILE") assertion(s))" >&2 exit 1 fi echo "wake digest/hmac harness: all invariants passed ($pass groups)" diff --git a/packages/mosaic/framework/tools/wake/test-wake-digest-quarantine.sh b/packages/mosaic/framework/tools/wake/test-wake-digest-quarantine.sh index d0e14370..481782b6 100755 --- a/packages/mosaic/framework/tools/wake/test-wake-digest-quarantine.sh +++ b/packages/mosaic/framework/tools/wake/test-wake-digest-quarantine.sh @@ -117,6 +117,9 @@ set -uo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness. +# shellcheck disable=SC1091 +. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init DIGEST="$SCRIPT_DIR/digest.sh" command -v jq >/dev/null 2>&1 || { @@ -176,12 +179,12 @@ echo "== Q1 (a): malformed address-free {kind,id,observed_hash} QUARANTINES; cle out="$("$DIGEST" render --from-file "$f" --agent default 2>"$err")" rc=$? [ "$rc" -eq 0 ] || fail_msg "Q1: render must EXIT 0 (per-entry quarantine, not whole-digest exit-4), got rc=$rc" - printf '%s' "$out" | grep -q "$SHA40" || fail_msg "Q1: the clean sibling (sha $SHA40) must STILL be delivered in the same drain [head-of-line block]" - printf '%s' "$out" | grep -q 'MALFORMED-Q' && fail_msg "Q1: the quarantined entry must be EXCLUDED from the rendered digest" + printf '%s' "$out" | has_match -q "$SHA40" || fail_msg "Q1: the clean sibling (sha $SHA40) must STILL be delivered in the same drain [head-of-line block]" + printf '%s' "$out" | has_match -q 'MALFORMED-Q' && fail_msg "Q1: the quarantined entry must be EXCLUDED from the rendered digest" [ -f "$(dlq "$home")" ] || fail_msg "Q1: a durable dead-letter file must be written" - grep -q 'MALFORMED-Q' "$(dlq "$home")" 2>/dev/null || fail_msg "Q1: the malformed entry must be DEAD-LETTERED (accounted-for, not silently dropped)" - grep -qi 'QUARANTINE' "$err" || fail_msg "Q1: a LOUD per-entry alarm must fire on stderr" - grep -q 'observed_seq=1' "$err" || fail_msg "Q1: the alarm must identify the offending entry (observed_seq=1)" + has_match -q 'MALFORMED-Q' "$(dlq "$home")" 2>/dev/null || fail_msg "Q1: the malformed entry must be DEAD-LETTERED (accounted-for, not silently dropped)" + has_match -qi 'QUARANTINE' "$err" || fail_msg "Q1: a LOUD per-entry alarm must fire on stderr" + has_match -q 'observed_seq=1' "$err" || fail_msg "Q1: the alarm must identify the offending entry (observed_seq=1)" ) && ok echo "== Q2 (b): reconciler enumeration (reconciled:true) renders ORIENTATION-tier, NO exit-4 ==" @@ -200,8 +203,8 @@ echo "== Q2 (b): reconciler enumeration (reconciled:true) renders ORIENTATION-ti out="$("$DIGEST" render --from-file "$f" --agent default 2>"$err")" rc=$? [ "$rc" -eq 0 ] || fail_msg "Q2: a reconciler enumeration must NOT exit-4 (it is ORIENTATION-tier), got rc=$rc" - printf '%s' "$out" | grep -q 'id=ENUM-B' || fail_msg "Q2: the enumeration must render as an ORIENTATION pointer (id=ENUM-B via _locator_line)" - printf '%s' "$out" | grep -q 'CLAIM@seq' && fail_msg "Q2: an enumeration must NOT render as an ACTIONABLE CLAIM@seq" + printf '%s' "$out" | has_match -q 'id=ENUM-B' || fail_msg "Q2: the enumeration must render as an ORIENTATION pointer (id=ENUM-B via _locator_line)" + printf '%s' "$out" | has_match -q 'CLAIM@seq' && fail_msg "Q2: an enumeration must NOT render as an ACTIONABLE CLAIM@seq" [ -s "$(dlq "$home")" ] && fail_msg "Q2: an ORIENTATION-tier enumeration must NOT be quarantined/dead-lettered" true ) && ok @@ -220,10 +223,10 @@ echo "== Q3 (c): TWO DISTINCT enumerations BOTH survive as SEPARATE orientation out="$("$DIGEST" render --from-file "$f" --agent default 2>"$err")" rc=$? [ "$rc" -eq 0 ] || fail_msg "Q3: two enumerations must render (exit 0), got rc=$rc" - n="$(printf '%s\n' "$out" | grep -c 'id=ENUM-C[12]' || true)" + n="$(printf '%s\n' "$out" | count_lines 'id=ENUM-C[12]' || true)" [ "$n" = "2" ] || fail_msg "Q3: BOTH distinct enumerations must survive as SEPARATE orientation pointers (expected 2, got $n) — neither coalesced away" - printf '%s' "$out" | grep -q 'id=ENUM-C1' || fail_msg "Q3: enumeration ENUM-C1 must be present" - printf '%s' "$out" | grep -q 'id=ENUM-C2' || fail_msg "Q3: enumeration ENUM-C2 must be present" + printf '%s' "$out" | has_match -q 'id=ENUM-C1' || fail_msg "Q3: enumeration ENUM-C1 must be present" + printf '%s' "$out" | has_match -q 'id=ENUM-C2' || fail_msg "Q3: enumeration ENUM-C2 must be present" [ -s "$(dlq "$home")" ] && fail_msg "Q3: enumerations must NOT be quarantined" true ) && ok @@ -239,10 +242,10 @@ echo "== Q4: PRESERVED — a genuine malformed ACTIONABLE claim is STILL loud (d out="$("$DIGEST" render --from-file "$f" --agent default 2>"$err")" rc=$? [ "$rc" -eq 0 ] || fail_msg "Q4: render must exit 0 (per-entry quarantine), got rc=$rc" - printf '%s' "$out" | grep -q 'CLAIM-KEEP' && fail_msg "Q4: a malformed actionable must NOT be delivered as if valid" - printf '%s' "$out" | grep -q '(none) — no consequential claims pending' || fail_msg "Q4: with the only claim quarantined, the ACTIONABLE section must show (none)" - grep -q 'CLAIM-KEEP' "$(dlq "$home")" 2>/dev/null || fail_msg "Q4: the malformed actionable must be DEAD-LETTERED (loudly surfaced, not silent)" - grep -qi 'QUARANTINE' "$err" || fail_msg "Q4: the malformed actionable must raise a LOUD alarm" + printf '%s' "$out" | has_match -q 'CLAIM-KEEP' && fail_msg "Q4: a malformed actionable must NOT be delivered as if valid" + printf '%s' "$out" | has_match -q '(none) — no consequential claims pending' || fail_msg "Q4: with the only claim quarantined, the ACTIONABLE section must show (none)" + has_match -q 'CLAIM-KEEP' "$(dlq "$home")" 2>/dev/null || fail_msg "Q4: the malformed actionable must be DEAD-LETTERED (loudly surfaced, not silent)" + has_match -qi 'QUARANTINE' "$err" || fail_msg "Q4: the malformed actionable must raise a LOUD alarm" ) && ok echo "== Q5: claim-precedence gated — a non-actionable-class entry carrying a claim (no hard locator) is STILL quarantined ==" @@ -258,8 +261,8 @@ echo "== Q5: claim-precedence gated — a non-actionable-class entry carrying a out="$("$DIGEST" render --from-file "$f" --agent default 2>"$err")" rc=$? [ "$rc" -eq 0 ] || fail_msg "Q5: render must exit 0, got rc=$rc" - grep -q 'CLAIMY' "$(dlq "$home")" 2>/dev/null || fail_msg "Q5: a claim-carrying entry with no hard locator must be quarantined (claim precedence, §2.1)" - printf '%s' "$out" | grep -q 'CI is green' && fail_msg "Q5: the un-verifiable claim must NOT be delivered" + has_match -q 'CLAIMY' "$(dlq "$home")" 2>/dev/null || fail_msg "Q5: a claim-carrying entry with no hard locator must be quarantined (claim precedence, §2.1)" + printf '%s' "$out" | has_match -q 'CI is green' && fail_msg "Q5: the un-verifiable claim must NOT be delivered" true ) && ok @@ -278,11 +281,11 @@ echo "== Q6 (a): dead-lettered entry routes EXACTLY ONE off-host alarm (payload out="$("$DIGEST" render --from-file "$f" --agent default 2>"$err")" rc=$? [ "$rc" -eq 0 ] || fail_msg "Q6: render must still EXIT 0 (per-entry quarantine, not whole-drain wedge), got rc=$rc" - n="$(grep -c . "$ALARM_OUT" 2>/dev/null || true)" + n="$(count_lines . "$ALARM_OUT" 2>/dev/null || true)" [ "$n" = "1" ] || fail_msg "Q6: EXACTLY ONE off-host alarm must route for the dead-lettered entry (got $n) [$(cat "$ALARM_OUT" 2>/dev/null)]" - grep -q '"observed_seq":21' "$ALARM_OUT" 2>/dev/null || fail_msg "Q6: the routed alarm payload must name the entry's observed_seq (21)" - grep -qi 'QUARANTINE' "$err" || fail_msg "Q6: the existing #920 stderr diagnostic must STILL fire (local + off-host, not either/or)" - printf '%s' "$out" | grep -q 'DLQ-Q6' && fail_msg "Q6: the quarantined entry must still be EXCLUDED from the rendered digest" + has_match -q '"observed_seq":21' "$ALARM_OUT" 2>/dev/null || fail_msg "Q6: the routed alarm payload must name the entry's observed_seq (21)" + has_match -qi 'QUARANTINE' "$err" || fail_msg "Q6: the existing #920 stderr diagnostic must STILL fire (local + off-host, not either/or)" + printf '%s' "$out" | has_match -q 'DLQ-Q6' && fail_msg "Q6: the quarantined entry must still be EXCLUDED from the rendered digest" true ) && ok @@ -300,9 +303,9 @@ echo "== Q7 (b): re-draining the SAME still-dead-lettered entry N times routes Z for i in 1 2 3 4; do "$DIGEST" render --from-file "$f" --agent default >/dev/null 2>"$TMP_ROOT/q7.err.$i" done - n="$(grep -c . "$ALARM_OUT" 2>/dev/null || true)" + n="$(count_lines . "$ALARM_OUT" 2>/dev/null || true)" [ "$n" = "1" ] || fail_msg "Q7: re-draining the SAME dead-lettered entry 4x must route ONLY ONE off-host alarm total (durable dedup by observed_seq); got $n [$(cat "$ALARM_OUT" 2>/dev/null)]" - grep -qi 'QUARANTINE' "$TMP_ROOT/q7.err.4" || fail_msg "Q7: the #920 stderr diagnostic must STILL fire on every re-drain (only the off-host route is deduped)" + has_match -qi 'QUARANTINE' "$TMP_ROOT/q7.err.4" || fail_msg "Q7: the #920 stderr diagnostic must STILL fire on every re-drain (only the off-host route is deduped)" ) && ok echo "== Q8 (c): a NEW distinct dead-lettered entry routes its OWN one alarm (dedup is per-entry, not a global latch) ==" @@ -321,10 +324,10 @@ echo "== Q8 (c): a NEW distinct dead-lettered entry routes its OWN one alarm (de "$DIGEST" render --from-file "$f1" --agent default >/dev/null 2>/dev/null "$DIGEST" render --from-file "$f1" --agent default >/dev/null 2>/dev/null # re-drain seq 31 -> must NOT re-alarm "$DIGEST" render --from-file "$f2" --agent default >/dev/null 2>/dev/null # NEW distinct seq 32 -> its own alarm - n="$(grep -c . "$ALARM_OUT" 2>/dev/null || true)" + n="$(count_lines . "$ALARM_OUT" 2>/dev/null || true)" [ "$n" = "2" ] || fail_msg "Q8: two DISTINCT dead-lettered entries must together route exactly 2 off-host alarms total (got $n) [$(cat "$ALARM_OUT" 2>/dev/null)]" - grep -q '"observed_seq":31' "$ALARM_OUT" 2>/dev/null || fail_msg "Q8: seq 31's alarm must be present" - grep -q '"observed_seq":32' "$ALARM_OUT" 2>/dev/null || fail_msg "Q8: seq 32's (the new distinct entry's) OWN alarm must be present" + has_match -q '"observed_seq":31' "$ALARM_OUT" 2>/dev/null || fail_msg "Q8: seq 31's alarm must be present" + has_match -q '"observed_seq":32' "$ALARM_OUT" 2>/dev/null || fail_msg "Q8: seq 32's (the new distinct entry's) OWN alarm must be present" ) && ok echo "== Q9 (d): WAKE_ALARM_SINK_CMD unconfigured OR unreachable -> FAIL LOUD (never silent no-alarm); per-entry, render still exits 0 ==" @@ -340,9 +343,9 @@ echo "== Q9 (d): WAKE_ALARM_SINK_CMD unconfigured OR unreachable -> FAIL LOUD (n out_a="$("$DIGEST" render --from-file "$f" --agent default 2>"$err_a")" rc_a=$? [ "$rc_a" -eq 0 ] || fail_msg "Q9a: per-entry quarantine must still exit 0 even when the off-host alarm sink is unconfigured (no whole-drain wedge), got rc=$rc_a" - grep -qi 'FAIL LOUD' "$err_a" || fail_msg "Q9a: an unconfigured off-host alarm target must FAIL LOUD on stderr [$(cat "$err_a")]" - grep -Eqi 'silent no-alarm|silent-miss|PERMANENTLY miss|permanent silent miss' "$err_a" || fail_msg "Q9a: the diagnostic must name the silent-miss hazard (G2a), mirroring beacon.sh's fail-closed wording [$(cat "$err_a")]" - printf '%s' "$out_a" | grep -q 'DLQ-Q9' && fail_msg "Q9a: the quarantined entry must still be EXCLUDED from the rendered digest" + has_match -qi 'FAIL LOUD' "$err_a" || fail_msg "Q9a: an unconfigured off-host alarm target must FAIL LOUD on stderr [$(cat "$err_a")]" + has_match -Eqi 'silent no-alarm|silent-miss|PERMANENTLY miss|permanent silent miss' "$err_a" || fail_msg "Q9a: the diagnostic must name the silent-miss hazard (G2a), mirroring beacon.sh's fail-closed wording [$(cat "$err_a")]" + printf '%s' "$out_a" | has_match -q 'DLQ-Q9' && fail_msg "Q9a: the quarantined entry must still be EXCLUDED from the rendered digest" true ) && ok ( @@ -355,9 +358,9 @@ echo "== Q9 (d): WAKE_ALARM_SINK_CMD unconfigured OR unreachable -> FAIL LOUD (n out_b="$("$DIGEST" render --from-file "$f" --agent default 2>"$err_b")" rc_b=$? [ "$rc_b" -eq 0 ] || fail_msg "Q9b: per-entry quarantine must still exit 0 even when the off-host alarm sink is unreachable, got rc=$rc_b" - grep -qi 'FAIL LOUD' "$err_b" || fail_msg "Q9b: an unreachable off-host alarm target must FAIL LOUD on stderr [$(cat "$err_b")]" - grep -qi 'UNREACHABLE' "$err_b" || fail_msg "Q9b: the diagnostic must name the unreachable target [$(cat "$err_b")]" - printf '%s' "$out_b" | grep -q 'DLQ-Q9' && fail_msg "Q9b: the quarantined entry must still be EXCLUDED from the rendered digest" + has_match -qi 'FAIL LOUD' "$err_b" || fail_msg "Q9b: an unreachable off-host alarm target must FAIL LOUD on stderr [$(cat "$err_b")]" + has_match -qi 'UNREACHABLE' "$err_b" || fail_msg "Q9b: the diagnostic must name the unreachable target [$(cat "$err_b")]" + printf '%s' "$out_b" | has_match -q 'DLQ-Q9' && fail_msg "Q9b: the quarantined entry must still be EXCLUDED from the rendered digest" true ) && ok @@ -383,16 +386,16 @@ echo "== Q10: snapshot metadata (#940) — snapshot_sha/snapshot_ts render on th out="$("$DIGEST" render --from-file "$f" --agent default 2>/dev/null)" rc=$? [ "$rc" -eq 0 ] || fail_msg "Q10: render must succeed (rc=$rc)" - snapa_line="$(printf '%s\n' "$out" | grep 'id=SNAP-A' || true)" - printf '%s' "$snapa_line" | grep -q 'snapshot_sha=0123abc4567890def0123abc4567890def012345' \ + snapa_line="$(printf '%s\n' "$out" | has_match 'id=SNAP-A' || true)" + printf '%s' "$snapa_line" | has_match -q 'snapshot_sha=0123abc4567890def0123abc4567890def012345' \ || fail_msg "Q10: snapshot_sha must render on the ORIENTATION pointer line [$snapa_line]" - printf '%s' "$snapa_line" | grep -q 'snapshot_ts=1753850000' \ + printf '%s' "$snapa_line" | has_match -q 'snapshot_ts=1753850000' \ || fail_msg "Q10: snapshot_ts must render on the ORIENTATION pointer line (age = emit_ts - snapshot_ts, local arithmetic) [$snapa_line]" - printf '%s' "$out" | grep -q 'git show 0123abc4567890def0123abc4567890def012345:BOARD.md' \ + printf '%s' "$out" | has_match -q 'git show 0123abc4567890def0123abc4567890def012345:BOARD.md' \ || fail_msg "Q10: snapshot_sha+path must upgrade the actionable re-verify hint to a one-call git show" # The sibling without metadata must not grow empty snapshot_ fields. - snapb_line="$(printf '%s\n' "$out" | grep 'id=SNAP-B' || true)" - printf '%s' "$snapb_line" | grep -q 'snapshot_' \ + snapb_line="$(printf '%s\n' "$out" | has_match 'id=SNAP-B' || true)" + printf '%s' "$snapb_line" | has_match -q 'snapshot_' \ && fail_msg "Q10: an entry without metadata must render NO snapshot_ fields [$snapb_line]" true ) && ok @@ -434,28 +437,28 @@ echo "== Q11 (#944): REAL detector-shape actionable RENDERS as CLAIM@seq; addres [ "$rc" -eq 0 ] || fail_msg "Q11: render must exit 0, got rc=$rc" # (a) POSITIVE: the live entry RENDERS as an actionable claim (not merely # passes the predicate) with the one-call git-show re-verify hint. - printf '%s' "$out" | grep -q 'seq 68 — CLAIM@seq' || fail_msg "Q11a: the live seq-68 detector-shape entry must RENDER as CLAIM@seq (positive control)" - printf '%s' "$out" | grep -q 'git show 55d4909569d2b5fbccfec49ec9ca83db5049f3ce:docs/scratchpads/heartbeat-planning' \ + printf '%s' "$out" | has_match -q 'seq 68 — CLAIM@seq' || fail_msg "Q11a: the live seq-68 detector-shape entry must RENDER as CLAIM@seq (positive control)" + printf '%s' "$out" | has_match -q 'git show 55d4909569d2b5fbccfec49ec9ca83db5049f3ce:docs/scratchpads/heartbeat-planning' \ || fail_msg "Q11a: the rendered claim must carry the one-call re-verify hint git show :" # (b) POSITIVE: path arm alone suffices; hint degrades to one-call re-read. - printf '%s' "$out" | grep -q 'seq 69 — CLAIM@seq' || fail_msg "Q11b: a path-only detector-shape entry must RENDER as CLAIM@seq (path arm)" - printf '%s' "$out" | grep -q 're-read BOARD.md' || fail_msg "Q11b: the path-only claim must carry the one-call re-read hint" - n_claims="$(printf '%s\n' "$out" | grep -c 'CLAIM@seq' || true)" + printf '%s' "$out" | has_match -q 'seq 69 — CLAIM@seq' || fail_msg "Q11b: a path-only detector-shape entry must RENDER as CLAIM@seq (path arm)" + printf '%s' "$out" | has_match -q 're-read BOARD.md' || fail_msg "Q11b: the path-only claim must carry the one-call re-read hint" + n_claims="$(printf '%s\n' "$out" | count_lines 'CLAIM@seq' || true)" [ "$n_claims" = "2" ] || fail_msg "Q11: EXACTLY the two valid entries must render as CLAIM@seq (got $n_claims)" # (c)+(d) NEGATIVES retained: both quarantine, each with its OWN alarm. - printf '%s' "$out" | grep -q 'ADDR-FREE' && fail_msg "Q11c: the address-free entry must be EXCLUDED from the digest" - printf '%s' "$out" | grep -q 'SNAP-ONLY' && fail_msg "Q11d: no bare path-less snapshot_sha entry may appear in the digest (gate must not widen past board_file)" - grep -q 'ADDR-FREE' "$(dlq "$home")" 2>/dev/null || fail_msg "Q11c: the address-free entry must be DEAD-LETTERED" + printf '%s' "$out" | has_match -q 'ADDR-FREE' && fail_msg "Q11c: the address-free entry must be EXCLUDED from the digest" + printf '%s' "$out" | has_match -q 'SNAP-ONLY' && fail_msg "Q11d: no bare path-less snapshot_sha entry may appear in the digest (gate must not widen past board_file)" + has_match -q 'ADDR-FREE' "$(dlq "$home")" 2>/dev/null || fail_msg "Q11c: the address-free entry must be DEAD-LETTERED" for snap_id in SNAP-ONLY-40 SNAP-ONLY-7 SNAP-ONLY-64; do - grep -q "$snap_id" "$(dlq "$home")" 2>/dev/null || fail_msg "Q11d: the bare snapshot_sha entry ($snap_id) must be DEAD-LETTERED" + has_match -q "$snap_id" "$(dlq "$home")" 2>/dev/null || fail_msg "Q11d: the bare snapshot_sha entry ($snap_id) must be DEAD-LETTERED" done - grep -q 'heartbeat-planning' "$(dlq "$home")" 2>/dev/null && fail_msg "Q11a: the valid live entry must NOT be dead-lettered" - grep -q 'PILOT-LOCAL' "$(dlq "$home")" 2>/dev/null && fail_msg "Q11b: the valid path-only entry must NOT be dead-lettered" - n_alarms="$(grep -c . "$ALARM_OUT" 2>/dev/null || true)" + has_match -q 'heartbeat-planning' "$(dlq "$home")" 2>/dev/null && fail_msg "Q11a: the valid live entry must NOT be dead-lettered" + has_match -q 'PILOT-LOCAL' "$(dlq "$home")" 2>/dev/null && fail_msg "Q11b: the valid path-only entry must NOT be dead-lettered" + n_alarms="$(count_lines . "$ALARM_OUT" 2>/dev/null || true)" [ "$n_alarms" = "4" ] || fail_msg "Q11: exactly the four invalid entries must alarm (got $n_alarms) [$(cat "$ALARM_OUT" 2>/dev/null)]" - grep -q '"observed_seq":70' "$ALARM_OUT" 2>/dev/null || fail_msg "Q11c: seq 70's own alarm must be present" + has_match -q '"observed_seq":70' "$ALARM_OUT" 2>/dev/null || fail_msg "Q11c: seq 70's own alarm must be present" for snap_seq in 71 72 73; do - grep -q "\"observed_seq\":$snap_seq" "$ALARM_OUT" 2>/dev/null || fail_msg "Q11d: seq $snap_seq's own alarm must be present" + has_match -q "\"observed_seq\":$snap_seq" "$ALARM_OUT" 2>/dev/null || fail_msg "Q11d: seq $snap_seq's own alarm must be present" done true ) && ok @@ -477,15 +480,15 @@ echo "== Q12 (#946): quarantined entries are DISCLOSED (by seq, content withheld [ "$rc" -eq 0 ] || fail_msg "Q12: render must exit 0, got rc=$rc" # DISCLOSURE: a held entry must be VISIBLE in the digest it was held from — # a silent hold is how five successive digests each stepped past seq 68... - printf '%s' "$out" | grep -q 'QUARANTINED' || fail_msg "Q12: the digest must carry a QUARANTINED disclosure section (no silent hold)" - printf '%s' "$out" | grep -q 'seq 2 .*HELD' || fail_msg "Q12: the disclosure must name the held seq (2) as HELD" + printf '%s' "$out" | has_match -q 'QUARANTINED' || fail_msg "Q12: the digest must carry a QUARANTINED disclosure section (no silent hold)" + printf '%s' "$out" | has_match -q 'seq 2 .*HELD' || fail_msg "Q12: the disclosure must name the held seq (2) as HELD" # ...but WITHOUT re-injecting the refused content: disclosure is by seq only; # the Q1/Q4/Q5/Q6/Q9/Q11 exclusion property stands. - printf '%s' "$out" | grep -q 'ADDR-Q12' && fail_msg "Q12: the quarantined entry's content/locators must stay EXCLUDED from the digest" + printf '%s' "$out" | has_match -q 'ADDR-Q12' && fail_msg "Q12: the quarantined entry's content/locators must stay EXCLUDED from the digest" # CLAMP: the embedded ack stops BELOW the quarantined seq, and says so loudly. - printf '%s' "$out" | grep -Eq 'consumed --upto 1$' || fail_msg "Q12: the embedded ack must be CLAMPED to --upto 1 (below quarantined seq 2)" - printf '%s' "$out" | grep -Eq 'consumed --upto 2( |$)' && fail_msg "Q12: the raw observed cursor (2) must NOT be embedded while seq 2 is quarantined" - printf '%s' "$out" | grep -q 'ACK CLAMPED' || fail_msg "Q12: the clamp must be LOUDLY disclosed in the ACK section" + printf '%s' "$out" | has_match -Eq 'consumed --upto 1$' || fail_msg "Q12: the embedded ack must be CLAMPED to --upto 1 (below quarantined seq 2)" + printf '%s' "$out" | has_match -Eq 'consumed --upto 2( |$)' && fail_msg "Q12: the raw observed cursor (2) must NOT be embedded while seq 2 is quarantined" + printf '%s' "$out" | has_match -q 'ACK CLAMPED' || fail_msg "Q12: the clamp must be LOUDLY disclosed in the ACK section" # A foreign-data render must NOT rewrite the lane's quarantine truth. [ -e "$home/default/quarantined.set" ] && fail_msg "Q12: a --from-file render must NOT write the store's quarantined.set (lane truth is store-mode only)" true @@ -503,9 +506,9 @@ echo "== Q13 (#946): nothing quarantined -> ack UNCLAMPED at the observed cursor out="$("$DIGEST" render --from-file "$f" --agent default 2>/dev/null)" rc=$? [ "$rc" -eq 0 ] || fail_msg "Q13: render must exit 0, got rc=$rc" - printf '%s' "$out" | grep -Eq 'consumed --upto 1$' || fail_msg "Q13: with nothing quarantined the ack must embed the observed cursor (1) unchanged" - printf '%s' "$out" | grep -q 'QUARANTINED' && fail_msg "Q13: no disclosure section when nothing is quarantined" - printf '%s' "$out" | grep -q 'ACK CLAMPED' && fail_msg "Q13: no clamp note when nothing is quarantined" + printf '%s' "$out" | has_match -Eq 'consumed --upto 1$' || fail_msg "Q13: with nothing quarantined the ack must embed the observed cursor (1) unchanged" + printf '%s' "$out" | has_match -q 'QUARANTINED' && fail_msg "Q13: no disclosure section when nothing is quarantined" + printf '%s' "$out" | has_match -q 'ACK CLAMPED' && fail_msg "Q13: no clamp note when nothing is quarantined" true ) && ok @@ -520,8 +523,8 @@ echo "== Q14 (#946): store-mode render SYNCS quarantine truth into the store — out="$("$DIGEST" render --from-store --agent default 2>/dev/null)" rc=$? [ "$rc" -eq 0 ] || fail_msg "Q14: render must exit 0, got rc=$rc" - printf '%s' "$out" | grep -q 'QUARANTINED' || fail_msg "Q14: the store-mode digest must disclose the held entry" - printf '%s' "$out" | grep -Eq 'consumed --upto 1$' || fail_msg "Q14: the embedded ack must clamp to 1 (below quarantined seq 2)" + printf '%s' "$out" | has_match -q 'QUARANTINED' || fail_msg "Q14: the store-mode digest must disclose the held entry" + printf '%s' "$out" | has_match -Eq 'consumed --upto 1$' || fail_msg "Q14: the embedded ack must clamp to 1 (below quarantined seq 2)" qf="$home/default/quarantined.set" [ "$(cat "$qf" 2>/dev/null)" = "2" ] || fail_msg "Q14: a store-mode render must sync quarantined.set to exactly {2}, got [$(cat "$qf" 2>/dev/null)]" # END-TO-END: even a hand-typed upto past the held seq is refused at the @@ -545,8 +548,8 @@ echo "== Q15 (#946): gate-fix RECOVERY — a stale quarantined.set is REPLACED b out="$("$DIGEST" render --from-store --agent default 2>/dev/null)" rc=$? [ "$rc" -eq 0 ] || fail_msg "Q15: render must exit 0, got rc=$rc" - printf '%s' "$out" | grep -q 'QUARANTINED' && fail_msg "Q15: nothing quarantines under the fixed gate — no disclosure section" - printf '%s' "$out" | grep -Eq 'consumed --upto 2$' || fail_msg "Q15: the ack must embed the full observed cursor (2) once the gate is fixed" + printf '%s' "$out" | has_match -q 'QUARANTINED' && fail_msg "Q15: nothing quarantines under the fixed gate — no disclosure section" + printf '%s' "$out" | has_match -Eq 'consumed --upto 2$' || fail_msg "Q15: the ack must embed the full observed cursor (2) once the gate is fixed" [ -s "$home/default/quarantined.set" ] && fail_msg "Q15: the clean render must REPLACE (clear) the stale quarantined.set — a cumulative-forever set would block acks on entries that now render, got [$(cat "$home/default/quarantined.set")]" "$STORE" consume --upto 2 >/dev/null 2>&1 || fail_msg "Q15: the ordinary consume must succeed after the clamp self-heals" ) && ok @@ -557,7 +560,7 @@ echo "== Q16 (guard): Q2's ENUM-B fixture must STAY address-free — the reconci # Token concatenated so THIS guard's own source lines never contain the # literal fixture id and cannot self-match. enum_id='ENUM''-B' - fixture_line="$(grep -F "\"id\":\"$enum_id\"" "$self" | grep -F '"observed_seq":5' | head -n1)" + fixture_line="$(has_match -F "\"id\":\"$enum_id\"" "$self" | has_match -F '"observed_seq":5' | head -n1)" [ -n "$fixture_line" ] || fail_msg "Q16: could not locate Q2's $enum_id fixture line (renamed/renumbered? update this guard)" fixture_json="$(printf '%s' "$fixture_line" | sed "s/.*'\({.*}\)'.*/\1/")" # Positive controls FIRST (blind-instrument rule): the extraction must yield @@ -578,7 +581,7 @@ echo "== Q16 (guard): Q2's ENUM-B fixture must STAY address-free — the reconci echo if [ -s "$FAILFILE" ]; then - echo "wake digest-quarantine harness: FAILED ($(grep -c . "$FAILFILE") assertion(s))" >&2 + echo "wake digest-quarantine harness: FAILED ($(count_lines . "$FAILFILE") assertion(s))" >&2 exit 1 fi echo "wake digest-quarantine harness: all invariants passed ($pass groups)" diff --git a/packages/mosaic/framework/tools/wake/test-wake-fn-oracle.sh b/packages/mosaic/framework/tools/wake/test-wake-fn-oracle.sh index e3766326..f97eb1a1 100755 --- a/packages/mosaic/framework/tools/wake/test-wake-fn-oracle.sh +++ b/packages/mosaic/framework/tools/wake/test-wake-fn-oracle.sh @@ -25,6 +25,9 @@ set -uo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness. +# shellcheck disable=SC1091 +. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init ORACLE="$SCRIPT_DIR/fn-oracle.sh" DET="$SCRIPT_DIR/detector.sh" @@ -62,8 +65,8 @@ echo "== O1: healthy pipeline -> synthetic-canary FN-rate = 0 ==" out="$("$ORACLE" run --slo-seconds 120 --count 3 2>&1)" rc=$? [ "$rc" -eq 0 ] || fail_msg "O1: a healthy pipeline must exit 0 (got $rc) [$out]" - echo "$out" | grep -q 'FN-RATE = 0/3' || fail_msg "O1: FN-rate must be 0/3 on a healthy pipeline [$out]" - echo "$out" | grep -q 'VERDICT = PASS' || fail_msg "O1: verdict must be PASS on a healthy pipeline [$out]" + echo "$out" | has_match -q 'FN-RATE = 0/3' || fail_msg "O1: FN-rate must be 0/3 on a healthy pipeline [$out]" + echo "$out" | has_match -q 'VERDICT = PASS' || fail_msg "O1: verdict must be PASS on a healthy pipeline [$out]" ) && ok echo "== O2: DISABLED detector (perfect no-op) -> FN-DETECTED (blindspot killer) ==" @@ -76,9 +79,9 @@ echo "== O2: DISABLED detector (perfect no-op) -> FN-DETECTED (blindspot killer) out="$("$ORACLE" run --slo-seconds 120 --count 3 2>&1)" rc=$? [ "$rc" -ne 0 ] || fail_msg "O2: a detector that drops a KNOWN delta MUST fail the oracle (non-zero exit), even at a perfect no-op rate" - echo "$out" | grep -q 'FN-RATE = 3/3' || fail_msg "O2: every dropped canary must count as a false-negative (FN-RATE 3/3) [$out]" - echo "$out" | grep -q 'VERDICT = FN-DETECTED' || fail_msg "O2: verdict must be FN-DETECTED for a dropping detector [$out]" - echo "$out" | grep -qi 'never OBSERVED' || fail_msg "O2: the failure must name the dropped (never-observed) delta [$out]" + echo "$out" | has_match -q 'FN-RATE = 3/3' || fail_msg "O2: every dropped canary must count as a false-negative (FN-RATE 3/3) [$out]" + echo "$out" | has_match -q 'VERDICT = FN-DETECTED' || fail_msg "O2: verdict must be FN-DETECTED for a dropping detector [$out]" + echo "$out" | has_match -qi 'never OBSERVED' || fail_msg "O2: the failure must name the dropped (never-observed) delta [$out]" ) && ok echo "== O3: reached CONSUMED but too slow -> FN-DETECTED (within-SLO clause) ==" @@ -91,10 +94,10 @@ echo "== O3: reached CONSUMED but too slow -> FN-DETECTED (within-SLO clause) == out="$("$ORACLE" run --slo-seconds 1 --count 1 2>&1)" rc=$? [ "$rc" -ne 0 ] || fail_msg "O3: a canary that reaches CONSUMED past its SLO must be a false-negative (non-zero exit)" - echo "$out" | grep -qi 'per-class SLO' || fail_msg "O3: the failure must attribute to the per-class SLO, not a drop [$out]" + echo "$out" | has_match -qi 'per-class SLO' || fail_msg "O3: the failure must attribute to the per-class SLO, not a drop [$out]" # It must NOT be the 'never observed' branch: the delta WAS observed/delivered, # just too slowly. This proves O3 exercises the SLO clause specifically. - if echo "$out" | grep -qi 'never OBSERVED'; then + if echo "$out" | has_match -qi 'never OBSERVED'; then fail_msg "O3: an SLO breach must NOT be misreported as a dropped delta [$out]" fi ) && ok @@ -110,7 +113,7 @@ echo "== O4: verdict is OFF-DOMAIN (from terminal consumed_seq, not detector sel out="$("$ORACLE" run --slo-seconds 120 --count 1 2>&1)" rc=$? [ "$rc" -ne 0 ] || fail_msg "O4: a drive that exits 0 but delivers nothing must still be FN-DETECTED (verdict is off-domain)" - echo "$out" | grep -q 'VERDICT = FN-DETECTED' || fail_msg "O4: off-domain verdict must not be fooled by a clean exit code [$out]" + echo "$out" | has_match -q 'VERDICT = FN-DETECTED' || fail_msg "O4: off-domain verdict must not be fooled by a clean exit code [$out]" ) && ok echo "== O5: no invented SLO -> --slo-seconds is REQUIRED (fail-loud) ==" @@ -121,12 +124,12 @@ echo "== O5: no invented SLO -> --slo-seconds is REQUIRED (fail-loud) ==" err="$("$ORACLE" run --count 1 2>&1)" rc=$? [ "$rc" -ne 0 ] || fail_msg "O5: run without an SLO must fail loud (no invented default)" - echo "$err" | grep -qi 'slo' || fail_msg "O5: the usage error must name the missing SLO [$err]" + echo "$err" | has_match -qi 'slo' || fail_msg "O5: the usage error must name the missing SLO [$err]" ) && ok echo if [ -s "$FAILFILE" ]; then - echo "wake fn-oracle harness: FAILED ($(grep -c . "$FAILFILE") assertion(s))" >&2 + echo "wake fn-oracle harness: FAILED ($(count_lines . "$FAILFILE") assertion(s))" >&2 exit 1 fi echo "wake fn-oracle harness: all invariants passed ($pass groups)" diff --git a/packages/mosaic/framework/tools/wake/test-wake-install.sh b/packages/mosaic/framework/tools/wake/test-wake-install.sh index 794e0293..852c1378 100755 --- a/packages/mosaic/framework/tools/wake/test-wake-install.sh +++ b/packages/mosaic/framework/tools/wake/test-wake-install.sh @@ -34,6 +34,9 @@ set -uo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness. +# shellcheck disable=SC1091 +. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init WI="$SCRIPT_DIR/wake-install.sh" BEACON="$SCRIPT_DIR/beacon.sh" FRAMEWORK_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" @@ -94,7 +97,7 @@ EOF export WAKE_INSTALL_MANIFEST="$BAD_MANIFEST" out="$(bash "$WI" install 2>&1)"; rc=$? [ "$rc" -ne 0 ] || fail_msg "I2: install must FAIL when a wake candidate is not framework-owned (got rc=$rc)" - echo "$out" | grep -qi 'Gate A VIOLATION' || fail_msg "I2: refusal must name the Gate A violation [$out]" + echo "$out" | has_match -qi 'Gate A VIOLATION' || fail_msg "I2: refusal must name the Gate A violation [$out]" # No partial write: the target must have received NO wake tool file. [ ! -e "$TGT/tools/wake/beacon.sh" ] || fail_msg "I2: a refused install must not have written any wake file (partial write leaked)" # And the positive control: with the REAL manifest, the same candidates install. @@ -121,7 +124,7 @@ EOF || fail_msg "I3: blank-reset drop-in write failed" out="$(bash "$WI" verify-single "$UNIT" 2>&1)"; rc=$? [ "$rc" -eq 0 ] || fail_msg "I3: blank-reset must resolve exactly one OnUnitActiveUSec (rc=$rc) [$out]" - echo "$out" | grep -qi 'EXACTLY ONE' || fail_msg "I3: verify must confirm exactly-one [$out]" + echo "$out" | has_match -qi 'EXACTLY ONE' || fail_msg "I3: verify must confirm exactly-one [$out]" # NEGATIVE CONTROL: a drop-in WITHOUT the reset line appends -> TWO values -> fail. cat >"$UD/$UNIT.d/interval.conf" <<'EOF' [Timer] @@ -141,7 +144,7 @@ echo "== I4: snapshot-guard — reap without a snapshot is REFUSED; allowed afte # (a) reap WITHOUT snapshot -> refuse, unit still present. out="$(bash "$WI" reap-unit "$UNIT" 2>&1)"; rc=$? [ "$rc" -ne 0 ] || fail_msg "I4: reap without a snapshot must be REFUSED (rc=$rc)" - echo "$out" | grep -qi 'snapshot-guard' || fail_msg "I4: refusal must name the snapshot-guard [$out]" + echo "$out" | has_match -qi 'snapshot-guard' || fail_msg "I4: refusal must name the snapshot-guard [$out]" [ -f "$UD/$UNIT" ] || fail_msg "I4: a refused reap must NOT delete the unit" # (b) snapshot, then reap -> allowed, unit gone, snapshot retained. bash "$WI" snapshot-unit "$UNIT" >/dev/null 2>&1 || fail_msg "I4: snapshot-unit failed" @@ -161,28 +164,28 @@ echo "== I5: fail-closed install-validate — unconfigured HMAC/alarm FAIL LOUD; export WAKE_HMAC_KEY_NAME="primary" out="$(bash "$WI" validate-hmac-key 2>&1)"; rc=$? [ "$rc" -ne 0 ] || fail_msg "I5: missing credential store must FAIL LOUD for the HMAC key (rc=$rc)" - echo "$out" | grep -qi 'UNSIGNED' || fail_msg "I5: HMAC failure must warn about unsigned wakes [$out]" + echo "$out" | has_match -qi 'UNSIGNED' || fail_msg "I5: HMAC failure must warn about unsigned wakes [$out]" # Now provide the key by-name -> pass, and the value must NEVER be echoed. jq -cn --arg k "$SECRET_KEY" '{wake:{hmac_keys:{"primary":$k}}}' >"$CRED" out2="$(bash "$WI" validate-hmac-key 2>&1)"; rc2=$? [ "$rc2" -eq 0 ] || fail_msg "I5: a by-name-resolvable HMAC key must pass (rc=$rc2) [$out2]" - echo "$out2" | grep -qF "$SECRET_KEY" && fail_msg "I5: validate must NEVER echo the HMAC key material" + echo "$out2" | has_match -qF "$SECRET_KEY" && fail_msg "I5: validate must NEVER echo the HMAC key material" # --- alarm target: unconfigured -> fail loud (silent no-alarm host). unset WAKE_ALARM_SINK_CMD out3="$(bash "$WI" validate-alarm-target 2>&1)"; rc3=$? [ "$rc3" -ne 0 ] || fail_msg "I5: unconfigured alarm target must FAIL LOUD (rc=$rc3)" - echo "$out3" | grep -qi 'silent no-alarm host' || fail_msg "I5: alarm failure must name the silent-no-alarm hazard [$out3]" + echo "$out3" | has_match -qi 'silent no-alarm host' || fail_msg "I5: alarm failure must name the silent-no-alarm hazard [$out3]" # unreachable -> fail loud. export WAKE_ALARM_SINK_CMD="false" out4="$(bash "$WI" validate-alarm-target 2>&1)"; rc4=$? [ "$rc4" -ne 0 ] || fail_msg "I5: unreachable alarm sink must FAIL LOUD (rc=$rc4)" - echo "$out4" | grep -qi 'UNREACHABLE' || fail_msg "I5: alarm failure must name the unreachable target [$out4]" + echo "$out4" | has_match -qi 'UNREACHABLE' || fail_msg "I5: alarm failure must name the unreachable target [$out4]" # reachable -> pass. export WAKE_ALARM_SINK_CMD="cat >/dev/null" bash "$WI" validate-alarm-target >/dev/null 2>&1 || fail_msg "I5: a configured+reachable alarm sink must pass" # The installer file must inline NO secret/endpoint. - grep -qF "$SECRET_ENDPOINT" "$WI" && fail_msg "I5: wake-install.sh must NOT inline any alarm endpoint" - grep -qE 'hmac_keys[^A-Za-z_].*=[^=].*[A-Za-z0-9]{8,}' "$WI" && fail_msg "I5: wake-install.sh must NOT inline key material" + has_match -qF "$SECRET_ENDPOINT" "$WI" && fail_msg "I5: wake-install.sh must NOT inline any alarm endpoint" + has_match -qE 'hmac_keys[^A-Za-z_].*=[^=].*[A-Za-z0-9]{8,}' "$WI" && fail_msg "I5: wake-install.sh must NOT inline key material" true ) && ok @@ -204,7 +207,7 @@ echo "== I6: reset->verify->retire — overlap keeps legacy running; only §4-ve [ "$rc" -eq 0 ] || fail_msg "I6: overlap reset-verify must succeed (rc=$rc) [$out]" [ -f "$UD/$TIMER" ] || fail_msg "I6: overlap phase must LEAVE the legacy timer running (retire withheld)" [ -f "$SNAP/$TIMER" ] || fail_msg "I6: the legacy timer must be snapshotted before any retire" - echo "$out" | grep -qi 'LEFT RUNNING' || fail_msg "I6: overlap must announce retire is withheld [$out]" + echo "$out" | has_match -qi 'LEFT RUNNING' || fail_msg "I6: overlap must announce retire is withheld [$out]" # (b) §4-vector pass: retire LAST, snapshot-guarded (fallback proven live above). out2="$(bash "$WI" reset-verify-retire c --interval 30min --vector-passed 2>&1)"; rc2=$? [ "$rc2" -eq 0 ] || fail_msg "I6: vector-passed retire must succeed (rc=$rc2) [$out2]" @@ -283,11 +286,11 @@ echo "== I9: dep-check — a host seed missing _lib/manifest.sh FAILS LOUD (name TGT="$(fresh i9-target)" out="$(WAKE_INSTALL_SOURCE="$FAKE" WAKE_INSTALL_TARGET="$TGT" bash "$WI_FAKE" install 2>&1)"; rc=$? [ "$rc" -ne 0 ] || fail_msg "I9: install MUST fail when _lib/manifest.sh is missing (rc=$rc)" - echo "$out" | grep -qi 'manifest.sh' || fail_msg "I9: the failure must NAME the missing library (manifest.sh) [$out]" - echo "$out" | grep -qiE 'REMEDY|mosaic update|re-seed|framework install' \ + echo "$out" | has_match -qi 'manifest.sh' || fail_msg "I9: the failure must NAME the missing library (manifest.sh) [$out]" + echo "$out" | has_match -qiE 'REMEDY|mosaic update|re-seed|framework install' \ || fail_msg "I9: the failure must give an actionable REMEDY, not just an error [$out]" # It must be a CLEAR fail-loud, NOT the obscure bare `source: No such file or directory`. - echo "$out" | grep -qi 'No such file or directory' \ + echo "$out" | has_match -qi 'No such file or directory' \ && fail_msg "I9: must not fail with a bare source error (obscure) [$out]" # Positive control: with the helper present (real framework root) install succeeds. TGT_OK="$(fresh i9-target-ok)" @@ -313,10 +316,10 @@ echo "== I10: systemd search-path — install links mosaic-wake.service into the rm -f "$UD/mosaic-wake.service" out2="$(bash "$WI" validate-systemd-path 2>&1)"; rc2=$? [ "$rc2" -ne 0 ] || fail_msg "I10: validate must FAIL when the unit is not in the search path (rc=$rc2) [$out2]" - echo "$out2" | grep -qi 'search path' || fail_msg "I10: validate failure must name the search-path miss [$out2]" + echo "$out2" | has_match -qi 'search path' || fail_msg "I10: validate failure must name the search-path miss [$out2]" # (c) idempotent re-install: exactly one search-path entry, still resolvable. bash "$WI" install >/dev/null 2>&1 || fail_msg "I10: re-run install must succeed" - n="$(find "$UD" -maxdepth 1 -name 'mosaic-wake.service' | grep -c .)" + n="$(find "$UD" -maxdepth 1 -name 'mosaic-wake.service' | count_lines .)" [ "$n" -eq 1 ] || fail_msg "I10: re-install must not duplicate the search-path entry (found $n)" bash "$WI" validate-systemd-path >/dev/null 2>&1 || fail_msg "I10: re-install must keep the unit resolvable" ) && ok @@ -334,12 +337,12 @@ echo "== I11: F7 — the legacy reap REFUSES unless the canon fallback wake is p # it must REFUSE (schedulable floor not met). out0="$(bash "$WI" fallback-proven-live 2>&1)"; rc0=$? [ "$rc0" -ne 0 ] || fail_msg "I11: fallback-proven-live must FAIL when the fallback wake is not installed (rc=$rc0)" - echo "$out0" | grep -qi 'F7' || fail_msg "I11: the refusal must name the F7 precondition [$out0]" + echo "$out0" | has_match -qi 'F7' || fail_msg "I11: the refusal must name the F7 precondition [$out0]" # (b) NEGATIVE — vector-passed reap with NO live fallback must be REFUSED and the # legacy timer LEFT RUNNING (never a coverage gap). out="$(bash "$WI" reset-verify-retire f --interval 30min --vector-passed 2>&1)"; rc=$? [ "$rc" -ne 0 ] || fail_msg "I11: reap must be REFUSED without a proven-live fallback (rc=$rc)" - echo "$out" | grep -qi 'FALLBACK WAKE is not proven live' || fail_msg "I11: refusal must name the un-proven fallback [$out]" + echo "$out" | has_match -qi 'FALLBACK WAKE is not proven live' || fail_msg "I11: refusal must name the un-proven fallback [$out]" [ -f "$UD/$TIMER" ] || fail_msg "I11: a refused reap must LEAVE the legacy timer running (F7 — no coverage gap)" # (c) POSITIVE — provision the fallback at the schedulable floor, then the reap # proceeds (F7 satisfied) and the legacy timer is retired. @@ -367,11 +370,11 @@ echo "== I12: fallback drain — a STALLED detector still gets delivery via the # even with no detector running — no starvation of the drain. out="$(bash "$DIGEST" render --from-store 2>/dev/null)"; rc=$? [ "$rc" -eq 0 ] || fail_msg "I12: the canon fallback drain must exit 0 (rc=$rc)" - echo "$out" | grep -q 'STALLED-DRAIN-MARK' \ + echo "$out" | has_match -q 'STALLED-DRAIN-MARK' \ || fail_msg "I12: the fallback drain must DELIVER the pending obligation a stalled detector left (no delivery starvation) [$out]" # Bind the invariant to the SHIPPED unit: its ExecStart must be this canon drain. UNIT="$FRAMEWORK_ROOT/systemd/user/mosaic-wake-fallback.service" - grep -qE '^ExecStart=.*digest\.sh render --from-store' "$UNIT" \ + has_match -qE '^ExecStart=.*digest\.sh render --from-store' "$UNIT" \ || fail_msg "I12: mosaic-wake-fallback.service ExecStart must fire the canon drain (digest.sh render --from-store)" ) && ok @@ -391,11 +394,11 @@ echo "== I13: install links + validates the canon fallback timer+service into th rm -f "$UD/mosaic-wake-fallback.timer" out="$(bash "$WI" validate-fallback-units 2>&1)"; rc=$? [ "$rc" -ne 0 ] || fail_msg "I13: validate must FAIL when a fallback unit is not in the search path (rc=$rc) [$out]" - echo "$out" | grep -qi 'search path' || fail_msg "I13: validate failure must name the search-path miss [$out]" + echo "$out" | has_match -qi 'search path' || fail_msg "I13: validate failure must name the search-path miss [$out]" # (c) idempotent re-install: exactly one entry per unit, still resolvable. bash "$WI" install >/dev/null 2>&1 || fail_msg "I13: re-run install must succeed" - nt="$(find "$UD" -maxdepth 1 -name 'mosaic-wake-fallback.timer' | grep -c .)" - ns="$(find "$UD" -maxdepth 1 -name 'mosaic-wake-fallback.service' | grep -c .)" + nt="$(find "$UD" -maxdepth 1 -name 'mosaic-wake-fallback.timer' | count_lines .)" + ns="$(find "$UD" -maxdepth 1 -name 'mosaic-wake-fallback.service' | count_lines .)" [ "$nt" -eq 1 ] && [ "$ns" -eq 1 ] || fail_msg "I13: re-install must not duplicate the fallback entries (timer=$nt service=$ns)" bash "$WI" validate-fallback-units >/dev/null 2>&1 || fail_msg "I13: re-install must keep the fallback units resolvable" ) && ok @@ -407,17 +410,17 @@ echo "== I14: per-class fallback cadence — blank-reset yields EXACTLY ONE OnUn TIMER="mosaic-wake-fallback.timer" # The shipped timer carries the base OnUnitActiveSec placeholder (=1h). cp "$FRAMEWORK_ROOT/systemd/user/$TIMER" "$UD/$TIMER" - grep -q '^OnUnitActiveSec=1h' "$UD/$TIMER" || fail_msg "I14: shipped fallback timer must carry a base OnUnitActiveSec placeholder" + has_match -q '^OnUnitActiveSec=1h' "$UD/$TIMER" || fail_msg "I14: shipped fallback timer must carry a base OnUnitActiveSec placeholder" # write-fallback-cadence writes the per-class cadence in BLANK-RESET form. out="$(bash "$WI" write-fallback-cadence 30min 2>&1)"; rc=$? [ "$rc" -eq 0 ] || fail_msg "I14: write-fallback-cadence must succeed + verify single (rc=$rc) [$out]" - echo "$out" | grep -qi 'exactly one' || fail_msg "I14: the cadence write must confirm exactly-one OnUnitActiveUSec [$out]" + echo "$out" | has_match -qi 'exactly one' || fail_msg "I14: the cadence write must confirm exactly-one OnUnitActiveUSec [$out]" [ -f "$UD/$TIMER.d/cadence.conf" ] || fail_msg "I14: the per-class cadence drop-in must be written under .d/" # Assert the blank-reset FORM: an empty `OnUnitActiveSec=` reset line IMMEDIATELY # FOLLOWED by the new value. Portable across GNU and BusyBox grep (Alpine CI) — # `grep -z` (NUL-data) is a GNU-only extension BusyBox grep does NOT support, so # match the reset line and require the value on the very next line (-A1) instead. - grep -A1 '^OnUnitActiveSec=$' "$UD/$TIMER.d/cadence.conf" | grep -qx 'OnUnitActiveSec=30min' \ + has_match -A1 '^OnUnitActiveSec=$' "$UD/$TIMER.d/cadence.conf" | has_match -qx 'OnUnitActiveSec=30min' \ || fail_msg "I14: the drop-in must use the blank-reset form (empty reset line, then the value)" bash "$WI" verify-single "$TIMER" >/dev/null 2>&1 || fail_msg "I14: base(1h)+blank-reset(30min) must resolve exactly one OnUnitActiveUSec" # NEGATIVE CONTROL: a drop-in WITHOUT the reset line appends -> base 1h + 30min -> two -> fail. @@ -428,7 +431,7 @@ echo "== I14: per-class fallback cadence — blank-reset yields EXACTLY ONE OnUn echo if [ -s "$FAILFILE" ]; then - echo "wake install harness: FAILED ($(grep -c . "$FAILFILE") assertion(s))" >&2 + echo "wake install harness: FAILED ($(count_lines . "$FAILFILE") assertion(s))" >&2 exit 1 fi echo "wake install harness: all invariants passed ($pass groups)" diff --git a/packages/mosaic/framework/tools/wake/test-wake-preimage.sh b/packages/mosaic/framework/tools/wake/test-wake-preimage.sh index f9058e60..3380dd5a 100755 --- a/packages/mosaic/framework/tools/wake/test-wake-preimage.sh +++ b/packages/mosaic/framework/tools/wake/test-wake-preimage.sh @@ -46,6 +46,9 @@ set -uo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness. +# shellcheck disable=SC1091 +. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init PRE="$SCRIPT_DIR/preimage.sh" STORE="$SCRIPT_DIR/store.sh" DET="$SCRIPT_DIR/detector.sh" @@ -202,9 +205,9 @@ echo "== P4: credential-store PATH refused — bytes never captured (acceptance sd="$(state_dir)" row="$(tail -n1 "$sd/preimage/preimage-ledger.jsonl")" [ "$(jq -r '.captured' <<<"$row")" = "false" ] || fail_msg "P4: row must record captured=false [$row]" - jq -r '.refused // ""' <<<"$row" | grep -qi 'path' || fail_msg "P4: refusal must name the path deny [$row]" + jq -r '.refused // ""' <<<"$row" | has_match -qi 'path' || fail_msg "P4: refusal must name the path deny [$row]" # THE invariant: the secret bytes exist NOWHERE under the wake state dir. - if grep -rq "$secret" "$sd" 2>/dev/null; then + if has_match -rq "$secret" "$sd" 2>/dev/null; then fail_msg "P4: credential bytes leaked into the wake state dir" fi ) && ok @@ -225,8 +228,8 @@ echo "== P5: secret-SHAPED content refused (refusal, not redaction) ==" sd="$(state_dir)" row="$(tail -n1 "$sd/preimage/preimage-ledger.jsonl")" [ "$(jq -r '.captured' <<<"$row")" = "false" ] || fail_msg "P5: row must record captured=false [$row]" - jq -r '.refused // ""' <<<"$row" | grep -qi 'secret' || fail_msg "P5: refusal must name secret-shaped content [$row]" - if grep -rq "$tok" "$sd" 2>/dev/null; then + jq -r '.refused // ""' <<<"$row" | has_match -qi 'secret' || fail_msg "P5: refusal must name secret-shaped content [$row]" + if has_match -rq "$tok" "$sd" 2>/dev/null; then fail_msg "P5: secret-shaped bytes leaked into the wake state dir" fi ) && ok @@ -275,7 +278,7 @@ echo "== P8: unresolvable adapter -> FAIL LOUD, never 'no change' (D2 class) ==" unset WAKE_WATCH_LIST WAKE_PREIMAGE_EXTRA MOSAIC_HOME out="$("$PRE" check --enqueue 2>&1)"; rc=$? [ "$rc" -ne 0 ] || fail_msg "P8: an unobservable preimage definition must FAIL LOUD (rc=0)" - echo "$out" | grep -qi 'does not resolve' || fail_msg "P8: the failure must name the unresolvable adapter [$out]" + echo "$out" | has_match -qi 'does not resolve' || fail_msg "P8: the failure must name the unresolvable adapter [$out]" ) && ok echo "== P9: corrupt ledger -> REFUSE to compare/re-baseline ==" @@ -294,7 +297,7 @@ echo "== P9: corrupt ledger -> REFUSE to compare/re-baseline ==" printf 'v2 changed\n' >"$fx/f.env" out="$("$PRE" check --enqueue 2>&1)"; rc=$? [ "$rc" -ne 0 ] || fail_msg "P9: a corrupt ledger must FAIL LOUD (rc=0)" - echo "$out" | grep -qi 'unparseable' || fail_msg "P9: the failure must name the corrupt ledger [$out]" + echo "$out" | has_match -qi 'unparseable' || fail_msg "P9: the failure must name the corrupt ledger [$out]" [ "$(wc -l <"$sd/preimage/preimage-ledger.jsonl")" = "$r1" ] || fail_msg "P9: nothing may be appended over corrupt history" ) && ok @@ -314,7 +317,7 @@ echo "== P10: oversized file -> bytes refused, hash still recorded ==" sd="$(state_dir)" row="$(tail -n1 "$sd/preimage/preimage-ledger.jsonl")" [ "$(jq -r '.captured' <<<"$row")" = "false" ] || fail_msg "P10: row must record captured=false [$row]" - jq -r '.refused // ""' <<<"$row" | grep -qi 'MAX_BYTES' || fail_msg "P10: refusal must name the size cap [$row]" + jq -r '.refused // ""' <<<"$row" | has_match -qi 'MAX_BYTES' || fail_msg "P10: refusal must name the size cap [$row]" sha="$(jq -r '.sha256' <<<"$row")" [ "$sha" = "$(sha256sum "$fx/big.bin" | awk '{print $1}')" ] || fail_msg "P10: hash must still be recorded [$row]" [ ! -f "$sd/preimage/objects/$sha" ] || fail_msg "P10: oversized bytes must NOT be stored" @@ -362,7 +365,7 @@ echo "== P12: detector — preimage infra failure is LOUD but does not starve ob printf 'NOT-JSON-GARBAGE{{{\n' >"$sd/preimage/preimage-ledger.jsonl" out="$("$DET" poll-once 2>&1)"; rc=$? [ "$rc" -ne 0 ] || fail_msg "P12: the pass must exit non-zero on preimage infra failure" - echo "$out" | grep -qi 'preimage' || fail_msg "P12: the failure must name the preimage check [$out]" + echo "$out" | has_match -qi 'preimage' || fail_msg "P12: the failure must name the preimage check [$out]" n="$(find "$sd/detector" -name 'watch-*.hash' 2>/dev/null | wc -l | tr -d '[:space:]')" [ "$n" -ge 1 ] || fail_msg "P12: source observation must still proceed (no watch hash baselined)" ) && ok @@ -397,10 +400,10 @@ echo "== P13: symlinked/renamed credential store refused on BOTH path forms (#96 n="$(jq -r 'select(.captured == false) | .path' "$sd/preimage/preimage-ledger.jsonl" | wc -l | tr -d '[:space:]')" [ "$n" = "2" ] || fail_msg "P13: both decoys must record captured=false (got $n)" # THE invariant (decoy method): the planted bytes exist NOWHERE in state. - if grep -rq "$s1" "$sd" 2>/dev/null; then + if has_match -rq "$s1" "$sd" 2>/dev/null; then fail_msg "P13: renamed-target store bytes leaked into the wake state dir" fi - if grep -rq "$s2" "$sd" 2>/dev/null; then + if has_match -rq "$s2" "$sd" 2>/dev/null; then fail_msg "P13: prefix-less key bytes leaked into the wake state dir" fi ) && ok @@ -423,7 +426,7 @@ echo "== P14: detector.env-class key — safe WITHOUT opt-in by polarity, refuse sd="$(state_dir)" row="$(tail -n1 "$sd/preimage/preimage-ledger.jsonl")" [ "$(jq -r '.captured' <<<"$row")" = "false" ] || fail_msg "P14a: extra must be record-only without opt-in [$row]" - if grep -rq "$hm" "$sd" 2>/dev/null; then + if has_match -rq "$hm" "$sd" 2>/dev/null; then fail_msg "P14a: key bytes leaked without any opt-in" fi # (b) The operator opts the env file in (the exact error the old usage text @@ -434,8 +437,8 @@ echo "== P14: detector.env-class key — safe WITHOUT opt-in by polarity, refuse [ "$rc" -eq 0 ] || fail_msg "P14b: refusal is not an infra failure (rc=$rc) [$out]" row="$(tail -n1 "$sd/preimage/preimage-ledger.jsonl")" [ "$(jq -r '.captured' <<<"$row")" = "false" ] || fail_msg "P14b: opted-in key material must still refuse [$row]" - jq -r '.refused // ""' <<<"$row" | grep -qi 'secret' || fail_msg "P14b: refusal must name secret-shaped content [$row]" - if grep -rq "$hm" "$sd" 2>/dev/null; then + jq -r '.refused // ""' <<<"$row" | has_match -qi 'secret' || fail_msg "P14b: refusal must name secret-shaped content [$row]" + if has_match -rq "$hm" "$sd" 2>/dev/null; then fail_msg "P14b: key bytes leaked despite refusal" fi ) && ok @@ -488,7 +491,7 @@ echo "== P16: deleted ledger over surviving objects/ — REFUSE to re-baseline ( printf '# v3\n' >>"$fx/adapter.sh" out="$("$PRE" check --enqueue 2>&1)"; rc=$? [ "$rc" -ne 0 ] || fail_msg "P16: absent ledger over prior objects must FAIL LOUD (rc=0) [$out]" - echo "$out" | grep -qi 'REFUSING to re-baseline' || fail_msg "P16: the failure must name the refusal [$out]" + echo "$out" | has_match -qi 'REFUSING to re-baseline' || fail_msg "P16: the failure must name the refusal [$out]" [ ! -e "$sd/preimage/preimage-ledger.jsonl" ] || fail_msg "P16: the ledger must NOT be silently recreated over deleted history" [ "$(ls "$sd/preimage/objects" | wc -l | tr -d '[:space:]')" = "$nobj" ] || fail_msg "P16: prior objects must remain untouched" [ "$(depth)" = "0" ] || fail_msg "P16: the v2->v3 change must NOT be absorbed or enqueued from an unverifiable baseline (depth=$(depth))" @@ -520,7 +523,7 @@ echo "== P17: allowlist symmetry — symlink to a DENIED target refuses; symlink sd="$(state_dir)" crow="$(jq -c --arg p "$(realpath "$fx/settings.json")" 'select(.path == $p)' "$sd/preimage/preimage-ledger.jsonl" | tail -n1)" [ "$(jq -r '.captured' <<<"$crow")" = "false" ] || fail_msg "P17: allowlisted symlink to a denied target must refuse [$crow]" - if grep -rq "$s" "$sd" 2>/dev/null; then + if has_match -rq "$s" "$sd" 2>/dev/null; then fail_msg "P17: credential bytes leaked via an allowlisted alias" fi brow="$(jq -c --arg p "$(realpath "$fx/alias.cfg")" 'select(.path == $p)' "$sd/preimage/preimage-ledger.jsonl" | tail -n1)" diff --git a/packages/mosaic/framework/tools/wake/test-wake-reconcile.sh b/packages/mosaic/framework/tools/wake/test-wake-reconcile.sh index e197c896..7705606f 100755 --- a/packages/mosaic/framework/tools/wake/test-wake-reconcile.sh +++ b/packages/mosaic/framework/tools/wake/test-wake-reconcile.sh @@ -29,6 +29,9 @@ set -uo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness. +# shellcheck disable=SC1091 +. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init RECON="$SCRIPT_DIR/reconcile.sh" STORE="$SCRIPT_DIR/store.sh" DET="$SCRIPT_DIR/detector.sh" @@ -87,7 +90,7 @@ EOF out="$("$RECON" inventory 2>&1)" rc=$? [ "$rc" -eq 0 ] || fail_msg "R1: a complete inventory must PASS (exit 0) [$out]" - echo "$out" | grep -qi 'COMPLETE' || fail_msg "R1: a complete inventory must report COMPLETE [$out]" + echo "$out" | has_match -qi 'COMPLETE' || fail_msg "R1: a complete inventory must report COMPLETE [$out]" ) && ok echo "== R2: OMITTED source -> FLAG (vacuous-pass prevented, not silently green) ==" @@ -106,8 +109,8 @@ EOF out="$("$RECON" inventory 2>&1)" rc=$? [ "$rc" -ne 0 ] || fail_msg "R2: an omitted (declared-but-unwatched) source must FLAG (non-zero), not silently pass" - echo "$out" | grep -qi 'r2' || fail_msg "R2: the flag must name the omitted source r2 [$out]" - echo "$out" | grep -qi 'vacuous' || fail_msg "R2: the flag must state the vacuous-pass is prevented [$out]" + echo "$out" | has_match -qi 'r2' || fail_msg "R2: the flag must name the omitted source r2 [$out]" + echo "$out" | has_match -qi 'vacuous' || fail_msg "R2: the flag must state the vacuous-pass is prevented [$out]" ) && ok echo "== R3: required_sources omission -> FLAG ==" @@ -126,7 +129,7 @@ EOF out="$("$RECON" inventory 2>&1)" rc=$? [ "$rc" -ne 0 ] || fail_msg "R3: a required_sources omission must FLAG (non-zero)" - echo "$out" | grep -qi "requires source 'r2'" || fail_msg "R3: the flag must name the required-but-omitted source r2 [$out]" + echo "$out" | has_match -qi "requires source 'r2'" || fail_msg "R3: the flag must name the required-but-omitted source r2 [$out]" ) && ok echo "== R4: dangling watch reference -> FLAG ==" @@ -144,7 +147,7 @@ EOF out="$("$RECON" inventory 2>&1)" rc=$? [ "$rc" -ne 0 ] || fail_msg "R4: a dangling reference must FLAG (non-zero)" - echo "$out" | grep -qi 'dangling' || fail_msg "R4: the flag must state it is dangling [$out]" + echo "$out" | has_match -qi 'dangling' || fail_msg "R4: the flag must state it is dangling [$out]" ) && ok echo "== R5/R6: pre-existing state -> UNACCOUNTED flag + enumerated into store; re-run 0 ==" @@ -173,14 +176,14 @@ EOF out="$("$RECON" reconcile 2>&1)" rc=$? [ "$rc" -ne 0 ] || fail_msg "R5: pre-existing unaccounted state must FLAG (non-zero) on first reconcile" - echo "$out" | grep -qi 'UNACCOUNTED=2' || fail_msg "R5: both pre-existing sources must be UNACCOUNTED [$out]" + echo "$out" | has_match -qi 'UNACCOUNTED=2' || fail_msg "R5: both pre-existing sources must be UNACCOUNTED [$out]" # R6: enumerated into the durable store — one entry per pre-existing source. [ "$(depth)" = "2" ] || fail_msg "R6: pre-existing state must be ENUMERATED into the store (depth 2), got $(depth)" # A follow-up reconcile now finds everything accounted -> 0 unaccounted. out2="$("$RECON" reconcile 2>&1)" rc2=$? [ "$rc2" -eq 0 ] || fail_msg "R6: a second reconcile must report 0 unaccounted (exit 0) [$out2]" - echo "$out2" | grep -qi 'UNACCOUNTED=0' || fail_msg "R6: second reconcile must be 0 unaccounted [$out2]" + echo "$out2" | has_match -qi 'UNACCOUNTED=0' || fail_msg "R6: second reconcile must be 0 unaccounted [$out2]" [ "$(depth)" = "2" ] || fail_msg "R6: a clean reconcile must NOT re-enumerate (depth still 2), got $(depth)" ) && ok @@ -211,7 +214,7 @@ EOF out="$("$RECON" reconcile 2>&1)" rc=$? [ "$rc" -eq 0 ] || fail_msg "R7: state reflected in the inbox must be ACCOUNTED (exit 0) [$out]" - echo "$out" | grep -qi 'UNACCOUNTED=0' || fail_msg "R7: inbox-reflected state must be 0 unaccounted [$out]" + echo "$out" | has_match -qi 'UNACCOUNTED=0' || fail_msg "R7: inbox-reflected state must be 0 unaccounted [$out]" [ "$(depth)" = "1" ] || fail_msg "R7: reconciler must NOT double-enumerate inbox-reflected state (depth still 1), got $(depth)" ) && ok @@ -236,7 +239,7 @@ EOF out="$("$RECON" reconcile 2>&1)" rc=$? [ "$rc" -ne 0 ] || fail_msg "R8: a source error must FAIL LOUD (non-zero exit)" - echo "$out" | grep -qi 'FAIL LOUD' || fail_msg "R8: the source error must be loud [$out]" + echo "$out" | has_match -qi 'FAIL LOUD' || fail_msg "R8: the source error must be loud [$out]" [ "$(depth)" = "0" ] || fail_msg "R8: a failed observation must NOT enumerate anything, got depth $(depth)" ) && ok @@ -278,7 +281,7 @@ EOF out="$("$RECON" reconcile 2>&1)" rc=$? [ "$rc" -ne 0 ] || fail_msg "R9: pre-existing beta is unaccounted on this pass -> must FLAG (non-zero) [$out]" - echo "$out" | grep -qi 'UNACCOUNTED=1' || fail_msg "R9: only beta should be unaccounted (alpha is inbox-accounted) [$out]" + echo "$out" | has_match -qi 'UNACCOUNTED=1' || fail_msg "R9: only beta should be unaccounted (alpha is inbox-accounted) [$out]" [ "$(depth)" = "2" ] || fail_msg "R9: reconciler must ENUMERATE beta into the co-fed store (depth 2), got $(depth)" # A further detector delta on beta must allocate 3 — the unified allocator @@ -292,8 +295,8 @@ EOF # already used, so this set would contain a duplicate (alias). seqs="$("$STORE" drain | jq -r '.observed_seq' | sort -n | tr '\n' ' ')" [ "$seqs" = "1 2 3 " ] || fail_msg "R9: co-fed observed_seqs must be distinct+gapless '1 2 3', got '$seqs' (a duplicate = the aliasing #908 dissolved)" - ndistinct="$("$STORE" drain | jq -r '.observed_seq' | sort -nu | grep -c .)" - ntotal="$("$STORE" drain | jq -r '.observed_seq' | grep -c .)" + ndistinct="$("$STORE" drain | jq -r '.observed_seq' | sort -nu | count_lines .)" + ntotal="$("$STORE" drain | jq -r '.observed_seq' | count_lines .)" [ "$ndistinct" = "$ntotal" ] || fail_msg "R9: aliasing detected — $ntotal entries but only $ndistinct distinct observed_seq" # The contiguous-prefix CONSUMED contract holds over the co-fed seqs. "$STORE" consume --upto 3 >/dev/null 2>&1 || fail_msg "R9: CONSUMED 3 must succeed over the gapless co-fed prefix" @@ -333,7 +336,7 @@ EOF out="$("$RECON" reconcile 2>&1)" rc=$? [ "$rc" -eq 0 ] || fail_msg "R10: a consumed state must be ACCOUNTED (exit 0, no spurious rc=1 CRITICAL) [$out]" - echo "$out" | grep -qi 'UNACCOUNTED=0' || fail_msg "R10: a consumed state must be 0 unaccounted (no re-enumeration) [$out]" + echo "$out" | has_match -qi 'UNACCOUNTED=0' || fail_msg "R10: a consumed state must be 0 unaccounted (no re-enumeration) [$out]" [ "$(depth)" = "0" ] || fail_msg "R10: reconciler must NOT re-enumerate a consumed state (depth still 0 = no duplicate wake), got $(depth)" ) && ok @@ -372,7 +375,7 @@ EOF [ "$rc" -ne 0 ] || fail_msg "R11: a genuine gap (r2) must still FLAG (non-zero) [$out]" # After #932: ONLY r2 is unaccounted (r1 suppressed by the store record). On # BASE both r1 and r2 re-enumerate (UNACCOUNTED=2) -> this assertion is red-first. - echo "$out" | grep -qi 'UNACCOUNTED=1' || fail_msg "R11: exactly ONE source (the gap r2) must be unaccounted; the consumed r1 must be suppressed [$out]" + echo "$out" | has_match -qi 'UNACCOUNTED=1' || fail_msg "R11: exactly ONE source (the gap r2) must be unaccounted; the consumed r1 must be suppressed [$out]" # Prove precisely WHICH state re-enumerated: the gap r2 IS enumerated, the # consumed r1 is NOT. (base re-enumerates r1 too -> the r1-absent assertion is # red-first; the r2-present assertion holds both before and after = no over-suppression.) @@ -383,7 +386,7 @@ EOF echo if [ -s "$FAILFILE" ]; then - echo "wake reconcile harness: FAILED ($(grep -c . "$FAILFILE") assertion(s))" >&2 + echo "wake reconcile harness: FAILED ($(count_lines . "$FAILFILE") assertion(s))" >&2 exit 1 fi echo "wake reconcile harness: all invariants passed ($pass groups)" diff --git a/packages/mosaic/framework/tools/wake/test-wake-store-ack.sh b/packages/mosaic/framework/tools/wake/test-wake-store-ack.sh index f925fb2c..2be6a4c4 100755 --- a/packages/mosaic/framework/tools/wake/test-wake-store-ack.sh +++ b/packages/mosaic/framework/tools/wake/test-wake-store-ack.sh @@ -42,6 +42,9 @@ set -uo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness. +# shellcheck disable=SC1091 +. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init STORE="$SCRIPT_DIR/store.sh" ACK="$SCRIPT_DIR/ack.sh" @@ -96,14 +99,14 @@ echo "== T1: three-cursor advancement ==" "$STORE" enqueue --seq 1 --class actionable --locators '{"repo":"r","issue":1}' >/dev/null "$STORE" enqueue --seq 2 --class actionable --locators '{"repo":"r","issue":2}' >/dev/null cur="$("$STORE" cursors)" - echo "$cur" | grep -q 'observed_seq=2' || fail_msg "T1: observed_seq should be 2 after enqueue 1,2 [$cur]" - echo "$cur" | grep -q 'consumed_seq=0' || fail_msg "T1: consumed_seq must NOT advance on enqueue (only on CONSUMED ack) [$cur]" - echo "$cur" | grep -q 'pending_depth=2' || fail_msg "T1: pending depth should be 2 [$cur]" + echo "$cur" | has_match -q 'observed_seq=2' || fail_msg "T1: observed_seq should be 2 after enqueue 1,2 [$cur]" + echo "$cur" | has_match -q 'consumed_seq=0' || fail_msg "T1: consumed_seq must NOT advance on enqueue (only on CONSUMED ack) [$cur]" + echo "$cur" | has_match -q 'pending_depth=2' || fail_msg "T1: pending depth should be 2 [$cur]" # consumed_seq advances only on CONSUMED. "$STORE" consume --upto 2 >/dev/null cur="$("$STORE" cursors)" - echo "$cur" | grep -q 'consumed_seq=2' || fail_msg "T1: consumed_seq should be 2 after CONSUMED 2 [$cur]" - echo "$cur" | grep -q 'pending_depth=0' || fail_msg "T1: pending drained after CONSUMED [$cur]" + echo "$cur" | has_match -q 'consumed_seq=2' || fail_msg "T1: consumed_seq should be 2 after CONSUMED 2 [$cur]" + echo "$cur" | has_match -q 'pending_depth=0' || fail_msg "T1: pending drained after CONSUMED [$cur]" ) && ok echo "== T2: digest coalesce-REPLACE vs actionable APPEND ==" @@ -116,16 +119,16 @@ echo "== T2: digest coalesce-REPLACE vs actionable APPEND ==" "$STORE" enqueue --seq 3 --class digest --locators '{"head":"bbb"}' >/dev/null "$STORE" enqueue --seq 4 --class human --locators '{"from":"peer"}' >/dev/null out="$("$STORE" drain)" - ndigest="$(printf '%s\n' "$out" | jq -c 'select(.class=="digest")' | grep -c . || true)" + ndigest="$(printf '%s\n' "$out" | jq -c 'select(.class=="digest")' | count_lines . || true)" [ "$ndigest" = "1" ] || fail_msg "T2: digest must COALESCE to a single pending entry, got $ndigest" head="$(printf '%s\n' "$out" | jq -r 'select(.class=="digest") | .locators.head')" [ "$head" = "bbb" ] || fail_msg "T2: newest digest must REPLACE prior (expected bbb, got $head)" - nactionable="$(printf '%s\n' "$out" | jq -c 'select(.class=="actionable")' | grep -c . || true)" - nhuman="$(printf '%s\n' "$out" | jq -c 'select(.class=="human")' | grep -c . || true)" + nactionable="$(printf '%s\n' "$out" | jq -c 'select(.class=="actionable")' | count_lines . || true)" + nhuman="$(printf '%s\n' "$out" | jq -c 'select(.class=="human")' | count_lines . || true)" [ "$nactionable" = "1" ] || fail_msg "T2: actionable must APPEND (never replaced), got $nactionable" [ "$nhuman" = "1" ] || fail_msg "T2: human must APPEND / stay durable, got $nhuman" # Durability never bypassed: all classes present in the durable store. - total="$(printf '%s\n' "$out" | grep -c . || true)" + total="$(printf '%s\n' "$out" | count_lines . || true)" [ "$total" = "3" ] || fail_msg "T2: durable store should hold digest+actionable+human = 3, got $total" ) && ok @@ -141,7 +144,7 @@ echo "== T3: contiguous-prefix CONSUMED (reject ack N while N-1 unconsumed) ==" fail_msg "T3: CONSUMED 3 must be REJECTED while seq 2 is a gap (unconsumed)" fi cur="$("$STORE" cursors)" - echo "$cur" | grep -q 'consumed_seq=0' || fail_msg "T3: rejected CONSUMED must NOT advance the cursor [$cur]" + echo "$cur" | has_match -q 'consumed_seq=0' || fail_msg "T3: rejected CONSUMED must NOT advance the cursor [$cur]" # Also reject via the ack wrapper. if "$ACK" consumed --upto 3 --no-sync >/dev/null 2>&1; then fail_msg "T3: ack.sh CONSUMED 3 must be REJECTED over a gap" @@ -150,11 +153,11 @@ echo "== T3: contiguous-prefix CONSUMED (reject ack N while N-1 unconsumed) ==" "$STORE" enqueue --seq 2 --class actionable --locators '{}' >/dev/null "$ACK" consumed --upto 3 --no-sync >/dev/null 2>&1 || fail_msg "T3: CONSUMED 3 should succeed once gap at 2 is filled" cur="$("$STORE" cursors)" - echo "$cur" | grep -q 'consumed_seq=3' || fail_msg "T3: consumed_seq should be 3 after contiguous prefix filled [$cur]" + echo "$cur" | has_match -q 'consumed_seq=3' || fail_msg "T3: consumed_seq should be 3 after contiguous prefix filled [$cur]" # Cumulative + can't regress: CONSUMED 2 after 3 is an idempotent no-op. "$ACK" consumed --upto 2 --no-sync >/dev/null 2>&1 || fail_msg "T3: cumulative CONSUMED 2 (<=3) should be an idempotent success" cur="$("$STORE" cursors)" - echo "$cur" | grep -q 'consumed_seq=3' || fail_msg "T3: cursor must not regress below 3 [$cur]" + echo "$cur" | has_match -q 'consumed_seq=3' || fail_msg "T3: cursor must not regress below 3 [$cur]" ) && ok echo "== T4: wake_id DELIVERY-dedup (dup delivery = re-RECEIVE, never re-action) ==" @@ -169,7 +172,7 @@ echo "== T4: wake_id DELIVERY-dedup (dup delivery = re-RECEIVE, never re-action) [ "$r2" = "DUP" ] || fail_msg "T4: duplicate delivery of same wake_id should be DUP (re-RECEIVE), got '$r2'" # RECEIVED (delivery) must NEVER advance consumed_seq (delivery != consumption). cur="$("$STORE" cursors)" - echo "$cur" | grep -q 'consumed_seq=0' || fail_msg "T4: RECEIVED must not advance consumed_seq [$cur]" + echo "$cur" | has_match -q 'consumed_seq=0' || fail_msg "T4: RECEIVED must not advance consumed_seq [$cur]" ) && ok echo "== T5: atomic write-tmp+rename survives crash mid-write ==" @@ -189,7 +192,7 @@ echo "== T5: atomic write-tmp+rename survives crash mid-write ==" drained="$("$STORE" drain)" printf '%s\n' "$drained" | jq -e . >/dev/null 2>&1 || fail_msg "T5: drain returned non-JSON — garbage temp corrupted the store" printf '%s\n' "$drained" | stream_any '.observed_seq==1' || fail_msg "T5: committed entry (seq 1) lost after simulated crash" - printf '%s\n' "$drained" | grep -q 999 && fail_msg "T5: uncommitted garbage (seq 999) leaked into the live store" + printf '%s\n' "$drained" | has_match -q 999 && fail_msg "T5: uncommitted garbage (seq 999) leaked into the live store" # A subsequent real mutation must succeed DESPITE the stale temp present. "$STORE" enqueue --seq 2 --class actionable --locators '{"issue":2}' >/dev/null || fail_msg "T5: enqueue after crash temp failed" # #927: the enqueue HOT PATH must NOT reap tmp files — an unconditional delete @@ -198,7 +201,7 @@ echo "== T5: atomic write-tmp+rename survives crash mid-write ==" # untouched by an enqueue; reaping it on the hot path is exactly the bug. [ -e "$STATE_DIR/.wake.tmp.crash12" ] || fail_msg "T5: the enqueue hot path must NOT delete tmp files off its own write (that hot-path reap was the #927 clobber)" d2="$("$STORE" drain)" - [ "$(printf '%s\n' "$d2" | grep -c .)" = "2" ] || fail_msg "T5: store not healthy after crash+recovery (expected 2 entries)" + [ "$(printf '%s\n' "$d2" | has_match -c .)" = "2" ] || fail_msg "T5: store not healthy after crash+recovery (expected 2 entries)" # Bounded accumulation is preserved via a MAINTENANCE reap (store.sh init / # detector tick), age-scoped so it only removes DEMONSTRABLY-orphaned tmps # (older than any plausible in-flight write) and never a live one. Age the @@ -209,7 +212,7 @@ echo "== T5: atomic write-tmp+rename survives crash mid-write ==" "$STORE" init >/dev/null 2>&1 || fail_msg "T5: store.sh init (maintenance) failed" [ -e "$STATE_DIR/.wake.tmp.crash12" ] && fail_msg "T5: maintenance reap (store.sh init) must remove a demonstrably-orphaned stale temp (bounded accumulation)" d3="$("$STORE" drain)" - [ "$(printf '%s\n' "$d3" | grep -c .)" = "2" ] || fail_msg "T5: store not healthy after maintenance reap (expected 2 entries)" + [ "$(printf '%s\n' "$d3" | has_match -c .)" = "2" ] || fail_msg "T5: store not healthy after maintenance reap (expected 2 entries)" printf '%s\n' "$d3" | jq -e . >/dev/null 2>&1 || fail_msg "T5: drain returned non-JSON after maintenance reap" ) && ok @@ -254,12 +257,12 @@ echo "== T6: durability survives restart (retain until CONSUMED) ==" # "Session 2": a brand-new process (this subshell invocation of store.sh) must # see the persisted entries — nothing was held in memory. d="$("$STORE" drain)" - [ "$(printf '%s\n' "$d" | grep -c .)" = "2" ] || fail_msg "T6: entries not retained across restart (expected 2)" + [ "$(printf '%s\n' "$d" | has_match -c .)" = "2" ] || fail_msg "T6: entries not retained across restart (expected 2)" printf '%s\n' "$d" | stream_any '.class=="human"' || fail_msg "T6: a human message was lost across restart (durability bypassed)" # Retained UNTIL consumed: after CONSUMED they are released. "$STORE" consume --upto 2 >/dev/null d2="$("$STORE" drain)" - n2="$(printf '%s\n' "$d2" | grep -c . || true)" + n2="$(printf '%s\n' "$d2" | count_lines . || true)" [ "$n2" = "0" ] || fail_msg "T6: entries should be released only AFTER CONSUMED (still $n2 pending)" ) && ok @@ -296,7 +299,7 @@ EOF end="$(date +%s.%N)" elapsed_ms="$(awk -v s="$start" -v e="$end" 'BEGIN { printf "%d", (e - s) * 1000 }')" [ "$elapsed_ms" -lt 1500 ] || fail_msg "T7: ack path blocked ${elapsed_ms}ms — must return without waiting on the background sync" - echo "$out" | grep -q 'CONSUMED 1' || fail_msg "T7: CONSUMED not reported [$out]" + echo "$out" | has_match -q 'CONSUMED 1' || fail_msg "T7: CONSUMED not reported [$out]" # Local write is durable IMMEDIATELY (no network needed to record the ack). STATE_DIR="$WAKE_STATE_HOME/default" jq_any "$STATE_DIR/ack-ledger.jsonl" '.type=="CONSUMED" and .upto==1' || @@ -321,8 +324,8 @@ echo "== T8: SOLE store-side allocator — enqueue (no --seq) allocates contiguo [ "$s1" = "1" ] || fail_msg "T8: first store-allocated observed_seq must be 1, got '$s1'" [ "$s2" = "2" ] || fail_msg "T8: second store-allocated observed_seq must be 2 (contiguous), got '$s2'" cur="$("$STORE" cursors)" - echo "$cur" | grep -q 'observed_seq=2' || fail_msg "T8: observed_seq cursor should be 2 [$cur]" - echo "$cur" | grep -q 'pending_depth=2' || fail_msg "T8: both allocations must be durably enqueued [$cur]" + echo "$cur" | has_match -q 'observed_seq=2' || fail_msg "T8: observed_seq cursor should be 2 [$cur]" + echo "$cur" | has_match -q 'pending_depth=2' || fail_msg "T8: both allocations must be durably enqueued [$cur]" # ANTI-SWALLOW: consume the prefix, then a LEGACY explicit --seq inside the # consumed prefix must FAIL LOUD (never the old silent seq<=consumed no-op). "$STORE" consume --upto 2 >/dev/null @@ -331,7 +334,7 @@ echo "== T8: SOLE store-side allocator — enqueue (no --seq) allocates contiguo fail_msg "T8: explicit --seq 1 <= consumed_seq 2 must FAIL LOUD (anti-swallow), not be a silent no-op" fi err="$("$STORE" enqueue --seq 1 --class actionable --locators '{}' 2>&1 || true)" - echo "$err" | grep -qi 'anti-swallow' || fail_msg "T8: the refusal must name the anti-swallow guarantee [$err]" + echo "$err" | has_match -qi 'anti-swallow' || fail_msg "T8: the refusal must name the anti-swallow guarantee [$err]" after_depth="$("$STORE" cursors | sed -n 's/pending_depth=//p')" [ "$before_depth" = "$after_depth" ] || fail_msg "T8: a refused enqueue must not mutate the store (depth $before_depth->$after_depth)" # And the NEXT real allocation is > consumed (2) — never inside the prefix. @@ -443,8 +446,8 @@ if command -v flock >/dev/null 2>&1; then [ -n "$a" ] && [ -n "$b" ] || fail_msg "T10: both concurrent enqueues must print an allocated seq (got '$a','$b')" [ "$a" != "$b" ] || fail_msg "T10: two concurrent enqueues must get DISTINCT seqs, both got '$a' (aliasing / lost write without the lock)" cur="$("$STORE" cursors)" - echo "$cur" | grep -q 'observed_seq=2' || fail_msg "T10: observed_seq must reach 2 after two enqueues [$cur]" - echo "$cur" | grep -q 'pending_depth=2' || fail_msg "T10: both entries must be durably stored (no lost write) [$cur]" + echo "$cur" | has_match -q 'observed_seq=2' || fail_msg "T10: observed_seq must reach 2 after two enqueues [$cur]" + echo "$cur" | has_match -q 'pending_depth=2' || fail_msg "T10: both entries must be durably stored (no lost write) [$cur]" # The two allocated seqs are exactly {1,2} (distinct, contiguous, gapless). lo="$a"; hi="$b"; [ "$a" -gt "$b" ] && { lo="$b"; hi="$a"; } { [ "$lo" = "1" ] && [ "$hi" = "2" ]; } || fail_msg "T10: concurrent seqs must be {1,2}, got {$lo,$hi}" @@ -492,7 +495,7 @@ echo "== T11: final observed_seq cursor write FAILURE — fail loud + observed.s # the _atomic_write failure and returns 0). [ "$rc" -ne 0 ] || fail_msg "T11: an enqueue whose FINAL cursor write fails must EXIT NON-ZERO (fail loud), got rc=$rc" # The loud diagnostic names the cursor write (not a generic error). - grep -qi 'cursor' "$errfile" || fail_msg "T11: the failure diagnostic must name the observed_seq cursor write [$(cat "$errfile")]" + has_match -qi 'cursor' "$errfile" || fail_msg "T11: the failure diagnostic must name the observed_seq cursor write [$(cat "$errfile")]" # (2) The cursor did NOT advance — the allocation is NOT committed. obs_after="$("$STORE" cursors | sed -n 's/^observed_seq=//p')" @@ -536,7 +539,7 @@ echo "== T12: #932 — consume records the last-consumed observed_hash per (kind r2h="$(jq -sr '[ .[] | select(.kind=="repo" and .id=="r2") ] | .[0].observed_hash' "$rec" 2>/dev/null)" [ "$r2h" = "HASH-C" ] || fail_msg "T12: repo/r2 must record HASH-C, got '$r2h'" # ADDITIVE: existing on-disk state files are unchanged/consistent post-consume. - "$STORE" cursors | grep -q 'consumed_seq=3' || fail_msg "T12: consumed_seq must be 3 after CONSUMED 3" + "$STORE" cursors | has_match -q 'consumed_seq=3' || fail_msg "T12: consumed_seq must be 3 after CONSUMED 3" ) && ok echo "== T13: #946 — ordinary consume REFUSES to advance past a quarantined seq (store + ack paths) ==" @@ -555,10 +558,10 @@ echo "== T13: #946 — ordinary consume REFUSES to advance past a quarantined se fail_msg "T13: ordinary consume --upto 3 must be REFUSED while seq 2 is quarantined" fi err="$("$STORE" consume --upto 3 2>&1 >/dev/null || true)" - echo "$err" | grep -q 'quarantined seq(s): 2' || fail_msg "T13: the refusal must NAME the quarantined seq [$err]" - echo "$err" | grep -q -- '--force-past-quarantine' || fail_msg "T13: the refusal must NAME the force flag [$err]" + echo "$err" | has_match -q 'quarantined seq(s): 2' || fail_msg "T13: the refusal must NAME the quarantined seq [$err]" + echo "$err" | has_match -q -- '--force-past-quarantine' || fail_msg "T13: the refusal must NAME the force flag [$err]" cur="$("$STORE" cursors)" - echo "$cur" | grep -q 'consumed_seq=0' || fail_msg "T13: a refused consume must NOT advance the cursor [$cur]" + echo "$cur" | has_match -q 'consumed_seq=0' || fail_msg "T13: a refused consume must NOT advance the cursor [$cur]" # BELOW the quarantined seq the ordinary path is unaffected. "$STORE" consume --upto 1 >/dev/null 2>&1 || fail_msg "T13: consume --upto 1 (below the quarantined seq) must succeed" # The ack wrapper propagates the refusal — no ordinary-path bypass exists. @@ -566,7 +569,7 @@ echo "== T13: #946 — ordinary consume REFUSES to advance past a quarantined se fail_msg "T13: ack.sh consumed --upto 3 must be REFUSED while seq 2 is quarantined (ordinary-path bypass)" fi cur="$("$STORE" cursors)" - echo "$cur" | grep -q 'consumed_seq=1' || fail_msg "T13: cursor must still be 1 after the refused ack [$cur]" + echo "$cur" | has_match -q 'consumed_seq=1' || fail_msg "T13: cursor must still be 1 after the refused ack [$cur]" ) && ok echo "== T14: #946 — FORCED step-over is LOUD, prunes the set, and NEVER fabricates a consumed-hash row for the quarantined entry ==" @@ -585,9 +588,9 @@ echo "== T14: #946 — FORCED step-over is LOUD, prunes the set, and NEVER fabri rc=$? [ "$rc" -eq 0 ] || fail_msg "T14: forced consume must succeed (rc=$rc) [$(cat "$errf")]" [ "$out" = "3" ] || fail_msg "T14: forced consume must print the new cursor 3, got '$out'" - grep -q 'FORCED PAST QUARANTINE' "$errf" || fail_msg "T14: the forced path must be LOUD on stderr [$(cat "$errf")]" - grep -q 'seq 2' "$errf" || fail_msg "T14: the forced-path diagnostic must name the stepped-over seq 2 [$(cat "$errf")]" - "$STORE" cursors | grep -q 'consumed_seq=3' || fail_msg "T14: forced consume must advance the cursor to 3" + has_match -q 'FORCED PAST QUARANTINE' "$errf" || fail_msg "T14: the forced path must be LOUD on stderr [$(cat "$errf")]" + has_match -q 'seq 2' "$errf" || fail_msg "T14: the forced-path diagnostic must name the stepped-over seq 2 [$(cat "$errf")]" + "$STORE" cursors | has_match -q 'consumed_seq=3' || fail_msg "T14: forced consume must advance the cursor to 3" # NO FALSE WITNESS: the quarantined entry (repo/b) was NEVER delivered, so no # consumed-hash row may exist for it — even on the forced path (the reconciler # re-enumerating it once is safe-but-noisy; a false witness silences it @@ -597,7 +600,7 @@ echo "== T14: #946 — FORCED step-over is LOUD, prunes the set, and NEVER fabri jq_any "$rec" '.kind=="repo" and .id=="b"' && fail_msg "T14: the quarantined entry repo/b must have NO consumed-hash row (a row would witness a delivery that never happened)" # The stepped-over seq is PRUNED from the set (it is consumed now; a stale # entry would re-refuse forever). - grep -qxF '2' "$qf" 2>/dev/null && fail_msg "T14: seq 2 must be PRUNED from quarantined.set after the forced step-over" + has_match -qxF '2' "$qf" 2>/dev/null && fail_msg "T14: seq 2 must be PRUNED from quarantined.set after the forced step-over" # The ack wrapper's force flag passes through, stays LOUD on stderr, and # still reports a CLEAN cursor line on stdout. "$STORE" enqueue --class actionable --locators '{"kind":"repo","id":"d","observed_hash":"HD"}' >/dev/null @@ -607,8 +610,8 @@ echo "== T14: #946 — FORCED step-over is LOUD, prunes the set, and NEVER fabri out2="$("$ACK" consumed --upto 5 --no-sync --force-past-quarantine 2>"$errf2")" rc2=$? [ "$rc2" -eq 0 ] || fail_msg "T14: forced ack must succeed (rc=$rc2) [$(cat "$errf2")]" - echo "$out2" | grep -q '^CONSUMED 5$' || fail_msg "T14: forced ack must report a CLEAN cursor line 'CONSUMED 5', got '$out2'" - grep -q 'FORCED PAST QUARANTINE' "$errf2" || fail_msg "T14: the forced-path loudness must survive the ack wrapper (stderr) [$(cat "$errf2")]" + echo "$out2" | has_match -q '^CONSUMED 5$' || fail_msg "T14: forced ack must report a CLEAN cursor line 'CONSUMED 5', got '$out2'" + has_match -q 'FORCED PAST QUARANTINE' "$errf2" || fail_msg "T14: the forced-path loudness must survive the ack wrapper (stderr) [$(cat "$errf2")]" jq_any "$rec" '.kind=="repo" and .id=="e"' && fail_msg "T14: the quarantined repo/e must have NO consumed-hash row via the forced ack path either" true ) && ok @@ -671,10 +674,10 @@ echo "== T16: #946 — quarantine-audit: a consumed-hash row matching a dead-let if "$STORE" quarantine-audit >"$rep" 2>&1; then fail_msg "T16: report-mode audit must exit NON-ZERO when false rows exist" fi - grep -q 'FALSE WITNESS' "$rep" || fail_msg "T16: the audit must name the false row loudly [$(cat "$rep")]" - grep -q '"id":"X"' "$rep" || fail_msg "T16: the audit must identify the false row (repo/X@1) [$(cat "$rep")]" - grep -q '"id":"Y"' "$rep" && fail_msg "T16: the clean row repo/Y must NOT be flagged" - grep -q '"id":"Z"' "$rep" && fail_msg "T16: the HEALED row repo/Z@4 must NOT be flagged (its dead-letter evidence is seq 3 with a different hash)" + has_match -q 'FALSE WITNESS' "$rep" || fail_msg "T16: the audit must name the false row loudly [$(cat "$rep")]" + has_match -q '"id":"X"' "$rep" || fail_msg "T16: the audit must identify the false row (repo/X@1) [$(cat "$rep")]" + has_match -q '"id":"Y"' "$rep" && fail_msg "T16: the clean row repo/Y must NOT be flagged" + has_match -q '"id":"Z"' "$rep" && fail_msg "T16: the HEALED row repo/Z@4 must NOT be flagged (its dead-letter evidence is seq 3 with a different hash)" # Report mode modifies nothing. jq_any "$rec" '.id=="X"' || fail_msg "T16: report mode must not modify the record" # REPAIR: exactly the false row is removed; the dead-letter LEDGER is history @@ -683,10 +686,10 @@ echo "== T16: #946 — quarantine-audit: a consumed-hash row matching a dead-let jq_any "$rec" '.id=="X"' && fail_msg "T16: --repair must REMOVE the provably-false X row" jq_any "$rec" '.id=="Y" and .observed_hash=="HY"' || fail_msg "T16: --repair must keep the clean Y row" jq_any "$rec" '.id=="Z" and .observed_hash=="HZ-NEW" and .observed_seq==4' || fail_msg "T16: --repair must keep the healed Z@4 row" - [ "$(grep -c . "$dl")" = "2" ] || fail_msg "T16: the dead-letter LEDGER must be untouched by --repair" + [ "$(has_match -c . "$dl")" = "2" ] || fail_msg "T16: the dead-letter LEDGER must be untouched by --repair" # Clean re-audit: OK, exit 0. "$STORE" quarantine-audit >"$TMP_ROOT/t16.ok" 2>&1 || fail_msg "T16: a clean audit must exit 0 [$(cat "$TMP_ROOT/t16.ok")]" - grep -qi 'OK' "$TMP_ROOT/t16.ok" || fail_msg "T16: a clean audit must say OK [$(cat "$TMP_ROOT/t16.ok")]" + has_match -qi 'OK' "$TMP_ROOT/t16.ok" || fail_msg "T16: a clean audit must say OK [$(cat "$TMP_ROOT/t16.ok")]" ) && ok echo "== T17: #952 — the clean-sweep message names BOTH unprovable residual classes; a surviving-but-empty-hash dead-letter row is correctly NOT convicted ==" @@ -722,20 +725,20 @@ echo "== T17: #952 — the clean-sweep message names BOTH unprovable residual cl # match can never fire: this is unprovable class 2, NOT a false witness. rep="$TMP_ROOT/t17.rep" "$STORE" quarantine-audit >"$rep" 2>&1 || fail_msg "T17: the audit must exit 0 — nothing here is provable [$(cat "$rep")]" - grep -q 'FALSE WITNESS' "$rep" && fail_msg "T17: the empty-hash evidence must NOT convict (the predicate is correct and must not change) [$(cat "$rep")]" + has_match -q 'FALSE WITNESS' "$rep" && fail_msg "T17: the empty-hash evidence must NOT convict (the predicate is correct and must not change) [$(cat "$rep")]" # The wording under test (#952): BOTH residual classes, named. - grep -qi 'pruned' "$rep" || fail_msg "T17: clean sweep must name residual class 1 — evidence pruned away [$(cat "$rep")]" - grep -qi 'empty observed_hash' "$rep" || fail_msg "T17: clean sweep must name residual class 2 — surviving evidence with an empty observed_hash [$(cat "$rep")]" + has_match -qi 'pruned' "$rep" || fail_msg "T17: clean sweep must name residual class 1 — evidence pruned away [$(cat "$rep")]" + has_match -qi 'empty observed_hash' "$rep" || fail_msg "T17: clean sweep must name residual class 2 — surviving evidence with an empty observed_hash [$(cat "$rep")]" # --repair on a clean sweep removes nothing: the unprovable row survives. "$STORE" quarantine-audit --repair >"$TMP_ROOT/t17.fix" 2>&1 || fail_msg "T17: --repair on a clean sweep must exit 0 [$(cat "$TMP_ROOT/t17.fix")]" jq_any "$rec" '.kind=="bench" and .observed_seq==13 and .observed_hash=="H-REAL-CONSUMED"' || fail_msg "T17: --repair must NOT remove the unprovable bench@13 row — the audit only removes what the ledger can convict" - [ "$(grep -c . "$dl")" = "1" ] || fail_msg "T17: the dead-letter LEDGER must be untouched" + [ "$(count_lines . "$dl")" = "1" ] || fail_msg "T17: the dead-letter LEDGER must be untouched" ) && ok echo if [ -s "$FAILFILE" ]; then - echo "wake store/ack harness: FAILED ($(grep -c . "$FAILFILE") assertion(s))" >&2 + echo "wake store/ack harness: FAILED ($(count_lines . "$FAILFILE") assertion(s))" >&2 exit 1 fi echo "wake store/ack harness: all invariants passed ($pass groups)" diff --git a/packages/mosaic/framework/tools/wake/test-wake-store-enqueue-race.sh b/packages/mosaic/framework/tools/wake/test-wake-store-enqueue-race.sh index 9d738081..94b19785 100755 --- a/packages/mosaic/framework/tools/wake/test-wake-store-enqueue-race.sh +++ b/packages/mosaic/framework/tools/wake/test-wake-store-enqueue-race.sh @@ -32,6 +32,9 @@ set -uo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness. +# shellcheck disable=SC1091 +. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init STORE="$SCRIPT_DIR/store.sh" command -v jq >/dev/null 2>&1 || { @@ -147,7 +150,7 @@ EOF wait "$pa" 2>/dev/null || true else # Confirm the window is genuinely open: A holds a live in-flight tmp now. - n_tmp="$(find "$STATE_DIR" -maxdepth 1 -name '.wake.tmp.*' -type f | grep -c . || true)" + n_tmp="$(find "$STATE_DIR" -maxdepth 1 -name '.wake.tmp.*' -type f | count_lines . || true)" [ "$n_tmp" -ge 1 ] || fail_msg "T-RACE: expected A's live in-flight tmp to exist while A holds the lock (got $n_tmp)" # B: its PRE-LOCK _wake_init_dir runs now (pre-fix: deletes A's live tmp), @@ -173,7 +176,7 @@ EOF if [ "$ra" -ne 0 ]; then fail_msg "T-RACE: enqueue A was SPURIOUSLY ABORTED (rc=$ra) — its live in-flight tmp was deleted by B's pre-lock cleanup [#927]. stderr: $(tr '\n' ' ' <"$a_err")" fi - if grep -q 'durable pending write FAILED' "$a_err" 2>/dev/null; then + if has_match -q 'durable pending write FAILED' "$a_err" 2>/dev/null; then fail_msg "T-RACE: enqueue A reported 'durable pending write FAILED' — the exact #927 spurious abort (its tmp was clobbered mid-write by a concurrent pre-lock cleanup)." fi [ "$rb" -eq 0 ] || fail_msg "T-RACE: enqueue B should also succeed (rc=$rb). stderr: $(tr '\n' ' ' <"$b_err")" @@ -189,20 +192,20 @@ EOF # #908 store invariants: both durably landed, cursor reached 2, no burned seq. cur="$("$STORE" cursors)" - echo "$cur" | grep -q 'observed_seq=2' || fail_msg "T-RACE: observed_seq must reach 2 (both allocations committed) [$cur]" - echo "$cur" | grep -q 'pending_depth=2' || fail_msg "T-RACE: both entries must be durably stored — no lost/aborted write [$cur]" - echo "$cur" | grep -q 'consumed_seq=0' || fail_msg "T-RACE: enqueue must never advance consumed_seq [$cur]" + echo "$cur" | has_match -q 'observed_seq=2' || fail_msg "T-RACE: observed_seq must reach 2 (both allocations committed) [$cur]" + echo "$cur" | has_match -q 'pending_depth=2' || fail_msg "T-RACE: both entries must be durably stored — no lost/aborted write [$cur]" + echo "$cur" | has_match -q 'consumed_seq=0' || fail_msg "T-RACE: enqueue must never advance consumed_seq [$cur]" # Gapless: the contiguous prefix 1..2 is consumable (no interior gap/burn). "$STORE" consume --upto 2 >/dev/null 2>&1 || fail_msg "T-RACE: CONSUMED 2 must succeed — seqs {1,2} are gapless (no burned seq)" # No stale tmp left leaking either. - n_leak="$(find "$STATE_DIR" -maxdepth 1 -name '.wake.tmp.*' -type f | grep -c . || true)" + n_leak="$(find "$STATE_DIR" -maxdepth 1 -name '.wake.tmp.*' -type f | count_lines . || true)" [ "$n_leak" = "0" ] || fail_msg "T-RACE: $n_leak stale tmp file(s) leaked after both enqueues committed" fi ) && ok echo if [ -s "$FAILFILE" ]; then - echo "wake store enqueue-race harness: FAILED ($(grep -c . "$FAILFILE") assertion(s)) — #927 TOCTOU reproduced (RED)" >&2 + echo "wake store enqueue-race harness: FAILED ($(count_lines . "$FAILFILE") assertion(s)) — #927 TOCTOU reproduced (RED)" >&2 exit 1 fi echo "wake store enqueue-race harness: all invariants passed ($pass group) — #927 race closed (GREEN)" diff --git a/packages/mosaic/framework/tools/wake/validate-973/check-973.py b/packages/mosaic/framework/tools/wake/validate-973/check-973.py new file mode 100755 index 00000000..d4d9b1e9 --- /dev/null +++ b/packages/mosaic/framework/tools/wake/validate-973/check-973.py @@ -0,0 +1,280 @@ +#!/usr/bin/env python3 +"""check-973.py — computation backend for the #973 validation harness. + +Everything here derives from exactly two inputs: the frozen denominator +artifact (denominator-089615f.json) and the SOURCE TEXT of the ten converted +suites at the current tree. It never reads the ledger — set arithmetic against +the runtime trace belongs to validate-973.sh, so the two legs of the +comparison come from independent code paths. + +Subcommands (all print sorted, stable output; non-zero exit on any failure): + + expected The expected coordinate set from the ARTIFACT: one + " :" row per denominator row (+3 = the + uniform header shift the converter applied; converter-verified). + Multi-grep lines stay ONE coordinate. + + static The converted-site inventory from the SOURCE TEXT at the current + tree: every non-comment line bearing a has_match/count_lines + token, as " :". Independent of the artifact + row list, so `expected == static` is a real check on the + conversion, not a tautology. (Amendment ONE, leg 1: the ledger is + an execution trace, not an inventory — the inventory must come + from the text.) + + arms The forced-error arm list: the 19 denominator canaries plus one + E-form arm (store-ack:733→736, a $(count_lines) capture compared + afterward — the A6 shape) plus one F-form arm (quarantine:560→563, + the multi-grep pipeline capture), as " : +
". Both extras are asserted to exist in the artifact with + the expected form — a renumber that moved them fails here, not + silently downstream. + + sweep Residual sweep: the denominator's own classifier (ported from the + frozen derivation) over the ten suites at the current tree must + find ZERO unconverted verdict-form grep sites; and, IN THE SAME + RUN, six per-form specimens planted into a temp copy of a real + suite must ALL be found with their correct forms — an instrument + that reports zero must first be seen finding what it claims to + find (A5). +""" + +import json +import re +import shutil +import sys +import tempfile +from pathlib import Path + +HERE = Path(__file__).resolve().parent +WAKE = HERE.parent +ART = HERE / "denominator-089615f.json" + +HEADER_SHIFT = 3 # converter inserted 3 header lines after SCRIPT_DIR in every suite + +# The two hand-picked extra arms (base coordinates; forms asserted at load). +EXTRA_ARMS = [ + ("test-wake-store-ack.sh", 733, "E-count-capture"), + ("test-wake-digest-quarantine.sh", 560, "F-extract-capture"), +] + +RX_HELPER = re.compile(r"(^|[^A-Za-z0-9_.-])(has_match|count_lines)([^A-Za-z0-9_.-]|$)") + +# ---- classifier, ported verbatim in logic from the frozen denominator +# ---- derivation (docs/journal/fleet/drift-derive-089615f__pepper.py) +RX_FAIL_SAME = re.compile(r"(\|\||&&)\s*fail") +RX_COUNT_SUB = re.compile(r"\$\(.*grep\s+[^)]*-c|\$\(\s*grep\s+-c") +RX_ASSIGN_SUB = re.compile(r'=\s*"?\$\(.*grep') +RX_IF = re.compile(r"^\s*(el)?if\s+.*grep") +RX_GREP = re.compile(r"(^|[^A-Za-z0-9_.-])grep([^A-Za-z0-9_.-]|$)") + + +def polarity(line): + m = RX_FAIL_SAME.search(line) + return "OR" if m.group(1) == "||" else "AND" + + +def classify(lines): + """Return (sites, dispo). Every line containing the word grep gets a row.""" + sites, dispo = [], [] + n = len(lines) + for i, raw in enumerate(lines): + line = raw + ln = i + 1 + if not RX_GREP.search(line): + continue + stripped = line.strip() + if stripped.startswith("#"): + dispo.append((ln, "comment", stripped)) + continue + nxt = "" + for j in range(i + 1, min(i + 3, n)): + if lines[j].strip(): + nxt = lines[j].strip() + break + if "$(" in line and RX_COUNT_SUB.search(line): + sites.append((ln, "E-count-capture", stripped)) + continue + if RX_ASSIGN_SUB.search(line) and "grep -c" not in line: + sites.append((ln, "F-extract-capture", stripped)) + continue + if RX_FAIL_SAME.search(line): + sites.append((ln, "A-same-line", stripped)) + continue + if stripped.endswith("\\"): + k = i + 1 + joined = stripped[:-1] + while k < n: + cont = lines[k].strip() + joined += " " + (cont[:-1] if cont.endswith("\\") else cont) + if not cont.endswith("\\"): + break + k += 1 + if re.search(r"(\|\||&&)\s*fail", joined) or ( + joined.rstrip().endswith(("||", "&&")) + and k + 1 < n + and lines[k + 1].strip().startswith("fail") + ): + sites.append((ln, "C-cont-backslash", stripped)) + continue + dispo.append((ln, "backslash-no-fail-continuation", stripped)) + continue + if stripped.endswith(("||", "&&")) and nxt.startswith("fail"): + sites.append((ln, "B-cont-operator", stripped)) + continue + if RX_IF.search(line): + window = " ".join(lines[j] for j in range(i, min(i + 5, n))) + if "fail" in window: + sites.append((ln, "D-if-form", stripped)) + continue + dispo.append((ln, "if-grep-no-fail-window", stripped)) + continue + win = " ".join(lines[j] for j in range(max(0, i - 2), min(i + 3, n))) + if re.search(r"fail", win, re.I): + dispo.append((ln, "BACKSTOP-HAND-REVIEW", stripped)) + else: + dispo.append((ln, "no-verdict-context", stripped)) + return sites, dispo + + +def load_art(): + art = json.loads(ART.read_text()) + assert art["total"] == 261 == len(art["rows"]), "artifact self-consistency" + return art + + +def helper_for(row): + return "count_lines" if row["form"].startswith("E") else "has_match" + + +def suite_files(art): + return sorted({r["file"] for r in art["rows"]}) + + +def cmd_expected(): + art = load_art() + out = sorted( + f"{helper_for(r)} {r['file']}:{r['line'] + HEADER_SHIFT}" for r in art["rows"] + ) + assert len(out) == len(set(out)) == 261, "expected set must be 261 distinct rows" + print("\n".join(out)) + return 0 + + +def cmd_static(): + art = load_art() + rows = [] + for f in suite_files(art): + for i, line in enumerate((WAKE / f).read_text().split("\n"), start=1): + if line.strip().startswith("#"): + continue + m = RX_HELPER.search(line) + if not m: + continue + helper = ( + "count_lines" + if RX_HELPER.search(line).group(2) == "count_lines" + else "has_match" + ) + rows.append(f"{helper} {f}:{i}") + print("\n".join(sorted(rows))) + return 0 + + +def cmd_arms(): + art = load_art() + by_key = {(r["file"], r["line"]): r for r in art["rows"]} + rows = [] + canaries = [r for r in art["rows"] if r.get("canary")] + assert len(canaries) == 19, f"expected 19 canaries, artifact has {len(canaries)}" + for r in canaries: + rows.append(f"{helper_for(r)} {r['file']}:{r['line'] + HEADER_SHIFT} {r['form']}") + for f, ln, want_form in EXTRA_ARMS: + r = by_key.get((f, ln)) + assert r is not None, f"extra arm {f}:{ln} not in artifact — renumbered?" + assert r["form"] == want_form, f"extra arm {f}:{ln} form {r['form']} != {want_form}" + rows.append(f"{helper_for(r)} {f}:{ln + HEADER_SHIFT} {r['form']}") + assert len(rows) == 21 + print("\n".join(rows)) + return 0 + + +PLANTS = [ + ("A-same-line", ['grep -q needle haystack || fail "plant-A"']), + ("B-cont-operator", ["grep -q needle haystack ||", ' fail "plant-B"']), + ("C-cont-backslash", ["grep -q needle \\", ' haystack || fail "plant-C"']), + ("D-if-form", ["if ! grep -q needle haystack; then", ' fail "plant-D"', "fi"]), + ("E-count-capture", ['[ "$(grep -c needle haystack)" = "1" ] || fail "plant-E"']), + ("F-extract-capture", ['val="$(grep needle haystack)"']), +] + + +def cmd_sweep(): + art = load_art() + bad = 0 + + # leg 1: real suites at the current tree must be residual-free + for f in suite_files(art): + lines = (WAKE / f).read_text().split("\n") + sites, _dispo = classify(lines) + residual = [] + for ln, form, text in sites: + if RX_HELPER.search(lines[ln - 1]): + # converted line whose PATTERN argument contains the word grep: + # not an unconverted site, but never silently absorbed either + print(f"SWEEP-NOTE {f}:{ln} converted line matches grep-token ({form}): {text[:80]}") + continue + residual.append((ln, form, text)) + for ln, form, text in residual: + print(f"SWEEP-RESIDUAL {f}:{ln} {form}: {text[:100]}") + bad += 1 + print(f"SWEEP {f}: {len(residual)} residual verdict site(s)") + + # leg 2, SAME RUN: the instrument must find six per-form plants + donor = suite_files(art)[0] + with tempfile.TemporaryDirectory() as td: + planted = Path(td) / donor + shutil.copy(WAKE / donor, planted) + base_lines = planted.read_text().split("\n") + offset = len(base_lines) + expect = {} + for form, snippet in PLANTS: + expect[offset + 1] = form # first physical line of each plant + base_lines.extend(snippet) + offset = len(base_lines) + planted.write_text("\n".join(base_lines)) + sites, _ = classify(planted.read_text().split("\n")) + found = {ln: form for ln, form, _t in sites if ln in expect} + unexpected = [(ln, form) for ln, form, _t in sites if ln not in expect] + hits = sum(1 for ln, form in expect.items() if found.get(ln) == form) + print(f"SWEEP-PLANTS found={hits}/6 in planted copy of {donor}") + if hits != 6: + for ln, form in sorted(expect.items()): + got = found.get(ln, "") + if got != form: + print(f"SWEEP-PLANT-MISS line {ln}: expected {form}, got {got}") + bad += 1 + if unexpected: + # the donor is a converted suite: any non-plant site the sweep finds + # in the copy contradicts the zero it just reported on the original + for ln, form in unexpected: + print(f"SWEEP-PLANT-UNEXPECTED {donor}(copy):{ln} {form}") + bad += 1 + + return 1 if bad else 0 + + +def main(): + cmds = { + "expected": cmd_expected, + "static": cmd_static, + "arms": cmd_arms, + "sweep": cmd_sweep, + } + if len(sys.argv) != 2 or sys.argv[1] not in cmds: + sys.exit(f"usage: check-973.py {{{'|'.join(cmds)}}}") + sys.exit(cmds[sys.argv[1]]()) + + +if __name__ == "__main__": + main() diff --git a/packages/mosaic/framework/tools/wake/validate-973/convert-973.py b/packages/mosaic/framework/tools/wake/validate-973/convert-973.py new file mode 100644 index 00000000..e696e8f6 --- /dev/null +++ b/packages/mosaic/framework/tools/wake/validate-973/convert-973.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 +"""convert-973.py — mechanical #973 site conversion, driven by the frozen +denominator artifact (denominator-089615f.json), never by ad-hoc grepping. + +For every row in the artifact it FIRST verifies the worktree line still says +what the artifact froze (exact match after whitespace strip, artifact-side +truncation as prefix match, or the normalized suite-summary template), and +aborts before touching anything on the first verification failure — a +conversion applied to a line the denominator did not measure would be the +umbrella defect wearing the converter's clothes. + +Transforms (behaviour-preserving; verdict semantics unchanged on grep rc 0/1): + E-count-capture `grep -c ARGS` -> `count_lines ARGS` (helper adds -c) + all other forms `grep ARGS` -> `has_match ARGS` (drop-in) + env prefixes (`LC_ALL=C grep`) are kept — the prefix reaches the grep child + through the function (microtest C8). + +The two multi-grep pipeline sites (digest-quarantine:560, install:420) convert +BOTH greps: each is measurement-bearing, and under pipefail an rc=2 in the +left element is masked by an rc=1 in the right — the same defect one pipe +deeper. They stay ONE denominator site each (one coordinate); the ledger +records helper calls, so those coordinates appear twice per execution and the +equality check compares SETS of coordinates. + +Finally each suite gains three header lines directly after its SCRIPT_DIR +assignment (source + wake_assert_init + comment), shifting every site by +3 +lines exactly; the validation harness maps base coordinates accordingly. +""" + +import json +import re +import sys +from pathlib import Path + +HERE = Path(__file__).resolve().parent +WAKE = HERE.parent +ART = HERE / "denominator-089615f.json" + +RX_GREP_TOKEN = re.compile(r"(^|[^A-Za-z0-9_.-])grep([^A-Za-z0-9_.-]|$)") + +HEADER = [ + "# #973: three-valued grep assertion helpers (has_match/count_lines); init saves real stderr for abort loudness.\n", + "# shellcheck disable=SC1091\n", + '. "$SCRIPT_DIR/_wake-common.sh" && wake_assert_init\n', +] + +MULTI_GREP_CONVERT_BOTH = { + ("test-wake-digest-quarantine.sh", 560), + ("test-wake-install.sh", 420), +} + +SUMMARY_TEMPLATE_MARK = '$(grep -c . "$FAILFILE")' + + +def verify(row, actual): + a = actual.strip() + t = row["text"].strip() + if a == t: + return True + if t and a.startswith(t): # artifact-side truncation + return True + # normalized suite-summary template rows + if t.startswith('echo "wake ') and SUMMARY_TEMPLATE_MARK in actual and a.startswith('echo "wake '): + return True + return False + + +def convert_line(row, line): + key = (row["file"], row["line"]) + n_grep = len(RX_GREP_TOKEN.findall(line)) + if key in MULTI_GREP_CONVERT_BOTH: + assert n_grep == 2, f"{key}: expected 2 grep tokens, found {n_grep}" + else: + assert n_grep == 1, f"{key}: expected 1 grep token, found {n_grep}: {line!r}" + + if row["form"].startswith("E"): + assert line.count("grep -c ") == 1, f"{key}: E row without single 'grep -c ': {line!r}" + return line.replace("grep -c ", "count_lines ", 1) + + def repl(m): + return m.group(1) + "has_match" + m.group(2) + + count = 2 if key in MULTI_GREP_CONVERT_BOTH else 1 + return RX_GREP_TOKEN.sub(repl, line, count=count) + + +def main(): + art = json.loads(ART.read_text()) + rows = art["rows"] + by_file = {} + for r in rows: + by_file.setdefault(r["file"], []).append(r) + + # pass 1: verify every row before touching any file + bad = 0 + texts = {} + for f, frs in by_file.items(): + lines = (WAKE / f).read_text().split("\n") + texts[f] = lines + for r in frs: + if not verify(r, lines[r["line"] - 1]): + bad += 1 + print(f"VERIFY-FAIL {f}:{r['line']}\n artifact: {r['text']!r}\n worktree: {lines[r['line'] - 1]!r}") + if bad: + sys.exit(f"ABORT: {bad} row(s) failed verification; nothing was modified.") + + # pass 2: convert + insert header + total = {"has_match": 0, "count_lines": 0} + for f, frs in sorted(by_file.items()): + lines = texts[f] + for r in frs: + i = r["line"] - 1 + new = convert_line(r, lines[i]) + assert new != lines[i], f"{f}:{r['line']}: no-op conversion" + lines[i] = new + total["count_lines" if r["form"].startswith("E") else "has_match"] += 1 + # header insertion after the SCRIPT_DIR= line + sd = [i for i, ln in enumerate(lines) if ln.startswith('SCRIPT_DIR="$(')] + assert len(sd) == 1, f"{f}: expected exactly one SCRIPT_DIR line, found {len(sd)}" + first_site = min(r["line"] for r in frs) - 1 + assert sd[0] < first_site, f"{f}: SCRIPT_DIR line {sd[0] + 1} not before first site {first_site + 1}" + lines[sd[0] + 1 : sd[0] + 1] = [h.rstrip("\n") for h in HEADER] + (WAKE / f).write_text("\n".join(lines)) + print(f"{f}: {len(frs)} sites converted, header at line {sd[0] + 2}") + + print(f"TOTAL: {total['has_match']} has_match + {total['count_lines']} count_lines = {sum(total.values())} sites in {len(by_file)} files") + assert sum(total.values()) == art["total"] == 261, "site count mismatch vs artifact" + + +if __name__ == "__main__": + main() diff --git a/packages/mosaic/framework/tools/wake/validate-973/denominator-089615f.json b/packages/mosaic/framework/tools/wake/validate-973/denominator-089615f.json new file mode 100644 index 00000000..49275cd3 --- /dev/null +++ b/packages/mosaic/framework/tools/wake/validate-973/denominator-089615f.json @@ -0,0 +1,3414 @@ +{ + "base_commit": "089615f", + "frozen_commit": "8d1d6e5", + "derivation": "union(frozen-257 forward-mapped with per-row disposition, fresh six-form derivation at base); legs must agree by set equality", + "predicates": { + "A": "same-line: grep + (||/&&)\\s*fail", + "B": "grep line ends ||/&&, next non-blank line starts fail", + "C": "grep line ends backslash, next line starts ||/&& fail", + "D": "if [!] ...grep...; then with fail in following 4 lines", + "E": "assignment capturing $(... grep -c ...)", + "F": "assignment capturing $(... grep ...) non-count", + "G": "grep with fail within +/-2 lines, no other form" + }, + "total": 261, + "by_form": { + "A-same-line": 204, + "E-count-capture": 28, + "B-cont-operator": 6, + "F-extract-capture": 4, + "C-cont-backslash": 10, + "D-if-form": 9 + }, + "rows": [ + { + "file": "test-wake-beacon.sh", + "line": 132, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'ALARM FIRED' || fail_msg \"B2: absence must announce the alarm fired [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 132, + "note": "" + }, + { + "file": "test-wake-beacon.sh", + "line": 153, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'silent no-alarm host' || fail_msg \"B3a: the failure must name the silent-no-alarm-host hazard [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 153, + "note": "" + }, + { + "file": "test-wake-beacon.sh", + "line": 159, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out2\" | grep -qi 'UNREACHABLE' || fail_msg \"B3b: the failure must name the unreachable target [$out2]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 159, + "note": "" + }, + { + "file": "test-wake-beacon.sh", + "line": 172, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -qi 'DEGRADED' || fail_msg \"B4: a different-supervision-root beacon must be FLAGGED degraded on stderr [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 172, + "note": "" + }, + { + "file": "test-wake-beacon.sh", + "line": 173, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -q 'degraded=true' || fail_msg \"B4: emit must NOT silently present a degraded beacon as healthy (degraded=true expected) [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 173, + "note": "" + }, + { + "file": "test-wake-beacon.sh", + "line": 185, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'not an independent' || fail_msg \"B5: the rejection must explain it is NOT an independent leg [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 185, + "note": "" + }, + { + "file": "test-wake-beacon.sh", + "line": 204, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "head -n1 \"$ALARM_OUT\" 2>/dev/null | grep -qF \"$SECRET_TARGET\" || fail_msg \"B6: the adapter must resolve+route to the BY-NAME target [$(cat \"$ALARM_OUT\" 2>/dev/n", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 204, + "note": "" + }, + { + "file": "test-wake-beacon.sh", + "line": 206, + "form": "A-same-line", + "polarity": "AND", + "canary": true, + "text": "grep -qF \"$SECRET_TARGET\" \"$BEACON\" && fail_msg \"B6: beacon.sh must NOT inline the target endpoint/secret\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 206, + "note": "" + }, + { + "file": "test-wake-beacon.sh", + "line": 207, + "form": "A-same-line", + "polarity": "AND", + "canary": true, + "text": "grep -qF \"$SECRET_TARGET\" \"$WAKE_ALARM_SINK_CMD\" && fail_msg \"B6: even the adapter must resolve by-name, not inline the secret\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 207, + "note": "" + }, + { + "file": "test-wake-beacon.sh", + "line": 221, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'silent no-alarm host' || fail_msg \"B7a: the failure must name the silent-no-alarm-host hazard [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 221, + "note": "" + }, + { + "file": "test-wake-beacon.sh", + "line": 230, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out2\" | grep -qi 'UNREACHABLE' || fail_msg \"B7b: the failure must name the unreachable sink [$out2]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 230, + "note": "" + }, + { + "file": "test-wake-beacon.sh", + "line": 241, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'slo' || fail_msg \"B8: the usage error must name the missing SLO [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 241, + "note": "" + }, + { + "file": "test-wake-beacon.sh", + "line": 270, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'ALIVE' || fail_msg \"B10: a fresh beacon must report ALIVE [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 270, + "note": "" + }, + { + "file": "test-wake-beacon.sh", + "line": 294, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'ALARM FIRED' || fail_msg \"B11: the receive-time-stale beacon must fire the absence alarm [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 294, + "note": "" + }, + { + "file": "test-wake-beacon.sh", + "line": 332, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'spoofed beacon' || fail_msg \"B12: the rejection must name the spoof [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 332, + "note": "" + }, + { + "file": "test-wake-beacon.sh", + "line": 340, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "grep -qF \"test-beacon-hmac-key-do-not-echo\" \"$BEACON\" && fail_msg \"B12: beacon.sh must NOT inline the HMAC key\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 340, + "note": "" + }, + { + "file": "test-wake-beacon.sh", + "line": 347, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "echo \"wake ... harness: FAILED ($(grep -c . \\\"$FAILFILE\\\") assertion(s))\" >&2", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 347, + "note": "summary-count subclass (mos-dt derivation): exit discarded by substitution inside echo; FAILED (0 assertion(s)) under grep error reads as flake" + }, + { + "file": "test-wake-detector.sh", + "line": 256, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -qi 'schema_version' || fail_msg \"D5: the failure must name schema_version [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 256, + "note": "" + }, + { + "file": "test-wake-detector.sh", + "line": 257, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -qi 'range' || fail_msg \"D5: the failure must state it is out of the supported range [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 257, + "note": "" + }, + { + "file": "test-wake-detector.sh", + "line": 290, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -qi 'FAIL LOUD' || fail_msg \"D6: the source error must be loud [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 290, + "note": "" + }, + { + "file": "test-wake-detector.sh", + "line": 301, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -qi 'AMBIGUOUS-EMPTY' || fail_msg \"D6: ambiguous-empty must be named in the loud failure [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 301, + "note": "" + }, + { + "file": "test-wake-detector.sh", + "line": 445, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -qi 'range' || fail_msg \"D9: the out-of-range failure must still state it is out of the supported range [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 445, + "note": "" + }, + { + "file": "test-wake-detector.sh", + "line": 516, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -qi 'snapshot' || fail_msg \"D11: dropping malformed metadata must be LOUD on stderr [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 516, + "note": "" + }, + { + "file": "test-wake-detector.sh", + "line": 525, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -qi 'snapshot' || fail_msg \"D11: rejecting a bad snapshot_sha must be LOUD on stderr [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 525, + "note": "" + }, + { + "file": "test-wake-detector.sh", + "line": 563, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -qi 'without a valid snapshot_sha' || fail_msg \"D12: dropping ts-without-sha must be LOUD on stderr [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 563, + "note": "" + }, + { + "file": "test-wake-detector.sh", + "line": 574, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -qi 'future-skew' || fail_msg \"D12: dropping a future ts must be LOUD on stderr [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 574, + "note": "" + }, + { + "file": "test-wake-detector.sh", + "line": 584, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -qi 'sane positive epoch' || fail_msg \"D12: rejecting an absurd ts must be LOUD on stderr [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 584, + "note": "" + }, + { + "file": "test-wake-detector.sh", + "line": 624, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -qi 'falling back to 300' || fail_msg \"D13: malformed slack must be LOUD on stderr [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 624, + "note": "" + }, + { + "file": "test-wake-detector.sh", + "line": 633, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -qi 'falling back to 300' || fail_msg \"D13: non-numeric slack must be LOUD on stderr [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 633, + "note": "" + }, + { + "file": "test-wake-detector.sh", + "line": 643, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -qi 'falling back to 300' || fail_msg \"D13: negative slack must be LOUD on stderr [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 643, + "note": "" + }, + { + "file": "test-wake-detector.sh", + "line": 655, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -qi 'falling back to 300' || fail_msg \"D13: multi-line slack must be LOUD on stderr [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 655, + "note": "" + }, + { + "file": "test-wake-detector.sh", + "line": 663, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -qi 'falling back to 300' || fail_msg \"D13: multi-line non-numeric slack must be LOUD on stderr [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 663, + "note": "" + }, + { + "file": "test-wake-detector.sh", + "line": 690, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -qi 'future-skew' || fail_msg \"D13: a valid tightened slack must still reject a future ts [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 690, + "note": "" + }, + { + "file": "test-wake-detector.sh", + "line": 699, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "echo \"wake ... harness: FAILED ($(grep -c . \\\"$FAILFILE\\\") assertion(s))\" >&2", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 699, + "note": "summary-count subclass (mos-dt derivation): exit discarded by substitution inside echo; FAILED (0 assertion(s)) under grep error reads as flake" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 105, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -q 'issue=#11' || fail_msg \"D1: OLDER change (issue #11) dropped \u2014 digest is a delta, not cumulative state\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 105, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 106, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -q 'issue=#22' || fail_msg \"D1: newer change (issue #22) missing\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 106, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 107, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -q 'seq 1' || fail_msg \"D1: seq 1 not listed in cumulative set\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 107, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 108, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -q 'seq 2' || fail_msg \"D1: seq 2 not listed in cumulative set\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 108, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 111, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -q 'pending=2' || fail_msg \"D1: cumulative pending count wrong (expected 2)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 111, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 130, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'mergeable=true' && fail_msg \"D2: an unlocated actionable claim must NOT be delivered as a valid CLAIM\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 130, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 131, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q 'mergeable=true' \"$h/default/dead-letter.jsonl\" 2>/dev/null || fail_msg \"D2: the malformed claim must be DEAD-LETTERED (fail-loud preserved, per-entry)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 131, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 132, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -qi 'QUARANTINE' \"$err\" || fail_msg \"D2: a LOUD per-entry alarm must fire for the malformed claim\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 132, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 143, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'ci=green' && fail_msg \"D2: imprecise sha (not 40-hex) must not satisfy the hard-locator gate (claim must not deliver)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 143, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 144, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q 'ci=green' \"$h/default/dead-letter.jsonl\" 2>/dev/null || fail_msg \"D2: imprecise-sha claim must be dead-lettered\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 144, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 152, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q \"$SHA40\" || fail_msg \"D2: a well-located actionable claim must be DELIVERED\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 152, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 167, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'mergeable=true' && fail_msg \"D2(#905): --stdin top-level-.claim must NOT be delivered (gate not bypassed)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 167, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 168, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q 'mergeable=true' \"$h/default/dead-letter.jsonl\" 2>/dev/null || fail_msg \"D2(#905): --stdin top-level .claim must be dead-lettered (gate enforced)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 168, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 177, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$out2\" | grep -q 'mergeable=true' && fail_msg \"D2(#905): --from-file top-level-.claim must NOT be delivered (gate not bypassed)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 177, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 178, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q 'mergeable=true' \"$h/default/dead-letter.jsonl\" 2>/dev/null || fail_msg \"D2(#905): --from-file top-level .claim must be dead-lettered (gate enforced)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 178, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 200, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -q 'NO-OP' || fail_msg \"D3: empty inbox must render an explicit NO-OP orientation\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 200, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 209, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out2\" | grep -q 'CLAIM@seq' || fail_msg \"D3: consequential fact not framed as CLAIM@seq\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 209, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 210, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out2\" | grep -qi 'VERIFY LIVE' || fail_msg \"D3: claim not marked for live verification\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 210, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 211, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out2\" | grep -qi 'do NOT act on this line' || fail_msg \"D3: claim missing do-not-auto-action framing\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 211, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 213, + "form": "B-cont-operator", + "polarity": "AND", + "canary": true, + "text": "echo \"$out2\" | grep -qiE 'merge now|go ahead and (merge|deploy)|safe to merge' &&", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 213, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 216, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out2\" | grep -q \"re-verify (ONE call)\" || fail_msg \"D3: actionable claim missing one-call re-verify locator\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 216, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 232, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$out\" | LC_ALL=C grep -q \"$(printf '\\x1b')\" && fail_msg \"D4: ANSI ESC survived the scrub\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 232, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 247, + "form": "B-cont-operator", + "polarity": "AND", + "canary": true, + "text": "printf '%s' \"$out\" | LC_ALL=C grep -qE \"${_b280}[${_b8b}-${_b8f}${_baa}-${_bae}]|${_bbom}\" &&", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 247, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 252, + "form": "B-cont-operator", + "polarity": "AND", + "canary": true, + "text": "printf '%s' \"$out\" | LC_ALL=C grep -qE \"[${_c00}-${_c08}${_c0e}-${_c1f}${_c7f}]\" &&", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 252, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 255, + "form": "A-same-line", + "polarity": "AND", + "canary": true, + "text": "printf '%s' \"$out\" | grep -q 'ghp_0123456789' && fail_msg \"D4: GitHub-token canary LEAKED into the digest\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 255, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 256, + "form": "A-same-line", + "polarity": "AND", + "canary": true, + "text": "printf '%s' \"$out\" | grep -q 'AKIAIOSFODNN7EXAMPLE' && fail_msg \"D4: AWS-key canary LEAKED into the digest\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 256, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 257, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'REDACTED-SECRET' || fail_msg \"D4: secret redaction marker absent \u2014 canary may not have been scrubbed\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 257, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 259, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'BEGIN UNTRUSTED DATA' || fail_msg \"D4: source free-text not placed in a delimited untrusted block\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 259, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 261, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q \"$SHA40\" || fail_msg \"D4: legitimate 40-hex SHA locator was wrongly scrubbed\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 261, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 326, + "form": "A-same-line", + "polarity": "AND", + "canary": true, + "text": "echo \"$env1\" | grep -q 'SUPERSECRET-KEYVALUE-XYZ' && fail_msg \"H2: key material LEAKED into the signed envelope\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 326, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 330, + "form": "A-same-line", + "polarity": "AND", + "canary": true, + "text": "echo \"$entry\" | grep -q 'SUPERSECRET-KEYVALUE-XYZ' && fail_msg \"H2: key material LEAKED into the signed entry\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 330, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 344, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -qi 'same-uid' \"$SIGN\" || fail_msg \"H2: same-uid threat boundary not documented in sign.sh\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 344, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 345, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -qi 'off-uid' \"$SIGN\" || fail_msg \"H2: off-uid future signer not named in sign.sh\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 345, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 358, + "form": "B-cont-operator", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$ack_line\" | grep -q 'WAKE_AGENT=someagent' ||", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 358, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 404, + "form": "F-extract-capture", + "polarity": "REVIEW", + "canary": false, + "text": "orientline=\"$(printf '%s\\n' \"$out\" | grep -E '^\\s*\\* seq 1 \\[digest\\]')\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 404, + "note": "verdict at a later comparison site" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 406, + "form": "B-cont-operator", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$orientline\" | grep -qE 'locator: *$' &&", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 406, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 409, + "form": "B-cont-operator", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$orientline\" | grep -qE 'remote=example/repo|id=r1|kind=repo' ||", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 409, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 424, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'mergeable=true' && fail_msg \"D6: a malformed actionable claim must NOT be delivered as valid (fail-loud preserved)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 424, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 425, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q 'mergeable=true' \"$h/default/dead-letter.jsonl\" 2>/dev/null || fail_msg \"D6: a malformed actionable must be DEAD-LETTERED (fail-loud preserved, per-entr", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 425, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 426, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -qi 'QUARANTINE' \"$err\" || fail_msg \"D6: a malformed actionable must raise a loud per-entry alarm\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 426, + "note": "" + }, + { + "file": "test-wake-digest-hmac.sh", + "line": 431, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "echo \"wake ... harness: FAILED ($(grep -c . \\\"$FAILFILE\\\") assertion(s))\" >&2", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 431, + "note": "summary-count subclass (mos-dt derivation): exit discarded by substitution inside echo; FAILED (0 assertion(s)) under grep error reads as flake" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 179, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q \"$SHA40\" || fail_msg \"Q1: the clean sibling (sha $SHA40) must STILL be delivered in the same drain [head-of-line block]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 179, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 180, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'MALFORMED-Q' && fail_msg \"Q1: the quarantined entry must be EXCLUDED from the rendered digest\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 180, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 182, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q 'MALFORMED-Q' \"$(dlq \"$home\")\" 2>/dev/null || fail_msg \"Q1: the malformed entry must be DEAD-LETTERED (accounted-for, not silently dropped)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 182, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 183, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -qi 'QUARANTINE' \"$err\" || fail_msg \"Q1: a LOUD per-entry alarm must fire on stderr\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 183, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 184, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q 'observed_seq=1' \"$err\" || fail_msg \"Q1: the alarm must identify the offending entry (observed_seq=1)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 184, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 203, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'id=ENUM-B' || fail_msg \"Q2: the enumeration must render as an ORIENTATION pointer (id=ENUM-B via _locator_line)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 203, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 204, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'CLAIM@seq' && fail_msg \"Q2: an enumeration must NOT render as an ACTIONABLE CLAIM@seq\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 204, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 223, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "n=\"$(printf '%s\\n' \"$out\" | grep -c 'id=ENUM-C[12]' || true)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 223, + "note": "error swallowed by || true" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 225, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'id=ENUM-C1' || fail_msg \"Q3: enumeration ENUM-C1 must be present\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 225, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 226, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'id=ENUM-C2' || fail_msg \"Q3: enumeration ENUM-C2 must be present\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 226, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 242, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'CLAIM-KEEP' && fail_msg \"Q4: a malformed actionable must NOT be delivered as if valid\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 242, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 243, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q '(none) \u2014 no consequential claims pending' || fail_msg \"Q4: with the only claim quarantined, the ACTIONABLE section must show (none", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 243, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 244, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q 'CLAIM-KEEP' \"$(dlq \"$home\")\" 2>/dev/null || fail_msg \"Q4: the malformed actionable must be DEAD-LETTERED (loudly surfaced, not silent)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 244, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 245, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -qi 'QUARANTINE' \"$err\" || fail_msg \"Q4: the malformed actionable must raise a LOUD alarm\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 245, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 261, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q 'CLAIMY' \"$(dlq \"$home\")\" 2>/dev/null || fail_msg \"Q5: a claim-carrying entry with no hard locator must be quarantined (claim precedence, \u00a72.1)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 261, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 262, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'CI is green' && fail_msg \"Q5: the un-verifiable claim must NOT be delivered\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 262, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 281, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "n=\"$(grep -c . \"$ALARM_OUT\" 2>/dev/null || true)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 281, + "note": "error swallowed by || true" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 283, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q '\"observed_seq\":21' \"$ALARM_OUT\" 2>/dev/null || fail_msg \"Q6: the routed alarm payload must name the entry's observed_seq (21)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 283, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 284, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -qi 'QUARANTINE' \"$err\" || fail_msg \"Q6: the existing #920 stderr diagnostic must STILL fire (local + off-host, not either/or)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 284, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 285, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'DLQ-Q6' && fail_msg \"Q6: the quarantined entry must still be EXCLUDED from the rendered digest\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 285, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 303, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "n=\"$(grep -c . \"$ALARM_OUT\" 2>/dev/null || true)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 303, + "note": "error swallowed by || true" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 305, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -qi 'QUARANTINE' \"$TMP_ROOT/q7.err.4\" || fail_msg \"Q7: the #920 stderr diagnostic must STILL fire on every re-drain (only the off-host route is deduped)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 305, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 324, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "n=\"$(grep -c . \"$ALARM_OUT\" 2>/dev/null || true)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 324, + "note": "error swallowed by || true" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 326, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q '\"observed_seq\":31' \"$ALARM_OUT\" 2>/dev/null || fail_msg \"Q8: seq 31's alarm must be present\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 326, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 327, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q '\"observed_seq\":32' \"$ALARM_OUT\" 2>/dev/null || fail_msg \"Q8: seq 32's (the new distinct entry's) OWN alarm must be present\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 327, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 343, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -qi 'FAIL LOUD' \"$err_a\" || fail_msg \"Q9a: an unconfigured off-host alarm target must FAIL LOUD on stderr [$(cat \"$err_a\")]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 343, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 344, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -Eqi 'silent no-alarm|silent-miss|PERMANENTLY miss|permanent silent miss' \"$err_a\" || fail_msg \"Q9a: the diagnostic must name the silent-miss hazard (G2a),", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 344, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 345, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$out_a\" | grep -q 'DLQ-Q9' && fail_msg \"Q9a: the quarantined entry must still be EXCLUDED from the rendered digest\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 345, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 358, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -qi 'FAIL LOUD' \"$err_b\" || fail_msg \"Q9b: an unreachable off-host alarm target must FAIL LOUD on stderr [$(cat \"$err_b\")]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 358, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 359, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -qi 'UNREACHABLE' \"$err_b\" || fail_msg \"Q9b: the diagnostic must name the unreachable target [$(cat \"$err_b\")]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 359, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 360, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$out_b\" | grep -q 'DLQ-Q9' && fail_msg \"Q9b: the quarantined entry must still be EXCLUDED from the rendered digest\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 360, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 386, + "form": "F-extract-capture", + "polarity": "REVIEW", + "canary": false, + "text": "snapa_line=\"$(printf '%s\\n' \"$out\" | grep 'id=SNAP-A' || true)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 386, + "note": "verdict at a later comparison site" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 387, + "form": "C-cont-backslash", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$snapa_line\" | grep -q 'snapshot_sha=0123abc4567890def0123abc4567890def012345' \\", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 387, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 389, + "form": "C-cont-backslash", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$snapa_line\" | grep -q 'snapshot_ts=1753850000' \\", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 389, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 391, + "form": "C-cont-backslash", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'git show 0123abc4567890def0123abc4567890def012345:BOARD.md' \\", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 391, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 394, + "form": "F-extract-capture", + "polarity": "REVIEW", + "canary": false, + "text": "snapb_line=\"$(printf '%s\\n' \"$out\" | grep 'id=SNAP-B' || true)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 394, + "note": "verdict at a later comparison site" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 395, + "form": "C-cont-backslash", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$snapb_line\" | grep -q 'snapshot_' \\", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 395, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 437, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'seq 68 \u2014 CLAIM@seq' || fail_msg \"Q11a: the live seq-68 detector-shape entry must RENDER as CLAIM@seq (positive control)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 437, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 438, + "form": "C-cont-backslash", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'git show 55d4909569d2b5fbccfec49ec9ca83db5049f3ce:docs/scratchpads/heartbeat-planning' \\", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 438, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 441, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'seq 69 \u2014 CLAIM@seq' || fail_msg \"Q11b: a path-only detector-shape entry must RENDER as CLAIM@seq (path arm)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 441, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 442, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 're-read BOARD.md' || fail_msg \"Q11b: the path-only claim must carry the one-call re-read hint\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 442, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 443, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "n_claims=\"$(printf '%s\\n' \"$out\" | grep -c 'CLAIM@seq' || true)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 443, + "note": "error swallowed by || true" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 446, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'ADDR-FREE' && fail_msg \"Q11c: the address-free entry must be EXCLUDED from the digest\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 446, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 447, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'SNAP-ONLY' && fail_msg \"Q11d: no bare path-less snapshot_sha entry may appear in the digest (gate must not widen past board_file)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 447, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 448, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q 'ADDR-FREE' \"$(dlq \"$home\")\" 2>/dev/null || fail_msg \"Q11c: the address-free entry must be DEAD-LETTERED\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 448, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 450, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q \"$snap_id\" \"$(dlq \"$home\")\" 2>/dev/null || fail_msg \"Q11d: the bare snapshot_sha entry ($snap_id) must be DEAD-LETTERED\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 450, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 452, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "grep -q 'heartbeat-planning' \"$(dlq \"$home\")\" 2>/dev/null && fail_msg \"Q11a: the valid live entry must NOT be dead-lettered\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 452, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 453, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "grep -q 'PILOT-LOCAL' \"$(dlq \"$home\")\" 2>/dev/null && fail_msg \"Q11b: the valid path-only entry must NOT be dead-lettered\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 453, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 454, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "n_alarms=\"$(grep -c . \"$ALARM_OUT\" 2>/dev/null || true)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 454, + "note": "error swallowed by || true" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 456, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q '\"observed_seq\":70' \"$ALARM_OUT\" 2>/dev/null || fail_msg \"Q11c: seq 70's own alarm must be present\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 456, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 458, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q \"\\\"observed_seq\\\":$snap_seq\" \"$ALARM_OUT\" 2>/dev/null || fail_msg \"Q11d: seq $snap_seq's own alarm must be present\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 458, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 480, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'QUARANTINED' || fail_msg \"Q12: the digest must carry a QUARANTINED disclosure section (no silent hold)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 480, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 481, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'seq 2 .*HELD' || fail_msg \"Q12: the disclosure must name the held seq (2) as HELD\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 481, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 484, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'ADDR-Q12' && fail_msg \"Q12: the quarantined entry's content/locators must stay EXCLUDED from the digest\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 484, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 486, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -Eq 'consumed --upto 1$' || fail_msg \"Q12: the embedded ack must be CLAMPED to --upto 1 (below quarantined seq 2)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 486, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 487, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$out\" | grep -Eq 'consumed --upto 2( |$)' && fail_msg \"Q12: the raw observed cursor (2) must NOT be embedded while seq 2 is quarantined\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 487, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 488, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'ACK CLAMPED' || fail_msg \"Q12: the clamp must be LOUDLY disclosed in the ACK section\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 488, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 506, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -Eq 'consumed --upto 1$' || fail_msg \"Q13: with nothing quarantined the ack must embed the observed cursor (1) unchanged\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 506, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 507, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'QUARANTINED' && fail_msg \"Q13: no disclosure section when nothing is quarantined\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 507, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 508, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'ACK CLAMPED' && fail_msg \"Q13: no clamp note when nothing is quarantined\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 508, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 523, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'QUARANTINED' || fail_msg \"Q14: the store-mode digest must disclose the held entry\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 523, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 524, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -Eq 'consumed --upto 1$' || fail_msg \"Q14: the embedded ack must clamp to 1 (below quarantined seq 2)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 524, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 548, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s' \"$out\" | grep -q 'QUARANTINED' && fail_msg \"Q15: nothing quarantines under the fixed gate \u2014 no disclosure section\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 548, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 549, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "printf '%s' \"$out\" | grep -Eq 'consumed --upto 2$' || fail_msg \"Q15: the ack must embed the full observed cursor (2) once the gate is fixed\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 549, + "note": "" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 560, + "form": "F-extract-capture", + "polarity": "REVIEW", + "canary": false, + "text": "fixture_line=\"$(grep -F \"\\\"id\\\":\\\"$enum_id\\\"\" \"$self\" | grep -F '\"observed_seq\":5' | head -n1)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 560, + "note": "verdict at a later comparison site" + }, + { + "file": "test-wake-digest-quarantine.sh", + "line": 581, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "echo \"wake ... harness: FAILED ($(grep -c . \\\"$FAILFILE\\\") assertion(s))\" >&2", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 581, + "note": "summary-count subclass (mos-dt derivation): exit discarded by substitution inside echo; FAILED (0 assertion(s)) under grep error reads as flake" + }, + { + "file": "test-wake-fn-oracle.sh", + "line": 65, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -q 'FN-RATE = 0/3' || fail_msg \"O1: FN-rate must be 0/3 on a healthy pipeline [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 65, + "note": "" + }, + { + "file": "test-wake-fn-oracle.sh", + "line": 66, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -q 'VERDICT = PASS' || fail_msg \"O1: verdict must be PASS on a healthy pipeline [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 66, + "note": "" + }, + { + "file": "test-wake-fn-oracle.sh", + "line": 79, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -q 'FN-RATE = 3/3' || fail_msg \"O2: every dropped canary must count as a false-negative (FN-RATE 3/3) [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 79, + "note": "" + }, + { + "file": "test-wake-fn-oracle.sh", + "line": 80, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -q 'VERDICT = FN-DETECTED' || fail_msg \"O2: verdict must be FN-DETECTED for a dropping detector [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 80, + "note": "" + }, + { + "file": "test-wake-fn-oracle.sh", + "line": 81, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'never OBSERVED' || fail_msg \"O2: the failure must name the dropped (never-observed) delta [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 81, + "note": "" + }, + { + "file": "test-wake-fn-oracle.sh", + "line": 94, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'per-class SLO' || fail_msg \"O3: the failure must attribute to the per-class SLO, not a drop [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 94, + "note": "" + }, + { + "file": "test-wake-fn-oracle.sh", + "line": 97, + "form": "D-if-form", + "polarity": "AND", + "canary": false, + "text": "if echo \"$out\" | grep -qi 'never OBSERVED'; then", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 97, + "note": "fail inside if-block" + }, + { + "file": "test-wake-fn-oracle.sh", + "line": 113, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -q 'VERDICT = FN-DETECTED' || fail_msg \"O4: off-domain verdict must not be fooled by a clean exit code [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 113, + "note": "" + }, + { + "file": "test-wake-fn-oracle.sh", + "line": 124, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -qi 'slo' || fail_msg \"O5: the usage error must name the missing SLO [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 124, + "note": "" + }, + { + "file": "test-wake-fn-oracle.sh", + "line": 129, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "echo \"wake ... harness: FAILED ($(grep -c . \\\"$FAILFILE\\\") assertion(s))\" >&2", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 129, + "note": "summary-count subclass (mos-dt derivation): exit discarded by substitution inside echo; FAILED (0 assertion(s)) under grep error reads as flake" + }, + { + "file": "test-wake-install.sh", + "line": 97, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'Gate A VIOLATION' || fail_msg \"I2: refusal must name the Gate A violation [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 97, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 124, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'EXACTLY ONE' || fail_msg \"I3: verify must confirm exactly-one [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 124, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 144, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'snapshot-guard' || fail_msg \"I4: refusal must name the snapshot-guard [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 144, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 164, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'UNSIGNED' || fail_msg \"I5: HMAC failure must warn about unsigned wakes [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 164, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 169, + "form": "A-same-line", + "polarity": "AND", + "canary": true, + "text": "echo \"$out2\" | grep -qF \"$SECRET_KEY\" && fail_msg \"I5: validate must NEVER echo the HMAC key material\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 169, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 174, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out3\" | grep -qi 'silent no-alarm host' || fail_msg \"I5: alarm failure must name the silent-no-alarm hazard [$out3]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 174, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 179, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out4\" | grep -qi 'UNREACHABLE' || fail_msg \"I5: alarm failure must name the unreachable target [$out4]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 179, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 184, + "form": "A-same-line", + "polarity": "AND", + "canary": true, + "text": "grep -qF \"$SECRET_ENDPOINT\" \"$WI\" && fail_msg \"I5: wake-install.sh must NOT inline any alarm endpoint\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 184, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 185, + "form": "A-same-line", + "polarity": "AND", + "canary": true, + "text": "grep -qE 'hmac_keys[^A-Za-z_].*=[^=].*[A-Za-z0-9]{8,}' \"$WI\" && fail_msg \"I5: wake-install.sh must NOT inline key material\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 185, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 207, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'LEFT RUNNING' || fail_msg \"I6: overlap must announce retire is withheld [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 207, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 286, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'manifest.sh' || fail_msg \"I9: the failure must NAME the missing library (manifest.sh) [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 286, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 287, + "form": "C-cont-backslash", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qiE 'REMEDY|mosaic update|re-seed|framework install' \\", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 287, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 290, + "form": "C-cont-backslash", + "polarity": "AND", + "canary": false, + "text": "echo \"$out\" | grep -qi 'No such file or directory' \\", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 290, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 316, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out2\" | grep -qi 'search path' || fail_msg \"I10: validate failure must name the search-path miss [$out2]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 316, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 319, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "n=\"$(find \"$UD\" -maxdepth 1 -name 'mosaic-wake.service' | grep -c .)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 319, + "note": "exit code discarded by substitution" + }, + { + "file": "test-wake-install.sh", + "line": 337, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out0\" | grep -qi 'F7' || fail_msg \"I11: the refusal must name the F7 precondition [$out0]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 337, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 342, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'FALLBACK WAKE is not proven live' || fail_msg \"I11: refusal must name the un-proven fallback [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 342, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 370, + "form": "C-cont-backslash", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -q 'STALLED-DRAIN-MARK' \\", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 370, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 374, + "form": "C-cont-backslash", + "polarity": "OR", + "canary": false, + "text": "grep -qE '^ExecStart=.*digest\\.sh render --from-store' \"$UNIT\" \\", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 374, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 394, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'search path' || fail_msg \"I13: validate failure must name the search-path miss [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 394, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 397, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "nt=\"$(find \"$UD\" -maxdepth 1 -name 'mosaic-wake-fallback.timer' | grep -c .)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 397, + "note": "exit code discarded by substitution" + }, + { + "file": "test-wake-install.sh", + "line": 398, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "ns=\"$(find \"$UD\" -maxdepth 1 -name 'mosaic-wake-fallback.service' | grep -c .)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 398, + "note": "exit code discarded by substitution" + }, + { + "file": "test-wake-install.sh", + "line": 410, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q '^OnUnitActiveSec=1h' \"$UD/$TIMER\" || fail_msg \"I14: shipped fallback timer must carry a base OnUnitActiveSec placeholder\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 410, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 414, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'exactly one' || fail_msg \"I14: the cadence write must confirm exactly-one OnUnitActiveUSec [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 414, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 420, + "form": "C-cont-backslash", + "polarity": "OR", + "canary": false, + "text": "grep -A1 '^OnUnitActiveSec=$' \"$UD/$TIMER.d/cadence.conf\" | grep -qx 'OnUnitActiveSec=30min' \\", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 420, + "note": "" + }, + { + "file": "test-wake-install.sh", + "line": 431, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "echo \"wake ... harness: FAILED ($(grep -c . \\\"$FAILFILE\\\") assertion(s))\" >&2", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 431, + "note": "summary-count subclass (mos-dt derivation): exit discarded by substitution inside echo; FAILED (0 assertion(s)) under grep error reads as flake" + }, + { + "file": "test-wake-preimage.sh", + "line": 205, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "jq -r '.refused // \"\"' <<<\"$row\" | grep -qi 'path' || fail_msg \"P4: refusal must name the path deny [$row]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 205, + "note": "" + }, + { + "file": "test-wake-preimage.sh", + "line": 207, + "form": "D-if-form", + "polarity": "AND", + "canary": true, + "text": "if grep -rq \"$secret\" \"$sd\" 2>/dev/null; then", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 207, + "note": "fail inside if-block" + }, + { + "file": "test-wake-preimage.sh", + "line": 228, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "jq -r '.refused // \"\"' <<<\"$row\" | grep -qi 'secret' || fail_msg \"P5: refusal must name secret-shaped content [$row]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 228, + "note": "" + }, + { + "file": "test-wake-preimage.sh", + "line": 229, + "form": "D-if-form", + "polarity": "AND", + "canary": true, + "text": "if grep -rq \"$tok\" \"$sd\" 2>/dev/null; then", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 229, + "note": "fail inside if-block" + }, + { + "file": "test-wake-preimage.sh", + "line": 278, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'does not resolve' || fail_msg \"P8: the failure must name the unresolvable adapter [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 278, + "note": "" + }, + { + "file": "test-wake-preimage.sh", + "line": 297, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'unparseable' || fail_msg \"P9: the failure must name the corrupt ledger [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 297, + "note": "" + }, + { + "file": "test-wake-preimage.sh", + "line": 317, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "jq -r '.refused // \"\"' <<<\"$row\" | grep -qi 'MAX_BYTES' || fail_msg \"P10: refusal must name the size cap [$row]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 317, + "note": "" + }, + { + "file": "test-wake-preimage.sh", + "line": 365, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'preimage' || fail_msg \"P12: the failure must name the preimage check [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 365, + "note": "" + }, + { + "file": "test-wake-preimage.sh", + "line": 400, + "form": "D-if-form", + "polarity": "AND", + "canary": true, + "text": "if grep -rq \"$s1\" \"$sd\" 2>/dev/null; then", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 400, + "note": "fail inside if-block" + }, + { + "file": "test-wake-preimage.sh", + "line": 403, + "form": "D-if-form", + "polarity": "AND", + "canary": true, + "text": "if grep -rq \"$s2\" \"$sd\" 2>/dev/null; then", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 403, + "note": "fail inside if-block" + }, + { + "file": "test-wake-preimage.sh", + "line": 426, + "form": "D-if-form", + "polarity": "AND", + "canary": true, + "text": "if grep -rq \"$hm\" \"$sd\" 2>/dev/null; then", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 426, + "note": "fail inside if-block" + }, + { + "file": "test-wake-preimage.sh", + "line": 437, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "jq -r '.refused // \"\"' <<<\"$row\" | grep -qi 'secret' || fail_msg \"P14b: refusal must name secret-shaped content [$row]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 437, + "note": "" + }, + { + "file": "test-wake-preimage.sh", + "line": 438, + "form": "D-if-form", + "polarity": "AND", + "canary": true, + "text": "if grep -rq \"$hm\" \"$sd\" 2>/dev/null; then", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 438, + "note": "fail inside if-block" + }, + { + "file": "test-wake-preimage.sh", + "line": 491, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'REFUSING to re-baseline' || fail_msg \"P16: the failure must name the refusal [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 491, + "note": "" + }, + { + "file": "test-wake-preimage.sh", + "line": 523, + "form": "D-if-form", + "polarity": "AND", + "canary": true, + "text": "if grep -rq \"$s\" \"$sd\" 2>/dev/null; then", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 523, + "note": "fail inside if-block" + }, + { + "file": "test-wake-reconcile.sh", + "line": 90, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'COMPLETE' || fail_msg \"R1: a complete inventory must report COMPLETE [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 90, + "note": "" + }, + { + "file": "test-wake-reconcile.sh", + "line": 109, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'r2' || fail_msg \"R2: the flag must name the omitted source r2 [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 109, + "note": "" + }, + { + "file": "test-wake-reconcile.sh", + "line": 110, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'vacuous' || fail_msg \"R2: the flag must state the vacuous-pass is prevented [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 110, + "note": "" + }, + { + "file": "test-wake-reconcile.sh", + "line": 129, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi \"requires source 'r2'\" || fail_msg \"R3: the flag must name the required-but-omitted source r2 [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 129, + "note": "" + }, + { + "file": "test-wake-reconcile.sh", + "line": 147, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'dangling' || fail_msg \"R4: the flag must state it is dangling [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 147, + "note": "" + }, + { + "file": "test-wake-reconcile.sh", + "line": 176, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'UNACCOUNTED=2' || fail_msg \"R5: both pre-existing sources must be UNACCOUNTED [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 176, + "note": "" + }, + { + "file": "test-wake-reconcile.sh", + "line": 183, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out2\" | grep -qi 'UNACCOUNTED=0' || fail_msg \"R6: second reconcile must be 0 unaccounted [$out2]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 183, + "note": "" + }, + { + "file": "test-wake-reconcile.sh", + "line": 214, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'UNACCOUNTED=0' || fail_msg \"R7: inbox-reflected state must be 0 unaccounted [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 214, + "note": "" + }, + { + "file": "test-wake-reconcile.sh", + "line": 239, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'FAIL LOUD' || fail_msg \"R8: the source error must be loud [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 239, + "note": "" + }, + { + "file": "test-wake-reconcile.sh", + "line": 281, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'UNACCOUNTED=1' || fail_msg \"R9: only beta should be unaccounted (alpha is inbox-accounted) [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 281, + "note": "" + }, + { + "file": "test-wake-reconcile.sh", + "line": 295, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "ndistinct=\"$(\"$STORE\" drain | jq -r '.observed_seq' | sort -nu | grep -c .)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 295, + "note": "exit code discarded by substitution" + }, + { + "file": "test-wake-reconcile.sh", + "line": 296, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "ntotal=\"$(\"$STORE\" drain | jq -r '.observed_seq' | grep -c .)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 296, + "note": "exit code discarded by substitution" + }, + { + "file": "test-wake-reconcile.sh", + "line": 336, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'UNACCOUNTED=0' || fail_msg \"R10: a consumed state must be 0 unaccounted (no re-enumeration) [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 336, + "note": "" + }, + { + "file": "test-wake-reconcile.sh", + "line": 375, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -qi 'UNACCOUNTED=1' || fail_msg \"R11: exactly ONE source (the gap r2) must be unaccounted; the consumed r1 must be suppressed [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 375, + "note": "" + }, + { + "file": "test-wake-reconcile.sh", + "line": 386, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "echo \"wake ... harness: FAILED ($(grep -c . \\\"$FAILFILE\\\") assertion(s))\" >&2", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 386, + "note": "summary-count subclass (mos-dt derivation): exit discarded by substitution inside echo; FAILED (0 assertion(s)) under grep error reads as flake" + }, + { + "file": "test-wake-store-ack.sh", + "line": 99, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$cur\" | grep -q 'observed_seq=2' || fail_msg \"T1: observed_seq should be 2 after enqueue 1,2 [$cur]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 90, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 100, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$cur\" | grep -q 'consumed_seq=0' || fail_msg \"T1: consumed_seq must NOT advance on enqueue (only on CONSUMED ack) [$cur]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 91, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 101, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$cur\" | grep -q 'pending_depth=2' || fail_msg \"T1: pending depth should be 2 [$cur]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 92, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 105, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$cur\" | grep -q 'consumed_seq=2' || fail_msg \"T1: consumed_seq should be 2 after CONSUMED 2 [$cur]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 96, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 106, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$cur\" | grep -q 'pending_depth=0' || fail_msg \"T1: pending drained after CONSUMED [$cur]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 97, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 119, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "ndigest=\"$(printf '%s\\n' \"$out\" | jq -c 'select(.class==\"digest\")' | grep -c . || true)\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 110, + "note": "error swallowed by || true" + }, + { + "file": "test-wake-store-ack.sh", + "line": 123, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "nactionable=\"$(printf '%s\\n' \"$out\" | jq -c 'select(.class==\"actionable\")' | grep -c . || true)\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 114, + "note": "error swallowed by || true" + }, + { + "file": "test-wake-store-ack.sh", + "line": 124, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "nhuman=\"$(printf '%s\\n' \"$out\" | jq -c 'select(.class==\"human\")' | grep -c . || true)\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 115, + "note": "error swallowed by || true" + }, + { + "file": "test-wake-store-ack.sh", + "line": 128, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "total=\"$(printf '%s\\n' \"$out\" | grep -c . || true)\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 119, + "note": "error swallowed by || true" + }, + { + "file": "test-wake-store-ack.sh", + "line": 144, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$cur\" | grep -q 'consumed_seq=0' || fail_msg \"T3: rejected CONSUMED must NOT advance the cursor [$cur]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 135, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 153, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$cur\" | grep -q 'consumed_seq=3' || fail_msg \"T3: consumed_seq should be 3 after contiguous prefix filled [$cur]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 144, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 157, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$cur\" | grep -q 'consumed_seq=3' || fail_msg \"T3: cursor must not regress below 3 [$cur]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 148, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 172, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$cur\" | grep -q 'consumed_seq=0' || fail_msg \"T4: RECEIVED must not advance consumed_seq [$cur]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 163, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 192, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "printf '%s\\n' \"$drained\" | grep -q 999 && fail_msg \"T5: uncommitted garbage (seq 999) leaked into the live store\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 183, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 201, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "[ \"$(printf '%s\\n' \"$d2\" | grep -c .)\" = \"2\" ] || fail_msg \"T5: store not healthy after crash+recovery (expected 2 entries)\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 192, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 212, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "[ \"$(printf '%s\\n' \"$d3\" | grep -c .)\" = \"2\" ] || fail_msg \"T5: store not healthy after maintenance reap (expected 2 entries)\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 203, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 257, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "[ \"$(printf '%s\\n' \"$d\" | grep -c .)\" = \"2\" ] || fail_msg \"T6: entries not retained across restart (expected 2)\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 248, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 262, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "n2=\"$(printf '%s\\n' \"$d2\" | grep -c . || true)\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 253, + "note": "error swallowed by || true" + }, + { + "file": "test-wake-store-ack.sh", + "line": 299, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out\" | grep -q 'CONSUMED 1' || fail_msg \"T7: CONSUMED not reported [$out]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 290, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 324, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$cur\" | grep -q 'observed_seq=2' || fail_msg \"T8: observed_seq cursor should be 2 [$cur]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 315, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 325, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$cur\" | grep -q 'pending_depth=2' || fail_msg \"T8: both allocations must be durably enqueued [$cur]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 316, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 334, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -qi 'anti-swallow' || fail_msg \"T8: the refusal must name the anti-swallow guarantee [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 325, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 446, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$cur\" | grep -q 'observed_seq=2' || fail_msg \"T10: observed_seq must reach 2 after two enqueues [$cur]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 437, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 447, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$cur\" | grep -q 'pending_depth=2' || fail_msg \"T10: both entries must be durably stored (no lost write) [$cur]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 438, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 495, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -qi 'cursor' \"$errfile\" || fail_msg \"T11: the failure diagnostic must name the observed_seq cursor write [$(cat \"$errfile\")]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 486, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 539, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "\"$STORE\" cursors | grep -q 'consumed_seq=3' || fail_msg \"T12: consumed_seq must be 3 after CONSUMED 3\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 530, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 558, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -q 'quarantined seq(s): 2' || fail_msg \"T13: the refusal must NAME the quarantined seq [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 549, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 559, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$err\" | grep -q -- '--force-past-quarantine' || fail_msg \"T13: the refusal must NAME the force flag [$err]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 550, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 561, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$cur\" | grep -q 'consumed_seq=0' || fail_msg \"T13: a refused consume must NOT advance the cursor [$cur]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 552, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 569, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$cur\" | grep -q 'consumed_seq=1' || fail_msg \"T13: cursor must still be 1 after the refused ack [$cur]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 560, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 588, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q 'FORCED PAST QUARANTINE' \"$errf\" || fail_msg \"T14: the forced path must be LOUD on stderr [$(cat \"$errf\")]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 579, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 589, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q 'seq 2' \"$errf\" || fail_msg \"T14: the forced-path diagnostic must name the stepped-over seq 2 [$(cat \"$errf\")]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 580, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 590, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "\"$STORE\" cursors | grep -q 'consumed_seq=3' || fail_msg \"T14: forced consume must advance the cursor to 3\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 581, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 600, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "grep -qxF '2' \"$qf\" 2>/dev/null && fail_msg \"T14: seq 2 must be PRUNED from quarantined.set after the forced step-over\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 591, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 610, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$out2\" | grep -q '^CONSUMED 5$' || fail_msg \"T14: forced ack must report a CLEAN cursor line 'CONSUMED 5', got '$out2'\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 601, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 611, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q 'FORCED PAST QUARANTINE' \"$errf2\" || fail_msg \"T14: the forced-path loudness must survive the ack wrapper (stderr) [$(cat \"$errf2\")]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 602, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 674, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q 'FALSE WITNESS' \"$rep\" || fail_msg \"T16: the audit must name the false row loudly [$(cat \"$rep\")]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 665, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 675, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -q '\"id\":\"X\"' \"$rep\" || fail_msg \"T16: the audit must identify the false row (repo/X@1) [$(cat \"$rep\")]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 666, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 676, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "grep -q '\"id\":\"Y\"' \"$rep\" && fail_msg \"T16: the clean row repo/Y must NOT be flagged\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 667, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 677, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "grep -q '\"id\":\"Z\"' \"$rep\" && fail_msg \"T16: the HEALED row repo/Z@4 must NOT be flagged (its dead-letter evidence is seq 3 with a different hash)\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 668, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 686, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "[ \"$(grep -c . \"$dl\")\" = \"2\" ] || fail_msg \"T16: the dead-letter LEDGER must be untouched by --repair\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 677, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 689, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -qi 'OK' \"$TMP_ROOT/t16.ok\" || fail_msg \"T16: a clean audit must say OK [$(cat \"$TMP_ROOT/t16.ok\")]\"", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "", + "line_at_8d1d6e5": 680, + "note": "" + }, + { + "file": "test-wake-store-ack.sh", + "line": 738, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "echo \"wake store/ack harness: FAILED ($(grep -c . \"$FAILFILE\") assertion(s))\" >&2", + "origin": "frozen-8d1d6e5", + "drift": "moved", + "text_note": "frozen-text-normalized", + "line_at_8d1d6e5": 685, + "note": "summary-count subclass (mos-dt derivation): exit discarded by substitution inside echo; FAILED (0 assertion(s)) under grep error reads as flake" + }, + { + "file": "test-wake-store-enqueue-race.sh", + "line": 150, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "n_tmp=\"$(find \"$STATE_DIR\" -maxdepth 1 -name '.wake.tmp.*' -type f | grep -c . || true)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 150, + "note": "error swallowed by || true" + }, + { + "file": "test-wake-store-enqueue-race.sh", + "line": 176, + "form": "D-if-form", + "polarity": "AND", + "canary": false, + "text": "if grep -q 'durable pending write FAILED' \"$a_err\" 2>/dev/null; then", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 176, + "note": "fail inside if-block" + }, + { + "file": "test-wake-store-enqueue-race.sh", + "line": 192, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$cur\" | grep -q 'observed_seq=2' || fail_msg \"T-RACE: observed_seq must reach 2 (both allocations committed) [$cur]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 192, + "note": "" + }, + { + "file": "test-wake-store-enqueue-race.sh", + "line": 193, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$cur\" | grep -q 'pending_depth=2' || fail_msg \"T-RACE: both entries must be durably stored \u2014 no lost/aborted write [$cur]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 193, + "note": "" + }, + { + "file": "test-wake-store-enqueue-race.sh", + "line": 194, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "echo \"$cur\" | grep -q 'consumed_seq=0' || fail_msg \"T-RACE: enqueue must never advance consumed_seq [$cur]\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 194, + "note": "" + }, + { + "file": "test-wake-store-enqueue-race.sh", + "line": 198, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "n_leak=\"$(find \"$STATE_DIR\" -maxdepth 1 -name '.wake.tmp.*' -type f | grep -c . || true)\"", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 198, + "note": "error swallowed by || true" + }, + { + "file": "test-wake-store-enqueue-race.sh", + "line": 205, + "form": "E-count-capture", + "polarity": "COUNT", + "canary": false, + "text": "echo \"wake ... harness: FAILED ($(grep -c . \\\"$FAILFILE\\\") assertion(s))\" >&2", + "origin": "frozen-8d1d6e5", + "drift": "unchanged", + "text_note": "", + "line_at_8d1d6e5": 205, + "note": "summary-count subclass (mos-dt derivation): exit discarded by substitution inside echo; FAILED (0 assertion(s)) under grep error reads as flake" + }, + { + "file": "test-wake-store-ack.sh", + "line": 725, + "form": "A-same-line", + "polarity": "AND", + "canary": false, + "text": "grep -q 'FALSE WITNESS' \"$rep\" && fail_msg \"T17: the empty-hash evidence must NOT convict (the predicate is correct and must not change) [$(cat \"$rep\")]\"", + "origin": "introduced-47f8689-pr967-T17", + "drift": "new", + "line_at_8d1d6e5": null, + "note": "authored by pepper in #967 T17 while the charter was in flight; independently derived by both pepper and mos-dt" + }, + { + "file": "test-wake-store-ack.sh", + "line": 727, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -qi 'pruned' \"$rep\" || fail_msg \"T17: clean sweep must name residual class 1 \u2014 evidence pruned away [$(cat \"$rep\")]\"", + "origin": "introduced-47f8689-pr967-T17", + "drift": "new", + "line_at_8d1d6e5": null, + "note": "authored by pepper in #967 T17 while the charter was in flight; independently derived by both pepper and mos-dt" + }, + { + "file": "test-wake-store-ack.sh", + "line": 728, + "form": "A-same-line", + "polarity": "OR", + "canary": false, + "text": "grep -qi 'empty observed_hash' \"$rep\" || fail_msg \"T17: clean sweep must name residual class 2 \u2014 surviving evidence with an empty observed_hash [$(cat \"$rep\")]\"", + "origin": "introduced-47f8689-pr967-T17", + "drift": "new", + "line_at_8d1d6e5": null, + "note": "authored by pepper in #967 T17 while the charter was in flight; independently derived by both pepper and mos-dt" + }, + { + "file": "test-wake-store-ack.sh", + "line": 733, + "form": "E-count-capture", + "polarity": "OR", + "canary": false, + "text": "[ \"$(grep -c . \"$dl\")\" = \"1\" ] || fail_msg \"T17: the dead-letter LEDGER must be untouched\"", + "origin": "introduced-47f8689-pr967-T17", + "drift": "new", + "line_at_8d1d6e5": null, + "note": "authored by pepper in #967 T17 while the charter was in flight; independently derived by both pepper and mos-dt" + } + ] +} diff --git a/packages/mosaic/framework/tools/wake/validate-973/microtest-wake-assert.sh b/packages/mosaic/framework/tools/wake/validate-973/microtest-wake-assert.sh new file mode 100755 index 00000000..bec281ae --- /dev/null +++ b/packages/mosaic/framework/tools/wake/validate-973/microtest-wake-assert.sh @@ -0,0 +1,299 @@ +#!/usr/bin/env bash +# microtest-wake-assert.sh — #973 instrument self-test. Run BEFORE trusting any +# validate-run evidence: it proves the counted ledger and the abort mechanics on +# two generated mini-suites, so a defect in the instrument cannot silently wear +# the colour of a clean validation. +# +# What it proves (each check named C1..C8 below): +# C1 green run: ledger set EQUALS a text-derived expected set spanning TWO +# files (file-field discrimination), row count > 1, both sentinels emitted, +# exit 0. Also pins the BASH_LINENO convention for backslash-continuation +# call sites against the first-physical-line convention the denominator +# artifact uses. +# C2 early-exit truncation: a suite that exits before its later site yields a +# SHORT ledger, and the expected-set comparison catches it — a counted +# ledger must report its own truncation, never a smaller total. +# C3 abort from inside a `( ... )` test subshell kills the WHOLE suite: no +# sentinel, non-zero exit, loud named reason (file:line + raw rc). +# C4 abort stays loud at a call site that appends 2>/dev/null (the preimage +# canary shape) — the saved-fd path. +# C5 abort escapes a `$( count_lines ... )` substitution (A6 shape): the +# count from a failed measurement is never compared and the suite dies. +# C6 abort escapes a pipeline tail (`printf | has_match`). +# C7 count_lines prints 0 on grep rc 1 (zero matches is a measurement, not an +# error) — implicit in C1's green run via the delta-count site. +# C8 an env-prefix on the helper (`LC_ALL=C has_match ...`) reaches the grep +# child — pins the conversion shape for the digest-hmac LC_ALL site. +# C9 an arm that matches NO site is loud about it by omission: green run, +# sentinel present, and NO "WAKE-ASSERT ARMED" line — so "did not abort" +# is separable into arm-never-matched (no ARMED line) vs error-path- +# broken (ARMED line, no abort). C3..C6 require the ARMED line AND the +# aborting site's ledger row (append lands BEFORE the grep runs, so an +# abort can never shorten the count it is part of). +# C10 the BASH_LINENO pin's abort arm fires: under a probe interpreter that +# misreports the continuation line, wake_assert_init aborts loudly and +# nothing past init executes — a pin whose failure arm was never seen +# firing is an undertaking, not a control. +# C11 the FAILED-summary template executes on the red path: a mini-suite +# driven deterministically red emits the exact converted summary shape +# (`FAILED ($(count_lines . "$FAILFILE") assertion(s))`) with the right +# count, exits 1, and the summary site's ledger row lands. The nine +# real-suite summary sites are structurally unreachable in a green run +# (guarded by [ -s "$FAILFILE" ]); their dispositions cite THIS check as +# the measured execution of the same template, so "unexecuted in the +# green run" never silently means "never executed anywhere". +set -uo pipefail + +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +export WAKE_COMMON="$HERE/../_wake-common.sh" +[ -f "$WAKE_COMMON" ] || { + echo "microtest: _wake-common.sh not found at $WAKE_COMMON" >&2 + exit 1 +} + +TMP="$(mktemp -d)" +trap 'rm -rf "$TMP"' EXIT + +fails=0 +check() { # check NAME COND-DESCRIPTION (pass/fail already decided by caller: $1=name $2=0|1 $3=detail) + if [ "$2" -eq 0 ]; then + echo " PASS $1" + else + echo " FAIL $1 — $3" + fails=$((fails + 1)) + fi +} + +# --- fixture data ---------------------------------------------------------- +printf 'alpha\nbeta\nbeta\ngamma-unused\n' >"$TMP/data.txt" + +# --- mini-suite A: six helper sites across every converted form ------------ +cat >"$TMP/mini-a.sh" <<'MINI_A' +#!/usr/bin/env bash +set -uo pipefail +. "$WAKE_COMMON" +wake_assert_init +TMP="$1" +FAILFILE="$TMP/failures-a" +: >"$FAILFILE" +fail_msg() { echo " FAIL: $*" >&2; echo x >>"$FAILFILE"; } +ok() { :; } +( + has_match -q alpha "$TMP/data.txt" || fail_msg "alpha missing" # SITE:or-subshell +) && ok +( + has_match -q FORBIDDEN "$TMP/data.txt" 2>/dev/null && fail_msg "forbidden present" # SITE:and-swallow +) && ok +( + [ "$(count_lines beta "$TMP/data.txt")" = "2" ] || fail_msg "beta count" # SITE:count-capture +) && ok +( + printf 'gamma\n' | has_match -q gamma || fail_msg "gamma pipeline" # SITE:pipeline +) && ok +( + has_match -q \ + alpha "$TMP/data.txt" || fail_msg "continuation" # SITE:continuation +) && ok +( + [ "$(count_lines delta "$TMP/data.txt")" = "0" ] || fail_msg "delta zero" # SITE:count-zero +) && ok +if [ -s "$FAILFILE" ]; then + echo "mini-a: FAILED" >&2 + exit 1 +fi +echo "mini-a: OK" >&2 +MINI_A + +# --- mini-suite B: second file, one site behind an early exit -------------- +cat >"$TMP/mini-b.sh" <<'MINI_B' +#!/usr/bin/env bash +set -uo pipefail +. "$WAKE_COMMON" +wake_assert_init +TMP="$1" +( + has_match -q alpha "$TMP/data.txt" || echo "b1 missing" >&2 # SITE:b-first +) +if [ "${MINI_B_EARLY_EXIT:-}" = "1" ]; then + exit 0 +fi +( + has_match -q beta "$TMP/data.txt" || echo "b2 missing" >&2 # SITE:b-second +) +echo "mini-b: OK" >&2 +MINI_B +chmod +x "$TMP/mini-a.sh" "$TMP/mini-b.sh" + +# Text-derived expected set: helper-name + basename:line for every SITE-marked +# call, taken from the generated files' TEXT (independent of BASH_LINENO), with +# the continuation site expected at its FIRST physical line — the denominator +# artifact's convention. +expected_set() { # expected_set FILE + local f="$1" base + base="$(basename "$f")" + awk ' + /# SITE:/ { + line = NR + if ($0 !~ /has_match|count_lines/) line = NR - 1 # marker on the continuation tail + print line + } + ' "$f" | while read -r ln; do + txt="$(sed -n "${ln}p" "$f")" + case "$txt" in + *count_lines*) printf 'count_lines %s:%s\n' "$base" "$ln" ;; + *) printf 'has_match %s:%s\n' "$base" "$ln" ;; + esac + done +} + +site_line() { # site_line FILE MARKER -> first physical line of that call + local f="$1" marker="$2" ln + ln="$(grep -n "# SITE:${marker}\$" "$f" | cut -d: -f1)" + # continuation marker sits on the tail line; the call starts one line up + if ! sed -n "${ln}p" "$f" | grep -Eq 'has_match|count_lines'; then + ln=$((ln - 1)) + fi + printf '%s' "$ln" +} + +# --- C1: green run, two files, set equality -------------------------------- +LEDGER="$TMP/ledger-c1" +: >"$LEDGER" +outA="$(WAKE_ASSERT_LEDGER="$LEDGER" bash "$TMP/mini-a.sh" "$TMP" 2>&1)" +rcA=$? +outB="$(WAKE_ASSERT_LEDGER="$LEDGER" bash "$TMP/mini-b.sh" "$TMP" 2>&1)" +rcB=$? +{ expected_set "$TMP/mini-a.sh"; expected_set "$TMP/mini-b.sh"; } | sort >"$TMP/expected-c1" +sort "$LEDGER" >"$TMP/got-c1" +n_expected="$(grep -c . "$TMP/expected-c1")" +if [ "$rcA" -eq 0 ] && [ "$rcB" -eq 0 ] && + printf '%s' "$outA" | grep -q 'mini-a: OK' && + printf '%s' "$outB" | grep -q 'mini-b: OK' && + [ "$n_expected" -gt 1 ] && + cmp -s "$TMP/expected-c1" "$TMP/got-c1"; then + check C1 0 "" +else + check C1 1 "rcA=$rcA rcB=$rcB expected($n_expected)/got diff: $(diff "$TMP/expected-c1" "$TMP/got-c1" 2>&1 | head -n 10 | tr '\n' ' ')" +fi + +# --- C2: early exit -> short ledger, comparison catches it ----------------- +LEDGER="$TMP/ledger-c2" +: >"$LEDGER" +WAKE_ASSERT_LEDGER="$LEDGER" MINI_B_EARLY_EXIT=1 bash "$TMP/mini-b.sh" "$TMP" >/dev/null 2>&1 +expected_set "$TMP/mini-b.sh" | sort >"$TMP/expected-c2" +sort "$LEDGER" >"$TMP/got-c2" +if ! cmp -s "$TMP/expected-c2" "$TMP/got-c2" && + grep -q "has_match mini-b.sh:$(site_line "$TMP/mini-b.sh" b-first)" "$TMP/got-c2" && + ! grep -q "mini-b.sh:$(site_line "$TMP/mini-b.sh" b-second)" "$TMP/got-c2"; then + check C2 0 "" +else + check C2 1 "truncated ledger was not detected as short" +fi + +# --- C3..C6: per-shape abort proofs ---------------------------------------- +abort_case() { # abort_case NAME MARKER HELPER + local name="$1" marker="$2" helper="$3" ln site out rc ledger + ln="$(site_line "$TMP/mini-a.sh" "$marker")" + site="mini-a.sh:${ln}" + ledger="$TMP/ledger-${name}" + : >"$ledger" + out="$(WAKE_ASSERT_LEDGER="$ledger" WAKE_ASSERT_FORCE_GREP_ERROR_AT="$site" \ + bash "$TMP/mini-a.sh" "$TMP" 2>&1)" + rc=$? + if [ "$rc" -ne 0 ] && + ! printf '%s' "$out" | grep -q 'mini-a: OK' && + ! printf '%s' "$out" | grep -q 'mini-a: FAILED' && + printf '%s' "$out" | grep -q "WAKE-ASSERT ARMED: forcing real grep error at $site" && + printf '%s' "$out" | grep -q "WAKE-ASSERT ABORT" && + printf '%s' "$out" | grep -q "$site" && + printf '%s' "$out" | grep -q "grep exit 2" && + grep -q "^${helper} ${site}\$" "$ledger"; then + check "$name" 0 "" + else + check "$name" 1 "rc=$rc site=$site ledger=$(grep -c . "$ledger") out=$(printf '%s' "$out" | tail -n 3 | tr '\n' ' ')" + fi +} +abort_case C3 or-subshell has_match +abort_case C4 and-swallow has_match +abort_case C5 count-capture count_lines +abort_case C6 pipeline has_match + +# --- C7: covered by C1 (delta-count site prints 0 on grep rc 1) ------------ +check C7 0 "" + +# --- C8: env-prefix on a function reaches the grep child ------------------- +envprobe() { command env | command grep -c '^LC_ALL=xx_wake_test$'; } +got="$(LC_ALL=xx_wake_test envprobe 2>/dev/null)" # bash's setlocale warning about the fake locale is itself proof the prefix landed +if [ "$got" = "1" ]; then check C8 0 ""; else check C8 1 "env-prefix did not reach child (got=$got)"; fi + +# --- C9: arm matching NO site -> green run, no ARMED line ------------------ +out="$(WAKE_ASSERT_FORCE_GREP_ERROR_AT="mini-a.sh:9999" bash "$TMP/mini-a.sh" "$TMP" 2>&1)" +rc=$? +if [ "$rc" -eq 0 ] && + printf '%s' "$out" | grep -q 'mini-a: OK' && + ! printf '%s' "$out" | grep -q 'WAKE-ASSERT ARMED'; then + check C9 0 "" +else + check C9 1 "rc=$rc out=$(printf '%s' "$out" | tail -n 3 | tr '\n' ' ')" +fi + +# --- C10: lineno pin aborts under an interpreter that breaks the convention - +cat >"$TMP/fake-bash" <<'FAKE' +#!/usr/bin/env bash +# stand-in for a bash whose BASH_LINENO convention differs: misreports the +# continuation call one line low (the exact skew the pin exists to catch) +printf '3\n5\n' +FAKE +chmod +x "$TMP/fake-bash" +out="$(WAKE_ASSERT_PIN_BASH="$TMP/fake-bash" bash -c '. "$WAKE_COMMON" && wake_assert_init && echo REACHED-PAST-INIT' 2>&1)" +rc=$? +if [ "$rc" -ne 0 ] && + ! printf '%s' "$out" | grep -q 'REACHED-PAST-INIT' && + printf '%s' "$out" | grep -q 'WAKE-ASSERT INIT ABORT: BASH_LINENO convention violated'; then + check C10 0 "" +else + check C10 1 "rc=$rc out=$(printf '%s' "$out" | tail -n 2 | tr '\n' ' ')" +fi + +# --- C11: red path executes the converted FAILED-summary template ----------- +cat >"$TMP/mini-c.sh" <<'MINI_C' +#!/usr/bin/env bash +set -uo pipefail +. "$WAKE_COMMON" +wake_assert_init +TMP="$1" +FAILFILE="$TMP/failures-c" +: >"$FAILFILE" +fail_msg() { echo " FAIL: $*" >&2; echo x >>"$FAILFILE"; } +ok() { :; } +( + has_match -q alpha "$TMP/data.txt" && fail_msg "alpha present" # SITE:c-inverted (deterministically red: alpha IS in the fixture) +) && ok +echo +if [ -s "$FAILFILE" ]; then + echo "wake mini-c harness: FAILED ($(count_lines . "$FAILFILE") assertion(s))" >&2 # SITE:c-summary + exit 1 +fi +echo "wake mini-c harness: all invariants passed (1 group)" +MINI_C +chmod +x "$TMP/mini-c.sh" +LEDGER="$TMP/ledger-c11" +: >"$LEDGER" +out="$(WAKE_ASSERT_LEDGER="$LEDGER" bash "$TMP/mini-c.sh" "$TMP" 2>&1)" +rc=$? +summary_ln="$(site_line "$TMP/mini-c.sh" c-summary)" +if [ "$rc" -eq 1 ] && + printf '%s' "$out" | grep -q 'wake mini-c harness: FAILED (1 assertion(s))' && + ! printf '%s' "$out" | grep -q 'all invariants passed' && + grep -q "^count_lines mini-c.sh:${summary_ln}\$" "$LEDGER"; then + check C11 0 "" +else + check C11 1 "rc=$rc summary_ln=$summary_ln ledger=$(tr '\n' ' ' <"$LEDGER") out=$(printf '%s' "$out" | tail -n 2 | tr '\n' ' ')" +fi + +echo +if [ "$fails" -gt 0 ]; then + echo "microtest-wake-assert: FAILED ($fails check(s))" >&2 + exit 1 +fi +echo "microtest-wake-assert: OK (all checks passed)" diff --git a/packages/mosaic/framework/tools/wake/validate-973/unexecuted-sites-dispositions.txt b/packages/mosaic/framework/tools/wake/validate-973/unexecuted-sites-dispositions.txt new file mode 100644 index 00000000..c2a0ba0b --- /dev/null +++ b/packages/mosaic/framework/tools/wake/validate-973/unexecuted-sites-dispositions.txt @@ -0,0 +1,37 @@ +# unexecuted-sites-dispositions.txt — #973 validation, amendment ONE leg 3. +# +# The ledger is an execution trace, not an inventory: a green instrumented run +# cannot execute a site that only lives on a suite's red path. Every converted +# site that did NOT appear in the green-run trace is enumerated here with an +# individual disposition; validate-973.sh fails if any unexecuted site lacks a +# row here, and ALSO fails if a row here names a site that DID execute (stale +# disposition). Key = first two whitespace-separated fields; text after "—" is +# the adjudication. +# +# All nine sites below are the same structural shape, adjudicated one by one +# from source text: the suite's FAILED-branch summary line, +# echo "wake harness: FAILED ($(count_lines . "$FAILFILE") assertion(s))" >&2 +# guarded by `if [ -s "$FAILFILE" ]` — structurally unreachable while every +# assertion passes, which is precisely the state a green validation run is +# required to be in. (The tenth suite, test-wake-preimage.sh, uses its own +# X/Y summary format with no grep in the red branch, so it has no row here.) +# +# The disposition is NOT "it would work": the exact template is EXECUTED red +# in microtest C11 (deterministically failed mini-suite, same +# count_lines-in-substitution summary shape → right count, exit 1, ledger row +# at the summary coordinate), and the E-in-substitution abort path is proven +# by microtest C5 plus the forced-error arm at test-wake-store-ack.sh:736. +# Each site's conversion text is independently verified by the static +# inventory (check-973.py static == expected, all 261 rows). +# +# Verified guard per site (line numbers at branch tip, +3 header shift): + +count_lines test-wake-beacon.sh:350 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 349; template execution measured by microtest C11; text verified by static inventory +count_lines test-wake-detector.sh:702 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 701; template execution measured by microtest C11; text verified by static inventory +count_lines test-wake-digest-hmac.sh:434 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 433; template execution measured by microtest C11; text verified by static inventory +count_lines test-wake-digest-quarantine.sh:584 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 583; template execution measured by microtest C11; text verified by static inventory +count_lines test-wake-fn-oracle.sh:132 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 131; template execution measured by microtest C11; text verified by static inventory +count_lines test-wake-install.sh:434 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 433; template execution measured by microtest C11; text verified by static inventory +count_lines test-wake-reconcile.sh:389 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 388; template execution measured by microtest C11; text verified by static inventory +count_lines test-wake-store-ack.sh:741 — red-path summary; guard `[ -s "$FAILFILE" ]` at line 740; template execution measured by microtest C11; text verified by static inventory +count_lines test-wake-store-enqueue-race.sh:208 — red-path summary (with "#927 TOCTOU reproduced (RED)" tail); guard `[ -s "$FAILFILE" ]` at line 207; template execution measured by microtest C11; text verified by static inventory diff --git a/packages/mosaic/framework/tools/wake/validate-973/validate-973.sh b/packages/mosaic/framework/tools/wake/validate-973/validate-973.sh new file mode 100755 index 00000000..f6e473e7 --- /dev/null +++ b/packages/mosaic/framework/tools/wake/validate-973/validate-973.sh @@ -0,0 +1,210 @@ +#!/usr/bin/env bash +# validate-973.sh — #973 validation driver. One run produces the complete +# evidence chain for the 261-site conversion: +# +# 0. instrument self-test (microtest) — no validate evidence is trusted +# before the instrument itself has been proven, including its abort arms. +# 1. expected set: 261 coordinates from the FROZEN artifact (+3 header +# shift), count asserted against the number declared below BEFORE any +# suite runs. +# 2. static inventory: converted call sites re-derived from SOURCE TEXT, +# must equal the expected set exactly (amendment ONE, leg 1 — the +# inventory comes from the text, never from the ledger). +# 3. green instrumented run: all ten suites with WAKE_ASSERT_LEDGER; each +# must exit 0 AND emit its own sentinel (per-suite formats differ and are +# pinned here — a suite that died early must never pass on another +# suite's output). +# 4. trace arithmetic on coordinate SETS (loops re-execute sites and the +# multi-grep lines append twice per pass, so counts are meaningless; +# sets are not): +# trace − expected MUST be empty (a helper ran at a coordinate the +# denominator never measured); +# expected − trace = converted-but-never-executed: enumerated, and +# every entry must carry a disposition in the +# committed unexecuted-sites-dispositions.txt, with +# no stale dispositions the other way (amendment +# ONE, legs 2+3 — the ledger is an execution trace, +# not an inventory; the difference is enumerated and +# individually dispositioned, never silently absent). +# 5. forced-error arms: the 19 denominator canaries plus one E-form and one +# F-form site, each run with WAKE_ASSERT_FORCE_GREP_ERROR_AT: the suite +# must emit the ARMED line (the arm proved it fired), the ABORT line +# naming the site, exit non-zero, emit NO sentinel, and the aborting +# site's ledger row must already be present (the append lands before the +# grep). +# 6. residual sweep: the denominator's own classifier finds zero unconverted +# verdict greps in the suites — and six per-form plants in the same run. +# +# Output discipline (A10): every line that reports on a suite names the file +# under test; exit codes are reported before failure counts. +set -uo pipefail + +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +WAKE="$(cd "$HERE/.." && pwd)" +CHECK="$HERE/check-973.py" +DISPO="$HERE/unexecuted-sites-dispositions.txt" +TMP="$(mktemp -d)" +trap 'rm -rf "$TMP"' EXIT + +# Declared BEFORE any suite runs (A2): the run must produce THESE numbers, +# not be described by whatever numbers it produced. +EXPECTED_SUITES=10 +EXPECTED_SITES=261 +EXPECTED_ARMS=21 + +fails=0 +flag() { + printf 'FAIL %s\n' "$*" + fails=$((fails + 1)) +} + +SUITES=( + test-wake-beacon.sh + test-wake-detector.sh + test-wake-digest-hmac.sh + test-wake-digest-quarantine.sh + test-wake-fn-oracle.sh + test-wake-install.sh + test-wake-preimage.sh + test-wake-reconcile.sh + test-wake-store-ack.sh + test-wake-store-enqueue-race.sh +) +[ "${#SUITES[@]}" -eq "$EXPECTED_SUITES" ] || + flag "suite list has ${#SUITES[@]} entries, declared $EXPECTED_SUITES" + +# Per-suite sentinel patterns, pinned: nine suites share the harness template +# (enqueue-race appends a tail after it); preimage uses its own format. +sentinel_for() { + case "$1" in + test-wake-preimage.sh) printf '%s' '^== test-wake-preimage: 17/17 passed ==$' ;; + *) printf '%s' 'harness: all invariants passed' ;; + esac +} + +# --- 0: instrument self-test ------------------------------------------------ +if bash "$HERE/microtest-wake-assert.sh" >"$TMP/microtest.out" 2>&1; then + echo "MICROTEST microtest-wake-assert.sh exit=0 (instrument proven)" +else + rc=$? + echo "MICROTEST microtest-wake-assert.sh exit=$rc" + sed 's/^/ /' "$TMP/microtest.out" | tail -n 15 + flag "instrument self-test failed — no validate evidence below is trustworthy" +fi + +# --- 1+2: expected set (artifact) vs static inventory (source text) --------- +python3 "$CHECK" expected | sort >"$TMP/expected.txt" || + flag "check-973.py expected failed" +n_expected="$(grep -c . "$TMP/expected.txt")" +echo "EXPECTED-SET $n_expected coordinates (declared: $EXPECTED_SITES)" +[ "$n_expected" -eq "$EXPECTED_SITES" ] || + flag "expected set has $n_expected coordinates, declared $EXPECTED_SITES" + +python3 "$CHECK" static | sort >"$TMP/static.txt" || + flag "check-973.py static failed" +if cmp -s "$TMP/expected.txt" "$TMP/static.txt"; then + echo "STATIC-INVENTORY equals expected set ($(grep -c . "$TMP/static.txt") rows from source text)" +else + flag "static inventory (source text) differs from expected set (artifact):" + diff "$TMP/expected.txt" "$TMP/static.txt" | head -n 20 | sed 's/^/ /' +fi + +# --- 3: green instrumented run ---------------------------------------------- +LEDGER="$TMP/ledger" +: >"$LEDGER" +for s in "${SUITES[@]}"; do + out="$(WAKE_ASSERT_LEDGER="$LEDGER" bash "$WAKE/$s" 2>&1)" + rc=$? + if printf '%s\n' "$out" | grep -Eq "$(sentinel_for "$s")"; then + sent="present" + else + sent="ABSENT" + fi + echo "SUITE $s exit=$rc sentinel=$sent" + [ "$rc" -eq 0 ] || flag "$s exited $rc in the green instrumented run" + [ "$sent" = "present" ] || flag "$s did not emit its sentinel" +done + +# --- 4: trace arithmetic on coordinate sets --------------------------------- +sort -u "$LEDGER" >"$TMP/trace.txt" +echo "TRACE $(grep -c . "$TMP/trace.txt") distinct coordinates from $(grep -c . "$LEDGER") ledger rows" + +comm -13 "$TMP/expected.txt" "$TMP/trace.txt" >"$TMP/rogue.txt" +if [ -s "$TMP/rogue.txt" ]; then + flag "trace contains coordinates OUTSIDE the frozen denominator:" + sed 's/^/ ROGUE /' "$TMP/rogue.txt" +else + echo "TRACE-MINUS-EXPECTED empty (no helper ran at an unmeasured coordinate)" +fi + +comm -23 "$TMP/expected.txt" "$TMP/trace.txt" >"$TMP/unexec.txt" +n_unexec="$(grep -c . "$TMP/unexec.txt" || true)" +echo "UNEXECUTED $n_unexec of $EXPECTED_SITES converted sites did not execute in the green run" +if [ ! -f "$DISPO" ]; then + flag "disposition file missing: $DISPO — every unexecuted site must be individually dispositioned" + sed 's/^/ UNDISPOSITIONED /' "$TMP/unexec.txt" +else + awk '!/^#/ && NF >= 2 {print $1, $2}' "$DISPO" | sort -u >"$TMP/dispo-keys.txt" + comm -23 "$TMP/unexec.txt" "$TMP/dispo-keys.txt" >"$TMP/undispo.txt" + comm -13 "$TMP/unexec.txt" "$TMP/dispo-keys.txt" >"$TMP/stale-dispo.txt" + if [ -s "$TMP/undispo.txt" ]; then + flag "unexecuted sites WITHOUT a disposition:" + sed 's/^/ UNDISPOSITIONED /' "$TMP/undispo.txt" + fi + if [ -s "$TMP/stale-dispo.txt" ]; then + flag "dispositions for sites that DID execute (stale — the file no longer matches the run):" + sed 's/^/ STALE-DISPO /' "$TMP/stale-dispo.txt" + fi + if [ ! -s "$TMP/undispo.txt" ] && [ ! -s "$TMP/stale-dispo.txt" ]; then + echo "DISPOSITIONS all $n_unexec unexecuted sites individually dispositioned, none stale" + fi +fi + +# --- 5: forced-error arms --------------------------------------------------- +python3 "$CHECK" arms >"$TMP/arms.txt" || flag "check-973.py arms failed" +n_arms="$(grep -c . "$TMP/arms.txt")" +echo "ARMS $n_arms forced-error arms (declared: $EXPECTED_ARMS)" +[ "$n_arms" -eq "$EXPECTED_ARMS" ] || + flag "arm list has $n_arms entries, declared $EXPECTED_ARMS" + +while read -r helper site form; do + f="${site%%:*}" + aled="$TMP/ledger-arm" + : >"$aled" + out="$(WAKE_ASSERT_LEDGER="$aled" WAKE_ASSERT_FORCE_GREP_ERROR_AT="$site" \ + bash "$WAKE/$f" 2>&1)" + rc=$? + bad="" + [ "$rc" -ne 0 ] || bad="$bad exit=0" + printf '%s\n' "$out" | grep -q "WAKE-ASSERT ARMED: forcing real grep error at $site" || + bad="$bad no-ARMED-line" + printf '%s\n' "$out" | grep -q "WAKE-ASSERT ABORT: ${helper} at ${site}: grep exit" || + bad="$bad no-ABORT-line" + printf '%s\n' "$out" | grep -Eq "$(sentinel_for "$f")" && + bad="$bad sentinel-emitted" + grep -q "^${helper} ${site}\$" "$aled" || + bad="$bad no-ledger-row" + if [ -z "$bad" ]; then + echo "ARM $site ($form) exit=$rc armed+abort+no-sentinel+ledger-row" + else + echo "ARM $site ($form) exit=$rc DEFECTS:$bad" + flag "arm $site ($form) failed:$bad" + fi +done <"$TMP/arms.txt" + +# --- 6: residual sweep ------------------------------------------------------ +if python3 "$CHECK" sweep >"$TMP/sweep.out" 2>&1; then + echo "SWEEP exit=0" +else + echo "SWEEP exit=$?" + flag "residual sweep failed" +fi +sed 's/^/ /' "$TMP/sweep.out" + +# --- summary (exit codes above, failure count last — A10) -------------------- +echo +if [ "$fails" -gt 0 ]; then + echo "validate-973: FAILED ($fails failure(s))" >&2 + exit 1 +fi +echo "validate-973: OK — $EXPECTED_SUITES suites, $EXPECTED_SITES sites, $EXPECTED_ARMS arms, sweep clean"