Native Spawn/Capture Contract
This contract records the current native spawned-app execution boundary after the staged EPY/C refactor extracted:
- argv assembly into
src/native_runtime/c/native_spawn_argv.c - multipart temp-body lifecycle into
src/native_runtime/c/native_spawn_temp_body.c - shared POSIX
execvcapture intosrc/native_runtime/c/native_process_capture.c
The goal is to keep the highest-risk execution behavior explicit while the remaining higher-level orchestration still lives in src/native_runtime/c/pharos_runtime.c.
This boundary is current implementation reality, not the long-term ideal. The preferred direction is to exercise spawned compiled-host behavior through native-first local checks more often so shell/native semantic drift is discovered early.
Primary native surfaces
Current primary files:
src/native_runtime/c/pharos_runtime.csrc/native_runtime/c/native_spawn_argv.csrc/native_runtime/c/native_spawn_temp_body.csrc/native_runtime/c/native_process_capture.c
Cases that must remain stable
1. Non-multipart compiled app request success
For non-multipart forwarded app requests, the native runtime must:
- assemble argv deterministically
- pass request body through
--form - capture child stdout/stderr through the shared
execvcapture path - return child output bytes unchanged to the caller when the child exits
0
2. Multipart compiled app request success
For multipart forwarded app requests, the native runtime must:
- materialize the request body into a temp file
- pass that path through
--body-file - avoid inlining multipart bytes into argv
- clean up the temp file after capture completes
3. Child non-zero exit handling
If the spawned compiled app exits non-zero, the native runtime must:
- preserve captured output for diagnostics when available
- surface a
502 Bad Gatewayresponse through higher-level orchestration - preserve the failure reason path currently labeled
app_host_exit
4. Empty or invalid child response handling
If the child returns no response bytes, the native runtime must treat that as failure at the higher-level request boundary.
Current native behavior is fail-closed:
- empty response →
502 Bad Gateway - request error logging remains enabled for the failure path
5. Shared capture primitive consistency
The shared POSIX capture primitive serves both:
- shell/runtime bridge command capture
- compiled app request execution capture
That shared primitive must continue to preserve:
- stdout/stderr merged capture
- exit-code-based success/failure translation
- no shell interpolation for compiled app request execution
Platform note
This contract does not newly claim parity across every target platform.
Current state remains:
- POSIX native capture path is implemented and active
- Windows and WASM/non-POSIX capture paths remain stubbed/blocked where unchanged
Any future expansion of non-POSIX process capture must be documented explicitly rather than assumed.
Preferred convergence check path
Where supported locally, prefer:
scripts/check.sh native-compiled-flow
That flow builds and smokes the native target before server-smoke verification, making spawned compiled-host execution part of the routine local validation path instead of a release-only edge surface.