One OS process loads one configuration set, catch-up’s projections, then observes those trees until stop.
It is the only writer of projections and of mapping edits that originate from blf.
Terms are in CONTEXT.md; decisions are in docs/adr/.
Hub and replicas
A link is a physical copy, so an edit in a target is invisible to the managed project until the daemon copies it.
The managed project is the hub. A successful apply increments a per-path generation, then fans out to in-sync replicas except the source.
Fan-out never writes the source replica and never writes an out-of-sync replica.
Shape of the process
One process, two programs in one address space. The accept thread binds JSON IPC and answers status without hashing.
Each managed project is a worker unit: one queue, at most one job, a LiveSync over that hub and its targets.
Distinct units run in parallel. A mapping unit (hub × one target) is an expansion row, not a thread.
0021: hashing or mutating a hub is a job on that unit. Submit from the resolve UI is a job too.
Lifecycle
IPC binds before catch-up. Start stays in the foreground until phase ready. Shells other than status wait through catch-up.
Live observation and the resolve UI start only in ready. Out-of-sync flags and held copies survive catch-up; catch-up does not overwrite an isolated replica.
Decline a removal plan, or start with no TTY when removals exist, and nothing is spawned.
Live path
Each worker unit scans its trees, coalesces in a mailbox keyed by (path, replica), then applies one change at a time.
Update is compare-and-swap. Delete uses a generation window of 3 and held copies, not isolation.
A mailbox pending on a replica also skips fan-out of that path, so a second replica is not overwritten while its own change is queued.
Mapping edits
The daemon does not watch mapping files. External edits take effect only by diffing the configuration set against the persisted mapping snapshot:
on start, before spawn; on reload, when already ready. Internal revlink / remove writes do not go through this classifier.
Same classifier both times. Start runs it in the foreground before spawn; reload runs it against the already-ready process.
Resolve UI
Status lists isolation; it does not pick a winner. While ready, the daemon serves localhost HTML on a second port (token in the set run directory).
Submit is resolve: a new hub generation, every replica of that path overwritten, out-of-sync cleared for that path only.
Start does not ask an isolation ack: this UI is served by the running daemon. Reload still warns and acks. Held rows list a clause only; restore stays later.