fix(wake): #924 route dead-letter quarantine alarm via WAKE_ALARM_SINK_CMD with per-observed_seq dedup (G2a) (#929)
Co-authored-by: jason.woltje <jason@diversecanvas.com> Co-committed-by: jason.woltje <jason@diversecanvas.com>
This commit was merged in pull request #929.
This commit is contained in:
@@ -26,6 +26,33 @@
|
||||
# `claim` (a consequential fact) with no hard locator is STILL gated
|
||||
# (quarantined), and the reconciled exemption does not leak to it. (§2.1)
|
||||
#
|
||||
# #924 (G2a fix — the #920 alarm was stderr/journal-LOCAL only, a permanent
|
||||
# silent-miss hazard since a dead-lettered entry is store-accounted and the
|
||||
# reconciler never re-flags it): the SAME per-entry alarm now ALSO routes
|
||||
# off-host via WAKE_ALARM_SINK_CMD (beacon.sh's W6/#910 pluggable adapter,
|
||||
# REUSED verbatim), deduped by observed_seq (the entry's durable identity).
|
||||
# Q6 (a) ONE off-host alarm + stderr diagnostic STILL fires: a dead-lettered
|
||||
# entry routes EXACTLY ONE alarm to a captured WAKE_ALARM_SINK_CMD
|
||||
# (payload names observed_seq), AND the #920 stderr diagnostic still
|
||||
# fires (local + off-host, never either/or).
|
||||
# Q7 (b) RE-DRAIN DEDUP: re-draining the SAME still-dead-lettered entry N
|
||||
# times routes ZERO additional off-host alarms (durable dedup by
|
||||
# observed_seq survives across separate digest.sh invocations, i.e.
|
||||
# across drains/restarts, since each invocation is a fresh process).
|
||||
# Q8 (c) NEW ENTRY OWN ALARM: a NEW distinct dead-lettered entry (a new
|
||||
# observed_seq) routes its OWN one alarm — dedup is per-entry, not a
|
||||
# global "alarm already fired at all" latch.
|
||||
# Q9 (d) FAIL-CLOSED: WAKE_ALARM_SINK_CMD unconfigured OR unreachable (exit
|
||||
# non-zero) is a LOUD stderr diagnostic (mirrors beacon.sh's
|
||||
# fail-closed wording) — never a silent no-alarm host. Per-entry, not
|
||||
# whole-drain: render still exits 0 (#920's no-head-of-line-block
|
||||
# property is preserved even when the off-host leg itself fails).
|
||||
#
|
||||
# RED-FIRST: Q6-Q9 all go RED against the pre-#924 (stderr-only) digest.sh —
|
||||
# it never references WAKE_ALARM_SINK_CMD at all, so no payload is EVER routed
|
||||
# (Q6/Q7/Q8 all see 0 captured alarms) and no "FAIL LOUD ... alarm sink"
|
||||
# diagnostic exists to fire (Q9).
|
||||
#
|
||||
# Hermetic: feeds controlled JSONL via `digest.sh render --from-file` — NO store,
|
||||
# NO network, NO openssl (so it runs identically under the CI openssl-mask).
|
||||
#
|
||||
@@ -57,6 +84,17 @@ ok() { pass=$((pass + 1)); }
|
||||
# A 40-hex sha = a valid §2.1 hard locator.
|
||||
SHA40="abcdef0123456789abcdef0123456789abcdef01"
|
||||
|
||||
# capture-alarm (#924): a REACHABLE off-host alarm route that APPENDS the
|
||||
# routed payload (one JSON line per invocation) to $ALARM_OUT, so a test can
|
||||
# count exactly how many off-host alarms fired across one or more digest.sh
|
||||
# invocations. Mirrors test-wake-beacon.sh's capture-alarm idiom.
|
||||
CAPTURE_ALARM="$TMP_ROOT/capture-alarm.sh"
|
||||
cat >"$CAPTURE_ALARM" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
cat >>"$ALARM_OUT"
|
||||
EOF
|
||||
chmod +x "$CAPTURE_ALARM"
|
||||
|
||||
# fresh_home NAME — a fresh WAKE_STATE_HOME dir, echoed.
|
||||
fresh_home() {
|
||||
local d="$TMP_ROOT/$1"
|
||||
@@ -165,6 +203,104 @@ echo "== Q5: claim-precedence gated — a non-actionable-class entry carrying a
|
||||
true
|
||||
) && ok
|
||||
|
||||
echo "== Q6 (a): dead-lettered entry routes EXACTLY ONE off-host alarm (payload names observed_seq) + stderr diagnostic STILL fires =="
|
||||
(
|
||||
home="$(fresh_home q6)"
|
||||
export WAKE_STATE_HOME="$home"
|
||||
unset WAKE_AGENT
|
||||
f="$TMP_ROOT/q6.jsonl"
|
||||
printf '%s\n' '{"observed_seq":21,"class":"actionable","locators":{"kind":"repo","id":"DLQ-Q6","path":"x.md","observed_hash":"aaaa"},"emit_ts":1}' >"$f"
|
||||
ALARM_OUT="$TMP_ROOT/q6.alarm.jsonl"
|
||||
export ALARM_OUT
|
||||
: >"$ALARM_OUT"
|
||||
export WAKE_ALARM_SINK_CMD="$CAPTURE_ALARM"
|
||||
err="$TMP_ROOT/q6.err"
|
||||
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" = "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"
|
||||
true
|
||||
) && ok
|
||||
|
||||
echo "== Q7 (b): re-draining the SAME still-dead-lettered entry N times routes ZERO additional off-host alarms (dedup by observed_seq) =="
|
||||
(
|
||||
home="$(fresh_home q7)"
|
||||
export WAKE_STATE_HOME="$home"
|
||||
unset WAKE_AGENT
|
||||
f="$TMP_ROOT/q7.jsonl"
|
||||
printf '%s\n' '{"observed_seq":22,"class":"actionable","locators":{"kind":"repo","id":"DLQ-Q7","path":"y.md","observed_hash":"bbbb"},"emit_ts":1}' >"$f"
|
||||
ALARM_OUT="$TMP_ROOT/q7.alarm.jsonl"
|
||||
export ALARM_OUT
|
||||
: >"$ALARM_OUT"
|
||||
export WAKE_ALARM_SINK_CMD="$CAPTURE_ALARM"
|
||||
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" = "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)"
|
||||
) && ok
|
||||
|
||||
echo "== Q8 (c): a NEW distinct dead-lettered entry routes its OWN one alarm (dedup is per-entry, not a global latch) =="
|
||||
(
|
||||
home="$(fresh_home q8)"
|
||||
export WAKE_STATE_HOME="$home"
|
||||
unset WAKE_AGENT
|
||||
f1="$TMP_ROOT/q8a.jsonl"
|
||||
f2="$TMP_ROOT/q8b.jsonl"
|
||||
printf '%s\n' '{"observed_seq":31,"class":"actionable","locators":{"kind":"repo","id":"DLQ-Q8A","path":"a.md","observed_hash":"c1"},"emit_ts":1}' >"$f1"
|
||||
printf '%s\n' '{"observed_seq":32,"class":"actionable","locators":{"kind":"repo","id":"DLQ-Q8B","path":"b.md","observed_hash":"c2"},"emit_ts":1}' >"$f2"
|
||||
ALARM_OUT="$TMP_ROOT/q8.alarm.jsonl"
|
||||
export ALARM_OUT
|
||||
: >"$ALARM_OUT"
|
||||
export WAKE_ALARM_SINK_CMD="$CAPTURE_ALARM"
|
||||
"$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" = "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"
|
||||
) && ok
|
||||
|
||||
echo "== Q9 (d): WAKE_ALARM_SINK_CMD unconfigured OR unreachable -> FAIL LOUD (never silent no-alarm); per-entry, render still exits 0 =="
|
||||
(
|
||||
home="$(fresh_home q9a)"
|
||||
export WAKE_STATE_HOME="$home"
|
||||
unset WAKE_AGENT
|
||||
f="$TMP_ROOT/q9.jsonl"
|
||||
printf '%s\n' '{"observed_seq":41,"class":"actionable","locators":{"kind":"repo","id":"DLQ-Q9","path":"z.md","observed_hash":"dddd"},"emit_ts":1}' >"$f"
|
||||
# (a) UNCONFIGURED alarm sink.
|
||||
unset WAKE_ALARM_SINK_CMD
|
||||
err_a="$TMP_ROOT/q9a.err"
|
||||
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"
|
||||
true
|
||||
) && ok
|
||||
(
|
||||
home2="$(fresh_home q9b)"
|
||||
export WAKE_STATE_HOME="$home2"
|
||||
unset WAKE_AGENT
|
||||
f="$TMP_ROOT/q9.jsonl"
|
||||
export WAKE_ALARM_SINK_CMD="false"
|
||||
err_b="$TMP_ROOT/q9b.err"
|
||||
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"
|
||||
true
|
||||
) && ok
|
||||
|
||||
echo
|
||||
if [ -s "$FAILFILE" ]; then
|
||||
echo "wake digest-quarantine harness: FAILED ($(grep -c . "$FAILFILE") assertion(s))" >&2
|
||||
|
||||
Reference in New Issue
Block a user