Programming Language

Nocter

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

/development/reviews/v0.19.0-phase-1.md

v0.19.0 Phase 1 Streaming Text Input Review

Result: passed (2026-08-28). This review covers the public BufReader line contracts, reusable destination behavior, UTF-8 validation authority, terminal-state convergence, bounded storage, native behavior, standard-library dependency boundaries, and editor behavior introduced by v0.19.0 Phase 1.

Review Criteria

The review traced:

  • every byte from an underlying partial read through delimiter classification, UTF-8 validation, publication into String, and later destruction;
  • every transition caused by EOF, explicit close, I/O failure, invalid UTF-8, and recoverable growth failure;
  • ownership of unread bytes, the incomplete line, the caller destination, UTF-8 policy, and the stable std.string.invalid_utf8 failure;
  • all new standard-library module dependencies and every public API added to String and BufReader;
  • public contract and implementation-source hover, member completion, and navigation;
  • duplicate validators, raw-pointer-derived string views, compatibility wrappers, new compiler primitives, and editor-only declaration reconstruction.

Findings and Remediation

A borrowed internal UTF-8 adapter would have bypassed result provenance

The first implementation attempted to turn a validated byte slice into &str inside std/internal/utf8 and pass that borrow into existing string mutation. The checker correctly rejected the result: a package-internal helper cannot manufacture a returned borrow whose origin is not expressed by its contract. Weakening provenance or adding a privileged primitive would have made the compiler understand an implementation shortcut.

The accepted design keeps validation independent of representation. std/internal/utf8 owns the validator and stable error construction; String.try_push_utf8 validates first and then copies bytes into storage owned by String. std/io/buffer sees only that safe public operation and never constructs a string view from a raw pointer.

Byte copying initially introduced an unnecessary public pointer dependency

The first String.try_push_utf8 body computed an offset address through std/ptr.addr. The standard dependency guard rejected the new string -> ptr edge. The operation now uses the package-internal byte-store contract, whose offset parameter already expresses the required copy. No user-facing pointer API or new compiler primitive is needed.

A buffered reader needs one raw incomplete-line owner

Publishing bytes directly into the caller's String would temporarily violate the invariant that every String contains valid UTF-8. Validating each refill independently would reject a scalar split across reads. BufReader therefore owns one reusable Vec<u8> for the current line, validates the complete delimiter-free byte sequence, and only then publishes it. This is not a second text representation: the buffer is raw bytes, while String remains the sole owner of validated text storage.

Final Boundary Assessment

  • spec/21-practical-standard-library.md exclusively owns observable line, delimiter, EOF, terminal, failure, and allocation-bound behavior.
  • std/io.File retains interruption retry and target I/O policy. BufReader consumes only the Reader result and does not reinterpret errno or syscall facts.
  • std/io/buffer exclusively owns unread-byte position, incomplete-line bytes, and its terminal state. One refill implementation serves byte reads and line reads.
  • std/internal/utf8 exclusively owns the UTF-8 state machine and the std.string.invalid_utf8 constructor. The public std/string.is_valid_utf8 function is a thin API projection onto that authority, not a second validator.
  • String exclusively owns mutation of its representation. try_push_utf8 validates before reserving or publishing bytes, so invalid input leaves an existing value unchanged.
  • EOF preserves a pending final line long enough to publish it once, while every subsequent byte and line operation observes the same terminal state. Failure and explicit close additionally discard the incomplete line.
  • storage is bounded by the configured read buffer, the largest current line, and caller-retained destination capacity. No completed line or complete file is retained.
  • the reviewed dependency set records only io/buffer -> string and string -> internal/utf8 as new ownership edges.
  • LSP tests consume the same checked standard-library declarations and bodies as compilation; no editor-only declaration or method reconstruction was added.

No unresolved correctness or responsibility-boundary finding remains in Phase 1 scope.

Verification

The completed tree passed with /private/tmp/nocter-v019-phase1 as the external Cargo target:

cargo test --locked --manifest-path development/compiler/Cargo.toml --workspace
cargo clippy --locked --manifest-path development/compiler/Cargo.toml \
  --workspace --all-targets -- -D warnings
cargo fmt --manifest-path development/compiler/Cargo.toml --all -- --check
node docs/build-docs.js
git diff --check

Native acceptance covers refill boundaries, a UTF-8 scalar split across refills, short final reads, lines larger than the buffer, empty lines, CRLF, lone CR, a final unterminated line, invalid UTF-8, repeated EOF, explicit close, zero requested capacity, destination reuse, and terminal failure. Editor acceptance covers member completion, imported navigation, and source-backed hover in both the public contract and implementation source.