mirror of
https://github.com/dtzp555-max/olp.git
synced 2026-07-21 21:15:10 +00:00
The /bin/sh -c wrapping that sandbox-runtime applies (bwrap argv prefix +
inner claude command) can return exit code null on cleanup even when the
underlying claude process completed cleanly and emitted the `result`
event. The previous logic treated any non-zero exit as fatal and threw
ProviderError, causing the HTTP handler to discard the already-yielded
chunks and respond with content:null.
resultEventSeen=true is the authoritative success signal — if it's set,
the model completed and the stop chunk was yielded. Abnormal exit after
that is sandbox bookkeeping noise.
Live PI231 evidence (2026-05-28 commit 2864275 deploy):
Direct provider test (bypasses HTTP):
chunk: {"type":"delta","content":"DIRECT_PROOF",...}
chunk: {"type":"stop","finish_reason":"stop"}
ERR: claude exit null ← throw after chunks yielded
HTTP response: choices[0].message.content == null
(chunks lost when consumer received throw)
Fix: only throw on non-zero exit when resultEventSeen=false. With the
guard, the smoke `reply: SANDBOX_PROOF` request now returns the proper
content through the HTTP layer.
The pre-PR-B (non-sandbox) path is unaffected: that path runs claude
directly (no /bin/sh wrap), so exit is always 0 when the model
completes, and the resultEventSeen check is a no-op for that path.
Authority:
- live PI231 2026-05-28 transcript (direct vs HTTP path divergence)
- ADR 0009 Amendment 1 § "NDJSON event handling" — result event is
the terminal-success indicator
- ADR 0014 § PR-B — sandbox wrap introduces /bin/sh layer
Tests: unchanged at 813 (this is a pure-defensive code path; Suite 44
on PI231 will now exercise the corrected path on E2E run).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>