Last-write-wins silently discards the other edit
Aliases: LWW · silent clobber · timestamp overwrite
What it is
Last-write-wins (LWW) keeps whichever copy has the later timestamp and overwrites the earlier. The overwrite happens in the sync pipe; the interface usually still shows one clean value, so the loss is silent: the overwritten author gets no failure event. Later on the clock is not a newer intent, and is not a better intent. A wrong clock, a bulk upload after offline, a retry, can all make “last” an accident.
This leaf is a warning against LWW as the default sync policy. It does not unpack field-level merge, and it does not discuss how a diff should be drawn — if the product uses LWW as the only verdict, the loss is already written into the policy.
Why it happens
Distribution wants a total order. LWW impersonates one with wall clocks (or a coarse stand-in for a logical clock): the later event swallows the earlier. The replicas converge. The cost of convergence is non-commutative destruction — A then B and B then A leave different worlds, and in one of them A’s labour is zero. For the user, destruction has no matching “save failed”, because from the winning side the save succeeded. The losing side often opens later, sees the other person’s sentence, and their own as if it never existed.
Clocks make “last” unstable. A device clock the user rewound, NTP not yet in, two devices saving at almost once, all swap the winner. An offline queue uploads an hour-old edit a minute ago: if the timestamp is upload time, offline labour beats a tiny online tweak; if it is edit time, a late-uploaded essay is clobbered by someone who touched a space. Either end, LWW is using a scalar to choose in a person’s place.
Where it stops holding
Counters, toggles, a “read” flag whose semantics really are “latest wins”, and where loss is acceptable, may hurt less than a conflict dialog. A single person, one device, never concurrent, will not trigger LWW. Append-only logs (insert, never rewrite history) have no overwrite for LWW to do. LWW inside a database used to invalidate a cache does not count if what is invalidated is not prose the user thought saved. The real danger is fields people treat as documents: names, amounts, paragraphs, recipients. LWW on those fields makes silent loss the default.
Applying it
- On user-visible content fields, do not use LWW as the only conflict policy. At minimum keep the overwritten copy when overwrite happens, and turn the overwrite into a visible event.
- If the substrate is historically LWW, the product layer must translate it into a conflict, rather than render the pipe’s converged value as “the current document”.
- Timestamps order display. They do not destroy.
- How to check: device A edits a paragraph and goes offline. Device B edits the same paragraph online and saves. A reconnects and uploads. Open the document: if only B’s sentence remains, A’s paragraph is nowhere, and there is no conflict or “overwritten” notice, that is LWW silent loss. Advance A’s clock by an hour and repeat — if the winner swaps and there is still no notice, the verdict follows the clock, not the authors.