fix(adapters): a process that fails to start fails its cell, not the run - #64
Conversation
…axis spawn() throws synchronously for unusable arguments (e.g. a null byte in an arg). Wrap it in try/catch and return a failed AgentOutput through the same metadata shape the normal exit path builds, instead of letting the exception escape adapter.run() and kill the whole run. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6cesfFBiaNe5ttYyXpLce
…rashing axis Node emits `error` on the child (not a throw) when the process cannot be started asynchronously, e.g. `spawn test-bin ENOENT`. Listen for it alongside `close` in the exit promise and surface the message through the existing error-precedence chain, ahead of stderr and the generic default. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6cesfFBiaNe5ttYyXpLce
…crash Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6cesfFBiaNe5ttYyXpLce
…s fixture Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6cesfFBiaNe5ttYyXpLce
✅ Deploy Preview for axisproject ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for axis-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (3)
🔗 Linked repositories identifiedCodeRabbit considers these linked repositories for cross-repo context during reviews:
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 SummarySummary by CodeRabbit
WalkthroughThe adapter now converts synchronous Priority: ⬇️ Low — Defer this adapter error-handling change because it is a narrow low-severity fix for process-start failures, with no broader product impact supplied. Estimated code review effort: 2 (Simple) | ~10 minutes Severity of issue fixed: Low Merge Risk: ⚪ Minimal · up to Spawn failures now produce structured failed runs instead of terminating the run, with focused coverage for synchronous throws and child-process error events. No merge-blocking risk remains. Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 2 files. (1 skipped: 1 unsupported.)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Warning Tools execution failed with the following error: Failed to run tools: 13 INTERNAL: Received RST_STREAM with code 2 (Internal server error) Warning Repository analysis: Could not refresh Comment |
…wn-failure-fails-cell # Conflicts: # test/unit/adapters/base/agent-adapter.test.ts
Summary
This is the other half of #63. That one stops a null byte from reaching
spawn(). This one asks what happens when a child process can't start at all, for any reason.Today,
spawn()throwing synchronously (bad args) and the child emittingerror(anENOENT, a binary that isn't there) were both unhandled in the base adapter. Either one escapesadapter.run()as a plain Error, not aScoringError, so scoring lets it propagate per the fail-loud rule — andaxis rundies without a meaningful report. Every other cell in the run had a perfectly good transcript and got nothing.Now both cases become a failed run for that one cell, with
metadata.errorset.callJudgealready knows how to withhold a failed run, so nothing downstream changes and fail-loud still applies to real bugs.What changed
src/adapters/base/agent-adapter.ts:spawn()is wrapped in try/catch and returns a failedAgentOutputthrough a smallfailedToStart()helper. Achild.on("error")listener resolves the exit promise. The spawn error sits second in the error precedence chain — aftergetResult().metadata.error, before stderr.TypeErrorfromspawn()and anENOENTerrorevent both resolve withmetadata.errorset and a non-zero exit code.createMockProcessgained an optionalerrorto emit.Not covered: ACP adapters have their own spawn path in
acp-adapter.ts. A start failure there still crashes the run. I'd rather do that as a follow-up than widen this one.Linear: EX-3027