v0.31.0 Phase 3 Native Failure and Lifecycle Review
Result: passed (2026-09-03). Phase 3 qualifies the owning output lifecycle at both its private target boundary and its public Command.output boundary. It adds no production mechanism or source-visible behavior.
Reviewed Boundary
The review covers empty and nonempty streams, arbitrary bytes, nonzero and signal termination, child setup and executable rejection, inherited descriptor collisions, repeated cleanup, interrupted-operation classification, exact-child observation, and continued simultaneous drain beyond finite pipe capacity.
Public Native Evidence
One compiled Nocter program invokes repository-created helpers through Command.output and checks:
- an empty successful child returns two empty vectors;
- ordinary stdout and stderr text matches every expected byte;
- a child terminated by
SIGTERMretains every byte written to both streams and reports signal 15; - forty-eight consecutive empty captures complete successfully with no fabricated bytes;
- a missing executable remains
std.process.not_foundrather than becoming exit code 127; - the Phase 2 adversarial child still returns exit code 23 and exactly 262,146 bytes per stream, including distinct NUL and non-UTF-8 tails.
The same compiled program executes normally, with its inherited stdout closed, and with its inherited stderr closed. Capture remains correct in all three environments. This is process-level evidence that OwnedPipe normalization prevents a new endpoint from colliding with descriptors 1 or 2; the public caller does not know or repair descriptor numbering.
Private Setup Evidence
A Darwin-native standard-library test closes the owned stdout writer before forking and then calls the ordinary captured-child launch transition. Descriptor installation fails in the child before image replacement. The launch channel returns LaunchReportAttempt.setup_rejected with a nonzero errno, both stream drains finish empty, and exact-child wait reports exit code 127.
The test crosses the real fork, dup2, report pipe, capture drain, and wait boundaries. It does not inject a fabricated public error or duplicate launch classification in the Rust harness.
Lifecycle and Authority Review
OwnedPiperemains the only raw endpoint owner and normalization authority;CaptureSessionremains the only correlated two-stream owner and closes all capture endpoints;- the child setup bridge alone installs standard descriptors and emits setup-stage failure;
CommandForkstill owns preparation and the single fork transition;observe_terminalremains the exact-child wait authority;- public process code selects stable
errorvalues only from typed private outcomes; - the Rust harness creates external helpers and process environments but does not reinterpret target records or internal launch states.
Repeated public capture supplies practical leak regression evidence. Private setup rejection proves that the post-fork failure path can report, drain, and reap without caller cleanup. Deterministic Phase 1 cases remain the authority for interrupted read and malformed kernel-fact classification; Phase 2 remains the authority for deadlock freedom and arbitrary-byte preservation. Phase 3 does not copy those lower-level models into another test-only implementation.
Findings
No open production defect, duplicate lifecycle authority, raw-descriptor leak, caller-discipline contract, or obsolete compatibility path was found. Phase 4 may build practical and editor integration directly on this closed native boundary.