Convergence Without Silent Loss: Versions, Conflicts, and Safe Replacement
Syncthing's block evidence can show that two file contents differ, but it cannot by itself decide which edit expresses the user's intent. This chapter focuses on the layer above transfer: how version vectors preserve causal information, how concurrent changes become deterministic conflict decisions, and how the puller protects a local file while a remote replacement is being prepared. The practical judgment is that Syncthing can converge reproducibly while preserving evidence of disagreement; reproducible convergence is not the same as a semantic merge or a backup.
A file version carries history, not just a date
A wall-clock timestamp answers when a device says a file was modified. It does not answer how that modification relates to changes made elsewhere. Suppose a laptop and a server both have the same starting version of a document. The laptop edits it while disconnected, and the server independently edits its own copy. If both clocks are accurate, the timestamps still do not tell Syncthing that one edit descended from the other. They only place the edits on a shared time axis that may be imprecise, adjusted, or insufficient to represent causality.
Syncthing's FileInfo therefore carries a version vector. A vector contains counters associated with device identities. When a device makes an update, its counter advances. When two vectors are compared, one can be equal to, newer than, or older than the other; they can also be concurrent, meaning that each contains an update the other does not dominate. Merging vectors takes the maximum counter for each participant, preserving the combined knowledge without pretending that one independent edit happened after the other.
The difference is easiest to see with the two-device example. Let the shared document begin at a common state. The laptop creates an update recorded under the laptop's counter. The server creates a separate update under the server's counter. Neither vector is greater than the other in the causal ordering. A simple “pick the later timestamp” rule would hide that fact. The vector comparison instead tells Syncthing that it is looking at competing histories and must enter conflict handling rather than treating one as an ordinary successor.
Now change the timing. If the laptop's update reaches the server first, and the server edits the file after incorporating that update, the server's later vector contains the laptop's contribution as well as its own. That version is causally beyond the laptop's earlier version, even if the wall clock on the two machines is unusual. The vector is not trying to make clocks accurate; it records which device knowledge was available when a later change was made. This is why it is a better basis for ordering distributed updates than a single timestamp.
Version vectors do not merge the text of a document. They do not understand paragraphs, database transactions, image layers, or application-specific intent. They answer a narrower but essential question: which update histories are related, and which are independent?