← GENESIS
Part VII — Scaling Decision-Making · Article 28

Enforcing Invariants Without Locks

Partition writes to single authorities — coordinate at routing, not at commit

One Authority Per Invariant established the principle: you enforce invariants not by locking state but by controlling who writes. This article is the mechanics — how a single writer actually enforces a hard constraint across concurrent events routed to the correct authority, without commit-time coordination among writers on the same facts.

Every business has rules that must not be violated. A customer cannot spend more than their available balance. A seat cannot be sold twice. A drug cannot be dispensed without a valid prescription. An order cannot be fulfilled from inventory that doesn’t exist.

These are invariants — conditions that must hold true across the system at all times. And they are the hardest problem in any distributed system — software, organisation, or hybrid — because the events that affect them arrive concurrently, from multiple sources. Writers must be routed to the correct partition; what you must not do is let multiple writers mutate the same facts without a single authority — that is where locks, approval chains, and distributed transactions appear.

The traditional answer is locking. When you need to enforce an invariant, you lock the relevant state, perform your check, make your change, and release the lock. The lock ensures that no other process can violate the invariant during your operation — a locking organisation when it becomes the default coordination model.

Locking works. It also scales poorly, introduces contention, creates deadlock risks, and couples the components that need to enforce the same invariant — because they all need access to the same lock.

There is a different approach, and it is the one the financial world has used for decades. Not because the financial world discovered event-driven architecture, but because it discovered the same underlying principle independently: you enforce invariants not by locking state, but by controlling who writes.

This article uses software examples because they are precise. The mechanics apply to any distributed system — pure software, pure human organisation, or mixed human + AI socio-technical stacks. Wherever facts arrive concurrently from multiple sources, wherever an invariant must hold at commit time, the same structure appears: partition work to a single writer per slice, route requests to that writer, use reservations so parallel preparation does not require commit-time locks, and record outcomes as committed facts others consume. A card network, a hospital formulary committee, and a fraud model with recorded delegation differ in substrate; the invariant logic does not. Article 23 extends the same pattern to cross-cutting platform domains at organisational scale.


The single writer principle

An invariant is a property that must hold true across a set of facts. The simplest way to guarantee that property is to ensure that only one authority — one process, one team, one named role, or one certified agent operating under recorded delegation — ever commits changes to that set of facts.

If only one process can write to the balance ledger, only one process can violate the balance invariant. You have reduced commit-time distributed coordination on that ledger to a local correctness problem inside the writer. The single writer enforces the invariant internally without negotiating with peer writers on the same partition, because it is the only writer for those facts.

This is the single writer principle. One aggregate, one writer, one authority — per partition of the invariant domain.

TransactionRequested ──► [Balance Writer] ──► TransactionApproved
                                          └──► TransactionRejected (insufficient funds)

The Balance Writer is the single authority over the balance. It processes transaction requests sequentially — or with carefully managed concurrency against a single state — and produces outcomes. Other processes observe the outcomes. They do not write to the balance. They cannot violate the invariant because they have no write access to the thing the invariant governs.


Partitioning — coordination at routing, not at commit

At scale, one physical writer is not enough — but one logical writer per partition still is. Partition the invariant domain so each fact maps to exactly one authority: by accountId, seat map key, saga instance id, consistent hash over aggregate id. Routing — gateway, message bus partition key, shard router — is distributed coordination: it must deliver each command to the sole writer for that slice. That coordination happens before the writer runs; it is not optional magic.

What the architecture avoids is commit-time coordination among writers on the same mutable state — global locks, cross-shard two-phase commit, synchronous n-way agreement while holding contested rows. Partitioning ensures writers do not conflict because they do not share write ownership of the same facts. Different accounts, different writers; same account, same writer — always.

                    ┌──► [Balance Writer — partition A]
Request(accountId) ─┼──► [Balance Writer — partition B]
                    └──► [Balance Writer — partition C]
         routing key = accountId  (coordination here)
         commit inside partition   (no peer-writer lock)

The event log may itself be physically sharded. The logical rule remains: one writer per invariant slice. Card networks, ledger shards, and event-sourced aggregates all use this shape — partition assignment is the scalable form of one authority per invariant, not a departure from it.

In human organisations, partitioning is case assignment: one credit analyst owns account X, one pharmacist owns ward Y’s controlled-drug ledger, one compliance officer owns customer Z’s KYC file. Routing is triage — intake sends work to the owning desk, not to every desk. In hybrid stacks, routing may send some partitions to automated bind under delegation L0 and others to human writers — still one writer per slice, never two authorities mutating the same committed fact.


Reservations as the coordination mechanism

The single writer principle solves write-side invariants. But it creates a different problem: latency. If the balance writer must process every transaction before any downstream process can proceed, and if downstream processes are waiting for confirmation, the system is synchronous end-to-end.

The solution is the reservation pattern. Rather than blocking downstream processes while the invariant check runs, you separate the reservation from the commitment.

Phase 1: Reserve. A downstream process that needs to spend from the balance does not spend it. It requests a reservation — a hold on a specific amount for a specific purpose, with an expiry.

FundsReservationRequested {
  accountId,
  reservationId,
  amount,
  purpose: "order-payment:order-xyz",
  requestedBy: "order-service",
  expiresAt: now + 15 minutes
}

The Balance Writer processes this request. If funds are available, it creates the reservation and publishes the confirmation. If not, it publishes a rejection. The reservation reduces the available balance — preventing double-spend — without committing the funds.

Phase 2: Proceed in parallel. While the reservation is pending, downstream processes continue. The order is validated, the inventory is checked, the shipping address is confirmed. These happen concurrently, not sequentially behind the balance check.

Phase 3: Commit or release. When all conditions are met, the reservation is committed — the funds are actually moved. If any condition fails, the reservation is released — the funds become available again.

FundsReservationCommitted { reservationId, committedAt }
FundsReservationReleased  { reservationId, reason, releasedAt }

The financial world has used this pattern for half a century. A credit card authorisation is a reservation. The authorisation reduces available credit — preventing overspending — without moving money. Settlement is the commit. Void is the release. The card network is the single writer enforcing the credit limit invariant.

The same three phases appear outside software: a hospital holds a bed and staff slot while labs run (reserve), prepares discharge paperwork in parallel (proceed), then commits admission or releases the hold. A hiring process reserves headcount while interviews proceed. An LLM-assisted workflow reserves inventory while the model drafts the order — the human or delegation policy commits only after the hold is confirmed. Reservation separates parallel reversible work from irreversible bind in every socio-technical system that takes the pattern seriously.


The reservation pattern and the commitment boundary

The reservation pattern connects directly to the commitment boundary from The Moment of Commitment.

The reservation confirmation is a Level 0 event — a decision made by the single writer that funds are available and held. It is ground truth. It was decided, at a specific moment, by a specific authority.

The final commit is also Level 0 — a decision that the reserved funds are now moved, the reservation is closed, the balance is permanently changed.

Between these two Level 0 events, downstream processes operate on the knowledge that the invariant is temporarily protected. They are Class C consumers of the reservation confirmation — they can proceed operationally, knowing that the funds are held, without needing to enforce the invariant themselves.

This separation of concerns is the structural elegance of the reservation pattern. The invariant enforcement stays with the single writer. Downstream processes proceed in parallel without commit-time coupling to the writer’s lock — protected by reservation, not by blocking on shared mutable state.


Identifying invariants that need single writers

Not every constraint is an invariant that needs a single writer. Many constraints are better enforced at write time by schema validation, by domain logic in the committing aggregate, or by idempotency keys that prevent duplicate processing.

A constraint needs the single writer pattern when:

It spans multiple facts that arrive from different sources. Balance invariants span all transactions against an account, which arrive from multiple channels. Seat inventory spans all reservation requests, which arrive from multiple booking services. These cannot be enforced locally — they require a single process with a complete view.

Violation is irreversible or costly to correct. If a customer’s balance briefly goes negative and then self-corrects, the business impact may be acceptable. If a seat is sold twice and both customers show up at the same time, the impact is not acceptable. The cost of violation determines whether the complexity of a single writer is warranted.

The invariant must hold in real time, not eventually. Some invariants can be enforced after the fact — detecting and correcting violations through a reconciliation process. Regulatory invariants, safety invariants, and financial invariants typically cannot. They must hold at the moment of commitment.

When all three conditions are met, the single writer is the correct design. When fewer than three apply, lighter enforcement mechanisms — optimistic concurrency, idempotency, eventual detection — are usually sufficient and far less complex.


Distributed invariants across boundaries

The hardest case is an invariant that spans multiple bounded contexts — services in software, functions or product teams in organisations, human and automated actors in hybrid pipelines. An order cannot be placed if the product is discontinued and the customer’s account is suspended and the delivery region is unsupported. These conditions live in three different places; the locking organisation response is to convene everyone before anyone acts.

The naive software solution is a synchronous call chain — the order service calls the product service, the customer service, and the logistics service before placing the order. This works at small scale and fails at large scale: coupling, latency, cascade failures. The organisational equivalent is a meeting before every action — same failure at a different scale.

The reservation pattern scales to this case, but requires a choreography of reservations across boundaries:

OrderPlacementRequested

        ├──► Product service reserves product availability
        │    ProductAvailabilityReserved / ProductUnavailable

        ├──► Customer service reserves account eligibility  
        │    AccountEligibilityReserved / AccountIneligible

        └──► Logistics service reserves delivery capacity
             DeliveryCapacityReserved / RegionUnsupported

An orchestrating process — a saga, in the terminology of distributed systems — monitors these reservations and commits or compensates based on their outcomes. If all three succeed, the order proceeds and all three reservations are committed. If any fail, the successful ones are released.

The saga is itself a single writer — it is the sole authority that converts the combination of reservations into a committed order. The invariant “an order can only be placed when all conditions are met” is enforced by this single orchestrator, which has visibility into all three reservation outcomes before committing. In an organisation, the case owner or operations coordinator plays the same role: not every function writes to the case file; one authority commits when all reservations are satisfied.

The key property preserved throughout is that every step produces Level 0 events. Every reservation is a decision. Every release is a decision. Every saga state transition is a decision. The full history of every attempted order placement — including the failures and compensations — is in the permanent record. The same auditability requirement applies to human and hybrid workflows: holds, releases, and commits must be named and recorded, not implied by email threads.


What the level hierarchy implies for invariant consumers

Returning to the dependency matrix from The Facets Composed, invariant enforcement is unambiguously Class A consumption.

Class A consumers — invariant enforcers — may only consume Level 0 facts or Level 1 authoritative aggregates. And when consuming Level 1, the reservation pattern must be in place.

The reason is timing. A Level 1 aggregate has bounded staleness — there is a window between when a Level 0 fact arrives and when the Level 1 aggregate reflects it. In that window, a Class A consumer reading the Level 1 aggregate sees a stale balance. If it makes an irreversible commitment based on that stale balance, it may violate the invariant.

The reservation pattern closes this window. Before making the commitment, the Class A consumer requests a reservation from the single writer. The single writer has a complete, current view of the facts it governs. The reservation is granted or rejected based on the actual current state, not a potentially stale aggregate.

This is why the matrix entry for Class A + Level 1 reads ”✓ with reservation” rather than just ”✓”. The Level 1 aggregate is useful for operational decisions. For invariant enforcement, the reservation is mandatory.


The simplicity underneath the pattern

The reservation pattern looks complex when described in full. In practice, the components are simple — in software, organisations, and socio-technical hybrids.

A single writer is an authority with one responsibility: maintain a consistent view of one aggregate and process requests against it sequentially. In software it is often a service; in an organisation it is a named team or role with exclusive commit rights to that domain. It does not need to be distributed internally. It needs to be reliable and its committed output needs to be durable and visible.

A reservation is a record with a status — requested, confirmed, committed, released — and an expiry. The single writer manages these records and uses them to answer the question “is this resource available?” in a way that accounts for currently held reservations — whether the record lives in an event store, a case-management system, or a controlled register.

The saga is an event-driven state machine — or an operations coordinator with explicit rules — that subscribes to reservation outcomes and emits commit or release when all prerequisites are known.

Each component is independently simple. Their composition produces distributed invariant enforcement without commit-time distributed locks on shared mutable state, without synchronous cross-boundary call chains (or cross-functional meetings) as the default path, and without coupling participants through anything other than the shared record of committed facts and partition-aware routing.

The event log — or organisational register of committed decisions — is the async coordination medium: facts propagate after commit. Routing is the sync coordination that assigns work to the correct single writer. Together they replace lock-based commit-time negotiation across writers; they do not eliminate coordination altogether. That division — coordinate at routing, not at commit — is what makes the pattern portable across every distributed socio-technical system this series describes.

Continue → One Authority Per Invariant — At Scale