Commit c05c058
* docs(plan): #264 Phase 5 TDD plan — bridge supervisor split
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(plan): #264 Phase 5 — amendments from multi-LLM plan review
- BLOCKER: child.on('error') funneled into one onDeath pass (ENOENT must
not crash the supervisor); integration test added
- BLOCKER: setEncoding('utf8') on stdin/worker.stdout (UTF-8 codepoint
splits corrupted JSON); real Buffer-split integration test
- initialize out of pending-set + initializeAnswered (crash-before-first-
response no longer wedges the handshake)
- terminal error names resolved logger.logFilePath, not tmpdir()
- SIGUSR2=exit-1 pinned by source-text test; workerRestarts monotonic
- onSpawned moved into apply()'s spawn branch
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(plan): #264 Phase 5 — codex-pair round-2 amendments (probe buffering, lock gate)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(plan): #264 Phase 5 — fix lock-gate shell snippet (shared cwd via subshells)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(plan): #264 Task 0 findings — (a)/(b) clean degradation, (c) SIGKILL repro confirmed
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(#264): LineSplitter — newline-delimited JSON-RPC framing
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(#264): SupervisorCore — handshake replay, death errors, bounded respawn budget
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(#264): supervisor entry — spawn/pipe/respawn worker, lock + parent-watch ownership
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(#264): cdp_status.bridge — supervised / workerRestarts / lastWorkerExit
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(#264): MCP entry point → dist/supervisor.js (RN_BRIDGE_SUPERVISOR=0 escape hatch)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(#264): supervisor split — architecture, troubleshooting, changeset
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* chore(#264): rebuilt dist (supervisor entry) + gitignore .brainstorm-tmp
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(#264/B200): process.ppid property, not nonexistent process.getppid()
Found by the Phase 5 lock-conflict live gate: both feature-detects always
fell back to 0, so (1) every lock recorded ppid:0 and isLockLive's orphan
check (livePpid !== body.ppid) reclaimed ANY live holder's lock — the
single-instance guarantee was broken since #182 — and (2) the parent-death
watch never fired (0 === 0 forever). New runtime test pins the real API.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(#264): carry bridge supervision facts on cdp_status failure paths + rebuilt dist
Live-gate finding: a sim with no Hermes target takes the connect-failure
path, which omitted bridge.* entirely — supervision facts are env-derived
and must be visible exactly when the bridge is unhealthy (same rationale
as the existing reconnect/autoConnect extras).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(#264): SIGUSR2 hot-reload no longer charges the crash budget
PR #273 review (Gemini): the reload's exit-1 was indistinguishable from a
crash — three reloads in 60s wedged the bridge into terminal mode. The
supervisor now flags the core before forwarding SIGUSR2; a flagged exit
respawns + replays + counts in telemetry without burning the budget.
Also documents the in-order-stdin reliance of the initialized replay.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(#264): per-child worker splitter — dead worker's partial frame can't contaminate the respawn
PR #273 Codex P2: a worker killed mid-write left an unterminated tail in
the shared LineSplitter, prefixing the fresh worker's first line and
corrupting the replayed-initialize answer. Deterministic repro fixture
(partial-then-echo-worker) + integration test; per-child splitter fix.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(#264): terminal error reaches a never-answered initialize (no silent handshake hang)
PR #273 Codex P2 round 2: initialize is exempt from pending (replayable by
design), so a worker crash-looping to budget exhaustion before its first
answer entered terminal mode without any response — the MCP host hung on
the handshake forever. The terminal transition now errors the handshake id.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(#264): queued mid-restart requests are delivered exactly once, never double-answered
codex-pair MED: a request queued during a restart was marked pending before
delivery — if the fresh worker crashed pre-drain, the id got a -32000 death
error AND a later queued replay (two responses for one JSON-RPC id). Now:
queueing != pending (a never-delivered request didn't fail; it drains once),
pending starts at delivery (drainQueue), and the terminal transition errors
+ drops queued ids so nothing hangs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(#264): strict handshake ordering — initialized replays after the initialize response
codex-pair MED: the eager initialized replay relied on SDK v1.29.0 not
gating tool calls (a hidden version-specific assumption). The swallow
branch now emits initialized + drains the queue only after the fresh
worker's initialize response arrives.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(#264): pre-handshake worker never receives client traffic; behavioral SIGUSR2 pin; comment hygiene
codex-pair round 5:
- the crash-before-first-response replay branch flipped to running and
drained the queue before the fresh worker answered initialize; now it
stays restarting and a replayForwardId gates the drain on the response
(symmetric with the swallow path)
- SIGUSR2 exit-1 contract pinned behaviorally against dist/index.js
instead of a source regex
- review-history comment references trimmed to durable invariants
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(#264): initialized arriving mid-restart replays exactly once
It was both cached (for the post-handshake replay) and queued, so the
fresh worker received two initialized frames. Cache-only during restart.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(#264): drop a dead child's late stdout lines
Node can emit 'exit' before stdout drains; after onDeath ran (pending ids
errored, replacement possibly spawned), a late line could double-answer an
errored id or satisfy the replayed-initialize gate in the fresh worker's
place. Guard the data handler with the per-child death flag.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent ea3e025 commit c05c058
27 files changed
Lines changed: 2762 additions & 27 deletions
File tree
- .changeset
- .claude-plugin
- docs-site/src/content/docs
- docs/superpowers/plans
- scripts/cdp-bridge
- dist
- lifecycle
- tools
- src
- lifecycle
- tools
- test
- fixtures
- integration
- unit
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
56 | 56 | | |
57 | 57 | | |
58 | 58 | | |
59 | | - | |
| 59 | + | |
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
| 34 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
106 | 106 | | |
107 | 107 | | |
108 | 108 | | |
| 109 | + | |
109 | 110 | | |
110 | 111 | | |
111 | 112 | | |
| |||
162 | 163 | | |
163 | 164 | | |
164 | 165 | | |
| 166 | + | |
| 167 | + | |
165 | 168 | | |
166 | 169 | | |
167 | 170 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
96 | 96 | | |
97 | 97 | | |
98 | 98 | | |
| 99 | + | |
| 100 | + | |
99 | 101 | | |
100 | 102 | | |
101 | 103 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
30 | 34 | | |
31 | 35 | | |
32 | 36 | | |
| |||
0 commit comments