2026-10-26: The Reboot That Met July's Board

A reboot does not break a daemon replaced four days ago. It evicts the old binary from RAM so you finally meet the new one.
When manoir came back from its October 25 reboot, apple-post-boot.sh paged with a stubborn scoreline: 32->32/41 — 1 fixed, 6 still failing. Even the single “fix” was fiction: Phase 3 had dutifully executed docker start homeassistant on a Mac whose Docker engine was retired in August and whose Home Assistant moved onto a dedicated Green appliance in July. Underneath those six red lines and two amber warnings sat two genuine service regressions, two silent launchd casualties, and four probes still grading a haus from three months earlier.
Six reds and two warnings, sorted by what was actually true
Section titled “Six reds and two warnings, sorted by what was actually true”| Check | What the board claimed | What was actually on disk |
|---|---|---|
mac/memory-vault |
:42069 DOWN |
Real regression. On October 22, memory-vault-mcp replaced ~/.sanctum/bin/sanctum-memory-vault. The old :42069 HTTP process stayed resident in RAM until the October 25 reboot; afterward, haus.sanctum.memory-vault launched the stdio-only MCP binary against /dev/null and exited every 15 seconds with connection closed: initialize request. |
mac/yoda-canary-internal |
last cycle FAIL |
Real voice regression. Yoda failed four consecutive hourly internal voice canaries (20:00Z through 23:00Z) with DuplexClosed while popping dead pre-warmed worker subprocesses from livekit-agents’s idle queue. |
mac/home-assistant |
:8123 DOWN |
Stale probe + hidden crash-loop. Home Assistant was healthy on Green via 10.0.0.1:8123 (socat on bridge100), while apple-services.sh still polled localhost:8123. Meanwhile, haus.sanctum.ha-green-bridge was silently crash-looping every 10 seconds under /opt/homebrew/bin/python3 (ModuleNotFoundError: No module named 'websocket'). |
mac/haus-control |
degraded: home-assistant |
Cascade. mac/firewalla-bridge (:1984) and lan/firewalla were healthy; the composite check failed solely because mac/home-assistant failed. |
mac/dashboard |
:1111 DOWN |
Stale probe. Command Center had moved behind haus.sanctum.pq-terminator.1111 (X25519MLKEM768 TLS 1.3 over command-center.sock), returning HTTP 200 on HTTPS while the probe spoke plain HTTP. |
vm/briefing-cron |
0 of 3 briefing jobs |
Stale probe. Morning, Cilghal, Mundi, and Windu briefings had migrated from yoda’s crontab to four haus.sanctum.*-briefing Mac LaunchAgents. |
mac/yoda-cert-monitor |
log stale or missing |
Silent launchd spawn failure. After Homebrew upgraded [email protected] in place, launchd rejected the cached vnode signature with OS_REASON_CODESIGNING at each 09:00 calendar tick. |
mac/docker |
no containers running |
Leftover directory. An empty ~/.colima folder from May triggered the local container check on a host where yoda runs every container. |
Teaching one Rust binary both doors (:42069 and MCP stdio)
Section titled “Teaching one Rust binary both doors (:42069 and MCP stdio)”In The Ferric Hub and the Compounding Wiki, memory-vault-mcp consolidated vault search, --consolidate, --wiki-lint, and --hub-caps into a single Rust binary backed by .vault.db (rusqlite + FTS5). Installing that binary onto ~/.sanctum/bin/sanctum-memory-vault unified the CLI and MCP stdio paths, while overlooking one detail: /Library/LaunchDaemons/haus.sanctum.memory-vault.plist runs that exact path as a persistent daemon (sanctum-memory-vault -m memory_vault) with MEMORY_VAULT_TRANSPORT=sse and a stale MEMORY_VAULT_PORT=18097 environment variable left over from spring.
Because the previous sanctum-memory daemon already held :42069 in memory, nothing complained for seventy-two hours. Once the reboot cleared RAM, launchd spawned the new binary with stdin wired to /dev/null. rmcp’s stdio transport read immediate EOF, logged Error: connection closed: initialize request, and died every ThrottleInterval (15s).
Splitting :42069 back into a separate binary would have reintroduced two SQLite schemas competing over .vault.db. Instead, memory-vault-mcp now speaks both transports from the same crate:
- MCP stdio (
rmcp) when invoked by an editor or agent harness with no daemon flags (MEMORY_VAULT_TRANSPORTunset orstdio). - Axum HTTP (
:42069) when invoked with-m memory_vault,--daemon,--http, orMEMORY_VAULT_TRANSPORT != "stdio", serving/,/health,/v1/search, and/v1/readagainst the sameVaultIndex.
Port resolution reads explicit --port first, then services.memory_vault.port (42069) from ~/.sanctum/instance.yaml, before falling back to MEMORY_VAULT_PORT — neutralizing the stale 18097 in the root plist without touching /Library/LaunchDaemons.
Four dead workers in Yoda’s pre-warmed queue
Section titled “Four dead workers in Yoda’s pre-warmed queue”Yoda’s voice daemon (haus.sanctum.yoda-agent) stayed running throughout the afternoon, yet four straight internal LiveKit canaries failed in three milliseconds:
livekit.agents - ERROR - unhandled exception while running the job task File ".../livekit/agents/ipc/proc_pool.py", line 176, in launch_job proc = await self._warmed_proc_queue.get() File ".../livekit/agents/ipc/job_proc_lazy_main.py", line 161, in launch_job await self._channel.asend( InitializeJobRequest(...) )livekit.agents.utils.aio.duplex_unix._DuplexClosedlivekit-agents 1.3.12 defaults num_idle_processes to 4 whenever a prewarm_fnc is registered. Under a brief host CPU stall exceeding proc_client.py’s 60-second ping_timeout, all four idle subprocesses concluded the parent had crashed and exited cleanly. In ProcPool._monitor_process_task, the supervisor removed each exited child from self._executors and spawned replacements, while leaving the four dead objects sitting at the head of self._warmed_proc_queue. The next four calls popped one corpse apiece, hit _DuplexClosed on InitializeJobRequest, and hung up before Yoda could draw breath. Only after four failed canaries drained the dead entries did the fifth canary reach a fresh worker.
In yoda-voice-agent, build_worker_options() now sets num_idle_processes=0. Spawning a fresh subprocess per call adds roughly 800ms of Silero VAD load — invisible inside a 20-second greeting budget — and makes a stale idle socket structurally impossible. Live verification via python -m canaries.canary_internal completed in 4802ms (first_audio_ms=3302).
Aligning the bridges, the signatures, and the post-boot board
Section titled “Aligning the bridges, the signatures, and the post-boot board”The remaining failures were a study in Kickstart Is Not a Heal:
- Home Assistant Green WebSocket relay and supervised
bridge100forwarder (haus.sanctum.ha-green-bridge+haus.sanctum.ha-vmnet-bridge). Two cold-boot traps hid on10.0.0.1:8123:sanctum-bootstrap.shfired a one-shot backgroundsocatto192.0.2.3:8123after a 120-second VM SSH wait (dying permanently ifbridge100assigned its IP later), whilevm-autostart.shspawned a competingsocatpointing at dead127.0.0.1:8123alongside a retired:1234LM Studio plist. Moving10.0.0.1:8123 -> 192.0.2.3:8123into a dedicatedRunAtLoad+KeepAliveLaunchAgent (haus.sanctum.ha-vmnet-bridge, woken immediately byvm-autostart.shwhenbridge100comes up) removed both races. Meanwhile, pointinghaus.sanctum.ha-green-bridgeat~/.sanctum/cli-venv/bin/python3and declaringwebsocket-client>=1.8insanctum-cli/pyproject.tomlfixed itsModuleNotFoundError: No module named 'websocket'crash-loop. - Stale BTM code-directory hash and missed-calendar catch-up (
haus.sanctum.yoda-cert-monitor+ Phase 1f). Re-bootstrappinghaus.sanctum.yoda-cert-monitorwithRunAtLoad=truerefreshedlaunchd’s cached Mach-O hash for.venv/bin/python, clearingOS_REASON_CODESIGNING(179 days remainingonyoda.crt). Inapple-post-boot.sh, Phase 1e now waits for all thirteen local listeners (4040,1984,2187,8123,8199,8765,1337,4077,42069,1111,8080,8008,1138), and Phase 1f (_refresh_if_stale) kickstartsyoda-cert-monitor,keychain-sync,secrets-audit, oryoda-canary-internalwhenever a power-off left their logs past freshness before Phase 2 grades the boot. - Post-boot probes, symlink guard, and remediations (
openclaw-skills/apple-toolkit).apple-services.shnow verifies10.0.0.1:8123plusha-green-bridge.pyliveness whenlocalhost:8123is absent, probeshttps://127.0.0.1:1111/for PQ-TLS Command Center, matches the Rustsanctum-sttworker, countshaus.sanctum.*-briefingMac LaunchAgents, and checks installed runtimes (OrbStack.app,Docker.app, orcolimainPATH) rather than a leftover~/.colimafolder.create-bin-symlinks.shnow skips standalone binaries in~/.sanctum/bin/sosanctum-memory-vaultis never overwritten by a legacy Python symlink, andpost-boot-remediation.jsoncovers13guarded remediations plus23core LaunchAgents (test-post-boot-remediations.sh).
Running the full un-skipped apple-post-boot.sh --skip-signal pipeline after the cutover returned 41/41 pass, 0 warn, 0 fail, 0 fixes and emptied ~/.sanctum/state/post-boot-prolonged-failures.json to {}. A post-boot board is only an instrument when it grades the haus that is actually running — and when every bridge, binary, and timer survives the next cold start on its own.