Choosing a conflict strategy
Copy page
Decision tree
Section titled “Decision tree”Can the write be modeled as an append-only fact? yes → movement ledger (no merge conflict) no → Does each column have independent writers? yes → merge: "field" + HLC scalars no → Is the field collaborative rich text / map? yes → crdtText / crdtMap columns inside field-merge table no → accept commit-order LWW; design around last-writer semanticsLWW — default
Section titled “LWW — default”Use when: status toggles, single-writer records, server-serialized workflows.
Risk: two offline edits to the same row — last commit wins; earlier edit lost.
Mitigation: ledgers, row partitioning by device, or field merge.
Field merge
Section titled “Field merge”Use when: profile fields, settings objects where different devices edit different keys concurrently.
Scalars compare HLC timestamps. Requires merge: "field" on the table source.
CRDT columns
Section titled “CRDT columns”Use when: shared note body, metadata map with concurrent structural edits.
Not a replacement for Google Docs cursors — Nizhal targets data sync, not full collaborative editing UX.
Movement ledgers
Section titled “Movement ledgers”Use when: balances, inventory, totals — the Phase 0 sweet spot.
Offline concurrent sales become additive entries; fold is commutative.
Server as tiebreaker
Section titled “Server as tiebreaker”Mutators can reject invalid merges (throw → 400, optimistic revert) instead of silently merging garbage.
Wire NizhalObserver.onConflict to measure how often each path fires in production.