Nocter v0.10.0 Phase 3
Status: Completed on 2026-08-09.
Purpose
Phase 3 removes the remaining special boundary around the standard library. std becomes an implicit toolchain package with ordinary package and module identity, while visibility becomes one ancestor-based module hierarchy shared by user packages and the standard library.
This phase removes pub(nocter). Visibility controls source access only. Permission to declare a compiler primitive or satisfy another trusted runtime role comes from the exact standard-library package identity, never from visibility spelling or filesystem containment alone.
Visibility Syntax
Nocter supports exactly these declaration visibility forms:
func local(): void
pub(./) func descendants(): void
pub(../) func parent_tree(): void
pub(../../) func grandparent_tree(): void
pub(/) func package_wide(): void
pub func universal(): void
- omitted visibility is accessible only inside the declaring directory module
pub(./)is accessible in the declaring module and its descendant modules- each additional
../moves the boundary to one ancestor module pub(/)is accessible throughout the declaring package- bare
pubis accessible from every package - a relative visibility boundary cannot move above the package root
- names, dependency aliases, and arbitrary module paths are not visibility syntax
- visibility is resolved from the declaring directory module, not the physical implementation file
- a re-export cannot widen the visibility of its target
Scoped visibility remains restricted to module-root index.nct declarations. Focused implementation sources continue to contain private bodies and helpers only. Interface members keep bare pub; the interface declaration determines whether the contract itself is package- or module-scoped. Construction and inherent member surfaces may use any explicit visibility supported by their owning declaration.
Semantic Identity
One compiler-owned source scope map assigns every loaded source:
- an exact
PackageId - an exact directory
ModuleId - whether its package is the active toolchain standard library
Access checks compare semantic identities. They do not inspect display paths, search for a std directory component, infer trust from Nocter-home containment, or reconstruct module ancestry from presentation strings. Same-module implementation sources share one ModuleId.
The resolved visibility model is:
private -> exact declaring ModuleId
pub(relative) -> one ancestor ModuleId and its module subtree
pub(/) -> exact declaring PackageId
pub -> unrestricted
AST JSON and formatting preserve the authored relative scope. Resolver facts retain the resolved boundary identity so type checking, imports, construction, coercion, diagnostics, and editor features consume one access decision.
Standard-Library Package
The installed standard library is an immutable toolchain package:
<Nocter-home>/std/
nocter.nct
index.nct
io/index.nct
iter/index.nct
...
nocter.nctdeclares the package name and release versionindex.nctis the package root module; domain APIs remain child modules- every compilation graph contains exactly one implicit
stdpackage selected by the active Nocter home - every source package receives the reserved
stddependency alias automatically stdis absent from user#dependenciesand generated#lockstdmay neither be shadowed nor fetched from an external source- single-file mode uses the same implicit standard-library package without inventing a user package
- imports inside
stdresolve the reserved alias back to that same package identity
The standard-library package identity authorizes primitive declarations and closed trusted roles. pub(/) only grants package-local access and never grants authority in an ordinary package.
Compiler and Tooling Integration
- package loading validates the standard-library package declaration against the active Nocter home release
- import resolution routes
stdthrough the implicit package node rather than a separate path branch - resolver import collection, qualification, member access, type leakage, and re-export checks use resolved visibility boundaries
- LSP workspace snapshots include the implicit package, and completion, hover, definition, references, rename, semantic tokens, and diagnostics use the same source scope map
- rename remains bounded by package identity and cannot edit the immutable toolchain package from a user workspace
- normalized source notation renders the authored
pub(...)form and never emitspub(nocter)
Migration
- every standard-library
pub(nocter)declaration becomespub(/) - standard-library comments and diagnostics use package visibility and standard-library authority as separate concepts
- source fixtures migrate without a compatibility parser for
pub(nocter) nocterreturns to an ordinary identifier outside unrelated grammar positions- no legacy AST variant, import-access tier, formatter branch, or LSP presentation survives
Completion Gate
- parser, formatter, AST JSON, diagnostics, and recovery cover every accepted visibility depth and reject names, malformed scopes, and traversal above the package root
- private, descendant, parent-tree, package, and universal access are tested across same-module sources, child modules, siblings, package dependencies, re-exports, members, construction, and coercion
- the standard library participates in package/module identity and no import or access decision
recognizes it by a path component or
ImportAccess::Nocter - primitive declarations require the exact implicit standard-library package identity regardless of authored visibility
- the distributed standard library builds and runs with
pub(/)and contains nopub(nocter) - public specification, contributor architecture, and generated documentation contain one current model
- the complete compiler verification suite, installed-home suite, public examples, source corpus,
formatting, warnings-denied Clippy, documentation generation, and
git diff --checkpass
Phase 3 does not add friend modules, named visibility namespaces, third-party trusted packages, unsafe source constructs, dependency-selectable standard libraries, separate compilation, or a v0.10.0 release artifact.
Completion Evidence
Visibilitynow represents private, module-tree, package, and universal boundaries directly. The parser, formatter, AST JSON, normalized presentation, diagnostics, and recovery accept onlypub(./), repeated ancestor forms such aspub(../../),pub(/), and barepub.SourceScopeMapassigns physical sources an exactPackageIdand directoryModuleId, resolves relative scopes once, and supplies the same semantic boundary to imports, re-exports, member filtering, trusted-role checks, and the package semantic index. Public boundaries remain valid in standalone source analysis, where no package scope exists.- Re-export lookup retains the original declaration span for diagnostics and navigation while applying the re-exporting module's visibility boundary. Chained re-exports cannot widen a target, and type members continue to use their original declaration boundary.
- The installed
std/nocter.nctandstd/index.nctdefine one implicit toolchain package. Package graphs reserve thestdalias, reject an explicitstddependency, validate the installed package name and exact toolchain version before writing generated locks, and make imports insidestdresolve to the same package identity. - Primitive and trusted runtime authority now comes from the selected standard-library package
identity. Ordinary packages cannot acquire authority with
pub(/)or a directory namedstd. - LSP auto-import and import-path completion consume package-graph dependencies and resolved visibility boundaries. They no longer infer standard-library identity by searching path components, and scoped exports are offered only inside their permitted module subtree.
- The distributed standard library and active fixtures contain
pub(/)rather thanpub(nocter). The complete test run passed all 3,433 compiler, CLI, native execution, installed-home, example, and corpus tests. Formatting and warnings-denied Clippy passed after the final mechanical formatting update. Documentation generation produced 111 pages, andgit diff --checkpassed.