fix(wake): #920 quarantine render-refused drain entry (no head-of-line block) + reconciler enumerations render orientation-tier (reconciled:true, render-tier not class=digest) (#922)
All checks were successful
ci/woodpecker/push/publish Pipeline was successful
ci/woodpecker/push/ci Pipeline was successful

Co-authored-by: jason.woltje <jason@diversecanvas.com>
Co-committed-by: jason.woltje <jason@diversecanvas.com>
This commit was merged in pull request #922.
This commit is contained in:
2026-07-26 08:45:51 +00:00
committed by Mos
parent 712c770b7a
commit 937a276208
5 changed files with 378 additions and 82 deletions

View File

@@ -26,8 +26,23 @@
#
# HARD LOCATORS (§2.1): every actionable claim MUST carry a precise locator
# (repo + issue#, a 40-char SHA, or file:anchor) so re-verification is ONE
# targeted call. A missing locator = malformed digest = FAIL-LOUD (non-zero
# exit, NOTHING emitted) — never a silent send.
# targeted call. A missing locator = malformed ACTIONABLE entry = FAIL-LOUD.
#
# #920 (per-entry quarantine — fail-loud WITHOUT head-of-line blocking): a
# render-refused entry (actionable-tier, no hard locator) is QUARANTINED — durably
# DEAD-LETTERED to $STATE_DIR/dead-letter.jsonl + a LOUD per-entry alarm — and
# EXCLUDED from this drain, while the REST of the cumulative set still renders
# (exit 0). The bad entry is accounted-for (never silently dropped); it can no
# longer wedge the whole drain (the live pilot defect: one malformed entry
# exit-4'd the entire cumulative-state drain, delivering NOTHING).
#
# #920 (amended FIX 2 — reconciler enumerations are ORIENTATION-tier): a
# reconciler ENUMERATION carries locators.reconciled==true (set ONLY by
# reconcile.sh). Enumerations are self-orienting STATE-POINTERS, never
# consequential claims, so they are EXEMPT from the actionable hard-locator gate
# and render as ORIENTATION pointers via _locator_line's digest-class vocabulary
# (kind/id/observed_hash/path/…). Their STORE class is left UNCHANGED (non-
# coalescing) so distinct enumerations never collapse (§2.3/T2/G3-R6 intact).
#
# BOUNDING / INJECTION / SECRETS (§2.1): link-not-inline (pointers + bounded
# summary; raw diffs/logs stay at rest). Source free-text is NEVER instruction-
@@ -71,8 +86,13 @@ Options:
--max-free-text N cap for a quoted untrusted block (default: 200 chars).
Exit codes:
0 digest rendered.
4 FAIL-LOUD: an actionable claim carried no hard locator (malformed digest).
0 digest rendered. Any render-refused ACTIONABLE entry (no §2.1 hard locator)
is QUARANTINED — DEAD-LETTERED to $STATE_DIR/dead-letter.jsonl + a loud
per-entry alarm — and EXCLUDED; the rest of the cumulative set still renders
(#920: fail-loud is per-entry, never a whole-drain wedge). Reconciler
enumerations (locators.reconciled==true) render ORIENTATION-tier, gate-exempt.
2 usage error.
3 jq is required but missing.
Environment:
WAKE_STATE_HOME override base state dir (XDG by default).
@@ -252,6 +272,68 @@ _free_text() {
' <<<"$1"
}
# _actionable_tier LINE — echo "1" iff the entry is ACTIONABLE-tier (subject to
# the §2.1 hard-locator gate and rendered as a CLAIM@seq), else "0". Shared by
# the quarantine pass AND the actionable render loop so both classify identically
# (no entry can render as a CLAIM@seq without having passed the gate).
#
# Actionable-tier = class "actionable" OR any entry whose locators carry a
# `claim` OR a top-level `claim` (a consequential fact) — matching the render
# tier's `.claim // .locators.claim` precedence.
#
# #920 (amended FIX 2): a reconciler ENUMERATION carries locators.reconciled==true
# (set ONLY by reconcile.sh — the detector's locator whitelist
# {kind,id,observed_hash}+{repo,path,anchor,remote,branches} cannot express it, so
# a source cannot forge it). Enumerations are ORIENTATION-tier state-pointers, NOT
# consequential claims, so they are EXEMPT from actionable classification (hence
# from the hard-locator/quarantine gate) and render as orientation pointers via
# _locator_line. Their STORE class is untouched (non-coalescing) so distinct
# enumerations never collapse (§2.3/T2/G3-R6 intact — the class=digest silent-drop
# that was REJECTED).
_actionable_tier() {
local line="$1" loc
loc="$(jq -c '.locators // {}' <<<"$line")"
# Orientation exemption FIRST: a reconciler enumeration is never actionable-tier.
if jq -e '(.reconciled // false) == true' >/dev/null 2>&1 <<<"$loc"; then
printf '0'
return 0
fi
if [ "$(jq -r '.class // "actionable"' <<<"$line")" = "actionable" ]; then
printf '1'
return 0
fi
if jq -e 'has("claim") and ((.claim // "") != "")' >/dev/null 2>&1 <<<"$loc"; then
printf '1'
return 0
fi
if jq -e 'has("claim") and ((.claim // "") != "")' >/dev/null 2>&1 <<<"$line"; then
printf '1'
return 0
fi
printf '0'
}
# _quarantine_entry LINE SEQ — QUARANTINE a render-refused entry (#920): append it
# verbatim to the durable dead-letter ledger ($STATE_DIR/dead-letter.jsonl, atomic
# write) and raise a LOUD per-entry fail-loud alarm on stderr. The entry is thereby
# accounted-for (never silently dropped) without wedging the rest of the
# cumulative-state drain. The append is idempotent (a still-pending malformed entry
# is re-drained every timer tick) so the ledger stays bounded. A dead-letter write
# failure is itself alarmed but never aborts the drain — the good entries MUST
# still deliver (availability is the whole point of #920).
_quarantine_entry() {
local line="$1" seq="$2" dlq="$STATE_DIR/dead-letter.jsonl"
if [ ! -f "$dlq" ] || ! grep -qxF "$line" "$dlq" 2>/dev/null; then
local existing
existing="$(cat "$dlq" 2>/dev/null || true)"
if ! printf '%s\n%s\n' "$existing" "$line" | grep -v '^[[:space:]]*$' | _atomic_write "$dlq"; then
echo "digest.sh: FAIL-LOUD QUARANTINE (#920) — malformed ACTIONABLE entry at observed_seq=$seq has no §2.1 hard locator AND the durable dead-letter write to $dlq FAILED. The entry is EXCLUDED from this digest and loudly surfaced here; investigate immediately." >&2
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
}
cmd_render() {
_need_jq
local src='store' from_file='' lane="${WAKE_LANE:-}" board_head='' \
@@ -284,35 +366,35 @@ cmd_render() {
local observed consumed depth
observed="$(_wake_read_int "$STATE_DIR/observed_seq" 0)"
consumed="$(_wake_read_int "$STATE_DIR/consumed_seq" 0)"
depth="$(printf '%s\n' "$pending" | grep -c . || true)"
# --- FAIL-LOUD PASS FIRST (§2.1): validate every actionable claim carries a
# hard locator BEFORE emitting a single byte. A malformed digest must never be
# partially sent. Actionable-tier = class "actionable" OR any entry whose
# locators carry a `claim` OR a top-level `claim` (a consequential fact) —
# matching the render tier's `.claim // .locators.claim` precedence, so no
# entry can render as a CLAIM@seq without passing this gate. -------------
local line class loc is_actionable
# --- QUARANTINE PASS FIRST (§2.1 fail-loud, PER-ENTRY — #920) --------------
# Partition the cumulative set into the DELIVERABLE set (pending_ok) and the
# render-refused entries. An ACTIONABLE-tier entry (per _actionable_tier) that
# carries NO §2.1 hard locator is QUARANTINED — durably DEAD-LETTERED + a loud
# per-entry alarm — and EXCLUDED, while every OTHER entry still renders (exit 0).
# This preserves fail-loud (the bad entry is accounted-for, never silently
# dropped) WITHOUT letting one malformed entry wedge the whole drain (the live
# #920 head-of-line-blocking defect that exit-4'd the entire cumulative-state
# drain). Reconciler enumerations (locators.reconciled==true) are ORIENTATION-
# tier and gate-exempt, so they pass straight through to the deliverable set.
local line loc seq pending_ok='' quarantined=0
while IFS= read -r line; do
[ -n "$line" ] || continue
printf '%s' "$line" | jq -e . >/dev/null 2>&1 || continue
class="$(jq -r '.class // "actionable"' <<<"$line")"
loc="$(jq -c '.locators // {}' <<<"$line")"
is_actionable=0
[ "$class" = "actionable" ] && is_actionable=1
if jq -e 'has("claim") and ((.claim // "") != "")' >/dev/null 2>&1 <<<"$loc"; then
is_actionable=1
fi
if jq -e 'has("claim") and ((.claim // "") != "")' >/dev/null 2>&1 <<<"$line"; then
is_actionable=1
fi
if [ "$is_actionable" = "1" ] && ! _has_hard_locator "$loc"; then
local seq
seq="$(jq -r '.observed_seq // "?"' <<<"$line")"
echo "digest.sh: FAIL-LOUD — malformed digest: actionable claim at observed_seq=$seq has no hard locator (repo+issue#/40-char SHA/file:anchor). Refusing to render (§2.1)." >&2
exit 4
if [ "$(_actionable_tier "$line")" = "1" ]; then
loc="$(jq -c '.locators // {}' <<<"$line")"
if ! _has_hard_locator "$loc"; then
seq="$(jq -r '.observed_seq // "?"' <<<"$line")"
_quarantine_entry "$line" "$seq"
quarantined=$((quarantined + 1))
continue
fi
fi
pending_ok="$pending_ok$line"$'\n'
done <<<"$pending"
# The deliverable cumulative set is the input MINUS the quarantined entries.
pending="$(printf '%s' "$pending_ok" | grep -v '^[[:space:]]*$' || true)"
depth="$(printf '%s\n' "$pending" | grep -c . || true)"
# --- render (all validated) ----------------------------------------------
local n_actionable=0
@@ -348,14 +430,13 @@ cmd_render() {
while IFS= read -r line; do
[ -n "$line" ] || continue
printf '%s' "$line" | jq -e . >/dev/null 2>&1 || continue
local aclass aloc a_is claim seq ft
aclass="$(jq -r '.class // "actionable"' <<<"$line")"
local aloc claim seq ft
# #920: _actionable_tier EXEMPTS reconciler enumerations (reconciled==true)
# so they never render as a CLAIM@seq — they are ORIENTATION-tier pointers
# only. Same classifier as the quarantine pass (single source of truth).
[ "$(_actionable_tier "$line")" = "1" ] || continue
aloc="$(jq -c '.locators // {}' <<<"$line")"
a_is=0
[ "$aclass" = "actionable" ] && a_is=1
claim="$(jq -r '.claim // (.locators.claim) // ""' <<<"$line")"
[ -n "$claim" ] && a_is=1
[ "$a_is" = "1" ] || continue
seq="$(jq -r '.observed_seq // "?"' <<<"$line")"
printf ' * seq %s — CLAIM@seq (point-in-time; UNTRUSTED — VERIFY LIVE, do NOT act on this line):\n' "$seq"
if [ -n "$claim" ]; then