From fb3c3c348f9780a29d8500a3189d226baee90da7 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Thu, 30 Jul 2026 08:02:55 -0500 Subject: [PATCH] =?UTF-8?q?fix(wake):=20#944=20path=20becomes=20a=20hard-l?= =?UTF-8?q?ocator=20arm=20=E2=80=94=20detector-shape=20actionable=20entrie?= =?UTF-8?q?s=20can=20now=20pass=20the=20=C2=A72.1=20gate=20+=20version=200?= =?UTF-8?q?.6.14?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The _has_hard_locator gate tested only repo+issue / 40-hex sha / file — the forge locator vocabulary. detector.sh (A1) builds board_file locators as kind/id/observed_hash + path (+ snapshot_sha/_ts when attested, #940): zero keys in common, so a class=actionable board_file entry could NEVER pass and every heartbeat-planning delta dead-lettered (live seqs 63/68, dragon-lin, 2026-07-30). Latent since #920; the #920 harness pinned the detector pilot shape as its malformed example, ratifying the gap. Fix: `path` becomes a hard-locator arm — and ONLY path. It carries the same one-call re-verify precision as `file` (re-read ; upgrades to git show : when snapshot-attested). Deliberate NON-arms: observed_hash (content hash, not an address) and bare path-less snapshot_sha (would widen the gate past the board_file vocabulary — review-adopted criterion). Quarantine is a render-time filter (entries never leave pending.jsonl; dead-letter.jsonl is ledger + alarm-dedup only), so existing UNCONSUMED dead-letters re-deliver automatically on the first post-upgrade drain. Consumed-past dead-letters are not requeued. Tests: Q11 positive control renders the live seq-68 entry VERBATIM as CLAIM@seq (real detector emission, not a hand-built dict); negative controls assert address-free and bare path-less snapshot_sha siblings still quarantine — the snapshot_sha control at all THREE lengths the detector's attestation validation ^[0-9a-f]{7,64}$ admits (7-char abbreviation, 40-hex, 64-char sha-256), so it distinguishes "no arm" from "arm present but length-gated" (review finding E1). Q1/Q6–Q9 fixtures moved off the now-valid path-bearing shape. RED at base: exactly the 8 Q11 assertions fail; Q1–Q10 pass under both digests. Closes #944 Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01NsKce8iZuSuRnu3gVMCBKB Written-by: pepper (sb-it-1-dt) --- .../mosaic/framework/tools/wake/digest.sh | 31 +++-- .../mosaic/framework/tools/wake/manifest.txt | 26 +++- .../tools/wake/test-wake-digest-quarantine.sh | 119 ++++++++++++++++-- 3 files changed, 156 insertions(+), 20 deletions(-) diff --git a/packages/mosaic/framework/tools/wake/digest.sh b/packages/mosaic/framework/tools/wake/digest.sh index 6db3d12c..dc4b91b2 100755 --- a/packages/mosaic/framework/tools/wake/digest.sh +++ b/packages/mosaic/framework/tools/wake/digest.sh @@ -209,13 +209,28 @@ _scrub_free() { # --------------------------------------------------------------------------- # _has_hard_locator LOCATORS_JSON — true iff the locators object carries at least -# one PRECISE locator sufficient for one-call re-verification: -# repo + issue (issue#) | 40-hex sha | file (file:anchor). +# one PRECISE locator sufficient for one-call re-verification. BOTH locator +# vocabularies in live use are accepted (the same two _locator_line documents +# under #914b): +# forge shape (§2.1): repo + issue (issue#) | 40-hex sha | file (file:anchor) +# detector shape (#944): path +# The `path` arm was added by #944: detector.sh (A1) builds board_file locators +# as kind/id/observed_hash + path (+ snapshot_sha when adapter-attested, #940) +# — none of which the gate tested — so a class=actionable board_file entry +# could NEVER pass and every heartbeat-planning delta dead-lettered (live seqs +# 63/68). `path` mirrors `file` exactly (same one-call "re-read X" hint below; +# with an attested snapshot_sha the hint upgrades to one-call +# `git show :`). DELIBERATELY NOT ARMS: `observed_hash` +# (a content hash, not an address) and bare `snapshot_sha` without `path` +# (a path-less 40-hex would widen the gate past the board_file vocabulary — +# review-adopted criterion on #944; snapshot_sha's precision is only reachable +# THROUGH a path, so path is the address and snapshot_sha stays a refinement). _has_hard_locator() { jq -e ' ((.repo // "") != "" and ((.issue // "") | tostring) != "") or (((.sha // "") | test("^[0-9a-f]{40}$"))) or ((.file // "") != "") + or ((.path // "") != "") ' >/dev/null 2>&1 <<<"$1" } @@ -223,16 +238,18 @@ _has_hard_locator() { # one-targeted-call re-verify hint, where available. # # #914b: covers BOTH locator vocabularies actually in use: -# - the HARD-locator shape (§2.1, gated by _has_hard_locator, unchanged): +# - the HARD-locator shape (§2.1, gated by _has_hard_locator): # repo+issue | 40-hex sha | file(:anchor). # - the shape detector.sh (A1) actually builds for a `digest`-class entry # (see detector.sh's enqueue-locators jq filter): kind/id/observed_hash + # whichever of repo/path/anchor/remote/branches the source def declares. # None of kind/id/observed_hash/remote/path/branches were recognized here # before, so a real digest-class pointer rendered a bare empty "locator:" -# line despite the entry carrying real (soft, non-hard) locator data. This -# is display-only: it does NOT feed _has_hard_locator, so the -# ACTIONABLE-tier hard-locator FAIL-LOUD gate is untouched. +# line despite the entry carrying real (soft, non-hard) locator data. +# (At #914b this was display-only; #944 later promoted `path` — and ONLY +# `path` — into _has_hard_locator, since it carries the same one-call +# re-verify precision as `file`. kind/id/observed_hash/remote/branches +# and bare snapshot_sha remain soft/display-only.) _locator_line() { local loc="$1" repo issue sha file anchor head parts='' reverify='' local remote path kind id ohash branches snap_sha snap_ts @@ -477,7 +494,7 @@ _quarantine_entry() { return 0 fi fi - echo "digest.sh: FAIL-LOUD QUARANTINE (#920) — malformed ACTIONABLE entry at observed_seq=$seq has no §2.1 hard locator (repo+issue#/40-char SHA/file:anchor). DEAD-LETTERED to $dlq and EXCLUDED from this digest; the rest of the cumulative set still renders (no head-of-line block). Re-feed the source with a valid hard locator." >&2 + echo "digest.sh: FAIL-LOUD QUARANTINE (#920) — malformed ACTIONABLE entry at observed_seq=$seq has no §2.1 hard locator (repo+issue# / 40-hex sha / file:anchor / path). DEAD-LETTERED to $dlq and EXCLUDED from this digest; the rest of the cumulative set still renders (no head-of-line block). Re-feed the source with a valid hard locator." >&2 # #924 (G2a): route the SAME per-entry alarm off-host too, deduped by # observed_seq so a still-dead-lettered entry re-drained every tick is # alarmed off-host EXACTLY ONCE (never once per re-render). diff --git a/packages/mosaic/framework/tools/wake/manifest.txt b/packages/mosaic/framework/tools/wake/manifest.txt index ee75d735..fdb094bf 100644 --- a/packages/mosaic/framework/tools/wake/manifest.txt +++ b/packages/mosaic/framework/tools/wake/manifest.txt @@ -318,8 +318,32 @@ # anchors, fatal in $((...))) rejects. Full rationale in the knob # paragraph of the 0.6.12 entry above. # Changed: detector.sh (+ test-wake-detector.sh D13). +# 0.6.14 #944 the §2.1 hard-locator gate was UNSATISFIABLE for detector-built +# actionable board_file entries: _has_hard_locator tested only +# repo+issue / 40-hex sha / file, while detector.sh (A1) builds +# kind/id/observed_hash + path (+ snapshot_sha/_ts when attested, +# #940) — no key in common, so every class=actionable board_file +# delta was structurally guaranteed to dead-letter (live: mos-dt +# seqs 63/68, 2026-07-30; the only tier with a 30m SLO delivered +# nothing on its only actionable source). Fix: `path` becomes a +# hard-locator arm — and ONLY path: it mirrors `file`'s one-call +# "re-read X" precision, upgrading to one-call +# `git show :` when a snapshot is attested. +# observed_hash (content hash, not an address) and bare path-less +# snapshot_sha (would widen the gate past the board_file +# vocabulary — review-adopted criterion) remain NON-arms. +# Quarantine is a RENDER-TIME filter (entries never leave +# pending), so existing UNCONSUMED dead-letters re-deliver +# automatically on the first post-upgrade drain; consumed-past +# dead-letters are not requeued. +# Changed: digest.sh (+ test-wake-digest-quarantine.sh: Q11 +# positive control — the live seq-68 entry verbatim must RENDER +# as CLAIM@seq — and Q1/Q6-Q9 fixtures moved off the now-valid +# path-bearing shape onto genuinely address-free shapes, +# amending the #920-era ruling that had pinned the live pilot's +# own locator shape as the malformed example). component=wake -version=0.6.13 +version=0.6.14 # 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-digest-quarantine.sh b/packages/mosaic/framework/tools/wake/test-wake-digest-quarantine.sh index 493a9634..74b014d1 100755 --- a/packages/mosaic/framework/tools/wake/test-wake-digest-quarantine.sh +++ b/packages/mosaic/framework/tools/wake/test-wake-digest-quarantine.sh @@ -4,12 +4,19 @@ # blocking) + reconciler ENUMERATIONS render ORIENTATION-tier. # # Each test asserts ONE invariant and goes RED against the pre-#920 digest.sh: -# Q1 (a) QUARANTINE + REST-DELIVERS: a malformed `actionable` carrying the live -# pilot's EXACT locator shape {kind,id,path,observed_hash} (no hard -# locator, no reconciled marker) is DEAD-LETTERED + alarmed AND EXCLUDED, -# while a clean valid sibling in the SAME drain still renders (exit 0). +# Q1 (a) QUARANTINE + REST-DELIVERS: a malformed `actionable` carrying NO hard +# locator ({kind,id,observed_hash} — a content hash but no ADDRESS, no +# reconciled marker) is DEAD-LETTERED + alarmed AND EXCLUDED, while a +# clean valid sibling in the SAME drain still renders (exit 0). # RED baseline: the old whole-digest exit-4 delivered NOTHING (the live # head-of-line-blocking wedge). (#920 FIX1) +# [#944 AMENDMENT: at #920 this fixture pinned the live pilot's shape +# {kind,id,path,observed_hash} as the malformed case — ratifying a gate +# the detector's own locators could never satisfy (every actionable +# heartbeat-planning delta dead-lettered; live seqs 63/68). #944 amends +# that ruling: `path` and 40-hex `snapshot_sha` are now hard-locator +# arms (see Q11), so the quarantine fixtures here and in Q6-Q9 use +# genuinely ADDRESS-FREE shapes instead.] # Q2 (b) ENUM-AS-ORIENTATION: a reconciler enumeration (locators.reconciled== # true) renders as an ORIENTATION-tier pointer and does NOT exit-4 / is # NOT quarantined. RED baseline: reconciled `actionable` + soft locators @@ -53,6 +60,30 @@ # (Q6/Q7/Q8 all see 0 captured alarms) and no "FAIL LOUD ... alarm sink" # diagnostic exists to fire (Q9). # +# #944 (unsatisfiable-gate fix): _has_hard_locator gains the `path` arm — and +# ONLY that arm — covering the detector-built board_file vocabulary. +# Q11 POSITIVE CONTROL + RETAINED NEGATIVES, one drain: (a) the live +# seq-68 entry VERBATIM (the exact production entry that dead-lettered +# under the unsatisfiable gate: kind/id/observed_hash + path + +# snapshot_sha + snapshot_ts, class=actionable, as detector.sh +# actually emits it — NOT a hand-built dict) must RENDER as a +# CLAIM@seq with the one-call `git show :` +# re-verify hint — the assertion is the rendered claim, not merely +# the predicate returning true; (b) a path-only sibling (no snapshot +# attestation — a pre-#940 adapter or a dropped attestation) must +# ALSO render, with the "re-read " hint; (c) an address-free +# sibling ({kind,id,observed_hash}) must STILL quarantine + route its +# own alarm — observed_hash is a content hash, not an address; (d) +# bare path-less snapshot_sha siblings must ALSO still quarantine — +# the widened gate must not widen PAST the board_file vocabulary +# (review-adopted criterion) — asserted at THREE lengths (7-char +# abbreviation, 40-hex, 64-char sha-256) spanning the detector's +# actual attestation validation ^[0-9a-f]{7,64}$ (detector.sh), so +# the assertion distinguishes "no snapshot_sha arm" from "an arm +# present but length-gated". RED baseline: pre-#944 +# digest.sh dead-letters (a) and (b) — an assertion nobody has seen +# succeed is as unproven as one nobody has seen fail. +# # 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). # @@ -105,15 +136,16 @@ fresh_home() { # dlq HOME — the dead-letter path for the default agent under HOME. dlq() { printf '%s/default/dead-letter.jsonl' "$1"; } -echo "== Q1 (a): malformed {kind,id,path,observed_hash} QUARANTINES; clean sibling STILL delivers ==" +echo "== Q1 (a): malformed address-free {kind,id,observed_hash} QUARANTINES; clean sibling STILL delivers ==" ( home="$(fresh_home q1)" export WAKE_STATE_HOME="$home" unset WAKE_AGENT f="$TMP_ROOT/q1.jsonl" - # The live pilot's EXACT malformed shape (no reconciled marker) + a clean sibling. + # An ADDRESS-FREE malformed shape (no reconciled marker) + a clean sibling. + # [#944: the original fixture carried `path`, which is now a hard-locator arm.] { - printf '%s\n' '{"observed_seq":1,"class":"actionable","locators":{"kind":"repo","id":"MALFORMED-Q","path":"docs/x.md","observed_hash":"deadbeef"},"emit_ts":1}' + printf '%s\n' '{"observed_seq":1,"class":"actionable","locators":{"kind":"repo","id":"MALFORMED-Q","observed_hash":"deadbeef"},"emit_ts":1}' printf '{"observed_seq":2,"class":"actionable","locators":{"sha":"%s","file":"src/a.ts"},"emit_ts":1}\n' "$SHA40" } >"$f" err="$TMP_ROOT/q1.err" @@ -209,7 +241,7 @@ echo "== Q6 (a): dead-lettered entry routes EXACTLY ONE off-host alarm (payload 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" + printf '%s\n' '{"observed_seq":21,"class":"actionable","locators":{"kind":"repo","id":"DLQ-Q6","observed_hash":"aaaa"},"emit_ts":1}' >"$f" ALARM_OUT="$TMP_ROOT/q6.alarm.jsonl" export ALARM_OUT : >"$ALARM_OUT" @@ -232,7 +264,7 @@ echo "== Q7 (b): re-draining the SAME still-dead-lettered entry N times routes Z 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" + printf '%s\n' '{"observed_seq":22,"class":"actionable","locators":{"kind":"repo","id":"DLQ-Q7","observed_hash":"bbbb"},"emit_ts":1}' >"$f" ALARM_OUT="$TMP_ROOT/q7.alarm.jsonl" export ALARM_OUT : >"$ALARM_OUT" @@ -252,8 +284,8 @@ echo "== Q8 (c): a NEW distinct dead-lettered entry routes its OWN one alarm (de 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" + printf '%s\n' '{"observed_seq":31,"class":"actionable","locators":{"kind":"repo","id":"DLQ-Q8A","observed_hash":"c1"},"emit_ts":1}' >"$f1" + printf '%s\n' '{"observed_seq":32,"class":"actionable","locators":{"kind":"repo","id":"DLQ-Q8B","observed_hash":"c2"},"emit_ts":1}' >"$f2" ALARM_OUT="$TMP_ROOT/q8.alarm.jsonl" export ALARM_OUT : >"$ALARM_OUT" @@ -273,7 +305,7 @@ echo "== Q9 (d): WAKE_ALARM_SINK_CMD unconfigured OR unreachable -> FAIL LOUD (n 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" + printf '%s\n' '{"observed_seq":41,"class":"actionable","locators":{"kind":"repo","id":"DLQ-Q9","observed_hash":"dddd"},"emit_ts":1}' >"$f" # (a) UNCONFIGURED alarm sink. unset WAKE_ALARM_SINK_CMD err_a="$TMP_ROOT/q9a.err" @@ -337,6 +369,69 @@ echo "== Q10: snapshot metadata (#940) — snapshot_sha/snapshot_ts render on th true ) && ok +echo "== Q11 (#944): REAL detector-shape actionable RENDERS as CLAIM@seq; address-free + bare-snapshot_sha siblings STILL quarantine ==" +( + home="$(fresh_home q11)" + export WAKE_STATE_HOME="$home" + unset WAKE_AGENT + f="$TMP_ROOT/q11.jsonl" + { + # (a) the LIVE seq-68 entry VERBATIM — the exact production entry that + # dead-lettered on the mos-dt lane under the unsatisfiable gate + # (dragon-lin dead-letter.jsonl, 2026-07-30). Detector-emitted shape, + # not a hand-built dict. + printf '%s\n' '{"observed_seq":68,"locators":{"kind":"board_file","id":"heartbeat-planning","observed_hash":"2e85f2474001961e920976a91981eca5bb86a5ff0df044e082a1e1f2dc7493b5","snapshot_sha":"55d4909569d2b5fbccfec49ec9ca83db5049f3ce","snapshot_ts":1785414523,"path":"docs/scratchpads/heartbeat-planning"},"class":"actionable","emit_ts":1785415057,"hmac":""}' + # (b) same vocabulary WITHOUT snapshot attestation (pre-#940 adapter or + # dropped-as-malformed attestation) — must pass via the path arm alone. + printf '%s\n' '{"observed_seq":69,"class":"actionable","locators":{"kind":"board_file","id":"PILOT-LOCAL","observed_hash":"abcd1234","path":"BOARD.md"},"emit_ts":2}' + # (c) ADDRESS-FREE — the retained negative: a content hash is not an address. + printf '%s\n' '{"observed_seq":70,"class":"actionable","locators":{"kind":"board_file","id":"ADDR-FREE","observed_hash":"ffff0000"},"emit_ts":2}' + # (d) bare path-less snapshot_sha — must NOT pass: the widened gate must + # not widen past the board_file vocabulary. Asserted at all three + # lengths the detector's attestation validation ^[0-9a-f]{7,64}$ + # admits: a 40-hex sha-1, a 7-char abbreviation, a 64-char sha-256. + # One length alone cannot distinguish "no arm" from "arm present but + # length-gated" (enumeration finding E1). + printf '%s\n' '{"observed_seq":71,"class":"actionable","locators":{"kind":"board_file","id":"SNAP-ONLY-40","observed_hash":"eeee1111","snapshot_sha":"55d4909569d2b5fbccfec49ec9ca83db5049f3ce"},"emit_ts":2}' + printf '%s\n' '{"observed_seq":72,"class":"actionable","locators":{"kind":"board_file","id":"SNAP-ONLY-7","observed_hash":"eeee2222","snapshot_sha":"55d4909"},"emit_ts":2}' + printf '%s\n' '{"observed_seq":73,"class":"actionable","locators":{"kind":"board_file","id":"SNAP-ONLY-64","observed_hash":"eeee3333","snapshot_sha":"55d4909569d2b5fbccfec49ec9ca83db5049f3ce55d4909569d2b5fbccfec49e"},"emit_ts":2}' + } >"$f" + ALARM_OUT="$TMP_ROOT/q11.alarm.jsonl" + export ALARM_OUT + : >"$ALARM_OUT" + export WAKE_ALARM_SINK_CMD="$CAPTURE_ALARM" + err="$TMP_ROOT/q11.err" + out="$("$DIGEST" render --from-file "$f" --agent default 2>"$err")" + rc=$? + [ "$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' \ + || 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)" + [ "$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" + 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" + 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)" + [ "$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" + 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" + done + true +) && ok + echo if [ -s "$FAILFILE" ]; then echo "wake digest-quarantine harness: FAILED ($(grep -c . "$FAILFILE") assertion(s))" >&2