writeonce/docs/examples/porch/middleware
shoney.arickathil e296d0541d fix(porch-store): close the ephemeral-row race, not just shrink it
- Root cause of the residual: a 4xx/5xx row lived under the bare key,
  so a second message could delete-and-replace it before the FIRST
  caller's own middleware-side read (necessarily outside receive,
  WO-E226) ever ran -- the owner itself could read back a LATER
  message's answer, not just a duplicate reading a stale one
- Fix: a 4xx/5xx miss is never stored under the bare key at all. Each
  such attempt gets its own row, keyed by a nonce carried back in the
  scalar reply's low digits, so no other message for the same bare key
  ever touches it -- the decision AND the row's identity are both
  fixed inside the one serialized receive call
- Disclosed trade-off: that row is never revisited by a bare-key
  lookup, so it is never TTL-pruned either -- permanent per failed
  attempt, the same no-sweeper trade-off this codebase already makes
  elsewhere, not a new one
- Gate leg 18e: reran 20x in isolation against the fix with zero
  500-500 or 200-200 outcomes (was reproducible before)
- §18's SIGTERM-stop check now force-kills on timeout before clearing
  $SRV, instead of matching §14/§17b's own gap where a still-running
  process escapes the exit trap too -- an orphan no longer survives
  past this leg regardless of the assertion's own outcome

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 464147a9ddf3a53cb1946637c3f517ba615ee358)
2026-09-15 01:15:30 +02:00
..
idempotent.wo fix(porch-store): close the ephemeral-row race, not just shrink it 2026-09-15 01:15:30 +02:00
keypool.wo fix(porch-store): close the ephemeral-row race, not just shrink it 2026-09-15 01:15:30 +02:00
limiter.wo fix(porch-store): trust_proxy falls back to net.peer on an absent XFF 2026-09-15 01:15:30 +02:00
store.wo feat(porch-store): add digest column to IdempotencyKey table 2026-09-15 01:15:30 +02:00