#!/usr/bin/env bash
# store.sh — A2 of the wake canon (EPIC #892, W2): the THREE-CURSOR durable
# queue (store + drain lib).
#
# CONTRACT ANCHORS (docs/scratchpads/heartbeat-planning/CONVERGED-DESIGN.md):
#   §1.2  three-cursor data-flow: observe -> durable store -> coalesce -> drain.
#   §2.3  classes & durability: ALL classes durable; coalescing is optional.
#   §2.4  cursor semantics: observed_seq is authoritative; SHAs are descriptors.
#
# Three cursors:
#   observed_seq  (store-owned SINGLE ALLOCATOR, #908) — monotonic int assigned by
#                 THIS lib at enqueue: next = observed_seq + 1, under an exclusive
#                 lock, committed IFF the durable write succeeds. Authoritative.
#                 There is exactly ONE allocator (this store); the detector and
#                 reconciler no longer allocate independently. Source SHAs are
#                 descriptors, NOT the cursor (§2.4).
#   pending-inbox (durable) — append store; retains until CONSUMED; survives
#                 pane death / park / restart.
#   consumed_seq  (consumer-owned) — advances ONLY on a CONSUMED ack, over a
#                 CONTIGUOUS gapless prefix <=N. NEVER on sender exit-0 / paste.
#
# Coalesce (§1.2/§2.3): class=digest REPLACES the pending cumulative-state entry
# (newest subsumes prior). Non-coalescible classes (actionable, human, ...)
# APPEND. ALL classes are stored durably — durability is NEVER bypassed.
# Absent class => treated as `actionable` (fail-safe).
#
# HMAC: entries carry an `hmac` field left as an UNSIGNED PLACEHOLDER ("").
# Signing is W3/A5, explicitly NOT W2.
#
# Every state mutation is atomic write-tmp+rename (see _wake-common.sh).
#
# Operator-agnostic: state via XDG/env only; no operator paths/names/secrets.
set -uo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=./_wake-common.sh disable=SC1091
. "$SCRIPT_DIR/_wake-common.sh"

STATE_DIR="$(wake_state_dir)"

_need_jq() {
  command -v jq >/dev/null 2>&1 || {
    echo "store.sh: jq is required" >&2
    exit 3
  }
}

usage() {
  cat >&2 <<'EOF'
Usage: store.sh <command> [options]

Commands:
  init                                   Create/repair the XDG state layout.
  enqueue [--class C] [opts]             Record an observation into the durable
                                         pending-inbox (coalesce or append) and
                                         ALLOCATE its observed_seq. store.sh is the
                                         SOLE allocator of observed_seq (#908):
                                         under an exclusive enqueue lock it reads
                                         the observed_seq cursor, sets
                                         next = observed_seq + 1, writes the
                                         pending record + observed.set + the cursor
                                         as ONE transaction, and PRINTS next to
                                         stdout. The cursor advances IFF the durable
                                         write succeeds (no burn-before-enqueue).
      --seq N            LEGACY explicit observed_seq (optional). Normal callers
                         (detector, reconciler) OMIT this and let the store
                         allocate. Retained only for tests/tools that must place a
                         SPECIFIC seq (e.g. construct a gap). An explicit seq that
                         is <= consumed_seq is REFUSED loudly (anti-swallow): the
                         idempotent-ignore path can never silently drop a wake.
      --class C          digest|actionable|human|terminal-log|reaction.
                         Absent/empty => actionable (fail-safe).
      --locators JSON    JSON value for the entry's locators (default {}).
      --emit-ts TS       epoch seconds (default: now).
  drain [--require-idle-cmd CMD]         Emit the deliverable set (pending-inbox,
                                         coalesced) as JSONL. WHAT to deliver;
                                         the actual paste is out of scope.
                                         If --require-idle-cmd is given and it
                                         exits non-zero, emit nothing (not idle).
  consume --upto N [--force-past-quarantine]
                                         Advance consumed_seq over the contiguous
                                         gapless prefix <=N; drop consumed
                                         entries. Rejects a gap (cannot ack N
                                         while N-1 is unconsumed). Cumulative &
                                         idempotent. REFUSES to advance past a
                                         QUARANTINED seq (#946): a quarantined
                                         entry was dead-lettered at render and
                                         never delivered in any digest, so an
                                         ordinary ack may not record it consumed.
                                         --force-past-quarantine is the ONLY way
                                         past — loud per stepped-over seq, and
                                         even then NO consumed-hash witness is
                                         recorded for the quarantined entry.
  quarantine-sync                        REPLACE the store-owned quarantined.set
                                         with the observed_seqs read from stdin
                                         (one per line; empty input CLEARS).
                                         Called by digest.sh after each
                                         authoritative store render — the set is
                                         re-DERIVED per render, never accumulated,
                                         so a fixed locator gate self-heals the
                                         consume clamp (#944 recovery).
  quarantine-audit [--repair]            Report consumed-hashes rows that are
                                         PROVABLY FALSE: the row matches a
                                         dead-letter ledger entry on
                                         (kind,id,observed_seq,observed_hash) at
                                         or below consumed_seq — i.e. the recorded
                                         consumption was of a quarantined,
                                         never-delivered entry (#946 Finding A).
                                         Report-only by default (exit 1 when any
                                         found); --repair removes exactly those
                                         rows (atomic, loud). The dead-letter
                                         ledger itself is NEVER modified (it is
                                         history). TWO residual classes are
                                         unprovable and never touched (#952):
                                         rows whose dead-letter evidence was
                                         pruned away, AND rows whose surviving
                                         evidence extracts an empty
                                         observed_hash (it can never satisfy
                                         the four-field conviction match).
  cursors                                Print observed_seq / consumed_seq / depth.

Environment:
  WAKE_STATE_HOME  override base (default ${XDG_STATE_HOME:-$HOME/.local/state}/mosaic/wake)
  WAKE_AGENT       per-agent queue namespace (default: default)
EOF
}

cmd_init() {
  _wake_init_dir "$STATE_DIR" || {
    echo "store.sh: failed to init $STATE_DIR" >&2
    exit 1
  }
  # Maintenance/daemon-start stale-tmp reap (#927). Cleanup is OFF the per-enqueue
  # hot path; `init` is a natural once-per-start maintenance point. It is
  # age-scoped, so even if an operator runs `init` while an enqueue is in flight
  # it can only reap demonstrably-orphaned (crash-left) tmps, never a live write.
  _wake_clean_stale_tmp "$STATE_DIR"
  echo "$STATE_DIR"
}

cmd_enqueue() {
  _need_jq
  local seq='' class='' locators='{}' emit_ts=''
  while [ $# -gt 0 ]; do
    case "$1" in
    --seq)
      seq="${2:-}"
      shift 2
      ;;
    --class)
      class="${2:-}"
      shift 2
      ;;
    --locators)
      locators="${2:-}"
      shift 2
      ;;
    --emit-ts)
      emit_ts="${2:-}"
      shift 2
      ;;
    *)
      echo "store.sh enqueue: unknown option '$1'" >&2
      exit 2
      ;;
    esac
  done

  # --seq is OPTIONAL (#908): normal callers omit it and the store allocates.
  # If supplied (legacy/explicit), it must be a non-negative integer.
  local explicit=0
  if [ -n "$seq" ]; then
    explicit=1
    case "$seq" in
    *[!0-9]*)
      echo "store.sh enqueue: --seq must be a non-negative integer" >&2
      exit 2
      ;;
    esac
  fi

  # Absent class => actionable (fail-safe, §2.3).
  [ -n "$class" ] || class="actionable"
  case "$class" in
  digest | actionable | human | terminal-log | reaction) : ;;
  *)
    echo "store.sh enqueue: unknown class '$class'" >&2
    exit 2
    ;;
  esac

  [ -n "$emit_ts" ] || emit_ts="$(date +%s)"
  case "$emit_ts" in
  *[!0-9]*)
    echo "store.sh enqueue: --emit-ts must be epoch seconds" >&2
    exit 2
    ;;
  esac

  # Validate locators is well-formed JSON.
  if ! printf '%s' "$locators" | jq -e . >/dev/null 2>&1; then
    echo "store.sh enqueue: --locators must be valid JSON" >&2
    exit 2
  fi

  # Ensure the layout exists. NB (#927): _wake_init_dir NO LONGER reaps stale
  # tmps — that would race a concurrent enqueue's live in-flight write (deleting
  # its tmp mid-rename -> spurious "durable pending write FAILED"). Stale-tmp
  # reaping is a maintenance action (store.sh init / detector tick), never on this
  # hot path.
  _wake_init_dir "$STATE_DIR"

  # --- serialize the whole allocate+write transaction (#908) ----------------
  # A single store-side allocator means the read of observed_seq, the durable
  # write, and the cursor bump MUST be one critical section: two concurrent
  # enqueues that both read observed_seq=N would otherwise both allocate N+1 and
  # collide. The lock (flock where present) makes concurrent enqueues get
  # DISTINCT seqs.
  _wake_lock_acquire "$STATE_DIR/.enqueue.lock" || {
    echo "store.sh enqueue: could not acquire the enqueue lock ($STATE_DIR/.enqueue.lock)" >&2
    exit 1
  }

  local consumed observed
  consumed="$(_wake_read_int "$STATE_DIR/consumed_seq" 0)"
  observed="$(_wake_read_int "$STATE_DIR/observed_seq" 0)"

  if [ "$explicit" -eq 0 ]; then
    # ALLOCATE: the store is the sole allocator. next = observed_seq + 1.
    seq=$((observed + 1))
  fi

  # --- anti-swallow FAIL-LOUD (#908, arrow #3) ------------------------------
  # observed_seq >= consumed_seq always (consumed advances only over the gapless
  # observed prefix), so an ALLOCATED next = observed+1 is ALWAYS > consumed. The
  # old "seq <= consumed => idempotent no-op" path is therefore UNREACHABLE for an
  # allocation; if it is ever reached the store is inconsistent (corruption) — we
  # FAIL LOUD, never a silent no-op. For a LEGACY explicit --seq, a seq inside the
  # consumed prefix is likewise refused loudly so it can never silently swallow a
  # fresh obligation (the migration-restart killer must be structurally impossible).
  if [ "$seq" -le "$consumed" ]; then
    _wake_lock_release
    if [ "$explicit" -eq 1 ]; then
      echo "store.sh enqueue: REFUSED explicit --seq $seq <= consumed_seq $consumed — anti-swallow (#908): a seq inside the consumed prefix is never a fresh obligation and must NEVER be silently ignored." >&2
    else
      echo "store.sh enqueue: FAIL LOUD (#908 allocation invariant) — computed observed_seq $seq <= consumed_seq $consumed (observed_seq cursor=$observed). The store is inconsistent; refusing to allocate rather than silently no-op." >&2
    fi
    exit 1
  fi

  # Build the durable entry. `hmac` is an UNSIGNED PLACEHOLDER (W3/A5 signs it).
  local entry
  entry="$(jq -cn \
    --argjson seq "$seq" \
    --arg class "$class" \
    --argjson locators "$locators" \
    --argjson emit_ts "$emit_ts" \
    '{observed_seq:$seq, locators:$locators, class:$class, emit_ts:$emit_ts, hmac:""}')" || {
    _wake_lock_release
    echo "store.sh enqueue: failed to build entry" >&2
    exit 1
  }

  # --- durable store write (coalesce vs append) -----------------------------
  # digest: REPLACE the single pending cumulative-state entry (drop any existing
  #         digest lines, then append the newest). Newest subsumes prior.
  # others: APPEND (never replaced).
  # In BOTH cases the entry lands in the durable store.
  #
  # ORDERING (#908, arrow #1 — no burn-before-enqueue): the durable pending write
  # comes FIRST and its failure ABORTS before the observed.set / observed_seq
  # cursor writes. The cursor advances IFF the durable pending write succeeds, so
  # a failed enqueue can never burn a seq that never reached the store.
  local new_pending
  if [ "$class" = "digest" ]; then
    new_pending="$(jq -c 'select(.class != "digest")' "$STATE_DIR/pending.jsonl" 2>/dev/null || true)"
    new_pending="$(printf '%s\n%s\n' "$new_pending" "$entry" | grep -v '^[[:space:]]*$' || true)"
  else
    new_pending="$(cat "$STATE_DIR/pending.jsonl" 2>/dev/null; printf '%s\n' "$entry")"
    new_pending="$(printf '%s' "$new_pending" | grep -v '^[[:space:]]*$' || true)"
  fi
  if ! printf '%s\n' "$new_pending" | grep -v '^[[:space:]]*$' | _atomic_write "$STATE_DIR/pending.jsonl"; then
    _wake_lock_release
    echo "store.sh enqueue: durable pending write FAILED for seq $seq — observed_seq cursor NOT advanced (no burned seq, no interior gap)." >&2
    exit 1
  fi

  # --- observed.set: record the seq in the live window (gap-detector SoT) ----
  # Snapshot observed.set's prior content FIRST: if the final cursor write below
  # fails AFTER this write advances observed.set, we roll observed.set back to this
  # snapshot so observed.set can never be left cross-file inconsistent with the
  # cursor (#917 — observed.set ahead of a cursor that never committed).
  local prev_observed_set
  prev_observed_set="$(cat "$STATE_DIR/observed.set" 2>/dev/null || true)"
  if ! {
    printf '%s' "$prev_observed_set"
    printf '\n%s\n' "$seq"
  } | grep -v '^[[:space:]]*$' | sort -n | uniq | _atomic_write "$STATE_DIR/observed.set"; then
    _wake_lock_release
    echo "store.sh enqueue: observed.set write FAILED for seq $seq — observed_seq cursor NOT advanced." >&2
    exit 1
  fi

  # --- observed_seq cursor: max monotonic int (COMMIT of the allocation) -----
  # Written LAST: only now, after the durable pending + observed.set writes
  # succeeded, does the cursor advance. This is the atomic commit point of the
  # allocation.
  #
  # #917 (defense-in-depth): this final write is GATED like the pending/observed.set
  # writes (#908) — its failure is FAIL-LOUD, never silently swallowed (which would
  # return success while the allocation stayed uncommitted). And because observed.set
  # was already advanced just above, a cursor-write failure would leave observed.set
  # ahead of the cursor (cross-file inconsistent); so on failure we ROLL observed.set
  # BACK to its pre-write snapshot before failing loud. Net: observed.set and the
  # cursor either BOTH advance or NEITHER does — never a stranded observed.set entry
  # above the cursor. (The pending write may remain ahead, exactly as #908 already
  # tolerates on the observed.set-failure path: the cursor is the sole COMMIT point,
  # so an uncommitted pending entry is re-derived/reconciled, never consumed — the
  # allocation is simply not committed.) On-disk format is UNCHANGED (read-compatible).
  if [ "$seq" -gt "$observed" ]; then
    if ! printf '%s' "$seq" | _atomic_write "$STATE_DIR/observed_seq"; then
      printf '%s' "$prev_observed_set" | grep -v '^[[:space:]]*$' | _atomic_write "$STATE_DIR/observed.set" || true
      _wake_lock_release
      echo "store.sh enqueue: observed_seq cursor write FAILED for seq $seq — allocation NOT committed; rolled observed.set back so it stays consistent with the cursor (#917)." >&2
      exit 1
    fi
  fi

  _wake_lock_release

  # Print the allocated observed_seq to stdout (sole-allocator contract): the
  # detector/reconciler capture it for logging/locators/emit.
  printf '%s\n' "$seq"
}

cmd_drain() {
  local idle_cmd=''
  while [ $# -gt 0 ]; do
    case "$1" in
    --require-idle-cmd)
      idle_cmd="${2:-}"
      shift 2
      ;;
    *)
      echo "store.sh drain: unknown option '$1'" >&2
      exit 2
      ;;
    esac
  done

  # Drain returns the deliverable set ONLY when the pane is idle-at-prompt. The
  # actual idle detection + paste is out of W2 scope (send-message.sh); the
  # caller supplies an idle predicate. No predicate => emit unconditionally.
  if [ -n "$idle_cmd" ]; then
    if ! sh -c "$idle_cmd" >/dev/null 2>&1; then
      return 0 # not idle-at-prompt: deliver nothing this cycle.
    fi
  fi

  [ -f "$STATE_DIR/pending.jsonl" ] || return 0
  grep -v '^[[:space:]]*$' "$STATE_DIR/pending.jsonl" 2>/dev/null || true
}

# _record_last_consumed UPTO — #932: at consume-truncation, record the
# last-consumed observed_hash per (kind,id) into a STORE-OWNED durable record
# (consumed-hashes.jsonl). This is the record the reconciler consults as its
# THIRD accounting source: after consume truncates the pending prefix, a consumed
# state matches NEITHER the inbox (truncated) NOR the reconciler's seen-ledger
# (which only covers the reconciler's OWN enumerations), so the reconciler used
# to treat it as UNACCOUNTED and re-enumerate it — one duplicate orientation wake
# + one spurious rc=1 CRITICAL per detector-active window per cycle (safe but
# noisy; G2a alarm-hygiene at fleet scale).
#
# Called BEFORE the pending prefix is dropped (it reads the entries being
# consumed). For each entry with observed_seq <= UPTO that carries full source
# locators (kind,id,observed_hash), keep the HIGHEST-seq hash per (kind,id) as
# that source's last-consumed state; merge with any prior record (monotonic —
# consume only advances, so a newer consume's seq always wins its key).
#
# TRUST BOUNDARY (load-bearing): this record is written ONLY here, at CONSUME of a
# durably-enqueued entry, so its existence implies the state WAS durably
# enqueued+consumed. It therefore structurally cannot exhibit the §5 swallow-hole
# signature (hash-advance-WITHOUT-enqueue). It is a STORE record — the detector's
# own hash-file stays DISTRUSTED and is never consulted for accounting.
#
# ADDITIVE: a new file consumed-hashes.jsonl; the existing on-disk format is
# unchanged and read-compatible (older code ignores this file). Atomic write.
# Best-effort: a failure here degrades to the pre-#932 safe-but-noisy behaviour
# (the reconciler re-enumerates the consumed state once — no lost obligation),
# never a failed consume.
_record_last_consumed() {
  local upto="$1" existing new_records merged qjson
  [ -f "$STATE_DIR/pending.jsonl" ] || return 0
  # #946: seqs in quarantined.set are EXCLUDED from the record — the trust
  # boundary above says "existence implies durably enqueued+CONSUMED", but a
  # quarantined entry was dead-lettered at render and NEVER delivered, so a row
  # for it would witness a delivery that never happened. This holds even on the
  # FORCED step-over path: the reconciler re-enumerating the state once is
  # safe-but-noisy; a false witness silences it forever.
  qjson="$(jq -nR -c '[inputs | select(length > 0) | tonumber? // empty]' "$STATE_DIR/quarantined.set" 2>/dev/null || true)"
  [ -n "$qjson" ] || qjson='[]'
  new_records="$(jq -c --argjson upto "$upto" --argjson quarantined "$qjson" '
    (.observed_seq // -1) as $seq
    | select($seq <= $upto)
    | select(($quarantined | index($seq)) == null)
    | select((.locators.kind // "") != "" and (.locators.id // "") != "" and (.locators.observed_hash // "") != "")
    | {kind:.locators.kind, id:.locators.id, observed_hash:.locators.observed_hash, observed_seq:.observed_seq}
  ' "$STATE_DIR/pending.jsonl" 2>/dev/null || true)"
  [ -n "$new_records" ] || return 0
  existing="$(cat "$STATE_DIR/consumed-hashes.jsonl" 2>/dev/null || true)"
  merged="$(printf '%s\n%s\n' "$existing" "$new_records" | grep -v '^[[:space:]]*$' |
    jq -s -c 'group_by([.kind, .id]) | .[] | max_by(.observed_seq)' 2>/dev/null || true)"
  [ -n "$merged" ] || return 0
  if ! printf '%s\n' "$merged" | grep -v '^[[:space:]]*$' | _atomic_write "$STATE_DIR/consumed-hashes.jsonl"; then
    echo "store.sh consume: WARN — could not record last-consumed hashes (#932); the reconciler may re-enumerate the consumed state once (safe-but-noisy), no lost obligation." >&2
  fi
}

cmd_consume() {
  local upto='' force=0
  while [ $# -gt 0 ]; do
    case "$1" in
    --upto)
      upto="${2:-}"
      shift 2
      ;;
    --force-past-quarantine)
      force=1
      shift
      ;;
    *)
      echo "store.sh consume: unknown option '$1'" >&2
      exit 2
      ;;
    esac
  done
  case "$upto" in
  '' | *[!0-9]*)
    echo "store.sh consume: --upto must be a non-negative integer" >&2
    exit 2
    ;;
  esac

  _need_jq
  _wake_init_dir "$STATE_DIR"

  local consumed observed
  consumed="$(_wake_read_int "$STATE_DIR/consumed_seq" 0)"
  observed="$(_wake_read_int "$STATE_DIR/observed_seq" 0)"

  # Cumulative & idempotent: CONSUMED N implies all <=N. N already covered is a
  # no-op success (the sender checks cursor-advanced-past-X, not per-wake).
  if [ "$upto" -le "$consumed" ]; then
    echo "$consumed"
    return 0
  fi

  # Never consume beyond what was observed.
  if [ "$upto" -gt "$observed" ]; then
    echo "store.sh consume: cannot CONSUMED $upto beyond observed_seq $observed" >&2
    exit 1
  fi

  # CONTIGUOUS gapless prefix: every seq in (consumed, upto] must have been
  # observed. A missing interior seq is a GAP => reject (cannot ack N while N-1
  # is unconsumed). observed.set is coalescing-immune, so a subsumed digest seq
  # still counts as observed and does not read as a gap.
  local k
  k=$((consumed + 1))
  while [ "$k" -le "$upto" ]; do
    if ! grep -qxF "$k" "$STATE_DIR/observed.set" 2>/dev/null; then
      echo "store.sh consume: gap at seq $k — cannot CONSUMED $upto while $k is unobserved/unconsumed" >&2
      exit 1
    fi
    k=$((k + 1))
  done

  # --- #946 quarantine CLAMP -------------------------------------------------
  # A quarantined seq was DEAD-LETTERED at render (no §2.1 hard locator): it was
  # never delivered in any digest, so advancing consumed_seq past it would record
  # consumption of an entry the consumer has never seen. The ordinary path
  # REFUSES; --force-past-quarantine is the ONLY way past, and it is loud per
  # stepped-over seq. digest.sh re-derives the set at each authoritative store
  # render (quarantine-sync REPLACE), so a fixed locator gate self-heals this
  # clamp without operator action.
  local qfile="$STATE_DIR/quarantined.set" blocked='' q
  if [ -s "$qfile" ]; then
    while IFS= read -r q; do
      case "$q" in '' | *[!0-9]*) continue ;; esac
      if [ "$q" -gt "$consumed" ] && [ "$q" -le "$upto" ]; then
        blocked="$blocked $q"
      fi
    done <"$qfile"
  fi
  if [ -n "$blocked" ]; then
    if [ "$force" -eq 0 ]; then
      echo "store.sh consume: REFUSED (#946 quarantine clamp) — quarantined seq(s):$blocked inside (consumed_seq=$consumed, upto=$upto] were dead-lettered at render and NEVER delivered in any digest. Advancing past them would record consumption of entries the consumer has never seen. Disposition them (see $STATE_DIR/dead-letter.jsonl) or step over EXPLICITLY with --force-past-quarantine." >&2
      exit 1
    fi
    for q in $blocked; do
      echo "store.sh consume: FORCED PAST QUARANTINE (#946) — stepping consumed_seq over quarantined seq $q (dead-lettered, NEVER delivered). No consumed-hash witness is recorded for it; the obligation stays visible ONLY in $STATE_DIR/dead-letter.jsonl." >&2
    done
  fi

  # #932: record the last-consumed observed_hash per (kind,id) BEFORE the pending
  # prefix is dropped (this reads the entries about to be truncated), so the
  # reconciler can recognise an already-consumed state as ACCOUNTED instead of
  # re-enumerating it. Additive, store-owned, best-effort (never fails consume).
  _record_last_consumed "$upto"

  # Advance the consumer cursor and drop the now-consumed prefix from the
  # durable store (retain-until-CONSUMED is satisfied).
  jq -c "select(.observed_seq > $upto)" "$STATE_DIR/pending.jsonl" 2>/dev/null |
    grep -v '^[[:space:]]*$' | _atomic_write "$STATE_DIR/pending.jsonl" || true
  awk -v c="$upto" 'NF && $1+0 > c' "$STATE_DIR/observed.set" 2>/dev/null |
    _atomic_write "$STATE_DIR/observed.set" || true
  printf '%s' "$upto" | _atomic_write "$STATE_DIR/consumed_seq"
  # #946: on a forced step-over, PRUNE the stepped-over seqs from quarantined.set
  # (they are inside the consumed prefix now; a stale entry would re-refuse the
  # next consume forever). Mirrors the observed.set prune idiom above.
  if [ -n "$blocked" ]; then
    awk -v c="$upto" 'NF && $1+0 > c' "$qfile" 2>/dev/null |
      _atomic_write "$qfile" || true
  fi
  echo "$upto"
}

# cmd_quarantine_sync — #946: REPLACE the store-owned quarantined.set with the
# observed_seqs read from stdin (one per line). Called by digest.sh after each
# AUTHORITATIVE full-set render (src=store): the set is re-DERIVED per render,
# never accumulated, so a fixed locator gate self-heals the consume clamp (the
# #944 recovery case — a cumulative-forever set would keep refusing acks on
# entries that now render). Empty input CLEARS the set. Foreign-data renders
# (--from-file/--stdin) never call this. Atomic write; invalid input is refused
# loudly with the set left untouched.
cmd_quarantine_sync() {
  [ $# -eq 0 ] || {
    echo "store.sh quarantine-sync: takes no options (observed_seqs on stdin, one per line)" >&2
    exit 2
  }
  local seq list=''
  while IFS= read -r seq; do
    [ -n "$seq" ] || continue
    case "$seq" in
    *[!0-9]*)
      echo "store.sh quarantine-sync: invalid observed_seq '$seq' — one non-negative integer per line; set left untouched" >&2
      exit 2
      ;;
    esac
    list="$list$seq"$'\n'
  done
  _wake_init_dir "$STATE_DIR"
  if ! { printf '%s' "$list" | grep -v '^[[:space:]]*$' || true; } | sort -n | uniq | _atomic_write "$STATE_DIR/quarantined.set"; then
    echo "store.sh quarantine-sync: quarantined.set write FAILED — the consume clamp may be stale for this lane" >&2
    exit 1
  fi
}

# cmd_quarantine_audit — #946 Finding A: the pre-#946 consume recorded
# consumed-hash rows for QUARANTINED (never-delivered) entries — false
# witnesses that silence the reconciler for keys whose only "consumption" was a
# dead-lettered entry (live: safe by population only where the key re-emitted
# and a later seq won the per-key max_by merge; keys that never recurred keep
# the false row forever).
#
# A row is PROVABLY FALSE iff the dead-letter ledger contains an entry matching
# it on (kind, id, observed_seq, observed_hash) AND row.observed_seq <=
# consumed_seq: the per-key max_by merge means the surviving row's provenance IS
# that quarantined entry (a healed row differs in seq/hash and never matches).
# PROVABILITY BOUND — TWO residual classes, both unprovable (#952): (1) a row
# whose dead-letter evidence was pruned/rotated away — no evidence to convict
# on; (2) a row whose dead-letter evidence SURVIVES but extracts an empty
# observed_hash (e.g. a deliberately non-conformant locator: nested
# .locators.* with no observed_hash key) — evidence exists but can never
# satisfy the four-field match, because _record_last_consumed only ever writes
# rows with a NON-empty hash. Neither class is touched — this audit only ever
# removes what the ledger can convict, and the clean-sweep message names BOTH
# classes: "no evidence" and "evidence unusable" are different operator
# conclusions. The dead-letter ledger itself is history and is NEVER modified
# here.
cmd_quarantine_audit() {
  local repair=0
  while [ $# -gt 0 ]; do
    case "$1" in
    --repair)
      repair=1
      shift
      ;;
    *)
      echo "store.sh quarantine-audit: unknown option '$1'" >&2
      exit 2
      ;;
    esac
  done
  _need_jq
  _wake_init_dir "$STATE_DIR"
  local rec="$STATE_DIR/consumed-hashes.jsonl" dlf="$STATE_DIR/dead-letter.jsonl"
  if [ ! -s "$rec" ]; then
    echo "store.sh quarantine-audit: OK — no consumed-hashes record to audit"
    return 0
  fi
  local dl
  dl="$(jq -s -c '[.[] | {kind: (.locators.kind // ""), id: ((.locators.id // "") | tostring), observed_seq: (.observed_seq // -1), observed_hash: (.locators.observed_hash // "")}]' "$dlf" 2>/dev/null || true)"
  [ -n "$dl" ] || dl='[]'
  local consumed
  consumed="$(_wake_read_int "$STATE_DIR/consumed_seq" 0)"
  local false_rows
  false_rows="$(jq -c --argjson dl "$dl" --argjson consumed "$consumed" '
    . as $row
    | select(($row.observed_seq // -1) <= $consumed)
    | select(($dl | map(select(
        .kind == ($row.kind // "")
        and .id == (($row.id // "") | tostring)
        and .observed_seq == ($row.observed_seq // -1)
        and .observed_hash == ($row.observed_hash // "")
      )) | length) > 0)
  ' "$rec" 2>/dev/null || true)"
  if [ -z "$false_rows" ]; then
    echo "store.sh quarantine-audit: OK — no provably-false consumed-hash rows. Two residual classes are unprovable and were NOT judged: rows whose dead-letter evidence was pruned/rotated away (no evidence to convict on), and rows whose surviving dead-letter evidence extracts an empty observed_hash (evidence exists but can never satisfy the four-field conviction match)."
    return 0
  fi
  local n row
  n="$(printf '%s\n' "$false_rows" | grep -c . || true)"
  while IFS= read -r row; do
    [ -n "$row" ] || continue
    if [ "$repair" -eq 1 ]; then
      echo "store.sh quarantine-audit: REPAIR — removing FALSE WITNESS row $row (matches a dead-lettered, never-delivered entry at/below consumed_seq=$consumed)" >&2
    else
      echo "FALSE WITNESS — consumed-hashes row $row matches a dead-lettered, never-delivered entry at/below consumed_seq=$consumed (the recorded consumption never happened)"
    fi
  done <<<"$false_rows"
  if [ "$repair" -eq 0 ]; then
    echo "store.sh quarantine-audit: $n provably-false row(s) found — run with --repair to remove exactly these rows"
    return 1
  fi
  local kept
  kept="$(jq -c --argjson dl "$dl" --argjson consumed "$consumed" '
    . as $row
    | select(
        (($row.observed_seq // -1) > $consumed)
        or (($dl | map(select(
          .kind == ($row.kind // "")
          and .id == (($row.id // "") | tostring)
          and .observed_seq == ($row.observed_seq // -1)
          and .observed_hash == ($row.observed_hash // "")
        )) | length) == 0)
      )
  ' "$rec" 2>/dev/null || true)"
  if ! { printf '%s\n' "$kept" | grep -v '^[[:space:]]*$' || true; } | _atomic_write "$rec"; then
    echo "store.sh quarantine-audit: consumed-hashes rewrite FAILED — record left untouched" >&2
    exit 1
  fi
  echo "store.sh quarantine-audit: repaired — removed $n provably-false row(s); dead-letter ledger untouched (history)"
}

cmd_cursors() {
  _wake_init_dir "$STATE_DIR"
  local observed consumed depth
  observed="$(_wake_read_int "$STATE_DIR/observed_seq" 0)"
  consumed="$(_wake_read_int "$STATE_DIR/consumed_seq" 0)"
  depth="$(grep -cv '^[[:space:]]*$' "$STATE_DIR/pending.jsonl" 2>/dev/null || echo 0)"
  printf 'observed_seq=%s\nconsumed_seq=%s\npending_depth=%s\n' "$observed" "$consumed" "$depth"
}

main() {
  [ $# -ge 1 ] || {
    usage
    exit 2
  }
  local cmd="$1"
  shift
  case "$cmd" in
  init) cmd_init "$@" ;;
  enqueue) cmd_enqueue "$@" ;;
  drain) cmd_drain "$@" ;;
  consume) cmd_consume "$@" ;;
  quarantine-sync) cmd_quarantine_sync "$@" ;;
  quarantine-audit) cmd_quarantine_audit "$@" ;;
  cursors) cmd_cursors "$@" ;;
  -h | --help | help) usage ;;
  *)
    echo "store.sh: unknown command '$cmd'" >&2
    usage
    exit 2
    ;;
  esac
}

main "$@"
