A client refused because another CBM build owns the account daemon printed
only "Close all CBM sessions and commands, then retry." The reporter had a
0.10.3 daemon kept alive by a running Codex session while starting 0.11.0
from a terminal, and nothing in the message said which process that was,
that an agent session held it, or that `daemon stop` exists.
The refusal itself is correct and stays unchanged: session-managed daemons
serving live sessions must never be killed by a newer client, and
cbm_daemon_conflict_format() is validated byte-for-byte across generations
on the HELLO wire, so its text cannot change without breaking old/new
daemon pairs.
The fix adds a separate, client-side remedy sentence built from the
cross-build STATUS probe (cbm_daemon_conflict_remedy_format): active daemon
pid, version, permanent vs session-managed, "already stopping", the pids of
the CBM sessions holding it, the likely cause (another editor or agent
launched a different install; compare `which -a codebase-memory-mcp` with
each client's MCP config) and `daemon stop` once no session uses it. When
STATUS does not answer, the remedy points at `daemon status`.
It is appended on every user-facing conflict exit: the MCP/CLI bootstrap
path (after the older-permanent auto-drain policy declines), the one-shot
CLI exact-build cohort refusal and the MCP client cohort refusal (the path
the reporter hit). Hooks skip the extra probe to keep their fail-open
budget. The probe uses the `daemon status` budget (3 s): the daemon hashes
the ~300 MB peer image before answering, which overran the 1 s connect
budget in the real-binary proof.
No identity or admission check changes; STATUS is already the
authenticated, cross-build observability op behind `daemon status`.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>