fix(wake): #908 unify observed_seq on a single store-side allocator (dissolve detector-private-counter seam) (#915)
Co-authored-by: jason.woltje <jason@diversecanvas.com> Co-committed-by: jason.woltje <jason@diversecanvas.com>
This commit was merged in pull request #915.
This commit is contained in:
@@ -15,6 +15,10 @@
|
||||
# R7 a source already reflected in the inbox -> ACCOUNTED (no double-
|
||||
# enumeration of detector-delivered state) (§4/G3-ii)
|
||||
# R8 a source adapter error -> FAIL LOUD (G2a parity; never 'no state') (§4/G2a)
|
||||
# R9 co-feed NO-ALIAS: detector + reconciler share the ONE store-side
|
||||
# observed_seq allocator, so co-feeding one store yields DISTINCT,
|
||||
# contiguous seqs (no aliasing). Formerly the fail-closed dual-
|
||||
# allocator refusal; #908 dissolves the hazard at the root. (§4/G3, #908)
|
||||
#
|
||||
# Uses FAKE/STUB sources only (no live network). Isolated per test.
|
||||
# shellcheck disable=SC2030,SC2031
|
||||
@@ -232,7 +236,7 @@ EOF
|
||||
[ "$(depth)" = "0" ] || fail_msg "R8: a failed observation must NOT enumerate anything, got depth $(depth)"
|
||||
) && ok
|
||||
|
||||
echo "== R9: serialized dual-allocator collision -> reconciler FAILS LOUD (never silent-alias) =="
|
||||
echo "== R9: co-feed NO-ALIAS — detector + reconciler share ONE store allocator; every observed_seq distinct + gapless (#908 resolved) =="
|
||||
(
|
||||
WAKE_STATE_HOME="$(fresh_state r9)"
|
||||
export WAKE_STATE_HOME
|
||||
@@ -241,7 +245,7 @@ echo "== R9: serialized dual-allocator collision -> reconciler FAILS LOUD (never
|
||||
mkdir -p "$stub"
|
||||
make_stub "$stub"
|
||||
export WAKE_DETECTOR_SOURCE_CMD="$stub/adapter.sh"
|
||||
# Pre-existing sources present at startup (the reviewer's alpha/beta repro).
|
||||
# The reviewer's alpha/beta repro (formerly the dual-allocator ALIASING case).
|
||||
printf 'ALPHA\n' >"$stub/repo_alpha"
|
||||
printf 'BETA\n' >"$stub/repo_beta"
|
||||
wl="$TMP_ROOT/r9.json"
|
||||
@@ -251,26 +255,44 @@ echo "== R9: serialized dual-allocator collision -> reconciler FAILS LOUD (never
|
||||
"watches": [ { "lane": "L", "sources": [ { "kind": "repo", "id": "alpha" }, { "kind": "repo", "id": "beta" } ] } ] }
|
||||
EOF
|
||||
export WAKE_WATCH_LIST="$wl"
|
||||
# A DETECTOR is co-feeding this store: baseline it (creates the detector's
|
||||
# private-counter state dir). The detector's private observed_seq allocator is
|
||||
# now live and INDEPENDENT of the store cursor — the exact co-feeding hazard.
|
||||
|
||||
# A DETECTOR is co-feeding this store. Under #908 both the detector and the
|
||||
# reconciler allocate observed_seq from the ONE store cursor (store.sh enqueue,
|
||||
# no --seq), so co-feeding is now SAFE — the reconciler ENUMERATES (no refusal),
|
||||
# and no seq can be aliased. (The old guard failed closed here; that refusal is
|
||||
# retired exactly to the extent the single allocator makes safe.)
|
||||
"$DET" poll-once >/dev/null 2>&1 || fail_msg "R9: detector baseline failed"
|
||||
# The pre-existing state is unaccounted (baseline is silent). Enumerating it
|
||||
# here would allocate a store-cursor seq the detector's private counter can
|
||||
# later REISSUE and alias — the serialized collision. The reconciler MUST
|
||||
# refuse (fail loud), NOT enqueue a collidable seq.
|
||||
before="$(depth)"
|
||||
# A real detector delta on alpha -> the store allocates observed_seq 1.
|
||||
printf 'ALPHA2\n' >"$stub/repo_alpha"
|
||||
"$DET" poll-once >/dev/null 2>&1 || fail_msg "R9: detector delta (alpha) failed"
|
||||
[ "$(depth)" = "1" ] || fail_msg "R9: detector delta should enqueue exactly one entry, got depth $(depth)"
|
||||
|
||||
# The reconciler co-feeds the SAME store: beta is still unaccounted (its
|
||||
# baseline was silent), so it enumerates beta -> the store allocates the NEXT
|
||||
# seq (2), NOT a reissue of 1. alpha's current state is already in the inbox
|
||||
# (accounted), so it is not double-enumerated.
|
||||
out="$("$RECON" reconcile 2>&1)"
|
||||
rc=$?
|
||||
[ "$rc" -ne 0 ] || fail_msg "R9: enumerating into a detector-co-fed store must FAIL LOUD (non-zero), not silently alias"
|
||||
echo "$out" | grep -qi 'dual-allocator' || fail_msg "R9: the failure must name the dual-allocator hazard [$out]"
|
||||
echo "$out" | grep -q '908' || fail_msg "R9: the failure must reference the #908 follow-up [$out]"
|
||||
echo "$out" | grep -qi 'REFUSED' || fail_msg "R9: the obligation must be REFUSED/flagged, not swallowed [$out]"
|
||||
# No collidable seq was written: depth is unchanged, so a later detector delta
|
||||
# cannot alias a reconciler-enumerated entry.
|
||||
[ "$(depth)" = "$before" ] || fail_msg "R9: a refused reconcile must NOT enqueue any (aliasable) seq, depth changed $before->$(depth)"
|
||||
# (That the sole-feeder path DOES still enumerate — i.e. the guard is not a
|
||||
# blanket no-op — is proven by R5/R6, which enumerate under --allow-enumerate.)
|
||||
[ "$rc" -ne 0 ] || fail_msg "R9: pre-existing beta is unaccounted on this pass -> must FLAG (non-zero) [$out]"
|
||||
echo "$out" | grep -qi 'UNACCOUNTED=1' || fail_msg "R9: only beta should be unaccounted (alpha is inbox-accounted) [$out]"
|
||||
[ "$(depth)" = "2" ] || fail_msg "R9: reconciler must ENUMERATE beta into the co-fed store (depth 2), got $(depth)"
|
||||
|
||||
# A further detector delta on beta must allocate 3 — the unified allocator
|
||||
# advances past the reconciler's seq, it can NEVER reissue/alias 1 or 2.
|
||||
printf 'BETA2\n' >"$stub/repo_beta"
|
||||
"$DET" poll-once >/dev/null 2>&1 || fail_msg "R9: detector delta (beta) failed"
|
||||
|
||||
# THE NO-ALIAS ASSERTION: every observed_seq across BOTH feeders is DISTINCT and
|
||||
# the observed prefix is CONTIGUOUS/GAPLESS (1,2,3). Under the OLD two-allocator
|
||||
# design the detector's private counter would have reissued a seq the reconciler
|
||||
# already used, so this set would contain a duplicate (alias).
|
||||
seqs="$("$STORE" drain | jq -r '.observed_seq' | sort -n | tr '\n' ' ')"
|
||||
[ "$seqs" = "1 2 3 " ] || fail_msg "R9: co-fed observed_seqs must be distinct+gapless '1 2 3', got '$seqs' (a duplicate = the aliasing #908 dissolved)"
|
||||
ndistinct="$("$STORE" drain | jq -r '.observed_seq' | sort -nu | grep -c .)"
|
||||
ntotal="$("$STORE" drain | jq -r '.observed_seq' | grep -c .)"
|
||||
[ "$ndistinct" = "$ntotal" ] || fail_msg "R9: aliasing detected — $ntotal entries but only $ndistinct distinct observed_seq"
|
||||
# The contiguous-prefix CONSUMED contract holds over the co-fed seqs.
|
||||
"$STORE" consume --upto 3 >/dev/null 2>&1 || fail_msg "R9: CONSUMED 3 must succeed over the gapless co-fed prefix"
|
||||
) && ok
|
||||
|
||||
echo
|
||||
|
||||
Reference in New Issue
Block a user