fix(wake): #920 quarantine render-refused drain entry (no head-of-line block) + reconciler enumerations render orientation-tier
Some checks failed
ci/woodpecker/pr/ci Pipeline was canceled
Some checks failed
ci/woodpecker/pr/ci Pipeline was canceled
Live pilot finding #6 (BLOCKING): a reconciler enumeration enqueued class=actionable with soft locators {kind,id,path,observed_hash} failed §2.1's ACTIONABLE hard-locator taxonomy, so digest render exit-4'd the ENTIRE cumulative-state drain — 4 consecutive timer failures, NOTHING delivered, including clean unrelated entries (head-of-line blocking). FIX 1 (quarantine, don't wedge): digest.sh cmd_render's fail-loud pass is now PER-ENTRY. A render-refused ACTIONABLE entry (no hard locator) is DEAD-LETTERED to $STATE_DIR/dead-letter.jsonl + a loud per-entry alarm and EXCLUDED, while the REST of the cumulative set still renders (exit 0). The bad entry is accounted-for, never silently dropped; one malformed entry can no longer wedge the whole drain. FIX 2 (AMENDED — render-tier, NOT class=digest): reconcile.sh's store class is UNCHANGED (non-coalescing) — the naive class=digest was rejected because store §2.3/T2 coalescing would silently collapse distinct enumerations (proven: reconcile R6 goes RED). Instead digest.sh's actionable-classifier now treats locators.reconciled==true (set only by reconcile.sh; not source-forgeable) as ORIENTATION-tier: gate-exempt, rendered as an orientation pointer via _locator_line's digest-class vocabulary. No exit-4, no wedge, no coalescing loss; §2.3/T2/G3-R6 intact. RED-FIRST: new test-wake-digest-quarantine.sh (openssl-independent) proves (a) malformed {kind,id,path,observed_hash} quarantines while a clean sibling still delivers, (b) a reconciled enumeration renders orientation-tier (no exit-4), (c) TWO distinct enumerations both survive as separate orientation renders (anti-collapse — the class=digest silent-drop we rejected), and the preserved per-entry actionable fail-loud. D2/D6 in test-wake-digest-hmac.sh updated from whole-digest exit-4 to per-entry quarantine. Wake manifest bumped 0.6.2 -> 0.6.3 + inventory. Closes #920 Part of #892 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0158NZqN2n2ymKFeJAZ4GUCb
This commit is contained in:
@@ -7,8 +7,9 @@
|
||||
# that invariant regresses:
|
||||
# D1 CUMULATIVE-STATE: two still-pending changes both render (not just the
|
||||
# latest delta) — a delta would silently drop the older change. (§2.1)
|
||||
# D2 HARD-LOCATOR enforcement: an actionable claim with no precise locator
|
||||
# FAILS LOUD (non-zero exit, nothing emitted). (§2.1)
|
||||
# D2 HARD-LOCATOR enforcement: an actionable claim with no precise locator is
|
||||
# QUARANTINED — dead-lettered + alarmed + excluded — never delivered as
|
||||
# valid (fail-loud PER-ENTRY, #920; the rest of the drain still renders). (§2.1)
|
||||
# D3 TWO-TIER trust: orientation decides the no-op case with ZERO tool calls;
|
||||
# an actionable fact is a CLAIM-TO-VERIFY, never auto-actioned. (§2.1)
|
||||
# D4 SCRUB: a secret-canary + ANSI/bidi/zero-width in SOURCE free-text is
|
||||
@@ -27,7 +28,8 @@
|
||||
# digest-class entry (the shape detector.sh actually enqueues:
|
||||
# kind/id/observed_hash/remote/path, not repo/issue/sha/file) carries a
|
||||
# non-empty, usable locator — and the ACTIONABLE-tier hard-locator
|
||||
# FAIL-LOUD (exit 4) is UNCHANGED for a malformed actionable claim. (§2.1)
|
||||
# FAIL-LOUD is PRESERVED (now per-entry quarantine, #920) for a malformed
|
||||
# actionable claim. (§2.1)
|
||||
#
|
||||
# Isolated: every test runs against a fresh temp state / credential file.
|
||||
set -uo pipefail
|
||||
@@ -100,60 +102,71 @@ echo "== D1: CUMULATIVE-STATE — two pending changes BOTH render (not just late
|
||||
echo "$out" | grep -q 'pending=2' || fail_msg "D1: cumulative pending count wrong (expected 2)"
|
||||
) && ok
|
||||
|
||||
echo "== D2: HARD-LOCATOR enforcement — actionable claim with no locator FAILS LOUD =="
|
||||
echo "== D2: HARD-LOCATOR enforcement — a malformed actionable claim is QUARANTINED (fail-loud PER-ENTRY, #920); never delivered as valid =="
|
||||
(
|
||||
WAKE_STATE_HOME="$(fresh_state d2)"
|
||||
h="$(fresh_state d2)"
|
||||
WAKE_STATE_HOME="$h"
|
||||
export WAKE_STATE_HOME
|
||||
unset WAKE_AGENT WAKE_LANE
|
||||
# An actionable claim carrying NO hard locator (no repo+issue / sha / file).
|
||||
"$STORE" enqueue --seq 1 --class actionable --locators '{"claim":"mergeable=true"}' >/dev/null
|
||||
if out="$("$DIGEST" render 2>/dev/null)"; then
|
||||
fail_msg "D2: malformed digest (actionable, no locator) must FAIL, but render succeeded"
|
||||
fi
|
||||
err="$TMP_ROOT/d2.err"
|
||||
rc=0
|
||||
"$DIGEST" render >/dev/null 2>&1 || rc=$?
|
||||
[ "$rc" -eq 4 ] || fail_msg "D2: expected fail-loud exit 4, got $rc"
|
||||
# Nothing emitted on stdout when malformed (no silent partial send).
|
||||
[ -z "${out:-}" ] || fail_msg "D2: a malformed digest emitted body instead of failing loud [$out]"
|
||||
# A present-but-imprecise sha (not 40 hex) does NOT satisfy the hard locator.
|
||||
WAKE_STATE_HOME="$(fresh_state d2b)"
|
||||
out="$("$DIGEST" render 2>"$err")" || rc=$?
|
||||
# #920: NO longer a whole-digest exit-4 — the malformed entry is QUARANTINED
|
||||
# (dead-lettered + alarmed + excluded) and the digest STILL renders (exit 0),
|
||||
# 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"
|
||||
|
||||
# A present-but-imprecise sha (not 40 hex) does NOT satisfy the hard locator ->
|
||||
# quarantined, not delivered.
|
||||
h="$(fresh_state d2b)"
|
||||
WAKE_STATE_HOME="$h"
|
||||
export WAKE_STATE_HOME
|
||||
"$STORE" enqueue --seq 1 --class actionable --locators '{"claim":"ci=green","sha":"abc123"}' >/dev/null
|
||||
rc=0
|
||||
"$DIGEST" render >/dev/null 2>&1 || rc=$?
|
||||
[ "$rc" -eq 4 ] || fail_msg "D2: imprecise sha (not 40-hex) must not satisfy the hard-locator gate (got exit $rc)"
|
||||
# The SAME claim WITH a precise 40-hex sha renders fine.
|
||||
WAKE_STATE_HOME="$(fresh_state d2c)"
|
||||
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"
|
||||
|
||||
# The SAME claim WITH a precise 40-hex sha renders fine (delivered, not quarantined).
|
||||
h="$(fresh_state d2c)"
|
||||
WAKE_STATE_HOME="$h"
|
||||
export WAKE_STATE_HOME
|
||||
"$STORE" enqueue --seq 1 --class actionable --locators "$(jq -cn --arg s "$SHA40" '{claim:"ci=green",sha:$s}')" >/dev/null
|
||||
"$DIGEST" render >/dev/null 2>&1 || fail_msg "D2: a well-located actionable claim must render"
|
||||
# --- #905: a NON-CANONICAL entry with a TOP-LEVEL `.claim` (store.sh never
|
||||
# emits this shape; only .locators.claim is canonical) and EMPTY .locators,
|
||||
# fed via --stdin / --from-file, must ALSO fail loud. The render tier honors
|
||||
# `.claim // .locators.claim` (renders CLAIM@seq either way), so the
|
||||
# fail-loud gate must cover top-level .claim too, else a hand-crafted /
|
||||
# non-canonical caller could bypass the hard-locator gate entirely.
|
||||
WAKE_STATE_HOME="$(fresh_state d2d)"
|
||||
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"
|
||||
[ -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;
|
||||
# only .locators.claim is canonical) and EMPTY .locators, fed via --stdin /
|
||||
# --from-file, must ALSO be gated. The classifier honors `.claim //
|
||||
# .locators.claim`, so a hand-crafted caller cannot bypass the hard-locator gate
|
||||
# — the entry is QUARANTINED (not delivered), not silently rendered.
|
||||
h="$(fresh_state d2d)"
|
||||
WAKE_STATE_HOME="$h"
|
||||
export WAKE_STATE_HOME
|
||||
toplevel_claim_entry='{"class":"reaction","claim":"mergeable=true","locators":{}}'
|
||||
out=""
|
||||
if out="$(printf '%s\n' "$toplevel_claim_entry" | "$DIGEST" render --stdin 2>/dev/null)"; then
|
||||
fail_msg "D2(#905): top-level .claim + empty locators must FAIL via --stdin, but render succeeded"
|
||||
fi
|
||||
[ -z "${out:-}" ] || fail_msg "D2(#905): --stdin top-level-.claim bypass emitted body instead of failing loud [$out]"
|
||||
toplevel_claim_entry='{"observed_seq":1,"class":"reaction","claim":"mergeable=true","locators":{}}'
|
||||
rc=0
|
||||
printf '%s\n' "$toplevel_claim_entry" | "$DIGEST" render --stdin >/dev/null 2>&1 || rc=$?
|
||||
[ "$rc" -eq 4 ] || fail_msg "D2(#905): expected fail-loud exit 4 for top-level .claim via --stdin, got $rc"
|
||||
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)"
|
||||
ff="$TMP_ROOT/d2d-entry.jsonl"
|
||||
printf '%s\n' "$toplevel_claim_entry" >"$ff"
|
||||
out2=""
|
||||
if out2="$("$DIGEST" render --from-file "$ff" 2>/dev/null)"; then
|
||||
fail_msg "D2(#905): top-level .claim + empty locators must FAIL via --from-file, but render succeeded"
|
||||
fi
|
||||
[ -z "${out2:-}" ] || fail_msg "D2(#905): --from-file top-level-.claim bypass emitted body instead of failing loud [$out2]"
|
||||
h="$(fresh_state d2e)"
|
||||
WAKE_STATE_HOME="$h"
|
||||
export WAKE_STATE_HOME
|
||||
rc=0
|
||||
"$DIGEST" render --from-file "$ff" >/dev/null 2>&1 || rc=$?
|
||||
[ "$rc" -eq 4 ] || fail_msg "D2(#905): expected fail-loud exit 4 for top-level .claim via --from-file, got $rc"
|
||||
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)"
|
||||
) && ok
|
||||
|
||||
echo "== D3: TWO-TIER — orientation no-op with ZERO tool calls; actionable = claim-to-verify =="
|
||||
@@ -371,14 +384,21 @@ echo "== D6 (#914b): DIGEST-CLASS LOCATOR THREADING — ORIENTATION pointer carr
|
||||
printf '%s' "$orientline" | grep -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 (exit 4) must be UNCHANGED ------
|
||||
WAKE_STATE_HOME="$(fresh_state d6b)"
|
||||
# --- ACTIONABLE-tier hard-locator FAIL-LOUD must be PRESERVED (now PER-ENTRY
|
||||
# quarantine, #920): a digest-class ORIENTATION pointer (above) renders soft,
|
||||
# but a genuine ACTIONABLE claim with no hard locator is still fail-loud — it is
|
||||
# QUARANTINED (dead-lettered + alarmed + excluded), never delivered as valid.
|
||||
h="$(fresh_state d6b)"
|
||||
WAKE_STATE_HOME="$h"
|
||||
export WAKE_STATE_HOME
|
||||
"$STORE" enqueue --seq 1 --class actionable --locators '{"claim":"mergeable=true"}' >/dev/null
|
||||
err="$TMP_ROOT/d6b.err"
|
||||
rc=0
|
||||
"$DIGEST" render >/dev/null 2>&1 || rc=$?
|
||||
[ "$rc" -eq 4 ] ||
|
||||
fail_msg "D6: actionable claim with no hard locator must still FAIL-LOUD exit 4 (got $rc) — regression in the unrelated hard-locator gate"
|
||||
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"
|
||||
) && ok
|
||||
|
||||
echo
|
||||
|
||||
Reference in New Issue
Block a user