Programming Language

Nocter

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

/releases/v0.30.0.md

Nocter v0.30.0 Release Notes

Nocter v0.30.0 adds the first standard-library subprocess boundary for ordinary command-line applications. An owning Command launches one exact executable path with owned arguments, inherits the current process environment, working directory, and standard streams, waits for its child, and returns a typed ExitStatus. The only implemented host and native target remains arm64-darwin.

Exact-path Commands

std/process now exposes:

use std/process.{Command, ExitStatus}

var command = Command.new("./helper")?
command.arg("one argument")?
let status: ExitStatus = command.status()?

Command.new and arg validate and copy their inputs. Empty executable paths, invalid UTF-8, and embedded NUL bytes are rejected before launch; a rejected argument leaves the command unchanged. The executable spelling is used exactly as supplied. Relative paths use the inherited working directory, and the standard library performs no PATH search, shell parsing, or command-line text joining.

status consumes the command, creates one child, and waits for that exact child. There is no independently discardable child handle, so ordinary source cannot omit reaping or forget a hidden process resource. All launch storage is prepared before child creation, and the child cannot return to ordinary Nocter allocation, destruction, or user code after fork.

Typed Terminal Status

ExitStatus keeps ordinary exit and signal termination distinct:

if status.success() {
    // The child exited with code zero.
}

let code = status.code() otherwise {
    let signal = status.signal()!
}

success is true only for ordinary exit code zero. Exactly one of code and signal is present. A nonzero child exit is a successfully observed status, not a T! failure.

Launch rejection is reported separately from child status. Missing executables, denied execution, invalid executable or argument requests, process creation failures, and terminal-observation failures use stable std.process.* error codes. A private close-on-exec channel prevents an intentional child exit code such as 127 from being mistaken for an exec failure.

Practical Integration

The new subprocess-status package example invokes a repository-owned helper through ./helper.sh, passes a whitespace-bearing argument without joining, and reports the helper's typed nonzero exit status. The same source crosses native compilation and execution, formatter checks, semantic hover, completion, declaration and implementation navigation, and installed-home qualification.

Compatibility and Non-goals

This release adds API without changing existing std/process argument, environment, current- directory, exit, or abort behavior. It does not add shell execution, PATH search, environment or working-directory overrides, standard-stream redirection, pipes, output capture, asynchronous children, process signals, another native target, or persistent compiler caches.

Candidate Qualification

Release-content commit 35ce75b3cb8b64fe918c5f4066d3bde14d2521b5 passed two independent locked workspace runs with 1,537 tests passed, zero failed, and one ignored in each run. The ignored public-HTTPS acquisition test passed separately. Warnings-denied all-target Clippy, no-default-features checking, deterministic documentation, formatter checks, and repository validation also passed.

Two independent optimized builds produced the same archive and installed home. The retained local archive is 8,278,398 bytes and has SHA-256 2a23e254fbfb07f387b6489d947945c7481f7c03be8d659efefe1c3c697412a8. Its isolated installed home passed version and integrity checks, every public example, package run/build/test/graph operations, the exact text-banner, stdin-prefix, and subprocess-status process contracts, framed LSP requests, immutability checking, and compiler and standard-library tamper rejection. Publication reuses that retained candidate without rebuilding it.