Skip to content

Harden the v2 sync engine: list merge policies, conditional deletes, shadow from reply, returning users, clock skew - #52

Merged
adamski merged 22 commits into
mainfrom
adam/dev-1150-hardening
Oct 1, 2026
Merged

adamski merged 22 commits into
mainfrom
adam/dev-1150-hardening

Conversation

@adamski

@adamski adamski commented Sep 30, 2026

Copy link
Copy Markdown
Collaborator

Hardening pass on the v2 sync engine, closing the design-review findings on lists, deletes, shadows, returning users and clock skew (DEV-1150).

  • List merge policy per path (Atomic, Append default; Full reserved and refused). List conflicts are always whole-list; append on one side merges with same-length edits on the other; overlapping same-length edits, both-side appends, inserts/removes and repeated values conflict.
  • Conditional deletes. A delete names the version it was made on (base_hash). A newer version supersedes a pending delete (DeleteSuperseded), keeping pre-delete edits as a kept copy (delete_superseded) only when edited. A no-shadow delete fetches the server copy first unless it is a never-sent create (incl. migrated docs). A delete the server refuses restores the server version (delete_refused copy when edited). A pending delete goes out behind parked rows; a refused delete parks itself.
  • Shadow from the upload reply, with a divergence cap: after 3 corrective uploads a doc parks with SyncError{diverged}. Shared 59-case JSON Patch fixture with the server.
  • Returning users: uploads are held until own's first changes answer. Refused uploads keep their sent marks.
  • Clock skew: a clock_skew join is re-signed once with the server's clock; the offset is kept for later reconnects.

Tests: lib 570, wire 15; property model covers lists on both sides under both policies at 20k seeds.

Closes #3

…n only while positions line up); otherwise the server's list is kept and the local one set aside
… both sides touch overlapping indices, so a shifted diff (a remove plus an insert, or a reorder) can no longer read as agreement; also treat an identical result at a colliding root list as clean, not a conflict
…when both sides changed it and ended up different, since a disjoint-looking edit may really be retargeted at the other side's twin
…ic and checks no element is lost or duplicated at a rebase
…res list conflicts to be whole, and checks element order
… another device supersedes it, and edits made before the delete are kept
…ently revive an element another device removed
…or fetches the server copy first, and a newer version supersedes it
@adamski
adamski merged commit 483fa3f into main Oct 1, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement delete-update conflict resolution

1 participant