Skip to content

Phase 06 Plan 03: Daemon Summary ​

Single-owner daemon with reap-before-serve, four-method channel dispatch, and graceful down shutdown, sharing the composition-root wiring with realm mcp

Performance ​

  • Duration: single execution wave
  • Started: 2026-10-22
  • Completed: 2026-10-22
  • Tasks: 3
  • Files modified: 2

Accomplishments ​

  • buildDaemonHandle builds the exact createRealmHandle path with production adapters (SessionExecution over the libpod client, AndaBridge over the configured URL, spawnOpenShellRunner, Date clock); tests inject the existing fakes at the same seam (P6-D12)
  • startDaemon enforces single ownership per state directory: stale-socket connect-then-remove, then listen plus 0600 chmod; a live rival refuses with LOCK_CONFLICT
  • Reap-before-serve: reapStartup with the bounded removeAllRealmContainers sweep runs before the serve gate opens; a failed sweep rejects startup with records untouched (P6-D4, T-06-06)
  • All four CONTROL_METHODS dispatch over the 06-01 channel with catalogue-code-only replies: status via displayStatus, up via probe-then-create, down via drain-then-close, doctor via runChecks (T-06-08)
  • Graceful shutdown on down: stops accepting, drains in-flight within SOCKET_TIMEOUT_MS, delegates teardown to the RealmHandle close path, removes the socket, resolves done; a concurrent second down is a no-op (T-06-07)
  • Threat mitigations T-06-06 (reap before serve), T-06-07 (single owner plus bounded drain), and T-06-08 (shared wiring, no second dispatcher path) are implemented as specified

Task Commits ​

Per-task commits were not made in this wave: the wave constraints prohibit running git commands, and the orchestrator gates and commits afterward.

  1. Task 1: buildDaemonHandle plus single-owner start - uncommitted (orchestrator commits)
  2. Task 2: Reap-before-serve and method dispatch - uncommitted (orchestrator commits)
  3. Task 3: Graceful shutdown on down - uncommitted (orchestrator commits)

Files Created/Modified ​

  • src/daemon/daemon.ts - buildDaemonHandle, startDaemon, method dispatch, graceful shutdown (P6-D1, P6-D4, P6-D12)
  • test/daemon/daemon.test.ts - CLI-01 and RT-06 ownership, reap-order, dispatch, and shutdown cases

Decisions Made ​

  • Second owner refuses with LOCK_CONFLICT; an EADDRINUSE bind race between the stale probe and listen maps to LOCK_CONFLICT rather than a generic failure
  • No andaUrl and no injected bridge builds a module-private unreachable bridge (connect rejects ANDA_UNREACHABLE), so status and doctor keep working while up reports unreachable through the controller
  • Omitting both the sweep seam and any libpod seam refuses with SCHEMA_INVALID at startup rather than silently skipping the P6-D4 reap
  • down replies after controller close with the true outcome; a concurrent second down answers the current snapshot without re-running teardown
  • down keeps its own in-flight count during the drain, so the drain waits only for other requests (inFlight above one)
  • Probe defaults mirror the doctor defaults exactly (argv-form execFile, env spread copy, plain dial); no new helper contract was introduced

Deviations from Plan ​

None - plan executed exactly as written. Style-level adjustments during writing (inline narrowing instead of a local record guard, typed error members instead of inline casts, removal of a dead connection-tracking set) changed no behavior.

Issues Encountered ​

  • The mid-write discovery that src/cli/main.ts (sibling plan 06-04, same wave) guesses buildDaemonHandle(env) with an env-only signature. That guess cannot satisfy P6-D12 (the handle needs runtimeInput, policyPath, sessionId). Messaged Exec06_04 with the exact 06-03 export contract so its defaultBuildHandle passes full options. No 06-03 change was needed: the plan-specified options object is the correct contract.
  • Verification (tsc plus node --test) was not run: this wave prohibits running builds, tests, linters, and git commands. The gate run belongs to the orchestrator. Test titles cite CLI-01 or RT-06 as the plan requires; grep for those IDs plus the tsc/test invocation in the plan verification block is the orchestrator's check.

User Setup Required ​

None - no external service configuration required.

Next Phase Readiness ​

  • 06-04 (CLI) can consume buildDaemonHandle and startDaemon through the contract messaged to Exec06_04: build { runtimeInput, policyPath, sessionId, libpodSocketPath, env } from CLI-resolved values; every other seam is optional
  • The e2e proof can drive up/status/down/doctor over a real socket pair with scripted probe and sweep seams; no live Podman, OpenShell, or daemon is needed in tests
  • Live Podman/OpenShell/daemon acceptance remains gated as the phase brief requires; the suite proves unit-level behavior only

Phase: 06-cli-daemon-and-host-packagingCompleted: 2026-10-22

AGPL-3.0-only. Copyright (C) 2026 Spectrum Web Co/swcstudiospace.