OneShot

All packsOffline Sync EngineSolve

last write wins vs crdt conflict resolution field merge

Field-level merge for free, without a CRDT library

Modeling state as (table, row, column) cells instead of whole rows means concurrent edits to different fields both survive automatically, with no merge code.

3 of 3 runs passedOne decision inside Offline Sync Engine (nextjs-dexie-postgres).

What goes wrong

A sync design built around whole-row last-write-wins treats any two concurrent edits to the same row as a conflict, even when they touch entirely different fields -- one device updates a status, another updates a note, both offline, and whole-row LWW picks one edit and silently discards the other, even though there was no actual disagreement about anything.

Why agents get it wrong

"Sync a row, resolve conflicts by timestamp" is the mental model most conflict-resolution explanations start from, because it's simpler to reason about than a cell-level model -- reaching for per-field granularity (or a full CRDT library) requires recognizing up front that most real conflicts in CRUD-shaped apps are actually non-conflicts between different fields, which isn't obvious until you've already built the whole-row version and watched it discard changes it shouldn't have.

What Offline Sync Engine pre-decides

The pack's unit of state is a cell -- (table, rowId, col) -> (value, hlc) -- so concurrent edits to different columns of the same row simply both apply; no merge code exists for that case because it was never a conflict at the storage level. Only a genuine same-field conflict falls back to LWW on the HLC, which the pack states plainly is the right tradeoff for CRUD-shaped data and the wrong one for collaborative rich text, where a CRDT library like Yjs or Automerge is the correct tool instead.

Source: ARCHITECTURE.md 'Core model: a synced cell store'

Coming soon — $99Full receipt and details for Offline Sync Engine

Related problems