Programming Language

Nocter

A self-contained systems language built around simplicity, encapsulation, and foolproof design.

/development/reviews/v0.32.0-phase-3.md

v0.32.0 Phase 3 Native Lifecycle Review

Result: complete with no open finding. Native qualification now exercises the configured subprocess contract through source discovery, semantic checking, target lowering, image emission, Darwin execution, and exact child observation. The review found one real deadlock in the Phase 2 implementation and reopened the transfer design rather than weakening the test.

Deadlock Finding and Root Cause

The first large three-direction test stopped after the child filled stdout while the parent was providing stdin. poll had correctly reported the input pipe writable, but the parent then passed the entire remaining input to a blocking write. Writable readiness guarantees immediate progress; it does not guarantee that an arbitrarily large write completes without blocking. The parent could therefore block inside write while the child blocked waiting for the parent to drain stdout.

The repair makes the parent input endpoint nonblocking before fork. The pipe boundary owns both descriptor-local SIGPIPE suppression and nonblocking writer configuration. Raw transfer classification exposes Darwin EAGAIN as a distinct would_block fact, and the session returns to poll without changing its offset. The child receives the opposite pipe endpoint, so its stdin does not inherit the parent's writer status flags. Captured reads remain bounded by the shared 8 KiB scratch buffer.

Lifecycle and Policy Authority

  • PreparedCommand remains the only post-fork address authority for path, argv, environment, directory, and finite input storage.
  • CommandIoSession remains the only owner of optional input and capture descriptors, offsets, liveness, buffers, and cleanup.
  • CommandOutputMode replaces a policy boolean after session creation. One execute_command path performs prepare, fork, child setup or parent observation, and one complete_command_observation function applies launch, capture, input, and terminal-mode policy. status and output only unwrap the corresponding closed completion variant.
  • The close-on-exec report preserves separate input setup, output setup, directory, and exec stages. Native protocol tests cover every stage, clean EOF, unknown stages, zero errno, partial payloads, channel failure, and the public error mapping.
  • Child observation still occurs exactly once before any stored launch or I/O failure is exposed.

Native Evidence

The new complete-session case proves:

  • clear_env, last-write-wins replacement, removal, and absence of inherited entries;
  • inherited environment retention plus exact replacement and removal;
  • directory change before relative executable replacement;
  • explicit empty stdin EOF;
  • 128 KiB stdin composed with 128 KiB initial stdout, 128 KiB stderr, and a subsequent stdin echo;
  • byte-for-byte stream order and length;
  • ordinary success when a child closes stdin before a 1 MiB parent input completes;
  • directory-stage failure mapping for both status and output.

Existing complete-session cases continue to cover nonzero and signal termination, exec rejection, closed stdout/stderr at process entry, repeated empty capture cleanup, and both terminal methods. All 38 nocter-native-session library tests pass, including 13 native standard-process cases.

Final Review

No obsolete capture-only transfer path, raw inherited-environment primitive, duplicate completion policy, or blocking stdin writer remains. Raw Darwin transitions publish typed facts and do not select public errors. The orchestration layer consumes those facts without inspecting pipe, poll, or payload representation. Phase 4 can now integrate the authored public example without changing the qualified lifecycle model.