* fix(debugger): let REA exit when a debugger could not be stopped
`rea debug-with-gdb` and `rea debug-with-rizin` printed cleanup_incomplete
and set exit status 1, but the retained child and its pipes kept the event
loop alive, so the process never exited. A stdio MCP server whose client
disconnected hung the same way.
closeOwnedDebuggerSessions is the owner both managers finish through. It now
unreferences retained sessions, as supervised providers already do after
incomplete cleanup, restores the references on retry, and names the retained
process IDs. The one-shot commands report those IDs, since no later command
can retry. Debugger ownership, signals and detach behavior are unchanged.
GDB cleanup requests also no longer hold the host until their 120 s command
deadline, because cleanup already bounds its own wait.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* fix(debugger): name retained debuggers when an MCP server shuts down
An MCP server that exits with a retained debugger logged only "REA provider
cleanup failed" and "could not close cleanly", so nothing named the process
left for the caller to check. The PIDs were on OwnedDebuggerCleanupError, but
each shutdown reporter read only the outer aggregate's message, and the debug
failure_cause description dropped the field too.
The failure type now lives in its own dependency-free module with one reader
that walks composed failures. The shutdown report, the server's onclose log,
the debug description and the one-shot CLI all use it, and the shutdown report
writes the same remediation the CLI returns.
The fake debuggers now model each request exactly, with real reply shapes, and
a request they do not model fails the test.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* test(debugger): compare retained-debugger guidance with its formatter
The new checks froze the wording "Check process ... and its target".
docs/testing.md asks guidance checks to compare with the owning formatter,
alongside independent checks of the facts. They now do, and each still proves
the process ID is named, because a formatter comparison alone would pass if the
formatter dropped it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>