fix(wake): #946 digest ack watermark clamped at quarantined seqs — disclose AND clamp
ci/woodpecker/pr/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
The embedded ack suggestion covered dead-lettered entries: quarantine is a render-time filter (0.6.14), so `ack.sh consumed --upto <observed_seq>` stepped the cursor past quarantined seqs and _record_last_consumed wrote consumed-hash witness rows for deliveries that never happened (live: mos-dt seq 68 buried under five successive digests; Finding A: a false 9d0f639f…@63 witness row). Fix, per the ruled disposition on #946: - digest.sh: rendered digest gains a QUARANTINED section (seq + class + HELD only — ids and locator values stay withheld, preserving the exclusion property); embedded ack clamped to min(observed_seq, min quarantined seq - 1) with a loud "# ACK CLAMPED (#946)" note; render --from-store syncs the store-owned quarantined.set via `store.sh quarantine-sync` (full replace — a gate fix self-heals stale quarantine); --from-file/--stdin never touch the set. - store.sh: consume REFUSES to cross an unconsumed quarantined seq; `--force-past-quarantine` is the ONLY way past, loud per-seq on stderr, and even the forced path never writes a consumed-hash witness for a quarantined seq; crossed seqs are pruned from the set after the cursor moves. New `quarantine-sync` (stdin seqs, full replace, invalid input is a loud no-op) and `quarantine-audit [--repair]` (sweeps consumed-hashes for rows provably contradicted by the dead-letter ledger; report exits 1; --repair removes only provably-false rows; the ledger is history and never modified; rows whose dead-letter evidence was pruned are unprovable and untouched). - ack.sh: plumbs --force-past-quarantine through to store consume; forced- path loudness is re-emitted on stderr while `CONSUMED <n>` stays clean. Tests: test-wake-store-ack.sh T13-T16 (34 assertions RED at base), test-wake-digest-quarantine.sh Q12-Q16 (10 RED at base; Q13/Q16 green-by-design controls). All nine wake suites green. version=0.6.15. Closes #946 Written-by: pepper (sb-it-1-dt) Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01NsKce8iZuSuRnu3gVMCBKB
This commit is contained in:
co-authored by
Claude Fable 5
parent
a6b5f6a01a
commit
e11bc66223
@@ -112,6 +112,14 @@ Exit codes:
|
||||
diagnostic (#924/G2a) — it never wedges the whole render either.
|
||||
Reconciler enumerations (locators.reconciled==true) render ORIENTATION-tier,
|
||||
gate-exempt.
|
||||
#946: quarantined entries are DISCLOSED in a QUARANTINED section (by
|
||||
seq/class only — content stays excluded) and the embedded ack copy-run
|
||||
line is CLAMPED below the lowest quarantined seq (the digest never
|
||||
instructs the consumer to record a delivery that never happened; the
|
||||
clamp is announced as an ACK CLAMPED note). A store-mode render also
|
||||
REPLACES the store's quarantined.set (store.sh quarantine-sync) so the
|
||||
consume path enforces the same clamp; --from-file/--stdin renders never
|
||||
touch the set.
|
||||
2 usage error.
|
||||
3 jq is required but missing.
|
||||
|
||||
@@ -544,7 +552,7 @@ cmd_render() {
|
||||
# #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
|
||||
local line loc seq pending_ok='' quarantined=0 q_seqs='' q_disclose=''
|
||||
while IFS= read -r line; do
|
||||
[ -n "$line" ] || continue
|
||||
printf '%s' "$line" | jq -e . >/dev/null 2>&1 || continue
|
||||
@@ -554,6 +562,17 @@ cmd_render() {
|
||||
seq="$(jq -r '.observed_seq // "?"' <<<"$line")"
|
||||
_quarantine_entry "$line" "$seq"
|
||||
quarantined=$((quarantined + 1))
|
||||
# #946: collect the quarantined identity for DISCLOSURE + the ack
|
||||
# CLAMP. Disclosure is by durable identity (observed_seq) + class ONLY:
|
||||
# this entry failed the locator gate, so its content is exactly what
|
||||
# this digest refuses to re-inject (the exclusion property Q1/Q4
|
||||
# assert) — the consumer re-verifies via the dead-letter ledger, never
|
||||
# via this line.
|
||||
case "$seq" in
|
||||
'' | *[!0-9]*) : ;; # an unnumbered entry cannot clamp the numeric cursor
|
||||
*) q_seqs="$q_seqs$seq"$'\n' ;;
|
||||
esac
|
||||
q_disclose="$q_disclose * seq $seq [$(_scrub_inline "$(jq -r '.class // "actionable"' <<<"$line")")] HELD — dead-lettered (no §2.1 hard locator); content withheld, NOT delivered."$'\n'
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
@@ -563,6 +582,33 @@ cmd_render() {
|
||||
pending="$(printf '%s' "$pending_ok" | grep -v '^[[:space:]]*$' || true)"
|
||||
depth="$(printf '%s\n' "$pending" | grep -c . || true)"
|
||||
|
||||
# --- #946: quarantine truth-sync + ack clamp ------------------------------
|
||||
# (1) SYNC: an AUTHORITATIVE full-set render (src=store) REPLACES the store's
|
||||
# quarantined.set with THIS render's quarantined seqs (possibly none — an
|
||||
# empty replace IS the #944 recovery: once the gate is fixed and everything
|
||||
# renders, the stale set clears and the store-side clamp self-heals). A
|
||||
# foreign-data render (--from-file/--stdin) must NEVER rewrite lane truth.
|
||||
if [ "$src" = "store" ]; then
|
||||
if ! printf '%s' "$q_seqs" | "$STORE_SH" quarantine-sync; then
|
||||
echo "digest.sh: WARN (#946) — store.sh quarantine-sync FAILED; the store-side consume clamp may be stale for this lane (the clamped ack line rendered below is still correct)." >&2
|
||||
fi
|
||||
fi
|
||||
# (2) CLAMP: the embedded ack may advance AT MOST to just below the LOWEST
|
||||
# quarantined seq — consume requires a contiguous prefix, so one held seq
|
||||
# caps everything above it. With nothing quarantined this is the observed
|
||||
# cursor unchanged. Render-local on purpose: it protects the copy-run line in
|
||||
# EVERY mode, including hermetic --from-file renders.
|
||||
local ack_upto="$observed" min_q='' qs q_list=''
|
||||
while IFS= read -r qs; do
|
||||
[ -n "$qs" ] || continue
|
||||
if [ -z "$min_q" ] || [ "$qs" -lt "$min_q" ]; then min_q="$qs"; fi
|
||||
done <<<"$q_seqs"
|
||||
if [ -n "$min_q" ] && [ "$((min_q - 1))" -lt "$ack_upto" ]; then
|
||||
ack_upto=$((min_q - 1))
|
||||
fi
|
||||
[ "$ack_upto" -ge 0 ] || ack_upto=0
|
||||
q_list="$(printf '%s' "$q_seqs" | tr '\n' ' ' | sed -e 's/[[:space:]]*$//')"
|
||||
|
||||
# --- render (all validated) ----------------------------------------------
|
||||
local n_actionable=0
|
||||
{
|
||||
@@ -656,6 +702,16 @@ cmd_render() {
|
||||
printf '%s\n' "$hbody"
|
||||
fi
|
||||
|
||||
# #946: QUARANTINED disclosure — a held entry must be VISIBLE in the digest
|
||||
# it was held from (five successive live digests each silently stepped the
|
||||
# consumer past buried seq 68). Disclosure is by seq/class ONLY; the
|
||||
# entry's content already failed the locator gate and stays EXCLUDED.
|
||||
if [ -n "$q_disclose" ]; then
|
||||
printf '\n-- QUARANTINED (dead-lettered; HELD — NOT delivered; the ack below does NOT cover these) --\n'
|
||||
printf '%s' "$q_disclose"
|
||||
printf ' disposition: see %s/dead-letter.jsonl — fix the source locator (re-delivery is automatic once the entry passes the gate), or step past EXPLICITLY with ack.sh consumed --force-past-quarantine.\n' "$STATE_DIR"
|
||||
fi
|
||||
|
||||
# Embedded ack copy-run line (W2). CONSUMED is a consumer act; this is the
|
||||
# exact local-write line the consumer runs after durable capture.
|
||||
#
|
||||
@@ -670,12 +726,19 @@ cmd_render() {
|
||||
# itself was env-less (agent=="default"), baking "default" is no worse than
|
||||
# today — the fix wins the common case where WAKE_AGENT was set at render.
|
||||
printf '\n-- ACK (copy-run; local-write only, never blocks on network) --\n'
|
||||
# #946: the embedded --upto is the CLAMPED cursor (ack_upto), never the raw
|
||||
# observed cursor while a quarantined seq sits inside (consumed, observed] —
|
||||
# the copy-run line itself must not instruct the consumer to record
|
||||
# deliveries that never happened. The clamp is disclosed loudly.
|
||||
if [ "$ack_upto" -ne "$observed" ]; then
|
||||
printf '# ACK CLAMPED (#946): embedding --upto %s, not observed_seq %s — quarantined seq(s) %s were dead-lettered and NEVER delivered; an ordinary ack cannot step past them. Only ack.sh consumed ... --force-past-quarantine (loud) can.\n' "$ack_upto" "$observed" "$q_list"
|
||||
fi
|
||||
local ack_line agent_scrubbed
|
||||
agent_scrubbed="$(_scrub_inline "$agent")"
|
||||
if [ -n "$wake_id" ]; then
|
||||
ack_line="$("$ACK_SH" embed --upto "$observed" --agent "$agent_scrubbed" --wake-id "$wake_id" 2>/dev/null || true)"
|
||||
ack_line="$("$ACK_SH" embed --upto "$ack_upto" --agent "$agent_scrubbed" --wake-id "$wake_id" 2>/dev/null || true)"
|
||||
else
|
||||
ack_line="$("$ACK_SH" embed --upto "$observed" --agent "$agent_scrubbed" 2>/dev/null || true)"
|
||||
ack_line="$("$ACK_SH" embed --upto "$ack_upto" --agent "$agent_scrubbed" 2>/dev/null || true)"
|
||||
fi
|
||||
printf '%s\n' "${ack_line:-# ack unavailable}"
|
||||
} | _redact_secrets
|
||||
|
||||
Reference in New Issue
Block a user