fix(wake): #917 gate the final observed_seq cursor write + observed.set/cursor consistency (defense-in-depth) (#933)
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 #933.
This commit is contained in:
2026-07-26 15:14:38 +00:00
committed by Mos
parent 17087efe15
commit 9becaf877f
3 changed files with 154 additions and 5 deletions

View File

@@ -251,9 +251,15 @@ cmd_enqueue() {
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 ! {
cat "$STATE_DIR/observed.set" 2>/dev/null
printf '%s\n' "$seq"
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
@@ -264,8 +270,25 @@ cmd_enqueue() {
# 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
printf '%s' "$seq" | _atomic_write "$STATE_DIR/observed_seq"
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