Atomic event commit
AtomicEventTransaction.CommitAsync accepts a complete AtomicEventTransactionRequest. Each participant names an actor path, stream, expected version, and nonempty event list. The request carries one operation ID, a lowercase SHA-256 request identity, and an optional AtomicRouteFence.
On this page
Required store behavior
The store must implement IAtomicEventTransactionStore and advertise SupportsAtomicEventTransactionsAndProjectionDispatch. It commits all participant events, required ancillary streams, projection dispatch handoffs, and the keyed completion receipt as one atomic operation. A selected fenced route also requires IRouteFencedAtomicEventTransactionStore and a commit-time comparison of route key, epoch, and deployment fingerprint.
Before returning a prior receipt on retry, the store compares the full frozen serialized batch. Reusing an operation ID with changed actor paths, expected versions, event types, or bytes must fail without another append. Current ownership, authorization, and deletion fences still apply to a retry.
AtomicEventTransactionReceipt records committed versions and attests to ancillary writes and projection handoffs. The helper validates that the receipt matches the request and expected final versions. External effects are outside this contract; read external effects for the durable intent boundary.
No-change outcomes
The regular eventful contract rejects an empty participant or empty event list. A durable no-op completion is a separate optional contextual capability with its own receipt shape and root-state checks. Do not manufacture an eventful receipt to represent a no-op.
Example: Commit a closed event batch
Given a capable store and the verified identity from the selected command route, this commits one participant at expected version zero. The current route fence is passed into the request and checked by the store.
public static Task<AtomicEventTransactionReceipt> Commit(
IStore store, Metadata headers, TrustedAtomicCommandIdentityClaim identity,
AtomicRouteFence routeFence)
{
var participant = new AtomicEventTransactionParticipant(
"CounterActor/42", "CounterActor-42", 0,
new IEvent[] { new Incremented(headers) });
var request = new AtomicEventTransactionRequest(
identity.OperationId, identity.RequestIdentity, [participant], routeFence);
return AtomicEventTransaction.CommitAsync(store, request);
}