Files
codebase-memory-mcp/tests
Martin VogelandClaude Fable 5.1 00060cec85 fix(daemon): fail the client fast when the daemon cannot start
A daemon that died at listener publication (a full /tmp) took the
lifetime reservation, failed, and released it; the waiting client saw the
generation vanish, respawned it, and repeated that for its whole 30 s
deadline before reporting "CBM daemon is active or starting but could not
accept this client" -- the opposite of what happened, with no cause and
no path. MCP hosts then dropped the server silently (#1828).

A detached daemon has no stderr and no channel back to its launcher, so
the host now appends one start-failure record per failed start to
<cache>/logs/cbm-daemon.start-failures.log -- next to cbm-daemon.log,
through the same owner-only private-log open. Deliberately NOT the
runtime directory: that is exactly what a full /tmp cannot write, and a
new artifact there would entangle the stale-generation cleanup that
#1894 just hardened. The record carries the listener detail from the
previous commit (component, stage, errno, path) plus the runtime
directory and a wall-clock stamp, and is written while the lifetime
reservation is still held, so a client that watches the generation
vanish already finds the cause.

The client bootstrap loop reads that record (every 50 ms after its own
spawn, and unconditionally before any relaunch), accepts only records for
its endpoint not older than its spawn instant (2 s skew), and stops at
once:

    error: CBM daemon failed to start: pending_publication failed with
    ENOSPC (No space left on device) at /tmp/cbm-daemon-1000/cbm-<key>.sock.pending.tmp;
    see ~/.cache/codebase-memory-mcp/logs/cbm-daemon.log

The read is an optional bootstrap op (unit contracts with fake ops are
untouched); the production op resolves the cache log directory. Every
other wait state -- a live or stopping generation, a mute holder, a
concurrent starter -- keeps its existing semantics and diagnostics.

Tests (daemon_bootstrap):
- daemon_bootstrap_fails_fast_when_daemon_dies_at_publication: the
  production bootstrap (real cohort, probe, startup lock, handoff) with a
  seam-only spawn override that forks a REAL daemon host whose record
  writes fail with ENOSPC. RED before: 34.7 s and "active or starting";
  GREEN after: FAILED in well under 5 s naming ENOSPC and the temp path,
  one child spawned, daemon log carries errno=ENOSPC path=... .
- daemon_bootstrap_start_failure_record_round_trip: record/read/format
  contract, a stale record and another endpoint's record are ignored.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-09-08 02:01:33 +02:00
..