Files
stack/packages/mosaic/framework/tools/wake/test-wake-fn-oracle.sh
T
Jason WoltjeandClaude Fable 5 5020c41749
ci/woodpecker/pr/ci Pipeline was successful
fix(wake): #984 fatal source guard + #985 absorb re-scan — #973 follow-up batch
Four changes, one coordinate shift:

1. #984: the ten suites sourced _wake-common.sh with `. file && wake_assert_init`
   under no set -e — a failed source left every helper undefined, every
   AND-polarity canary silently green, and the suite exiting 0 having run ZERO
   wake assertions. The source is now guarded alone in an explicit block that
   echoes a wake-authored diagnostic to real stderr and exits 97; init runs on
   its own line. Negative test: a copied suite without _wake-common.sh exits 97
   with the diagnostic.

2. #985: the sweep absorb branch keyed on helper-token presence alone, so a
   converted line that ALSO ran a raw grep verdict (has_match ... && grep -q
   SECRET ... && fail) was absorbed as benign. The absorb decision now re-scans
   the line remainder for grep in command position (RX_GREP_CMD, quote-unaware
   by design — errs toward loud), and is factored into residual_sites(), the
   ONE path both sweep legs share: leg 2 previously used raw classify() and
   never exercised the absorb branch at all. Plants G (helper+raw-grep, must
   stay residual) and H (grep only in pattern argument, must absorb as note)
   prove both directions; SWEEP-PLANTS is now 8/8.

3. validate-973.sh arms loop: the sentinel check was the one AND-polarity grep
   in the file — a grep error (rc>=2) read as "no sentinel" and passed toward
   green. Converted to the three-valued idiom with its own loud error arm.

4. Dead polarity() deleted from check-973.py (unreferenced since the frozen
   derivation was ported).

The #984 guard is +4 lines uniformly above every site in all ten suites, so
HEADER_SHIFT moves 3 -> 7 and the nine disposition rows shift +4; the frozen
artifact is untouched. Verified: expected==static (261 rows), full
validate-973.sh terminal-green (10 suites, 21 arms at shifted coordinates,
dispositions none-stale, sweep clean 8/8).

Written-by: pepper (sb-it-1-dt)
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NsKce8iZuSuRnu3gVMCBKB
2026-07-31 04:42:37 -05:00

140 lines
6.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# test-wake-fn-oracle.sh — RED-FIRST invariant harness for W5 (EPIC #892):
# the FN-oracle / synthetic-canary (fn-oracle.sh, A6).
#
# Each test asserts ONE CONVERGED-DESIGN invariant and is designed to go RED if
# that invariant regresses:
# O1 healthy pipeline -> synthetic-canary FN-rate = 0 (PASS, exit 0) (§4 vector)
# O2 a DISABLED / dropping detector (perfect no-op rate) -> FN-DETECTED —
# the off-domain false-negative-blindspot killer: a detector that silently
# drops a KNOWN injected delta FAILS the oracle even at 0 wakes/day (§4/A8)
# O3 reached-CONSUMED-but-too-slow -> FN-DETECTED (the "within its per-class
# SLO" clause; a late delivery is still a false negative) (§4)
# O4 the verdict is OFF-DOMAIN: it is rendered from the terminal store cursor
# (consumed_seq), independent of any detector self-report (§4/A8)
# O5 no invented SLO: --slo-seconds is REQUIRED (fail-loud usage guard) (design law)
#
# Uses the oracle's OWN isolated state namespace + a pluggable drive command
# (WAKE_ORACLE_DETECTOR_CMD) so a disabled detector can be exercised. No live
# network, no operator queue touched.
#
# SC2030/SC2031 are DELIBERATELY disabled: each test runs in its own ( ) subshell
# and re-exports the per-test env, so environments are isolated by design (the
# same idiom as test-wake-detector.sh).
# shellcheck disable=SC2030,SC2031
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
if ! . "$SCRIPT_DIR/_wake-common.sh"; then
echo "WAKE-ASSERT INIT ABORT: cannot source _wake-common.sh — suite ran ZERO wake assertions (#984)" >&2
exit 97
fi
wake_assert_init
ORACLE="$SCRIPT_DIR/fn-oracle.sh"
DET="$SCRIPT_DIR/detector.sh"
command -v jq >/dev/null 2>&1 || {
echo "SKIP: jq not available" >&2
exit 0
}
TMP_ROOT="$(mktemp -d)"
trap 'rm -rf "$TMP_ROOT"' EXIT
# Failures recorded to a FILE (subshell-safe — a var counter would silently
# swallow failures across the per-test subshells; mirrors the W2/W4 harnesses).
FAILFILE="$TMP_ROOT/failures"
: >"$FAILFILE"
pass=0
fail_msg() {
echo " FAIL: $*" >&2
echo "x" >>"$FAILFILE"
}
ok() { pass=$((pass + 1)); }
fresh_home() {
local d="$TMP_ROOT/$1"
rm -rf "$d"
mkdir -p "$d"
printf '%s' "$d"
}
echo "== O1: healthy pipeline -> synthetic-canary FN-rate = 0 =="
(
WAKE_ORACLE_HOME="$(fresh_home o1)"
export WAKE_ORACLE_HOME
unset WAKE_ORACLE_DETECTOR_CMD
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" | 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) =="
(
WAKE_ORACLE_HOME="$(fresh_home o2)"
export WAKE_ORACLE_HOME
# A fully-disabled detector: it observes nothing, enqueues nothing — a
# "perfect" 0-wake rate that would look ideal on the wakes/day metric alone.
export WAKE_ORACLE_DETECTOR_CMD="true"
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" | 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) =="
(
WAKE_ORACLE_HOME="$(fresh_home o3)"
export WAKE_ORACLE_HOME
# The REAL detector delivers the canary, but a delay pushes event->CONSUMED
# past a tight per-class SLO. A late delivery is still a false negative.
export WAKE_ORACLE_DETECTOR_CMD="sleep 2 && '$DET' poll-once"
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" | 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" | has_match -qi 'never OBSERVED'; then
fail_msg "O3: an SLO breach must NOT be misreported as a dropped delta [$out]"
fi
) && ok
echo "== O4: verdict is OFF-DOMAIN (from terminal consumed_seq, not detector self-report) =="
(
WAKE_ORACLE_HOME="$(fresh_home o4)"
export WAKE_ORACLE_HOME
# A drive that LIES 'success' (exit 0) but enqueues nothing. If the oracle
# trusted the drive's exit code it would pass; because it judges only the
# terminal store state, it correctly reports FN-DETECTED.
export WAKE_ORACLE_DETECTOR_CMD="exit 0"
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" | 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) =="
(
WAKE_ORACLE_HOME="$(fresh_home o5)"
export WAKE_ORACLE_HOME
unset WAKE_ORACLE_DETECTOR_CMD WAKE_ORACLE_SLO_SECONDS
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" | 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 ($(count_lines . "$FAILFILE") assertion(s))" >&2
exit 1
fi
echo "wake fn-oracle harness: all invariants passed ($pass groups)"