Skip to content

Dynamic Consistency Boundaries

A Dynamic Consistency Boundary (DCB) is how EvidentSource lets you enforce cross-entity invariants at append time, atomically, without distributed transactions and without saga orchestration.

The idea is formalized at dcb.events. This page is a practical orientation.

Classic event sourcing works well when every command touches one entity. It stops working neatly when a command needs to enforce a rule across several entities — “transfer between accounts A and B only if both have sufficient funds at the moment the transfer lands.”

Traditional answers: distributed transactions (complicated, slow, lock-prone), sagas (eventual consistency, compensation logic, operational complexity), or single-entity aggregates that absorb everything they might need to touch (denormalization that fights the model).

When decide returns events, it also returns conditions — predicates expressed against the event store that must hold at the exact moment of append. EvidentSource checks them atomically; if any fail, the append is rejected and decide can be retried.

return {
events: [{ type: "TransferApproved", subject: transferId, data: { ... } }],
conditions: [
// No new debits on source account since we read its state
unchangedSince(sourceAccountId, sourceState.revision),
// No new debits on destination account either
unchangedSince(destinationAccountId, destinationState.revision),
],
};

You get:

  • Atomicity across multiple entities
  • Linearizable read-your-write consistency
  • No coordinator — the condition check is part of the append, done in the event-store core
  • No compensation logic — either it all lands or none of it does

EvidentSource supports predicate primitives over:

  • Stream revisions (unchangedSince, atRevision)
  • Subject last-event predicates
  • Event-type presence/absence within a subject or stream
  • Time-bounded versions of each

See Reference: Constraints for the full list.

Any time a command’s correctness depends on state you read and that state could change between your read and your append. DCB conditions are how decide says: “This decision was made assuming X — if X isn’t still true, don’t apply it.”