Skip to main content

Module sync

Module sync 

Source
Expand description

Daemon-held multi-device sync + execution-lease subsystem — the sync.* / lease.* WS surface’s engine (slice B6 of docs/proposals/multi-device-sync.md).

One SyncSubsystem per daemon is one device in the user’s sync fleet: it owns a car_sync::SyncSession (the pump over an append-only oplog + deterministic fold) against a car_sync::FsRelay rooted at <journal_dir>/sync/relay/ — so the single-user two-device case (two Macs sharing that directory, e.g. via a synced folder, or two daemons on one host in tests) converges out of the box — plus an in-process linearizable car_sync::InMemoryLeaseCoordinator for the execution lease.

The handler layer (handler.rs) is thin: it parses params and calls the &mut self methods here under the subsystem’s tokio::sync::Mutex, which is why the convergence + fence + lease behaviour is unit-tested directly on SyncSubsystem (two instances sharing an FsRelay dir + a cloned coordinator) rather than only through the WS round-trip.

§State domains: wired vs. pending (honest boundary)

  • Conversation — wired end-to-end. SyncSubsystem::record_turn routes a conversation write through the oplog (a Surface::Conversation op), and SyncSubsystem::resume returns the repaired, provider-valid Vec<Message> from car_sync::SyncState::resume_messages — so transcript resume across devices is real, not a stub. What is not done: auto-teeing the daemon’s existing internal conversation persistence (car-inference/memgine) into the oplog — a host uses sync.record_turn explicitly. That internal reroute is the pending B2 adoption step.
  • Intent ledger — wired. SyncSubsystem::record_intent writes the leased-execution Surface::Intent ledger (terminal-guarded), and SyncSubsystem::fence_check runs the B6 dispatch fence over it.
  • Any other surface — a generic tee. SyncSubsystem::append records an op on any car_sync::Surface (knowledge/skill/declagent/routing/…), so a host can tee those domains into the oplog today. Rerouting the daemon’s own knowledge/registry write paths through it is the pending step.

§Encryption & distributed coordination

Two subsystem flavors:

  • SyncSubsystem::open — the local default: a shared-directory FsRelay + an in-process InMemoryLeaseCoordinator, cleartext payloads. The single-host / synced-folder case.
  • SyncSubsystem::open_remote — the Parslee-backed path (selected when .car/config.toml [sync] backend = "parslee"): a NetworkRelay + distributed NetworkLeaseCoordinator over a car_sync::SyncTransport (the real car_parslee::ParsleeSyncTransport, or a LoopbackTransport reference server in tests), scoped to the user’s Parslee identity, with op payloads E2E-encrypted under a login-derived SyncKeyProvider. The session encrypts-on-append / decrypts-before-fold, so the relay holds only ciphertext, and the lease is a genuinely cross-device fencing register. This is “phone + Mac after one login” and it is exercised end-to-end (two_remote_devices_converge_e2e_through_the_network_relay).

The cross-device key is login-derived: car_sync::DerivedKeyProvider from_passphrase is the zero-knowledge source that works today (same passphrase → same keys on every device, the server never sees it); a Parslee-issued per-user master is the alternative. Config propagation has a tested tee primitive (SyncSubsystem::tee_config/SyncSubsystem::config_get, partition-guarded). Under E2E, checkpoint publishing is guarded off (SyncSession::publish_checkpoint) so no cleartext/inconsistent snapshot reaches the relay.

Remaining follow-ups: the live Parslee server implementing the contract (cross-repo — docs/proposals/parslee-sync-backend.md); per-subsystem adoption of the config tee (each config write-path calling tee_config

  • applying config_get on pull); and per-scope encrypted checkpoint push (restores relay-side GC — until then the server owns retention).

Structs§

HostEndpoint
One device’s announced A2A endpoint and peer identity.
SyncSubsystem
A daemon device’s sync endpoint + lease coordinator. Held behind a tokio::sync::Mutex on ServerState; every method is &mut self.

Functions§

parse_intent_status
Parse an IntentStatus string.
parse_scope
Parse an optional scope param: {scope: "personal"} (default) or {scope: {org: "acme"}} / {org: "acme"}Shared.
parse_surface
Parse a surface param string into a Surface. registry:<kind> maps to Registry { kind }. Unknown surfaces error (never silently defaulted).