Repository navigation
cc's MCP debug logger writes nothing under perry — even when its catch handler demonstrably runs; and exec/execFile callback order is inverted #9500
Description
Activity
Significance upgrade from the clean 15-case re-run (layer-1-only cc binary, PR #9498 in): the missing MCP log tree is not a diagnostics nicety — it is the only remaining divergence for the whole
mcp addfamily.B11_mcp_list_cfg's detail shows stdout already byte-identical to node after the spawn fix, withHOME-PATHS-ONLY-IN-NODE: ['.cache/claude-cli-nodejs/<CWDKEY>/mcp-logs-*']as the sole flag. The same pattern holds across the add-family cases (~12 of the 15). The connect-path residual (#9499) bites only the self-server cases (E20/E21/E22), which still carry a stdout diff.So the expected suite arithmetic: #9499 + this issue together clear all 15; this issue alone is worth ~12 cases. Whoever picks it up should also note the #9485 thread's finding that the logger stays silent even when the error path demonstrably runs — and re-test on a post-#9491 build first, since
appendFileerror-swallowing (a prime suspect for a silently-failing logger) was fixed there.PR #9531 covers all three findings; the short version of what the measurements said:
- The silent MCP debug logger was cc session transcripts are written incompletely: 1 line vs node's 5 (async queue-and-flush path, NOT the exit hooks) #9421, fixed by fix(fs): appendFile must report failure, not resolve; writeFileSync must throw; mode must reach open(2) (#9421) #9491.
straceon the pre-fix(fs): appendFile must report failure, not resolve; writeFileSync must throw; mode must reach open(2) (#9421) #9491 cc binary shows both engines reaching the sameopenat(…/mcp-logs-alpha/….jsonl, O_APPEND) = ENOENT; node follows with the recursivemkdirchain and a successful retry, perry with nothing —appendFileSyncreturned success, so thecatch { mkdirSync; appendFileSync }arm that is the only code creating the tree never ran. The flush itself always happened (the 1 s timer). cc compiled from post-fix(fs): appendFile must report failure, not resolve; writeFileSync must throw; mode must reach open(2) (#9421) #9491 main writes the logs in all 15 harness cases; the shape is pinned bytest_gap_9500_mcp_debug_logger_shape.ts, which fails on a pre-fix(fs): appendFile must report failure, not resolve; writeFileSync must throw; mode must reach open(2) (#9421) #9491 tree. - exec/execFile order is a same-turn delivery artefact, not a rule. Node fires whichever of two instant children was submitted second first; for three identical batches in one process it gives
C B AthenB A C. The only order node guarantees — completion order — perry matches, and that is whattest_gap_9500_exec_callback_completion_order.tspins. The reactor is unchanged. - The module-name knowledge was five copies, not four (the HIR had two that already disagreed). They are now one table in
perry-dispatch, with every consumer derived from it.
With the logs readable, three further divergences fell out and are filed with fixtures: #9535 (child lifecycle delivered before the continuation that awaited
'spawn'→ the SDK'sNot connected), #9536 (fetch(URL instance)→Invalid URL), #9537 (null-byte validation missing on therequire()path). Those plus #9499 are what remains of the 15.- The silent MCP debug logger was cc session transcripts are written incompletely: 1 line vs node's 5 (async queue-and-flush path, NOT the exit hooks) #9421, fixed by fix(fs): appendFile must report failure, not resolve; writeFileSync must throw; mode must reach open(2) (#9421) #9491.
- added 4 commits that reference this issue
on Sep 2, 2026
Two secondary findings from the #9485 investigation (PR #9498).
1. The MCP debug log tree is never created
Node writes 6 lines to
~/.cache/claude-cli-nodejs/<key>/mcp-logs-*/…jsonlon a failed connect. Perry writes nothing — no.cachetree at all — even though the bundle'sOLcatch demonstrably runs (i8(...)/yz(...)execute; the connect returnstype:"failed", not the outerBX5catch).#9485 assumed the missing logs were purely downstream of never connecting. That is now disproven: the connect fails, the error path runs, and the logger is still silent. Most likely an async-write/exit-flush gap adjacent to the #9421 family (merged PR #9491 fixed
appendFileerror-swallowing; this logger may use a different write shape —createWriteStreamis still synchronous-under-the-hood per #9493, and a failed dir-creation on this path would now throw post-#9491 rather than vanish — re-test on a post-#9491 build first, the behaviour may have changed).Why it matters: this is why #9485 had zero diagnostics to start from. Debug logging that dies silently multiplies the cost of every other bug.
2.
cp.exec/cp.execFilecallbacks fire in the opposite order vs nodeperry: exec→execFile; node: execFile→exec (same script, same commands). Ordering-sensitive test suites and promisified-parallel patterns can see it. Small, but it is a scheduling-semantics divergence in freshly-unlocked territory (PR #9498 made these callable as
cp.exec(...)at all), so it was previously unreachable.3. Drift-capable duplicate knowledge (maintenance, not behaviour)
is_cjs_style_native_default_import,cjs_default_namespace_name,cjs_default_base_module, and the dispatch router's table were four hand-maintained copies of the same module-name knowledge; #9498 collapsed the router's copy onto the canonical one with ratchet tests. The other three remain and can drift exactly the way the router did. A follow-up that derives them from one source kills the recurring-bug factory.