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

This commit was merged in pull request #983.
This commit is contained in:
Mos
2026-07-31 08:39:04 +00:00
parent 089615f63b
commit 4fb44f6345
18 changed files with 4855 additions and 262 deletions
@@ -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)"