Merge conflicts as design
Most CRDT writeups stop where the design problem starts — what does the merged document look like to a human?
A typical CRDT walkthrough ends triumphantly with a sentence like “and the two documents converge to the same state without coordination.” The “state” in question is a tree, or a sequence, or a map of registers. The document the user sees is a different story.
The interesting design question — the one I almost never see in the literature — is what the user sees when they open the merged document. The literature mostly assumes the user sees nothing, because the merge was clean. This is a polite lie. You can converge correctly and still leave the reader staring at a sentence that no longer means anything.
Three actual cases
I’ve been keeping a small log of merge-shaped weirdness while dogfooding Locust:
- Two devices both edit the same paragraph. The CRDT picks a winner that no human would have picked — the winning device just happened to have a higher actor ID.
- One device deletes a section the other was extending. The convergent state preserves the additions, orphaned, as a homeless paragraph.
- Both devices add a different second paragraph after the same first. The result is two disjoint trains of thought stitched awkwardly together.
The bug in each of these is not in the data structure. It is in the fact that the data structure is rendered with no visible seam, as if nothing happened.
A small claim
A merge that produced any case 1–3 should be visible as a merge in the resulting document, until the user reads through it once.
Not as a banner. As a faint stain, in the gutter, that goes away after you’ve read past it.
Pointed at by
Should the seam fade? — a question — “…rge* in the resulting document — see the claim in merge-conflicts-as-design — then the obvious follow-up is: w……” read
Sync architecture sketch — a note — “…els right; a year feels excessive. See also: the merge-conflicts-as-design essay for what the user *sees* when……” read
Locust — “…user sees and acts on. See the running thread in merge-conflicts-as-design.…” read