Programming Language

Nocter

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

/development/reviews/v0.20.0-phase-2.md

v0.20.0 Phase 2 Unified Query Entry Review

Result

Phase 2 is complete. No correctness or architecture blocker remains in the reviewed scope. CLI and workspace analysis now differ in computation lifetime and presentation policy, not source parser, semantic scheduler, recovery traversal, or session transition.

The phase was reopened after the first review found enforcement gaps. The final design rejects foreign and stale source revisions, routes every production package-root probe through the computed provider, prevents session from depending on semantic query execution, and keeps executable identity inseparable from the target program that declared it.

A final repository-wide follow-up also closed three structural gaps: semantic publication and query demand now share one private owner, inactive revision-derived computation storage is bounded, and direct parse/package convenience entries no longer exist in production APIs.

A later whole-repository audit corrected an over-broad package-state contract. Exact-package publication is now modeled explicitly as cache warming rather than as part of the root-source transaction. The distinction matches the persisted authority: only an authored root #lock can select a cached package.

Reviewed Flow

The accepted flow is:

command policy ----------------> ephemeral CompilerComputation
workspace revision policy -----> persistent CompilerComputation
                                           |
                     computed source syntax provider
                                           |
                         discovery + semantic publication
                                           |
                              closed UnitAnalysisProduct
                                           |
                         session outcome/target translation
                                           |
                              optional native lowering

CompilerComputation hides the raw database and exposes source revision publication, one syntax provider, one closed unit-analysis demand, and instrumentation. Neither command nor workspace code can demand a declaration, preparation, body, or finalization query directly. Session cannot invoke those stages; it can only translate the variants already selected by UnitAnalysisProduct.

Findings Closed During Review

Parse-goal identity was lost at a shared physical path

Discovery previously reused an existing syntax tree whenever a module root path was already in the package graph. The existing tree represented package-declaration parsing, while semantic body inputs required source-file parsing. A generated-lock package test exposed the mismatch as a missing body input. Discovery now requests ParseGoal::SourceFile for every module source even when the physical source already has another parse product. Path identity no longer substitutes for parse-product identity.

Package state returned a pre-commit source snapshot

A generated lock was committed after the transaction had selected the graph it returned. The computed provider correctly rejected that graph because its retained root bytes differed from the filesystem bytes after commit. Package-state transactions now revalidate through the injected read-only resolver after committing generated lock source and return only that post-commit graph. Commands inject their ephemeral compiler computation as the resolver, so package parsing and later discovery share one source/query authority.

Native and session layers could reopen semantic compilation

Executable, native-image-set, and native-test requests previously carried DiscoveredUnit and called session compilation internally. They now own CompiledTarget. The eager session semantic pipeline and public direct analysis/compilation entries were deleted, including forwarding paths.

Command target conversion could narrow a closed diagnostic result

The first query-backed command adapter converted a failed AnalyzedUnit into only its primary CompileSessionError, then rebuilt a command failure from that error. Recovery diagnostics already selected by the query could therefore be discarded. Target conversion now returns a closed session failure envelope containing the primary error, exact source snapshot, and complete diagnostic set. Command presentation consumes that envelope without reconstructing semantic diagnostics.

Semantic publication relied on a correctly behaving caller

Module-surface fingerprints, body publications, and discovered units could previously be assembled through public functions in a separate query crate. The current owner happened to pair them correctly, but the type boundary did not enforce that fact. Semantic input construction and final demand now live in a private nocter-compiler-computation subsystem. A caller can submit only an owner-bound discovered unit; it cannot manufacture or reorder semantic inputs.

Persistent workspace computation retained every historical key

The computation database had no inactive-entry policy and retained old overlay bytes, semantic scopes, body inputs, and query products for the lifetime of the language server. Inputs now declare persistent or revision-derived retention. Compiler computation retains 32 accepted source revisions and collects older revision-derived dependency closures while preserving independent persistent roots. The unused changed_at state was removed; fingerprints and verified revisions remain the sole invalidation facts.

Lower layers exposed direct production parser and resolver entries

Discovery and package-state exposed convenience functions that constructed a direct parser, so a future production caller could bypass the shared source query authority. Production APIs now require an injected syntax or package-resolution provider. Direct parsing remains only in tests.

Exact-package cache publication was described as transactional state

The package-state owner published validated exact packages before its final root-source compare-and-replace, but its documentation promised that any later failure exposed no persistent state. Rolling back published cache entries would be unsafe under concurrent readers and unnecessary because those entries carry no selection authority. Cache publication now has a dedicated owner and result type, while root lock-source commit remains the failure-atomic transition. A regression test proves that a concurrent root edit can reject the lock transition, leave the root source unchanged, and retain only the complete immutable exact package.

Boundary Audit

  • There is one production source-text/parse query implementation and one raw database owner.
  • Syntax-provider access and semantic analysis both require the same owner-bound current source token. Internal semantic publication cannot invalidate that source identity.
  • There is one complete-versus-incomplete unit query and one public session consumer.
  • Discovery owns physical topology and exact parse-goal binding; it does not schedule semantics.
  • Session depends only on nocter-semantic-product, owns target/runtime validation and recovery-capability projection, and cannot schedule compiler stages.
  • Session owns the complete source-and-diagnostic failure envelope; command presentation cannot reduce it to a primary diagnostic and rebuild it.
  • Native layers receive executable programs already closed with their declaring target owner; they cannot pair an identity from one target program with another or observe source discovery.
  • Package-state mutation accepts an injected read-only resolver and cannot return a snapshot older than its own commit. Its filesystem revision advances only after an exact-cache visibility transition or root source commit, not after an overlay-only resolver retry.
  • Exact-package cache publication is append-only and separate from root dependency selection. A cached identity cannot enter a graph without the root's authored #lock authority.
  • Command and workspace crates depend on nocter-compiler-computation but not directly on semantic computation or declaration lowering.
  • Semantic input types and intermediate query entries are private to their owner; correct pairing is not a caller obligation.
  • Query and revision-derived input storage is bounded by an owner-selected retained source window.

Evidence

  • One-shot command instrumentation executes source text, parse, declaration surface, module surface, declaration, preparation, body-name, typed-body, finalization, complete-analysis, and unit-analysis query families through the shared owner.
  • Existing workspace instrumentation continues to prove parsing and semantic reuse across accepted revisions and equality between warmed and fresh analysis results.
  • Command acquisition tests cover post-lock source authority, command tests cover diagnostics and native output, and native-session tests cover complete and incomplete semantic outcomes through the query entry.
  • Architecture tests freeze the shared dependency entry. Rust dependency visibility, rather than a source-text scan, prevents session from naming semantic-stage calls.

The complete workspace test suite, warnings-denied all-target Clippy, formatting, documentation generation, and repository integrity gates passed on 2026-08-30.