feat(daemon): quiesce request that retires an idle daemon atomically
Merged
TH
10h ago+688+688+012345678901234567890123456789-15-15-01234567890123456789
Summary
Layer 1 of 3 for #3754 (umbrella #3747): the daemon half of replacing an incompatible daemon safely.
- A daemon now answers
daemon_quiesce, authenticated with its token and fenced to its pid and start time. It closes admission and counts in-flight requests, sessions, repair sessions and live leases in one synchronous step. Any of them refuses withdaemon-busyand reopens admission; otherwise it answersdrainingand exits. - A remote-origin request is refused. The request is answered before dispatch, so it works on the socket and HTTP transports.
- The daemon publishes
capabilities: ['quiesce']indaemon.json; a daemon that predates it omits the field. - Shared vocabulary lives in
daemon-resolution.ts, and the daemon side indaemon-idle-reap.ts, because both are already in the eager closures. ADR 0006 gains a short section, including what the census does not count (uploads, lease-less holds).
No client behavior changes here. 10 files. The last PR in the stack closes #3754.
Validation
pnpm check:affected --run --head ad938223f9: passed (format, lint, typecheck, layering, fallow, build, vitest-related). New runtime tests boot the real daemon and quiesce it over its socket and HTTP: idle drain, busy refusal per cause with admission reopened, wrong token, pid and start-time fences, remote-origin refusal.
🤖 Generated with Claude Code