Skip to main content

Module reload

Module reload 

Source
Expand description

synaps daemon reload (PLAN-phase3 §2.8, C3): version gate → drain → Checkpoint{Reload} every session → reload-state → announce Reloading/Bye{Reloading} → execv self (same pid, adopted flock, CLOEXEC listener) → new image rehydrates sessions from reload-state BEFORE accepting.

What reload cannot preserve (§2.8, stated once): in-flight turns (checkpointed = cancelled; partial history + restart marker kept), pending prompts (answered None), PTY/background shells (closed, announced), turn_replay, input ownership (the owner reclaims it on reconnect via was_owner). What it preserves — each session’s Checkpoint{Reload} reply carries a SessionReloadRecord: its journal and id (the rehydrated session continues the same journal), its SessionConfig as created (cwd, system, prompt manifest, compaction policy, auto-compact, …), its keep-warm pin, its lifecycle (a Parked session comes back Parked), the non-persisted runtime knobs (settings_replay: context window, compaction model, retries, timeouts, tool-output cap, worker grants, /system), and the CURRENT model/thinking (/model mid-session survives).

Structs§

Prepared
Steps 1–4 (§2.8): gate, drain, checkpoint, reload-state, announce. Nothing irreversible has happened when this returns Ok; the caller (the requesting connection) sends its own Bye{Reloading}, flushes, then calls exec.
PrintVersion
<exe> daemon --print-version output.
ReloadRequest
ReloadSession
One recorded session.
ReloadState
registry_dir()/daemon[-P].reload.json body.

Enums§

ReloadError

Constants§

DRAIN_SECS_ENV
Env: default drain budget in seconds.
LOCK_FD_ENV
Env: inherited daemon.lock fd (mandatory when RELOAD_STATE_ENV is set).
RELOAD_STATE_ENV
Env: path of the reload-state file handed to the new image.
RETRY_AFTER_MS
What clients are told to wait before reconnecting.

Functions§

adopt_from_env
New-image side (Daemon::start): when RELOAD_STATE_ENV is set, the lock is ADOPTED from LOCK_FD_ENV (mandatory — refuse to start without it, risk §6.8) and the recorded generation is returned.
exec
Step 5: rewrite daemon.json (generation+1, same pid), stop sidecars, hand the flock to the next image and execv. Returns only on failure — then daemon.json/reload-state are restored, extension discovery is re-spawned (the sidecars were stopped for the exec — M4: no zombie daemon without hooks), and the old image keeps serving (sessions checkpointed but alive; clients that got Bye reconnect to THIS image — a reconnect_of.generation mismatch is tolerated, the daemon answers with its own generation).
prepare
probe_version
Run <exe> daemon --print-version (5 s) and parse it.
rehydrate
reload_state_path
resolve_exe
The executable to re-exec: argv[0] canonicalised (NOT /proc/self/exe, which reads “(deleted)” after an in-place rebuild); current_exe only as a fallback when argv[0] is not resolvable (e.g. bare name on PATH).
validate_exe
M8: --exe must be something we would trust to execv in our own pid: an existing regular file (canonicalised), executable, owned by our uid (or root — package-installed binaries), not group/world-writable. Returns the canonical path. Same-uid 0600 socket → not a privilege boundary; this is a footgun guard, not a sandbox.
version_gate
Directional gate (§2.1): new protocol ≥ ours (clients must still be able to reconnect) and new binary ≥ ours (newer OR EQUAL; same-version rebuilds are the common case).