The Conflict Problem
Introduction
The last section closed at a door. Every tool in it — quorums, terms, logs, leases — funneled each decision through one place, so the system could hand back one answer and never take it back. This section opens with the systems that look at that door and walk away.
Two designers edit the same document from two continents, and neither cursor waits for a majority before the letter appears. A phone lands after six hours offline, holding a week's worth of unsent edits, and nobody expects it to have gone read-only over the Atlantic. Two regions keep accepting writes while the cable between them is being dredged up by a fishing trawler. Three different rooms, one refusal: they will not make a human wait out a round trip, and they will not stop working when the network does.
So they accept two answers, on purpose. And then they have to face what they've done. The clocks lessons handed you the tool that proves two writes are concurrent — the vector testifies, and keep both is the honest verdict. What they never said is what to do with the pair. This lesson is that reckoning: what accepting two answers actually costs, what any honest way out must guarantee, and why the hardest part is not code at all.

A Receipt, Not an Error
Start by renaming the thing. In the consensus lessons, two answers meant catastrophe: split brain, the doomed failover script, the thing quorums exist to prevent. Here, a conflict is not a failure. A conflict is a receipt — proof that the system kept serving people while the network was broken or the distance was long. Every conflict in your store is a write you did not refuse and a wait you did not inflict. That's what was purchased. The receipt just came due.
You've already watched the purchase get made twice. In CAP, Properly, the comment path chose to stay available and risk a merge while the payment path refused. In Replication Topologies, you drove the moment a conflict is born: two leaders, two regions, one row, both writes acknowledged. And in Version Conflicts, you watched what most databases do with the receipt when nobody's looking: compare two timestamps and throw one write away. Last-write-wins doesn't pick the last write; it picks the biggest number. Conflict destruction, wearing the costume of a policy.
What's new in this section is the posture. These systems don't treat the conflict as an embarrassing edge case to be quietly shredded. They treat it as a first-class citizen: detected on purpose, stored with care, resolved by something that actually knows what the data means. Collaborative editors, phone sync engines, multi-region stores: an entire family of software whose defining skill is facing the receipt instead of eating it.
The Reckoning Has Four Jobs
Living with conflicts decomposes into four jobs, and naming them now gives you the map for this whole section.
Detect. You cannot face what you cannot see. A single timestamp slot can't see concurrency at all — that was the whole crime scene in Version Conflicts. Detection takes causality machinery: the vector that testifies, or its everyday cousin, the common ancestor. When git merges two branches, it diffs both against the commit they split from. Same idea, three decades of daily practice.
Represent. Once seen, the conflict has to live somewhere. One slot (and a loser chosen instantly), two siblings side by side, a whole tree of revisions, or the operations themselves kept as a log instead of the states they produced. CouchDB is bluntly honest here: after replication, both versions exist on both sides, and the store keeps every conflicting revision until something with more context cleans up.
Resolve. Somebody collapses two answers into one. There are exactly four candidates: a rule inside the store (cheap, blind), the data type itself (a value that knows how to merge), the application (code that knows what a cart means), or a human (the most expensive resolver, and sometimes the only correct one — every git conflict marker you've ever edited was this job landing on your desk).
Converge. Whatever resolves, every replica must end at the same answer without a leader to ask. This job is so easy to get wrong, and so quietly disastrous when you do, that it gets its own section below.
There's also a when. Resolve at write time and the answer is always clean but somebody's work dies young, before anyone with context can look. Resolve at read time and the store hands out siblings until a reader collapses them, the way the cart in Version Conflicts was mended at the till. Resolve at sync time, when a device comes back from the tunnel, and the merge happens in a batch, which is where phones live. Later is safer and messier; earlier is tidier and blinder.
That's the section map. CRDTs builds data types that carry their own merge. Operational Transformation resolves by transforming the operations — two cursors, one sentence. Conflict Resolution Strategies is the full catalog of resolvers and when each one is the right buy. Offline-First Sync is the loop that runs all four jobs every time a phone comes back from a tunnel. One lesson per job you can't fake.

The Merge Dilemma
Now the uncomfortable center of the whole subject. Suppose detection worked: two branches, proven concurrent, both sitting in front of you. Merge them. It turns out every concurrent pair falls into one of two worlds, and everything depends on which one you're standing in.
Some pairs compose. Ana adds sunscreen to the packing list; Ben, offline, adds a hat. Nothing about one edit denies the other. The union keeps both intents, and both people see a list containing exactly what they meant. You met this in Vector Clocks: a cart is an accumulation, and the union has no losers. Even Amazon's famous cart merge is just this move, with its known price, paid knowingly: an add is never lost, but a concurrently deleted item can climb back out of the grave.
Some pairs contradict. Ana books seat 14A. Ben books seat 14A. The merged plane does not have two seats 14A. A username claimed twice, a flag switched on and off, one document title set to two different strings: there is no clever union here, no transformation that makes both true. Someone must lose, or the application must refuse, which is exactly why the payment path in CAP, Properly chose to refuse rather than double-charge. When both answers can't be true, honesty beats availability.
Here is the dilemma: the store cannot tell these two worlds apart. Sunscreen-plus-hat and 14A-versus-14A look identical from below — two concurrent writes touching the same object. What separates compose from contradict is meaning: what a packing list is for, what a seat is. Which is why the deepest sentence in Version Conflicts was never really about databases: only your application knows what your data means. A merge is a claim about what the user meant. Machinery can carry the claim; it cannot make it for you.
One dial changes how often you even face the choice: the size of the thing you compare. Treat the whole trip plan as one value and any two concurrent edits collide, even a title change against a tag change. Compare per field and those two compose on their own; only same-field edits still fight. Compare the operations themselves (add sunscreen, rename title) and even more pairs compose, because intent travels with the edit instead of being guessed from two finished states. Finer granularity dissolves conflicts before they exist, and that one idea powers both of the next two lessons.

The Convergence Contract
One guarantee died when you walked away from the door. The last section's promise — one answer, never taken back — is gone; nothing here can offer it. Its replacement is the contract every system in this section signs instead:
Replicas that have seen the same set of updates must arrive at the same state. Not the right state — the same state, everywhere, with no leader to ask.
That sounds almost too weak to matter, until you watch a system without it. Say each replica just applies updates in the order they arrive, letting the newest arrival win. Ana's phone applies her title first, then Ben's; Ben's laptop applies his own first, then Ana's. Same two updates, both directions delivered, nothing lost — and the two devices now show different titles, forever. No further messages fix it; resending just replays the same trap. This is the divergence trap, and it's worse than either answer winning: the system doesn't have two answers anymore, it has two realities, and no record that they split.
Escaping the trap puts two laws on any resolver, whoever it is. Deterministic: the outcome may depend only on the updates themselves — never on arrival order, local mood, or a coin flip. Order-blind: merging A then B must equal merging B then A, so it can't matter which direction of the exchange landed first. (And since sync loops love to re-deliver, an update applied twice must count once.) Meet these and replicas converge no matter how gossip shuffled the deliveries. Break either and you've built the trap with extra steps.
Now the twist that makes this lesson's hardest idea click: last-write-wins satisfies the contract. Biggest-number-wins is perfectly deterministic and perfectly order-blind — every replica agrees, instantly, forever, on the same destroyed write. Convergence is the floor, not the finish. There are two separate questions — does it converge? and does it keep what people meant? — and the grown-up systems answer both. CouchDB makes the floor explicit: it picks a winner using a deterministic algorithm so that the same choice will be made on all peers, and keeps the losing revisions on every replica until the application, the thing that knows the meaning, comes back for them. Converge first, so nothing splits; preserve the evidence, so nothing is silently gone.

See It, Break It: The Divergence Trap
Theory over. Go split a reality. Below are two replicas of one trip plan: Ana's phone and Ben's laptop, with Ben's clock running five seconds fast, as somebody's always is. Cut the link and edit both sides: type titles, add tags, remove tags. Then heal, press sync, and watch the operations cross as packets.
Run it once in arrival order and read the lamps: both sides received everything, and they disagree anyway — the trap, live. Switch to timestamp wins and sync again: the lamps flip, CONVERGED goes green, and something you typed is quietly gone; note which write died and whose clock killed it. Then try honest merge: adds survive, a delete that raced an add loses loudly instead of silently, and if you set two different titles, the loser doesn't vanish — it waits, flagged, for a human with context. If you'd rather watch it break before driving it, stage the trap replays the classic double-edit on both machines.

You've Been Doing This All Along
If this problem feels exotic, look at your own desk. git is a conflict-embracing replicated store you already trust with your career: every clone accepts writes with no leader, detection is a diff against the common ancestor, representation is the conflict marker, and the resolver of last resort is you, at 6 p.m., deciding what the code meant. Nobody calls that a database failure. It's the design.
The same shape repeats up and down production. CouchDB and Riak keep siblings and hand them to the application. Amazon's cart unions its branches and takes the resurrection trade with open eyes. Calendar systems double-book a room and route the contradiction to the humans who own it. In every case the architecture is the same four jobs (detect honestly, represent without destroying, resolve with meaning, converge everywhere), and the differences are just who gets the resolver's chair.
What nobody sane does is hand-write that machinery per feature. The next four lessons are the industrial versions of the chair: data types that merge themselves, transformations that let two cursors share a sentence, the strategy catalog, and the sync loop that runs it all on a phone.
Key Takeaways
- A conflict is a receipt, not an error. It's proof the system stayed available while the network was broken or the distance was long. These systems choose the receipt; then face it.
- The reckoning has four jobs: detect, represent, resolve, converge. A timestamp slot can't even see the conflict; vectors and ancestors can. Store siblings, not corpses. Resolvers come in four sizes: store rule, data type, application, human.
- Compose or contradict — and the store can't tell. Sunscreen-plus-hat merges; seat 14A versus seat 14A cannot. The difference is meaning, so a merge is a claim about what the user meant, and only the application can make it.
- The convergence contract replaces the one-answer guarantee: same updates, same state, everywhere. Any resolver must be deterministic and order-blind, or replicas that exchanged everything still split — the divergence trap.
- Convergence is the floor, not the finish. Last-write-wins converges perfectly on a destroyed write. Ask both questions: does it converge, and does it keep what people meant?
Now weigh the contract you just signed up to enforce: deterministic, order-blind, intent-keeping, hand-written, correctly, for every field of every feature, forever. That's a heavy tax on being available. Unless the values themselves could carry the proof — a counter that can't miscount, a set that unions itself, data types where the merge is built in and mathematically incapable of the trap. They exist, they run inside systems you use daily, and they're next: CRDTs.