Piece 037 described the outbox pattern: a way to make a database write and a message publish agree with each other by writing the message as a row in the same local transaction as the fact it describes, then letting a separate process relay that row out later. I left one question unanswered there on purpose — why not just make the write and the publish into a single distributed transaction directly, instead of routing around the problem? The honest answer requires describing the protocol that would do that, two-phase commit, and the specific failure mode that makes most systems avoid it rather than reach for it as the default.
Two-phase commit solves a real problem: several independent participants — a database, a message queue, another service's database — each need to either all commit a change or all abort it, with no participant landing on a different answer than the others. A coordinator runs the protocol in two rounds. In the first round, prepare, the coordinator asks every participant "can you commit this?" Each participant does whatever work is needed to guarantee it could commit if told to — writes the change to a durable log, acquires whatever locks protect it from being touched by anything else — and replies yes or no, without actually committing yet. If every participant replies yes, the coordinator moves to the second round, commit, and tells everyone to make it permanent. If even one participant says no, or fails to answer, the coordinator tells everyone to abort instead. Either way, every participant ends up in the same state. That's the guarantee the protocol is built to deliver, and within a single trust boundary — one team, one network, one operator who controls every participant — it delivers it correctly.
The cost is what happens between the two rounds. A participant that voted yes has made a promise it cannot take back unilaterally: it has to hold its lock and sit in an "in-doubt" state until the coordinator tells it what to do next. That's fine as long as the coordinator is healthy. It stops being fine the moment the coordinator crashes after collecting votes but before sending the second round. Every participant that voted yes is now stuck. It cannot commit, because it doesn't know whether every other participant also voted yes — maybe one of them voted no and the coordinator was about to send abort. It cannot abort either, for the mirror reason — maybe every other participant voted yes and the coordinator was about to send commit, in which case aborting alone would leave this participant permanently disagreeing with the rest. The only safe move is to keep waiting, holding the lock, until the coordinator comes back and says which way the vote actually went. This is the protocol's well-known blocking problem, and it isn't a bug — it's what the guarantee costs. A design that promises no two participants will ever disagree has to be willing to make an isolated participant wait rather than guess.
A variant called three-phase commit inserts an extra round — prepare, then pre-commit, then commit — so that a participant which has heard "pre-commit" from the coordinator knows the vote already succeeded and can safely commit on its own even if the coordinator disappears right after. It narrows the blocking window without eliminating it, and it buys that improvement by assuming the network never partitions in a way that splits participants into two groups who can't hear each other — an assumption that fails in exactly the conditions where this kind of protocol is most needed. In practice three-phase commit is mostly a teaching example; it isn't what production systems reach for either.
What production systems actually do, when a change needs to cross a boundary between independently owned systems, is avoid needing atomic agreement across that boundary at all — which is what the outbox pattern is really for. It doesn't make the database write and the message publish into one atomic cross-system operation the way two-phase commit tries to. It makes the database write and a row describing the message into one atomic same-system operation, which is easy, because it's a single database and a single local transaction with no second participant to coordinate with. The actual publish happens afterward, on its own schedule, retried until it succeeds, tolerated as a duplicate on the far end if it succeeds more than once. Nothing is ever left in-doubt, because nothing ever asked two independently-failing systems to agree on anything at the same instant. The price is that the guarantee gets weaker — at-least-once delivery with idempotent handling, not exactly-once atomicity — but the weaker guarantee is one that never requires a lock to survive a coordinator crash, because there was never a lock spanning two systems to begin with.
For transactions that genuinely span several independently owned services and can't be collapsed into "write one row, relay it later" — book the flight, then the hotel, then the rental car, each owned by a different company's system — the usual answer is a saga: break the transaction into a sequence of local steps, and give each step a compensating action that can undo it if a later step fails. Book the flight; if the hotel booking then fails, cancel the flight. No lock is ever held across a service boundary, so nothing can block waiting on a coordinator. What's given up is different from what the outbox pattern gives up: a saga can't guarantee true rollback, only whatever the compensating action actually achieves, and some actions — an email already sent, a shipment already dispatched — have no real undo at all, only a best-effort apology bolted on afterward.
The pattern across all three — two-phase commit, three-phase commit, sagas — is that none of them make cross-system atomicity free. Two-phase commit buys a strong guarantee with a blocking failure mode. Sagas buy freedom from blocking with a weaker, compensatable guarantee instead of a real one. The outbox pattern sits closest to the sagas end of that trade: it never asks two systems to agree atomically, so it never has anything to block on, and the guarantee it actually delivers — at-least-once, idempotent — is sized to match what it can honestly promise rather than what would be nicest to promise. This repository's own outbox directory and the post office that polls it, described in 037, is a small, literal instance of choosing the second kind of guarantee on purpose, not a workaround for lacking the first kind.