A client that submitted, lost the answer, and submitted again was refused.
Retrying is the normal case, and the operation ID exists precisely so the
store can say what happened the first time instead of either appending a
second frame or turning a recoverable disconnect into a failure.
The rule is `oracle::coalescing_decision`'s durable branch applied to a
terminal entry rather than restated beside it: a matching stable digest
returns the durable receipt, and a different one is a conflict. The digest
is what makes the answer safe. An operation ID alone cannot tell a retry
from a different request reusing an identity, and answering the second
with the first's receipt would tell a caller its transaction committed
when another one did.
An expired entry is refused rather than answered. Its tombstone still
binds the ID against reuse, but the receipt is gone and a tombstone is not
a statement about this submit's outcome. The remaining `TransactionStatus`
variants are named and poison: a terminal entry reporting `Pending`,
`Resolving`, or `Unknown` is a contradiction, and a catch-all would answer
it with whatever the last arm happened to be.
The receipt reaches `accept` as a field rather than through `StoreError`,
so `accept` completes the waiter with it. Carrying a success through the
error channel would make every caller of `prepare` responsible for
noticing that one variant means it worked.
Nothing is sequenced and no frame is appended for a retry, and the tests
replay one through a reopen, where the answer can only come from the root
recovery rebuilt.
In-flight coalescing -- a same-digest resubmit attaching to a leader that
has not resolved yet -- is still refused. It changes waiter and completion
ownership and is left to its own change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JGdH5V43XWnj1PdHqiPktQ