Builtpublic

Protocol

Conflict copies never appear because every folder has exactly one writer.

1 writer

Two files is the whole thing. One request, one response. A few conventions sit on top.

Every folder has exactly one writer

Two-way sync produces conflict copies when two machines edit the same file. So the folders are split such that the situation cannot arise.

Folder Written by Read by
<peer>/inbox the senders the peer
<peer>/outbox the peer only the senders
<peer>/log the peer only anyone

No file is ever edited by two machines. So there is no conflict-resolution logic — not because conflicts don’t happen, but because the structure makes them impossible.

The folder name names the side that executes. home/inbox is what the home machine runs. I originally named them by sender and found it confusing, so I flipped it — looking at a file, the question you have is “who runs this,” not “who sent it.”

Half-written files are never replicated

A file is written under a temporary name and then renamed. By the time the sync tool sees it, it’s already complete.

Skip this and half-written JSON crosses over, and the far side fails parsing it. And that failure barely reproduces — it only happens when file size and sync timing line up.

The id is the filename

The request id always equals the filename, and it carries the sender’s name inside it.

So two machines writing into the same inbox never collide on names. And the file listing alone tells you who sent what and when — the directory listing is the log.

The alternative was a separate id with sequential filenames, but then you have to open a file to know what it is.

Telling silence apart from “working on it”

An async channel doesn’t fail with an error. It fails with silence, and silence is indistinguishable from still working.

So the watcher writes running the instant it claims a job, and overwrites it when finished.

That one line is what separates “not seen yet” from “being worked on.” It changes the question you ask when no answer comes: the first means suspect the sync, the second means just wait.

The bug: head-of-line starvation

The code that capped how many jobs to handle per tick ran before the filter that removes already-answered requests.

So if three finished-but-uncleared requests sat at the head of the queue, new work was never picked up at all. No error. The watcher kept ticking. The logs looked fine.

The smoke test caught it because the fourth job went unprocessed. The first three all passed — three jobs would have shipped it.

It surfaced on the fourth because the cap happened to be three, and that was luck. With a cap of ten it would have surfaced on the eleventh, and there is no reason to throw eleven jobs at a smoke test.