Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

RFD-0010 — Module system and standpoints

Committed Opened 2026-05-03 · Committed 2026-05-03

Question

How are Argon source files organized into modules, and how do standpoints (the language’s mechanism for perspectival modeling) integrate with the module system?

Decision

Module organization follows Rust conventions:

  • Every .ar file is a module. The module’s name is the file stem; the module path is the relative directory path.
  • The package’s entry file is prelude.ar at the package root. The entry file resolves as pkg::prelude and acts as the package-module primary file.
  • Imports use Rust-style use vocab::path syntax. There is no implicit prelude (RFD-0014); every name visible in a module has a corresponding use line or fully-qualified path.
  • Default visibility is module-internal (file-scoped). The pub keyword promotes a declaration to package-public visibility. Two-tier visibility (RFD-0011) — no fine-grained access modifiers.
  • Module configuration splits across two scopes: package-level structure (standpoints { }, defeats { }, etc. in ox.toml) and module-level locals.

Standpoints are first-class. A standpoint is a perspective on the knowledge base — a specific viewpoint under which facts may hold or not. Standpoints declare in a project-level partial-order lattice; bridge rules and standpoint compositions follow the lattice. Standpoint scoping integrates with per-tenant overlays (RFD-0020): each tenant carries a primary standpoint sourced from their tenant config.

use foo::bar::Sym; parses as single-symbol Named import (Rust-style), not as a glob or module import.

Rationale

Filesystem hierarchy is the module hierarchy. Forcing the language’s namespace structure to match the filesystem layout removes a degree of freedom that produces drift. A reader looking at ufo/properties/identity.ar knows the qualified path is ufo::properties::identity without having to read the file.

No implicit prelude. Auto-imported names are convenience that compounds confusion: which module is Nat from? Adding the explicit use line takes one second when writing and saves an hour when debugging. Bare primitive names produce diagnostic OE0101 with a contextual hint pointing at the appropriate std::math::* import.

Standpoints as a lattice, not a flag. Real perspectival modeling has multiple cross-cutting viewpoints (legal vs. accounting, insurer vs. policyholder, federal vs. state). A standpoint flag would have collapsed all these into one axis. The lattice admits multiple orthogonal viewpoints with explicit composition.

Module-internal default reduces accidental coupling. Most declarations should not be public. Defaulting to module-internal means that promoting something to pub is a deliberate act, and the declaration’s visibility is visible in its declaration line.

Consequences

  • File names map directly to module names; rename a file → rename the module.
  • prelude.ar is the convention; library entry + package-module primary file in one.
  • Re-exports use pub use. Re-export resolution is a fixpoint over local ∪ re_exports in the elaborator’s import-resolution pass; chain depth is bounded by module_count + 1 (cycles surface as OE0903).
  • Package-name canonicalization: manifests admit hyphens or underscores; canonical form is underscored; transform at parse.
  • Standpoints integrate with the kernel’s bitemporal event log (RFD-0021) as discriminator axes (standpoint_id, module_id, fork_id).