mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-03 08:03:38 +08:00
Every Windows guard shared ONE daemon. test_daemon_stability.py said each section "runs under its OWN cache directory: daemon coordination is cache-scoped" -- it is not. The rendezvous key is FNV-1a over a compile-time domain string (service.c: cbm_daemon_rendezvous_key) under a machine-global parent (win_default_runtime_parent -> SHGetFolderPathW(CSIDL_LOCAL_APPDATA), which ignores the LOCALAPPDATA variable). So the guard's own `daemon stop` and kill -9 sections, the sibling guards, and anything else on the runner all met the same daemon, and a daemon wedged anywhere failed every check after it. That is the shape of this week's test-windows-guards red on #1874: lifecycle's `daemon start` connected, the UI-config handshake never answered, and stability / hook_augment / ui_drive / cli_non_ascii went red in a row with an orphan daemon killed at cleanup -- on a diff and a base that were each green elsewhere. CBM_RUNTIME_DIR is the only relocation hook (bootstrap.c, resolved in cbm_daemon_bootstrap_endpoint_new for every product endpoint). Each stability section now gets a private runtime parent next to its cache, created before the binary runs -- the endpoint validates the parent and never creates it -- and the daemon inherits it from the client that spawns it. Proven on macOS: a daemon on the default rendezvous keeps its pid across the whole guard (three stops and a kill -9 inside it). The reporting was hiding the cause as well: * every SETUP FAIL printed nothing at all, and every RED printed a 300-400 character HEAD slice, which is the allocator preamble, never the error. Excerpts now show the tail (1500 chars); setup paths print the daemon's full output. * a subprocess timeout raised on a parallel-client worker thread was lost and the client reported as "rc=none" with no output; it is now kept as a failed result with its partial output. A section-level timeout is a named RED with the command and output, not a bare traceback. * the MCP session's stderr went to DEVNULL; it now goes to a file that is printed when initialize never answers -- and that case is a RED against a running daemon, not a "setup" skip. * exit 2 was documented and never produced. Only `daemon start` failing raises it now (test_daemon_lifecycle.py owns that surface as a regression, so the board loses nothing); main() runs every section and names all of the failing ones. * test_hook_augment.py / test_cli_non_ascii_arg.py print full stdout AND stderr on their index-setup failures instead of 300 chars of stdout. On POSIX (local iteration only) the namespace lives under /tmp: sun_path caps the socket at 104 bytes on macOS and TMPDIR there is ~50 bytes deep. Out of scope, noted: test_daemon_lifecycle.py, test_non_ascii_path.py and test_ui_drive_listing.py still use the machine-global rendezvous; a too-long CBM_RUNTIME_DIR on POSIX is refused (ipc.c sun_path check) with no validation detail. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>