Files
codebase-memory-mcp/tests
Martin VogelandClaude Fable 5.1 92cb3b9a4b fix(test): bound the cli activation-guard scope fixture's host waits (#2115)
The four namespace-scope tests fork a real host daemon and, in the parent,
waited on it with two UNBOUNDED calls: read() for the child's one-byte
readiness signal in cli_scope_fixture_start, and waitpid(host, 0) in
cli_scope_fixture_finish. If the forked child stalls before it can signal —
a fork-time sanitizer allocator stall is the classic cause, the same hazard
the earlier posix_spawn work addressed — the parent blocks forever and the
WHOLE cli suite hangs to the CI wall-clock kill (the observed rc=124 at 900 s
on the ubuntu-24.04-arm gcc shard, which passed on every other #2115 shard).

Attribution: the production drain path is already bounded (DRAIN 15 s, CONTROL
2 s) and a foreign-namespace install takes the non-blocking scope probe and
skips draining entirely, so this is not a production deadlock — it is a
test-fixture determinism gap, amplified by ASan on a loaded arm runner.

Fix, test-only:
- cli_scope_wait_ready(): poll the ready pipe to a generous, bounded deadline
  (90 s, comfortably past the child's own 45 s cohort-admission deadline plus
  service start), so a wedged child yields a clean ASSERT_TRUE(ready) failure
  instead of an unbounded read().
- cli_scope_reap_host(): reap with WNOHANG to a bound (60 s), then SIGKILL and
  reap, so a wedged child is force-killed rather than hanging finish(); a
  killed child leaves host_exit == -1, which fails the caller's assertion
  cleanly. This also prevents a stuck child from holding cohort locks that
  would poison later tests.
- cli_scope_host_serving(): raise the status probe deadline from 5 s to 15 s so
  a slow-but-alive daemon on a loaded runner is not misread as "drained" (the
  flaky ASSERT(host_serving) failure this fixture showed); it still fails
  cleanly when the daemon is genuinely gone or reports stopping.

None of these decides a healthy test — the child signals in well under a
second on a healthy runner; the bounds only convert an otherwise unbounded
hang into a deterministic pass/fail.

The scoping contract still binds: with cli_activation_resolve_scope forced to
always return ACTIVE, the three "must-not-drain" tests go RED at
ASSERT(host_serving) and the host-namespace "must-drain" test stays GREEN.
cli suite: 313 passed locally (macOS, twice); 30-round pre-fix and 8-round
post-fix stress of the four tests were clean; a fault-injected never-ready
child fails all four cleanly in ~37 s with no suite hang.

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