ADR-0022 — Three-tree reconciliation (local / remote / synced)

Context

A sync engine must decide, per file, whether a difference between device and cloud came from the local side, the remote side, or both (a conflict). Doing this with a two-way diff (local vs remote) is ambiguous — “remote added X” is indistinguishable from “local deleted X” — and that ambiguity is the classic cause of sync data loss. Representing sync as a queue of in-flight operations (the legacy Dropbox model) is not robust to crashes, reordering, and offline divergence.

Decision

Model client state as three trees and compute sync as a three-way merge (Dropbox Nucleus model):

A pure planner consumes (R, L, S) and emits operations to converge them; each completed op advances S. Nodes are keyed by stable ID, not path (O(1) renames). The server’s change journal (ADR-0008) provides a total order, so per-file vector clocks are unnecessary (unlike P2P engines such as Syncthing).

Consequences

Positive

Negative / costs

Alternatives considered

Scaling

Dirty-set planning visits only changed nodes (not the whole tree); subtree ops execute in parallel; folder moves are O(1) via node-ID.