diff --git a/AGENTS.md b/AGENTS.md
index 189b94c47..18f2596ee 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -21,6 +21,44 @@ Do not spend context window or analysis on those files unless explicitly request
When asked to change or move an API, import path, command, feature, or behavior, do not add or keep compatibility layers, aliases, shims, fallback paths, or legacy entrypoints unless explicitly requested. A requested change means the old behavior should be removed.
When updating tests, remove obsolete tests that only assert removed/old implementation behavior does not exist. Do not preserve rejection or absence checks for API/features that were intentionally removed unless explicitly requested.
+Treat tests as evidence for a named invariant, not as specifications merely
+because they already exist. Add or retain automated tests when they protect at
+least one of the following:
+
+- externally observable behavior or a public API;
+- a documented diagnostic or serialized/generated format;
+- ABI, ownership, lifetime, memory-safety, build, or release behavior;
+- a stage handoff or architectural boundary whose violation would allow a
+ downstream stage to make an upstream decision; or
+- repository structure that is directly consumed by tooling.
+
+Do not add tests whose only purpose is to freeze prose, wording, heading or
+section order, private class or function names, complete file inventories,
+dataclass field inventories, exact internal call order, preferred inheritance,
+or incidental directory/module layout. Those are recommendations for
+contributor review unless the user explicitly promotes one to a maintained
+contract. Unit tests may construct internal models when their behavior or
+completed state is the invariant, but they should not assert implementation
+shape just to prevent refactoring.
+
+When an existing test fails after an intentional change, identify the behavior
+or risk it was meant to protect before changing production code. Keep or
+rewrite the test when that invariant remains a contract; remove it when it only
+records the previous implementation or a recommendation. Do not change correct
+behavior solely to satisfy a brittle test.
+
+The agent owns the review work that is not delegated to rigid tests. Before and
+after a refactor, compare the affected public behavior and stage outputs. When
+editing documentation, examples, diagnostics, or generated text, preserve the
+existing meaning, behavior, and wording as much as the request permits; inspect
+the diff and run the affected example or focused command when practical. Treat
+illustrative wording and demonstration output as review recommendations unless
+they are explicitly documented as stable formats. A command/result pair shown
+in a package guide must remain factual: run the command and compare stable
+output with the page, or validate only the displayed invariant when the output
+is an excerpt or depends on the active target. Do not duplicate that expected
+output in a separate test inventory.
+
Before wrapper planning begins in `prik/planning/planner.py`, the
post-IR policy stage must have completed every semantic decision needed by
wrapper generation, including object kind, ownership, transfer, destruction,
@@ -85,4 +123,8 @@ pull-request verification:
- `python3 -m radon cc prik -n C -s --total-average`
- `python3 -m radon mi prik -s`
Treat Ruff, Bandit, Vulture, and the Radon policy as blocking. The full Radon complexity and maintainability reports are advisory but must still be run. If a command cannot run because a dependency, network service, or CI-only environment value is unavailable, state that explicitly in the final response.
+
+The codegen complexity checker is also advisory: review and report its findings,
+but do not change correct behavior or fail the task solely to satisfy its
+structural recommendations.
When you create a commit add this prefix to the message to know that you did push the commit "codex: ..."
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fdf85d720..05d58552f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,14 +13,108 @@ release tags add a leading `v` to the package version.
and one canonical page per production package, with local structures,
important objects, runnable examples, expected outputs, test owners, change
routes, and invariants.
-- Consolidated cross-stage concepts and contributor workflows, retained future
- and deferred designs explicitly, and removed TODO-only pages, duplicate
- architecture maps, and completed migration ledgers.
+- Consolidated contributor workflows and removed nonessential concept and
+ design drafts, TODO-only pages, duplicate architecture maps, and completed
+ migration ledgers.
- Added Zenodo version and concept DOI links to the citation metadata, README,
and About page.
### Changed
+- Marked the contributor Architecture and Codebase Map as reviewed for
+ publication; the renamed map now focuses on package and cross-stage module
+ ownership.
+- Clarified the Feature-to-Code Map as the capability-to-owner and evidence
+ index, linking reviewed user documentation and retaining only planned
+ contributor-documentation paths before their review.
+- Revised the Feature-to-Code Map with reviewed package-guide links,
+ stage-ordered change routes, narrower focused evidence, and separate array,
+ callback, and error routes.
+- Condensed the contributor Testing Strategy around test ownership, stage
+ evidence, stable contracts, end-to-end evidence, fixture placement, and
+ verification scope.
+- Clarified contributor workflows for changing PRIK, local verification, pull
+ request checks, and documentation maintenance.
+- Linked the Contributing workflow to the Feature-to-Code Map and Testing
+ Strategy, explained its pre-push hook setup, and normalized its editable
+ checkout test commands.
+- Clarified that pull-request validation requires the performance benchmark and
+ identified its workflow implementation.
+- Renamed the Package Guides section to Architecture Components and grouped its
+ build stages separately from its supporting components, distinguishing
+ cross-build pipeline orchestration from sequential stages.
+- Ordered the Developer Documentation sidebar by the architecture reading path,
+ with build stages before supporting components.
+- Made every expandable documentation-sidebar section label open its first
+ published page, including through nested sections, while the adjacent **+**
+ control only expands or collapses it.
+- Made documentation tables wrap readable cell content instead of hiding
+ later columns behind unnecessary horizontal scrolling.
+- Added accessible two-, three-, and four-view example tabs to the User Guide;
+ Getting Started remains linear and example results stay visible.
+- Reviewed the Pipeline Component guide around the source-build handoff,
+ independent contract and inspection workflows, and build-result ownership.
+- Reviewed the Preprocessing Stage guide around its Fortran source route,
+ compiler-derived target probes, module navigation, and executable examples.
+- Reviewed the Parsing Stage guide around its Fortran and semantic-`.pyi`
+ algorithms, source-level navigation, executable examples, and ownership
+ boundaries.
+- Reviewed the Semantics Stage guide around its shared IR, frontend-conversion
+ algorithms, raw contract facts, executable examples, and policy boundary.
+- Reviewed the Policy Stage guide around ordered policy completion, immutable
+ interoperability decisions, module algorithms, executable examples, and the
+ planning boundary.
+- Reviewed the Planning Stage guide around deterministic policy projection,
+ editable plan ownership, module algorithms, executable examples, and the
+ generator freeze boundary.
+- Reviewed the Code Generation Stage guide around its generator handoff,
+ backend lowering algorithms, plan-only decisions, executable examples, and
+ focused evidence.
+- Reviewed the Printing Stage guide around representation-specific traversal,
+ safe source formatting, isolated `.pyi` emission, executable examples, and
+ focused evidence.
+- Reviewed the Compiler Stage guide around coherent toolchain selection,
+ explicit command construction, conditional native-support installation,
+ executable examples, and focused evidence.
+- Added focused C Binding and Fortran Bridge lowering guides with executable
+ manually constructed plans and printed backend-source examples.
+- Moved binding and bridge algorithms and rendered-source demonstrations out
+ of the Code Generation overview and into their focused lowering guides.
+- Explained each reviewed package-guide execution example in terms of its
+ in-memory setup and the stage boundary established by its output.
+- Added Pipeline Component and source-level navigation for contract loading,
+ wrapper generation, build-manifest replay, and `build.py` orchestration.
+- Removed empty package-marker entries from the Pipeline Component and Compiler
+ Stage guides.
+- Added a brief Developer Documentation overview that routes readers to
+ Architecture, then Architecture Components, and linked it from the website
+ home page.
+- Replaced the contributor architecture's text-only build path with a rendered
+ diagram of its two input routes and shared pipeline.
+- Made the architecture build-path diagram keyboard-accessible and linked each
+ route and stage to its reviewed component guide.
+- Added accessible explanations for `.pyi`, f2py `.pyf`, ABI, semantic IR,
+ array order, and the GIL throughout User Documentation and on the Home page,
+ plus per-stage detail panels to the architecture diagram.
+- Changed the site-wide repository control into a “★ Star on GitHub” call to
+ action while preserving its repository destination.
+- Published concise Contracts, Naming, Runtime, and Utilities component guides,
+ restored their architecture links, corrected the diagram fallback, and
+ clarified the NumPy result type in the architecture example.
+- Made numeric scalar results consistently preserve their exact NumPy types;
+ Boolean scalar results remain Python `bool` values.
+- Corrected user documentation to distinguish numeric and Boolean scalar
+ boundaries, and aligned the Getting Started route with normal package
+ installation rather than a repository checkout.
+- Reduced documentation tests to enforce publication, link integrity,
+ executable examples, and public-reference contracts without freezing prose,
+ headings, page inventories, private names, or source-tree layout.
+- Reclassified implementation-structure and codegen-complexity checks as
+ contributor recommendations, while retaining hard behavioral, safety, ABI,
+ publication, and architectural-boundary contracts.
+- Moved contributor package-guide execution checks into the documentation
+ suite, using each guide's displayed result instead of a duplicate exact-
+ output inventory.
- Reduced the root `prik` API to its version and normal-user build entrypoints;
parser, semantic, probe, runtime, and planning tools now use their owning
package import paths.
@@ -29,16 +123,10 @@ release tags add a leading `v` to the package version.
- Made `prik` an import-only package boundary by removing its direct-script
demonstration; command and stage-value examples remain available from their
owning modules.
-- Expanded the contributor architecture and package guides into a complete
- stage-by-stage tutorial, with every supported Python module, runnable example
- result, focused test purpose, and change route recorded and checked against
- the source tree.
+- Expanded the contributor architecture and package guides with concrete stage
+ handoffs, runnable example results, focused test purposes, and change routes.
- Moved generated documentation and distribution output under the hidden
`.artifacts/` directory in local commands and CI workflows.
-- Centralized every production-file execution-example output contract in one
- contributor-architecture test inventory with one named test per file.
-- Renamed the central infrastructure owner to `execution_examples/` so its
- responsibility is explicit in the test tree.
- Consolidated developer and maintainer material under one Contributor
Documentation tree and removed the separate maintainer documentation lane.
- Moved the bundled header-only binding runtime from the package root into
@@ -52,9 +140,7 @@ release tags add a leading `v` to the package version.
the former `prik.compiling`, `prik.probes`, parser-local C preprocessor, and
pipeline-local preprocessing import paths were removed.
- Replaced the public semantic-to-NumPy helper API with stage-owned semantic,
- contract-runtime, and code-generation datatype catalogues, and documented the
- complete internal datatype lifecycle from compiler probing to runtime
- validation.
+ contract-runtime, and code-generation datatype catalogues.
- Separated post-IR policy and wrapper planning into `prik.policy` and
`prik.planning`; code generation now renders plan-driven docstrings, and the
former maintainer import paths were removed.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 63643cfdc..6aa89dbcd 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -13,7 +13,7 @@ python3 -m pip install -e ".[qa]"
Run the smallest relevant test while you work:
```bash
-PYTHONPATH=. python3 -m pytest -q path/to/tests
+python3 -m pytest -q path/to/tests
```
## Before opening a pull request
@@ -26,7 +26,7 @@ PYTHONPATH=. python3 -m pytest -q path/to/tests
```bash
python3 -m ruff check .
python3 -m ruff format --check .
-PYTHONPATH=. python3 -m pytest -q path/to/tests
+python3 -m pytest -q path/to/tests
```
Keep the pull request easy to review: explain the problem, the solution, and
diff --git a/docs/developer/architecture.md b/docs/developer/architecture.md
index cbea7fab3..7d1af4a03 100644
--- a/docs/developer/architecture.md
+++ b/docs/developer/architecture.md
@@ -1,241 +1,159 @@
---
-title: Contributor Architecture Guide
+title: PRIK Architecture
audience: developers, maintainers, contributors
prerequisites: repository checkout
-related: packages/index.md, source-map.md, feature-to-code-map.md, testing-strategy.md
+related: packages/index.md, codebase-map.md, feature-to-code-map.md, testing-strategy.md
status: maintained
-publication: draft
+publication: reviewed
---
-# Contributor Architecture Guide
-
-Read this page before changing PRIK. It gives the complete wrapper path, the
-handoff at every stage, and the owner of each top-level directory. Then read
-the linked package guide for the file you intend to change. Package guides
-explain local modules, runnable examples, and focused tests; this page stays
-at the workflow level.
-
-## Repository Structure
-
-```text
-prik/
-├── prik/ # Production Python package and wrapper stages
-├── tests/ # Feature-first and stage-owned verification
-├── docs/ # User and contributor documentation sources
-├── docs_theme/ # Maintained MkDocs template customizations
-├── examples/ # Complete wrapper projects and real libraries
-├── benchmarks/ # Performance workloads and publication tooling
-├── tools/ # Repository maintenance and quality scripts
-├── .github/ # Continuous integration and release workflows
-├── .artifacts/ # Hidden generated documentation and distributions
-├── pyproject.toml # Package and Python-tool configuration
-├── mkdocs.yml # Documentation navigation and site configuration
-├── CHANGELOG.md # Visible unreleased and released changes
-├── CONTRIBUTING.md # Contributor entrypoint
-├── README.md # Public project overview
-└── AGENTS.md # Repository implementation and verification rules
-```
-
-The production package is arranged by stage ownership, not alphabetically:
-
-```text
-prik/
-├── __init__.py # Supported public Python API
-├── __main__.py # python3 -m prik launcher
-├── cli.py # Command validation and stage dispatch
-├── contracts/ # Public semantic .pyi vocabulary
-├── compiler/ # Native compiler and linker services
-├── preprocessing/ # Source preparation and target probes
-├── parsers/ # Fortran and semantic .pyi syntax frontends
-├── semantics/ # Language-neutral semantic IR
-├── policy/ # Completed post-IR interoperability decisions
-├── planning/ # Backend-neutral wrapper plans
-├── codegen/ # Backend nodes and Python facade generation
-├── printers/ # C, Fortran, and semantic .pyi serialization
-├── pipeline/ # Cross-stage workflow orchestration
-├── runtime/ # Imported-extension handles and native support
-├── naming/ # Shared public and generated-symbol rules
-└── utilities/ # Genuinely stage-neutral mechanisms
-```
+# PRIK Architecture
-The deferred C-input frontend is deliberately not part of this published
-Fortran workflow. Generated C bindings are part of the supported backend and
-remain visible in the code-generation and printer guides.
+PRIK turns Fortran declarations into importable CPython extensions. It first
+records source facts, converts them into a language-neutral semantic model,
+completes the interoperability policy, plans the wrapper, and emits and builds
+the native code. Editable semantic `.pyi` contracts can enter the same process
+at semantic-IR construction.
-## Package-Root Entry Points
+This document describes the system-level model: the stages, their handoffs,
+their authority boundaries, and the representations they produce. The linked
+[architecture component guides](packages/index.md) describe the implementation inside each
+package.
-Only user-facing entrypoint modules live directly in `prik/`. Shared
-mechanisms live in their owning subpackage, so the root does not take
-ownership from a stage package.
+## Build Architecture
-| File | Read it when | It receives and produces |
-| --- | --- | --- |
-| `prik/__init__.py` | you need the normal-user build API | Import-only facade for `__version__` and the three build entrypoints. Import parsing, contracts, probes, runtime handles, and semantic tools from their owning packages. |
-| `prik/__main__.py` | you are tracing `python3 -m prik` | Calls `prik.cli.main()` only when executed as a module. |
-| `prik/cli.py` | you are changing a command or option | Turns terminal arguments into validated stage requests and dispatches them to the owning parser or pipeline. |
+The package root is a small public facade. A direct Fortran build enters through
+`build_fortran_extension`:
-Run the direct command demonstration from the repository root:
+```python
+from prik import build_fortran_extension
-```bash
-python3 prik/cli.py --version
+result = build_fortran_extension("solver.f90", output_dir="build/solver")
+module = result.import_module()
```
-```text
-prik 0.2.1
-```
+`prik.__init__` exposes `__version__` and the source-first and contract-first
+build entry points: `build_fortran_extension` and `build_pyi_extension`. The
+CLI enters through `python3 -m prik` and dispatches to the same stage owners.
+Its parser, semantic, and report commands intentionally stop before a complete
+wrapper build.
-The table identifies the supported import surface. The example shows the
-command dispatcher. The stage-record freeze demonstration belongs to the
-[Utilities package guide](packages/utilities.md). Their exact output is
-checked by the
-[central execution-example tests](../../tests/fortran/infrastructure/execution_examples/test_execution_examples.py).
-
-## End-To-End Workflow
-
-The normal source-driven Fortran route is a one-way sequence:
-
-```text
-CLI or Python build request
- -> preprocessing and target probes
- -> Fortran parser facts
- -> language-neutral semantic IR
- -> complete interoperability policy
- -> backend-neutral wrapper plan
- -> C and Fortran nodes plus Python facade text
- -> C and Fortran source text
- -> in-memory generated wrapper
- -> native compilation and linking
- -> importable extension and runtime objects
-```
+The two input routes converge in semantic IR construction, then share policy,
+planning, generation, and native compilation:
-Semantic `.pyi` input enters at semantic-IR construction. It is an editable
-contract input that uses the same policy, planning, code-generation, and build
-path; it is not a second backend. A type-mapping report follows the same
-facts for inspection but does not create a wrapper.
+
-## Stage Handoffs
+Select a stage or input route to open its component guide. Each route box opens
+its first owning stage.
-Read the rows top to bottom. Each output is the next row's authoritative
-input; a later row may organize or lower it, but may not silently change its
-meaning.
+Pipeline orchestration spans the complete build: it coordinates source facts,
+shared meaning, completed interoperability policy, a wrapper plan, emitted
+artifacts, and the final result. `compiler/` is the native execution service
+invoked after generated source is available. The following table names the
+concrete representations produced for one small wrapper.
-| Stage owner | Receives | Produces | Next owner |
-| --- | --- | --- | --- |
-| `preprocessing/` | source paths, compiler configuration, target requests | prepared source, provenance, dependency facts, measured target facts | `parsers/`, `semantics/` |
-| `parsers/` | prepared Fortran text or `.pyi` text | source parser models or a Python AST, with locations and diagnostics | `semantics/` |
-| `semantics/` | frontend facts and measured type facts | `SemanticModule`: stable identities, shapes, provenance, and raw metadata | `policy/` |
-| `policy/` | semantic IR plus raw requests | complete immutable choices for ownership, transport, projection, lifecycle, setters, and support | `planning/` |
-| `planning/` | policy-complete semantic IR | `ModulePlan` with binding and bridge views, ordering, names, and build requirements | `codegen/` |
-| `codegen/` | a validated plan | typed C/Fortran nodes and planned Python facade source | `printers/`, `pipeline/` |
-| `printers/` | formed native nodes or semantic IR | C, Fortran, or `.pyi` text | `pipeline/` or caller |
-| `pipeline/` | completed stage inputs | generated artifacts, written files, native build requests, and public result records | `compiler/`, `runtime/` |
-| `compiler/` | explicit source, object, include, library, and link inputs | recorded or executed native commands and a shared extension | `runtime/` |
-| `runtime/` | generated extension operations and completed handle contracts | validated Python handle objects and live NumPy views | Python caller |
+Three supporting packages cross those stages without becoming hidden policy
+owners: [`contracts/`](packages/contracts.md) supplies the public semantic
+`.pyi` vocabulary; [`naming/`](packages/naming.md) supplies stable public and
+generated-name rules; and [`utilities/`](packages/utilities.md) supplies only
+stage-neutral mechanisms. [`runtime/`](packages/runtime.md) enforces completed
+handle and view behavior after the generated extension is imported.
-`naming/` supplies deterministic public and native names where planning or
-generation needs them. `utilities/` supplies small stage-neutral mechanisms;
-neither is a hidden policy stage. `contracts/` supplies the public `.pyi`
-vocabulary before parsing begins.
+Type-mapping reports inspect source and semantic facts without building a
+wrapper. They are an inspection route, not a second backend.
-## Authority And Dependency Rules
+## `scale` Across the Pipeline
-The handoff table describes data flow. This table describes decision-making.
+The [one-command quick start](../index.md#from-fortran-to-python-in-one-command)
+introduces the source, build command, and `7.5` result. Here, its `scale`
+function illustrates the representations produced across the pipeline.
-| Stage | May decide | Must not decide |
-| --- | --- | --- |
-| Preprocessing and probes | prepared source, provenance, dependencies, measured target facts | declaration meaning, semantic types, wrapper support |
-| Parsers | syntax facts, source structure, source-located diagnostics | ownership, Python API, lowering |
-| Semantic IR | language-neutral identities, shapes, origins, raw contract metadata | completed lifetime, projections, or emitted mechanisms |
-| Policy | exports, object kind, owner, transfer, destruction, storage, writeback, nullability, projections, setters, support | source grammar or backend text |
-| Planning | a typed projection and ordering of completed facts | a new semantic decision or presentation text |
-| Code generation | plan-selected backend mechanisms and syntax nodes | fallback policy inferred from datatype, `intent`, aliases, or local memory checks |
-| Printers | formatting and serialization | orchestration, filenames, or semantic decisions |
-| Pipeline | stage order, artifact assembly, manifests, and compilation scheduling | grammar, policy, lowering, or command mechanics |
-| Compiler and runtime | native command execution and enforcement of completed runtime contracts | wrapper API or lifetime-policy selection |
-
-The critical boundary is before `WrapperPlanner.build()`: all semantic choices
-needed by binding and bridge generation must be explicit. If a required choice
-is absent, downstream code must fail with the owning diagnostic rather than
-guess a default.
-
-## Package Guide Map
-
-Use one guide at a time after this page. Every guide has the same reading
-order: purpose, input/output handoff, complete Python-module tour, runnable
-examples, focused tests, change routes, and invariants.
-
-| Package | Use it for | Guide |
+| Stage owner | Result for `scale` | What that owner is responsible for |
| --- | --- | --- |
-| `contracts/` | public semantic `.pyi` names | [Contracts](packages/contracts.md) |
-| `compiler/` | native commands, profiles, and support installation | [Compiler](packages/compiler.md) |
-| `preprocessing/` | parser input, provenance, includes, and target facts | [Preprocessing](packages/preprocessing.md) |
-| `parsers/` | Fortran syntax facts and raw `.pyi` AST | [Parsers](packages/parsers.md) |
-| `semantics/` | language-neutral IR and raw metadata | [Semantics](packages/semantics.md) |
-| `policy/` | completed interoperability decisions | [Policy](packages/policy.md) |
-| `planning/` | deterministic plan projection and ordering | [Planning](packages/planning.md) |
-| `codegen/` | binding, bridge, nodes, and Python facade mechanisms | [Code generation](packages/codegen.md) |
-| `printers/` | C, Fortran, and `.pyi` serialization | [Printers](packages/printers.md) |
-| `pipeline/` | whole-wrapper, contract, report, and build workflows | [Pipeline](packages/pipeline.md) |
-| `runtime/` | imported handle behavior and native payload | [Runtime](packages/runtime.md) |
-| `naming/` | stable public and generated symbols | [Naming](packages/naming.md) |
-| `utilities/` | stage-neutral expression, string, and visitor helpers | [Utilities](packages/utilities.md) |
-
-The [datatype lifecycle](concepts/datatype-lifecycle.md) follows one datatype
-across these owners. It is deliberately separate from the package tours.
-
-## Tests And Evidence
-
-Feature tests own behavior; documentation tests own navigation and guide
-coverage. Start with the package guide's **Tests And What They Prove** section,
-then use the [testing strategy](testing-strategy.md) to choose the narrowest
-command for the changed stage.
-
-Direct source-file examples are real production-owned
-`if __name__ == "__main__"` flows. Run them from the repository root as:
-
-```bash
-python3 /.py
-```
+| `pipeline/` | A public build request, artifact layout, native build request, and eventually a `WrapperBuildResult`. | Orchestrate the complete build without taking over stage-owned decisions. |
+| `preprocessing/` | Prepared source, provenance, dependencies, and compiler-derived type facts. | Make the source and target facts available to later stages. |
+| `parsers/` | A `FortranProject` with source-faithful function, argument, type, and `intent` facts. | Record syntax and source-located diagnostics without deciding wrapper behavior. |
+| `semantics/` | A language-neutral semantic model ([`SemanticModule`](packages/semantics.md)) containing a callable and its stable type, shape, origin, and raw contract metadata. | Give frontend facts a shared meaning. |
+| `policy/` | The semantic model with complete export, transport, ownership, projection, lifecycle, and support choices. | Decide how the callable may interoperate with Python. |
+| `planning/` | A deterministic wrapper plan ([`ModulePlan`](packages/planning.md)) with ordered binding and bridge operations, names, and build requirements. | Project and validate completed choices without making new policy. |
+| `codegen/` | Planned CPython-binding and Fortran-bridge nodes plus Python-facade representation. | Implement the plan-selected mechanisms. |
+| `printers/` | Generated C and Fortran source text. | Serialize formed nodes without deciding behavior. |
+| `compiler/` | Recorded or executed native commands and a linked extension. | Compile and link the explicit native inputs. |
+| Extension module and [`runtime/`](packages/runtime.md) | An importable `scale` module; its call returns `np.float64(7.5)` for `np.float64(3.0)` and `np.float64(2.5)`. | The generated public Python interface and any imported runtime support it uses. |
-The central execution inventory checks their stable output. Documentation
-tests check guide structure, source coverage, links, metadata, and navigation;
-they do not replace feature tests for the behavior the example demonstrates.
+The first incorrect representation locates the stage whose behavior or
+diagnostic changed.
-## Where A Change Begins
+## Architectural Boundaries
-| You need to change | Start with | Then inspect |
-| --- | --- | --- |
-| CLI option or dispatch | `prik/cli.py` | selected owner and CLI/user documentation |
-| Source expansion or provenance | `prik/preprocessing/source.py` | parser-boundary tests |
-| Fortran syntax fact | `prik/parsers/fortran/` | semantic converter if IR changes |
-| Semantic `.pyi` syntax | `prik/parsers/pyi/parser.py` | `semantics/pyi2ir.py`, printer, and contract reference according to meaning |
-| Stable IR/type fact | `prik/semantics/` | policy and downstream projections |
-| Ownership, projection, setters, or support | `prik/policy/` | planning only to project a completed result |
-| Plan representation or ordering | `prik/planning/` | binding/bridge consumers |
-| Emitted native mechanism | narrow `prik/codegen/` owner | matching printer only if node representation changes |
-| Formatting | matching `prik/printers/` module | golden-output tests |
-| Artifact or compilation workflow | `prik/pipeline/build.py` | compiler service for argv mechanics |
-| Runtime handle enforcement | `prik/runtime/handles.py` | policy first if permission or ownership is undecided |
-
-For exact file ownership use the [source map](source-map.md). For a documented
-feature's supported scope and evidence use the [feature-to-code map](feature-to-code-map.md).
-
-## Contributor Documentation Structure
-
-```text
-docs/developer/
-├── index.md
-├── architecture.md
-├── source-map.md
-├── feature-to-code-map.md
-├── testing-strategy.md
-├── packages/ # One detailed guide per production package
-├── concepts/ # Cross-stage concepts
-├── workflows/ # Contribution, QA, CI, docs, and releases
-├── design/ # Accepted future architecture and open decisions
-├── roadmap/ # Active incomplete work only
-└── deferred/ # Intentionally unpublished input-language material
-```
+> **Meaning moves forward. Downstream stages implement earlier decisions; they
+> do not silently reinterpret them.**
-There is no separate maintainer tree. Completed migration logs and placeholder
-pages belong in Git history after their durable decisions have moved here.
+PRIK deliberately separates four kinds of work:
+
+| Kind of work | Owner | Boundary |
+| --- | --- | --- |
+| Source facts | `preprocessing/`, `parsers/` | What was written and what the compiler target reports. |
+| Shared meaning | `semantics/` | A language-neutral model, not a Python API or emitted code. |
+| Interoperability decisions | `policy/` | Complete policy before planning starts. |
+| Planned mechanism and emitted text | `planning/`, `codegen/`, `printers/` | Implement the completed decision; do not replace it. |
+
+The critical boundary is before
+[`WrapperPlanner.build()`](packages/planning.md), the planning operation that
+projects policy-complete semantic IR into a `ModulePlan`. By then, policy has
+completed every decision needed by wrapper generation: object kind, ownership,
+transfer, destruction, storage, mutability and writeback, nullability, output
+projection, setter behavior, release responsibility, and support.
+
+Planning may order, name, validate, and project those choices. It must not
+invent a new interoperability decision. Code generation then dispatches from
+the plan into named implementation mechanisms.
+
+Binding and bridge generation must not infer or override policy from a
+datatype, Fortran `intent`, alias shape, storage layout, or a local memory
+check. If a required decision is absent, its owner reports the diagnostic; a
+downstream fallback would hide an architectural error.
+
+The architecture preserves these invariants:
+
+- Parsers preserve source facts; semantic IR supplies shared meaning.
+- Policy is complete before planning; planning projects rather than creates it.
+- Code generation implements a plan; printers only serialize it.
+- Pipeline orchestrates stages; it does not become a parser, policy engine, or
+ lowering backend.
+- Supported behavior has focused owner-stage evidence and, when public,
+ end-to-end evidence.
+
+## Input Routes
+
+PRIK has two supported ways to describe a wrapper. They converge at
+`SemanticModule` and use the same policy, planning, lowering, build, and
+runtime architecture afterward.
+
+| Input | Enters through | Architectural role |
+| --- | --- | --- |
+| Fortran source | preprocessing, Fortran parsing, and Fortran-to-IR conversion | Source-first wrapper contract. |
+| Semantic `.pyi` | raw `.pyi` parsing and `.pyi`-to-IR conversion | Contract-first wrapper surface with explicit native implementation inputs. |
+
+The C-input frontend is deferred and is not part of the published contributor
+architecture. This does not affect PRIK's generated CPython C binding backend,
+which remains part of the supported Fortran-wrapper architecture.
+
+## Ownership and Evidence
+
+The stage at which PRIK first has enough information to determine an answer
+owns both the behavior and its diagnostic. Syntax facts belong to parsing;
+language-neutral types and shapes belong to semantics; ownership, projection,
+lifetime, setters, and support belong to policy; completed wrapper operations
+belong to planning; and emitted mechanisms belong to code generation.
+
+Focused tests prove an invariant at its earliest owner. Public support claims
+also require end-to-end build, import, call, and behavior evidence. The
+[testing strategy](testing-strategy.md) records the complete evidence model;
+the [codebase map](codebase-map.md), [feature-to-code map](feature-to-code-map.md),
+and [architecture component guides](packages/index.md) record the detailed
+ownership.
+For package and module ownership, continue with the
+[Codebase Map](codebase-map.md).
diff --git a/docs/developer/assets/build-path.svg b/docs/developer/assets/build-path.svg
new file mode 100644
index 000000000..b35a21265
--- /dev/null
+++ b/docs/developer/assets/build-path.svg
@@ -0,0 +1,158 @@
+
diff --git a/docs/developer/codebase-map.md b/docs/developer/codebase-map.md
new file mode 100644
index 000000000..d953c7c6d
--- /dev/null
+++ b/docs/developer/codebase-map.md
@@ -0,0 +1,72 @@
+---
+title: Codebase Map
+audience: developers, contributors
+prerequisites: contributor architecture guide
+related: architecture.md, packages/index.md, feature-to-code-map.md, testing-strategy.md
+status: maintained
+publication: reviewed
+---
+
+# Codebase Map
+
+This page is the directory of ownership for the maintained Fortran wrapper
+route. It identifies the package or module that owns a concern. The
+[architecture](architecture.md) explains the stage handoffs and authority
+boundaries; the [feature-to-code map](feature-to-code-map.md) connects a
+user-visible behavior to its documentation and evidence.
+
+## Public And Build Entry Points
+
+| Location | Responsibility |
+| --- | --- |
+| `prik/__init__.py` | Public build entry points and version. |
+| `prik/cli.py` | CLI argument validation, stage selection, and output routing. |
+| `prik/pipeline/build.py` | Source-first and contract-first extension-build orchestration. |
+| `prik/pipeline/pyi.py` | Semantic `.pyi` loading and external-type reconciliation. |
+| `prik/pipeline/wrapper.py` | Completed plan to rendered-wrapper orchestration and artifact records. |
+| `prik/compiler/compilers.py` | Native compiler invocation and tool lookup. |
+
+## Component Ownership
+
+| Component | Owns | Key modules |
+| --- | --- | --- |
+| [`prik.pipeline`](packages/pipeline.md) | Build, wrapper, contract, report, and artifact orchestration. | `build.py`, `pyi.py`, `wrapper.py`, `type_mapping_report.py` |
+| [`prik.preprocessing`](packages/preprocessing.md) | Prepared Fortran input, provenance, includes, and target probes. | `source.py`, `fortran.py`, `probes/fortran_types.py` |
+| [`prik.parsers`](packages/parsers.md) | Fortran and semantic `.pyi` syntax facts. | `fortran/parser.py`, `pyi/parser.py` |
+| [`prik.semantics`](packages/semantics.md) | Language-neutral semantic IR, conversions, scalar vocabulary, and raw metadata. | `models.py`, `fortran2ir.py`, `pyi2ir.py` |
+| [`prik.policy`](packages/policy.md) | Completed ownership, export, lifecycle, and support policy. | `completion.py`, `construction.py`, `ownership.py`, `exports.py` |
+| [`prik.planning`](packages/planning.md) | Policy-complete, backend-neutral wrapper plans. | `models.py`, `planner.py` |
+| [`prik.codegen`](packages/codegen.md) | Plan-driven C and Fortran lowering, backend scalar projection, and Python facades. | `c/binding.py`, `c/python_surface.py`, `fortran/bridge.py` |
+| [`prik.printers`](packages/printers.md) | Serialization of C, Fortran, and semantic `.pyi` representations. | `c.py`, `fortran.py`, `pyi.py` |
+| [`prik.compiler`](packages/compiler.md) | Compiler execution, native-support installation, and linking. | `compilers.py`, `objects.py`, `native_support.py` |
+| [`prik.runtime`](packages/runtime.md) | Imported runtime objects and bundled native support. | `handles.py`, `native_support/` |
+| [`prik.contracts`](packages/contracts.md) | Public semantic `.pyi` contract vocabulary. | `__init__.py` |
+| [`prik.naming`](packages/naming.md) | Public-name normalization and generated-symbol construction. | `policy.py`, `native_symbols.py` |
+| [`prik.utilities`](packages/utilities.md) | Small helpers with no stage-specific ownership. | `declaration_expressions.py`, `stage_values.py`, `strings.py`, `visitor.py` |
+
+The [architecture component guides](packages/index.md) give each component's
+local module tour,
+boundaries, execution example, and focused tests.
+
+## Cross-Stage Hotspots
+
+| Concern | Primary owners |
+| --- | --- |
+| Prepared source and target facts | `prik/preprocessing/source.py`, `prik/preprocessing/fortran.py`, `prik/preprocessing/probes/fortran_types.py` |
+| Parsed language facts | `prik/parsers/fortran/parser.py`, `prik/parsers/pyi/parser.py` |
+| Shared meaning | `prik/semantics/models.py`, `prik/semantics/fortran2ir.py`, `prik/semantics/pyi2ir.py` |
+| Completed interoperability policy | `prik/policy/completion.py`, `prik/policy/construction.py`, `prik/policy/ownership.py`, `prik/policy/exports.py` |
+| Deterministic wrapper planning | `prik/planning/models.py`, `prik/planning/planner.py` |
+| Fortran bridge and CPython binding lowering | `prik/codegen/fortran/bridge.py`, `prik/codegen/c/binding.py`, `prik/codegen/c/python_surface.py` |
+| Generated-text serialization | `prik/printers/fortran.py`, `prik/printers/c.py`, `prik/printers/pyi.py` |
+| Native build and runtime payload | `prik/compiler/objects.py`, `prik/compiler/compilers.py`, `prik/compiler/native_support.py`, `prik/runtime/native_support/` |
+| Names and scalar representations | `prik/naming/policy.py`, `prik/naming/native_symbols.py`, `prik/semantics/scalar_types.py`, `prik/codegen/primitive_scalar_types.py` |
+
+## Documentation And Evidence
+
+The [feature-to-code map](feature-to-code-map.md) names the public
+documentation and focused tests for a supported behavior. The
+[testing strategy](testing-strategy.md) describes test-tree ownership. Update
+this map when package or cross-stage module ownership changes; update a package
+guide when its local module structure changes. The supported public surface is
+recorded in the public feature matrix.
diff --git a/docs/developer/concepts/datatype-lifecycle.md b/docs/developer/concepts/datatype-lifecycle.md
deleted file mode 100644
index 274a385d5..000000000
--- a/docs/developer/concepts/datatype-lifecycle.md
+++ /dev/null
@@ -1,374 +0,0 @@
----
-title: Datatype Lifecycle
-audience: developers, maintainers, contributors
-prerequisites: contributor architecture guide, semantic IR
-related: ../architecture.md, ../packages/preprocessing.md, ../packages/semantics.md, ../packages/codegen.md, ../../user/reference/semantic-ir.md
-status: maintained
-publication: draft
----
-
-# Datatype Lifecycle
-
-This page is the implementation contract for datatype handling inside PRIK. It
-traces native declarations from compiler measurement and parsing through
-semantic normalization, policy completion, wrapper planning, generated NumPy
-boundaries, and runtime validation. It also identifies the separate registries
-used at those stages and explains why they must not be collapsed into one
-bidirectional type map.
-
-The central rule is:
-
-> Compiler probes describe the selected native target, semantic IR gives those
-> facts stable language-neutral identities, policy completes behavior for each
-> use site, and code generation selects emitted representations from the
-> completed plan.
-
-NumPy is a Python-boundary representation. It is not the authority for native
-storage, semantic identity, ownership, mutability, or lifetime.
-
-## End-To-End Datatype Flow
-
-```text
-native source declaration
- -> compiler preprocessing
- -> parser-native datatype, kind, shape, and attribute facts
- -> compiler probes for target-dependent kind and storage values
- -> source-to-IR conversion
- -> stable semantic name and resolved dtype
- -> origin and native spelling
- -> rank, shape, storage category, and source provenance
- -> post-IR policy completion
- -> ownership, transfer, destruction, mutability, and projection
- -> boundary storage mode and supported/blocked decision
- -> wrapper planning
- -> datatype family plus completed transfer/result/access plans
- -> backend scalar registry and specialized datatype lowering
- -> generated native bridge and Python/NumPy binding nodes
- -> language printers
- -> native compilation and linking
- -> exact runtime boundary validation
-```
-
-Each arrow changes the representation for a reason. The parser preserves what
-the source declared. Probing supplies facts the source spelling alone cannot
-determine. Semantic conversion normalizes equivalent source forms. Policy adds
-context-dependent behavior. Planning freezes that behavior into an
-implementation contract. Codegen then chooses syntax and runtime operations;
-it does not reinterpret the datatype.
-
-## The Four Datatype Authorities
-
-PRIK deliberately has four related but non-interchangeable authorities.
-
-| Authority | Owner | Key | Value | Purpose |
-| --- | --- | --- | --- | --- |
-| Native target facts | `prik/preprocessing/probes/` | compiler expression or native spelling | measured kind, storage, precision, signedness, or availability | Describe the selected compiler target. |
-| Semantic scalar catalogue | `prik/semantics/scalar_types.py` | stable semantic name such as `Float64` | family and intrinsic storage facts | Define language-neutral scalar vocabulary without importing NumPy. |
-| Runtime contract factories | `prik/contracts/__init__.py` | semantic contract name | real NumPy scalar factory or an explicit constructor error | Make public semantic `.pyi` symbols safely usable at runtime where supported. |
-| Backend datatype catalogues | `prik/codegen/primitive_scalar_types.py` | resolved semantic name | emitted NumPy expressions plus native spellings, NumPy type macros, Python parse/result behavior, and descriptor spelling | Project semantic dtypes for reporting and lower implemented primitive scalar plans without coupling the two generators. |
-
-The same semantic name appears in more than one table because each table owns
-different facts. Consistency tests compare their overlapping keys, but one
-stage must not import a later stage merely to avoid repeating an invariant it
-owns independently.
-
-## Native Target Probing
-
-### Why probing exists
-
-Source spelling is insufficient for target-dependent datatypes. A default
-integer kind, a selected real kind, a legacy star-width declaration, and a
-named interoperable kind can denote different storage on different compiler
-targets or under different target-changing flags.
-
-The build pipeline therefore uses the same effective compiler configuration
-for preprocessing, datatype measurement, native compilation, and generated
-bridge compilation. Flags that change kinds, widths, ABI, or target architecture
-must reach probing. A report measured under one target must not be reused as if
-it described another.
-
-`prik/preprocessing/probes/fortran_types.py` compiles generated measurement programs and
-returns `FortranTypeProbeReport`. Its cache identity includes the generated
-source, compiler identity, flags, working directory, target environment, and
-optional runner. The two main outputs are:
-
-- compile-time values used to resolve kind and specification expressions;
-- storage facts for intrinsic datatype/kind pairs used by semantic conversion.
-
-`prik/pipeline/build.py` collects requirements from the parsed project, asks the
-probe service only for required facts, and supplies the evaluated values and
-type facts to `FortranToIRConverter`. Probes never decide ownership, Python
-visibility, output projection, or wrapper support.
-
-
-
-### Probe reports are evidence, not semantic models
-
-A probe report records reproducible compiler observations. It may be serialized
-or cached, but it does not become semantic IR and it does not contain wrapper
-policy. Source-to-IR conversion owns the interpretation of those observations.
-
-The Markdown datatype report lives in `prik/pipeline/type_mapping_report.py`
-because it intentionally combines several stages:
-
-```text
-probe facts -> semantic conversion -> backend NumPy projection -> Markdown
-```
-
-That report is documentation and inspection output. It is not an alternative
-conversion path and must reuse the normal converters and backend catalogue.
-
-## Parsing And Semantic Normalization
-
-Parsers preserve native declarations rather than prematurely replacing them
-with Python or NumPy types. Relevant parser facts include:
-
-- native base type and kind spelling;
-- declaration or measured storage width;
-- scalar versus array shape and rank;
-- pointer, allocatable, target, optional, and value attributes;
-- character kind and length syntax;
-- derived-type identity and scope;
-- procedure/callback signature structure;
-- source coordinates and the original native spelling.
-
-The source-to-IR converters combine those facts with target measurements and
-produce `SemanticType` plus `SemanticOrigin` and `SemanticStorageContract`.
-`SemanticType.name` is the public semantic identity. `SemanticType.dtype` is
-the resolved storage dtype used by later stages. They can differ when a stable
-public concept has target-specific storage.
-
-For example, an unresolved native default integer can begin as `Int`, then
-resolve to `Int32` or `Int64` after compiler measurement. The converter records
-the source spelling and target provenance; it does not replace those facts with
-`numpy.int32` or `numpy.int64`.
-
-## Semantic Scalar Catalogue
-
-`prik/semantics/scalar_types.py` is the single semantic vocabulary for
-primitive scalar names. Its immutable `SemanticScalarSpec` records only facts
-that are intrinsic to the semantic identity:
-
-- datatype family;
-- storage width when the semantic identity fixes one;
-- whether the name represents a Boolean storage contract.
-
-The module exposes checked helpers for scalar membership and Boolean storage
-width. It does not import NumPy and contains no emitted source spelling.
-Extended `Float128` and `Complex256` catalogue entries intentionally leave
-`storage_bits` unresolved because supported targets can store them in 80/96/128
-or 160/192/256 bits respectively; compiler facts select the actual storage.
-
-Boolean names demonstrate why the semantic and NumPy layers are distinct:
-
-| Semantic name | Native storage contract | NumPy boundary dtype |
-| --- | --- | --- |
-| `Bool` | default or interoperable Boolean, normalized to 8-bit boundary storage | `numpy.bool_` |
-| `Bool8` | 8 bits | `numpy.bool_` |
-| `Bool16` | 16 bits | `numpy.bool_` |
-| `Bool32` | 32 bits | `numpy.bool_` |
-| `Bool64` | 64 bits | `numpy.bool_` |
-
-The binding normalizes Boolean values at the boundary, while the generated
-bridge uses the compiler-resolved native logical representation. A NumPy dtype
-alone therefore cannot reconstruct the original semantic Boolean contract.
-
-## Runtime Contract Factories
-
-`prik/contracts/__init__.py` owns the public names used by generated and edited
-semantic `.pyi` contracts. Its private contract-factory catalogue maps a
-semantic name to a real NumPy scalar factory where a portable runtime value
-exists. This lets expressions such as `Float64()` create the exact scalar type
-required by a generated wrapper and lets typed descriptor contracts retain a
-concrete `numpy.dtype`.
-
-Names without a portable runtime factory remain explicit contract symbols and
-raise a focused constructor error. Examples include unresolved `Int`, `UInt`,
-`CEnum`, `Char`, `String`, and `Void`. The contracts package does not perform
-source-to-IR conversion and its factories do not define native ABI storage.
-
-## Backend Primitive Scalar Catalogue
-
-`prik/codegen/primitive_scalar_types.py` owns two readable mappings.
-`NumpyDtypeRegistry.TYPES` maps every resolved semantic dtype with a maintained
-NumPy projection to its emitted expression. `PrimitiveScalarTypeRegistry.TYPES`
-contains the narrower set with implemented native wrapper lowering. Each
-`BackendScalarType` entry uses keyword arguments so a maintainer can audit one
-row without remembering positional field order.
-
-The fields cover:
-
-| Field | Meaning |
-| --- | --- |
-| `semantic_name` | Resolved semantic key consumed from the wrapper plan. |
-| `c_spelling` | Native binding-side storage spelling. |
-| `fortran_spelling` | Generated bridge declaration spelling. |
-| `python_parse_unit` | Python argument parsing unit used by the binding. |
-| `numpy_type_macro` | NumPy array dtype identity checked or allocated in generated code. |
-| `python_result_kind` | Result-conversion path for an ordinary procedure result. |
-| `python_type_name` | Python/NumPy scalar expression shown in validation diagnostics or constructors. |
-| `python_module_result_kind` | Result-conversion path for module state. |
-| `cfi_type_spelling` | Descriptor element type identity for descriptor-based boundaries. |
-
-The catalogue contains only implemented primitive scalar lowering lanes.
-Adding a semantic name to the semantic catalogue does not automatically enable
-wrapper generation. Unsupported entries must continue to fail during policy or
-planning rather than acquiring guessed backend spellings.
-
-
-
-## Why There Is No Universal NumPy-To-Semantic Map
-
-The maintained lookup direction is:
-
-```text
-resolved semantic dtype -> stage-owned NumPy or backend facts
-```
-
-The reverse direction is not generally valid:
-
-- every Boolean storage contract projects to `numpy.bool_`;
-- `numpy.longdouble`, `numpy.clongdouble`, and `numpy.uintp` vary by platform;
-- source concepts such as unresolved `Int`, `CEnum`, and fixed-length native
- character storage require context that a NumPy dtype does not carry;
-- ownership, mutability, rank, layout, pointer association, allocation state,
- and callback identity are not dtype properties.
-
-Runtime validation may compare an actual NumPy dtype with the exact dtype in a
-completed plan. It must not use the observed dtype to infer semantic meaning or
-select a different lowering path. If a future frontend accepts NumPy types as
-source annotations, that frontend must own an explicitly contextual and
-possibly lossy input mapping.
-
-## Non-Primitive Datatype Families
-
-### Arrays
-
-An array is not a separate scalar dtype. Semantic IR stores its element dtype,
-rank, shape expressions, bounds provenance, layout/order, contiguity, and
-pointer or allocatable attributes in `SemanticArrayContract`. Policy completes
-copy/alias behavior, writeback, nullability, descriptor ownership, and result
-projection. The plan then records exact validation and transfer actions.
-
-Generated bindings validate dtype, rank, shape, layout, alignment,
-writeability, and permitted stride forms from that plan. They do not silently
-cast or transpose unless policy selected an explicit copy path.
-
-### Characters And Strings
-
-Character handling combines element kind, declared or resolved length, scalar
-versus array rank, and ABI byte storage. `String` is the stable semantic family,
-but `numpy.str_` is only a Python-facing representation; fixed native character
-storage may instead use exact byte buffers. Length and encoding constraints
-must therefore survive semantic IR and policy completion.
-
-### Derived Types
-
-Derived-type identity is scoped and semantic. Generated wrappers keep native
-objects opaque and use holders, accessors, and completed lifecycle policy
-instead of mirroring an arbitrary native layout in Python. Field datatypes pass
-through the same semantic and policy stages as ordinary variables.
-
-Arrays of derived types remain unsupported unless the language-support matrix
-states otherwise. A primitive scalar registry entry must never be fabricated
-for a derived identity.
-
-### Pointers And Allocatables
-
-Pointer and allocatable arrays combine an element semantic dtype with descriptor
-kind, association/allocation state, ownership, nullability, and release
-responsibility. Policy completes those decisions before planning. Runtime
-handles expose descriptor-backed operations, while generated code uses the
-planned element dtype for validation and descriptor metadata.
-
-A live zero-copy NumPy view can become stale after native deallocation,
-reallocation, or pointer reassociation. Datatype matching does not solve that
-lifetime boundary; see the [Policy package](../packages/policy.md).
-
-### Callbacks
-
-A callback datatype is a full prototype: argument types, result type, calling
-convention, value/reference storage, rank, and mutability. It is not reducible
-to a scalar function-pointer token. Semantic conversion resolves the prototype,
-policy completes callback handoff and result behavior, and planning freezes the
-native slots used by codegen.
-
-## Policy And Planning Boundaries
-
-Datatype facts answer questions such as “this is a rank-two `Float64` array.”
-They do not answer:
-
-- who owns it;
-- whether it is borrowed, copied, moved, or aliased;
-- whether native mutation is visible or discarded;
-- whether an output is hidden and projected into the Python result;
-- whether storage is stack, heap, or alias;
-- whether destruction or descriptor release is required;
-- whether a getter or setter is exposed.
-
-Those decisions belong to post-IR policy completion. `WrapperPlanner` projects
-the completed facts into typed transfer, result, field, module-variable, and
-lifecycle plans. Backend generators dispatch from those records into named
-mechanisms and must fail if a required datatype lowering is absent.
-
-## Failure Rules
-
-| Failure | Stage that should reject it |
-| --- | --- |
-| Compiler cannot measure a required target fact | probe service |
-| Native declaration is syntactically unsupported | parser |
-| Native fact cannot map to a stable semantic datatype | source-to-IR conversion |
-| Datatype is known but unsafe or unsupported in its use-site context | policy completion |
-| Completed datatype/policy combination has no plan representation | wrapper planner |
-| Planned datatype has no backend mechanism | codegen checked dispatch |
-| Runtime value has the wrong exact dtype, rank, layout, or mutability | generated binding validation |
-
-No stage should silently replace a failed mapping with a nearby width, host
-default, NumPy coercion, or different ownership path.
-
-## Change Workflow And Evidence
-
-When adding or changing a datatype:
-
-1. Add parser coverage for every accepted source spelling and source location.
-2. Add probe coverage when storage or kind depends on the compiler target.
-3. Add or update `SemanticScalarSpec` only for stable semantic vocabulary.
-4. Verify source-to-IR conversion records the resolved dtype and native
- provenance.
-5. Complete use-site behavior in policy and add explicit blockers for
- unsupported combinations.
-6. Extend wrapper-plan records only when existing transfer/result records
- cannot represent the completed behavior.
-7. Add one backend catalogue entry or a specialized lowering mechanism.
-8. Add generated-source assertions and an end-to-end runtime case when emitted
- behavior changes.
-9. Update the semantic datatype reference, feature matrix, and this page when
- support boundaries change.
-
-Primary evidence owners are:
-
-| Concern | Tests |
-| --- | --- |
-| Target measurement | `tests/fortran/data_types/probes/` |
-
-| Semantic scalar catalogue and conversion | `tests/fortran/data_types/semantics/`, semantic conversion tests |
-| Public contract factories | semantic `.pyi` contract tests |
-| Backend scalar catalogue | `tests/fortran/data_types/codegen/` |
-| Generated datatype report | `tests/fortran/data_types/pipeline/test_type_mapping_report.py` |
-| Runtime scalar and array behavior | feature-local end-to-end datatype and array tests |
-
-The report and registry tests should assert readable representative mappings,
-not preserve obsolete public helpers or duplicate every internal dictionary as
-an external API.
diff --git a/docs/developer/deferred/c-parser.md b/docs/developer/deferred/c-parser.md
index eaa4e9169..56a7b907d 100644
--- a/docs/developer/deferred/c-parser.md
+++ b/docs/developer/deferred/c-parser.md
@@ -1186,8 +1186,7 @@ PRIK_C_DOCS_END -->
**Status:** This is a long-term architecture document, not a statement that
-> every backend below exists. The source-driven Fortran-to-Python wrapper is
-> implemented and documented in
-> [the Fortran wrapper reference](../../user/reference/fortran-wrapper.md). C parsing, semantic IR,
-> `.pyi`, and semantic inspection are implemented, but the runtime backend for
-> user-supplied C inputs will be added later. Other language backends and the
-> broader coercion runtime remain design goals.
-PRIK_C_DOCS_END -->
-
-## Vision
-
-The goal of this project is to create a modern interoperability framework capable of wrapping and connecting libraries written in multiple native languages through a unified semantic API layer.
-
-The system should:
-
-* expose clean Python APIs
-* support semantic interoperability between different native runtimes
-* support automatic coercions and conversions
-* support runtime constraints and validation contracts
-* support zero-copy array interoperability when possible
-* avoid compiler dependence whenever possible
-* avoid forcing users to modify native code
-* avoid the limitations of SWIG/f2py-style systems
-* support wrapping libraries even when the source code is unavailable
-
-
-
-The project is not merely a wrapper generator.
-
-It is a:
-
-* semantic wrapper compiler
-* interoperability runtime
-* runtime coercion engine
-* runtime validation engine
-* runtime validation contract system
-* language-independent semantic API system
-
----
-
-## Core Philosophy
-
-The most important architectural decision is:
-
-> The semantic API layer is the source of truth.
-
-NOT:
-
-* parser ASTs
-* compiler internals
-* ABI details
-* native language syntax
-
-The system separates:
-
-| Concern | Responsibility |
-| --- | --- |
-| Semantic API | `.pyi`-style interface layer |
-| Runtime coercions | conversion registry and coercion graph |
-| Runtime validation | constraint checks on adapted values |
-| Validation contracts | reusable preconditions, postconditions, and invariants |
-| Initializer contracts | import-time initialization of native state through extension hooks |
-| Native ABI | backend adapters |
-| Source parsing | optional helper |
-
-This separation is the foundation of the whole architecture.
-
----
-
-## Why Existing Systems Are Not Enough
-
-### SWIG
-
-SWIG is:
-
-* parser-centric
-* macro-heavy
-* difficult to debug
-* weak for scientific arrays
-* poor for runtime semantics
-* poor for modern interoperability
-
-It also becomes difficult to maintain when:
-
-* ownership becomes complex
-* NumPy arrays are involved
-* GPU arrays are involved
-* runtime conversions are needed
-* API remapping becomes advanced
-
-### f2py
-
-f2py is:
-
-* Fortran-specific
-* procedural
-* compiler/build-centric
-* not semantic-runtime oriented
-* weak for object systems
-* weak for heterogeneous runtimes
-
-### pybind11
-
-pybind11 is excellent for:
-
-* clean bindings
-* modern Python APIs
-
-But:
-
-* bindings are handwritten
-* there is no semantic interoperability layer
-* no runtime coercion model
-* no language-independent abstraction
-
----
-
-## High-Level Architecture
-
-The architecture is composed of multiple layers.
-
-
-
-The validation engine enforces concrete checks. Validation contracts describe when those checks run, what they guarantee, and how failures are reported.
-
----
-
-## Canonical Semantic Interface Layer
-
-The `.pyi`-style interface file is the central abstraction.
-
-It defines:
-
-* semantic APIs
-* classes
-* functions
-* methods
-* semantic types
-* allowed coercions
-* constraints
-* validation contracts
-* ownership semantics
-* API remapping
-
-This layer is:
-
-* language-independent
-* parser-independent
-* editable
-* human-readable
-* stable
-
-The native parser is NOT the source of truth.
-
-The `.pyi` interface file is.
-
----
-
-## Example Basic Wrapper
-
-Suppose native Fortran code contains a procedural matrix API:
-
-```fortran
-module sparse_mod
-
- type :: sparse_matrix
- end type
-
-contains
-
- subroutine create_sparse(A, nrows, ncols)
- type(sparse_matrix), intent(out) :: A
- integer, intent(in) :: nrows, ncols
- end subroutine
-
- subroutine sparse_multiply(A, x, y)
- type(sparse_matrix), intent(in) :: A
- real(8), intent(in) :: x(:)
- real(8), intent(out) :: y(:)
- end subroutine
-
-end module
-```
-
-The semantic interface may expose a Pythonic object model:
-
-```python
-from prik.contracts import bind
-
-@bind("sparse_matrix")
-class SparseMatrix:
-
- @bind("create_sparse")
- def __init__(
- self,
- nrows: int[Positive],
- ncols: int[Positive],
- ) -> None: ...
-
- @bind("sparse_multiply")
- @contract(
- pre=lambda c: c.args.x.shape == (c.self.ncols,) and c.args.x.dtype == "float64",
- post=lambda c: c.result.shape == (c.self.nrows,) and c.result.dtype == "float64",
- )
- def multiply(
- self,
- x: Float64Vector[From(np.ndarray), CPUResident],
- ) -> Float64Vector: ...
-```
-
-This allows:
-
-* semantic API redesign
-* Pythonic APIs
-* decoupling native APIs from exposed APIs
-* explicit validation of user-facing expectations
-* reusable runtime checks without changing native source code
-
----
-
-## API Projection
-
-The framework allows transforming procedural APIs into clean object-oriented APIs.
-
-Native:
-
-```fortran
-call sparse_multiply(A, x, y)
-```
-
-Exposed Python API:
-
-```python
-y = A.multiply(x)
-```
-
-This is called:
-
-> semantic API projection.
-
-The projection records how Python-level `self`, arguments, and return values map to native parameters.
-
----
-
-## Semantic Types
-
-Semantic types represent:
-
-> what an object means conceptually.
-
-NOT:
-
-* its memory layout
-* its native language representation
-* its ABI representation
-
-Examples:
-
-* `Float64Matrix`
-* `SparseMatrix`
-* `Tensor3D`
-* `CSRMatrix`
-* `ComplexVector`
-* `DeviceBuffer`
-
-Semantic types are language-independent.
-
----
-
-## Coercions
-
-Coercions define:
-
-> how one type can be adapted into another.
-
-Examples:
-
-* `int -> float`
-* `np.ndarray -> Float64Matrix`
-* `TorchTensor -> Float64Matrix`
-* `CuPyArray -> DeviceBuffer`
-
-Coercions should be explicit in the semantic interface so that the runtime can reject surprising conversions and explain accepted ones.
-
----
-
-## Declaring Coercions
-
-The semantic interface can declare allowed coercions.
-
-Example:
-
-```python
-def scale(alpha: float[From(int)], x: Float64Vector) -> Float64Vector: ...
-```
-
-Meaning:
-
-```text
-int -> float
-```
-
-is an allowed coercion for `alpha`.
-
----
-
-## Matrix Example
-
-```python
-from prik.contracts import ORDER_F
-
-def solve(
- A: Float64Matrix[
- From(np.ndarray),
- ORDER_F,
- Writable,
- "N", "N",
- ],
- b: Float64Vector[
- From(np.ndarray),
- "N",
- ],
-) -> Float64Vector["N"]: ...
-```
-
-This means:
-
-* target semantic type for `A`:
- * `Float64Matrix`
-* allowed coercion for `A`:
- * `np.ndarray -> Float64Matrix`
-* required constraints for `A`:
- * Fortran-contiguous (`ORDER_F`)
- * writable
- * square shape
-* cross-argument contract:
- * `A.shape[0] == A.shape[1] == b.shape[0]`
-
----
-
-## Constraints
-
-Constraints define:
-
-> requirements the final adapted representation must satisfy.
-
-Constraints are NOT coercions.
-
-Examples:
-
-* `Positive`
-* `Writable`
-* `ORDER_F`
-* `CPUResident`
-* shape subscriptions such as `Float64["N", "N"]`
-* `Aligned(64)`
-* `Finite`
-* `NonNull`
-
-
-
-A constraint is usually local to one value: dtype, shape, device, alignment, mutability, ownership, or value range.
-
----
-
-## Runtime Coercion Engine
-
-The runtime coercion engine is responsible for converting accepted Python objects into semantic runtime objects.
-
-Responsibilities:
-
-* find an allowed conversion path from the observed input type to the target semantic type
-* rank competing conversion paths by cost, safety, and zero-copy potential
-* apply conversions in order
-* preserve ownership and lifetime metadata
-* emit a trace that can be shown in diagnostics
-
-Example conversion trace:
-
-
-
----
-
-## Runtime Validation Engine
-
-The runtime validation engine checks that semantic runtime objects satisfy the declared constraints and contract predicates.
-
-Responsibilities:
-
-* validate per-argument constraints after coercion
-* validate cross-argument preconditions before native calls
-* validate return-value postconditions after native calls
-* validate object invariants after mutating methods
-* produce structured errors with the failing parameter, expected condition, observed value, and coercion trace
-
-Example validation error:
-
-
-
-The validation engine is runtime-oriented. It does not replace static typing; it protects the native ABI boundary and provides clear diagnostics for dynamic Python inputs.
-
----
-
-## Runtime Validation Contracts
-
-Runtime validation contracts are reusable groups of validation rules that describe the semantic obligations of an API.
-
-Contracts may include:
-
-* preconditions: requirements before a native call
-* postconditions: guarantees after a native call
-* invariants: requirements that must remain true for an object over its lifetime
-* aliasing rules: whether inputs may overlap in memory
-* mutation rules: which arguments may be modified
-* ownership rules: whether returned objects borrow, own, or view native memory
-
-Example:
-
-```python
-@contract(
- pre=[
- lambda ctx: ctx.args.A.shape == (ctx.args.N, ctx.args.N),
- lambda ctx: ctx.args.b.shape == (ctx.args.N,),
- lambda ctx: ctx.args.A.device == ctx.args.b.device == 'cpu',
- ],
- post=[
- lambda ctx: ctx.result.shape == (ctx.args.N,),
- lambda ctx: ctx.result.dtype == "float64",
- ],
- invariants=[
- lambda ctx: not ctx.result.aliases(ctx.args.A)",
- ],
-)
-def solve(
- A: Float64Matrix[From(np.ndarray), CPUResident],
- b: Float64Vector[From(np.ndarray), CPUResident],
-) -> Float64Vector: ...
-```
-
-Contracts are higher-level than constraints. A constraint can say `b` has shape `N`; a contract can say `A` and `b` agree on the same `N` and that the returned vector does not alias mutable input storage.
-
----
-
-## Runtime Initializer Contracts
-
-Runtime initializer contracts describe how mutable native state is initialized when a generated extension module is imported.
-
-They are separate from constants. A `Final[...]` declaration records an immutable API value, while an initializer contract writes a value into mutable native storage through the completed setter policy.
-
-The implemented minimal slice is literal defaults on mutable module variables:
-
-```python
-from prik.contracts import Int32
-
-counter: Int32 = 41
-```
-
-That form can be lowered to a typed value and assigned through the generated extension setter after the native module is initialized.
-
-The longer-term contract is more general. An initializer expression may be executable Python:
-
-```python
-from prik.contracts import Float64, Int32
-
-from .init_hooks import initial_counter, runtime_scale
-
-counter: Int32 = initial_counter(seed=41)
-scale: Float64 = 1.0 + runtime_scale()
-```
-
-Executable initializer contracts should run at the generated extension level, not by translating Python expressions into equivalent native bridge code. The extension can import Python modules, call Python hook functions, call generated Python wrappers if needed, convert the final result to the declared semantic type, and assign it through the generated setter for the native variable.
-
-Initializer contracts complement validation contracts:
-
-* initializers run during extension import
-* preconditions run before a wrapped function call
-* postconditions run after a wrapped function call
-* invariants may be checked after initialization and after later mutations
-
-Import-time initializer pipeline:
-
-```text
-Create extension module
- ↓
-Install generated functions and properties
- ↓
-Import requested Python hook modules
- ↓
-Evaluate initializer expressions
- ↓
-Convert initializer results to semantic types
- ↓
-Assign through generated native setters
- ↓
-Expose initialized module
-```
-
-Because executable initializers are user Python, their side effects, environment dependencies, import cycles, and exceptions belong to the user contract. If an initializer raises, extension import should fail with a diagnostic attached to the semantic declaration being initialized.
-
----
-
-## Important Concept Separation
-
-The architecture separates:
-
-| Concept | Meaning |
-| --- | --- |
-| Semantic type | what the object is |
-| Coercion | how another type becomes it |
-| Constraint | local requirements on an adapted value |
-| Validation contract | API-level preconditions, postconditions, invariants, and aliasing rules |
-| Initializer contract | import-time native-state initialization through generated setters |
-| Backend adapter | semantic object → ABI representation |
-
-This separation is fundamental.
-
----
-
-## Runtime Coercion Registry
-
-Allowed coercions declared in `.pyi` are implemented through a runtime coercion registry in the equivalent `.py` file.
-
-Example:
-
-```python
-@coercion(np.ndarray, Float64Matrix, implicit=True, cost=1, zero_copy="if_compatible")
-def ndarray_to_matrix(A: np.ndarray) -> Float64MatrixObject:
- return Float64MatrixObject.from_numpy(A)
-```
-
-This registers:
-
-```text
-np.ndarray -> Float64Matrix
-```
-
-inside the runtime registry.
-
----
-
-## Runtime Contract Registry
-
-Validation contracts can also be registered and reused by name.
-
-Example:
-
-```python
-@validation_contract
-def square_linear_system(ctx):
- A = ctx.arg("A")
- b = ctx.arg("b")
- result = ctx.result
-
- ctx.require(A.ndim == 2, "A must be a matrix")
- ctx.require(A.shape[0] == A.shape[1], "A must be square")
- ctx.require(b.shape == (A.shape[0],), "b must match A rows")
- ctx.ensure(result.shape == b.shape, "solution shape must match b")
-```
-
-The interface can then reference the contract:
-
-```python
-@contract(square_linear_system)
-def solve(A: Float64Matrix, b: Float64Vector) -> Float64Vector: ...
-```
-
-
-
----
-
-## Runtime Dispatch Flow
-
-Suppose:
-
-```python
-x = solve(np.ones((10, 10)), np.ones(10))
-```
-
-Runtime pipeline:
-
-```text
-Input objects
- ↓
-Find semantic target types
- ↓
-Find coercion paths
- ↓
-Apply coercions
- ↓
-Validate argument constraints
- ↓
-Validate contract preconditions
- ↓
-Backend adapters
- ↓
-Native ABI call
- ↓
-Validate contract postconditions and invariants
- ↓
-Return Python object
-```
-
----
-
-## Coercion Graphs
-
-The runtime should support composed coercions.
-
-Example:
-
-```text
-TorchTensor
- ↓
-np.ndarray
- ↓
-Float64Matrix
-```
-
-The runtime can automatically infer:
-
-```text
-TorchTensor -> Float64Matrix
-```
-
-through graph traversal when the path is declared safe and allowed for the target API.
-
----
-
-## Coercion Metadata
-
-Coercions may contain metadata.
-
-Example:
-
-```python
-@coercion(
- np.ndarray,
- Float64Matrix,
- implicit=True,
- cost=1,
- zero_copy=True,
- preserves_aliasing=True,
-)
-def ndarray_to_matrix(A):
- ...
-```
-
-Possible metadata:
-
-* implicit/explicit
-* safe/unsafe
-* cost
-* zero-copy
-* ownership
-* device awareness
-* aliasing behavior
-* mutability preservation
-
----
-
-## Semantic Runtime Objects
-
-The runtime should internally use semantic runtime objects.
-
-Example:
-
-```python
-class Float64MatrixObject:
- ptr: int
- shape: tuple[int, int]
- strides: tuple[int, int]
- owner: object | None
- device: str
- writable: bool
- aliases: set[int]
-```
-
-These objects are:
-
-* language-independent
-* runtime-oriented
-* semantic representations
-
-NOT:
-
-* NumPy arrays
-* Fortran descriptors
-* Eigen matrices
-
----
-
-## Backend Adapters
-
-Backend adapters convert:
-
-```text
-Semantic runtime object
- ↓
-Native ABI representation
-```
-
-Examples:
-
-* Fortran descriptors
-* Eigen maps
-* CUDA tensors
-
-
-
-Adapters should receive values only after coercion and validation have completed. This keeps ABI code focused on call mechanics instead of user-input cleanup.
-
----
-
-## Wrapping Libraries Without Source Code
-
-The framework should support wrapping:
-
-* `.so`
-* `.dll`
-* static libraries
-
-without source code.
-
-Users provide:
-
-* semantic `.pyi`
-* coercions if needed
-* validation contracts if needed
-* optional metadata
-
-No source parsing required.
-
----
-
-## Optional Parser Frontends
-
-Parsers are helpers.
-
-NOT the foundation.
-
-Possible parsers:
-
-* Fortran parser
-* Rust parser
-
-
-
-Their role:
-
-* generate starter `.pyi`
-* synchronize declarations
-* help users bootstrap wrappers
-
-The semantic interface remains canonical.
-
----
-
-## Mixed-Language Libraries
-
-The framework should support libraries implemented in multiple languages simultaneously.
-
-Example:
-
-* Fortran numerical kernels
-* Rust runtime safety
-* CUDA kernels
-
-
-
-All unified through:
-
-* semantic types
-* coercions
-* constraints
-* validation contracts
-* backend adapters
-
----
-
-## Example Mixed-Language Workflow
-
-Suppose:
-
-### Fortran solver
-
-```fortran
-subroutine solve_system(A, b, x)
-```
-
-
-
-
-
-### Rust optimizer
-
-
-
-The semantic API may expose:
-
-```python
-from prik.contracts import ORDER_F
-
-class Solver:
- @contract(pre=square_linear_system)
- def solve(
- self,
- A: Float64Matrix[From(np.ndarray), ORDER_F],
- b: Float64Vector[From(np.ndarray)],
- ) -> Float64Vector: ...
-
-class Mesh:
- @contract(post=[lambda ctx:ctx.self.is_valid()])
- def refine(self) -> None: ...
-
-def optimize(
- x: Float64Vector[From(np.ndarray), Writable, CPUResident],
-) -> OptimizationResult: ...
-```
-
-The user does not care about implementation language. The semantic layer records type meaning, conversion policy, validation policy, and backend dispatch.
-
----
-
-## Ownership and Lifetime Management
-
-The runtime must manage:
-
-* borrowed references
-* owned references
-* zero-copy views
-* temporary coercions
-* destruction policies
-* aliasing constraints
-* mutation contracts
-
-This is one of the hardest parts of the system.
-
----
-
-## Zero-Copy Interoperability
-
-The runtime should avoid unnecessary copies whenever possible.
-
-Examples:
-
-| Conversion | Strategy |
-| --- | --- |
-| NumPy F-order → Fortran | zero-copy |
-| NumPy → Eigen::Map | zero-copy when dtype, alignment, and strides match |
-| Torch CUDA → CPU array | copy, unless API accepts GPU memory |
-| CuPy array → CUDA kernel | zero-copy when stream and device contracts match |
-
-
-
-The runtime should optimize coercion paths automatically while still honoring explicit API contracts.
-
----
-
-## Scientific Computing Focus
-
-The architecture is especially useful for:
-
-* HPC
-* FEM
-* CFD
-* climate models
-* tensor runtimes
-* numerical libraries
-* GPU computing
-* scientific Python ecosystems
-
-because these domains already contain:
-
-* mixed-language systems
-* difficult interoperability
-* array-heavy APIs
-* strict shape, device, ownership, and aliasing requirements
-
-
-
----
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-## Diagnostics
-
-Diagnostics are extremely important.
-
-The framework should provide:
-
-* clear coercion errors
-* constraint validation errors
-* contract validation errors
-* coercion trace visualization
-* ownership diagnostics
-* backend dispatch diagnostics
-
-Example diagnostic:
-
-```text
-ContractError in Solver.solve(A, b)
- contract: square_linear_system
- failed: b.shape == (A.shape[0],)
- observed:
- A.shape = (10, 10)
- b.shape = (8,)
- coercion trace:
- A: np.ndarray -> Float64Matrix [zero-copy]
- b: np.ndarray -> Float64Vector [zero-copy]
-```
-
-This should be much better than typical SWIG/f2py errors.
-
----
-
-## Plugin Ecosystem
-
-Third-party ecosystems should be able to register:
-
-* semantic types
-* coercions
-* constraints
-* validation contracts
-* backend adapters
-
-This allows:
-
-* NumPy support
-* Torch support
-* JAX support
-* CUDA support
-* sparse matrix ecosystems
-* domain-specific runtimes
-
----
-
-## Roadmap
-
-### Phase 1: Semantic API and IR
-
-* Define the `.pyi`-style semantic grammar.
-* Represent semantic types, argument mappings, ownership rules, constraints, and validation contracts in the IR.
-* Generate a minimal Python-facing wrapper skeleton from the IR.
-
-### Phase 2: Runtime Coercion Engine
-
-* Implement the coercion registry.
-* Support direct coercions, composed coercion paths, cost ranking, and zero-copy metadata.
-* Add structured coercion traces for diagnostics.
-
-### Phase 3: Runtime Validation Engine
-
-* Implement local constraint validation for shape, dtype, contiguity, device, mutability, ownership, and alignment.
-* Attach validation failures to source parameters and semantic declarations.
-* Run validation after coercion and before backend adaptation.
-
-### Phase 4: Runtime Contracts
-
-* Add reusable contract declarations for preconditions, postconditions, invariants, aliasing, mutation, and ownership.
-* Add initializer contracts for import-time native-state setup through generated extension setters.
-* Support named contract registration and inline contracts in the semantic interface.
-* Validate cross-argument relationships such as matching dimensions, shared devices, non-overlapping buffers, and stable object invariants.
-* Include contract traces in diagnostics.
-
-### Phase 5: Backend Adapters
-
-* Add CUDA/device-memory adapters once device contracts are available.
-
-
-
-### Phase 6: Parser Frontends and Ecosystem Plugins
-
-* Add optional parser frontends that generate starter semantic interfaces.
-* Add plugin APIs for NumPy, Torch, JAX, CUDA, and sparse matrix ecosystems.
-* Keep parser output editable and subordinate to the canonical semantic interface.
-
----
-
-## Long-Term Goal
-
-The final system becomes:
-
-* a semantic wrapper compiler
-* a runtime interoperability framework
-* a mixed-language scientific runtime layer
-* a semantic coercion engine
-* a runtime validation engine
-* a runtime validation contract system
-* an extension-level initializer contract system
-* a modern replacement for old wrapper systems
-
-The key innovation is:
-
-```text
-Semantic interoperability
-instead of
-parser-centric wrapper generation
-```
-
----
-
-## Final Summary
-
-The architecture is built around:
-
-```text
-Semantic API
- ↓
-Contract layer
- ├─ Initializer contracts at extension import
- └─ Validation contracts around wrapped calls
- ↓
-Coercions
- ↓
-Constraints
- ↓
-Semantic runtime objects
- ↓
-Backend adapters
- ↓
-Native execution
-```
-
-The project focuses on:
-
-* clean semantic APIs
-* runtime interoperability
-* mixed-language support
-* runtime coercion
-* runtime validation
-* runtime validation contracts
-* extension-level initializer contracts
-* scientific computing
-* extensibility
-* high performance
-* language independence
-
-while avoiding:
-
-* parser dependence
-* compiler dependence
-* rigid ABI-centric designs
-* old wrapper system limitations.
diff --git a/docs/developer/design/wrapper-open-decisions.md b/docs/developer/design/wrapper-open-decisions.md
deleted file mode 100644
index 14a476cbc..000000000
--- a/docs/developer/design/wrapper-open-decisions.md
+++ /dev/null
@@ -1,542 +0,0 @@
----
-title: Wrapper Open Decisions
-audience: developers, maintainers, contributors
-prerequisites: Fortran wrapper reference, semantic IR reference
-related: ../architecture.md, ../packages/policy.md, ../packages/planning.md, multilanguage-runtime.md
-status: design
-publication: draft
----
-
-# Wrapper Open Decisions
-
-
-
-Reference details live in:
-
-- `docs/developer/packages/parsers.md`
-- `docs/user/reference/fortran-wrapper.md`
-- `docs/user/reference/semantic-ir.md`
-
-
-
-## Known Semantic Gaps To Track
-
-These are source-language concepts that the parser or semantic layer can often
-see today, but that still need a stronger `.pyi`, semantic, or wrapper policy
-before generated wrappers should treat them as supported behavior.
-
-
-
-
-
-### Fortran Gaps
-
-| Gap | Current risk | Proposed direction |
-| --- | --- | --- |
-| Procedure pointers and dummy procedures | A broad `Procedure` type loses enough signature and lifetime information that wrappers cannot safely call or receive callbacks. | Resolve abstract interface signatures into a first-class semantic callable form. Preserve procedure pointer, optional, pass-through, and callback lifetime facts; block wrapper generation until call direction and ownership policy are explicit. |
-| Pointer and allocatable ownership | Allocatable and pointer arrays use explicit descriptor handles. Module and derived-field handles borrow their native owner; owned allocatable results retain persistent wrapper-owned descriptor storage. An unallocated or unassociated descriptor remains a present handle whose `to_numpy()` result is `None`; otherwise `to_numpy()` returns a current live view and callers use `.copy()` explicitly for independent storage. Allocatable `intent(inout)` descriptor arguments accept handles and project the same caller handle, while ordinary arrays and ordinary array results keep NumPy data-buffer semantics. Rank-zero derived module allocatables/pointers use nullable live member proxies. Wrapper-owned allocatable and pointer derived results use persistent typed holders. Module allocatable dummies use reversible `move_alloc` holder transactions; module pointer dummies use typed association transactions and exact restoration. C transports opaque holder addresses and typed operation pointers, never descriptors. A pointer holder owns its association container, not an unknown native target. | Complete descriptor kind, handle/storage kind, actual declaration, dummy form, owner retention, live extraction or member mechanism, mutation/writeback, release, transaction cleanup, and operation permissions in post-IR policy before lowering. Route module, field, argument, and result generation through named policy dispatch. Keep contiguous-view, descriptor-view, scoped-reference, module-transaction, and typed-holder mechanisms distinct; never fall back from incomplete policy to a copy, fabricated address, or compiler-private descriptor. |
-| Assumed-rank, assumed-type, and optional descriptor-heavy arguments | Descriptors such as `dimension(..)` and `type(*)` can accept many native shapes that Python cannot infer safely. | Represent descriptor category, rank constraints, element type availability, optional presence, and contiguity. Generate wrappers only for explicit accepted rank/dtype policies or through backend shims that validate descriptors. |
-| Generic interfaces and operators | Named generics, defined operators, named operators, and defined assignment now preserve explicit concrete-target links. Python cannot intercept `=`, arbitrary named operators, or infer safe in-place mutation. Static extension-type inheritance is represented in Python, and scalar polymorphic input dispatch reuses the same generated overload selection path. | Use Python data-model slots for intrinsic operators, `operator_name`/`r_operator_name` methods for named operators, and mutating `assign` methods for defined assignment. Keep exact dtype/rank/extension-class dispatch and reject indistinguishable signatures during generation. |
-| Coarrays, teams, events, and directive-driven device/offload behavior | These introduce parallel runtime or device-memory semantics outside normal host wrappers. | Treat as out of the initial wrapper scope. Preserve diagnostics where detected and require a separate runtime design before claiming support. |
-
-
-
-## Settled Scope
-
-
-
-
-
-
-
-Verbose wrapper builds should print the exact compiler command lines they run,
-not only the source or target being compiled. The printed command should be
-shell-quoted so users can copy it to reproduce object compilation, generated
-wrapper compilation (including its header-only native binding support), and
-final shared-library linking.
-
-
-
-Raw macro-generated declarations are not a separate parser target. If a macro
-creates a declaration, that declaration should be visible after preprocessing:
-
-
-
-After preprocessing, the parser should see the expanded declaration and does not
-need to understand `DECLARE_SCALE` itself.
-
-
-
-## Wrapper Decisions To Revisit
-
-### ABI Boundary
-
-We already collect wrapper-relevant declaration facts. The open wrapper-phase
-question is how much exact ABI behavior the generated wrapper must model itself
-versus delegate to a compiled shim or backend compiler.
-
-Example:
-
-
-
-
-
-### Pointer Ownership And Lifetime
-
-The wrapper must not infer ownership silently. A pointer can mean borrowed
-storage, owned allocation, mutable in-place data, read-only data, optional data,
-or a sentinel-terminated buffer. The user must provide the missing policy in the
-wrapper contract.
-
-Example:
-
-
-
-These signatures alone do not prove who owns the memory, how long it lives, or
-whether Python should copy, borrow, mutate, or free it. The wrapper design
-should make that explicit in `.pyi` or another policy layer.
-
-### Pointer, Size, And Output Projections
-
-
-
-Example:
-
-
-
-The exact native contract is `out`, `capacity`, and `written`. A wrapper could
-project this to `list[float]` or `np.ndarray`, but only after the user says how
-large the output should be, who allocates it, how errors are handled, and whether
-the result is copied or shared.
-
-### Callback Policy
-
-Callback wrappers need more than the function pointer type. The wrapper must
-know whether the native library stores the callback, which Python object keeps it
-alive, whether callbacks may happen on native threads, how exceptions propagate,
-how `void *ctx` pairs with the callback, and how registration/unregistration
-works.
-
-Example:
-
-
-
-The parser can record the callback signature. The wrapper phase must decide the
-lifetime, context pairing, threading, exception, and unregistration behavior
-before generating a Python API.
-
-### Fortran Allocatable And Pointer Reassociation
-
-Fortran allocatable and pointer dummy arguments can replace the storage visible
-to the caller. The parser and semantic IR should preserve allocatable/pointer
-facts, but wrapper generation must decide Python replacement and lifetime
-behavior.
-
-Example:
-
-```fortran
-subroutine build_grid(x, n)
- integer, intent(in) :: n
- real, allocatable, intent(out) :: x(:)
-end subroutine
-```
-
-The Fortran procedure may allocate or reallocate `x`. For allocatable array
-dummy arguments, prik uses copy-return ownership: the bridge copies allocated
-native storage into NumPy-owned memory, deallocates the temporary Fortran
-allocation, and returns the new Python object. `None` represents an unallocated
-dummy.
-
-Array transfer policy is based on the native storage category and owner, not on
-whether an array appears as a top-level result, module variable, or derived-type
-field:
-
-- Allocatable dummy arguments and function results are temporary replacement
- values at the Python boundary. They use copy-return storage and become
- Python-owned NumPy arrays or `None`.
-- Allocatable derived-type fields are owned by the containing native instance.
- A field getter returns `None` or a borrowed NumPy view whose base keeps the
- containing Python wrapper alive.
-- Target-backed allocatable module arrays are owned by the Fortran module for
- the process lifetime. Explicit getters may return `None` or borrowed NumPy
- views.
-- Pointer arrays do not have intrinsic ownership. A pointer target may be a
- callee allocation, a module variable, a derived-type field, a dummy argument,
- a section, or external state. Therefore pointer array results, module
- variables, and derived-type fields must not become borrowed views or
- detached-copy values unless an explicit policy identifies the target owner,
- lifetime, deallocation rules, association replacement behavior, aliasing,
- mutability, shape, and contiguity.
-
-The current safe policy behavior for exposed pointer fields and module
-variables is a conservative descriptor-handle profile: association inspection
-and `nullify()` are distinct from target ownership, and allocation,
-deallocation, and resize remain opt-in. Pointer-array descriptor arguments need
-generated handle handoff before they can be accepted, and pointer-array results
-need stable owner storage, target lifetime, descriptor extraction, and destroy
-behavior before they can return handles. Until generated handle accessors exist,
-wrapper planning must stop generation instead of returning a view, leaking a
-callee allocation, double-freeing a borrowed target, or inventing ownership.
-
-This means a returned derived-type wrapper owns the native instance itself, but
-does not automatically own targets reachable through pointer components. Putting
-a pointer array inside an `intent(out)` derived type does not change the pointer
-array policy: the object may be returned, but the pointer component remains
-unavailable until explicit descriptor extraction, target lifetime, and release
-policy exists.
-
-
-
-
-
-Pointer reassociation has similar policy questions:
-
-```fortran
-subroutine attach_view(x)
- real, pointer, intent(out) :: x(:)
-end subroutine
-```
-
-The wrapper must define whether `x` becomes a borrowed view, an owned Python
-object, or a blocked interface unless the user supplies more policy. Until
-that policy exists, Fortran pointer `intent(out)` and `intent(inout)` dummy
-arguments should remain blocked by default. A final associated pointer does not
-prove whether the target was allocated for this return, borrowed from module
-storage, borrowed from a derived-type field, associated with another dummy
-argument, or kept alive elsewhere by native code.
-
-The narrow current contract for procedure pointer arrays is:
-
-- Pointer-array descriptor arguments are represented in semantic policy but
- block wrapper lowering until generated handle handoff is implemented.
-- Pointer array function results block wrapper lowering until stable owner
- storage, target lifetime, descriptor extraction, and generated destroy
- behavior are implemented.
-- Pointer `intent(out)` and `intent(inout)` dummy arguments require explicit
- policy metadata before they can be projected to Python returns or mutable
- Python-visible arguments.
-- Module pointer variables and derived-type pointer fields use the default
- conservative handle policy. Generated accessors remain blocked until
- descriptor-handle code generation is implemented; ownership-changing
- operations still require explicit policy.
-
-Scalar pointer `intent(in)` dummies use a call-local wrapper temporary. The
-generated bridge associates the native pointer with that temporary only for the
-call, so Python never receives a native address and does not observe writes or
-reassociation. Scalar pointer function results use copied-value projection: the
-bridge copies an associated value into wrapper-owned temporary storage and
-returns an ordinary Python scalar, while an unassociated result returns `None`.
-
-Future `.pyi` pointer policy should make each missing fact explicit:
-
-| Policy fact | Why the wrapper needs it |
-| --- | --- |
-| Nullability | Defines whether an unassociated pointer is valid and whether Python should receive `None` or raise an error. |
-| Transfer mode | Distinguishes detached copy, borrowed NumPy view, native-owned capsule, Python-owned input storage, and blocked exact-native pointer passing. |
-| Target owner | Identifies who owns the storage: a Python argument, a containing wrapper instance, a module variable, a callee allocation, an external library, or unknown native state. |
-| Lifetime | States how long a borrowed target remains valid: call only, owner object lifetime, module lifetime, explicit release, or unknown. |
-| Deallocation policy | Says whether the wrapper must never deallocate, should deallocate after copying, should attach a destructor capsule, or must call a named native release routine. This is the main missing fact for pointer outputs. |
-| Shape source | Provides extents for array pointers, such as explicit `.pyi` dimensions, companion size arguments, descriptor bounds, or source pointer bounds. |
-| Contiguity and strides | Decides whether only contiguous targets are supported, whether strided sections may become NumPy views, or whether non-contiguous targets must be copied or rejected. |
-| Reassociation behavior | Defines what happens when Fortran points the dummy somewhere else: ignore the original Python input, return the final association as a detached copy, write back association state, invalidate old views, or block. |
-| Aliasing | States whether two returned pointers may share one target and whether Python must preserve that identity or may return independent copies. |
-| Mutability | Declares whether Python may write through a borrowed view and whether native code may write while Python holds it. |
-
-These facts are policy, not parser facts. The parser and semantic IR should
-preserve the native pointer, target, rank, bounds, intent, and contiguity
-information they can observe, but wrapper planning should keep reporting a
-blocker when the user-supplied policy is not strong enough for the requested
-Python behavior.
-
-Semantic `.pyi` expresses these facts in one keyword-only annotation:
-
-```python
-from prik.contracts import Annotated, Float64, Pointer, PointerPolicy
-
-value: Annotated[
- Pointer[Float64[:]],
- PointerPolicy(
- nullable=True,
- transfer="snapshot_copy",
- target_owner="module",
- lifetime="module",
- deallocation="never",
- shape_source="pointer_bounds",
- contiguity="contiguous",
- reassociation="snapshot_final",
- aliasing="independent_copy",
- mutability="copy",
- ),
-]
-```
-
-All ten keys round-trip through semantic IR. Metadata is descriptive policy,
-not permission to bypass backend safety checks. In particular,
-`transfer="borrowed_view"` remains blocked until the generated Python object
-can retain the native owner and stale views can be invalidated after
-reassociation or reallocation.
-
-### Fortran Assumed-Rank Wrappers
-
-
-
-Example:
-
-```fortran
-subroutine inspect(x)
- real, intent(in) :: x(..)
-end subroutine
-```
-
-The generated wrapper exposes one Python entrypoint for `inspect(x)`. Passing a
-rank-3 `float64` Fortran-contiguous array selects the bridge case for rank 3 and
-the native routine still receives the original assumed-rank dummy through a
-rank-3 pointer view. Procedures with more than one assumed-rank argument use
-nested bridge dispatch so each argument is viewed at its own runtime rank.
-
-This support is intentionally limited to typed numeric arrays. Assumed-type
-`type(*)` and unlimited polymorphic `class(*)` arguments remain blocked because
-the wrapper cannot infer the element dtype, layout, or descriptor contract from
-the source declaration alone; that information must come from a later `.pyi`
-policy.
-
-### Fortran Numeric Array Wrapper Subset
-
-The settled numeric array subset uses validation and copy rules instead of
-implicit conversion:
-
-- Pointer array function results remain blocked until returned-handle owner
- storage, target lifetime, descriptor extraction, and destroy behavior are
- implemented.
-- Multidimensional Fortran results and arguments preserve Fortran order.
-- The maximum supported wrapper rank is 15. Higher ranks are rejected before
- wrapper generation. Numeric assumed-rank `dimension(..)` dummy arguments use
- generated Fortran rank dispatch for actual NumPy array ranks 1 through 15.
- Rank 0 scalars are not accepted by the automatic assumed-rank policy.
-- Python supplies full storage for assumed-size dummy arguments. The wrapper
- validates the declared extents it can express from literals, constants, and
- scalar argument names. The omitted final extent remains the caller's
- responsibility.
-- `intent(in)` arrays may be read-only. `intent(out)` and `intent(inout)` arrays
- must be writeable.
-- NumPy inputs must be native-endian and aligned. The wrapper does not perform
- unsafe casts, byte swaps, or alignment-fixing copies.
-- Overlapping Python-visible arrays are not copied or de-aliased by prik; the
- call is forwarded to Fortran, so the native routine's aliasing contract still
- governs behavior.
-
-
-
-Assumed-type `type(*)`, character arrays, and derived-type arrays remain
-blocked until explicit dtype, descriptor, ABI, layout, construction, and
-ownership policies are supplied.
diff --git a/docs/developer/feature-to-code-map.md b/docs/developer/feature-to-code-map.md
index dc77c092e..ddbc534b4 100644
--- a/docs/developer/feature-to-code-map.md
+++ b/docs/developer/feature-to-code-map.md
@@ -1,73 +1,45 @@
---
-title: Feature To Code Map
+title: Feature-to-Code Map
audience: developers, contributors
-prerequisites: source map, testing strategy
-related: source-map.md, ../user/language-support/feature-matrix.md
+prerequisites: PRIK Architecture, Codebase Map
+related: architecture.md, codebase-map.md, packages/index.md, testing-strategy.md
status: maintained
-publication: draft
+publication: reviewed
---
-# Feature To Code Map
-
-Use this page when starting from a user-visible feature. The table points to
-the public docs, implementation files, focused tests, and evidence required
-before documentation may call the behavior supported.
-
-## Feature Map
-
-| Feature or behavior | Public docs | Main implementation files | Focused tests | Support evidence |
-| --- | --- | --- | --- | --- |
-| Fortran parse output | `docs/developer/packages/parsers.md` | `prik/parsers/fortran/parser.py`, `models.py`, `lexer.py`, `type_resolver.py` | `tests/fortran/source_parsing/parsing/`, `tests/fortran/source_parsing/parsing/test_fortran_fixture_suite.py` | Parser facts and diagnostics match fixtures |
-| CLI stage selection and output | `docs/user/getting-started/beginner-workflow.md`, `docs/user/reference/cli-commands.md` | `prik/cli.py`, `prik/parsers/fortran/cli.py` | `tests/fortran/command_line_interface/pipeline/`, Fortran parser CLI tests, documentation example tests | Command output and diagnostics match checked expectations |
-| Compiler preprocessing | `docs/user/examples/recipes/compiler-preprocessing.md`, `docs/developer/packages/preprocessing.md`, `docs/developer/packages/parsers.md` | `prik/preprocessing/source.py`, `prik/preprocessing/fortran.py` | `tests/fortran/source_preprocessing/preprocessing/`, `tests/fortran/source_preprocessing/preprocessing/test_parser_boundaries.py` | Prepared Fortran input, dependencies, and source mappings are stable |
-| Semantic `.pyi` generation | `docs/user/reference/semantic-pyi-format.md` | `prik/printers/pyi.py` | `tests/fortran/semantic_pyi_format/pipeline/`, `tests/fortran/semantic_pyi_format/pipeline/test_modern_example.py` | Printed `.pyi` round-trips or matches fixtures |
-| Semantic `.pyi` conversion and editing | `docs/user/reference/pyi-contracts/index.md`, `docs/user/reference/semantic-pyi-format.md`, `docs/user/examples/recipes/semantic-pyi-contracts.md` | `prik/parsers/pyi/parser.py`, `prik/pipeline/pyi.py`, `prik/semantics/pyi2ir.py`, `models.py` | `tests/fortran/semantic_pyi_format/` | Edited contracts parse to Python AST, then become semantic IR with preserved native facts |
-| Semantic and wrapper-planning errors | `docs/user/guide/error-handling.md`, `docs/user/reference/diagnostic-codes.md` | `prik/semantics/fortran2ir.py`, `prik/policy/completion.py`, `prik/planning/planner.py` | `tests/fortran/infrastructure/semantics/`, feature-local `policy/`, and feature-local `codegen/` tests | Each owning stage rejects unsupported or incomplete contracts |
-| Fortran wrapper orchestration | `docs/user/reference/fortran-wrapper.md`, `docs/user/guide/building-shared-library.md` | `prik/pipeline/build.py` | `tests/fortran/building_shared_library/end_to_end/test_source_build_modes.py`, multi-source wrapper tests | Builds report artifacts and compile/link as documented |
-| Completed semantic policy to generated wrapper | `docs/user/reference/fortran-wrapper.md` | `prik/policy/completion.py`, `prik/planning/models.py`, `prik/planning/planner.py`, `prik/codegen/docstrings.py`, `prik/pipeline/wrapper.py` | `tests/fortran/infrastructure/semantics/`, `tests/fortran/infrastructure/codegen/`, and feature-local policy/codegen tests | Runtime policy is explicit, the typed plan is complete, and the generated wrapper compiles and runs |
-| Native compilation and binding support | `docs/user/reference/fortran-wrapper.md`, `docs/user/guide/building-shared-library.md`, `docs/developer/packages/compiler.md`, `docs/developer/workflows/quality-assurance.md` | `prik/compiler/`, `prik/runtime/native_support/` | `tests/fortran/building_shared_library/end_to_end/test_runtime_compatibility.py`, build-mode tests | Generated sources compile, link, import, and clean up correctly |
-| Source documentation structure | `docs/developer/source-map.md` | `docs/`, package README files, `tests/docs/test_reference_and_source_map.py` | documentation metadata, navigation, source-map, and example tests | Pages have metadata, audience separation, and source coverage checks |
-| Semantic IR | `docs/user/reference/semantic-ir.md` | `prik/semantics/models.py`, `fortran2ir.py`, `pyi2ir.py` | `tests/fortran/semantic_ir/semantics/`, `tests/fortran/semantic_pyi_format/semantics/` | Fortran or semantic `.pyi` facts lower without losing wrapper-relevant meaning |
-| Generated Fortran bridge | `docs/user/reference/fortran-wrapper.md` | `prik/codegen/fortran/bridge.py`, `prik/printers/fortran.py`, `prik/pipeline/wrapper.py` | `tests/fortran/infrastructure/codegen/`, feature-local codegen and end-to-end tests | Generated bridge compiles and preserves the native calling contract |
-| Generated CPython binding | `docs/user/reference/fortran-wrapper.md` | `prik/codegen/c/binding.py`, `prik/codegen/c/python_surface.py`, `prik/printers/c.py`, `prik/pipeline/wrapper.py` | `tests/fortran/infrastructure/codegen/`, feature-local codegen and end-to-end tests | Extension imports, validates Python inputs, dispatches overloads in C, and installs the derived-class Python facade |
-| Public API exports | `README.md`, `docs/user/reference/python-api.md` | `prik/__init__.py` | `tests/fortran/source_parsing/parsing/test_public_entrypoints.py` | Import paths are intentional and documented |
-
-
-
-## First-File Rule
-
-For a feature change, start with the implementation file named in the feature
-map and read only the downstream files that the change actually crosses. For
-example, a CLI output change normally starts and ends in `prik/cli.py`, while a
-wrapper output-projection change must move through semantic policy completion,
-the typed wrapper planner, and the selected bridge and binding implementation
-methods.
-
-When the user-visible behavior changes, update the public docs in the same row
-before or alongside the implementation. The documentation structure test keeps
-this routing page tied to the source hotspots and package README files.
-
-## Workflow Feature Pointers
-
-| User workflow | Start in code | Do not mark supported until |
-| --- | --- | --- |
-| Wrapping functions and subroutines | `prik/semantics/fortran2ir.py`, policy completion, `prik/planning/planner.py`, bridge and binding generators | Runtime tests compile, import, call, and verify return and failure behavior |
-| Wrapping modules and module variables | parser module facts, semantic module conversion, naming policy, wrapper generators | Python-visible names, accessors, and unsupported module constructs are tested |
-| Arrays and allocatables | semantic array contracts, ownership policy, typed wrapper plans, bridge/binding array handlers | dtype, shape, rank, contiguity, mutation, returned arrays, and failure paths are tested; ordinary NumPy array actuals validate and extract their buffer directly in the C binding, descriptor handles use the planned runtime-handle path, and strided contracts carry a dense-actual role for zero-copy fast-path selection |
-| Pointer arguments | semantic metadata, ownership policy, bridge/binding pointer handlers | Owner, lifetime, association, and blocked cases are explicit and tested |
-| Optional arguments | parser optional attributes, semantic arguments, binding argument parsing | Present/absent calls and unsupported combinations are tested |
-| Generic interfaces | parser interface facts, semantic overload sets, `FunctionOverloadSet`, binding dispatch | Overload selection and ambiguity failures are tested at runtime |
-| Enumerations | parser enum facts, semantic constants/classes, codegen projection | Python-visible values and unsupported enum forms are tested |
-| Derived types | semantic classes, ownership policy, bridge class handling, CPython class binding | Lifetime, construction, field access, finalization, and invalid calls are tested |
-| Callbacks | completed callback policy, `CallbackHandoffPlan`, direct Fortran adapter lowering, direct CPython trampoline lowering | Callback ABI/copy direction is validated before emission; lifetime, same-thread re-entry, exception abort, and call-scoped cleanup are compiled and tested |
-| Error handling | stage diagnostics, generated cleanup paths, CPython exception state | Failure path tests prove diagnostics or Python exceptions |
-| Packaging and distribution | `prik/pipeline/build.py`, `prik/compiler/`, future packaging integration | Build artifacts, native dependencies, and platform constraints are documented and tested |
-
-## Evidence Rule
-
-A feature can appear in user workflow docs only after the implementation,
-focused tests, and runtime evidence match the public claim. Parser or semantic
-support alone is not enough for runtime wrapper support.
+# Feature-to-Code Map
+
+This map connects a user-visible capability to its primary source owners,
+documentation, and focused evidence. It is a change-routing index, not a
+second support matrix: [Architecture](architecture.md) defines the stage
+handoffs, the [Codebase Map](codebase-map.md) lists package ownership, and the
+public feature matrix states the support boundary and limitations.
+
+## Feature Routes
+
+Links in the documentation column are reviewed pages.
+
+Find the capability, read its documentation, start with the leftmost owner,
+and run its focused evidence. Use the [Architecture](architecture.md) when the
+change crosses a stage boundary.
+
+| Capability | Relevant documentation | Change route | Focused evidence |
+| --- | --- | --- | --- |
+| Fortran inspection and semantic IR | [Parsers](packages/parsers.md) | `prik/parsers/fortran/parser.py` → `prik/semantics/fortran2ir.py` → `prik/semantics/models.py` | `tests/fortran/source_parsing/parsing/`, `tests/fortran/semantic_ir/semantics/` |
+| CLI commands and reports | [Beginner workflow](../user/getting-started/beginner-workflow.md) | `prik/cli.py` → `prik/parsers/fortran/cli.py` | `tests/fortran/command_line_interface/pipeline/`, `tests/docs/test_examples.py` |
+| Source preparation and target types | [Preprocessing](packages/preprocessing.md) | `prik/preprocessing/source.py` → `prik/preprocessing/fortran.py` → `prik/preprocessing/probes/fortran_types.py` → `prik/semantics/scalar_types.py` → `prik/codegen/primitive_scalar_types.py` | `tests/fortran/source_preprocessing/preprocessing/`, `tests/fortran/data_types/` |
+| Semantic `.pyi` generation and editing | [.pyi contracts](../user/reference/pyi-contracts/index.md) | `prik/parsers/pyi/parser.py` → `prik/semantics/pyi2ir.py` → `prik/pipeline/pyi.py` → `prik/printers/pyi.py` | `tests/fortran/semantic_pyi_format/parsing/`, `tests/fortran/semantic_pyi_format/semantics/`, `tests/fortran/semantic_pyi_format/pipeline/` |
+| Source-first extension builds | [Building the shared library](../user/guide/building-shared-library.md) | `prik/pipeline/build.py` → `prik/pipeline/wrapper.py` → `prik/compiler/compilers.py` | `tests/fortran/building_shared_library/end_to_end/test_source_build_modes.py`, `tests/fortran/building_shared_library/end_to_end/test_multi_source_builds.py` |
+| Contract-first extension builds | [.pyi contracts](../user/reference/pyi-contracts/index.md) | `prik/pipeline/build.py` → `prik/pipeline/pyi.py` → `prik/semantics/pyi2ir.py` | `tests/fortran/semantic_pyi_format/end_to_end/test_authoritative_contract_runtime.py`, `tests/fortran/pyi_contracts/exports_and_modules/` |
+| Calls, results, and optional arguments | [Functions](../user/guide/wrapping-functions.md), [subroutines](../user/guide/wrapping-subroutines.md) | `prik/semantics/fortran2ir.py` → `prik/policy/completion.py` → `prik/planning/planner.py` → `prik/codegen/c/binding.py` and `prik/codegen/fortran/bridge.py` | `tests/fortran/functions/`, `tests/fortran/optional_arguments/`, `tests/fortran/pyi_contracts/calls_and_results/` |
+| Arrays | [Arrays](../user/guide/arrays.md) | `prik/semantics/fortran2ir.py` → `prik/policy/completion.py` → `prik/planning/planner.py` → `prik/codegen/c/binding.py` and `prik/codegen/fortran/bridge.py` | `tests/fortran/arrays/` |
+| Modules, interfaces, constants, and exported names | [Modules](../user/guide/wrapping-modules.md), [interfaces](../user/guide/generic-interfaces.md), [enumerations](../user/guide/enumerations.md) | `prik/parsers/fortran/parser.py` → `prik/semantics/fortran2ir.py` → `prik/policy/exports.py` → `prik/naming/policy.py` | `tests/fortran/modules/`, `tests/fortran/generic_interfaces/`, `tests/fortran/pyi_contracts/exports_and_modules/` |
+| Derived objects, allocatables, pointers, and lifetimes | [Derived types](../user/guide/wrapping-derived-types.md), [allocatables](../user/guide/allocatables.md), [pointers](../user/guide/pointers.md), [memory management](../user/guide/memory-management.md) | `prik/policy/ownership.py` → `prik/policy/construction.py` → `prik/policy/native_array_handles.py` → `prik/planning/planner.py` → `prik/runtime/handles.py` | `tests/fortran/derived_types/`, `tests/fortran/allocatables/`, `tests/fortran/pointers/` |
+| Callbacks | [Callbacks](../user/guide/callbacks.md) | `prik/policy/models.py` → `prik/policy/completion.py` → `prik/planning/planner.py` → `prik/codegen/c/binding.py` and `prik/codegen/fortran/bridge.py` | `tests/fortran/callbacks/` |
+| Projected errors | [Error handling](../user/guide/error-handling.md) | `prik/policy/models.py` → `prik/policy/completion.py` → `prik/planning/planner.py` → `prik/codegen/c/binding.py` and `prik/codegen/fortran/bridge.py` | `tests/fortran/error_handling/` |
+| Native compilation, extension runtime, and public build API | [Compiler](packages/compiler.md), [Quality Assurance](workflows/quality-assurance.md) | `prik/__init__.py` → `prik/pipeline/build.py` → `prik/compiler/objects.py` → `prik/compiler/compilers.py` → `prik/compiler/native_support.py` → `prik/runtime/native_support/` | `tests/fortran/building_shared_library/end_to_end/test_runtime_compatibility.py`, `tests/fortran/source_parsing/parsing/test_public_entrypoints.py` |
+
+Each change route begins with the first owner for a capability; it is not a
+complete call graph. When a change crosses a representation boundary, the
+[Architecture](architecture.md) identifies the next stage and the relevant
+[architecture component guide](packages/index.md) gives its local route.
diff --git a/docs/developer/index.md b/docs/developer/index.md
index a5e94c27b..ca15b1993 100644
--- a/docs/developer/index.md
+++ b/docs/developer/index.md
@@ -1,56 +1,48 @@
---
-title: Contributor Documentation
+title: Developer Documentation
audience: developers, maintainers, contributors
prerequisites: repository checkout
related: architecture.md, packages/index.md, workflows/contributing.md
status: maintained
-publication: draft
+publication: reviewed
---
-# Contributor Documentation
+# Developer Documentation
-This is the single documentation area for changing, testing, governing, and
-releasing PRIK. Start with the architecture guide, then open the detailed
-package, workflow, concept, design, or active-roadmap page needed for the task.
+PRIK turns source or semantic `.pyi` contracts into importable CPython
+extensions through a staged build pipeline. These documents explain that
+architecture, the components that implement it, and how to locate change and
+test ownership.
-## Orientation
+## Read these first
-- [Contributor architecture](architecture.md): shallow repository/package
- structure, complete workflow, authority rules, CLI/root files, and package
- routes.
-- [Source package guides](packages/index.md): one detailed page per production
- package, with local structure, important objects, runnable examples, tests,
- change routes, and invariants.
-- [Source map](source-map.md): exact file and hotspot lookup.
-- [Feature-to-code map](feature-to-code-map.md): user-visible capability to
- source, tests, and documentation.
-- [Testing strategy](testing-strategy.md): language/feature/stage ownership and
- verification selection.
+When you are new to PRIK, read these pages in order:
-## Cross-Cutting Concepts
+1. [PRIK Architecture](architecture.md) — build flow, stage handoffs, and the
+ boundary at which each decision becomes fixed.
+2. [Architecture Components](packages/index.md) — each build stage and supporting
+ component: local modules, entrypoints, examples, and focused tests.
-- [Datatype lifecycle](concepts/datatype-lifecycle.md): compiler measurement,
- semantic identity, policy, backend representation, and runtime validation.
+## Get set up
-## Contributor Workflows
+Install an editable checkout with development tools:
-- [Contributing](workflows/contributing.md)
-- [Quality assurance](workflows/quality-assurance.md)
-- [Continuous integration and delivery](workflows/ci.md)
-- [Documentation architecture](workflows/documentation.md)
-- [Release process](workflows/release.md)
+```bash
+python3 -m pip install -e ".[qa]"
+```
-## Design And Planning
+For the short public checklist (branch, tests, changelog, license), see the
+repository-root `CONTRIBUTING.md`. The full contributor path is in
+[Contributing workflow](workflows/contributing.md).
-- [Multilanguage runtime architecture](design/multilanguage-runtime.md) is an
- explicit long-term design, not a support claim.
-- [Wrapper open decisions](design/wrapper-open-decisions.md) records unresolved
- or revisitable design questions.
-- [Active roadmaps](roadmap/index.md) contain incomplete work only.
+## For a specific change
-## Deferred Input-Language Material
-
-The C parser/C-to-IR reference is retained under `deferred/` and excluded from
-the published Fortran contributor workflow until that input path is mature.
-This does not hide the generated CPython C binding backend used by Fortran
-wrappers.
+| Need | Doc |
+| --- | --- |
+| Locate packages, modules, and hotspots | [Codebase Map](codebase-map.md) |
+| Connect a capability to code and evidence | [Feature-to-Code Map](feature-to-code-map.md) |
+| Choose where tests live and what they prove | [Testing Strategy](testing-strategy.md) |
+| Contribute, verify locally, and open a PR | [Contributing workflow](workflows/contributing.md) |
+| Static analysis and broader verification | [Quality Assurance](workflows/quality-assurance.md) |
+| Hosted PR checks | [Pull request checks](workflows/ci.md) |
+| Maintain docs and executable examples | [Documentation maintenance](workflows/documentation.md) |
diff --git a/docs/developer/packages/codegen.md b/docs/developer/packages/codegen.md
index 0a8832b87..57f171af8 100644
--- a/docs/developer/packages/codegen.md
+++ b/docs/developer/packages/codegen.md
@@ -1,13 +1,13 @@
---
-title: Code Generation Package
+title: Code Generation Stage
audience: developers, maintainers, contributors
prerequisites: contributor architecture guide, completed wrapper plan
related: ../architecture.md, index.md, planning.md, printers.md, pipeline.md
status: maintained
-publication: draft
+publication: reviewed
---
-# Code Generation Package
+# Code Generation Stage
## Purpose And Boundaries
@@ -29,20 +29,19 @@ prik/codegen/
├── checks.py
├── visitor.py
├── c/
-│ ├── __init__.py
│ ├── binding.py
│ ├── python_surface.py
│ └── naming.py
└── fortran/
- ├── __init__.py
└── bridge.py
```
## What This Stage Receives And Produces
```text
-validated ModulePlan
+editable ModulePlan
-> plan-driven public docstrings
+ -> WrapperGenerator freezes and validates the handoff
-> CBindingGenerator + PythonSurfaceEmitter
-> FortranBridgeGenerator
-> typed C/Fortran nodes and Python facade text
@@ -60,21 +59,81 @@ validated ModulePlan
| [`prik/codegen/overloads.py`](../../../prik/codegen/overloads.py) | `OverloadPlanQueries` answers structural questions about completed overload plans. | Shared overload-plan inspection is needed without re-deciding overload policy. |
| [`prik/codegen/checks.py`](../../../prik/codegen/checks.py) | Shared code-generation validation and complexity-check support. | A codegen invariant or its repository gate changes. |
| [`prik/codegen/visitor.py`](../../../prik/codegen/visitor.py) | `ClassVisitor` and `UnsupportedWrapperCodegenNodeError` provide backend-node dispatch and explicit unsupported-node failure. | Generic codegen visitor behavior changes. |
-| [`prik/codegen/c/__init__.py`](../../../prik/codegen/c/__init__.py) | Boundary for C/CPython binding mechanics. | Establishing a deliberate C-backend import API. |
-| [`prik/codegen/c/binding.py`](../../../prik/codegen/c/binding.py) | `CBindingGenerator` lowers completed binding-plan views into CPython/NumPy C nodes. | A plan-selected Python boundary, lifecycle, error, or module mechanism changes. |
+| [`prik/codegen/c/binding.py`](../../../prik/codegen/c/binding.py) | `CBindingGenerator` lowers completed binding-plan views into CPython/NumPy C nodes. See [C Binding Lowering](codegen/c-binding.md). | A plan-selected Python boundary, lifecycle, error, or module mechanism changes. |
| [`prik/codegen/c/naming.py`](../../../prik/codegen/c/naming.py) | Binding-local generated names that should not become global naming policy. | A C-binding private symbol convention changes. |
| [`prik/codegen/c/python_surface.py`](../../../prik/codegen/c/python_surface.py) | `PythonSurfaceContext` and `PythonSurfaceEmitter` produce planned classes, holders, and module proxies embedded in the extension. | Generated Python facade behavior changes. |
-| [`prik/codegen/fortran/__init__.py`](../../../prik/codegen/fortran/__init__.py) | Boundary for Fortran bridge mechanics. | Establishing a deliberate bridge-backend import API. |
-| [`prik/codegen/fortran/bridge.py`](../../../prik/codegen/fortran/bridge.py) | `FortranBridgeGenerator` lowers bridge-plan views into `bind(C)` modules, accessors, descriptors, and native calls. | A plan-selected ABI declaration, conversion, call slot, or native bridge mechanism changes. |
+| [`prik/codegen/fortran/bridge.py`](../../../prik/codegen/fortran/bridge.py) | `FortranBridgeGenerator` lowers bridge-plan views into Fortran modules with `bind(C)` entrypoints, accessors, descriptors, and native calls. See [Fortran Bridge Lowering](codegen/fortran-bridge.md). | A plan-selected ABI declaration, conversion, call slot, or native bridge mechanism changes. |
Specialized emitter methods remain local because each makes the selected
mechanism auditable. Shared code must never reconstruct policy from datatype,
source `intent`, dotted shape, aliases, or local memory checks.
-## Execution Examples
+## Module Algorithms
+
+### Generation handoff: document, freeze, validate, lower
+
+The canonical route begins in `pipeline/wrapper.py`, at
+`WrapperGenerator.generate()`. It fills plan-derived docstrings while the
+`ModulePlan` remains editable, freezes that exact graph, validates its
+cross-backend consistency, and asks the specialized lowerers to preflight their
+selected primitive mechanisms before producing nodes for `printers/`.
+
+`codegen/` owns the presentation and lowering work in that sequence. It does
+not own plan freezing, policy completion, source-file writing, or compilation.
+
+### `nodes.py`, `visitor.py`, and scalar spelling
+
+`nodes.py` defines the editable C and Fortran syntax vocabulary passed to
+printers: modules, includes and declarations, functions and procedures,
+control flow, calls, assignments, interfaces, types, and raw leaf
+expressions. A node adds a representable language construct; it does not
+choose whether the construct is safe or required.
+
+`ClassVisitor` dispatches a node to the nearest `_visit_` method.
+Missing handlers raise `UnsupportedWrapperCodegenNodeError`, which makes an
+unimplemented lowering case explicit rather than silently emitting a nearby
+form.
+
+`PrimitiveScalarTypeRegistry.type_for()` and
+`NumpyDtypeRegistry.expression_for()` provide C, Fortran, NumPy, CPython, and
+descriptor spellings for already-resolved semantic scalars. Registry lookups
+fail for unknown names, and scalar lookup returns a fresh editable node.
+
+### `docstrings.py` and `overloads.py`: plan readers
+
+`WrapperDocstringBuilder.render()` fills only unset documentation fields on a
+plan. It renders child callables and fields before their class and namespace
+summaries, while preserving an explicitly supplied string, including `""`.
+It presents completed signatures, shapes, optionality, results, and errors; it
+does not derive new wrapper behavior.
+
+`OverloadPlanQueries` exposes the structural facts already fixed in an
+`OverloadPlan`, such as the visible passed-object receiver. It is shared
+inspection, not overload matching or dispatch policy.
+
+### Specialized lowerings
+
+The C binding and Fortran bridge lower separate, completed views of the same
+plan. Their algorithms, source-printing examples, and failure boundaries are
+described in [C Binding Lowering](codegen/c-binding.md) and [Fortran Bridge
+Lowering](codegen/fortran-bridge.md). Neither page assigns policy completion to
+code generation.
+
+### `checks.py`: maintainability recommendations
+
+`check_codegen_package()` and `check_codegen_paths()` inspect generator,
+printer, and wrapper-orchestration Python for focused methods, explicit
+visitor dispatch, registries, and forbidden printer calls. The command reports
+maintainability recommendations for review; behavior, ABI, and safety tests
+remain the enforcing evidence.
+
+## Run The Workflows
Typed nodes before printing:
+`nodes.py` constructs one minimal C module and one minimal Fortran module,
+each with a single typed body node. It does not call a printer.
+
```bash
python3 prik/codegen/nodes.py
```
@@ -85,8 +144,14 @@ Fortran node tree: FortranModule -> bind_c_ping -> FortranCall
Source text rendered: False
```
+The two paths name node classes rather than source text, confirming that this
+layer has formed a language representation but has not yet formatted it.
+
Primitive backend representations:
+`primitive_scalar_types.py` looks up `Float64` twice and asks the scalar and
+NumPy catalogues for its selected spellings.
+
```bash
python3 prik/codegen/primitive_scalar_types.py
```
@@ -97,8 +162,15 @@ NumPy C macro: NPY_FLOAT64
Fresh editable node per lookup: True
```
+The first two lines connect one semantic identity to C, Fortran, NumPy, and
+NumPy-C spellings. `True` confirms that callers receive fresh editable nodes
+instead of sharing mutable syntax objects.
+
Plan-driven docstrings:
+`docstrings.py` constructs one scalar semantic function, completes policy,
+projects its plan, and fills the function's unset binding docstring.
+
```bash
python3 prik/codegen/docstrings.py
```
@@ -120,8 +192,14 @@ TypeError
If an argument has an incompatible Python type or dtype.
```
+The signature, sections, and `TypeError` all come from completed plan facts;
+the formatter does not infer a new calling rule.
+
The Python facade:
+`python_surface.py` constructs a planned opaque `State` class with an absent
+constructor and emits its small embedded Python facade.
+
```bash
python3 prik/codegen/c/python_surface.py
```
@@ -141,58 +219,20 @@ def _prik_wrap_State(capsule, owner=None, ops=None, origin='direct'):
...
```
-The binding and bridge files also have direct examples:
-
-```bash
-python3 prik/codegen/c/binding.py
-```
-
-The complete output is 22 lines. These exact selected lines identify the plan
-and the native call inside the generated binding node tree:
+The slots, rejected constructor, and wrapper helper are generated from that
+class plan. They show the planned Python surface without selecting its native
+lifecycle policy.
-```text
-Native procedure: DOUBLE_VALUE
-Native call slots: implicit:value
-C module: binding_demo_wrapper
-Header guard: BINDING_DEMO_WRAPPER_H
-Header prototypes: wrap_double_value
-Binding wrapper: wrap_double_value
-...
- CExpressionStatement(expression=CodeExpression(text='result = bind_c_double_value(bound_value)'))
-...
- CReturn(expression=CodeExpression(text='result_obj'))
-```
+## Tests And Evidence
-```bash
-python3 prik/codegen/fortran/bridge.py
-```
-
-The complete output is 17 lines. Its exact selected lines show the matching
-slot and bridge call:
-
-```text
-Native procedure: DOUBLE_VALUE
-Native call slots: implicit:value
-Bridge module: bind_c_bridge_demo_wrapper
-...
-Bridge procedure: bind_c_double_value
-Binding name: bind_c_double_value
-Procedure kind: function
-Result: result :: real(c_double)
-...
- FortranAssignment(target='result', expression=CodeExpression(text='native_double_value(value)'))
-Internal procedures: (none)
-```
-
-Together the outputs demonstrate that both backends lower one shared plan
-without asking the other backend to decide policy.
-
-## Tests And What They Prove
-
-- [Codegen infrastructure](../../../tests/fortran/infrastructure/codegen/) covers nodes, generators, planning handoffs, and validation.
-- [Feature-local codegen suites](../../../tests/fortran/) cover emitted mechanisms for each supported feature.
-- [Direct execution inventory](../../../tests/fortran/infrastructure/execution_examples/test_execution_examples.py) fixes every direct module demonstration on this page.
-- `python3 tools/check_codegen_complexity.py` protects the generator-complexity policy.
+| Evidence | What it establishes |
+| --- | --- |
+| [Codegen infrastructure](../../../tests/fortran/infrastructure/codegen/test_binding.py) | C binding nodes, module assembly, source-independent lowering, and selected validation paths. |
+| [Plan handoff and generated wrappers](../../../tests/fortran/infrastructure/pipeline/test_wrapper_generator.py) | Docstring rendering, plan freezing, cross-backend validation, node generation, and rendered-wrapper assembly. |
+| [Primitive scalar lowering](../../../tests/fortran/data_types/codegen/test_primitive_scalar_type_catalogue.py) | Scalar spelling catalogue and exact C, Fortran, NumPy, and result representation selection. |
+| [Array lowering](../../../tests/fortran/arrays/codegen/test_array_buffer_lowering.py) | Planned buffer handoff and emitted binding/bridge operations. |
+| [Derived-type lowering](../../../tests/fortran/derived_types/codegen/test_derived_lowering.py) | Plan-selected native object, lifecycle, and bridge/binding mechanisms. |
+| [Codegen review command](../../../tests/tools/test_check_codegen_complexity_cli.py) | The maintainability recommendation command and its command-line behavior. |
## Change Routes
@@ -204,7 +244,7 @@ without asking the other backend to decide policy.
- If the change requires choosing ownership, storage, projection, setter
exposure, or support, stop and add the missing upstream policy/plan fact.
-## Invariants And Common Mistakes
+## Boundaries And Invariants
- Generators dispatch from completed plan actions; no datatype/intent fallback
may silently choose behavior.
@@ -226,3 +266,13 @@ A new datatype should extend completed policy and one transfer/result shape,
then add one named validator and one named lowering method per affected
backend. It should not create a parallel module/function plan hierarchy or add
datatype branching to generic traversal.
+
+## Failure Boundary
+
+This stage reports an unsupported completed plan action, missing visitor
+handler, unavailable backend spelling, inconsistent frozen plan, or unplanned
+backend mechanism. It delegates ownership, lifetime, public projection, and
+support decisions to `policy/` and `planning/`; it delegates source formatting
+to `printers/` and build execution to `pipeline/` and `compiler/`. Start with
+the first invalid plan record or unsupported lowering action, not the rendered
+source or compiler error that follows.
diff --git a/docs/developer/packages/codegen/c-binding.md b/docs/developer/packages/codegen/c-binding.md
new file mode 100644
index 000000000..51af48ee4
--- /dev/null
+++ b/docs/developer/packages/codegen/c-binding.md
@@ -0,0 +1,231 @@
+---
+title: C Binding Lowering
+audience: developers, maintainers, contributors
+prerequisites: Code Generation Stage guide, completed wrapper plan
+related: ../../architecture.md, ../codegen.md, ../planning.md, ../printers.md, fortran-bridge.md
+status: maintained
+publication: reviewed
+---
+
+# C Binding Lowering
+
+## Role And Boundary
+
+[`prik/codegen/c/binding.py`](../../../../prik/codegen/c/binding.py) lowers the
+binding view of a completed `ModulePlan` into a `CModule` and `CHeader`. The
+result is CPython and NumPy C syntax nodes, not source text and not a compiled
+extension. `CSourcePrinter` serializes the nodes later.
+
+The generator implements the Python boundary selected by the plan: argument
+conversion, bridge calls, Python results, errors, lifecycle actions, extension
+initialization, and generated Python surfaces. It may select local names and
+the necessary C syntax, but never chooses ownership, optionality, storage, or
+conversion policy.
+
+## Input And Output
+
+```text
+ModulePlan.binding + namespaces + function binding views
+ -> CBindingGenerator.require_supported()
+ -> CBindingGenerator.visit()
+ -> CModule + CHeader
+ -> CSourcePrinter
+ -> C binding source + header text
+```
+
+`require_supported()` checks that the already selected primitive spellings are
+available. It is capability preflight, not a second policy pass.
+
+## Lowering Algorithm
+
+`_visit_ModulePlan()` returns the paired C module and header. `binding_module()`
+collects namespace functions, determines whether the plan requires runtime
+helpers, and assembles declarations and functions in emitted dependency order:
+shared helpers, class and descriptor support, wrappers, overload dispatchers,
+then module initialization. `binding_header()` derives bridge prototypes from
+the same plan.
+
+`_visit_FunctionPlan()` works in three ordered parts:
+
+1. It creates one local-name context and puts declarations before executable
+ statements.
+2. It applies the plan's `argument_conversion_order`; each transfer dispatches
+ on its completed optional, callback, descriptor, or derived facet.
+3. It emits the bridge call, selected result construction, and lifecycle work.
+
+`PythonSurfaceEmitter` is used only when the plan contains generated classes,
+holders, or module proxies. `CBindingNames` keeps its private C symbols aligned
+with the binding helpers. Public names still come from the plan.
+
+## Run A Minimal Manual Plan
+
+This is the smallest complete plan: a public Python `ping()` that calls the
+standalone native `PING` subroutine. Its empty transfer, result, slot, and
+lifecycle tuples are intentional—there are no datatype or ownership decisions
+for code generation to infer.
+
+In a normal build, `WrapperPlanner` constructs the plan after policy completion
+and `WrapperGenerator` freezes and validates it before lowering. Construct a
+plan directly only to study an isolated backend mechanism like this one.
+
+### Plan Shape
+
+This abbreviated, non-runnable sketch shows the records in construction order.
+Expand the full source to run the complete example.
+
+```python
+binding = BindingFunctionPlan(...)
+bridge = BridgeFunctionPlan(...)
+function = FunctionPlan(..., binding=binding, bridge=bridge)
+namespace = NamespacePlan(..., functions=(function,))
+plan = ModulePlan(
+ binding=BindingModulePlan(...),
+ bridge=BridgeModulePlan(...),
+ namespaces=(namespace,),
+)
+
+generator = CBindingGenerator()
+c_module, _header = generator.visit(plan)
+print(CSourcePrinter().doprint(...))
+```
+
+
+Full runnable source
+
+
+```python
+from prik.codegen.c.binding import CBindingGenerator
+from prik.planning.models import (
+ BindingFunctionPlan, BindingModulePlan, BridgeFunctionPlan,
+ BridgeModulePlan, FunctionPlan, ModulePlan, NamespacePlan,
+)
+from prik.policy.models import ExternalDeclarationMode, NativeInvocationKind
+from prik.printers.c import CSourcePrinter
+
+binding = BindingFunctionPlan(
+ python_name="ping",
+ docstring="Call PING.",
+ release_gil=False,
+ status_error=None,
+ argument_conversion_order=(),
+)
+bridge = BridgeFunctionPlan(
+ native_name="PING",
+ native_invocation=NativeInvocationKind.PROCEDURE,
+ native_operator=None,
+ standalone=True,
+ external_declaration=ExternalDeclarationMode.IMPLICIT_EXTERNAL,
+ native_module=None,
+ native_is_subroutine=True,
+)
+function = FunctionPlan(
+ owner_path="demo.ping",
+ symbol_name="ping",
+ binding=binding,
+ bridge=bridge,
+ class_call=None,
+ arguments=(),
+ results=(),
+ native_call_slots=(),
+ declaration_callables=(),
+ available_roles=(),
+)
+namespace = NamespacePlan(
+ owner_path="demo",
+ python_path=(),
+ functions=(function,),
+ docstring="Manual codegen demonstration.",
+)
+plan = ModulePlan(
+ owner_path="demo",
+ binding=BindingModulePlan(owner_path="demo"),
+ bridge=BridgeModulePlan(owner_path="demo"),
+ namespaces=(namespace,),
+)
+
+generator = CBindingGenerator()
+generator.require_supported(plan)
+c_module, _header = generator.visit(plan)
+wrapper = next(item for item in c_module.functions if item.name == "wrap_ping")
+print(CSourcePrinter().doprint(wrapper))
+```
+
+```text
+static PyObject * wrap_ping(PyObject * self, PyObject * args, PyObject * kwargs) {
+ static char * kwlist[] = {NULL};
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist)) return NULL;
+ bind_c_ping();
+ Py_RETURN_NONE;
+}
+```
+
+
+
+The plan's public name produces `wrap_ping`; its bridge record produces
+`bind_c_ping`. The C generator adds CPython parsing and result mechanics, but
+the selected plan remains the reason that call is permitted and named that way.
+
+## Run The Module Demonstration
+
+`binding.py` also contains a direct demonstration of its normal input route.
+It constructs one scalar semantic function, completes policy, builds its plan,
+preflights C scalar support, lowers the binding nodes, and prints the header
+and wrapper through `CSourcePrinter`. Expand **Example source** on the
+published site to see that exact `__main__` setup.
+
+```bash
+python3 prik/codegen/c/binding.py
+```
+
+```text
+Rendered C header:
+#ifndef BINDING_DEMO_WRAPPER_H
+#define BINDING_DEMO_WRAPPER_H
+#include
+static PyObject * wrap_double_value(PyObject * self, PyObject * args, PyObject * kwargs);
+#endif /* BINDING_DEMO_WRAPPER_H */
+
+Rendered C binding wrapper:
+static PyObject * wrap_double_value(PyObject * self, PyObject * args, PyObject * kwargs) {
+ static char * kwlist[] = {"value", NULL};
+ PyObject * bound_value_obj;
+ double bound_value;
+ double result;
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &bound_value_obj)) return NULL;
+ if (prik_float64_unpack_exact(bound_value_obj, &bound_value) < 0) { if (!PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, "Expected an argument of type numpy.float64 for argument value. Received ", Py_TYPE(bound_value_obj)->tp_name); } return NULL; };
+ result = bind_c_double_value(bound_value);
+ PyObject * result_obj = prik_float64_to_numpy(&result);
+ if (result_obj == NULL) {
+ return NULL;
+ }
+ return result_obj;
+}
+```
+
+The header exposes the bridge wrapper prototype. The wrapper's rendered body
+shows the Python-to-bridge call and conversion back to a NumPy scalar result.
+
+## Change Routes And Evidence
+
+- Change CPython extraction, Python results, C errors, or binding-side
+ lifecycle emission in `binding.py`.
+- Change generated class, holder, or proxy Python source in
+ [`python_surface.py`](../../../../prik/codegen/c/python_surface.py).
+- Change cross-backend names used only by C helpers in
+ [`naming.py`](../../../../prik/codegen/c/naming.py).
+- If the change needs a new ownership, transfer, or projection decision, stop
+ at `policy/` or `planning/`; do not add a binding-local fallback.
+
+| Evidence | What it establishes |
+| --- | --- |
+| [Binding infrastructure](../../../../tests/fortran/infrastructure/codegen/test_binding.py) | Invalid NumPy scalar macros fail at the C binding helper boundary. |
+| [Wrapper-generator handoff](../../../../tests/fortran/infrastructure/pipeline/test_wrapper_generator.py) | Frozen-plan validation and generated C binding, header, and wrapper assembly. |
+| [Array lowering](../../../../tests/fortran/arrays/codegen/test_specialized_array_roles.py) | Plan-selected specialized array roles lower through the binding boundary. |
+
+## Failure Boundary
+
+The C backend reports an unsupported completed action, unavailable scalar
+spelling, invalid plan reference, or missing node visitor. It delegates missing
+semantic decisions to `policy/` and `planning/`, source formatting to
+`printers/`, and compilation to `compiler/`. Start with the first invalid plan
+record, not with the generated C compiler diagnostic.
diff --git a/docs/developer/packages/codegen/fortran-bridge.md b/docs/developer/packages/codegen/fortran-bridge.md
new file mode 100644
index 000000000..499476a93
--- /dev/null
+++ b/docs/developer/packages/codegen/fortran-bridge.md
@@ -0,0 +1,239 @@
+---
+title: Fortran Bridge Lowering
+audience: developers, maintainers, contributors
+prerequisites: Code Generation Stage guide, completed wrapper plan
+related: ../../architecture.md, ../codegen.md, ../planning.md, ../printers.md, c-binding.md
+status: maintained
+publication: reviewed
+---
+
+# Fortran Bridge Lowering
+
+## Role And Boundary
+
+[`prik/codegen/fortran/bridge.py`](../../../../prik/codegen/fortran/bridge.py)
+lowers the bridge view of a completed `ModulePlan` into a `FortranModule`. The
+result is a typed Fortran syntax tree, not formatted source or a compiled
+library. `FortranSourcePrinter` serializes it later.
+
+The bridge implements the ABI selected by the plan: `bind(C)` procedures,
+native imports and interfaces, declarations, representation conversion,
+ordered native calls, writeback, cleanup, and derived-value lifecycles. It
+does not infer a native interface, argument optionality, ownership, or result
+projection from source-language details.
+
+## Input And Output
+
+```text
+ModulePlan.bridge + namespaces + function bridge views
+ -> FortranBridgeGenerator.require_supported()
+ -> FortranBridgeGenerator.visit()
+ -> FortranModule
+ -> FortranSourcePrinter
+ -> Fortran bridge source
+```
+
+`require_supported()` verifies only that selected primitive representations can
+be emitted. It does not validate or complete the cross-backend plan; the normal
+`WrapperGenerator` handoff does that before it calls this backend.
+
+## Lowering Algorithm
+
+`_visit_ModulePlan()` collects the `iso_c_binding` symbols, required native
+module uses, interfaces, holder definitions, and procedures for every
+namespace. It adds derived and callback support only when plan facts require
+them.
+
+`_visit_FunctionPlan()` preserves the plan's execution order:
+
+1. It determines the bridge result form and orders ABI parameters by their
+ recorded position.
+2. It emits declarations and representation initializers, then forms the
+ native invocation from the ordered call slots.
+3. It runs the selected writeback and cleanup finalizers, wrapping derived
+ result or carrier lifecycles when the plan requires them.
+
+The bridge result exposes a `bind(C)` name for the C binding. For a standalone
+native procedure, the bridge record explicitly selects its external declaration;
+for a module procedure, it supplies the native module use. Those are completed
+plan facts, not heuristics in the generator.
+
+## Run A Minimal Manual Plan
+
+This is the same complete no-argument `PING` plan used by the C binding deep
+dive. With no transfers, results, slots, or lifecycle actions, it is small
+enough to construct explicitly while still containing both mandatory module
+views and a complete bridge record.
+
+Real builds must obtain plans from `WrapperPlanner` after policy completion and
+must pass through `WrapperGenerator` for freezing and cross-backend validation.
+Use direct construction only to inspect a backend lowering path.
+
+### Plan Shape
+
+This abbreviated, non-runnable sketch shows the records in construction order.
+Expand the full source to run the complete example.
+
+```python
+binding = BindingFunctionPlan(...)
+bridge = BridgeFunctionPlan(...)
+function = FunctionPlan(..., binding=binding, bridge=bridge)
+namespace = NamespacePlan(..., functions=(function,))
+plan = ModulePlan(
+ binding=BindingModulePlan(...),
+ bridge=BridgeModulePlan(...),
+ namespaces=(namespace,),
+)
+
+generator = FortranBridgeGenerator()
+bridge_module = generator.visit(plan)
+print(FortranSourcePrinter().doprint(...))
+```
+
+
+Full runnable source
+
+
+```python
+from prik.codegen.fortran.bridge import FortranBridgeGenerator
+from prik.planning.models import (
+ BindingFunctionPlan, BindingModulePlan, BridgeFunctionPlan,
+ BridgeModulePlan, FunctionPlan, ModulePlan, NamespacePlan,
+)
+from prik.policy.models import ExternalDeclarationMode, NativeInvocationKind
+from prik.printers.fortran import FortranSourcePrinter
+
+binding = BindingFunctionPlan(
+ python_name="ping",
+ docstring="Call PING.",
+ release_gil=False,
+ status_error=None,
+ argument_conversion_order=(),
+)
+bridge = BridgeFunctionPlan(
+ native_name="PING",
+ native_invocation=NativeInvocationKind.PROCEDURE,
+ native_operator=None,
+ standalone=True,
+ external_declaration=ExternalDeclarationMode.IMPLICIT_EXTERNAL,
+ native_module=None,
+ native_is_subroutine=True,
+)
+function = FunctionPlan(
+ owner_path="demo.ping",
+ symbol_name="ping",
+ binding=binding,
+ bridge=bridge,
+ class_call=None,
+ arguments=(),
+ results=(),
+ native_call_slots=(),
+ declaration_callables=(),
+ available_roles=(),
+)
+namespace = NamespacePlan(
+ owner_path="demo",
+ python_path=(),
+ functions=(function,),
+ docstring="Manual codegen demonstration.",
+)
+plan = ModulePlan(
+ owner_path="demo",
+ binding=BindingModulePlan(owner_path="demo"),
+ bridge=BridgeModulePlan(owner_path="demo"),
+ namespaces=(namespace,),
+)
+
+generator = FortranBridgeGenerator()
+generator.require_supported(plan)
+bridge_module = generator.visit(plan)
+print(FortranSourcePrinter().doprint(bridge_module.procedures[0]))
+```
+
+```text
+subroutine bind_c_ping() bind(c, name="bind_c_ping")
+ external :: PING
+ call PING()
+end subroutine bind_c_ping
+```
+
+
+
+The bridge record fixes the public C-ABI name and marks `PING` as an external
+subroutine. The generator contributes the bridge declaration and call syntax;
+it does not decide whether `PING` is callable or how values cross the boundary.
+
+## Run The Module Demonstration
+
+`bridge.py` also contains a direct demonstration of its normal input route. It
+constructs one scalar semantic function, completes policy, builds its plan,
+preflights bridge scalar support, lowers the Fortran nodes, and prints the
+module through `FortranSourcePrinter`. Expand **Example source** on the
+published site to see that exact `__main__` setup.
+
+```bash
+python3 prik/codegen/fortran/bridge.py
+```
+
+```text
+Rendered Fortran bridge source:
+module bind_c_bridge_demo_wrapper
+ use iso_c_binding, only: &
+ c_associated, &
+ c_bool, &
+ c_char, &
+ c_double, &
+ c_double_complex, &
+ c_f_pointer, &
+ c_float, &
+ c_float_complex, &
+ c_int8_t, &
+ c_int16_t, &
+ c_int, &
+ c_int32_t, &
+ c_int64_t, &
+ c_loc, &
+ c_null_char, &
+ c_ptr, &
+ c_null_ptr, &
+ c_size_t, &
+ c_sizeof
+ use bridge_demo, only: native_double_value => DOUBLE_VALUE
+ implicit none
+contains
+ function bind_c_double_value(value) result(result) bind(c, name="bind_c_double_value")
+ real(c_double), value :: value
+ real(c_double) :: result
+ result = native_double_value(value)
+ end function bind_c_double_value
+end module bind_c_bridge_demo_wrapper
+```
+
+The module and procedure names identify the planned C-ABI boundary. The final
+assignment is the printed native call that the completed bridge plan selected.
+`DOUBLE_VALUE` remains the procedure exported by `bridge_demo`; the `use`
+statement imports it locally as `native_double_value`, so the bridge calls that
+alias. This gives every imported module procedure a distinct bridge-local name.
+
+## Change Routes And Evidence
+
+- Change bridge ABI declarations, native invocation, conversion, writeback, or
+ cleanup in `bridge.py`.
+- Change a primitive's Fortran spelling in
+ [`primitive_scalar_types.py`](../../../../prik/codegen/primitive_scalar_types.py).
+- If an ABI fact is absent from a bridge record, add the completed policy and
+ plan fact upstream; do not inspect semantic source or invent a default here.
+
+| Evidence | What it establishes |
+| --- | --- |
+| [Wrapper-generator handoff](../../../../tests/fortran/infrastructure/pipeline/test_wrapper_generator.py) | Frozen-plan validation and generated Fortran bridge assembly. |
+| [Module-variable lowering](../../../../tests/fortran/modules/codegen/test_scalar_module_variable_lowering.py) | Matched C and Fortran scalar module-variable operations and their bridge procedures. |
+| [Array lowering](../../../../tests/fortran/arrays/codegen/test_specialized_array_roles.py) | Plan-selected specialized array roles lower through the bridge ABI. |
+
+## Failure Boundary
+
+The bridge reports unavailable primitive spellings, unsupported completed
+actions, invalid plan references, and missing node visitors. It delegates
+missing semantic choices to `policy/` and `planning/`, source formatting to
+`printers/`, and compilation to `compiler/`. Start with the first invalid plan
+record or bridge procedure, not with a later Fortran compiler error.
diff --git a/docs/developer/packages/compiler.md b/docs/developer/packages/compiler.md
index 77e929746..015ea8e27 100644
--- a/docs/developer/packages/compiler.md
+++ b/docs/developer/packages/compiler.md
@@ -1,27 +1,26 @@
---
-title: Compiler Package
+title: Compiler Stage
audience: developers, maintainers, contributors
prerequisites: contributor architecture guide, native compiler toolchain
related: ../architecture.md, index.md, pipeline.md, runtime.md, ../workflows/quality-assurance.md
status: maintained
-publication: draft
+publication: reviewed
---
-# Compiler Package
+# Compiler Stage
## Purpose And Boundaries
-`prik/compiler/` receives explicit source, object, include, library, flag, and
-link inputs and turns them into native commands. It owns compiler-family
-profiles, command construction and execution, and native-support installation.
-It does not preprocess source, discover build order, probe datatype meaning,
-or decide wrapper policy.
+`prik/compiler/` turns explicit native-build requests into compiler commands.
+It owns coherent compiler-family profiles, command construction and execution,
+and conditional installation of the bundled native support. It does not
+preprocess source, discover build order, probe datatype meaning, or decide
+wrapper policy.
## Local Structure
```text
prik/compiler/
-├── __init__.py
├── compiler_profiles.py
├── objects.py
├── compilers.py
@@ -31,31 +30,81 @@ prik/compiler/
## What This Stage Receives And Produces
```text
-explicit ObjectFile and link inputs from prik.pipeline
- -> coherent compiler-family profile
- -> compile/link argv
- -> recorded or executed native process
- -> object file or shared extension
+selected Fortran executable -> compatible vendor profile and C driver
+explicit ObjectFile -> compile argv -> object file
+ordered objects + link args -> link argv -> shared extension
+
+generated imports + output directory -> conditional native-support installation
```
-The selected Fortran compiler family supplies its matching C driver and
-family-specific switches. The pipeline owns dependency-ready batches; the
-compiler executes one request at a time.
+The pipeline supplies dependency-ready batches and decides when native support
+is needed. This component executes one explicit request at a time. Selecting a
+Fortran compiler identifies its compatible C driver and family-specific flags;
+it never combines unrelated toolchain profiles.
## Directory Tour
| Module | Main entrypoints and contents | Change it when |
| --- | --- | --- |
-| [`prik/compiler/__init__.py`](../../../prik/compiler/__init__.py) | Deliberately empty package boundary; callers use the owning modules or pipeline APIs. | Establishing a small compiler-package public import surface. |
| [`prik/compiler/compiler_profiles.py`](../../../prik/compiler/compiler_profiles.py) | Profile data and `fortran_compiler_family()` map a Fortran executable to its compatible C driver and flags. | Supporting a compiler family or changing family-specific build settings. |
| [`prik/compiler/objects.py`](../../../prik/compiler/objects.py) | `ObjectFile` is the immutable description of one source-to-object request. | A compilation input needs another explicit field or validation rule. |
| [`prik/compiler/compilers.py`](../../../prik/compiler/compilers.py) | `Compiler` builds, records, runs, and reports compile/link commands; `get_condaless_search_path()` isolates environment lookup. | Command spelling, subprocess execution, or command reporting changes. |
| [`prik/compiler/native_support.py`](../../../prik/compiler/native_support.py) | `install_native_support()` copies the bundled support payload and creates the NumPy API-version header. | The pipeline needs a different support-installation result; edit the payload itself under `runtime/native_support/`. |
-## Execution Examples
+## Module Algorithms
+
+### `compiler_profiles.py`: select one coherent toolchain
+
+`available_compilers` records the C and Fortran settings for each supported
+vendor. While constructing those profiles, `_toolchain()` attaches the active
+Python and NumPy include and link settings required for a CPython extension.
+
+`fortran_compiler_family()` only classifies a Fortran executable name: it
+returns the identifying token, vendor profile, and matching C executable name.
+It does not locate executables or run a command.
+`Compiler.from_fortran_executable()` performs the lookup, first beside the
+selected Fortran executable and then on the configured search path. It rejects
+an unknown family or a missing matching C driver.
+
+### `objects.py`: carry one complete compilation request
+
+`ObjectFile` is a frozen record for one source-to-object operation. It
+normalizes paths and iterable fields, accepts only C or Fortran, and carries
+the source, output path, flags, include and library directories, libraries,
+and requested tools. Compilation order and dependency discovery remain in the
+pipeline.
+
+### `compilers.py`: construct and run explicit argv commands
+
+`Compiler` loads a built-in profile, a JSON profile, or an installed profile.
+Its `compile_object()` method creates the declared output directory, selects
+the correct language driver, combines profile flags with the request's flags,
+adds include paths, and adds the vendor-specific Fortran module-output flag.
+It then records the exact argv and either executes it or returns it in
+record-only mode.
+
+`link_extension()` requires a nonempty ordered object list. It selects the
+linker for the requested language, adds shared-library, profile, Python, and
+library inputs, preserves the supplied object and link-argument order, and
+returns the extension path. It does not reorder dependencies or search for
+additional objects. `get_condaless_search_path()` is the isolated compiler
+lookup helper for environments whose Conda paths should be ignored.
+
+### `native_support.py`: install support only when generated imports need it
+
+`install_native_support()` does nothing unless generated imports request
+`binding_support` or one of its files. When needed, it locks the destination,
+replaces the copied header-only payload, and writes `numpy_version.h` for the
+active NumPy API level. The pipeline owns the generated imports and destination
+directory; this module only performs that installation.
+
+## Run The Workflows
Compiler-family selection:
+`compiler_profiles.py` classifies an example `gfortran-13` executable name and
+reads the matching built-in profile; it does not locate or invoke a compiler.
+
```bash
python3 prik/compiler/compiler_profiles.py
```
@@ -67,8 +116,15 @@ Matching C executable: gcc
Fortran module-output flag: -J
```
+The vendor, C driver, and module-output flag are one coherent family choice.
+They are profile facts that `Compiler.from_fortran_executable()` later uses for
+real executable lookup.
+
One immutable compilation request:
+`objects.py` constructs one `ObjectFile` for a generated Fortran bridge. It
+does not create the source or invoke a compiler.
+
```bash
python3 prik/compiler/objects.py
```
@@ -80,8 +136,14 @@ Flags: ('-O2',)
Include directories: build/modules
```
+These fields are the complete explicit input for one compilation request; the
+pipeline, not `ObjectFile`, decides when that request is compiled.
+
Record-only command construction:
+`compilers.py` creates a temporary C request and a GNU compiler configured to
+record commands without executing them.
+
```bash
python3 prik/compiler/compilers.py
```
@@ -95,8 +157,15 @@ Contains requested flag: True
Commands recorded: 1
```
+The missing object file and recorded `-c` command show that command construction
+is independently inspectable. The requested flag appears after profile flags,
+and no native subprocess ran.
+
Bundled runtime installation:
+`native_support.py` requests `binding_support/prik_binding.h` into a temporary
+directory, which is enough to trigger conditional support installation.
+
```bash
python3 prik/compiler/native_support.py
```
@@ -107,16 +176,19 @@ Binding header present: True
NumPy version header present: True
```
-Together these outputs prove that profile selection, request construction,
-native command mechanics, and support installation remain separate operations.
+The two `True` lines show that the payload and active-NumPy header were written
+only after the generated import requested them. Together the examples cover
+toolchain classification, explicit request representation, command creation,
+and conditional support installation.
-## Tests And What They Prove
+## Tests And Evidence
-- [Compiler construction tests](../../../tests/fortran/building_shared_library/compiling/) cover profile selection and compile/link argv.
-- [Build pipeline tests](../../../tests/fortran/building_shared_library/pipeline/) cover compiler handoff from a build plan.
-- [Source build modes](../../../tests/fortran/building_shared_library/end_to_end/test_source_build_modes.py) covers real source-build outcomes.
-- [Runtime ABI compatibility](../../../tests/fortran/building_shared_library/end_to_end/test_runtime_compatibility.py) covers installed support used by a compiled extension.
-- [Direct execution inventory](../../../tests/fortran/infrastructure/execution_examples/test_execution_examples.py) fixes the four demonstrations above.
+| Evidence | What it establishes |
+| --- | --- |
+| [Compiler profile and command construction](../../../tests/fortran/building_shared_library/compiling/test_compiler_verbose.py) | Coherent C/Fortran driver selection, explicit overrides, profile and user-flag order, optional-flag probing, record-only mode, and preserved link-input order. |
+| [Generated-wrapper build handoff](../../../tests/fortran/building_shared_library/pipeline/test_generated_wrapper_build.py) | Generated sources, conditional support installation, explicit C and Fortran object requests, and the final ordered link request passed from the pipeline. |
+| [Source build modes](../../../tests/fortran/building_shared_library/end_to_end/test_source_build_modes.py) | The selected source-build mode produces an importable native extension. |
+| [Native-support surface](../../../tests/fortran/infrastructure/runtime/test_native_support.py) | The bundled payload remains header-only and exposes the small native binding API expected by generated sources. |
## Change Routes
@@ -127,9 +199,18 @@ native command mechanics, and support installation remain separate operations.
- Change native payload contents in `prik/runtime/native_support/`; change only
their installation here.
-## Invariants And Common Mistakes
+## Boundaries And Invariants
- Never infer ownership, dtype, Python API shape, or wrapper support here.
- Never silently mix a selected Fortran driver with an unrelated C profile.
- Each invocation receives explicit inputs; hidden project discovery belongs
upstream.
+
+## Failure Boundary
+
+This component reports invalid object requests, unknown or incomplete
+toolchains, unavailable compiler executables, and failed compiler processes.
+It delegates dependency order, artifact selection, and build manifests to
+`pipeline/`; generated imports and output locations are also pipeline facts.
+Start with the selected profile or the first recorded argv whose inputs are
+wrong, rather than with the extension that fails later.
diff --git a/docs/developer/packages/contracts.md b/docs/developer/packages/contracts.md
index 18e55e80c..10bdad5e2 100644
--- a/docs/developer/packages/contracts.md
+++ b/docs/developer/packages/contracts.md
@@ -1,59 +1,61 @@
---
-title: Contracts Package
+title: Contracts Component
audience: developers, maintainers, contributors
prerequisites: contributor architecture guide, semantic .pyi format
related: index.md, parsers.md, semantics.md, ../architecture.md
status: maintained
-publication: draft
+publication: reviewed
---
-# Contracts Package
+# Contracts Component
## Purpose And Boundaries
-`prik/contracts/` owns the public names written in semantic `.pyi` contracts.
-Those names describe scalar types, arrays, storage, ownership requests,
-projections, native calls, callbacks, and descriptor handles. The package is a
-public syntax vocabulary; it does not define semantic IR, complete policy, or
-generate wrappers.
+`prik/contracts/` is the public vocabulary used in semantic `.pyi` files. It
+defines the importable names for scalar and array types, descriptor handles,
+metadata expressions, native-call descriptions, callbacks, and decorators.
-## Local Structure
+The package preserves valid Python annotation syntax at runtime. It does not
+parse that syntax, assign semantic meaning, complete interoperability policy,
+or generate a wrapper. Those responsibilities belong to `parsers/`,
+`semantics/`, `policy/`, and `codegen/` respectively.
+
+## How A Contract Name Is Used
```text
-prik/contracts/
-└── __init__.py
+name imported from prik.contracts
+ -> Python AST produced by the .pyi parser
+ -> semantic interpretation in pyi2ir.py
+ -> policy completion, planning, and generation
```
-The single module is intentional. A semantic contract imports one stable
-public namespace instead of depending on internal stage packages.
+For example, `Float64[:, :]` creates a declarative array-contract object whose
+element type, rank, and shape can be inspected. It does not create semantic IR
+or a NumPy array. A concrete scalar name such as `Float64` additionally has a
+zero-valued NumPy constructor so generated contracts can be imported and used
+as Python modules.
-## What This Stage Receives And Produces
+## Local Structure
```text
-semantic .pyi text
- -> names imported from prik.contracts
- -> Python AST in prik.parsers.pyi
- -> contract interpretation in prik.semantics.pyi2ir
- -> completed policy in prik.policy
+prik/contracts/
+└── __init__.py
```
-Some primitive symbols also construct exact NumPy scalar values at runtime.
-Subscriptions such as `Float64[:, :]` construct declarative contract objects;
-they do not create semantic IR objects.
-
-## Directory Tour
-
-| Module | Main entrypoints and contents | Change it when |
-| --- | --- | --- |
-| [`prik/contracts/__init__.py`](../../../prik/contracts/__init__.py) | The complete public vocabulary: scalar and array markers, descriptor markers (`Allocatable`, `Pointer`), metadata expressions, decorators, and the small runtime constructors behind concrete scalar and descriptor contracts. | Adding, removing, or documenting public `.pyi` syntax. This one file is intentionally the stable import namespace; private `_Contract*` classes preserve annotation syntax at runtime. |
+[`prik/contracts/__init__.py`](../../../prik/contracts/__init__.py) contains
+the complete public namespace. Its contents have four roles:
-The canonical public import path is part of the file format. Internal code may
-interpret these names, but must not replace them with imports from semantics,
-policy, or codegen.
+- scalar, array, descriptor, and wrapped-type markers describe values;
+- expression helpers such as `Arg`, `Len`, and `Ownership` describe metadata;
+- decorators such as `native_call`, `prototype`, and `standalone` describe
+ callable structure; and
+- `CONTRACT_SYMBOLS` and `CONTRACT_TYPE_NAMES` give parsers and printers the
+ canonical public vocabulary.
-## Execution Example
+Private `_Contract*` classes implement import-time annotation behavior. They
+are mechanisms behind the public names, not part of the contract language.
-Run the real package entry file:
+## Run The Contract Demonstration
```bash
python3 prik/contracts/__init__.py
@@ -64,33 +66,25 @@ Float64() -> np.float64(0.0) (float64)
Float64[:, :] -> element=Float64, rank=2, shape=(slice(None, None, None), slice(None, None, None))
```
-The first line proves that a primitive contract scalar has exact NumPy runtime
-behavior. The second proves that array subscription produces declarative rank
-and shape syntax for later semantic interpretation.
-
-## Tests And What They Prove
-
-- [Contract runtime tests](../../../tests/fortran/data_types/runtime/) protect scalar and descriptor-constructor behavior.
-- [Semantic `.pyi` parser tests](../../../tests/fortran/semantic_pyi_format/parsing/) protect recognition of the public vocabulary.
-- [Semantic `.pyi` round-trip tests](../../../tests/fortran/semantic_pyi_format/pipeline/) protect loading and re-emission through the shared contract path.
-- [Direct execution inventory](../../../tests/fortran/infrastructure/execution_examples/test_execution_examples.py) fixes the example output above.
-
-## Change Routes
+The first line demonstrates the concrete NumPy scalar constructor. The second
+shows the declarative type, rank, and shape retained by an array annotation;
+later stages interpret those facts.
-- Add or rename public syntax here first, then update `.pyi` parsing,
- conversion, printing, user reference documentation, and focused round-trip
- tests.
-- Change semantic meaning in `prik/semantics/pyi2ir.py`, not in a runtime
- constructor.
-- Change ownership or lowering selection in policy after semantic conversion.
+## Change Routes And Evidence
-## Invariants And Common Mistakes
+- Change public `.pyi` names in `prik/contracts/__init__.py`, then update the
+ parser, semantic conversion, printer, and
+ [semantic `.pyi` reference](../../user/reference/pyi-contracts/index.md).
+- Change the meaning of a contract in `prik/semantics/pyi2ir.py`.
+- Change ownership, projection, or support decisions in `prik/policy/`.
-- Keep `prik.contracts` stable and public; do not expose internal policy models
- through this namespace.
-- A valid Python annotation is not automatically a supported wrapper contract.
-- NumPy construction behavior must not become the semantic datatype authority.
+| Evidence | What it establishes |
+| --- | --- |
+| [Contract runtime tests](../../../tests/fortran/data_types/runtime/) | Concrete scalar constructors and invalid constructor use. |
+| [Semantic `.pyi` parser tests](../../../tests/fortran/semantic_pyi_format/parsing/) | Recognition of the public vocabulary and annotation syntax. |
+| [Semantic `.pyi` pipeline tests](../../../tests/fortran/semantic_pyi_format/pipeline/) | Contract loading, semantic conversion, and re-emission. |
-See the [semantic `.pyi` user reference](../../user/reference/semantic-pyi-format.md)
-for the public language and the [semantics package](semantics.md) for its IR
-interpretation.
+The import path and public names are part of the file format. A name being
+valid Python syntax does not by itself make the corresponding wrapper behavior
+supported, and runtime constructors must not become the authority for semantic
+datatype decisions.
diff --git a/docs/developer/packages/index.md b/docs/developer/packages/index.md
index 33367f5eb..fc7fa94c0 100644
--- a/docs/developer/packages/index.md
+++ b/docs/developer/packages/index.md
@@ -1,46 +1,53 @@
---
-title: Source Package Guides
+title: Architecture Components
audience: developers, maintainers, contributors
prerequisites: contributor architecture guide
-related: ../architecture.md, ../source-map.md, ../feature-to-code-map.md
+related: ../architecture.md, ../codebase-map.md, ../feature-to-code-map.md, ../testing-strategy.md
status: maintained
-publication: draft
+publication: reviewed
---
-# Source Package Guides
+# Architecture Components
-These pages are the file-level companion to the
-[architecture guide](../architecture.md). Read the architecture guide once for
-the whole flow, then use this table to enter the owner of a change. Do not read
-the guides as thirteen alternative pipelines: each describes one handoff in
-the same pipeline.
+The [architecture](../architecture.md) shows how PRIK moves from inputs to an
+importable extension. This page groups the build stages that transform those
+inputs and the supporting components they depend on. Each guide maps one
+architecture component to its `prik` source package, local modules, and tests.
+The [codebase map](../codebase-map.md) provides the complementary module and
+hotspot inventory.
-| Package | Read it when you need to change | Canonical guide |
+## Build Workflow and Stages
+
+`pipeline/` spans the complete build and is listed first because it composes
+the stages below.
+
+| Component | Responsibility | Relevant changes |
+| --- | --- | --- |
+| [`prik.pipeline`](pipeline.md) | Composes wrapper, contract, report, artifact, and build workflows. | Public build workflows, artifact layout, or cross-stage orchestration. |
+| [`prik.preprocessing`](preprocessing.md) | Prepares Fortran input and measures target facts. | Includes, provenance, parser input, or target probes. |
+| [`prik.parsers`](parsers.md) | Records Fortran and semantic-`.pyi` syntax facts. | Declarations, locations, parser diagnostics, or raw `.pyi` AST. |
+| [`prik.semantics`](semantics.md) | Builds the shared language-neutral semantic model. | Semantic types, shapes, origins, or raw contract metadata. |
+| [`prik.policy`](policy.md) | Completes interoperability and support decisions. | Ownership, projection, lifecycle, exports, or support choices. |
+| [`prik.planning`](planning.md) | Projects completed policy into backend-neutral wrapper plans. | Planned operations, ordering, namespaces, or backend views. |
+| [`prik.codegen`](codegen.md) | Lowers plans into C and Fortran nodes and Python facades. | Binding, bridge, node, or facade mechanisms. |
+| [`prik.printers`](printers.md) | Serializes C, Fortran, and semantic `.pyi` representations. | Generated text, formatting, escaping, or line wrapping. |
+| [`prik.compiler`](compiler.md) | Constructs and executes native compilation and linking commands. | Compiler profiles, command arguments, linking, or native-support installation. |
+
+## Supporting Components
+
+| Component | Responsibility | Relevant changes |
| --- | --- | --- |
-| `prik.contracts` | public semantic `.pyi` syntax | [Contracts](contracts.md) |
-| `prik.compiler` | compiler profiles, command argv, or native-support installation | [Compiler](compiler.md) |
-| `prik.preprocessing` | parser input, provenance, includes, or target probes | [Preprocessing](preprocessing.md) |
-| `prik.parsers` | Fortran syntax facts or raw `.pyi` syntax | [Parsers](parsers.md) |
-| `prik.semantics` | the shared semantic graph, types, or raw metadata | [Semantics](semantics.md) |
-| `prik.policy` | completed ownership, projection, lifecycle, or support choices | [Policy](policy.md) |
-| `prik.planning` | plan representation, ordering, or backend views | [Planning](planning.md) |
-| `prik.codegen` | generated binding, bridge, node, or Python-facade mechanism | [Code generation](codegen.md) |
-| `prik.printers` | C, Fortran, or `.pyi` text serialization | [Printers](printers.md) |
-| `prik.pipeline` | wrapper, contract, report, artifact, or build orchestration | [Pipeline](pipeline.md) |
-| `prik.runtime` | imported native handles or bundled native support | [Runtime](runtime.md) |
-| `prik.naming` | public-name normalization or generated symbols | [Naming](naming.md) |
-| `prik.utilities` | a genuinely stage-neutral helper | [Utilities](utilities.md) |
-
-Each guide answers the same practical questions:
-
-1. What does this stage receive and produce?
-2. Which module owns the behavior I need to change?
-3. Which classes and functions are the important entrypoints?
-4. What does each direct-execution example prove?
-5. Which tests protect that behavior?
-
-The directory tour covers every supported Python module under that package,
-including package initializers and nested backend packages. The deferred
-C-input frontend is intentionally excluded from the published Fortran route.
-Source-tree `README.md` files remain short orientation notes and link back to
-these canonical guides.
+| [`prik.contracts`](contracts.md) | Defines the public semantic `.pyi` vocabulary. | Contract syntax or its public imported names. |
+| [`prik.naming`](naming.md) | Normalizes public names and constructs generated symbols. | Public-name normalization, collisions, or generated symbols. |
+| [`prik.runtime`](runtime.md) | Provides imported native handles and bundled native support. | Runtime handle behavior or native-support payloads. |
+| [`prik.utilities`](utilities.md) | Holds mechanisms with no stage-specific owner. | A genuinely stage-neutral helper. |
+
+Each guide records the same local contract:
+
+1. Its responsibility and boundaries.
+2. Its inputs, outputs, modules, and important entrypoints.
+3. Direct-execution examples and the behavior they demonstrate.
+4. Focused tests, change routes, and invariants.
+
+The guides cover the current Fortran-wrapper route. The C-input frontend is
+deferred material and does not change the generated CPython C binding backend.
diff --git a/docs/developer/packages/naming.md b/docs/developer/packages/naming.md
index 804738932..448ec98e7 100644
--- a/docs/developer/packages/naming.md
+++ b/docs/developer/packages/naming.md
@@ -1,19 +1,38 @@
---
-title: Naming Package
+title: Naming Component
audience: developers, maintainers, contributors
prerequisites: contributor architecture guide
-related: ../architecture.md, index.md, planning.md, codegen.md, ../source-map.md
+related: ../architecture.md, index.md, policy.md, planning.md, codegen.md
status: maintained
-publication: draft
+publication: reviewed
---
-# Naming Package
+# Naming Component
## Purpose And Boundaries
-`prik/naming/` owns public and generated names whose stability and collision
-rules are shared across planning and generation. It does not own semantic
-policy or emitted source syntax.
+`prik/naming/` owns naming rules shared by policy, planning, printers, and code
+generation. It keeps Python-visible names valid and collision-free and creates
+deterministic native symbols within target-language constraints. It does not
+choose exports, ownership, wrapper support, or emitted syntax.
+
+## The Two Naming Routes
+
+```text
+source spelling + public namespace
+ -> normalize Python identifier
+ -> reserve it or add a collision suffix
+ -> public export name
+
+owner identity + preferred generated name + target rules
+ -> escape reserved or special names
+ -> avoid occupied symbols
+ -> deterministic native symbol
+```
+
+Public names and generated symbols are deliberately separate. Escaping a
+Python keyword must not rename the underlying Fortran symbol, and a C or
+Fortran restriction must not change the public Python API.
## Local Structure
@@ -24,23 +43,25 @@ prik/naming/
└── native_symbols.py
```
-## What This Stage Receives And Produces
-
-```text
-raw public or generated identity + occupied namespace
- -> normalized public name or bounded native symbol
- -> planning and code generation
-```
+- [`prik.naming`](../../../prik/naming/__init__.py) re-exports the supported
+ public-name and generated-symbol policy API. Change it only when that
+ package-level API changes.
+- [`policy.py`](../../../prik/naming/policy.py) contains
+ `normalize_public_name()`, `NamingPolicy.reserve_public_name()`, and
+ `generated_symbol()`. Change it for normalization, strict-name behavior,
+ namespace collisions, keywords, or target-language rules.
+- [`native_symbols.py`](../../../prik/naming/native_symbols.py) contains
+ `NativeSymbolNames.compact()`. It combines a readable prefix with a hash of
+ the full owner identity under a requested length limit.
-## Directory Tour
+`NamingPolicy` retains public reservations for one construction operation.
+`NativeSymbolNames` is stateless: the same owner, preferred spelling, and
+limit always produce the same result.
-| Module | Main entrypoints and contents | Change it when |
-| --- | --- | --- |
-| [`prik/naming/__init__.py`](../../../prik/naming/__init__.py) | Re-exports the supported normalization and generated-symbol policy objects. | Changing the package-level naming API. |
-| [`prik/naming/policy.py`](../../../prik/naming/policy.py) | `NamingPolicy`, `NormalizedPublicName`, `PublicNameRecord`, and `GeneratedSymbolRules` normalize Python names, reserve namespaces, and apply language rules. | Public-name normalization, collision handling, keyword escaping, or target language symbol rules. |
-| [`prik/naming/native_symbols.py`](../../../prik/naming/native_symbols.py) | `NativeSymbolNames` retains owner identity and creates compact, deterministic compiler-safe fragments. | Bounded native-symbol spelling or hash/prefix rules. |
+## Run The Naming Demonstrations
-## Execution Examples
+The policy example shows normalization, a public collision, and one C special
+method rewrite:
```bash
python3 prik/naming/policy.py
@@ -52,6 +73,9 @@ Collision-safe public name: render_value_2
C destructor symbol: state_drop
```
+The compact-symbol example preserves a readable prefix while using the full
+owner path for collision resistance:
+
```bash
python3 prik/naming/native_symbols.py
```
@@ -62,21 +86,17 @@ Stable native symbol: point_coordinate_d_c2fc5940
Within 27-character limit: True
```
-The first example distinguishes public namespace allocation from generated
-target naming. The second preserves a readable prefix while hashing the full
-owner identity under a compiler symbol limit.
-
-## Tests And What They Prove
-
-- [Naming infrastructure](../../../tests/fortran/infrastructure/naming/) covers normalization, collisions, and stable generated names.
-- [Direct execution inventory](../../../tests/fortran/infrastructure/execution_examples/test_execution_examples.py) fixes the two demonstrations above.
-
-## Change Routes
+## Change Routes And Evidence
-- Change public normalization and collision policy in `policy.py`.
-- Change stable ABI fragments in `native_symbols.py` with exact-name tests.
+- Change Python normalization, namespace reservation, or target-language rules
+ in `policy.py`.
+- Change bounded native helper symbols in `native_symbols.py`; treat their
+ spelling as generated ABI when compiled artifacts refer to it.
-## Invariants And Common Mistakes
+| Evidence | What it establishes |
+| --- | --- |
+| [Naming tests](../../../tests/fortran/infrastructure/naming/) | Python keyword handling, strict mode, namespace collisions, language keywords, and special-method rewriting. |
-- Never consult completed ownership or emit language syntax here.
-- The same inputs must always produce the same generated symbol.
+Naming must be deterministic for identical inputs. This component may apply a
+rule supplied by a target language, but it must never infer semantic policy or
+emit source text.
diff --git a/docs/developer/packages/parsers.md b/docs/developer/packages/parsers.md
index 0e191136e..bc9924176 100644
--- a/docs/developer/packages/parsers.md
+++ b/docs/developer/packages/parsers.md
@@ -1,25 +1,47 @@
---
-title: Parsers Package
+title: Parsing Stage
audience: developers, maintainers, contributors
prerequisites: contributor architecture guide, prepared source
-related: ../architecture.md, index.md, preprocessing.md, semantics.md, ../source-map.md
+related: ../architecture.md, index.md, preprocessing.md, semantics.md, ../codebase-map.md
status: maintained
-publication: draft
+publication: reviewed
---
-# Parsers Package
+# Parsing Stage
## Purpose And Boundaries
-`prik/parsers/` owns syntax-level facts. The Fortran frontend preserves source
-units, declarations, visibility, locations, and diagnostics. The semantic
-`.pyi` frontend deliberately stops at a standard Python AST. A parser reports
-what its input says; it does not assign a stable semantic type, choose
-ownership, decide wrapper support, or emit a Python API.
+`prik/parsers/` records syntax-level facts. The Fortran frontend preserves
+source units, declarations, visibility, locations, and diagnostics. The
+semantic-`.pyi` frontend returns a standard Python AST. A parser reports what
+its input says; it does not assign stable semantic types, choose ownership,
+decide wrapper support, or emit a Python API.
-The C-input frontend is intentionally deferred from the published contributor
-workflow. This guide covers the supported Fortran and semantic-`.pyi` path;
-generated C binding remains documented under [code generation](codegen.md).
+The `c/` directory is early work for a future C frontend. C support is not yet
+complete and is outside the current Fortran-wrapper route, so this guide covers
+only the supported Fortran and semantic-`.pyi` parsers.
+
+## Inputs And Results
+
+```text
+prepared Fortran text
+ -> lexer: logical lines with original locations
+ -> source-unit scanner: classified file-level units and their regions
+ -> FortranParser visitors and scoped declaration collection
+ -> source-visible type, shape, kind, and visibility resolution
+ -> FortranFile or dependency-aware FortranProject
+ -> Fortran-to-IR conversion
+
+semantic .pyi text or path
+ -> ast.parse
+ -> ast.Module
+ -> .pyi-to-IR conversion
+```
+
+`FortranFile` and `FortranProject` preserve parser facts. A parsed intrinsic
+kind expression, `intent`, or array shape is still source syntax, not a
+compiler-measured target fact or completed wrapper decision. The `.pyi` result
+is Python syntax only; contract interpretation begins in `semantics/`.
## Local Structure
@@ -35,52 +57,107 @@ prik/parsers/
│ ├── parser.py
│ ├── type_resolver.py
│ └── utils.py
-└── pyi/
- ├── __init__.py
- └── parser.py
+├── pyi/
+│ ├── __init__.py
+│ └── parser.py
+└── c/ incomplete future C frontend
```
-## What This Stage Receives And Produces
+## Directory Tour
-```text
-prepared Fortran text
- -> logical lines with original locations
- -> Fortran parser models and diagnostics
- -> Fortran-to-IR conversion
+| Module | Public boundary and result | Change it when |
+| --- | --- | --- |
+| [`prik/parsers/__init__.py`](../../../prik/parsers/__init__.py) | Names the language frontend namespaces; it does not flatten their APIs. | The parser-frontend layout changes. |
+| [`prik/parsers/fortran/__init__.py`](../../../prik/parsers/fortran/__init__.py) | Re-exports `FortranParser`, `parse_fortran_file()`, `parse_fortran_project()`, parser models, and `FortranParseError`. | The supported Fortran-parser import surface changes. |
+| [`prik/parsers/fortran/__main__.py`](../../../prik/parsers/fortran/__main__.py) | Runs the Fortran parser CLI for `python3 -m prik.parsers.fortran`. | Module-launch behavior changes. |
+| [`prik/parsers/fortran/utils.py`](../../../prik/parsers/fortran/utils.py) | `detect_source_form()` chooses fixed or free form; `split_csv()` separates only top-level Fortran comma lists. | Source-form detection or grammar-neutral list splitting changes. |
+| [`prik/parsers/fortran/lexer.py`](../../../prik/parsers/fortran/lexer.py) | `preprocess_lines()` produces logical lines with original coordinates; `strip_comment()` preserves string literals and OpenMP directives. | Comment handling, continuation folding, or location preservation changes. |
+| [`prik/parsers/fortran/models.py`](../../../prik/parsers/fortran/models.py) | Passive source-fact records: `FortranFile`, `FortranProject`, units, declarations, shapes, and `FortranParseError`. | A parser result, source fact, or diagnostic representation changes. |
+| [`prik/parsers/fortran/type_resolver.py`](../../../prik/parsers/fortran/type_resolver.py) | `extract_kind_from_type_spec()` preserves intrinsic kind and character syntax after declaration parsing. | Parser-level type-spec spelling extraction changes. |
+| [`prik/parsers/fortran/parser.py`](../../../prik/parsers/fortran/parser.py) | `FortranParser`, `parse_fortran_file()`, and `parse_fortran_project()` build file and project models. | Grammar, source-unit structure, declarations, parser diagnostics, or project assembly changes. |
+| [`prik/parsers/fortran/cli.py`](../../../prik/parsers/fortran/cli.py) | `main()` formats parser reports and diagnostics. Its `--semantics` and `--pyi` options explicitly invoke later stages. | Parser CLI arguments, report layout, or diagnostic presentation changes. |
+| [`prik/parsers/pyi/__init__.py`](../../../prik/parsers/pyi/__init__.py) | Re-exports `parse_pyi_text()` and `parse_pyi_file()`. | The supported raw-`.pyi` parser import surface changes. |
+| [`prik/parsers/pyi/parser.py`](../../../prik/parsers/pyi/parser.py) | Parses text or a file into `ast.Module` with no contract interpretation. | Raw Python syntax input, file reading, or parse diagnostics change. |
-semantic .pyi text
- -> ast.Module
- -> .pyi-to-IR conversion
-```
+## Module Workflows
-Fortran parser models retain source spellings such as `real(kind=...)`,
-`intent`, and declaration shapes. Target-dependent kind values arrive from
-preprocessing probes and are resolved in semantic conversion, not here.
+### `fortran/parser.py`: source units to parser models
-## Directory Tour
+Start at `parse_fortran_file()` for one source string or path. It delegates to
+`FortranParser.parse_file()`, whose algorithm is:
-| Module | Main entrypoints and contents | Change it when |
-| --- | --- | --- |
-| [`prik/parsers/__init__.py`](../../../prik/parsers/__init__.py) | Declares the parser frontend namespaces. | The package-level frontend layout changes. |
-| [`prik/parsers/fortran/__init__.py`](../../../prik/parsers/fortran/__init__.py) | Re-exports the supported Fortran parser API: parser functions, `FortranParser`, parser models, and `FortranParseError`. | The supported Fortran-parser import API changes. |
-| [`prik/parsers/fortran/__main__.py`](../../../prik/parsers/fortran/__main__.py) | Module launcher for `python3 -m prik.parsers.fortran`; delegates to the CLI. | Module-launch behavior changes, not parser semantics. |
-| [`prik/parsers/fortran/utils.py`](../../../prik/parsers/fortran/utils.py) | `detect_source_form()` and `split_csv()` are small, grammar-neutral lexical helpers. | Source-form detection or top-level comma splitting changes. |
-| [`prik/parsers/fortran/lexer.py`](../../../prik/parsers/fortran/lexer.py) | `strip_comment()` and `preprocess_lines()` remove comments, fold continuations, and retain logical-line locations. | Lexical normalization or source-coordinate retention changes. |
-| [`prik/parsers/fortran/models.py`](../../../prik/parsers/fortran/models.py) | Passive parser records including `FortranFile`, `FortranProject`, `FortranModule`, variables, signatures, derived types, enums, shapes, and `FortranParseError`. | A parser-level source fact or diagnostic representation changes. |
-| [`prik/parsers/fortran/type_resolver.py`](../../../prik/parsers/fortran/type_resolver.py) | `extract_kind_from_type_spec()` preserves type, kind, and character syntax without measuring its meaning. | Parser-level type-spec spelling extraction changes. |
-| [`prik/parsers/fortran/parser.py`](../../../prik/parsers/fortran/parser.py) | `FortranParser`, source-unit records, `parse_fortran_file()`, and `parse_fortran_project()` slice units, build models, resolve parser-level scope, and order projects. | Grammar, declaration extraction, source-unit structure, parser diagnostics, or project ordering changes. |
-| [`prik/parsers/fortran/cli.py`](../../../prik/parsers/fortran/cli.py) | `main()` turns parser requests into stable human or JSON reports. | Parser CLI arguments or report presentation changes. |
-| [`prik/parsers/pyi/__init__.py`](../../../prik/parsers/pyi/__init__.py) | Re-exports `parse_pyi_text()` and `parse_pyi_file()`. | The supported raw-`.pyi` parser import surface changes. |
-| [`prik/parsers/pyi/parser.py`](../../../prik/parsers/pyi/parser.py) | `parse_pyi_text()` and `parse_pyi_file()` validate and return `ast.Module` without semantic interpretation. | Accepted Python syntax or raw parse diagnostics change. |
+1. Read the source and call `preprocess_lines()` to retain logical lines and
+ original coordinates.
+2. Ask the stateless `_SourceUnitScanner` to find direct file-level units and
+ classify each unit's specification, execution, and `contains` regions.
+3. Dispatch each `SourceUnit` to its `_visit_` method. The visitor creates
+ an explicit `_ParserScope` and parses only the regions allowed for that unit.
+4. Shared declaration helpers create `FortranVariable`, `FortranArgument`,
+ `FortranProcedureSignature`, and other passive source records.
+5. Resolve derived-type links, source-visible compile-time symbols, and
+ file-owned interfaces, then assemble a `FortranFile`.
+
+Execution statements do not become wrapper metadata. Procedure-internal
+subprograms are ignored after their boundaries are recognized; procedure-local
+interfaces are revisited only when needed to type callback dummy arguments.
+
+`parse_fortran_project()` accepts a mapping of names to source, explicit
+paths, or a directory. It parses each file once, resolves cross-file
+compile-time facts, checks project-level duplicate symbols, orders directory
+files by dependencies, and returns a `FortranProject`. The project result is a
+registry of the preserved file models, not a semantic module.
+
+The source file follows this reading order: public entrypoints, unit visitors,
+file and project assembly, source-unit preparation, grammar/header helpers,
+scope and declaration parsing, finalization, then project diagnostics. Read
+the visitor for the unit you are changing before its private helper group.
+
+### `lexer.py`, `utils.py`, and `type_resolver.py`: syntax preservation
+
+`detect_source_form()` uses a known filename suffix first, then a small
+fixed-form continuation-column heuristic. `preprocess_lines()` removes comments
+without touching quoted strings, folds fixed- and free-form continuations, and
+returns `(logical_line, original_line_number, original_source_line)` tuples.
+Those tuples are the location contract used by parser diagnostics.
+
+`split_csv()` uses the shared balanced-expression scanner, so commas inside
+dimensions, calls, brackets, or quoted text do not split a Fortran list.
+`extract_kind_from_type_spec()` operates after the declaration parser isolates
+an intrinsic type specifier: it preserves positional or `kind=` syntax and
+keeps character length and kind together. Neither helper evaluates a kind
+expression.
-Read `fortran/parser.py` by entrypoint, then source-unit scanning, then the
-visitor that owns the construct you are changing. Do not add policy or codegen
-conditions to a parser visitor: preserve the fact and let the next stage
-decide whether it is supported.
+### `models.py`: passive parser vocabulary
-## Execution Examples
+`FortranVariable` and `FortranArgument` hold a declaration's spelling,
+attributes, type, kind, and shape. `FortranProcedureSignature`,
+`FortranDerivedType`, `FortranInterface`, and the module-like records organize
+those facts by source unit. `FortranFile` is one parsed source; `FortranProject`
+adds cross-file registries and dependencies. `FortranParseError` renders a
+source-located, compiler-style diagnostic.
-Logical-line preparation:
+These records may provide structured views of preserved expressions and shapes,
+but they do not make target, ownership, or wrapper-support decisions.
+
+### `pyi/parser.py`: Python syntax only
+
+`parse_pyi_text()` calls `ast.parse()` and returns its `ast.Module`.
+`parse_pyi_file()` reads UTF-8 text then uses the same function. The module
+does not recognize PRIK decorators, validate contract types, or build a
+`SemanticModule`; `semantics/pyi2ir.py` owns all of that interpretation.
+
+### `cli.py`: presentation after parsing
+
+`python3 -m prik.parsers.fortran` enters `__main__.py`, which delegates to
+`cli.main()`. The normal CLI path parses one or more files or directories and
+renders a human-readable report or JSON. `--semantics` and `--pyi` deliberately
+cross the parser boundary into semantic conversion and printing; they are
+inspection conveniences, not parser behavior.
+
+## Run The Workflows
+
+Logical-line preparation preserves a line's original location after a free-form
+continuation is folded:
```bash
python3 prik/parsers/fortran/lexer.py
@@ -94,31 +171,43 @@ line 4: real, intent(in) :: offset
line 5: end subroutine shift
```
-Fortran file parsing:
+The script supplies one continued subroutine declaration and prints the logical
+records returned by the lexer. `line 1` remains the origin of the folded first
+statement, which is the location a later parser diagnostic should report.
+
+Type-spec extraction preserves syntax without evaluating it:
```bash
-python3 prik/parsers/fortran/parser.py
+python3 prik/parsers/fortran/type_resolver.py
```
```text
-Module: metrics
-Parameter: n = 4
-Procedure: scale(values: real[1])
+integer(4) -> 4
+real(kind=selected_real_kind(15, 307)) -> selected_real_kind(15, 307)
+character(len=16, kind=c_char) -> len=16, kind=c_char
```
-Type-spec preservation:
+It passes three type-specification fragments to the extractor. The output
+retains expressions such as `selected_real_kind(15, 307)` instead of evaluating
+them, leaving target-dependent meaning for later stages.
+
+Fortran file parsing assembles the parser model used by the next stage:
```bash
-python3 prik/parsers/fortran/type_resolver.py
+python3 prik/parsers/fortran/parser.py
```
```text
-integer(4) -> 4
-real(kind=selected_real_kind(15, 307)) -> selected_real_kind(15, 307)
-character(len=16, kind=c_char) -> len=16, kind=c_char
+Module: metrics
+Parameter: n = 4
+Procedure: scale(values: real[1])
```
-Parser report formatting:
+The script parses one in-memory module containing a parameter and a rank-one
+subroutine argument. The output is parser vocabulary only: no semantic type,
+ownership, or wrapper decision has been added.
+
+The CLI example uses that same parser result and normal report formatter:
```bash
python3 prik/parsers/fortran/cli.py
@@ -132,7 +221,11 @@ File: geometry.f90
- function norm(value:real[0]) -> real[0]
```
-Raw semantic-`.pyi` parsing:
+The CLI script parses one small file and formats the resulting project record.
+Its nested report shows the same module and procedure hierarchy exposed by the
+programmatic parser, rather than a separate interpretation path.
+
+The semantic-`.pyi` parser returns an AST before any contract interpretation:
```bash
python3 prik/parsers/pyi/parser.py
@@ -145,36 +238,47 @@ Argument annotation: Float64
Semantic conversion performed: False
```
-These outputs are intentionally parse-only. They show preserved source facts,
-not a completed `SemanticModule`, wrapper plan, or generated source.
+The script parses a one-function `.pyi` string and selects its AST node. The
+function name and annotation are syntax facts; `False` confirms that semantic
+conversion remains the next stage's responsibility.
-## Tests And What They Prove
+## Tests And Evidence
-- [Fortran parser tests](../../../tests/fortran/source_parsing/parsing/) cover source forms, units, declarations, diagnostics, and project ordering.
-- [Fortran parser CLI tests](../../../tests/fortran/command_line_interface/pipeline/) cover parser command dispatch and report output.
-- [Semantic `.pyi` parsing tests](../../../tests/fortran/semantic_pyi_format/parsing/) cover raw `.pyi` AST parsing and diagnostics.
-- [Semantic IR conversion tests](../../../tests/fortran/semantic_ir/semantics/) prove the downstream Fortran-model handoff.
-- [Direct execution inventory](../../../tests/fortran/infrastructure/execution_examples/test_execution_examples.py) fixes the five demonstrations above.
+| Evidence | What it establishes |
+| --- | --- |
+| [Fortran parser suite](../../../tests/fortran/source_parsing/parsing/) | Source forms, units, declarations, scopes, diagnostics, project assembly, and parser models. |
+| [Public parser entrypoints](../../../tests/fortran/source_parsing/parsing/test_public_entrypoints.py) | File, project, and singular-unit entrypoint contracts. |
+| [Source forms and diagnostics](../../../tests/fortran/source_parsing/parsing/test_source_form_and_diagnostics_regressions.py) | Logical source preparation, unit boundaries, and public diagnostic metadata. |
+| [Parser CLI](../../../tests/fortran/command_line_interface/pipeline/test_stage_dispatch.py) | Module launcher, report modes, diagnostic presentation, and explicit semantic/`.pyi` inspection modes. |
+| [Semantic `.pyi` parsing](../../../tests/fortran/semantic_pyi_format/parsing/test_python_ast_contracts.py) | Raw `ast.Module` results and the AST-to-semantic-conversion handoff. |
## Change Routes
-- Change source form, comments, continuations, or logical locations in
+- Change source forms, comments, continuations, or logical locations in
`fortran/utils.py` or `fortran/lexer.py`.
-- Change parser facts in `fortran/models.py`; change grammar and source-unit
- construction in `fortran/parser.py`.
-- Change parser report layout in `fortran/cli.py`.
-- Change only raw `.pyi` AST parsing in `pyi/parser.py`; put meaning in
+- Change a parser result record or its diagnostic shape in `fortran/models.py`.
+- Change type-spec spelling preservation in `fortran/type_resolver.py`.
+- Change grammar, source-unit classification, declarations, source-visible
+ compile-time resolution, or project assembly in `fortran/parser.py`.
+- Change presentation and CLI options in `fortran/cli.py`.
+- Change only raw `.pyi` AST parsing in `pyi/parser.py`; put contract meaning in
`semantics/pyi2ir.py`.
-- If a change needs target kind values, use preprocessing probes; if it needs
- ownership, projection, or support, use policy after semantic conversion.
-## Invariants And Common Mistakes
+## Boundaries And Invariants
-- Preserve original source locations through lexical and structural parsing.
-- Keep parser models passive and source-faithful; do not attach completed
- policy to them.
-- `parse_fortran_project()` only receives explicit project files; it does not
- invent recursive source discovery.
+- Preprocess compiler directives before parsing; the raw Fortran parser
+ preserves branch alternatives rather than choosing one.
+- Preserve source coordinates through lexical and structural parsing.
+- Keep parser models source-faithful and policy-free.
- A construct that parses successfully is not automatically wrapper support.
-- The `.pyi` parser returns Python AST. Contract interpretation starts only in
- `semantics/pyi2ir.py`.
+- Target kind values come from preprocessing probes; stable semantic types and
+ contract interpretation come from `semantics/`.
+
+## Failure Boundary
+
+This stage reports invalid parser input, malformed or mismatched unit endings,
+unsupported wrapper-relevant syntax, duplicate parser symbols, and invalid raw
+Python syntax. It delegates compiler expansion and target facts to
+`preprocessing/`, shared meaning to `semantics/`, and support decisions to
+`policy/`. Start with the first incorrect logical line, source unit, or parser
+model—not the later semantic or build failure.
diff --git a/docs/developer/packages/pipeline.md b/docs/developer/packages/pipeline.md
index 5603b92ea..ab372079c 100644
--- a/docs/developer/packages/pipeline.md
+++ b/docs/developer/packages/pipeline.md
@@ -1,86 +1,127 @@
---
-title: Pipeline Package
+title: Pipeline Component
audience: developers, maintainers, contributors
-prerequisites: contributor architecture guide, package guides for participating stages
+prerequisites: contributor architecture guide, architecture component guides for participating stages
related: ../architecture.md, index.md, compiler.md, planning.md, codegen.md, printers.md
status: maintained
-publication: draft
+publication: reviewed
---
-# Pipeline Package
+# Pipeline Component
## Purpose And Boundaries
-`prik/pipeline/` composes complete workflows across established stage
-boundaries. It selects the next stage, preserves progress and timing, assigns
-artifact names, writes generated payloads, coordinates compilation/linking,
-and returns public results. It does not absorb parser grammar, semantic rules,
-policy, backend lowering, printer formatting, or compiler command mechanics.
+`prik/pipeline/` coordinates complete build and inspection workflows across
+established stage boundaries. It owns public build requests, artifact layout,
+source writing, progress, and result records. It does not decide source
+meaning, wrapper policy, emitted mechanisms, text formatting, or compiler
+commands.
+
+## A Source Build Through This Component
+
+The source-first public entrypoint is `build_fortran_extension`. It delegates
+each transformation to its owner, then carries the resulting objects forward:
+
+```text
+Fortran source
+ -> preprocessing, parsing, and semantic conversion
+ -> policy completion
+ -> WrapperPlanner
+ -> WrapperGenerator
+ -> GeneratedWrapper: rendered C, Fortran, and header payloads in memory
+ -> build.py: files, NativeBuildPlan, compiler execution, and linking
+ -> WrapperBuildResult
+ -> import_module(): imported extension
+```
+
+A contract-first build enters through `build_pyi_extension`. Its entry `.pyi`
+contract supplies the public API and explicit native inputs supply the
+implementation; after semantic modules are assembled, it shares the same
+policy, planning, generation, output, and build path. The
+`type_mapping_report.py` workflow is separate: it inspects target and semantic
+datatype facts without creating a wrapper.
## Local Structure
```text
prik/pipeline/
-├── __init__.py
├── pyi.py
├── type_mapping_report.py
├── wrapper.py
└── build.py
```
-## What This Stage Receives And Produces
-
-```text
-semantic modules or source-build request
- -> completed policy and WrapperPlanner
- -> WrapperGenerator
- -> backend node generation
- -> language printers
- -> GeneratedWrapper
- -> build.py writes sources and creates NativeBuildPlan
- -> prik.compiler compiles and links
- -> WrapperBuildResult
-```
-
## Directory Tour
| Module | Main entrypoints and contents | Change it when |
| --- | --- | --- |
-| [`prik/pipeline/__init__.py`](../../../prik/pipeline/__init__.py) | Package boundary for high-level workflows. | Establishing a deliberate pipeline-level import API. |
-| [`prik/pipeline/pyi.py`](../../../prik/pipeline/pyi.py) | `pyi_*_to_semantic_module()` workflows and `emit_module_stubs()` load text, files, and path sets; cache one operation; reconcile external types; and emit stub packages. | `.pyi` batch loading, external-type reconciliation, per-operation cache behavior, or stub-package output changes. |
-| [`prik/pipeline/type_mapping_report.py`](../../../prik/pipeline/type_mapping_report.py) | Report builders connect target probes, semantic conversion, and backend dtype projection into an auditable table. | Cross-stage datatype-report content or evidence changes. |
-| [`prik/pipeline/wrapper.py`](../../../prik/pipeline/wrapper.py) | `GeneratedSource`, `GeneratedWrapper`, and `WrapperGenerator` validate/freeze a plan, invoke docstring and backend generation, print sources, name artifacts, and return one in-memory wrapper. | Plan-to-rendered-wrapper orchestration changes. |
-| [`prik/pipeline/build.py`](../../../prik/pipeline/build.py) | `NativeCompilationUnit`, `NativePrebuiltArtifact`, `NativeLinkItem`, `NativeBuildPlan`, and `WrapperBuildResult` own public build APIs, output, manifests, dependency-ready compilation, linking, and extension import. | Artifact layout, native input plans, build scheduling, manifests, linking, or imported-result behavior changes. |
+| [`prik/pipeline/pyi.py`](../../../prik/pipeline/pyi.py) | `pyi_*_to_semantic_module()` loads text, files, or path sets into semantic modules. `emit_module_stubs()` completes copied modules and renders `.pyi` stubs. | Contract loading, external-type reconciliation, per-operation cache behavior, or stub output. |
+| [`prik/pipeline/type_mapping_report.py`](../../../prik/pipeline/type_mapping_report.py) | Converts compiler probe facts through semantic conversion and backend dtype projection into a Markdown report. | Datatype-report content or its cross-stage evidence. |
+| [`prik/pipeline/wrapper.py`](../../../prik/pipeline/wrapper.py) | `WrapperGenerator.generate()` freezes and validates a `ModulePlan`, delegates backend generation and printing, and returns an in-memory `GeneratedWrapper`. | Plan-to-rendered-wrapper orchestration. |
+| [`prik/pipeline/build.py`](../../../prik/pipeline/build.py) | `build_fortran_extension()`, `build_pyi_extension()`, and `build_pyi_extension_from_manifest()` write artifacts, prepare native inputs, compile/link, and return `WrapperBuildResult`. `NativeBuildPlan` records those native inputs. | Public build behavior, artifact layout, build modes, manifests, scheduling, linking, or extension import. |
+
+## Module Workflows
+
+- **`pyi.py` has two routes.** `pyi_*_to_semantic_module()` parses a contract
+ and converts it to semantic IR; path-set loading also reconciles external
+ type references. `emit_module_stubs()` deep-copies semantic modules, adds
+ required opaque dependencies, completes policy, and renders `.pyi` text.
+- **`wrapper.py` is the rendered-wrapper boundary.** `GeneratedSource` and
+ `GeneratedWrapper` are the handoff records. `WrapperGenerator.generate()`
+ freezes and validates the completed plan before either backend lowers it,
+ then assembles printed C, Fortran, and header payloads with stable names.
+- **`type_mapping_report.py` is inspection only.** Its fixed C and Fortran
+ inventories pass through the normal target probes, semantic converters, and
+ NumPy dtype registry before Markdown rendering. It does not create a wrapper.
+
+## `build.py` Navigation
+
+`build.py` is the orchestration hub. Its public records describe inputs and
+results without executing a build: `NativeCompilationUnit`,
+`NativePrebuiltArtifact`, `NativeLinkItem`, `NativeBuildPlan`, and
+`WrapperBuildResult`. Its three public entrypoints are source-first builds,
+contract-first builds, and replay of a saved contract-build manifest.
+
+Read its private sections as grouped phases, not as independent helpers:
-## Execution Examples
-
-```bash
-python3 prik/pipeline/pyi.py
+```text
+source or .pyi contract plus native inputs
+ -> source/contract preparation and semantic-module assembly
+ -> policy completion -> WrapperPlanner -> WrapperGenerator
+ -> generated-source materialization and native build plan
+ -> dependency-aware compilation, linking, and WrapperBuildResult
+
+.pyi builds additionally: contract graph/export projection
+ -> manifest serialization or replay
```
-```text
-Loaded semantic module: math
-Loaded contract marker: True
-Functions: scale
-Re-emitted module:
-from prik.contracts import Float64
+The source file groups helpers around build configuration, generated-wrapper
+materialization, native compilation scheduling, `.pyi` contract loading and
+exports, native planning and link inputs, manifest handling, wrapper-module
+assembly, Makefile output, type probing, and semantic preparation. Start from
+the matching public entrypoint at the bottom, then follow only the phase it
+calls.
-def scale(
- value: Float64
-) -> Float64: ...
-```
+## Run The Workflows
+
+The following commands are independent. Start with the source-build example:
+it exercises the complete public path described above.
```bash
-python3 prik/pipeline/type_mapping_report.py
+python3 prik/pipeline/build.py
```
```text
-| `int` | signed 32-bit | `Int (Int32 storage)` | `numpy.int32` |
+scale(3.0, 2.5) = 7.5
```
-The exact width depends on the active target and requires a C compiler. The
-columns expose native spelling, measured fact, semantic identity, and NumPy
-projection rather than hiding them behind one universal datatype table.
+This command writes a temporary Fortran source, builds an extension, imports
+it through `WrapperBuildResult.import_module()`, and calls its generated API.
+`7.5` therefore confirms generation, native compilation, import, and the
+public call—not merely that source files were written. It requires configured
+C and Fortran compilers.
+
+`WrapperGenerator` demonstrates the handoff immediately before disk output:
```bash
python3 prik/pipeline/wrapper.py
@@ -92,28 +133,54 @@ Rendered sources: bind_c_generator_demo_wrapper.f90, generator_demo_wrapper.c, g
Native support: binding_support
```
-This result is still in memory: no file has been written or compiled.
+The result is a `GeneratedWrapper` in memory; this command does not write or
+compile files. The initializer and three source names identify the exact
+artifacts that the next build step would write and compile.
+
+The contract-loading workflow produces semantic IR and re-emits a stub:
```bash
-python3 prik/pipeline/build.py
+python3 prik/pipeline/pyi.py
```
```text
-scale(3.0, 2.5) = 7.5
+Loaded semantic module: math
+Loaded contract marker: True
+Functions: scale
+Re-emitted module:
+from prik.contracts import Float64
+
+def scale(
+ value: Float64
+) -> Float64: ...
```
-The final example requires configured C and Fortran compilers. It follows the
-entire public source-build path, imports the resulting extension, and calls its
-generated Python API.
+The script loads one in-memory contract. The marker confirms that the semantic
+module retains its `.pyi` origin; the final text is a fresh stub emitted from
+that semantic model rather than the original syntax tree.
+
+The target-datatype report is an inspection route, not a wrapper build:
-## Tests And What They Prove
+```bash
+python3 prik/pipeline/type_mapping_report.py
+```
-- [Pipeline infrastructure](../../../tests/fortran/infrastructure/pipeline/) covers wrapper assembly and cross-stage records.
-- [Semantic `.pyi` pipeline](../../../tests/fortran/semantic_pyi_format/pipeline/) covers contract loading, reconciliation, and stub emission.
-- [Build pipeline](../../../tests/fortran/building_shared_library/pipeline/) covers files, manifests, and build-plan handoffs.
-- [Compilation integration](../../../tests/fortran/building_shared_library/compiling/) covers native command integration.
-- [End-to-end builds](../../../tests/fortran/building_shared_library/end_to_end/) covers produced extension behavior.
-- [Direct execution inventory](../../../tests/fortran/infrastructure/execution_examples/test_execution_examples.py) fixes the four demonstrations above.
+```text
+| `int` | signed 32-bit | `Int (Int32 storage)` | `numpy.int32` |
+```
+
+The exact width depends on the active C target. The row keeps native spelling,
+measured fact, semantic identity, and NumPy projection separate.
+
+## Tests And Evidence
+
+| Evidence | What it establishes |
+| --- | --- |
+| [Pipeline infrastructure](../../../tests/fortran/infrastructure/pipeline/) | Plan-to-rendered-wrapper assembly and cross-stage records. |
+| [Semantic `.pyi` pipeline](../../../tests/fortran/semantic_pyi_format/pipeline/) | Contract loading, reconciliation, and stub emission. |
+| [Build pipeline](../../../tests/fortran/building_shared_library/pipeline/) | Artifact output, manifests, build modes, and build-plan handoffs. |
+| [Compilation integration](../../../tests/fortran/building_shared_library/compiling/) | Native command integration. |
+| [End-to-end builds](../../../tests/fortran/building_shared_library/end_to_end/) | Build, import, and generated-extension behavior. |
## Change Routes
@@ -123,37 +190,33 @@ generated Python API.
- Change disk output, manifests, native build requests, compilation scheduling,
linking, or imports in `build.py`.
-## Invariants And Common Mistakes
+## Boundaries And Invariants
-- `WrapperGenerator` owns plan-to-rendered-wrapper orchestration, not semantic
- decisions and not native compilation.
-- Per-operation semantic caches must not become process-global because later
- stages attach and freeze data.
-- A pipeline helper delegates domain rules to their owning package.
-- There is one direct generation route and no legacy retry:
+- `WrapperGenerator` owns plan-to-rendered-wrapper orchestration. It neither
+ makes semantic decisions nor invokes a compiler.
+- `build.py` owns source output and public result records. `compiler/` owns the
+ native commands it receives.
+- A `.pyi` build treats its edited entry contract as authoritative for the
+ Python API; it does not reparse native source to reconstruct that API.
+- Path-set `.pyi` caches are operation-local. They must not become process-wide
+ because later stages attach and freeze data.
- ```python
- complete_semantic_policies(module)
- plan = WrapperPlanner().build(module)
- generated = WrapperGenerator().generate(plan)
- ```
+The sole generation route is:
- Unsupported completed policy fails with its exact owner before either
- backend emits source.
-- `.pyi` builds reuse the same backend but take API/ABI facts from one edited
- entry contract plus explicit native inputs; they never reparse native source
- to reconstruct the Python API.
+```python
+complete_semantic_policies(module)
+plan = WrapperPlanner().build(module)
+generated = WrapperGenerator().generate(plan)
+```
-## Failure Ownership
+Unsupported policy fails at its owner before either backend emits source.
-| Failure | Earliest owner |
-| --- | --- |
-| Compiler preprocessing or native include expansion | preprocessing |
-| Required target facts cannot be measured | preprocessing probe |
-| Source syntax cannot be represented | parser |
-| Source facts cannot form a contract | semantic conversion |
-| Lifetime, ABI, projection, or support is unsafe | policy completion |
-| Completed policy is inconsistent while projected | planning |
-| A supported plan lacks an emitted mechanism | binding or bridge generator |
-| Native command or link plan is wrong | compiler or build pipeline |
-| Imported runtime behavior is wrong | generated binding, runtime support, or upstream policy according to cause |
+## Failure Boundary
+
+Pipeline code reports invalid public build inputs, output modes, artifact
+layout, manifests, and imported-result handling. It delegates source facts to
+preprocessing and parsing; shared meaning to semantics; interoperability to
+policy; completed-operation consistency to planning; emitted mechanisms to
+code generation; text to printers; and native commands to compiler. Start
+debugging with the first wrong representation or result, not with the final
+build failure.
diff --git a/docs/developer/packages/planning.md b/docs/developer/packages/planning.md
index 66488f312..7662f8b81 100644
--- a/docs/developer/packages/planning.md
+++ b/docs/developer/packages/planning.md
@@ -1,13 +1,13 @@
---
-title: Planning Package
+title: Planning Stage
audience: developers, maintainers, contributors
prerequisites: contributor architecture guide, completed policy
-related: ../architecture.md, index.md, policy.md, codegen.md, ../source-map.md
+related: ../architecture.md, index.md, policy.md, codegen.md, ../codebase-map.md
status: maintained
-publication: draft
+publication: reviewed
---
-# Planning Package
+# Planning Stage
## Purpose And Boundaries
@@ -30,10 +30,10 @@ prik/planning/
```text
policy-completed SemanticModule
- -> WrapperPlanner validation and projection
+ -> WrapperPlanner validates completed records and projects views
-> editable ModulePlan
-> freeze at WrapperGenerator boundary
- -> backend node generation
+ -> binding and bridge node generation
```
## Directory Tour
@@ -53,14 +53,15 @@ actions, and module variables:
```text
ModulePlan
- -> binding and bridge module views
- -> NamespacePlan
- -> FunctionPlan
- -> ArgumentTransferPlan
- -> ResultPlan
- -> NativeCallSlotPlan
- -> LifecycleActionPlan
- -> ModuleVariablePlan
+├── BindingModulePlan
+├── BridgeModulePlan
+└── NamespacePlan (root and child namespaces)
+ ├── FunctionPlan
+ │ ├── ArgumentTransferPlan
+ │ ├── ResultPlan
+ │ ├── NativeCallSlotPlan
+ │ └── LifecycleActionPlan
+ └── ModuleVariablePlan
```
Each argument or result owns explicit binding and bridge views. Its native-call
@@ -73,7 +74,48 @@ conventions, and one candidate ID per overload set. Generated dispatch chooses
an ID before making a native call, preserving first-match behavior for
overlapping optional domains without speculative calls.
-## Execution Examples
+## Module Algorithms
+
+### `planner.py`: completed policy to namespace tree
+
+`WrapperPlanner.build()` is the public boundary. It accepts one
+policy-completed `SemanticModule` and dispatches it through the planner's
+visitor. The completed-policy accessors used during projection reject missing
+or blocked records, so planning cannot fill in a default.
+
+For each module, the planner resets its derived-type and field indexes, then
+assigns backend symbols, qualifying only genuinely colliding native type names.
+It projects direct functions and variables, then uses `_ClassPolicyCatalog` to
+join each public class to its completed derived-type, surface, method, and
+overload policies. The catalogue is read-only: it maps existing owner paths to
+their semantic declarations without deciding policy again.
+
+The planner attaches class and overload callables to the function collections
+that need their native entrypoints. It completes generated symbols, adds every
+required parent namespace, and creates namespace plans in root-first path
+order. Finally it collects headers selected by completed descriptor-handle
+plans and returns one editable `ModulePlan`.
+
+### `models.py`: shared plans and backend views
+
+`models.py` defines editable `StageRecord` plans. `ModulePlan` is the root;
+each `NamespacePlan` groups the public functions, variables, derived types,
+classes, and overloads for one Python path. A `FunctionPlan` owns call-wide
+ordering, while its transfers, results, native slots, and lifecycle actions
+carry the datatype-specific details.
+
+Binding and bridge records are separate facets of the same planned operation.
+For example, an `ArgumentTransferPlan` holds both backend views and shares its
+single `NativeCallSlotPlan` with `FunctionPlan.native_call_slots`. This prevents
+two backends from carrying independent interpretations of one ABI position.
+
+The plan remains editable only until `WrapperGenerator.generate()` validates
+and freezes it. Add presentation details to code generation, not planning.
+
+## Run The Workflows
+
+`models.py` constructs the smallest complete plan directly: a no-argument
+`ping()` export with a standalone native `PING` target.
```bash
python3 prik/planning/models.py
@@ -86,6 +128,13 @@ Native procedure: PING
Native slots: 0
```
+The two names show the separate Python and native views carried by one plan.
+Zero slots is complete for a no-argument subroutine; it is not an omitted
+decision.
+
+`planner.py` follows the normal route. It constructs one `Float64` function,
+completes its semantic policy, then asks `WrapperPlanner` to project the plan.
+
```bash
python3 prik/planning/planner.py
```
@@ -97,16 +146,18 @@ Native target: DOUBLE_VALUE
Conversion order: ('planner_demo.double_value.value',)
```
-The model example demonstrates representation. The planner example follows
-the real sequence—semantic IR, policy completion, then planning—and shows the
-stable role connecting binding conversion to the native call slot.
+The conversion-order owner path is the stable link between binding conversion
+and the matching native call slot. It is copied from completed policy rather
+than reconstructed by either backend.
-## Tests And What They Prove
+## Tests And Evidence
-- [Plan model tests](../../../tests/fortran/infrastructure/codegen/test_plan.py) protect plan-record shape and freeze behavior.
-- [Planner tests](../../../tests/fortran/infrastructure/codegen/test_planner.py) protect validation, projection, symbols, and order.
-- [Feature-local codegen stages](../../../tests/fortran/) protect plan use for each supported feature.
-- [Direct execution inventory](../../../tests/fortran/infrastructure/execution_examples/test_execution_examples.py) fixes the model and planner outputs above.
+| Evidence | What it establishes |
+| --- | --- |
+| [Planner](../../../tests/fortran/infrastructure/codegen/test_planner.py) | Namespace grouping, exports, class lookup, array projection, and failure on missing, empty, or unsupported policy. |
+| [Plan ownership and freezing](../../../tests/fortran/infrastructure/pipeline/test_wrapper_generator.py) | A plan is editable before generation; the generator validates and freezes it before backend and printer use. |
+| [Overload dispatch plans](../../../tests/fortran/generic_interfaces/codegen/test_overload_dispatch_plan.py) | Candidate order, matching, and pre-call dispatch for supported generic interfaces. |
+| [Native handle planning](../../../tests/fortran/memory_management/codegen/test_native_handle_planning.py) | Descriptor-handle state, operation sets, required headers, and central plan validation. |
## Change Routes
@@ -116,7 +167,7 @@ stable role connecting binding conversion to the native call slot.
policy first.
- Change emitted temporaries or syntax downstream in codegen.
-## Invariants And Common Mistakes
+## Boundaries And Invariants
- Missing completed policy is an error, never a reason to infer a default.
- Binding and bridge views may share one ABI contract without hiding their
@@ -126,3 +177,11 @@ stable role connecting binding conversion to the native call slot.
keep their function-wide order explicit.
- Lifecycle actions stay explicit because cleanup and writeback order may span
several transfers and differ on failure.
+
+## Failure Boundary
+
+Planning reports a missing, blocked, inconsistent, or unexported completed
+policy; it also reports impossible plan relationships such as a missing native
+slot or unsupported datatype family. It delegates semantic and support
+decisions to `policy/`, and emitted syntax to `codegen/`. Start with the first
+invalid policy or plan record, not a binding, bridge, or compiler symptom.
diff --git a/docs/developer/packages/policy.md b/docs/developer/packages/policy.md
index 376f069e7..bc16dc8d3 100644
--- a/docs/developer/packages/policy.md
+++ b/docs/developer/packages/policy.md
@@ -1,21 +1,21 @@
---
-title: Policy Package
+title: Policy Stage
audience: developers, maintainers, contributors
prerequisites: contributor architecture guide, semantic IR
related: ../architecture.md, index.md, semantics.md, planning.md, runtime.md, ../../user/guide/memory-management.md
status: maintained
-publication: draft
+publication: reviewed
---
-# Policy Package
+# Policy Stage
## Purpose And Boundaries
`prik/policy/` is the final semantic authority before planning. It turns raw
-semantic facts and metadata into complete immutable interoperability decisions:
-public exports, object kind, owner, transfer, destruction, storage, mutability,
-writeback, nullability, projection, lifecycle, descriptor operations, setter
-behavior, and support blockers.
+semantic facts and metadata into complete, immutable interoperability
+decisions: public exports, object kind, owner, transfer, destruction, storage,
+mutability, writeback, nullability, projection, lifecycle, descriptor
+operations, setter behavior, and support blockers.
Planning, binding, bridge, and runtime code consume these decisions. They may
validate and dispatch from them, but may not infer an alternative answer from
@@ -39,10 +39,10 @@ prik/policy/
```text
SemanticModule + normalized raw metadata
- -> export completion and semantic graph completion
- -> ownership, callable, class, result, and descriptor-policy construction
- -> complete_semantic_policies()
- -> immutable completed policy attached to semantic IR
+ -> entry-export filtering and Python export completion
+ -> ownership and accessor decisions
+ -> class, callable, result, overload, and descriptor policy construction
+ -> immutable completed policies attached to semantic IR
-> WrapperPlanner
```
@@ -60,13 +60,79 @@ downstream fallback.
| [`prik/policy/exports.py`](../../../prik/policy/exports.py) | `PythonExportPolicy`, `complete_python_export_policy()`, and `completed_python_exports()` create collision-checked Python placement. | Export namespace, visibility, or collision behavior changes. |
| [`prik/policy/construction.py`](../../../prik/policy/construction.py) | Feature constructors build coherent function, result, native-slot, callback, class, overload, and module-variable policies from completed ownership decisions. | A supported feature needs different completed policy composition. |
| [`prik/policy/completion.py`](../../../prik/policy/completion.py) | `complete_semantic_policies()` runs the dependency-ordered completion pass, attaches outcomes, and validates blockers. | Completion order, cross-declaration completion, or the stage boundary changes. |
-| [`prik/policy/native_array_handles.py`](../../../prik/policy/native_array_handles.py) | `NativeArrayHandlePolicy`, interop/handle/projection dispatchers, and build-requirement records complete descriptor operations and selected ABI/build requirements. | Descriptor-backed array behavior, ABI selection, allowed operations, or build headers change. |
+| [`prik/policy/native_array_handles.py`](../../../prik/policy/native_array_handles.py) | `NativeArrayHandlePolicy`, ABI selectors and dispatchers, and `native_array_handle_build_requirements()` describe already-completed descriptor handles and their build requirements. | Descriptor-backed array ABI selection, allowed operations, dispatch, or build headers change. |
-Start with `completion.py` to see the order, follow its call into the focused
-resolver or constructor, and finish in `models.py` to confirm the durable
-output. Do not begin in code generation when the question is semantic.
+`completion.py` shows the dependency order. `ownership.py` and
+`construction.py` contain the focused decision rules; `models.py` is the
+durable output vocabulary that planning reads.
-## How To Read A Completed Decision
+## Module Algorithms
+
+### `completion.py`: one ordered completion pass
+
+`complete_semantic_policies()` accepts one `SemanticModule` or an iterable,
+updates each module in place, and returns the same modules in input order. It
+first limits declarations to explicit entry exports when that metadata is
+present, then completes collision-checked Python export names.
+
+The remaining order is intentional. It resolves local derived-type identities,
+then persistent module variables and their accessors. It completes classes,
+their derived-type graph, surfaces, methods, and overloads before building
+module-variable policies. Finally it completes direct functions, overload
+candidates, and module overload tables, then marks the module prepared for
+planning. Later steps depend on records attached by earlier ones.
+
+### `ownership.py`: lifetime facts to lowering-ready decisions
+
+`OwnershipPolicyResolver` is the primitive used during completion. For one
+semantic type and its context—argument, result, field, getter, setter, or
+module variable—it derives storage facts, selects a default for the object
+kind, applies declared ownership and pointer requests, and validates alias,
+pointer, immutability, projection, and lifetime combinations.
+
+Only after that validation does it attach boundary storage and the Python,
+native, and code-generation actions. An unsupported combination remains a
+blocked `OwnershipDecision` with its reason; no later stage chooses a
+substitute. `decide_semantic_variable()`, `decide_semantic_getter()`, and
+`decide_semantic_setter()` apply the same rule to their specific locations.
+
+### `construction.py`: decisions to wrapper-facing records
+
+The construction helpers combine completed decisions into immutable records
+for functions, results, native call slots, module variables, derived types,
+classes, overloads, callbacks, transformations, and lifecycles.
+
+For a function, `build_function_wrapper_policy()` fixes native-slot order,
+projects visible arguments, completes result and declaration-callable records,
+binds declaration extents, records writeback and cleanup, and aggregates all
+support blockers. The resulting `FunctionWrapperPolicy` is the planner's
+complete description of the wrapper mechanism;
+`completed_function_wrapper_policy()` rejects absent or blocked records at
+that boundary.
+
+### `exports.py` and `native_array_handles.py`: focused completion products
+
+`complete_python_export_policy()` writes one collision-checked Python name for
+each public declaration in its namespace. `completed_python_exports()` reads
+those names as immutable `PythonExportPolicy` records while assembling a
+wrapper policy.
+
+`completion.py` creates native-array handle policies for descriptor-backed
+arrays. `native_array_handles.py` carries those records through the rest of
+the build: `array_interop_policy()` selects ordinary data-buffer or descriptor
+ABI, dispatchers select the preplanned handler, and
+`native_array_handle_build_requirements()` collects required generated-code
+headers from completed modules.
+
+### `models.py`: the durable vocabulary
+
+`models.py` groups frozen records and enums by what later stages must know:
+argument/result and native-slot handoff, array and descriptor handling,
+lifecycle and transformations, callbacks, derived types and class surfaces,
+overloads, module variables, and native status errors. It defines the data
+shape of a completed decision; it does not choose one.
+
+## Completed Decision Vocabulary
Policy keeps related questions separate. This makes aliases, copies, views,
and cleanup auditable instead of encoding them in one overloaded `owned`
@@ -103,7 +169,7 @@ The binding and bridge may create local temporary variables inside a selected
implementation method, but those are emitted-code details. They are not a
license to choose a new semantic policy.
-## Execution Examples
+## Run The Workflows
Completed record immutability:
@@ -117,6 +183,10 @@ Lifecycle policy: copy_out writeback via copy_in_out
Completed record mutation rejected: True
```
+The script creates completed array and lifecycle records, then attempts to
+change one field. `True` confirms that completed policy is immutable once a
+decision is ready for planning.
+
Ownership resolution:
```bash
@@ -128,6 +198,10 @@ before: math.scale(value): Float64 semantic IR
after: scalar/caller/call_local; scalar_value -> pass_value
```
+It gives the resolver one raw scalar argument context. The `after` line names
+the selected object kind, owner, transfer, and the Python-to-native mechanism
+that later stages must consume unchanged.
+
Public export completion:
```bash
@@ -140,6 +214,10 @@ Python export: linear_algebra.scale_value
Completed policy type: PythonExportPolicy
```
+The script adds one export request to a semantic function and completes it.
+The output separates the native owner from the public Python path and confirms
+that the path is now a completed policy record.
+
Feature-policy construction:
```bash
@@ -151,6 +229,10 @@ before: math.scale(value): Float64 semantic IR
after: direct_transfer; result=native_scalar; native=pass_value
```
+This example supplies already resolved scalar ownership for one argument and
+result, then builds only the function policy. Its output shows the resulting
+bridge transfer, result ABI, and native call action—not generated source.
+
Full ordered completion:
```bash
@@ -162,6 +244,10 @@ before: math.scale(value): Float64 semantic IR
after: math.scale(value): scalar_value -> pass_value
```
+Here the script starts with raw semantic IR and invokes the full completion
+sequence. The final conversion pair shows the exact completed actions that the
+planner will project into both backend views.
+
Descriptor-backed array completion:
```bash
@@ -175,16 +261,22 @@ Array ABI: descriptor
Selected build header: ISO_Fortran_binding.h
```
+The script marks a pointer array as a native handle and supplies its completed
+handle policy. The result links its allowed Python operations and alias storage
+to the descriptor ABI and build header required downstream.
+
The outputs move from raw semantic facts to immutable decisions. They do not
generate source; that begins only after planning.
-## Tests And What They Prove
+## Tests And Evidence
-- [Policy infrastructure](../../../tests/fortran/infrastructure/semantics/) covers policy records, completion order, and general semantic-policy rules.
-- [Native handle policy](../../../tests/fortran/infrastructure/semantics/test_native_array_handles.py) covers descriptor policy, allowed operations, and ABI requirements.
-- [Feature-local policy suites](../../../tests/fortran/) cover ownership and projection decisions for the supported wrapper features.
-- [Planner tests](../../../tests/fortran/infrastructure/codegen/test_planner.py) prove that planning rejects incomplete policy instead of filling it in.
-- [Direct execution inventory](../../../tests/fortran/infrastructure/execution_examples/test_execution_examples.py) fixes the six demonstrations above.
+| Evidence | What it establishes |
+| --- | --- |
+| [Policy completion](../../../tests/fortran/infrastructure/semantics/test_policy_completion.py) | Completion precedes lowering; accessor, projection, and missing-conversion failures remain explicit. |
+| [Wrapper policy](../../../tests/fortran/infrastructure/semantics/test_wrapper_policy.py) | Function, result, call-slot, array, export, status, and support policies are complete before planning. |
+| [Ownership policy](../../../tests/fortran/memory_management/policy/test_memory_ownership_policy.py) | Contradictory explicit ownership contracts fail before lowering. |
+| [Descriptor handle policy](../../../tests/fortran/allocatables/policy/test_allocatable_handle_policy.py) | Allocatable descriptor-handle decisions, ownership, access, and support blockers. |
+| [Planner boundary](../../../tests/fortran/infrastructure/codegen/test_planner.py) | Planning rejects a missing completed wrapper policy instead of filling it in. |
## Change Routes
@@ -201,7 +293,7 @@ generate source; that begins only after planning.
- Project an already completed fact in planning; lower an already selected
mechanism in codegen. Neither is a replacement policy owner.
-## Invariants And Common Mistakes
+## Boundaries And Invariants
- Completion order stays explicit; do not replace it with an opaque pass
registry.
@@ -211,5 +303,14 @@ generate source; that begins only after planning.
are distinct ABI choices.
- A valid source declaration or `.pyi` annotation is not proof of safe
wrapper support.
-- If a generator guesses a decision, move that decision into policy completion
- and add the focused policy test before changing lowering.
+- If a generator needs a decision, make it explicit in policy completion and
+ add focused policy evidence before changing lowering.
+
+## Failure Boundary
+
+This stage reports incomplete, contradictory, or unsupported interoperability
+contracts, including missing ownership, unsafe lifetime combinations, invalid
+projection, unavailable accessor behavior, and unsupported wrapper mechanisms.
+It delegates parser and semantic facts to earlier stages, and it delegates
+planning, rendering, and native compilation to later stages. Diagnose the first
+incorrect completed policy or blocker, not a later generated-code symptom.
diff --git a/docs/developer/packages/preprocessing.md b/docs/developer/packages/preprocessing.md
index 4eaa6c678..99980cb76 100644
--- a/docs/developer/packages/preprocessing.md
+++ b/docs/developer/packages/preprocessing.md
@@ -1,71 +1,124 @@
---
-title: Preprocessing Package
+title: Preprocessing Stage
audience: developers, maintainers, contributors
prerequisites: contributor architecture guide, native project compiler flags
-related: ../architecture.md, index.md, parsers.md, semantics.md, ../concepts/datatype-lifecycle.md
+related: ../architecture.md, index.md, parsers.md, semantics.md
status: maintained
-publication: draft
+publication: reviewed
---
-# Preprocessing Package
+# Preprocessing Stage
## Purpose And Boundaries
-`prik/preprocessing/` turns original Fortran source into authoritative parser
-input and measures compiler-dependent target facts needed by semantic
-conversion. Compiler expansion, native Fortran includes, and executable probes
-are separate mechanisms with separate results. The package does not parse
-declarations, assign semantic scalar identities, choose NumPy dtypes, or
-complete wrapper policy.
+`prik/preprocessing/` turns original Fortran source into parser input and
+measures the compiler-dependent facts that semantic conversion needs. It owns
+compiler invocation, source provenance, native `INCLUDE` expansion, and
+target probes. It does not parse declarations, construct semantic IR, choose
+semantic scalar identities, or complete wrapper policy.
-## Local Structure
-
-```text
-prik/preprocessing/
-├── __init__.py
-├── source.py
-├── fortran.py
-└── probes/
- ├── __init__.py
- └── fortran_types.py
-```
+The package contains early C-frontend modules: `c.py` collects raw directive
+metadata and `probes/c_types.py` measures C ABI facts. C support is not yet
+complete; a future C frontend may build on them. They do not participate in
+the current Fortran wrapper path.
-The C preprocessing and target-probe modules remain deferred from the
-published Fortran contributor workflow.
+## A Fortran Source Through This Stage
-## What This Stage Receives And Produces
+The primary route is `preprocess_source()` in `source.py`. It retains the
+prepared source and the facts that explain how it was produced:
```text
-original Fortran path + PreprocessingConfig
- -> compiler expansion and line-marker recovery
+Fortran source path + PreprocessingConfig
+ -> select compiler command: direct compiler, compile database, or template
+ -> compiler-expanded source
+ -> source mappings, dependencies, optional macros, diagnostics, and recipe
-> native Fortran INCLUDE expansion
- -> PreprocessResult(source, provenance, dependencies, recipe, diagnostics)
+ -> PreprocessResult.source
-> Fortran parser
-compiler identity + target flags + kind/storage requirements
- -> executable target probe
- -> FortranTypeProbeReport
+semantic requirements + compiler and target configuration
+ -> Fortran type probe: generate, compile, and run a small program
+ -> FortranTypeProbeReport(values, recipe, source_text)
-> Fortran-to-IR conversion
```
-Recipes retain compiler, adapter, argv, include directories, macro flags,
-included files, source mappings, and diagnostics so a build can explain or
-replay its parser input. Probe cache identity includes the compiler and target
-configuration; measured facts must not cross targets silently.
+`PreprocessResult` is prepared parser input plus provenance; it is not parsed
+syntax or semantic meaning. `FortranTypeProbeReport` is a compiler measurement
+plus its recipe; it is not a stable semantic scalar or NumPy dtype.
-## Directory Tour
+## Local Structure
-| Module | Main entrypoints and contents | Change it when |
-| --- | --- | --- |
-| [`prik/preprocessing/__init__.py`](../../../prik/preprocessing/__init__.py) | Re-exports the supported source-preparation records, adapters, and entrypoints, including `expand_native_fortran_includes()`. | The supported preprocessing import API changes. |
-| [`prik/preprocessing/source.py`](../../../prik/preprocessing/source.py) | `PreprocessingConfig`, `PreprocessingPlan`, `PreprocessingRecipe`, `PreprocessResult`, `SourceMapping`, and `IncludedFile`; builds compiler invocations, runs them, recovers mappings, and retains diagnostics/provenance. | Compiler-preprocessor adapters, recipes, line-marker handling, source provenance, or diagnostics change. |
-| [`prik/preprocessing/fortran.py`](../../../prik/preprocessing/fortran.py) | `expand_native_fortran_includes()` expands native `INCLUDE` directives recursively while preserving locations and diagnostics. | Native Fortran include discovery or expansion changes. |
-| [`prik/preprocessing/probes/__init__.py`](../../../prik/preprocessing/probes/__init__.py) | Namespace marker for compiler-derived target facts. | A probe-level public import surface is deliberately introduced. |
-| [`prik/preprocessing/probes/fortran_types.py`](../../../prik/preprocessing/probes/fortran_types.py) | `FortranTypeProbeRecipe` and `FortranTypeProbeReport` compile and run small target programs for kind expressions, storage widths, logical representations, and compile-time values. | Measured fact generation, validation, cache identity, or probe execution changes. |
+```text
+prik/preprocessing/
+├── __init__.py
+├── source.py
+├── fortran.py
+├── c.py deferred C inspection support
+└── probes/
+ ├── fortran_types.py
+ └── c_types.py deferred C inspection support
+```
-## Execution Examples
+## Directory Tour
-Coordinated preprocessing:
+| Module | Public boundary and result | Change it when |
+| --- | --- | --- |
+| [`prik/preprocessing/__init__.py`](../../../prik/preprocessing/__init__.py) | Re-exports the supported shared source-preparation records, adapters, and entrypoints. | The shared preprocessing import surface changes. |
+| [`prik/preprocessing/source.py`](../../../prik/preprocessing/source.py) | `preprocess_source()` is the compiler-backed route. `PreprocessingConfig` selects its command; `PreprocessResult` returns expanded text, provenance, and diagnostics. | Compiler adapters, invocations, recipes, mappings, dependencies, macros, or diagnostics change. |
+| [`prik/preprocessing/fortran.py`](../../../prik/preprocessing/fortran.py) | `expand_native_fortran_includes()` turns remaining textual `INCLUDE` statements into parser input while retaining mappings and diagnostics. | Native Fortran include discovery or expansion changes. |
+| [`prik/preprocessing/probes/fortran_types.py`](../../../prik/preprocessing/probes/fortran_types.py) | `evaluate_fortran_type_requirements()` and `evaluate_fortran_type_facts()` turn semantic requirements into cached compiler measurements; `FortranTypeProbeReport` retains values and recipe. | Fortran fact generation, validation, cache identity, or semantic-facing probe results change. |
+
+## Module Workflows
+
+### `source.py`: compiler-backed parser input
+
+`preprocess_source()` is the normal boundary. Start with it when changing the
+prepared-source path. It validates `PreprocessingConfig`, then
+`build_preprocess_invocation()` selects a command-template, compile-database,
+or direct-compiler invocation. It executes that invocation, collects compiler
+line markers, dependencies, optional macros, and diagnostics, then delegates
+remaining native Fortran `INCLUDE` statements to `fortran.py`.
+
+The public records divide the work: `PreprocessingPlan` and `Invocation`
+describe a request and command before execution; `PreprocessingRecipe` and
+`PreprocessResult` record the completed operation; `SourceMapping`,
+`IncludedFile`, `MacroDefinition`, and `PreprocessingDiagnostic` retain its
+side facts. The convenience runners return only source or source plus a typed
+recipe; use `preprocess_source()` when the next stage needs the complete
+result.
+
+The source is organized in the same order: configuration and validation,
+adapter facades, invocation construction, provenance recovery, then execution
+and result assembly. Private helpers belong to one of those phases.
+
+### `fortran.py`: native includes after compiler expansion
+
+`expand_native_fortran_includes()` receives an already compiler-expanded
+Fortran stream. It resolves an `INCLUDE` beside its including source before the
+configured directories, expands it recursively, and returns parser text,
+dependency edges, source mappings, and diagnostics. It records a missing file
+or cycle rather than making parser decisions; `source.py` promotes error
+diagnostics after assembling the complete result.
+
+### `probes/fortran_types.py`: target facts for semantic conversion
+
+The module generates a small Fortran program, compiles and runs it for the
+configured target, validates its result, and caches the report by compiler,
+flags, runner, environment, and generated source.
+
+`evaluate_fortran_type_requirements()` and
+`evaluate_fortran_type_facts()` receive semantic requirement records. They
+reuse a supplied or cached `FortranTypeProbeReport` and return the values that
+the Fortran semantic converter needs. `probe_fortran_type_expressions()` is
+the uncached measurement boundary; `probe_fortran_type_expressions_cached()`
+is the normal repeated-use boundary. A report is valid only for the target
+identity encoded in its recipe and cache key.
+
+## Run The Workflows
+
+`source.py` demonstrates the source-preparation handoff. Its complete direct
+example also prints a small C source-preparation demonstration; C frontend
+support remains future work.
```bash
python3 prik/preprocessing/source.py
@@ -75,15 +128,30 @@ python3 prik/preprocessing/source.py
Before Fortran include expansion:
module greeting
include 'constants.inc'
-...
+contains
+subroutine show_answer()
+print *, answer
+end subroutine show_answer
+end module greeting
+
After Fortran include expansion:
module greeting
integer, parameter :: answer = 42
-...
+contains
+subroutine show_answer()
+print *, answer
+end subroutine show_answer
+end module greeting
Native includes: 1; diagnostics: 0
+...
```
-Native include expansion in isolation:
+The script supplies a small module with one include and prints the parser input
+before and after preprocessing. The replacement of the `include` line, plus
+the dependency and diagnostic counts, shows that source expansion preserves
+the information needed by the parser without reporting a problem.
+
+The Fortran-specific module shows the parser input and provenance it returns:
```bash
python3 prik/preprocessing/fortran.py
@@ -99,7 +167,12 @@ Generated source mappings: 5
Diagnostics: 0
```
-Compiler-measured Fortran type facts:
+This narrower example prepares one Fortran source with one native include. Its
+expanded text is the parser input; the mapping count records how generated
+lines still lead back to their source locations.
+
+The target-probe example shows a compiler measurement, not a fixed semantic
+type. It requires `gfortran` or `f95`.
```bash
python3 prik/preprocessing/probes/fortran_types.py
@@ -109,31 +182,42 @@ python3 prik/preprocessing/probes/fortran_types.py
selected_int_kind(9) = 4
```
-The first two outputs prove that prepared source retains dependency and source
-mapping facts. The probe output is a native kind value, not yet a stable
-semantic scalar or NumPy dtype. The probe example requires `gfortran` or
-`f95`.
+The reported number is target-dependent. The example establishes that the
+compiler, rather than PRIK, supplied the fact.
-## Tests And What They Prove
+## Tests And Evidence
-- [Fortran preprocessing](../../../tests/fortran/source_preprocessing/preprocessing/) covers adapters, recipes, mappings, dependencies, and diagnostics.
-- [Parser boundary tests](../../../tests/fortran/source_preprocessing/preprocessing/test_parser_boundaries.py) prove that prepared source reaches parsing with preserved facts.
-- [Fortran target probes](../../../tests/fortran/data_types/probes/test_fortran_type_probes.py) cover measured type facts and cache separation.
-- [Direct execution inventory](../../../tests/fortran/infrastructure/execution_examples/test_execution_examples.py) fixes the three demonstrations above.
+| Evidence | What it establishes |
+| --- | --- |
+| [Fortran preprocessing](../../../tests/fortran/source_preprocessing/preprocessing/) | Adapters, recipes, mappings, native includes, diagnostics, and parser handoffs. |
+| [Parser boundaries](../../../tests/fortran/source_preprocessing/preprocessing/test_parser_boundaries.py) | Prepared source reaches parsing with preserved facts and unsupported raw constructs stop at the correct boundary. |
+| [Fortran type probes](../../../tests/fortran/data_types/probes/test_fortran_type_probes.py) | Compiler facts, requirement evaluation, cache separation, and report validation. |
## Change Routes
-- Change compiler expansion, provenance, recipes, or diagnostics in
+- Change compiler expansion, commands, provenance, recipes, or diagnostics in
`source.py`.
-- Change native `INCLUDE` behavior in `fortran.py`.
-- Change target measurement or cache identity in `probes/fortran_types.py`.
-- Change parser grammar downstream; change stable scalar identity or backend
- mapping in the owning semantic/codegen package.
-
-## Invariants And Common Mistakes
-
-- Preserve original source coordinates through every source transformation.
-- Run native probes in temporary working directories so `.mod` and other
- compiler products cannot pollute the repository.
-- Do not combine textual preprocessing and target measurement into one generic
- operation simply because both run before parsing.
+- Change native Fortran `INCLUDE` behavior in `fortran.py`.
+- Change compiler-measured Fortran facts or cache identity in
+ `probes/fortran_types.py`.
+- Change stable scalar identity in `semantics/`, backend dtype projection in
+ `codegen/`, and wrapper behavior in the later owning stage.
+
+## Boundaries And Invariants
+
+- Preserve original coordinates through every source transformation.
+- Keep compiler expansion, native include expansion, and target measurement
+ as separate operations.
+- Run probes in temporary directories so compiler products cannot enter the
+ repository.
+- Do not reuse source provenance or a probe report across a materially
+ different compiler target.
+
+## Failure Boundary
+
+This stage reports invalid preprocessing configuration, compiler execution
+failures, missing native includes, include cycles, and invalid probe results.
+It delegates declaration syntax to `parsers/`, stable meaning to `semantics/`,
+and wrapper support to later stages. Start with the first incorrect prepared
+source, provenance record, or compiler fact—not the later parser or build
+failure.
diff --git a/docs/developer/packages/printers.md b/docs/developer/packages/printers.md
index de8ced5a1..a5b71e9ae 100644
--- a/docs/developer/packages/printers.md
+++ b/docs/developer/packages/printers.md
@@ -1,13 +1,13 @@
---
-title: Printers Package
+title: Printing Stage
audience: developers, maintainers, contributors
prerequisites: contributor architecture guide, formed source representations
related: ../architecture.md, index.md, codegen.md, pipeline.md, parsers.md
status: maintained
-publication: draft
+publication: reviewed
---
-# Printers Package
+# Printing Stage
## Purpose And Boundaries
@@ -47,7 +47,52 @@ The fact that code generation calls a printer at the end of wrapper rendering
does not make printing part of codegen ownership. `pipeline/wrapper.py`
coordinates both distinct stages.
-## Execution Examples
+## Module Algorithms
+
+### `c.py`: C nodes to C text
+
+`CSourcePrinter.doprint()` is the public entrypoint. It freezes a supplied
+`StageRecord`, dispatches it through the C node visitor, and returns text. A
+`CModule` is rendered in compiler order: macro definitions, includes,
+declarations, then functions. A `CHeader` adds its guard around includes and
+prototypes.
+
+The remaining visitors add C punctuation, indentation, signatures, and string
+escaping to node-selected values. CPython method tables and module-property
+support are serialized from their C nodes; no semantic model or wrapper plan is
+consulted.
+
+### `fortran.py`: Fortran nodes to free-form text
+
+`FortranSourcePrinter.doprint()` likewise freezes a supplied node and renders
+it through the Fortran visitor. A module is emitted in Fortran specification
+and body order: uses, type definitions, interfaces, declarations, then
+procedures and standalone procedures.
+
+After rendering, the printer wraps overlong free-form lines at safe whitespace
+or comma boundaries. It can continue string literals without changing their
+value, never splits comments or doubled-quote escapes, and rejects an
+unsplittable line that remains above the 132-column compiler-safe limit.
+
+### `pyi.py`: semantic IR to an editable contract
+
+`PyiPrinter.emit()` creates a fresh `_PyiEmissionContext` for every call. The
+context records contract imports, aliases, public-name reservations, source
+array defaults, and nested namespaces without mutating a reusable printer or
+the semantic IR.
+
+For a module, the printer first renders public classes, prototypes, variables,
+functions, and overload sets into body sections. As visitors use contract
+symbols, the shared context records imports; final import sections are then
+placed before the body. Visitors preserve semantic native identity,
+projections, storage, imports, and contract annotations, but do not complete
+wrapper policy. `emit_module()` is the normal one-module convenience entrypoint
+and still creates a fresh context.
+
+## Run The Workflows
+
+`c.py` constructs one small C module containing a `wrap_ping` function and
+passes that already formed node tree to `CSourcePrinter`.
```bash
python3 prik/printers/c.py
@@ -63,6 +108,12 @@ static PyObject * wrap_ping(PyObject * self) {
}
```
+The include, C signature, indentation, and semicolons are printer work. The
+example contains no semantic model or wrapper plan for the printer to inspect.
+
+`fortran.py` constructs one bridge module with explicit `iso_c_binding` and
+native-module uses, then prints its one bridge function.
+
```bash
python3 prik/printers/fortran.py
```
@@ -82,6 +133,12 @@ contains
end module bind_c_printer_demo_wrapper
```
+The result preserves the declared use order and native alias, then applies
+Fortran declaration, procedure, and indentation syntax to the supplied nodes.
+
+`pyi.py` constructs one semantic `double_value` function with `Float64` types
+and a native `DOUBLE_VALUE` identity, then emits one contract module.
+
```bash
python3 prik/printers/pyi.py
```
@@ -97,14 +154,17 @@ def double_value(
```
The native examples prove that punctuation and layout are added to already
-formed nodes. The `.pyi` example proves that required contract imports and
-native identity are derived without attaching wrapper policy.
+formed nodes. The `.pyi` import and `@bind` line show that required contract
+imports and native identity are derived from semantic IR without attaching
+wrapper policy.
-## Tests And What They Prove
+## Tests And Evidence
-- [Printer infrastructure](../../../tests/fortran/infrastructure/printers/) covers native syntax serialization and formatting.
-- [Semantic `.pyi` round trips](../../../tests/fortran/semantic_pyi_format/) cover contract emission and re-parsing.
-- [Direct execution inventory](../../../tests/fortran/infrastructure/execution_examples/test_execution_examples.py) fixes the three rendered examples above.
+| Evidence | What it establishes |
+| --- | --- |
+| [Native source printers](../../../tests/fortran/infrastructure/printers/test_source_printers.py) | C and Fortran serialization, rejection of wrapper plans, line wrapping, literal preservation, and unsplittable-line diagnostics. |
+| [Semantic `.pyi` conversion smoke](../../../tests/fortran/semantic_pyi_format/pipeline/test_pyi_printer_conversion_smoke.py) | Emitted contract fixtures can be parsed and converted through the normal semantic-`.pyi` route. |
+| [`.pyi` imports and packages](../../../tests/fortran/semantic_pyi_format/pipeline/test_pyi_printer_imports_and_packages.py) | Isolated emission state, imports, aliases, packages, name collisions, and opaque dependencies. |
## Change Routes
@@ -113,8 +173,18 @@ native identity are derived without attaching wrapper policy.
plan rather than consulting semantic IR from the printer.
- Change filenames or multi-source artifact order in the pipeline.
-## Invariants And Common Mistakes
+## Boundaries And Invariants
- Native source printers accept backend nodes, not semantic models.
- The `.pyi` printer accepts semantic IR, not wrapper plans.
-- Emission contexts are per-operation and restored safely after failures.
+- Each `.pyi` emission owns fresh context, so one failure cannot leak imports
+ or reserved names into the next emission.
+
+## Failure Boundary
+
+Native printers report unsupported node types and, for Fortran, a line that
+cannot be safely wrapped. The `.pyi` printer reports unsupported semantic
+models or invalid contract-emission facts. Printers delegate missing node facts
+to `codegen/` and missing semantic facts to earlier stages; they delegate file
+names and writing to `pipeline/`. Start with the first invalid node or semantic
+record, not the rendered text that exposes it.
diff --git a/docs/developer/packages/runtime.md b/docs/developer/packages/runtime.md
index 2326758d1..b4cbc6242 100644
--- a/docs/developer/packages/runtime.md
+++ b/docs/developer/packages/runtime.md
@@ -1,57 +1,67 @@
---
-title: Runtime Package
+title: Runtime Component
audience: developers, maintainers, contributors
prerequisites: contributor architecture guide, completed native handle policy
related: ../architecture.md, index.md, policy.md, compiler.md, pipeline.md
status: maintained
-publication: draft
+publication: reviewed
---
-# Runtime Package
+# Runtime Component
## Purpose And Boundaries
-`prik/runtime/` owns Python objects that remain active after importing a
-generated extension and the bundled native header payload used by generated
-bindings. Runtime objects validate descriptor metadata, retain owners, adapt
-generated operations, and expose policy-selected NumPy views. They enforce
-completed behavior; they do not decide ownership or invent missing operations.
+`prik/runtime/` provides Python objects used after a generated extension is
+imported and the native support compiled into generated bindings. It validates
+the operations and descriptor metadata supplied by the extension, retains
+required owners, and exposes the NumPy views permitted by completed policy.
+
+Runtime code enforces decisions already made by policy and represented in the
+wrapper plan. It does not decide ownership, invent a missing operation, or
+select a different view behavior from local descriptor facts.
+
+## A Native Array Handle At Runtime
+
+```text
+generated operation dictionary + dtype, rank, ownership, and view policy
+ -> NativeArrayHandleBase validation and owner retention
+ -> AllocatableArray or PointerArray
+ -> state, lifecycle, association, and to_numpy() operations
+```
+
+The operation dictionary is the boundary between generated extension code and
+the stable Python handle API. An operation exists only when the completed plan
+allows the generator to expose it. Missing operations fail explicitly rather
+than being inferred from `allocatable` or `pointer` alone.
## Local Structure
```text
prik/runtime/
-├── __init__.py
├── handles.py
└── native_support/
- ├── __init__.py
├── prik_binding.h
└── LICENSE
```
-## What This Stage Receives And Produces
-
-```text
-generated extension operation dictionary
- -> descriptor metadata validation
- -> AllocatableArray or PointerArray adapter
- -> policy-permitted allocate/deallocate/resize/nullify/to_numpy operations
-```
-
-The native-support initializer only makes the payload locatable. The compiler
-installs it into a generated `binding_support/` include directory.
-
-## Directory Tour
-
-| Path | Main entrypoints and contents | Change it when |
-| --- | --- | --- |
-| [`prik/runtime/__init__.py`](../../../prik/runtime/__init__.py) | Package boundary for Python runtime support. | A small supported runtime import surface is deliberately introduced. |
-| [`prik/runtime/handles.py`](../../../prik/runtime/handles.py) | `NativeArrayHandleBase`, `AllocatableArray`, and `PointerArray` validate generated operations, retain owners, and produce policy-permitted live NumPy views. | Handle protocol, validation, retention, descriptor conversion, or Python operation behavior changes. |
-| [`prik/runtime/native_support/__init__.py`](../../../prik/runtime/native_support/__init__.py) | Locates the bundled native-support payload without creating another Python runtime API. | Payload discovery changes. |
-| `runtime/native_support/prik_binding.h` | Bundled native capsule, descriptor, validation, conversion, and release support compiled into generated bindings. | A generated binding requires changed native support; also inspect `compiler/native_support.py` installation. |
-| `runtime/native_support/LICENSE` | License text distributed with the native payload. | The payload licensing changes. |
-
-## Execution Example
+- [`handles.py`](../../../prik/runtime/handles.py) contains the Python runtime.
+ `NativeArrayHandleBase` validates common metadata and operations.
+ `AllocatableArray` adds allocation state, resize, and deallocation;
+ `PointerArray` adds association, nullification, allocation, resize, and
+ deallocation when supplied. Internal adapters translate generated call
+ signatures and descriptor handoffs.
+- `native_support/prik_binding.h` contains header-only CPython/NumPy
+ conversion, descriptor, validation, capsule, and release support. Change it
+ only with its generated C users and `prik/compiler/native_support.py`.
+- `native_support/LICENSE` is distributed with the native payload.
+
+`to_numpy()` returns `None` for an absent allocatable or pointer and otherwise
+validates the completed view policy, dtype, rank, and any required contiguity.
+Native argument handoff performs the additional expected shape, layout,
+alignment, byte-order, and writeability checks. A returned NumPy array is a
+view of native storage; a caller that needs independent storage must copy it.
+
+## Run The Handle Demonstration
```bash
python3 prik/runtime/handles.py
@@ -65,35 +75,28 @@ Resized shape: (4,)
Generated resize received NumPy extents: True
```
-The example supplies the same operation dictionary shape exported by a
-generated extension. It proves descriptor selection, validation, operation
-adaptation, and the generated NumPy extent convention. The returned NumPy
-storage is live, not a detached snapshot.
-
-The native payload intentionally has no standalone Python example: it is
-compiled only as part of a generated binding.
+The example supplies the same operation-dictionary shape as generated code.
+It creates an allocatable handle, reads its live NumPy view, and routes a
+resize through the adapter. The native header has no standalone Python route;
+the compiler installs it into a generated `binding_support/` directory.
-## Tests And What They Prove
+## Change Routes And Evidence
-- [Allocatable runtime tests](../../../tests/fortran/allocatables/runtime/) cover allocatable operations and NumPy views.
-- [Pointer runtime tests](../../../tests/fortran/pointers/runtime/) cover pointer association and views.
-- [Memory-management runtime tests](../../../tests/fortran/memory_management/runtime/) cover release and ownership enforcement.
-- [Runtime infrastructure](../../../tests/fortran/infrastructure/runtime/) covers generated-operation protocols.
-- [Compiled runtime compatibility](../../../tests/fortran/building_shared_library/end_to_end/test_runtime_compatibility.py) covers the payload in a real extension.
-- [Direct execution inventory](../../../tests/fortran/infrastructure/execution_examples/test_execution_examples.py) fixes the handle demonstration above.
-
-## Change Routes
-
-- Change handle protocol, validation, retention, or adapters in `handles.py`.
-- Change header implementation in `native_support/` and installation in
+- Change handle protocol, validation, retention, views, or adapters in
+ `handles.py`.
+- Change the native payload together with its generated users and
`prik/compiler/native_support.py`.
-- Complete any new ownership, operation permission, or view policy upstream
- before runtime enforcement.
-
-## Invariants And Common Mistakes
-
-- Outstanding zero-copy NumPy views cannot be revoked after native
- reallocation or pointer reassociation. Callers must discard or copy them.
-- Runtime must reject operations absent from completed policy rather than
- guessing permission from descriptor kind.
-- The native support directory is a payload, not a second pipeline stage.
+- Complete new ownership, lifecycle, operation, or view policy before planning
+ rather than selecting it in runtime code.
+
+| Evidence | What it establishes |
+| --- | --- |
+| [Allocatable runtime tests](../../../tests/fortran/allocatables/runtime/) | Allocation state, operations, descriptor handoffs, and NumPy views. |
+| [Pointer runtime tests](../../../tests/fortran/pointers/runtime/) | Association, nullification, pointer descriptors, and views. |
+| [Memory-management runtime tests](../../../tests/fortran/memory_management/runtime/) | Owner retention, release, and array handoffs. |
+| [Native-support tests](../../../tests/fortran/infrastructure/runtime/) | Bundled payload discovery and installation inputs. |
+| [Compiled runtime compatibility](../../../tests/fortran/building_shared_library/end_to_end/test_runtime_compatibility.py) | The payload and Python runtime working through a real extension. |
+
+An outstanding zero-copy NumPy view cannot be revoked after native
+reallocation, deallocation, or pointer reassociation. Users must discard or
+copy such views before changing the native storage.
diff --git a/docs/developer/packages/semantics.md b/docs/developer/packages/semantics.md
index 496f9dbb1..b3ac15f4a 100644
--- a/docs/developer/packages/semantics.md
+++ b/docs/developer/packages/semantics.md
@@ -1,21 +1,57 @@
---
-title: Semantics Package
+title: Semantics Stage
audience: developers, maintainers, contributors
-prerequisites: contributor architecture guide, parser package guide
-related: ../architecture.md, index.md, parsers.md, policy.md, ../concepts/datatype-lifecycle.md
+prerequisites: contributor architecture guide, parsing-stage guide
+related: ../architecture.md, index.md, parsers.md, policy.md
status: maintained
-publication: draft
+publication: reviewed
---
-# Semantics Package
+# Semantics Stage
## Purpose And Boundaries
-`prik/semantics/` converts Fortran parser facts or semantic `.pyi` AST into the
-same language-neutral `SemanticModule` graph. It owns stable types, public and
-native identities, shapes, projections, provenance, storage contracts, and raw
-metadata. It does not complete ownership, select lowering actions, plan
-wrappers, or emit source.
+`prik/semantics/` converts Fortran parser models or semantic-`.pyi` AST into a
+shared, language-neutral `SemanticModule` graph. It owns stable types, native
+and public identities, shapes, storage contracts, projections, provenance, and
+raw contract metadata. It does not complete ownership, choose lowering
+actions, plan wrappers, or emit source.
+
+`c2ir.py` is preparatory work for a future C frontend. C support is not yet
+complete and is outside the current Fortran-wrapper route, so this guide covers
+the supported Fortran and semantic-`.pyi` paths.
+
+## Inputs And Shared Representation
+
+```text
+FortranFile or FortranProject
+ -> collect unresolved kind and storage requirements when needed
+ -> preprocessing probes provide compile-time values and type facts
+ -> FortranToIRConverter
+ -> SemanticModule graph
+
+parsed semantic .pyi ast.Module
+ -> convert_pyi_to_ir
+ -> local overload, prototype, and declaration-expression resolution
+ -> batch external-reference reconciliation when multiple contracts are loaded
+ -> native-contract preparation and validation
+ -> SemanticModule graph
+
+SemanticModule graph + raw metadata
+ -> policy completion
+```
+
+Both frontend routes produce the same vocabulary. `SemanticModule` contains
+functions, prototypes, overload sets, classes, variables, imports, and module
+origin. `SemanticType` carries a stable type identity, rank, shape, storage,
+constraints, metadata, and source origin. `SemanticFunction`, `SemanticClass`,
+and `ProjectionMapping` retain callable and public-to-native correspondence.
+`SemanticStorageContract` and `SemanticArrayContract` describe the declared
+storage and shape; `SemanticOrigin` retains where a fact came from.
+
+These are semantic facts, not completed policy. In particular, raw ownership
+metadata and a declared storage contract do not decide who owns an object or
+which bridge mechanism implements it.
## Local Structure
@@ -30,41 +66,110 @@ prik/semantics/
├── pyi_metadata.py
├── ownership_metadata.py
├── native_array_handles.py
-└── native_contract.py
-```
-
-The deferred C-to-IR path is intentionally excluded from the published
-Fortran contributor workflow.
-
-## What This Stage Receives And Produces
-
-```text
-Fortran parser models + measured target facts ─┐
- ├─> SemanticModule graph
-semantic .pyi AST ─────────────────────────────┘
- -> raw ownership/native contract metadata
- -> prik.policy completion
+├── native_contract.py
+└── c2ir.py incomplete future C frontend
```
## Directory Tour
-| Module | Main entrypoints and contents | Change it when |
+| Module | Public boundary and result | Change it when |
| --- | --- | --- |
-| [`prik/semantics/__init__.py`](../../../prik/semantics/__init__.py) | Re-exports supported Fortran conversion and `.pyi` conversion entrypoints. | The supported semantic-conversion import API changes. |
-| [`prik/semantics/models.py`](../../../prik/semantics/models.py) | `SemanticModule`, `SemanticFunction`, `SemanticClass`, `SemanticArgument`, `SemanticType`, storage/array contracts, and `SemanticOrigin` form the shared language-neutral graph. | A downstream consumer needs a new language-neutral fact. |
-| [`prik/semantics/scalar_types.py`](../../../prik/semantics/scalar_types.py) | `SemanticScalarSpec` and the scalar catalogue give stable identities and intrinsic family/storage facts without backend spelling. | Stable scalar vocabulary or intrinsic facts change. |
-| [`prik/semantics/fortran2ir.py`](../../../prik/semantics/fortran2ir.py) | `FortranToIRConverter` combines parser models and measured facts into semantic IR; public helpers handle files, modules, and projects. | A Fortran source fact needs a different semantic interpretation. |
-| [`prik/semantics/pyi2ir.py`](../../../prik/semantics/pyi2ir.py) | `convert_pyi_to_ir()` interprets parsed Python AST as an editable semantic contract and reconciles external type references. | A supported `.pyi` construct needs semantic meaning. |
-| [`prik/semantics/metadata.py`](../../../prik/semantics/metadata.py) | Passive keys shared by semantic owners. | A generic semantic metadata key or its canonical spelling changes. |
-| [`prik/semantics/pyi_metadata.py`](../../../prik/semantics/pyi_metadata.py) | Passive keys specific to `.pyi` interpretation. | Parsed `.pyi` metadata needs a canonical key. |
-| [`prik/semantics/ownership_metadata.py`](../../../prik/semantics/ownership_metadata.py) | Normalizes raw ownership and pointer requests without resolving them. | A frontend request needs preservation before policy completion. |
-| [`prik/semantics/native_array_handles.py`](../../../prik/semantics/native_array_handles.py) | `NativeArrayHandleFacts` keeps descriptor, data, and element facets separate. | Semantic description of a native descriptor-backed array changes. |
-| [`prik/semantics/native_contract.py`](../../../prik/semantics/native_contract.py) | `NativeContractIssue` and helpers prepare and validate source-free native placement and ABI facts. | Native contract validation or diagnostics change. |
-
-Combined multi-file `.pyi` loading belongs to `prik/pipeline/pyi.py`. Completed
-ownership, projection, and lowering actions belong to `policy/`, never here.
-
-## Execution Examples
+| [`prik/semantics/__init__.py`](../../../prik/semantics/__init__.py) | Re-exports frontend-conversion helpers. Its C exports are preparatory, not a supported C wrapper route. | The semantic-conversion import surface changes. |
+| [`prik/semantics/models.py`](../../../prik/semantics/models.py) | Defines the shared `SemanticModule` graph, its declarations, types, contracts, projections, origins, and equality rules. | A later stage needs a new language-neutral fact. |
+| [`prik/semantics/scalar_types.py`](../../../prik/semantics/scalar_types.py) | `SemanticScalarSpec` and the scalar catalogue define stable scalar identities, families, and intrinsic storage widths without backend spellings. | Stable scalar vocabulary or intrinsic scalar facts change. |
+| [`prik/semantics/fortran2ir.py`](../../../prik/semantics/fortran2ir.py) | `FortranToIRConverter` and file/module/project helpers convert parser models with optional compiler facts into semantic modules. | A Fortran source fact needs different semantic meaning. |
+| [`prik/semantics/pyi2ir.py`](../../../prik/semantics/pyi2ir.py) | `convert_pyi_to_ir()` interprets one parsed contract; `reconcile_external_type_refs()` resolves a converted batch's cross-module references. | A supported `.pyi` construct or cross-contract reference needs different meaning. |
+| [`prik/semantics/metadata.py`](../../../prik/semantics/metadata.py) | Defines generic cross-stage metadata keys. | A generic semantic metadata key or its canonical spelling changes. |
+| [`prik/semantics/pyi_metadata.py`](../../../prik/semantics/pyi_metadata.py) | Defines `.pyi` loading-state metadata keys. | A `.pyi` loading-state key changes. |
+| [`prik/semantics/ownership_metadata.py`](../../../prik/semantics/ownership_metadata.py) | Validates and stores raw ownership and pointer-contract metadata without completing it. | A frontend ownership or pointer request needs preservation before policy completion. |
+| [`prik/semantics/native_array_handles.py`](../../../prik/semantics/native_array_handles.py) | Marks allocatable or pointer array descriptors and derives their ordinary data and element facets. | Semantic facts for native descriptor-backed arrays change. |
+| [`prik/semantics/native_contract.py`](../../../prik/semantics/native_contract.py) | Prepares `.pyi` native origins and reports invalid source-free native contracts. | Native contract placement, validation, or diagnostics change. |
+
+## Module Algorithms
+
+### `fortran2ir.py`: parser facts to semantic modules
+
+`fortran_module_to_semantic_module()`,
+`fortran_file_to_semantic_modules()`, and
+`fortran_project_to_semantic_modules()` select the appropriate input shape,
+then dispatch it through `FortranToIRConverter`.
+
+The converter uses a class visitor: each Fortran parser model reaches its
+matching `_visit_` method. It normalizes intrinsic base type and
+kind into a semantic scalar identity, applies supplied compiler `type_facts`
+where a target measurement is required, preserves source shapes and origins,
+and creates semantic storage and projection records. It never chooses an
+ownership or lowering action.
+
+For a module, conversion builds procedures first, then callback prototypes,
+derived classes, overload sets, variables, enum constants, imports, and
+visibility. File and project conversion extend this context with known derived
+types, callback interfaces, and procedures before converting each source unit
+in parser order. Standalone procedures become a synthetic semantic module.
+
+`collect_fortran_type_storage_requirements()` and
+`collect_semantic_compile_time_requirements()` are the inspection half of
+target-dependent conversion: they identify the expressions that preprocessing
+must measure. Pass the resulting values and type facts back to conversion.
+`resolve_semantic_compile_time_values()` is separate: it copies already-built
+IR and substitutes known symbolic text without mutating the original.
+
+### `pyi2ir.py`: contract AST to semantic modules
+
+`convert_pyi_to_ir()` accepts only an `ast.Module` from `parsers/pyi`. It
+creates `_PyiAstParser`, whose `_ModuleVisitor` first records user type names,
+then converts imports, variables, classes, functions, prototypes, decorators,
+annotations, and projections in source order.
+
+After every local declaration is available, the parser resolves pending
+overloads, local prototype references, and declaration-expression callables.
+It then marks imported types as unresolved external references. When a pipeline
+loads several contract modules, `reconcile_external_type_refs()` matches those
+references against the batch: prototypes become callback references and classes
+become wrapped or opaque external types.
+
+The converter validates the supported contract subset and preserves declared
+native facts. It does not execute declarations, load native code, infer a
+wrapper mechanism, or complete ownership policy.
+
+### `models.py` and `scalar_types.py`: the shared vocabulary
+
+`models.py` is deliberately a data vocabulary. `SemanticModule` is the
+convergence object consumed by policy and planning. `SemanticType` describes a
+value or object shape; `SemanticStorageContract` and `SemanticArrayContract`
+preserve storage and array declarations; `SemanticOrigin` preserves native
+identity and source provenance. Functions, classes, methods, prototypes, and
+overload sets organize those facts without deciding how they will be lowered.
+
+`scalar_types.py` maps stable names such as `Float64` and `Int32` to a scalar
+family and, when fixed by the name, storage width. Names such as `Int` remain
+target-dependent. NumPy dtypes and emitted C or Fortran spellings belong to
+later boundary owners.
+
+### Raw metadata, descriptors, and native contracts
+
+`metadata.py` and `pyi_metadata.py` contain canonical key names only. They
+prevent frontend and later-stage code from inventing equivalent spellings.
+
+`ownership_metadata.py` validates raw owner, transfer, destruction, and
+pointer-contract requests before storing them on semantic metadata. This
+normalizes frontend input but does not resolve the completed policy that
+`policy/` owns.
+
+`native_array_handles.py` marks an array semantic type as an allocatable or
+pointer descriptor. `native_array_data_type()` returns a copied ordinary-array
+facet with handle-only metadata removed; `native_array_handle_facts()` derives
+that data facet and its rank-zero element facet.
+
+`native_contract.py` applies native origins to `.pyi` modules and validates the
+declared module scope, projection ordering, type completeness, and callback
+references. `native_contract_issues()` returns all issues; `validate_pyi_native_contract()`
+raises the first one. This is contract validation, not wrapper-policy
+completion.
+
+## Run The Workflows
+
+The model example shows the shared representation assembled without a frontend:
```bash
python3 prik/semantics/models.py
@@ -77,6 +182,12 @@ Argument: values: Float64, rank=1, shape=('n',), order=F
Source provenance: fortran real
```
+The script constructs the module, function, argument, and storage records
+directly. The output shows that one semantic type can retain shape, order, and
+Fortran provenance without containing a C or Fortran backend spelling.
+
+The scalar catalogue separates stable identity from backend spelling:
+
```bash
python3 prik/semantics/scalar_types.py
```
@@ -87,6 +198,12 @@ Int: family=signed_integer, storage=target-dependent
Backend spelling stored here: False
```
+It looks up one fixed-width real and one target-dependent integer identity.
+The final line is the boundary: language-specific spelling is deliberately a
+later code-generation concern.
+
+The two frontend converters reach the same kind of semantic declaration:
+
```bash
python3 prik/semantics/fortran2ir.py
```
@@ -103,6 +220,13 @@ python3 prik/semantics/pyi2ir.py
math.scale(value): Float64 -> Float64
```
+The Fortran example converts a parser-level declaration; the `.pyi` example
+converts a parsed contract declaration. Their matching `math.scale` records
+show the two frontends converging on the same semantic vocabulary, while their
+source-specific details remain attached as provenance and metadata.
+
+Raw ownership and pointer requests remain distinct from completed policy:
+
```bash
python3 prik/semantics/ownership_metadata.py
```
@@ -113,6 +237,13 @@ Pointer contract: nullable=True, lifetime=owner, reassociation=forbidden
Completed lowering action present: False
```
+The script attaches raw ownership and pointer requests to a semantic value.
+Those fields describe what the contract asks for; `False` confirms that policy
+completion has not yet selected a lowering action.
+
+Native array handles retain the descriptor separately from its data and element
+facets:
+
```bash
python3 prik/semantics/native_array_handles.py
```
@@ -124,6 +255,13 @@ Element facet: Float64, rank=0
Handle marker retained by data facet: False
```
+The example creates a descriptor-backed array type and reads its separate data
+and element facets. The final line confirms that the handle marker stays on the
+descriptor boundary instead of leaking into the ordinary data value.
+
+Native-contract preparation reports declared contract errors before policy or
+generation:
+
```bash
python3 prik/semantics/native_contract.py
```
@@ -134,29 +272,52 @@ Valid contract issues: 0
Invalid contract issue: pyi_native_type_missing at math.broken.value
```
-These examples show stable semantic representation and raw contract facts.
-None contains a completed binding or bridge action.
+The script prepares one valid and one invalid contract declaration. Zero valid
+issues and the named invalid issue show that contract diagnostics are attached
+before policy completion or any backend lowering begins.
-## Tests And What They Prove
+## Tests And Evidence
-- [Semantic IR conversion](../../../tests/fortran/semantic_ir/semantics/) covers Fortran-model conversion and graph shape.
-- [Semantic `.pyi` behavior](../../../tests/fortran/semantic_pyi_format/) covers contract interpretation and external references.
-- [Datatype semantics](../../../tests/fortran/data_types/semantics/) covers stable type and storage facts.
-- [Native handle semantics](../../../tests/fortran/infrastructure/semantics/test_native_array_handles.py) covers descriptor/data/element separation.
-- [Direct execution inventory](../../../tests/fortran/infrastructure/execution_examples/test_execution_examples.py) fixes the seven stage demonstrations above.
+| Evidence | What it establishes |
+| --- | --- |
+| [Semantic IR conversion](../../../tests/fortran/semantic_ir/semantics/) | Fortran-model conversion, compile-time requirements, specialization, and semantic graph properties. |
+| [Fortran datatype semantics](../../../tests/fortran/data_types/semantics/) | Stable scalar identities, storage facts, and compiler-measurement handoffs. |
+| [Semantic `.pyi` conversion](../../../tests/fortran/semantic_pyi_format/semantics/) | Contract constructs, imports, external references, projections, classes, overloads, and round trips. |
+| [Native array handles](../../../tests/fortran/infrastructure/semantics/test_native_array_handles.py) | Descriptor marking and separation of handle, data, and element facts. |
+| [Native contract validation](../../../tests/fortran/semantic_pyi_format/semantics/test_types_and_values.py) | Native-contract preparation, validation, and diagnostic ownership. |
## Change Routes
-- Change graph shape in `models.py` only when downstream contracts need a new
- language-neutral fact.
+- Change the shared IR graph, equality, or a language-neutral representation
+ in `models.py`.
- Change stable primitive vocabulary in `scalar_types.py`.
-- Change frontend interpretation in the matching converter.
-- Change lifetime, transfer, setter, projection, or support decisions in
- policy, never in semantic conversion.
-
-## Invariants And Common Mistakes
-
-- Parser source spellings and backend dtype spellings are not semantic type
- identities.
+- Change Fortran parser-fact interpretation, compile-time requirement
+ collection, or semantic specialization in `fortran2ir.py`.
+- Change `.pyi` contract interpretation or batch reference reconciliation in
+ `pyi2ir.py`; path-set loading remains in `pipeline/pyi.py`.
+- Change raw metadata canonicalization in the matching metadata module.
+- Change descriptor facts in `native_array_handles.py` and source-free native
+ contract validation in `native_contract.py`.
+- Change ownership, transfer, lifecycle, projections, support, or lowering
+ actions in `policy/`, not in semantic conversion.
+
+## Boundaries And Invariants
+
+- Parser spellings, target compiler facts, semantic scalar identities, and
+ backend spellings are different representations.
+- Preserve native names, scope, and source provenance while normalizing a
+ frontend fact.
- Raw ownership metadata is not completed ownership policy.
-- Preserve provenance when normalizing language-specific facts.
+- Batch reference reconciliation requires all participating `.pyi` modules;
+ single-module conversion leaves external references unresolved by design.
+- A semantic declaration is not automatically wrapper support.
+
+## Failure Boundary
+
+This stage reports unsupported frontend facts, invalid semantic contracts,
+missing target facts needed for semantic conversion, unresolved local contract
+relationships, and invalid source-free native placement. It delegates source
+syntax to `parsers/`, compiler measurement to `preprocessing/`, completed
+interoperability choices to `policy/`, and lowering to later stages. Start with
+the first incorrect parser fact, compiler fact, or semantic record—not a later
+policy, build, or generated-code failure.
diff --git a/docs/developer/packages/utilities.md b/docs/developer/packages/utilities.md
index 16375ece1..4161340ea 100644
--- a/docs/developer/packages/utilities.md
+++ b/docs/developer/packages/utilities.md
@@ -1,50 +1,66 @@
---
-title: Utilities Package
+title: Utilities Component
audience: developers, maintainers, contributors
prerequisites: contributor architecture guide
related: ../architecture.md, index.md, semantics.md, planning.md, codegen.md
status: maintained
-publication: draft
+publication: reviewed
---
-# Utilities Package
+# Utilities Component
## Purpose And Boundaries
-`prik/utilities/` contains small mechanisms that are genuinely independent of
-one compiler stage. A helper belongs here only while it avoids stage-owned
-semantic policy, syntax grammar, and workflow orchestration.
+`prik/utilities/` contains mechanisms shared by more than one architecture
+stage. A helper belongs here only while it remains independent of source
+grammar, semantic policy, backend behavior, and build orchestration.
## Local Structure
```text
prik/utilities/
-├── __init__.py
├── declaration_expressions.py
├── stage_values.py
├── strings.py
└── visitor.py
```
-## What This Stage Receives And Produces
+- [`declaration_expressions.py`](../../../prik/utilities/declaration_expressions.py)
+ splits declaration text, translates Fortran extents, resolves references to
+ wrapper roles, evaluates constant expressions, and renders completed C or
+ Fortran expressions.
+- [`stage_values.py`](../../../prik/utilities/stage_values.py) provides
+ `StageRecord`, which a producer assembles before its consumer recursively
+ freezes it. `FrozenStageRecordError` rejects later mutation.
+- [`strings.py`](../../../prik/utilities/strings.py) provides
+ `create_incremented_string()` for collision-free local names and
+ `random_string()` for unconstrained temporary identifiers. Public and native
+ name policy belongs in `prik.naming`.
+- [`visitor.py`](../../../prik/utilities/visitor.py) provides `ClassVisitor`.
+ It selects the most specific configured class handler, then deliberately
+ follows the model's method-resolution order.
+
+## Declaration-Expression Workflow
+
+`declaration_expressions.py` keeps one expression in different forms at
+explicit boundaries:
```text
-stage-owned caller facts
- -> reusable expression, local-name, or visitor mechanism
- -> requesting stage
+Fortran declaration text
+ -> parser-safe splitting
+ -> public Python-style extent expression
+ -> references bound to completed wrapper roles
+ -> constant evaluation or backend rendering
```
-## Directory Tour
+The caller supplies array facts during translation, available roles during
+resolution, and backend substitutions during rendering. The utility reports
+unresolved blockers; it does not decide whether a wrapper can supply a value.
-| Module | Main entrypoints and contents | Change it when |
-| --- | --- | --- |
-| [`prik/utilities/__init__.py`](../../../prik/utilities/__init__.py) | Package boundary for small stage-neutral mechanisms. | Establishing a deliberate package-level utility API. |
-| [`prik/utilities/declaration_expressions.py`](../../../prik/utilities/declaration_expressions.py) | `ResolvedDeclarationExtent`, `DeclarationExpressionCall`, and `ArrayExpressionSource` translate, validate, resolve, evaluate, and render declaration extents at explicit handoffs. | An extent representation or its stage-owned translation changes. |
-| [`prik/utilities/stage_values.py`](../../../prik/utilities/stage_values.py) | `StageRecord` keeps an output editable until its consumer calls `freeze()`, which recursively converts nested lists, maps, and sets into immutable values. `FrozenStageRecordError` rejects later mutation. | A cross-stage record needs an immutable consumer boundary; do not use it to make semantic policy decisions. |
-| [`prik/utilities/strings.py`](../../../prik/utilities/strings.py) | Collision-safe local-name helpers allocate deterministic temporary identifiers. | Generic local name allocation changes; public name policy belongs in `naming/`. |
-| [`prik/utilities/visitor.py`](../../../prik/utilities/visitor.py) | `ClassVisitor` provides exact-class dispatch with intentional MRO fallback. | Shared generic dispatch changes, not a stage's visitor methods. |
+## Run The Module Demonstrations
-## Execution Examples
+The declaration-expression example follows one extent through translation,
+role binding, and Fortran rendering:
```bash
python3 prik/utilities/declaration_expressions.py
@@ -58,8 +74,8 @@ Fortran rendering: native_source_extent_0
Compile-time product: 6
```
-The expression changes representation at explicit stages. Backend rendering
-uses a plan-supplied substitution and does not rediscover argument ownership.
+The stage-value example shows that a producer can edit nested values until the
+consumer freezes the record:
```bash
python3 prik/utilities/stage_values.py
@@ -71,10 +87,11 @@ Frozen consumer input: geometry -> ('scale', 'norm')
Mutation rejected: ParserOutput is frozen by its consuming stage
```
-`StageRecord` is a utility rather than a pipeline stage: the caller owns the
-moment it freezes a record. Wrapper generation freezes a completed plan,
-printers freeze generated syntax nodes, and build integration freezes the
-generated wrapper before writing files.
+Wrapper generation freezes a completed plan, printers freeze generated nodes,
+and build integration freezes the generated wrapper before writing it.
+
+The remaining examples show collision-free local naming and exact-class/MRO
+visitor dispatch:
```bash
python3 prik/utilities/strings.py
@@ -94,23 +111,21 @@ Exact handler: literal:42
MRO fallback: expression:Expression
```
-## Tests And What They Prove
-
-- [Utility infrastructure](../../../tests/fortran/infrastructure/utilities/) covers local-name and visitor behavior.
-- [Pipeline freeze-boundary tests](../../../tests/fortran/infrastructure/pipeline/test_wrapper_generator.py) cover plan and generated-node mutation rejection after consumption.
-- [Declaration-expression semantics](../../../tests/fortran/arrays/semantics/test_declaration_expression_utilities.py) covers role resolution and expression rendering.
-- [Direct execution inventory](../../../tests/fortran/infrastructure/execution_examples/test_execution_examples.py) fixes the four demonstrations above.
-
-## Change Routes
+## Change Routes And Evidence
-- Keep parsing, role resolution, evaluation, and backend rendering separate in
- declaration-expression code.
+- Keep declaration parsing, public normalization, role resolution, constant
+ evaluation, and backend rendering as separate operations.
+- Freeze a `StageRecord` at its consumer boundary, after its producing stage
+ has completed local assembly.
+- Put public or target-language name rules in `prik.naming`, not `strings.py`.
+- Define semantic or backend visitor handlers in their owning stage; the
+ shared visitor supplies dispatch only.
-## Invariants And Common Mistakes
+| Evidence | What it establishes |
+| --- | --- |
+| [Utility tests](../../../tests/fortran/infrastructure/utilities/) | Local-name allocation and generic visitor dispatch. |
+| [Declaration-expression tests](../../../tests/fortran/arrays/semantics/test_declaration_expression_utilities.py) | Translation, validation, role resolution, evaluation, and rendering. |
+| [Wrapper freeze-boundary tests](../../../tests/fortran/infrastructure/pipeline/test_wrapper_generator.py) | Plans and generated nodes reject mutation after consumption. |
-- Consumers define their own visitor handlers; `ClassVisitor` does not merge
- frontend or backend visitor responsibilities.
-- Freeze only at the consumer boundary. Freezing a record while its producing
- stage is still assembling it prevents legitimate local completion.
-- Move a helper out of utilities as soon as it starts selecting semantic
- policy or a pipeline action.
+Move a helper out of `utilities/` as soon as it starts selecting semantic
+policy, emitted mechanisms, or a pipeline action.
diff --git a/docs/developer/roadmap/documentation-content-checklist.md b/docs/developer/roadmap/documentation-content-checklist.md
index 00b3e79d8..ca9954333 100644
--- a/docs/developer/roadmap/documentation-content-checklist.md
+++ b/docs/developer/roadmap/documentation-content-checklist.md
@@ -22,9 +22,8 @@ relying on private conversation or implied project knowledge.
Move an item from the open queue to completed content evidence only when all of
these are true:
-- [ ] The page status is accurate: `maintained` for current public behavior,
- `design` for accepted architecture, or `not-yet-implemented` for explicit
- future behavior.
+- [ ] The page status is accurate: `maintained` for current public behavior or
+ `not-yet-implemented` for explicit future behavior.
- [ ] The page explains what is supported now and what is unsupported without
exposing internal test-evidence ledgers in public user-facing prose.
- [ ] User-facing pages include a task-oriented workflow, expected output or API
@@ -83,7 +82,7 @@ more specialized pages.
unsupported features, and where to report bugs.
PRIK_C_DOCS_END -->
-### Contributor Architecture And Package Guides
+### Contributor Architecture And Component Guides
- [x] `docs/developer/architecture.md`: shallow repository/package maps,
complete wrapper workflow, stage authority, root entrypoints, change routes,
@@ -91,30 +90,21 @@ PRIK_C_DOCS_END -->
- [x] `docs/developer/packages/`: one maintained guide per top-level production
package with local structure, essential objects, executable examples, expected
output, focused tests, change routes, and invariants.
-- [x] `docs/developer/concepts/datatype-lifecycle.md`: cross-stage datatype
- authority from target probing through semantic identity, policy, backend
- representation, and runtime validation.
- [x] `docs/developer/workflows/contributing.md`: documentation-first changes,
ownership lookup, support evidence, test selection, pull requests, review,
and contribution licensing.
- [x] `docs/developer/workflows/quality-assurance.md`: active blocking/advisory
tools, exact commands, coverage parity, compiler lanes, and local limits.
-- [x] `docs/developer/workflows/ci.md`: staged GitHub validation,
- documentation deployment, benchmark evidence, and stable ruleset context.
-- [x] `docs/developer/workflows/release.md`: package identity, trusted
- publishing, artifact review, publication, and clean-environment verification.
+- [x] `docs/developer/workflows/ci.md`: pull-request validation and the hosted
+ evidence that follows local verification.
- [x] `docs/developer/workflows/documentation.md`: documentation placement,
- metadata, publication, navigation, and continuous quality.
-- [x] `docs/developer/design/multilanguage-runtime.md`: explicit long-term
- architecture separated from current support claims.
-- [x] `docs/developer/design/wrapper-open-decisions.md`: unresolved or
- revisitable design questions separated from implemented package contracts.
+ local verification, and draft review.
- [x] `docs/developer/deferred/c-parser.md`: retained but unpublished C
parser/C-to-IR material, separate from the generated CPython C backend.
-The old TODO-only contributor pages, duplicate pipeline/source maps, completed
-wrapper-plan and native-array migration ledgers, and separate internal/design
-indexes were removed after their stable facts moved to these owners.
+The old TODO-only contributor pages, duplicate pipeline/codebase maps, completed
+wrapper-plan and native-array migration ledgers, and separate internal indexes
+were removed after their stable facts moved to these owners.
### Tutorials And Examples
@@ -159,8 +149,7 @@ indexes were removed after their stable facts moved to these owners.
- [x] `docs/developer/packages/index.md`: route contributors from each production
package to its canonical guide.
- [x] `docs/developer/index.md`: distinguish implemented package references,
- cross-cutting concepts, workflows, design proposals, active roadmaps, and
- deferred input-language material.
+ workflows, active roadmaps, and deferred input-language material.
- [ ] Public documentation site publication gate: deploy the existing MkDocs
documentation as the project website only after all of the following are
true; do not create a separate marketing-content system for this milestone.
@@ -200,7 +189,7 @@ primary placeholder queue.
- [x] `docs/developer/architecture.md`: canonical contributor architecture
orientation and folder-by-folder rollout plan.
- [x] `docs/developer/workflows/documentation.md`: maintained two-area
- documentation and publication contract.
+ documentation and local-verification workflow.
- [x] `docs/user/getting-started/index.md`: maintained beginner route from
installation through the normal rebuild workflow.
- [x] `docs/user/getting-started/installation.md`: maintained user and contributor
@@ -279,7 +268,7 @@ primary placeholder queue.
- [x] `docs/user/language-support/feature-matrix.md`: maintained support matrix.
- [x] `docs/developer/workflows/contributing.md`: maintained contributor
development and review workflow.
-- [x] `docs/developer/source-map.md`: maintained source route map.
+- [x] `docs/developer/codebase-map.md`: maintained package and module ownership map.
- [x] `docs/developer/feature-to-code-map.md`: maintained feature route
map.
- [x] `docs/developer/architecture.md`: maintained shallow repository/package
@@ -289,7 +278,7 @@ primary placeholder queue.
- [x] `docs/developer/workflows/quality-assurance.md`: maintained quality and QA
policy reference.
- [x] `docs/developer/packages/index.md`: maintained package ownership map and
- detailed package guide index.
+ detailed architecture component guide index.
- [x] `docs/developer/packages/policy.md`: maintained
ownership philosophy, completed policy vocabulary, supported lifetime triples,
pointer-policy boundary, validation order, source routes, and safety boundary.
diff --git a/docs/developer/roadmap/index.md b/docs/developer/roadmap/index.md
index 73a78750b..7bd6590ed 100644
--- a/docs/developer/roadmap/index.md
+++ b/docs/developer/roadmap/index.md
@@ -10,7 +10,7 @@ publication: draft
# Active Roadmaps
Only incomplete work belongs here. Implemented behavior is documented in user
-and package guides; completed migration ledgers are removed after their stable
+and architecture component guides; completed migration ledgers are removed after their stable
decisions and evidence routes have moved to canonical documentation.
## Active Work
diff --git a/docs/developer/roadmap/semantic-pyi-wrapper-checklist.md b/docs/developer/roadmap/semantic-pyi-wrapper-checklist.md
index 0f5550c18..9d3b99810 100644
--- a/docs/developer/roadmap/semantic-pyi-wrapper-checklist.md
+++ b/docs/developer/roadmap/semantic-pyi-wrapper-checklist.md
@@ -429,7 +429,8 @@ PRIK_C_DOCS_END -->
before semantic policy completion runs. Evidence:
`tests/fortran/semantic_pyi_format/parsing/test_python_ast_contracts.py::test_pyi_parser_returns_python_ast_only`,
`prik/semantics/README.md`, and
- `docs/developer/architecture.md` and the detailed package guides.
+ `docs/developer/architecture.md` and the detailed architecture component
+ guides.
- [x] Risky-but-explicit identity contracts document their exact behavior
instead of being silently healed. Fixed-length `String[n]` `intent(inout)`
identity calls may return `None` with no observable Python mutation when the
diff --git a/docs/developer/source-map.md b/docs/developer/source-map.md
deleted file mode 100644
index caa6991c4..000000000
--- a/docs/developer/source-map.md
+++ /dev/null
@@ -1,232 +0,0 @@
----
-title: Source Map
-audience: developers, contributors
-prerequisites: repository checkout, developer guide
-related: feature-to-code-map.md, testing-strategy.md
-status: maintained
-publication: draft
----
-
-# Source Map
-
-Use this page when you need to find the owning source files before changing a
-feature. It is populated from the current maintained developer guide and the
-current Python package layout.
-
-## Top-Level Entry Points
-
-| Start here | Owns | Continue to |
-| --- | --- | --- |
-| `prik/cli.py` | User CLI, stage selection, output routing, diagnostics, wrapper-build option validation | parser frontends, semantic conversion, wrapper planning, `prik/pipeline/build.py` |
-| `prik/pipeline/build.py` | End-to-end Fortran source and semantic `.pyi` extension builds | preprocessing, parser, probes, completed semantic policy, wrapper planning and generation, compilation |
-| `prik/__init__.py` | Public Python exports | parser public-entrypoint tests and user examples |
-| `prik/policy/ownership.py` | Central ownership, transfer, destruction, and generated-action policy | policy completion and typed wrapper planning |
-| `prik/preprocessing/source.py` | Compiler-backed Fortran source expansion, provenance, and dependency facts | parser input preparation |
-
-| `prik/preprocessing/fortran.py` | Native Fortran `INCLUDE` expansion and source mappings | Fortran parser input preparation |
-| `prik/preprocessing/probes/fortran_types.py` | Fortran kind/storage facts and cache | semantic Fortran conversion and wrapper builds |
-| `prik/pipeline/type_mapping_report.py` | Cross-stage target datatype mapping examples | semantic and codegen datatype catalogues plus documentation example tests |
-| `prik/semantics/scalar_types.py` | Stable scalar names, families, and intrinsic storage facts | source-to-IR conversion and policy completion |
-| `prik/codegen/primitive_scalar_types.py` | Resolved semantic-to-NumPy projection and implemented backend scalar lowering facts | mapping reports plus binding and bridge generation |
-| `examples/blas/` | Complete Reference BLAS correctness example, source inventory, build fixtures, and the authoritative native source set | dedicated BLAS/LAPACK workflow and full-library integration |
-| `examples/lapack/` | Complete Reference LAPACK source set and SciPy-exposed float64 correctness inventory | dedicated BLAS/LAPACK workflow and full-library integration |
-
-
-
-## Common Change Routes
-
-Use this table when you know the behavior you need to change but not the
-owning layer. Open the first file, then follow the downstream files only as the
-change crosses ownership boundaries.
-
-| Change area | Open first | Public docs to update | Focused evidence |
-| --- | --- | --- | --- |
-| CLI flags, stage selection, output formatting, diagnostics | `prik/cli.py` | `docs/user/reference/cli-commands.md`, `docs/user/getting-started/beginner-workflow.md` | `tests/fortran/command_line_interface/pipeline/`, `tests/docs/test_examples.py` |
-| Compiler preprocessing, include paths, macros, and target flags | `prik/preprocessing/source.py` | `docs/user/examples/recipes/compiler-preprocessing.md`, `docs/developer/packages/preprocessing.md`, `docs/developer/packages/parsers.md` | `tests/fortran/source_preprocessing/preprocessing/`, `tests/fortran/source_preprocessing/preprocessing/test_parser_boundaries.py` |
-| Datatype probing, semantic normalization, NumPy projection, and mapping reports | `prik/preprocessing/probes/fortran_types.py`, `prik/semantics/scalar_types.py`, `prik/codegen/primitive_scalar_types.py`, `prik/pipeline/type_mapping_report.py` | `docs/developer/concepts/datatype-lifecycle.md`, `docs/user/reference/semantic-ir.md` | `tests/fortran/data_types/` |
-| Fortran parser facts and diagnostics | `prik/parsers/fortran/parser.py` | `docs/developer/packages/parsers.md`, `docs/user/examples/recipes/inspect-fortran-api.md` | `tests/fortran/source_parsing/parsing/` |
-| Semantic `.pyi` parsing, conversion, printing, package generation, and round-trip behavior | `prik/parsers/pyi/parser.py`, `prik/pipeline/pyi.py`, `prik/semantics/pyi2ir.py`, `prik/printers/pyi.py` | `docs/user/reference/semantic-pyi-format.md`, `docs/user/reference/pyi-contracts/index.md`, `docs/user/examples/recipes/semantic-pyi-contracts.md` | `tests/fortran/semantic_pyi_format/`, `tests/fortran/semantic_pyi_format/pipeline/test_contract_package_generation.py`, `tests/fortran/semantic_pyi_format/pipeline/test_contract_loading.py`, `tests/fortran/semantic_pyi_format/end_to_end/test_authoritative_contract_runtime.py`, `tests/fortran/semantic_pyi_format/pipeline/` |
-| Wrapper-planning errors and support claims | `prik/policy/completion.py`, `prik/planning/planner.py` | `docs/user/reference/diagnostic-codes.md`, `docs/user/language-support/feature-matrix.md` | `tests/fortran/infrastructure/semantics/`, feature-local `policy/`, and `tests/fortran/infrastructure/codegen/` |
-| Source-driven Fortran wrapper orchestration | `prik/pipeline/build.py` | `docs/user/reference/fortran-wrapper.md`, `docs/user/guide/building-shared-library.md` | `tests/fortran/building_shared_library/end_to_end/test_source_build_modes.py`, `tests/fortran/building_shared_library/end_to_end/test_multi_source_builds.py` |
-| Semantic `.pyi` wrapper orchestration from native artifacts | `prik/pipeline/build.py`, `prik/pipeline/pyi.py`, `prik/semantics/pyi2ir.py` | `docs/user/reference/fortran-wrapper.md`, `docs/user/reference/semantic-pyi-format.md` | `tests/fortran/building_shared_library/pipeline/test_pyi_build_modes.py`, `tests/fortran/semantic_pyi_format/end_to_end/test_authoritative_contract_runtime.py`, `tests/fortran/pyi_contracts/exports_and_modules/`, `tests/fortran/pyi_contracts/functions_and_classes/` |
-| Ownership, lifetime, output projection, and unsupported wrapper policy | `prik/policy/completion.py`, `prik/policy/ownership.py`, `prik/policy/models.py`, `prik/policy/construction.py`, `prik/planning/planner.py` | `docs/user/guide/memory-management.md`, `docs/user/reference/semantic-pyi-format.md`, `docs/user/reference/fortran-wrapper.md` | `tests/fortran/infrastructure/semantics/`, feature-local `policy/`, and `tests/fortran/infrastructure/codegen/` |
-| Immediate callback policy, typed adapters, and trampolines | `prik/policy/models.py`, `prik/policy/construction.py`, `prik/policy/completion.py`, `prik/planning/models.py`, `prik/planning/planner.py`, `prik/codegen/c/binding.py`, `prik/codegen/fortran/bridge.py` | `docs/user/guide/callbacks.md`, `docs/user/reference/semantic-pyi-format.md` | `tests/fortran/callbacks/` |
-| Native compilation, binding support, and shared-library linking | `prik/pipeline/build.py`, `prik/compiler/compilers.py`, `prik/compiler/native_support.py` | `docs/user/reference/fortran-wrapper.md`, `docs/developer/packages/compiler.md`, `docs/developer/packages/pipeline.md` | `tests/fortran/building_shared_library/end_to_end/test_runtime_compatibility.py`, `tests/fortran/building_shared_library/end_to_end/test_source_build_modes.py` |
-| Public Python exports | `prik/__init__.py` | `README.md`, `docs/user/reference/python-api.md` | `tests/fortran/source_parsing/parsing/test_public_entrypoints.py` |
-| Reference BLAS source ownership, inventory, and numerical validation | `examples/blas/routine_inventory.py`, `examples/blas/tests/test_routine_coverage.py` | `examples/blas/README.md`, `docs/user/examples/blas-wrapper.md` | `examples/blas/tests/test_*.py`, `examples/blas/ci/full_surface.py`, dedicated real-libraries workflow |
-| Reference LAPACK source ownership, inventory, and numerical validation | `examples/lapack/routine_inventory.py`, `examples/lapack/tests/test_routine_coverage.py` | `examples/lapack/README.md`, `docs/user/examples/lapack-wrapper.md` | `examples/lapack/tests/test_*.py`, `examples/lapack/ci/full_surface.py`, dedicated real-libraries workflow |
-| FFTPACK public-module boundary, source ownership, and numerical validation | `examples/fftpack/routine_inventory.py`, `examples/fftpack/tests/test_routine_coverage.py` | `examples/fftpack/README.md`, `docs/user/examples/fftpack-wrapper.md` | `examples/fftpack/tests/test_*.py`, `tests/fortran/building_shared_library/end_to_end/real_libraries/test_fftpack_routines.py`, dedicated real-libraries workflow |
-| MINPACK source ownership, parameter constants, and numerical validation | `examples/minpack/routine_inventory.py`, `examples/minpack/tests/test_routine_coverage.py` | `examples/minpack/README.md`, `docs/user/examples/minpack-wrapper.md` | `examples/minpack/tests/test_*.py`, `tests/fortran/building_shared_library/end_to_end/real_libraries/test_minpack_routines.py`, dedicated real-libraries workflow |
-| Source navigation documentation | `docs/developer/source-map.md`, `docs/developer/feature-to-code-map.md`, package README files | `docs/developer/source-map.md` | `tests/docs/test_reference_and_source_map.py` |
-| Generated Fortran bridge | `prik/codegen/fortran/bridge.py`, `prik/printers/fortran.py`, `prik/pipeline/wrapper.py` | `docs/user/reference/fortran-wrapper.md` | `tests/fortran/infrastructure/codegen/`, `tests/fortran/` generated-wrapper assertions |
-| Generated CPython binding and Python-visible runtime behavior | `prik/codegen/c/binding.py`, `prik/codegen/c/python_surface.py`, `prik/codegen/c/naming.py`, `prik/printers/c.py`, `prik/pipeline/wrapper.py` | `docs/user/reference/fortran-wrapper.md`, `docs/user/reference/python-api.md` | `tests/fortran/infrastructure/codegen/`, `tests/fortran/` |
-
-
-
-
-
-## Package Map
-
-| Package | Purpose | Main files | Primary tests and docs |
-| --- | --- | --- | --- |
-| `prik/contracts/` | Public semantic `.pyi` contract vocabulary | `__init__.py` | `tests/fortran/semantic_pyi_format/`, semantic `.pyi` reference |
-| `prik/compiler/` | Compiler execution, compile objects, vendor profiles, native support installation, and linking | `compilers.py`, `objects.py`, `compiler_profiles.py`, `native_support.py` | compiler and shared-library build tests |
-| `prik/preprocessing/` | Compiler-backed Fortran source expansion, native includes, provenance, and target probes | `source.py`, `fortran.py`, `probes/fortran_types.py` | Fortran preprocessing and target-probe tests |
-| `prik/pipeline/` | Semantic `.pyi` loading, cross-stage datatype reporting, plan-to-source wrapper generation, and native build orchestration | `pyi.py`, `type_mapping_report.py`, `wrapper.py`, `build.py` | `.pyi`, datatype report, wrapper generation, and build tests |
-| `prik/runtime/` | Python runtime objects and bundled native support consumed by generated extensions | `handles.py`, `native_support/` | runtime handle, native-support, and wrapper runtime tests |
-| `prik/parsers/` | Public namespace for the Fortran and semantic `.pyi` frontends | child parser packages | `tests/fortran/source_parsing/parsing/`, `tests/fortran/semantic_pyi_format/parsing/` |
-| `prik/parsers/fortran/` | Fortran lexer, recursive parser, models, type resolver, and parser CLI helpers | `parser.py`, `lexer.py`, `models.py`, `type_resolver.py`, `cli.py` | `tests/fortran/source_parsing/parsing/`, `docs/developer/packages/parsers.md` |
-| `prik/parsers/pyi/` | Semantic `.pyi` text/file parsing to Python AST | `parser.py` | `tests/fortran/semantic_pyi_format/parsing/`, `docs/user/reference/semantic-pyi-format.md` |
-| `prik/semantics/` | Language-neutral semantic IR, scalar datatype vocabulary, Fortran-to-IR conversion, `.pyi` conversion, and raw ownership or descriptor metadata | `models.py`, `scalar_types.py`, `fortran2ir.py`, `pyi2ir.py`, `ownership_metadata.py`, `native_array_handles.py` | `tests/fortran/data_types/semantics/`, `tests/fortran/semantic_ir/semantics/`, `tests/fortran/semantic_pyi_format/semantics/` |
-| `prik/policy/` | Post-IR ownership, export, wrapper-policy construction, immutable policy models, descriptor-handle policy, and ordered completion | `ownership.py`, `exports.py`, `models.py`, `native_array_handles.py`, `construction.py`, `completion.py` | infrastructure semantics and feature-local policy tests |
-| `prik/planning/` | Editable backend-neutral wrapper-plan records and mechanical policy projection | `models.py`, `planner.py` | infrastructure and feature-local codegen tests |
-| `prik/codegen/` | Backend datatype projection, plan-driven docstrings, and direct lowering into C and Fortran syntax nodes | `primitive_scalar_types.py`, `docstrings.py`, `nodes.py`, `c/`, `fortran/` | data-type and infrastructure codegen, feature-local codegen, and end-to-end tests |
-| `prik/printers/` | Language-specific serialization of C nodes, Fortran nodes, and semantic IR | `c.py`, `fortran.py`, `pyi.py` | source-printer and semantic-contract printer tests |
-| `prik/naming/` | Unified public-name and generated-symbol policy for Python, generated C, and generated Fortran targets | `policy.py`, `native_symbols.py` | naming, visibility, and wrapper runtime tests |
-| `prik/utilities/` | Small shared Python utilities | `strings.py`, `visitor.py` | `tests/fortran/infrastructure/utilities/` and tests that exercise callers |
-
-
-
-## Hotspot Index
-
-These files are the maintained source-navigation anchors. If ownership moves,
-update this table, the package README files, and the mechanical checks in
-`tests/docs/test_reference_and_source_map.py` in the same change.
-
-| Hotspot | Owns |
-| --- | --- |
-| `prik/__init__.py` | Public Python API exports. |
-| `prik/cli.py` | CLI argument validation, stage selection, output routing, and wrapper-build entry. |
-| `prik/pipeline/build.py` | End-to-end source and `.pyi` wrapper build orchestration. |
-| `prik/preprocessing/source.py` | Compiler-backed source preprocessing and dependency facts. |
-| `prik/pipeline/type_mapping_report.py` | Target facts, semantic conversion, and backend NumPy projection rendered as a mapping report. |
-| `prik/preprocessing/probes/fortran_types.py` | Fortran kind and storage probing. |
-| `prik/semantics/scalar_types.py` | Stable primitive scalar identities, families, and intrinsic storage widths. |
-| `prik/semantics/ownership_metadata.py` | Raw ownership and pointer-contract metadata keys and normalized semantic setters. |
-| `prik/semantics/native_array_handles.py` | Raw semantic descriptor-handle facts attached before policy completion. |
-| `prik/policy/ownership.py` | Central ownership, transfer, destruction, and generated-action policy. |
-| `prik/policy/exports.py` | Completed Python namespace and export-name policy. |
-| `prik/parsers/fortran/parser.py` | Fortran parser project model and diagnostics. |
-| `prik/parsers/fortran/cli.py` | Fortran parser report formatting. |
-| `prik/semantics/metadata.py` | Cross-stage semantic metadata keys that survive parser, policy, printer, and lowering boundaries. |
-| `prik/semantics/models.py` | Semantic IR dataclasses and core model metadata. |
-| `prik/semantics/fortran2ir.py` | Fortran parser facts to semantic modules. |
-| `prik/parsers/pyi/parser.py` | Minimal `.pyi` text/file parsing to Python AST. |
-| `prik/pipeline/pyi.py` | Semantic `.pyi` text/file/path-set conversion and external-type reconciliation. |
-| `prik/semantics/pyi2ir.py` | Semantic `.pyi` AST conversion and validation. |
-| `prik/policy/models.py` | Immutable backend-neutral completed wrapper-policy vocabulary. |
-| `prik/policy/construction.py` | Wrapper-policy construction rules and completed-policy accessors. |
-| `prik/policy/completion.py` | Ordered post-IR semantic policy completion before wrapper planning. |
-| `prik/policy/native_array_handles.py` | Completed descriptor-handle policy and build requirements. |
-| `prik/planning/models.py` | Typed, policy-complete wrapper plan records. |
-| `prik/planning/planner.py` | Semantic policy to wrapper-plan conversion. |
-| `prik/naming/native_symbols.py` | Stable generated native-symbol construction shared by planning and code generation. |
-| `prik/codegen/docstrings.py` | Plan-driven Python-facing documentation generation. |
-| `prik/codegen/primitive_scalar_types.py` | Primitive scalar backend and NumPy lowering catalogue. |
-| `prik/pipeline/wrapper.py` | Single plan-to-rendered-wrapper orchestration and generated-wrapper result records. |
-| `prik/codegen/fortran/bridge.py` | Direct Fortran bridge lowering from typed plans. |
-| `prik/codegen/c/binding.py` | Direct Python-extension binding lowering from typed plans. |
-| `prik/codegen/c/python_surface.py` | Executable derived-class facade and thin class-overload forwarding source. |
-| `prik/codegen/c/naming.py` | Shared symbols referenced by generated C and the embedded Python facade. |
-| `prik/printers/c.py` | C binding and header node serialization. |
-| `prik/printers/fortran.py` | Fortran bridge node serialization. |
-| `prik/printers/pyi.py` | Semantic IR serialization as editable `.pyi`. |
-| `prik/compiler/objects.py` | Native compile object model. |
-| `prik/compiler/compilers.py` | Compiler command execution and tool lookup. |
-| `prik/compiler/native_support.py` | Native binding support installation for generated wrappers. |
-| `prik/naming/policy.py` | Public wrapper names and generated target-language symbols. |
-| `prik/runtime/native_support/` | Header-only native runtime payload copied into generated builds as `binding_support/`. |
-
-
-
-## Layer-To-Layer Route
-
-For source-driven Fortran wrappers, read in this order:
-
-```text
-prik/cli.py
- -> prik/pipeline/build.py
- -> prik/preprocessing/source.py
- -> prik/parsers/fortran/parser.py
- -> prik/preprocessing/probes/fortran_types.py
- -> prik/semantics/fortran2ir.py
- -> prik/policy/completion.py
- -> prik/planning/planner.py
- -> prik/pipeline/wrapper.py
- -> prik/codegen/fortran/bridge.py
- -> prik/codegen/c/binding.py
- -> prik/compiler/compilers.py
- -> tests/fortran/
-```
-
-For semantic `.pyi` builds, the parser branch is replaced by:
-
-```text
-prik/parsers/pyi/parser.py
- -> prik/pipeline/pyi.py
- -> prik/semantics/pyi2ir.py
- -> prik/policy/completion.py
- -> prik/planning/planner.py
- -> prik/pipeline/wrapper.py
-```
-
-
-
-
-
-
-
-## Package-Level Notes
-
-The hardest source packages also have local README files:
-
-- `prik/README.md`
-- `prik/parsers/README.md`
-- `prik/parsers/fortran/README.md`
-- `prik/parsers/pyi/README.md`
-- `prik/semantics/README.md`
-- `prik/policy/README.md`
-- `prik/planning/README.md`
-- `prik/printers/README.md`
-- `prik/pipeline/README.md`
-- `prik/preprocessing/README.md`
-- `prik/compiler/README.md`
-
-
-
-Keep these files short. They should tell developers where to enter the code,
-what the package owns, what it must not own, and where the tests and public docs
-live.
diff --git a/docs/developer/testing-strategy.md b/docs/developer/testing-strategy.md
index ab55332a2..ed7ef612d 100644
--- a/docs/developer/testing-strategy.md
+++ b/docs/developer/testing-strategy.md
@@ -1,255 +1,107 @@
---
title: Testing Strategy
audience: developers, contributors
-prerequisites: repository structure
-related: workflows/quality-assurance.md, workflows/contributing.md
+prerequisites: PRIK Architecture, Feature-to-Code Map
+related: architecture.md, feature-to-code-map.md, workflows/quality-assurance.md
status: maintained
-publication: draft
+publication: reviewed
---
# Testing Strategy
-The canonical ownership and command map is
-[`../../tests/README.md`](../../tests/README.md). The Fortran feature index is
-[`../../tests/fortran/README.md`](../../tests/fortran/README.md). Maintainers
-record the active migration gates in
-`docs/developer/roadmap/fortran-test-suite-cleanup-checklist.md`.
+This page explains how PRIK assigns test ownership and how to choose the
+smallest evidence that can prove a change. `tests/README.md` is the canonical
+test-suite directory map; `tests/fortran/README.md` is the Fortran feature
+index and command map.
-## Choose tests by language, feature, and stage
+## Test Ownership
-Tests first answer which native input contract they exercise:
+| Change or behavior | Test owner | What it proves |
+| --- | --- | --- |
+| Documentation content, metadata, navigation, or examples | `tests/docs/` | Published documentation and its repository contracts. |
+| Maintainer command or CI-support behavior | `tests/tools/` | Repository tooling behavior. |
+| Release or automation safety | `tests/workflows/` | Workflow safety properties. |
+| User-visible Fortran or semantic `.pyi` wrapper behavior | `tests/fortran///` | The documented capability at its owning stage. |
+| Internal cross-feature mechanism | `tests/fortran/infrastructure//` | A mechanism with no honest user-visible feature owner. |
-- `tests/docs/` owns documentation metadata, navigation, examples, and content;
-- `tests/tools/` owns maintainer commands and CI support scripts;
-- `tests/workflows/` owns exceptional automation-safety checks;
-- `tests/fortran/` owns Fortran input and semantic `.pyi` wrapper behavior;
-
-
-Within Fortran, user-visible behavior is feature first and pipeline stage
-second:
+For user-visible behavior, choose the feature before the stage:
```text
tests/fortran///
```
-This makes a documentation feature independently navigable:
+`infrastructure/` is not a fallback for tests that touch many packages. A
+feature remains feature-owned when it crosses parsing, policy, planning, and
+lowering. Infrastructure is only for reusable internal mechanisms that have no
+public-capability owner.
-```bash
-python3 -m pytest -q tests/fortran/arrays
-python3 -m pytest -q tests/fortran/derived_types
-python3 -m pytest -q tests/fortran/source_parsing
-python3 -m pytest -q tests/fortran/command_line_interface
-python3 -m pytest -q tests/fortran/pyi_contracts/calls_and_results
-```
+## Stable Contracts
+
+Tests protect observable behavior, public interfaces, serialized or generated
+formats, safety properties, and explicit architectural boundaries. A refactor
+that preserves those contracts should not require unrelated test changes.
+
+Do not freeze prose, heading order, private names, complete inventories, or
+incidental code and directory layout. Test structure only when tooling consumes
+it or it prevents a named, costly failure. When an intentional change breaks a
+test, identify its invariant: keep or rewrite a durable contract; remove a test
+that records only the old implementation or a review preference.
+
+Documentation tests verify publication metadata, links, public references,
+marked user examples, and package-guide command/result pairs. The page is the
+expected-output source: stable output is exact; excerpts and target-dependent
+output are checked only for the facts shown. Editorial wording and organization
+remain contributor-review responsibilities.
+
+## Evidence By Stage
+
+Run the earliest stage that can prove the invariant.
+
+| Stage | Evidence |
+| --- | --- |
+| `parsing/` | Source facts and source-located diagnostics. |
+| `probes/` or `preprocessing/` | Compiler-derived target facts and prepared source. |
+| `semantics/` | Language facts become the intended semantic IR. |
+| `policy/` | Ownership, lifetime, projection, mutability, storage, and support choices are complete. |
+| `codegen/` or `printers/` | Completed policy selects the intended plan, mechanism, or generated text. |
+| `compiling/` or `pipeline/` | Commands, inputs, artifacts, and build transitions are correct. |
+| `runtime/` | Shared runtime mechanisms behave correctly outside a complete feature journey. |
+| `end_to_end/` | Input produces an imported extension whose public Python behavior is called and verified. |
+
+An unsupported form belongs at its first decisive stage. Assert the owning
+PRIK diagnostic there; do not force a known policy rejection through native
+compilation only to observe a later failure.
+
+## End-To-End Evidence
+
+End-to-end tests establish a public wrapper journey: source or intentional
+`.pyi` input, generated wrapper, compilation and link, imported extension, and
+a call to the public Python surface. Successful compilation or import alone is
+not end-to-end evidence.
+
+Full-library BLAS and LAPACK evidence is a separate real-library lane. Do not
+run LAPACK locally unless explicitly requested.
+
+## Test And Fixture Placement
+
+Keep a test and its checked fixtures with their final behavioral owner. Use
+feature-local `end_to_end/fixtures/` for complete native projects; keep
+parser, semantic, and policy setup with the corresponding stage. Generate
+build products and temporary contracts in pytest temporary directories.
+
+Check in generated `.pyi` only when its exact text, imports, placement, or
+package shape is the invariant. Shared test support may provide builders and
+assertions, but it must not become an alternate import surface for production
+code.
+
+## Selecting And Expanding Verification
-Use `tests/fortran/infrastructure/` only for a cross-feature mechanism with no
-honest public-capability owner. Public Fortran parsing, preprocessing,
-command-line behavior, and semantic-IR conversion have the explicit
-`source_parsing/`, `source_preprocessing/`, `command_line_interface/`, and
-`semantic_ir/` owners. Generic internal policy dispatch, typed-plan mechanics,
-compiler construction, and runtime-handle plumbing may remain infrastructure.
-Ordinary regressions stay with their feature and stage. Minimized,
-cross-feature parser interactions discovered in real-world sources belong in
-`tests/fortran/source_parsing/parsing/`.
-
-Treat a full third-party parser corpus as temporary evidence. Use contextual
-line/branch coverage and named model assertions to identify what it uniquely
-proves, replace those facts with minimized regressions, and delete the upstream
-snapshot once the focused suite subsumes it. Aggregate coverage alone is not a
-reason to keep hundreds of sources. A temporary corpus may be staged outside
-the authoritative test tree while it is being reduced.
-
-## Stage tests and end-to-end tests
-
-Stage tests answer where a fact, policy decision, mechanism, or diagnostic is
-owned. Use the earliest stage that can prove the invariant:
-
-- parsing for source-model facts and parser diagnostics;
-- probes or preprocessing for compiler facts and source processing;
-- semantics for IR construction;
-- policy for ownership, transfer, destruction, writeback, nullability,
- projection, storage, getter/setter, and Python-exposure decisions;
-- wrapper code generation for typed-plan dispatch and emitted mechanisms;
-- compiling or pipeline for commands, native inputs, artifacts, and build
- transitions; and
-- runtime for shared execution mechanisms that are not complete feature
- journeys.
-
-End-to-end tests answer whether a supported public feature survives the whole
-journey. They start from user-owned Fortran source or an intentional `.pyi`,
-generate wrappers, compile and link an extension, import it from an isolated
-build directory, call the public Python surface, and verify visible behavior.
-Successful compilation or import without a public call is insufficient.
-
-Feature end-to-end tests live below the owning feature's `end_to_end/`
-directory and carry `fortran_end_to_end`. Full-library integration nodes carry
-`real_library`. The complete correctness examples under `examples/blas/` and
-`examples/lapack/` use both markers and run only in the dedicated BLAS/LAPACK
-lane.
-
-The opt-in numerical showcases under
-`tests/fortran/building_shared_library/end_to_end/real_libraries/` locate a
-sibling checkout or an explicitly configured source directory, build the real
-library sources, call representative generated routines, and compare against
-independently known numerical answers. `PRIK_FFTPACK_SOURCE_DIR` and
-`PRIK_MINPACK_SOURCE_DIR` override the default sibling `fftpack/src` and
-`minpack/src` locations. The tests skip when the corresponding checkout is
-absent.
-
-## Diagnostics and unsupported behavior
-
-Put an unsupported case at its first decisive stage and assert a stable prik
-diagnostic. Do not force a known policy rejection through compilation merely
-to observe a compiler failure.
-
-Error cases stay with their owning feature. The Error Handling feature owns
-only behavior that is itself an error-handling contract, such as native-status
-projection, exception type/message behavior, cleanup on failure, and public
-diagnostic routing. `tests/fortran/CONTRACT_COVERAGE.md` indexes negative
-evidence and terminal stages across all features.
-
-## Fixture ownership
-
-Keep fixtures beside their final behavioral owner:
-
-- parser-only sources with parsing;
-- semantic/policy setup with that stage;
-- complete native projects below feature-local `end_to_end/fixtures/`;
-- edited `.pyi` below the edit family it proves;
-- minimized real-world parser interactions with source parsing; and
-- the authoritative full BLAS source set below `examples/blas/native/`, shared
- by the correctness example, full-library integration, LAPACK CI build, and
- build comparison tooling;
-- the authoritative Reference LAPACK implementation corpus below
- `examples/lapack/native/`, shared by its correctness example and full-library
- integration.
-
-Generate build products and temporary contracts in temporary directories.
-Compiler capability probes must also run with a temporary working directory so
-side products such as Fortran `.mod` files cannot escape into the repository
-root merely because the primary object or executable has an explicit output
-path. Check in generated `.pyi` only where exact generation text,
-imports, placement, or package shape is the invariant.
-
-For BLAS behavior, source `examples/blas/build_all.sh`, then run
-`python3 -m pytest -q examples/blas/tests` or one of its named test functions.
-The aggregate script sources the exact documented `build_prik.sh` and
-`build_f2py.sh` sequences. This compiles the sorted 155-source implementation
-once and builds each wrapper once; the direct f2py script compiles the
-committed reviewed `blas.pyf` and links the native artifact produced by the
-PRIK script.
-Documentation source markers require the displayed commands to remain
-byte-for-byte equal to the executed scripts. `test_routine_coverage.py` audits
-the parsed source inventory, f2py signature drift, both export sets, visible
-named tests, and terminal outcomes. The dedicated CI lane explicitly adds
-`examples/blas/ci/full_surface.py` to the same pytest invocation and does not
-rebuild its wrappers afterward. User-run correctness tests and maintainer-only
-audits therefore have separate directories.
-
-For LAPACK behavior, the dedicated lane sources `examples/lapack/build_all.sh`
-and then runs `python3 -m pytest -q examples/lapack/tests`. The aggregate
-script sources the exact documented `build_prik.sh` and `build_f2py.sh`
-sequences. The complete native corpus is compiled once, each wrapper is built
-once, and the direct f2py script compiles the committed reviewed `lapack.pyf`
-against the native artifact produced by the PRIK script while testing the
-127-routine SciPy 1.18.0 `float64` inventory. Documentation source markers keep
-the displayed commands equal to the executed scripts. The inventory audit
-fails on SciPy drift, signature drift, missing sources or exports, missing
-explicitly named tests, and divergent documentation claims. CI explicitly
-adds `examples/lapack/ci/full_surface.py`
-to the same pytest invocation, reusing the complete PRIK extension to require
-all 2,066 procedure exports, including module namespaces, and run a
-non-inventory runtime smoke call. User-run
-correctness tests and maintainer-only audits have separate directories.
-
-The complete `examples/` tree is a copyable execution boundary. Example code
-may depend on an installed `prik` and its documented external toolchain, but it
-must not import repository-only helpers from `tests/`. The workflow must source
-the documented build scripts through `build_all.sh` before starting pytest,
-rather than run a second build test that repeats native compilation or wrapper
-construction.
-
-## Ownership discipline
-
-Every maintained test and checked fixture has one behavioral owner. Directory
-layout, exact file inventories, and the current organization of the tests are
-maintainer conventions rather than executable product contracts. Do not add
-tests whose only purpose is to make an intentional reorganization fail. Add a
-structural check only for a concrete, unusually costly risk that cannot be
-protected by a behavior test. Cross-feature product mechanics require an
-explicit infrastructure owner; documentation and maintainer tools use their
-named top-level feature owners.
-
-A test has one of two navigation shapes after language ownership is known:
-
-- user-visible behavior lives under
- `tests/fortran///`; or
-- a genuinely internal mechanism lives under
- `tests/fortran/infrastructure//test_.py`.
-
-For example, semantic-policy internals use
-`infrastructure/semantics/test_ownership.py` and
-`test_policy_completion.py`; wrapper internals use
-`infrastructure/codegen/test_plan.py`, `test_planner.py`, and
-`tests/fortran/infrastructure/pipeline/test_wrapper_generator.py`. Other internal owners mirror `prik/compiler/`,
-`prik/contracts/`, `prik/pipeline/`, `prik/runtime/`, and the remaining source
-packages when they have real internal tests. Do not create empty mirror
-directories or combine multiple production owners in generic backend or policy
-collection modules. A retained direct-execution example
-under `if __name__ == "__main__"` is maintained by the same dedicated test
-module.
-
-Documentation tests are grouped by invariant rather than by Markdown page.
-Generic metadata, navigation, source-marker, link, and executable-example
-validators stay parameterized over applicable pages. Page-specific content
-contracts live in a module named for the documentation area they protect.
-Workflow checks belong under `tests/workflows/` only when they
-protect concrete behavior or release safety; they should not duplicate or
-freeze the current CI organization. Tests for maintainer tools and workflow
-safety and all blocking static-analysis checks run through the tracked pre-push
-hook for early feedback, together with the fast publication and user-content
-documentation checks and one compiled scalar-wrapper test that exercises the
-public source-build path through a native call. They remain in GitHub Actions
-for shared enforcement. Enable the hook once per clone with
-`git config core.hooksPath .githooks`.
-
-Test support contains reusable construction or assertion behavior, not an
-alternate import surface for production code. Tests import `pytest`, Python
-standard-library names, and production symbols from their real owners; support
-modules do not re-export them merely to shorten imports.
-
-## Required verification
-
-Run the narrowest owning directory first. After moving or splitting tests, run
-collection before execution and compare node IDs, parametrized suffixes,
-markers, skips, and xfails. Then run every destination touched by the move.
-
-For code or test changes, run the complete static-analysis suite documented in
-`AGENTS.md`. Documentation-only changes use the focused documentation checks
-and whitespace check.
-
-Do not run the complete coverage workflow after each feature. The migration
-records one CI-equivalent baseline and one final new-suite-only comparison.
-Both use `COVERAGE_PROCESS_START=pyproject.toml`, combine subprocess data with
-`python3 -m coverage combine`, and retain per-file executed line and branch
-data. LAPACK remains CI-only unless a maintainer explicitly requests a local
-run.
-
-## Fixture Regeneration
-
-Regenerate broad fixture sets only after a focused test explains the intended
-change. Update the narrowest affected owner:
+Run the narrowest owner first:
```bash
-python3 tests/fortran/source_parsing/parsing/generate_parser_goldens.py \
- tests/fortran/source_parsing/parsing/fixtures/general/basic_subroutine.f90
-python3 tests/fortran/semantic_ir/semantics/generate_semantic_fixtures.py
-WRAPPER_UPDATE_PYI_FIXTURES=1 python3 -m pytest -q \
- tests/fortran/semantic_pyi_format/pipeline/test_contract_package_generation.py
+python3 -m pytest -q tests/fortran//
```
-Include regenerated artifacts only when the parser, semantic IR, or public
-contract representation intentionally changed. Never regenerate a broad set to
-hide uncertainty or unrelated drift.
+After moving or splitting tests, collect first, then run every destination
+touched by the move. The [quality-assurance workflow](workflows/quality-assurance.md)
+defines the required static analysis and broader verification.
diff --git a/docs/developer/workflows/ci.md b/docs/developer/workflows/ci.md
index 2f265247a..f134f6364 100644
--- a/docs/developer/workflows/ci.md
+++ b/docs/developer/workflows/ci.md
@@ -1,120 +1,30 @@
---
-title: Continuous Integration And Delivery
-audience: developers, maintainers, contributors
-prerequisites: testing strategy
-related: ../testing-strategy.md, quality-assurance.md, release.md
+title: Pull Request Checks
+audience: developers, contributors
+prerequisites: quality assurance
+related: contributing.md, quality-assurance.md
status: maintained
-publication: draft
+publication: reviewed
---
-# Continuous Integration And Delivery
+# Pull Request Checks
-GitHub Actions owns repository quality checks and the reviewed-documentation
-deployment. The documentation workflow builds the same filtered MkDocs site
-that maintainers can preview locally, uploads the generated
-`.artifacts/site/` directory, and deploys it through GitHub Pages.
+GitHub Actions supplies the evidence that is impractical to run for every
+local change. It is the final verification for a pull request, not a workflow
+contributors need to administer.
-Workflow names identify a unique pipeline scope, and every job display name is
-self-contained. The `Pull Request` workflow declares the staged validation jobs
-directly, avoiding the extra caller and called-workflow name layers produced by
-nested reusable workflows. Pull requests expose one aggregate required check
-after those jobs complete. Required status checks must use the exact `workflow
-/ job` context documented in the
-[quality-assurance guide](quality-assurance.md). Because GitHub
-treats a renamed check as a different context, update the repository ruleset
-whenever either half of that name changes.
+| Check | What it covers |
+| --- | --- |
+| Static analysis | Linting, formatting, security, dead code, and changed-code complexity policy. |
+| Compiler and platform tests | Supported Python versions, Linux and macOS, GNU Fortran, IFX, and Flang. |
+| Real libraries | BLAS, LAPACK, FFTPACK, and MINPACK wrappers. |
+| Documentation and benchmarks | Required performance benchmark and generated snapshot, documentation tests, and a strict site build. |
-Generated documentation and distribution output lives under the ignored,
-hidden `.artifacts/` directory and must never be committed. Packaging scratch
-output and setuptools `.egg-info` metadata are directed beneath the same hidden
-root. Keeping every generated copy out of the maintained source tree ensures
-rename-aware quality gates compare the previous package directly with its
-current source path instead of matching it to a generated duplicate.
+Run the applicable local checks from [Quality Assurance](quality-assurance.md)
+before opening a pull request. If CI fails, start with the named failing test
+or check and fix the owning behavior. Do not change workflow configuration
+unless the task specifically concerns automation.
-PyPI publication is deliberately separate from ordinary push and pull-request
-workflows. Publishing a GitHub Release triggers a build job, followed by a
-protected `pypi` environment job that authenticates through OpenID Connect.
-See the [release process](release.md) for the exact trusted-publisher
-identity and approval sequence.
-
-## Test Platforms
-
-The `Test Matrix` workflow runs the ordinary suite on Ubuntu with every supported
-Python version. It also runs the complete ordinary suite on macOS 15 with
-Python 3.12 and GNU Fortran 13, preceded by the portable compiler smoke tests.
-Both selections exclude `real_library`; BLAS and LAPACK run only in their
-dedicated Ubuntu workflow.
-
-The `Compiler Compatibility` workflow also runs LLVM Flang on macOS 15. Intel
-IFX remains Linux-only because Intel does not provide IFX for macOS.
-
-For pull requests, `Pull Request` runs code quality and the parser contract
-first. Compiler-compatibility smoke testing starts only after both policy checks
-succeed. The Ubuntu Python 3.12 matrix entry records and uploads project
-coverage, avoiding a second job that would execute the same suite.
-Native-library validation waits for the complete matrix, and the documentation
-performance benchmark and strict site build run last. An `always()` aggregate
-job converts any failed or dependency-skipped required stage into one stable
-ruleset result. The purpose-specific workflows remain independent entry points
-for main, release, scheduled, and manual execution; the pull-request workflow
-does not call them as nested reusable workflows.
-
-## Documentation Publication
-
-The `Pull Request` workflow runs the pinned performance benchmark, consumes its
-generated snapshot, executes the documentation tests, and performs a strict
-production build without deploying. The independent `Documentation` workflow
-runs on pushes to `main` and manual dispatches, repeats those checks, and
-deploys the reviewed site when GitHub Pages is configured to use GitHub
-Actions.
-
-Every validated pull request and push to `main` runs the same prik/f2py
-correctness and rigorous performance suite. The job extracts its platform and
-toolchain metadata, generates the result-dependent Performance page sections
-and SVG, and uploads the generated documentation together with the raw
-`pyperf` files. The website build overlays that artifact before testing and
-building MkDocs. Generated results are deployment inputs, not automated
-commits to `main`.
-
-The benchmark job always targets GitHub's `ubuntu-24.04-arm` standard runner,
-whose hosted pool is based on Microsoft Cobalt 100 processors. It verifies the
-ARM64 architecture and CPU part `0xd49` used by Neoverse N2/Cobalt 100 before
-installing dependencies or measuring. This avoids the different AMD processor
-generations that may back successive x86-64 Ubuntu jobs. The documentation
-build and deployment remain on x86-64 Ubuntu because they consume only the
-generated Markdown and SVG artifact.
-
-The pre-merge benchmark catches code-induced failures before `main`. The
-`main` run is still required because it generates the deployment artifact for
-the merged commit; external runner or service failures can still occur and
-must be retried or diagnosed honestly. The workflow pins the benchmark
-toolchain. Each runtime group uses an A/B/B/A sequence that splits a reduced
-worker budget evenly between PRIK-first and f2py-first measurements, then
-merges both passes before publication. Clean-build rounds alternate tool order.
-Runtime cases use separate latency, medium, and bulk sampling budgets, giving
-nanosecond-scale calls more independent samples without multiplying the cost of
-the largest array workloads. The combined budget targets roughly 20 minutes on
-the pinned runner while retaining all workloads.
-
-Documentation workflow concurrency is isolated by Git ref. Pull-request runs
-may cancel an older run for the same ref, but a `main` run is never canceled by
-a pull request or a newer `main` run. This lets the rigorous ARM64 benchmark
-finish and publish a complete result artifact while still superseding stale
-pull-request documentation checks.
-
-Enable the repository once through **Settings > Pages > Build and deployment >
-Source > GitHub Actions**. Then open **Actions > Documentation > Run workflow**,
-select `main`, and run it. Later documentation changes deploy automatically
-after they are merged or pushed to `main`; maintainers do not build or upload
-`.artifacts/site/` themselves.
-
-Before changing a page to `publication: reviewed`, preview the production view
-with `python3 -m mkdocs serve`. Use
-`PRIK_DOCS_INCLUDE_DRAFTS=1 python3 -m mkdocs serve` to review unpublished
-pages with their draft warning. The lane index must also be reviewed before a
-page in that lane can enter the deployed artifact.
-
-Coverage troubleshooting and the exact local parity commands live in
-[Quality Assurance](quality-assurance.md). Workflow-specific implementation
-details remain in `.github/workflows/`; this page records the stable pipeline
-contract rather than duplicating every YAML step.
+`Pull Request / Validation · all required checks` is the aggregate required
+status before merge. The exact CI implementation lives in
+`.github/workflows/merge-validation.yml`.
diff --git a/docs/developer/workflows/contributing.md b/docs/developer/workflows/contributing.md
index 07818838c..7dbdcbf0a 100644
--- a/docs/developer/workflows/contributing.md
+++ b/docs/developer/workflows/contributing.md
@@ -2,17 +2,15 @@
title: Contributing Workflow
audience: developers, maintainers, contributors
prerequisites: repository checkout, Python 3.10 or newer
-related: ../architecture.md, quality-assurance.md, ../testing-strategy.md, documentation.md
+related: ../architecture.md, ../codebase-map.md, ../feature-to-code-map.md, ../testing-strategy.md, quality-assurance.md, documentation.md
status: maintained
publication: reviewed
---
# Contributing Workflow
-This is the practical workflow for changing PRIK. The root
-[`CONTRIBUTING.md`](../../../CONTRIBUTING.md) is the short public entrypoint;
-this page supplies the complete contributor sequence without duplicating
-package architecture.
+This page is the practical path for changing PRIK. The root
+[`CONTRIBUTING.md`](../../../CONTRIBUTING.md) is the short public entrypoint.
## Prepare The Checkout
@@ -21,170 +19,67 @@ python3 -m pip install -e ".[qa]"
git config core.hooksPath .githooks
```
-Create a focused branch and begin with the smallest test owner for the
-behavior. Do not start with the full suite while discovering the change.
+This enables PRIK's repository pre-push checks for this checkout.
-## Change Workflow
-
-1. Identify the public behavior, limitation, or internal invariant.
-2. Use the [architecture guide](../architecture.md),
- [source map](../source-map.md), or
- [feature-to-code map](../feature-to-code-map.md) to find its owner.
-3. Read the owning package guide and relevant user contract before editing.
-4. Update the documentation contract first when public behavior, ownership,
- or limitations change.
-5. Add or update focused tests at the earliest stage that proves the behavior.
-6. Implement the change in the owning stage and extend downstream stages only
- when their representation or mechanism genuinely changes.
-7. Run focused verification, then the required static and broader checks.
-8. Add a concise **Unreleased** changelog entry for visible behavior,
- workflows, examples, supported features, or limitations.
-
-For policy-sensitive wrapper work, semantic decisions must be complete before
-planning. A binding or bridge change should implement a newly selected plan
-mechanism, not infer a new policy from datatype, intent, aliases, or storage.
-
-## Support Evidence Rule
-
-Documentation may claim support only when current implementation and evidence
-prove it. Acceptable evidence includes:
-
-- a focused test for the contract;
-- a maintained golden that proves exact generated representation;
-- a checked repository command using a maintained fixture; or
-- a compiled/imported/called runtime test for wrapper behavior.
-
-Parser support does not establish semantic or wrapper support. Compilation
-alone does not establish runtime behavior. Unsupported cases should fail at
-the earliest stage with enough facts to report a stable diagnostic.
-
-## Documentation Examples
-
-Important production files expose small public-API examples under
-`if __name__ == "__main__"`; package guides document their exact commands and
-outputs. Their centralized execution owner is
-[`test_execution_examples.py`](../../../tests/fortran/infrastructure/execution_examples/test_execution_examples.py).
-
-Markdown snippets use the repository's checked markers:
-
-````markdown
-
-```bash
-python3 -m prik parse path/to/example.f90
-```
-
-
-```text
-File: path/to/example.f90
-...
-```
-````
-
-Use `prik-doc-test: run` when only successful execution is stable. Use
-`prik-doc-source` for fixture-backed source blocks. Do not mark placeholder,
-checkout-modifying, compiler-environment-dependent, or intentionally failing
-commands as executable documentation.
-
-Run the example documentation checks with:
-
-```bash
-python3 -m pytest -q tests/docs/test_examples.py
-```
-
-## Selecting Tests
+Create a focused branch. Start with the smallest test owner for the behavior,
+not the full suite.
-Use the [testing strategy](../testing-strategy.md) for the authoritative
-placement rules. Common starting points are:
-
-```bash
-python3 -m pytest -q tests/fortran/source_parsing/parsing/
-python3 -m pytest -q tests/fortran/semantic_ir/semantics/
-python3 -m pytest -q tests/fortran/infrastructure/semantics/
-python3 -m pytest -q tests/fortran/infrastructure/codegen/
-python3 -m pytest -q tests/fortran/command_line_interface/pipeline/
-python3 -m pytest -q tests/docs
-```
-
-Use a feature-local `policy/`, `codegen/`, `runtime/`, or `end_to_end/` owner
-when the behavior belongs to a documented feature. Compiled tests must import
-and call the generated API; build success alone is insufficient.
-
-## Common Change Routes
-
-### Add A Fortran Construct
-
-1. Add the smallest parser example under
- `tests/fortran/source_parsing/parsing/` or the feature's parsing owner.
-2. Preserve the new source fact in `prik/parsers/fortran/`; add model fields
- only when downstream consumers need them.
-3. Extend `prik/semantics/fortran2ir.py` and semantic tests only if the
- language-neutral contract changes.
-4. Complete any new ownership, projection, setter, or support decision in
- `prik/policy/` before planning.
-5. Extend the plan and named binding/bridge lowering mechanisms only when the
- completed behavior needs a new representation.
-6. Add feature-local codegen and end-to-end evidence, then update the user
- guide and feature matrix.
-
-Regenerate only an intentionally changed Fortran parser fixture:
-
-```bash
-python3 tests/fortran/source_parsing/parsing/generate_parser_goldens.py \
- tests/fortran/source_parsing/parsing/fixtures/general/basic_subroutine.f90
-```
+## Change Workflow
-### Add Semantic `.pyi` Syntax Or Projection
-
-1. Add syntax tests under `tests/fortran/semantic_pyi_format/parsing/`.
-2. Change `prik/parsers/pyi/parser.py` only if raw Python AST parsing changes;
- otherwise interpret the syntax in `prik/semantics/pyi2ir.py`.
-3. Update `prik/printers/pyi.py` and round-trip tests for emitted syntax.
-4. Update semantic models only when the IR needs a new contract fact.
-5. Complete new behavior in policy, project it through planning, and add
- runtime evidence when the edit affects wrappers.
-6. Update the semantic `.pyi` user reference.
-
-### Add A Code-Generation Backend Or Mechanism
-
-A new backend is not accepted merely because it prints source. It must consume
-the completed shared plan without importing construction rules, define its own
-typed representation and printer boundary, fail closed on unsupported action
-combinations, preserve shared native slots and lifecycle ordering, and provide
-focused generation plus compiled/runtime evidence. Add a backend only after
-the shared plan can express its requirements without backend-specific semantic
-policy.
-
-For a mechanism inside an existing backend, start in the narrow specialized
-emitter named by the package guide. Do not replace specialized methods with a
-flag-driven generic emitter or move semantic decisions down to make the
-mechanism easier to generate.
-
-### Add A Stage-Owned Error
-
-Report a failure at the first stage with enough facts to explain it. Syntax and
-source-processing failures belong to preprocessing/parsing; invalid contracts
-belong to semantic conversion; unsafe ownership, ABI, projection, or support
-belongs to completed policy; inconsistent plan projection belongs to planning;
-an unavailable emitted mechanism belongs to backend preflight. Assert the
-stable owner path and reason at that stage rather than forcing a known failure
-through native compilation.
-
-## Pull Request And Review
-
-Before opening a pull request:
-
-- keep the change focused and remove superseded implementation/tests/docs;
-- explain the problem, stage ownership, solution, and verification;
-- identify user-visible behavior and limitations;
-- run the applicable focused tests and the required checks from
- [Quality Assurance](quality-assurance.md); and
-- ensure all required GitHub checks pass before merge.
-
-Review should verify dependency direction, completed-policy authority,
-diagnostic ownership, focused and end-to-end evidence, generated ABI stability,
-documentation consistency, and removal of obsolete paths. Reviewers should not
-accept a compatibility alias for an intentionally moved internal API unless
-the change explicitly requires one.
+1. Define the behavior, limitation, diagnostic, or internal invariant.
+2. Find its owner through the [architecture guide](../architecture.md),
+ [codebase map](../codebase-map.md), or
+ [feature-to-code map](../feature-to-code-map.md). Read the owning
+ architecture component guide and any relevant user contract.
+3. Update the documentation contract first when public behavior, ownership, or
+ limitations change.
+4. Use the [testing strategy](../testing-strategy.md) to add or update focused
+ evidence at the earliest stage that can prove the behavior.
+5. Change the owning stage. Extend later stages only when their representation
+ or mechanism must change.
+6. Run focused verification, then the checks required by
+ [Quality Assurance](quality-assurance.md).
+7. Add an **Unreleased** changelog entry for visible behavior, supported
+ features, examples, workflows, or limitations.
+
+For wrapper work, policy must complete every semantic decision before planning.
+Binding and bridge code implement the selected plan; they do not infer policy
+from datatype, intent, aliases, or storage.
+
+## Evidence And Documentation
+
+Documentation may claim support only when implementation and evidence prove it.
+Parser evidence does not establish semantic or wrapper support, and compilation
+does not establish runtime behavior. A public wrapper claim needs a build,
+import, call, and observable result. Unsupported input should fail at the first
+stage with enough facts for a stable diagnostic.
+
+Architecture component guides may show a production-file command and
+representative result.
+The documentation suite runs those pairs and uses the page as the expected
+output. Stable output is exact; excerpts and target-dependent output are
+checked only for the facts shown. See
+[Documentation maintenance](documentation.md) when adding executable Markdown
+examples.
+
+Use the [testing strategy](../testing-strategy.md) for test ownership. Keep
+user-visible behavior in its feature owner, not `infrastructure/`. A compiled
+test must import and call the generated API; build success alone is not enough.
+
+## Stage Boundaries
+
+Add a source fact in parsing, its language-neutral meaning in semantics, and
+ownership or support decisions in policy. Planning projects completed policy;
+code generation, printing, and compilation implement that projection. Put a
+new diagnostic at the first stage that can explain it. The architecture and
+architecture component guides describe these boundaries in detail.
+
+## Pull Request
+
+Keep the pull request focused. Describe the problem, owner, behavior change,
+and verification; identify user-visible limitations. Remove superseded code,
+tests, and documentation. The hosted checks are summarized in
+[Pull request checks](ci.md).
## Contribution License
diff --git a/docs/developer/workflows/documentation.md b/docs/developer/workflows/documentation.md
index 487c2cae5..497e61532 100644
--- a/docs/developer/workflows/documentation.md
+++ b/docs/developer/workflows/documentation.md
@@ -1,233 +1,72 @@
---
-title: Documentation Architecture
+title: Documentation Maintenance
audience: developers, maintainers, contributors
-prerequisites: repository checkout, documentation metadata standard
-related: ../architecture.md, ../testing-strategy.md, ../../user/index.md
+prerequisites: repository checkout
+related: ../architecture.md, ../testing-strategy.md, quality-assurance.md, ../../user/index.md
status: maintained
-publication: draft
+publication: reviewed
---
-# Documentation Architecture
+# Documentation Maintenance
-This page defines how prik documentation is organized and maintained. It is a
-repository-governance contract, not part of the product-learning material.
-`mkdocs.yml` owns the complete intended navigation for the User and Contributor
-areas. A publication hook filters that tree so GitHub Pages contains only
-pages explicitly marked as reviewed.
+PRIK has two active documentation areas: `docs/user/` for product users and
+`docs/developer/` for contributors and maintainers. `mkdocs.yml` defines the
+page order, and `docs_theme/nav.html` makes each expandable section label open
+its first page while its **+** control expands or collapses the section.
+`old_docs/` is historical material outside the site.
-## Architecture Principles
+## Write The Right Contract
-1. Active documentation has two physical areas: `user/` and `developer/`. The
- latter is presented as Contributor Documentation and serves developers,
- maintainers, and future contributors from one architectural account. Both
- areas may be published after review.
-2. `docs/index.md` is the website entry point. Each area index gates its whole
- area: a draft area index prevents every page below that area from entering
- the production site, even when an individual child page is marked reviewed.
-3. Implemented behavior is documented as supported only when current code and
- tests prove it. Public user pages describe behavior and limits without
- exposing internal test-evidence ledgers.
-4. Planned behavior is marked explicitly and never presented as an implemented
- user contract.
-5. Contributor governance and volatile internals do not appear in user workflows.
-6. Historical material remains under `old_docs/` and outside active navigation.
-7. User-facing source-driven examples show the complete input source before the
- command that consumes it. Generated paths must come from an immediately
- preceding command, and commands show their expected result. Fixture-backed
- examples stay synchronized with their checked source.
-8. The website keeps its documentation navigation expanded, shows a draggable
- scrollbar when the sidebar is longer than the screen, and renders an
- accessible copy control on every code block, including command-output and
- result blocks.
-9. On desktop-sized viewports, the page body starts beside the navigation and
- uses a `1200px` maximum width: wider than the theme default for code and
- tables, but still bounded for readable prose. Any unused space remains on
- the far right rather than separating the sidebar from the content.
-10. Code and result blocks use a consistent responsive width capped at `56rem`.
- They reserve dedicated right-side space for the copy control, and long lines
- scroll inside the block instead of widening the page.
+User pages explain supported behavior and its limits. Contributor pages explain
+ownership, architecture, tests, and maintenance. Planned work must be marked
+as planned, not as current support.
-`docs/index.md` is the user-first project entrance. It uses the canonical
-`PRIK — Python Runtime Interop Kit` identity and public description, shows the
-shortest checked source-to-import workflow, summarizes the product's concrete
-advantages, and links to real-library evidence before sending the reader into
-Getting Started. Contributor and deeper User Guide destinations stay available
-through site navigation instead of competing with that first task.
-The FAQ uses natural task questions as concise routes to authoritative guides;
-it does not duplicate those guides.
+Support claims require current implementation and evidence. A parser test does
+not prove wrapper support, and a successful build does not prove runtime
+behavior. Examples must be complete enough to run in a clean checkout: show
+the input before the command that consumes it, and show the result when it
+helps the reader verify success.
-## Audience Areas
+For one user-guide example with two or more matching views, use the
+`prik-example-tabs` component. When an example shows both **Fortran source**
+and **Python usage**, include the complete generated `.pyi` as the third view.
+Later sections may quote only the relevant contract snippet. Use only the
+relevant pair when source is absent. Select source first when it exists;
+otherwise select the contract first. Put the `generate --pyi` command directly
+below the contract, mirroring the build command below the source. Place the
+observable result immediately after the tab set. Do not use it in Getting
+Started, whose pages should remain linear.
-| Area | Primary reader | Publication | Content |
-| --- | --- | --- | --- |
-| `user/` | People using prik | Documentation website after review | Getting Started, guides, performance benchmarks, tutorials, examples, public reference, support status, FAQ, troubleshooting |
-| `developer/` | Developers, maintainers, and future contributors changing or governing prik | Documentation website after review | Architecture, package guides, cross-stage concepts, source navigation, testing, contribution and project workflows, design decisions, active roadmaps, and deferred input-language references |
+When an example teaches a contract edit, add a separate **Generated contract**
+view before **Edited contract**. Put the generation command below the former
+and the edited-contract build command below the latter.
-Pages use their task and stability for placement within the contributor tree.
-Implemented architecture, design proposals, roadmaps, and release procedures
-remain separate topics, but they do not claim separate architectural
-audiences. Cross-area links between user and contributor documentation should
-explain why the reader is leaving the current task.
+## Add Or Update A Page
-## Reading Order And Cross-Links
+1. Put the page in the user or contributor area that matches its reader and
+ task.
+2. Add front matter with `title`, `audience`, `prerequisites`, `related`,
+ `status`, and `publication`.
+3. Add it to `mkdocs.yml` in its intended reading order and update necessary
+ index or contextual links.
+4. Keep related source, tests, commands, and limitations accurate.
-The `nav` sequence in `mkdocs.yml` is the canonical reading order. Sequential
-User documentation pages may link back to pages the reader has already
-completed. They must not link from instructional prose to a later page in that
-sequence. Explicit terminal navigation blocks headed `Next` may link forward
-because choosing a next destination is their purpose. Outside those blocks,
-name the later topic in plain text and say that it is covered later instead of
-asking the reader to leave the current task.
-When a section index presents an ordered reading list of pages in that same
-section, keep the list and the matching `mkdocs.yml` subsection in the same
-order so sidebar next/previous navigation follows the advertised route.
-`Next` blocks list destinations as bullets, and each bullet includes at least
-one Markdown link. If an intended destination page does not exist yet, either
-remove the destination until it is useful or create the draft page with
-metadata and a TODO section.
-
-Each page includes the behavior, warning, ownership fact, or limitation needed
-for its current task. A forward reference never defers a fact needed now.
-README documentation lists, area indexes, and explicit navigation menus are
-exceptions because choosing a destination is their purpose. Same-page anchors
-and links to source or test evidence do not change documentation reading order.
-Contextual links to `user/reference/pyi-contracts/` are also allowed after a
-Getting Started or User Guide section has already taught a complete small
-contract edit. These links provide optional lookup of the full editing rules;
-they must not replace instructions required to complete the current example.
-
-## Page Metadata Contract
-
-Every page under `docs/` starts with front matter containing:
-
-- `title`: navigation title;
-- `audience`: primary intended readers;
-- `prerequisites`: assumed knowledge or pages;
-- `related`: adjacent pages; and
-- `status`: `maintained`, `draft`, `planned-documentation`,
- `not-yet-implemented`, `design`, or `active-roadmap`;
-- `publication`: `draft` until a maintainer has reviewed the page for the
- website, then `reviewed`.
-
-Pages with status `draft`, `planned-documentation`, or
-`not-yet-implemented` include a `## TODO` section.
-
-## Publication Review Contract
-
-Publication is fail-closed. A missing or unknown `publication` value is treated
-as `draft`. Production builds include a Markdown page only when:
-
-1. its own front matter says `publication: reviewed`;
-2. `docs/index.md` is reviewed; and
-3. for a page in `user/` or `developer/`, that area's index is also reviewed
- (`user/index.md` or `developer/index.md`).
-
-The publication hook removes every other Markdown page from the MkDocs file
-collection and navigation before rendering, so drafts do not enter generated
-HTML, search, or the sitemap. When a reviewed page mentions an unpublished
-documentation page, the production build keeps the link visible with its
-expected website route even though the target page itself is not published.
-Links to existing repository evidence outside the `docs/` tree are rewritten to
-the matching file or directory on GitHub; links to missing targets remain
-unchanged so the strict build can reject them. Links to another active
-documentation page or directory must stay relative to `docs/`.
-
-Use the normal local server to preview exactly what GitHub Pages will publish:
+## Verify Locally
```bash
+python3 -m pytest -q tests/docs
+git diff --check
python3 -m mkdocs serve
+python3 -m mkdocs build --strict
```
-Use the explicit draft-preview environment flag while reviewing unpublished
-pages locally:
+`tests/docs` checks links, metadata, public references, and executable
+examples. Package-guide production commands are checked against the result
+shown in the guide.
+
+New pages remain `publication: draft` until a maintainer reviews them. To
+preview draft pages locally, run:
```bash
PRIK_DOCS_INCLUDE_DRAFTS=1 python3 -m mkdocs serve
```
-
-Draft preview adds a visible warning to unpublished pages. Changing a page from
-`publication: draft` to `publication: reviewed` is the only publication-state
-edit. Existing navigation remains the intended complete tree; the hook reveals
-reviewed entries automatically. New pages must still be added to `mkdocs.yml`.
-
-## Repository Tree
-
-```text
-docs/
- index.md
- user/
- index.md
- performance.md
- getting-started/
- guide/
- tutorials/
- examples/
- reference/
- language-support/
- faq/
- troubleshooting/
- developer/
- index.md
- architecture.md
- source-map.md
- feature-to-code-map.md
- testing-strategy.md
- packages/
- concepts/
- workflows/
- design/
- roadmap/
- deferred/
- javascripts/
- code-copy.js
- stylesheets/
- site.css
- code-copy.css
- old_docs/
-```
-
-The repository-root `CHANGELOG.md` is the canonical release history. It lives
-beside `README.md` and `pyproject.toml` so GitHub and package users can find it
-without navigating the documentation website.
-
-New active pages must be created in one of the two areas. Website-only static
-behavior and presentation assets live in `javascripts/` and `stylesheets/`.
-Do not restore separate developer/maintainer architecture trees or place
-contributor governance beside the website landing page. Historical
-`old_docs/` material is never eligible for website publication.
-
-The Performance page keeps its explanatory text and reproduction workflow in
-reviewed Markdown. Result-dependent summary, table, and environment blocks are
-bounded by `prik-performance-*` comments and are generated from paired `pyperf`
-files by `tools/generate_performance_docs.py`. The same tool owns the runtime
-comparison SVG and the clean-build comparison SVG. Clean-build results contain
-development and optimized compiler profiles and record the compiler-process
-limit used by prik; f2py retains its normal Meson/Ninja scheduler. Generation
-must fail when a marker is missing or duplicated;
-it must not rewrite prose outside those blocks. The environment block records
-both the operating-system distribution and the lower-level platform string so
-published results identify the benchmark host clearly.
-
-Automated performance snapshots run on the fixed `ubuntu-24.04-arm` workflow
-label after verifying its Neoverse N2/Cobalt 100 CPU part. The benchmark scripts
-add an architecture-neutral CPU identity to every runtime and build result
-because pyperf's Linux metadata collector does not report `cpu_model_name` on
-every ARM64 `/proc/cpuinfo` format. Documentation generation continues to
-require matching CPU metadata across each prik/f2py result pair.
-Runtime results combine equal reduced worker budgets from PRIK-first and
-f2py-first passes in the same job. The merged suites drive publication, while
-the order-specific suites remain in the uploaded artifact for auditability.
-
-## Continuous Documentation Quality
-
-- Require metadata for every active page.
-- Keep website navigation, repository routing, area indexes, and physical areas
- synchronized.
-- Reject draft pages and draft-gated areas from published site navigation.
-- Require explicit publication metadata on every active page.
-- Check that User documentation does not link forward from instructional prose,
- except for the documented contextual `.pyi` contract references.
-- Treat unsupported-feature placeholders as blocking reminders during feature
- completion.
-- Run link, structure, generated-reference freshness, and executable-example
- checks in CI.
diff --git a/docs/developer/workflows/quality-assurance.md b/docs/developer/workflows/quality-assurance.md
index 4a7db95fb..dbfd28890 100644
--- a/docs/developer/workflows/quality-assurance.md
+++ b/docs/developer/workflows/quality-assurance.md
@@ -4,14 +4,13 @@ audience: developers, maintainers, contributors
prerequisites: repository checkout, QA dependencies
related: contributing.md, ../testing-strategy.md, ci.md
status: maintained
-publication: draft
+publication: reviewed
---
# Quality Assurance
-This page records the active quality stack and commands. Historical rollout
-logs and completed tool-adoption checklists belong in Git history, not in the
-current contributor workflow.
+This page defines the local evidence expected before a pull request. Start
+with the smallest owner; CI provides broader platform and library evidence.
## Install
@@ -20,26 +19,7 @@ python3 -m pip install -e ".[qa]"
python3 tools/check_static_analysis_versions.py
```
-## Active Cadence
-
-| Cadence | Evidence |
-| --- | --- |
-| Inner loop | Smallest owning pytest target and Ruff on changed code |
-| Local pre-push | Blocking static analysis, focused documentation smoke, one compiled scalar-wrapper smoke, `tests/tools/`, and `tests/workflows/` |
-| Pull request | Static analysis, compiler smoke, Python matrix, project coverage, real libraries, performance/docs, aggregate required check |
-| Manual discovery | Deep Hypothesis fuzz profile and advisory complexity reports |
-| Dependency change or annual review | Dependency vulnerability review |
-
-The one stable required ruleset context is:
-
-```text
-Pull Request / Validation · all required checks
-```
-
-If the workflow or job display name changes, update the repository ruleset;
-do not keep an alias job for the old name.
-
-## Focused And Documentation Checks
+## Routine Verification
Run the narrowest behavioral owner first:
@@ -47,16 +27,15 @@ Run the narrowest behavioral owner first:
python3 -m pytest -q path/to/owning/tests
```
-Documentation-only changes that do not alter Python, tests, build
-configuration, or tooling use:
+For documentation-only changes:
```bash
python3 -m pytest -q tests/docs
git diff --check
```
-When Python code, test logic, build behavior, or tools change, run the complete
-blocking and advisory static suite:
+For Python, test, build, or tool changes, run focused tests and the static
+suite:
```bash
python3 -m ruff check .
@@ -70,15 +49,14 @@ python3 -m radon cc prik -n C -s --total-average
python3 -m radon mi prik -s
```
-Ruff, Bandit, Vulture, codegen complexity, version checks, and the changed-code
-Radon policy are blocking. Full Radon reports are advisory. If automatic Radon
-base detection lacks CI SHA metadata locally, rerun with `--base-ref main` and
-report that fact.
+Ruff, Bandit, Vulture, version checks, and the changed-code Radon policy are
+blocking. The codegen review and full Radon reports are advisory. If automatic
+Radon base detection lacks CI SHA metadata, rerun with `--base-ref main`.
-## Coverage And Test-Order Reproduction
+## Broader Evidence
-Do not run the complete coverage workflow for routine changes. When
-investigating a CI coverage failure, mirror subprocess collection exactly:
+Do not run complete coverage for routine changes. When investigating a CI
+coverage failure, mirror CI collection:
```bash
COVERAGE_PROCESS_START=pyproject.toml \
@@ -88,61 +66,35 @@ python3 -m coverage combine
python3 -m coverage report
```
-The blocking project coverage target is 90%. Codecov patch status is
-informational, but new reachable behavior still needs focused tests.
-
-Reproduce an order-dependent failure with the seed from CI:
+The project coverage target is 90%. Reproduce an order-dependent failure with
+the seed from CI:
```bash
python3 -m pytest -q --randomly-seed=
```
-## Compiler And Property Evidence
-
-Run a configured alternate-compiler lane with:
+Run an alternate compiler lane when changing compiler portability or native
+generation:
```bash
python3 tools/run_fortran_toolchain_lane.py --compiler=/path/to/ifx
python3 tools/run_fortran_toolchain_lane.py --compiler=/path/to/flang
```
-`--plan` prints the selected tests without running them. CI currently pins
-IFX/ICX 2026.1.1 and Flang/Clang 22.1.8 as evidence versions, not declared
-minimum versions.
-
-Run property and deep fuzz profiles with:
+Run property or fuzz profiles when changing generated invariants or
+investigating a failure:
```bash
python3 -m pytest -q -m property --hypothesis-profile=ci
HYPOTHESIS_PROFILE=fuzz python3 -m pytest -q -m fuzz --hypothesis-show-statistics
```
-Minimize an actionable fuzz failure and preserve it as a focused regression in
-the owning feature/stage suite.
-
-## Tool Responsibilities
-
-| Tool | Role |
-| --- | --- |
-| pytest and coverage.py | Behavioral regression and project coverage |
-| pytest-randomly | Stable-seed order-coupling detection |
-| Hypothesis | Generated parser, semantic, and codegen invariants |
-| Ruff | Linting, formatting, modernization, and bounded McCabe checks |
-| Bandit | Medium-confidence/severity security boundary review |
-| Vulture | Dead-code detection with narrow exclusions |
-| Radon | Blocking changed-hotspot policy plus advisory project reports |
-| GitHub Actions | Reproducible shared compiler, platform, library, benchmark, docs, and release evidence |
-
-Mutation testing and pre-commit are not part of the active stack. The tracked
-`.githooks` pre-push hook is the supported local automation boundary.
-
-## Real Libraries And Verification Limits
+Minimize an actionable fuzz failure and retain it as a focused regression.
-Ordinary local suites exclude `real_library`. BLAS, FFTPACK, and MINPACK may be
-run through their documented example workflows. LAPACK wrapper tests remain a
-GitHub Actions responsibility unless explicitly requested locally.
+## Limits
-GitHub Actions writes path-aware JUnit reports and prints failed pytest node
-IDs at the end of failed matrix logs. The real-library lane builds and tests
-the complete maintained BLAS, LAPACK, FFTPACK, and MINPACK examples using their
-documented entrypoints.
+Native changes need focused codegen evidence and relevant end-to-end coverage.
+Ordinary local runs exclude `real_library`. BLAS, FFTPACK, and MINPACK have
+their own example workflows; leave LAPACK wrapper tests to GitHub Actions
+unless explicitly requested. See [Pull request checks](ci.md) for hosted
+coverage, compiler, real-library, benchmark, and documentation evidence.
diff --git a/docs/developer/workflows/release.md b/docs/developer/workflows/release.md
deleted file mode 100644
index a38c3aee8..000000000
--- a/docs/developer/workflows/release.md
+++ /dev/null
@@ -1,114 +0,0 @@
----
-title: Release Process
-audience: maintainers
-prerequisites: CI/CD, changelog
-related: ci.md, quality-assurance.md
-status: maintained
-publication: reviewed
----
-
-# Release Process
-
-PRIK publishes source distributions and universal Python wheels to PyPI from a
-GitHub Release. GitHub Actions authenticates with PyPI through OpenID Connect;
-the repository does not store a long-lived PyPI token.
-
-## Package Identity
-
-The public names are fixed as follows:
-
-| Surface | Name |
-| --- | --- |
-| PyPI distribution | `prik` |
-| Python package | `prik` |
-| Console command | `prik` |
-| Module command | `python -m prik` |
-| GitHub repository | `PyNumLab/prik` |
-
-Release tags use `v`, for example `v0.1.0`. The version without the
-leading `v` must exactly match `[project].version` in `pyproject.toml`.
-
-## One-Time Trusted Publisher Setup
-
-Before the first release, add a pending trusted publisher at
- with these exact values:
-
-| PyPI field | Value |
-| --- | --- |
-| PyPI project name | `prik` |
-| GitHub owner | `PyNumLab` |
-| Repository name | `prik` |
-| Workflow name | `publish-to-pypi.yml` |
-| Environment name | `pypi` |
-
-The pending publisher creates the PyPI project on the first successful
-publication. It does not reserve the name before that upload.
-
-In the GitHub repository, create an environment named `pypi` under **Settings
-> Environments**. Add a required reviewer so publication pauses for explicit
-approval. Do not add a PyPI API token or password to GitHub secrets.
-
-## Prepare a Release
-
-1. Choose a version that does not already exist on PyPI.
-2. Set `[project].version` in `pyproject.toml`.
-3. Move the user-visible entries from **Unreleased** into a versioned section
- in the repository-root [`CHANGELOG.md`](../../../CHANGELOG.md).
-4. Run the focused package checks and the repository's required static
- analysis. Let GitHub Actions run the complete cross-platform suite.
-5. Merge the release preparation through the normal review process and wait
- for the `main` branch checks to pass.
-
-Build the same artifacts locally when reviewing the release candidate:
-
-```bash
-python3 -m pip install --upgrade build twine
-python3 -m build --outdir .artifacts/dist
-python3 -m twine check .artifacts/dist/*
-```
-
-`.artifacts/dist/` must contain one source distribution and one universal
-wheel. The hidden `.artifacts/` tree contains reproducible local and CI output;
-only its ignore placeholder is maintained source. The repository-root
-`setup.cfg` also directs setuptools' temporary `.egg-info` metadata into that
-hidden tree. The source distribution must include the repository-root
-`CHANGELOG.md`. Install the wheel in a fresh virtual environment and verify
-`prik --version`,
-`prik.__version__`, `prik --help`, and `python -m prik --help` before creating
-the release.
-
-## Publish
-
-Create a GitHub Release from the exact reviewed commit and use a tag matching
-the project version, such as `v0.1.0`. Use that version's section from
-[`CHANGELOG.md`](../../../CHANGELOG.md) as the release notes. Publishing the
-GitHub Release triggers `.github/workflows/publish-to-pypi.yml`.
-
-The workflow builds and checks the artifacts in an unprivileged job. A
-separate `pypi` environment job downloads only those artifacts, requests an
-OpenID Connect identity token, and uploads them with PyPA's publishing action.
-Approve that environment deployment only after checking the tag, commit, and
-artifact job.
-
-PyPI versions and files are immutable. Never delete and recreate a tag to
-replace a published version; fix the problem and publish a new version.
-
-## Verify the Published Package
-
-After the workflow succeeds, use a clean environment so a source checkout
-cannot mask packaging errors:
-
-```bash
-python3 -m venv /tmp/prik-release-check
-/tmp/prik-release-check/bin/python -m pip install --upgrade pip
-/tmp/prik-release-check/bin/python -m pip install prik==0.1.0
-/tmp/prik-release-check/bin/prik --version
-/tmp/prik-release-check/bin/python -c 'import prik; print(prik.__version__)'
-/tmp/prik-release-check/bin/prik --help
-/tmp/prik-release-check/bin/python -m prik --help
-```
-
-Confirm the version and both distribution files on
-. If a release is unsafe to install, yank it on
-PyPI and publish a corrected version; yanking is preferable to deleting files
-because it preserves reproducibility for exact version pins.
diff --git a/docs/index.md b/docs/index.md
index 44dafb94c..f7e578464 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -3,7 +3,7 @@ title: PRIK — Python Runtime Interop Kit
description: PRIK generates native Python bindings from Fortran projects, producing importable extensions and editable .pyi contracts for Pythonic APIs.
audience: users
prerequisites: none
-related: user/getting-started/index.md, user/getting-started/installation.md, user/performance.md
+related: user/getting-started/index.md, user/getting-started/installation.md, user/performance.md, developer/architecture.md
status: maintained
publication: reviewed
---
@@ -25,6 +25,8 @@ to support more native languages over time.
---
+
+
## From Fortran to Python in one command
Install the package in a virtual environment:
@@ -110,3 +112,7 @@ values below `1.0×` favor f2py.
[Install PRIK →](user/getting-started/installation.md){ .prik-primary-cta }
[Read Getting Started →](user/getting-started/index.md){ .prik-primary-cta }
+
+**Working on PRIK itself?**
+
+[Read Developer Documentation →](developer/index.md){ .prik-primary-cta }
diff --git a/docs/javascripts/example-tabs.js b/docs/javascripts/example-tabs.js
new file mode 100644
index 000000000..365cbda31
--- /dev/null
+++ b/docs/javascripts/example-tabs.js
@@ -0,0 +1,87 @@
+(function () {
+ "use strict";
+
+ function activateTab(tabs, panels, selected) {
+ const panelId = selected.getAttribute("aria-controls");
+ tabs.forEach(function (tab) {
+ const isSelected = tab === selected;
+ tab.setAttribute("aria-selected", String(isSelected));
+ tab.tabIndex = isSelected ? 0 : -1;
+ });
+ panels.forEach(function (panel) {
+ panel.hidden = panel.id !== panelId;
+ });
+ }
+
+ function activateFragmentTab(example, tabs, panels) {
+ if (!window.location.hash) {
+ return false;
+ }
+
+ const target = document.getElementById(window.location.hash.slice(1));
+ const panel = target && target.closest(".prik-example-panel");
+ if (!panel || !example.contains(panel)) {
+ return false;
+ }
+
+ const tab = tabs.find(function (candidate) {
+ return candidate.getAttribute("aria-controls") === panel.id;
+ });
+ if (!tab) {
+ return false;
+ }
+
+ activateTab(tabs, panels, tab);
+ return true;
+ }
+
+ function initialiseExampleTabs(example) {
+ const tabs = Array.from(example.querySelectorAll('[role="tab"]'));
+ const panels = tabs
+ .map(function (tab) {
+ return document.getElementById(tab.getAttribute("aria-controls"));
+ })
+ .filter(Boolean);
+ if (tabs.length < 2 || panels.length !== tabs.length) {
+ return;
+ }
+
+ const selected = tabs.find(function (tab) {
+ return tab.getAttribute("aria-selected") === "true";
+ }) || tabs[0];
+ if (!activateFragmentTab(example, tabs, panels)) {
+ activateTab(tabs, panels, selected);
+ }
+
+ tabs.forEach(function (tab, index) {
+ tab.addEventListener("click", function () {
+ activateTab(tabs, panels, tab);
+ });
+ tab.addEventListener("keydown", function (event) {
+ const offsets = { ArrowLeft: -1, ArrowRight: 1, Home: -index, End: tabs.length - index - 1 };
+ if (!(event.key in offsets)) {
+ return;
+ }
+ event.preventDefault();
+ const nextIndex = (index + offsets[event.key] + tabs.length) % tabs.length;
+ const next = tabs[nextIndex];
+ activateTab(tabs, panels, next);
+ next.focus();
+ });
+ });
+
+ window.addEventListener("hashchange", function () {
+ activateFragmentTab(example, tabs, panels);
+ });
+ }
+
+ function initialiseExampleTabSets() {
+ document.querySelectorAll("[data-prik-example-tabs]").forEach(initialiseExampleTabs);
+ }
+
+ if (document.readyState === "loading") {
+ document.addEventListener("DOMContentLoaded", initialiseExampleTabSets);
+ } else {
+ initialiseExampleTabSets();
+ }
+})();
diff --git a/docs/javascripts/term-tooltips.js b/docs/javascripts/term-tooltips.js
new file mode 100644
index 000000000..fbffea833
--- /dev/null
+++ b/docs/javascripts/term-tooltips.js
@@ -0,0 +1,295 @@
+(function () {
+ "use strict";
+
+ const termDefinitions = {
+ ".pyf": {
+ id: "pyf",
+ label: "What is a .pyf file?",
+ text: "An f2py signature file. It describes the Fortran routines and interface used to generate a Python extension.",
+ },
+ ".pyi": {
+ id: "pyi",
+ label: "What is a .pyi file?",
+ text: "A Python stub file standardized by PEP 484. It contains type hints and API signatures rather than executable runtime code. In PRIK, a semantic .pyi file is also an editable contract for the Python API and its mapping to native procedures.",
+ },
+ };
+ const textTermDefinitions = {
+ abi: {
+ id: "abi",
+ label: "What is an ABI?",
+ text: "Application Binary Interface: the low-level rules that let Python and compiled code communicate correctly. They define how functions receive arguments, how values are represented in memory, and how functions return results.",
+ },
+ "c-order": {
+ id: "c-order",
+ label: "What is C-order?",
+ text: "C-style, row-major array layout: values in the last index are next to each other in memory.",
+ },
+ "f-order": {
+ id: "f-order",
+ label: "What is F-order?",
+ text: "Fortran-style, column-major array layout: values in the first index are next to each other in memory.",
+ },
+ gil: {
+ id: "gil",
+ label: "What is the GIL?",
+ text: "Global Interpreter Lock: CPython's lock around interpreter execution. Native code may release it only when it does not need to access Python objects.",
+ },
+ "semantic ir": {
+ id: "semantic-ir",
+ label: "What is semantic IR?",
+ text: "Semantic intermediate representation: PRIK's shared, language-neutral model of an API. Source and .pyi contracts are converted into this model before PRIK decides how to build the wrapper.",
+ },
+ };
+ const textTermPattern = /\b(?:ABI|semantic IR|Fortran-order|F-order|C-order|GIL)\b/gi;
+
+ function normalisePath(path) {
+ return path.replace(/index\.html$/, "").replace(/\/+$/, "/");
+ }
+
+ function supportsTermTooltips() {
+ const homeLink = document.querySelector(".wy-side-nav-search > a");
+ const currentPath = normalisePath(window.location.pathname);
+ const homePath = homeLink
+ ? normalisePath(new URL(homeLink.getAttribute("href"), window.location.href).pathname)
+ : "";
+
+ return currentPath === homePath || /\/user(?:\/|$)/.test(currentPath);
+ }
+
+ function setOpen(wrapper, isOpen) {
+ const trigger = wrapper.querySelector(".prik-term-trigger");
+ wrapper.classList.toggle("is-open", isOpen);
+ if (trigger.hasAttribute("aria-expanded")) {
+ trigger.setAttribute("aria-expanded", String(isOpen));
+ }
+ if (isOpen) {
+ window.requestAnimationFrame(function () {
+ positionTooltip(wrapper);
+ });
+ }
+ }
+
+ function positionTooltip(wrapper) {
+ const tooltip = wrapper.querySelector(".prik-term-tooltip");
+ const trigger = wrapper.querySelector(".prik-term-trigger");
+ const margin = 12;
+ const viewportWidth = document.documentElement.clientWidth;
+ const viewportHeight = document.documentElement.clientHeight;
+ const triggerBounds = trigger.getBoundingClientRect();
+ const tooltipWidth = tooltip.offsetWidth;
+ const tooltipHeight = tooltip.offsetHeight;
+ const preferredLeft = triggerBounds.left + triggerBounds.width / 2;
+ const left = Math.min(
+ Math.max(preferredLeft, margin + tooltipWidth / 2),
+ viewportWidth - margin - tooltipWidth / 2,
+ );
+ let top = triggerBounds.top - tooltipHeight - margin;
+ const opensBelow = top < margin;
+
+ if (opensBelow) {
+ top = Math.min(triggerBounds.bottom + margin, viewportHeight - tooltipHeight - margin);
+ }
+ tooltip.classList.toggle("prik-term-tooltip-below", opensBelow);
+ tooltip.style.left = Math.round(left) + "px";
+ tooltip.style.top = Math.round(Math.max(margin, top)) + "px";
+ }
+
+ function repositionOpenTooltips() {
+ document.querySelectorAll(".prik-term-wrap.is-open").forEach(positionTooltip);
+ }
+
+ function closeAll(except) {
+ document.querySelectorAll(".prik-term-wrap.is-open").forEach(function (wrapper) {
+ if (wrapper !== except) {
+ setOpen(wrapper, false);
+ }
+ });
+ }
+
+ function createTooltip(visibleTerm, definition, index, link) {
+ const wrapper = document.createElement("span");
+ const trigger = document.createElement(link ? "span" : "button");
+ const tooltip = document.createElement("span");
+ const tooltipId = "prik-" + definition.id + "-tooltip-" + index;
+
+ wrapper.className = "prik-term-wrap";
+ trigger.className = "prik-term-trigger";
+ if (link) {
+ const describedBy = link.getAttribute("aria-describedby");
+ link.setAttribute("aria-describedby", [describedBy, tooltipId].filter(Boolean).join(" "));
+ } else {
+ trigger.type = "button";
+ trigger.setAttribute("aria-describedby", tooltipId);
+ trigger.setAttribute("aria-expanded", "false");
+ trigger.setAttribute("aria-label", definition.label);
+ }
+ tooltip.className = "prik-term-tooltip";
+ tooltip.id = tooltipId;
+ tooltip.setAttribute("role", "tooltip");
+ tooltip.textContent = definition.text;
+
+ trigger.append(visibleTerm);
+ wrapper.append(trigger, tooltip);
+
+ const control = link || trigger;
+ control.addEventListener("focus", function () {
+ closeAll(wrapper);
+ setOpen(wrapper, true);
+ });
+ control.addEventListener("blur", function () {
+ setOpen(wrapper, false);
+ });
+ control.addEventListener("pointerenter", function () {
+ closeAll(wrapper);
+ setOpen(wrapper, true);
+ });
+ control.addEventListener("pointerleave", function () {
+ if (document.activeElement !== control) {
+ setOpen(wrapper, false);
+ }
+ });
+ if (!link) {
+ trigger.addEventListener("click", function () {
+ closeAll(wrapper);
+ setOpen(wrapper, true);
+ });
+ trigger.addEventListener("keydown", function (event) {
+ if (event.key === "Escape") {
+ setOpen(wrapper, false);
+ trigger.blur();
+ }
+ });
+ }
+
+ return wrapper;
+ }
+
+ function enhanceCodeTerm(term, index) {
+ const definition = termDefinitions[term.textContent];
+ const wrapper = createTooltip(term.cloneNode(true), definition, index, term.closest("a"));
+ term.replaceWith(wrapper);
+ }
+
+ function textDefinition(match) {
+ const normalized = match.toLowerCase();
+ if (normalized === "fortran-order") {
+ return textTermDefinitions["f-order"];
+ }
+ return textTermDefinitions[normalized];
+ }
+
+ function isPlainTextTerm(node) {
+ const parent = node.parentElement;
+ return parent && node.nodeValue.trim() && !parent.closest("button, code, h1, h2, h3, h4, h5, h6, pre, script, style, .prik-term-wrap");
+ }
+
+ function sectionFor(element) {
+ const headings = document.querySelectorAll(".rst-content h1, .rst-content h2, .rst-content h3, .rst-content h4, .rst-content h5, .rst-content h6");
+ let section = 0;
+
+ headings.forEach(function (heading, index) {
+ if (heading.compareDocumentPosition(element) & Node.DOCUMENT_POSITION_FOLLOWING) {
+ section = index + 1;
+ }
+ });
+ return section;
+ }
+
+ function enhanceCodeTerms() {
+ const seenBySection = new Map();
+ let index = 0;
+ const documentedTerms = Array.from(document.querySelectorAll(".rst-content code")).filter(function (term) {
+ return Object.prototype.hasOwnProperty.call(termDefinitions, term.textContent) && !term.closest("pre, button, h1, h2, h3, h4, h5, h6");
+ });
+
+ documentedTerms.forEach(function (term) {
+ const section = sectionFor(term);
+ const seen = seenBySection.get(section) || new Set();
+ const definition = termDefinitions[term.textContent];
+
+ if (!seen.has(definition.id)) {
+ enhanceCodeTerm(term, index);
+ seen.add(definition.id);
+ index += 1;
+ }
+ seenBySection.set(section, seen);
+ });
+ return { index: index, seenBySection: seenBySection };
+ }
+
+ function enhanceTextTerms(startIndex, seenBySection) {
+ const content = document.querySelector(".rst-content");
+ let index = startIndex;
+ if (!content) {
+ return;
+ }
+
+ const walker = document.createTreeWalker(content, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);
+ const textNodes = [];
+ let section = 0;
+ while (walker.nextNode()) {
+ if (walker.currentNode.nodeType === Node.ELEMENT_NODE && walker.currentNode.matches("h1, h2, h3, h4, h5, h6")) {
+ section += 1;
+ } else if (walker.currentNode.nodeType === Node.TEXT_NODE && isPlainTextTerm(walker.currentNode)) {
+ textNodes.push({ node: walker.currentNode, section: section });
+ }
+ }
+
+ textNodes.forEach(function (entry) {
+ const node = entry.node;
+ const seen = seenBySection.get(entry.section) || new Set();
+ const fragment = document.createDocumentFragment();
+ const text = node.nodeValue;
+ let lastIndex = 0;
+ let changed = false;
+ let match;
+
+ textTermPattern.lastIndex = 0;
+ while ((match = textTermPattern.exec(text))) {
+ const definition = textDefinition(match[0]);
+ fragment.append(document.createTextNode(text.slice(lastIndex, match.index)));
+ if (seen.has(definition.id)) {
+ fragment.append(document.createTextNode(match[0]));
+ } else {
+ const visibleTerm = document.createElement("span");
+ visibleTerm.className = "prik-term-label";
+ visibleTerm.textContent = match[0];
+ fragment.append(createTooltip(visibleTerm, definition, index, node.parentElement.closest("a")));
+ seen.add(definition.id);
+ index += 1;
+ }
+ lastIndex = match.index + match[0].length;
+ changed = true;
+ }
+
+ if (changed) {
+ fragment.append(document.createTextNode(text.slice(lastIndex)));
+ node.replaceWith(fragment);
+ }
+ seenBySection.set(entry.section, seen);
+ });
+ }
+
+ function initialiseTooltips() {
+ if (!supportsTermTooltips()) {
+ return;
+ }
+
+ const enhancedCodeTerms = enhanceCodeTerms();
+ enhanceTextTerms(enhancedCodeTerms.index, enhancedCodeTerms.seenBySection);
+
+ document.addEventListener("pointerdown", function (event) {
+ if (!event.target.closest(".prik-term-wrap")) {
+ closeAll();
+ }
+ });
+ window.addEventListener("resize", repositionOpenTooltips);
+ window.addEventListener("scroll", repositionOpenTooltips, true);
+ }
+
+ if (document.readyState === "loading") {
+ document.addEventListener("DOMContentLoaded", initialiseTooltips);
+ } else {
+ initialiseTooltips();
+ }
+})();
diff --git a/docs/stylesheets/site.css b/docs/stylesheets/site.css
index 70481256c..7a132767c 100644
--- a/docs/stylesheets/site.css
+++ b/docs/stylesheets/site.css
@@ -3,6 +3,15 @@
margin: 0;
}
+.rst-content .wy-table-responsive table td,
+.rst-content .wy-table-responsive table th {
+ white-space: normal;
+}
+
+.rst-content .wy-table-responsive table code {
+ overflow-wrap: anywhere;
+}
+
.wy-nav-side {
padding-bottom: 0;
}
@@ -259,6 +268,163 @@
margin: 0;
}
+.prik-build-path {
+ display: block;
+ width: 100%;
+ max-width: 60rem;
+ aspect-ratio: 960 / 515;
+ height: auto;
+ margin: 1.5rem 0;
+}
+
+.prik-example-tabs {
+ max-width: 56rem;
+ margin: 1.5rem 0;
+ border: 1px solid #cfdde5;
+ border-radius: 0.55rem;
+ background: #fff;
+ box-shadow: 0 1px 3px rgb(0 0 0 / 8%);
+}
+
+.prik-example-tablist {
+ display: flex;
+ overflow-x: auto;
+ border-bottom: 1px solid #cfdde5;
+ background: #f5fbfa;
+}
+
+.prik-example-tab {
+ flex: 0 0 auto;
+ padding: 0.75rem 1rem;
+ border: 0;
+ border-bottom: 3px solid transparent;
+ background: transparent;
+ color: #43515d;
+ cursor: pointer;
+ font: inherit;
+ font-weight: 700;
+}
+
+.prik-example-tab:hover {
+ background: rgb(23 107 100 / 8%);
+ color: #0f514c;
+}
+
+.prik-example-tab[aria-selected="true"] {
+ border-bottom-color: #176b64;
+ background: #fff;
+ color: #0f514c;
+}
+
+.prik-example-tab:focus-visible {
+ position: relative;
+ z-index: 1;
+ outline: 2px solid #f5b041;
+ outline-offset: -2px;
+}
+
+.prik-example-panel {
+ padding: 0 1rem;
+}
+
+.prik-example-panel > :first-child {
+ margin-top: 1rem;
+}
+
+.prik-example-panel > :last-child {
+ margin-bottom: 1rem;
+}
+
+.prik-term-wrap {
+ position: relative;
+ display: inline-flex;
+ align-items: baseline;
+ vertical-align: baseline;
+}
+
+.prik-term-trigger {
+ padding: 0;
+ border: 0;
+ border-radius: 0.2rem;
+ background: transparent;
+ color: inherit;
+ cursor: help;
+ font: inherit;
+ line-height: inherit;
+}
+
+.prik-term-trigger > code,
+.prik-term-trigger > .prik-term-label {
+ border-bottom: 1px dashed #176b64;
+ border-radius: 0.2rem;
+ background: #e7f4f2;
+ color: #0f514c;
+}
+
+.prik-term-trigger:hover > code,
+.prik-term-trigger:hover > .prik-term-label,
+.prik-term-wrap.is-open .prik-term-trigger > code,
+.prik-term-wrap.is-open .prik-term-trigger > .prik-term-label {
+ background: #d9eeea;
+}
+
+.prik-term-trigger:focus-visible {
+ outline: 2px solid #f5b041;
+ outline-offset: 2px;
+}
+
+.prik-term-tooltip {
+ position: fixed;
+ z-index: 20;
+ top: 0;
+ left: 50%;
+ width: min(19rem, calc(100vw - 2rem));
+ padding: 0.7rem 0.8rem;
+ border: 1px solid #0f514c;
+ border-radius: 0.45rem;
+ background: #253746;
+ box-shadow: 0 5px 14px rgb(0 0 0 / 22%);
+ color: #fff;
+ font-size: 0.84rem;
+ line-height: 1.45;
+ text-align: left;
+ white-space: normal;
+ overflow-wrap: break-word;
+ transform: translate(-50%, 0.25rem);
+ visibility: hidden;
+ opacity: 0;
+ pointer-events: none;
+ transition:
+ opacity 120ms ease,
+ transform 120ms ease,
+ visibility 120ms ease;
+}
+
+.prik-term-tooltip::after {
+ position: absolute;
+ bottom: -0.38rem;
+ left: 50%;
+ width: 0.7rem;
+ height: 0.7rem;
+ border-right: 1px solid #0f514c;
+ border-bottom: 1px solid #0f514c;
+ background: #253746;
+ content: "";
+ transform: translateX(-50%) rotate(45deg);
+}
+
+.prik-term-tooltip.prik-term-tooltip-below::after {
+ top: -0.38rem;
+ bottom: auto;
+ transform: translateX(-50%) rotate(225deg);
+}
+
+.prik-term-wrap.is-open .prik-term-tooltip {
+ transform: translate(-50%, 0);
+ visibility: visible;
+ opacity: 1;
+}
+
@media screen and (max-width: 768px) {
.wy-breadcrumbs-aside {
display: block;
@@ -266,9 +432,21 @@
margin-top: 0.75rem;
}
+ .rst-content .wy-table-responsive table td,
+ .rst-content .wy-table-responsive table th {
+ padding: 0.45rem 0.5rem;
+ font-size: 0.82rem;
+ }
+
.prik-performance-summary {
grid-template-columns: 1fr;
}
+
+ .prik-example-tab {
+ padding: 0.7rem 0.85rem;
+ font-size: 0.9rem;
+ }
+
}
.rst-content pre {
@@ -276,3 +454,9 @@
max-width: 56rem;
padding-right: 3.25rem;
}
+
+@media (prefers-reduced-motion: reduce) {
+ .prik-term-tooltip {
+ transition: none;
+ }
+}
diff --git a/docs/user/getting-started/first-wrapped-function.md b/docs/user/getting-started/first-wrapped-function.md
index 6e45d12cf..59ec154ba 100644
--- a/docs/user/getting-started/first-wrapped-function.md
+++ b/docs/user/getting-started/first-wrapped-function.md
@@ -50,9 +50,10 @@ def scale(
```
`Float64` means the function requires `numpy.float64` scalar arguments and
-returns the same scalar type. `@standalone` identifies a procedure outside a
-Fortran module. `@native_call(...)` maps the two Python arguments to the native
-call and passes each scalar by address.
+returns a `numpy.float64` result.
+`@standalone` identifies a procedure outside a Fortran module.
+`@native_call(...)` maps the two Python arguments to the native call and passes
+each scalar by address.
This file is both the wrapper contract and an editable description of the
Python interface. You can leave it unchanged for this example; later pages
@@ -101,7 +102,8 @@ result : float64
`help(scale.scale)` shows the same signature, parameter types, result, and
documented exceptions. Generated modules, classes, methods, and properties
-also provide docstrings.
+also provide docstrings. The displayed `float64` records the exact NumPy scalar
+type accepted and returned by this function.
---
diff --git a/docs/user/getting-started/index.md b/docs/user/getting-started/index.md
index 2e713ae23..2927c0270 100644
--- a/docs/user/getting-started/index.md
+++ b/docs/user/getting-started/index.md
@@ -2,7 +2,7 @@
title: Getting Started
description: Install PRIK, set up compilers, and build your first Fortran-to-Python extension
audience: users
-prerequisites: repository checkout
+prerequisites: none
related: installation.md, verification.md
status: maintained
publication: reviewed
@@ -10,7 +10,8 @@ publication: reviewed
# Getting Started
-This guide takes you from a fresh clone to your first working Python extension built from Fortran code.
+This guide takes you from a fresh environment to your first working Python
+extension built from Fortran code.
Start with GNU (`gfortran` and `gcc`), tested on Linux and macOS. LLVM Flang
is tested on both platforms; Intel IFX is tested on Linux. See
diff --git a/docs/user/guide/allocatables.md b/docs/user/guide/allocatables.md
index 2fea95fae..919e7ceeb 100644
--- a/docs/user/guide/allocatables.md
+++ b/docs/user/guide/allocatables.md
@@ -12,7 +12,7 @@ publication: reviewed
A Fortran allocatable descriptor records whether storage is allocated and, for
arrays, its address, shape, and strides. The descriptor controls the allocation,
-and an prik handle gives Python access to that descriptor.
+and a PRIK handle gives Python access to that descriptor.
## Key Concepts
@@ -202,6 +202,20 @@ print(values.to_numpy())
## Complete Example
+The source, generated contract, and Python call describe the same allocatable
+handle. The result stays visible below the three views.
+
+
+
+Result:
+
+```text
+[[2. 2. 2.]
+ [2. 2. 2.]]
+[1. 1. 1. 1.]
+66.0
+300.0
+[2. 4. 6. 8.]
+```
## What prik Validates
diff --git a/docs/user/guide/callbacks.md b/docs/user/guide/callbacks.md
index 464c1eb34..f6540cd73 100644
--- a/docs/user/guide/callbacks.md
+++ b/docs/user/guide/callbacks.md
@@ -10,7 +10,7 @@ publication: reviewed
# Callbacks
-Callbacks let wrapped Fortran call a Python function while an prik call is
+Callbacks let wrapped Fortran call a Python function while a PRIK call is
running. They are useful for objective functions, progress hooks, custom
transforms, and small pieces of user-defined numerical logic.
@@ -83,6 +83,20 @@ The lambda receives converted Python objects, not `Addr(...)` markers.
## Small Example
+The source, generated contract, and Python call describe the same immediate
+callback. The result stays visible below the three views.
+
+
+
+Result:
+
+```text
+7.5
+```
## Choosing The Prototype Spelling
diff --git a/docs/user/guide/data-types.md b/docs/user/guide/data-types.md
index c28ff55da..8aea24663 100644
--- a/docs/user/guide/data-types.md
+++ b/docs/user/guide/data-types.md
@@ -18,6 +18,20 @@ wrapper because kind numbers are compiler-dependent.
## Example
+The source, generated contract, and Python call describe the same API. The
+observable values remain below the three views.
+
+
## Usage in Python
@@ -62,7 +109,15 @@ result = round_trip_color(green)
print(result) # 10
```
----
+
+
+
+Result:
+
+```text
+-1 0 10 11
+10
+```
## Key Points
diff --git a/docs/user/guide/error-handling.md b/docs/user/guide/error-handling.md
index 9e976cb21..08f7a6a35 100644
--- a/docs/user/guide/error-handling.md
+++ b/docs/user/guide/error-handling.md
@@ -39,48 +39,127 @@ Use the two diagnostic flags for different problems:
| `--debug` | prik fails unexpectedly and you need the full Python traceback. |
`--verbose` keeps the normal concise error message. `--debug` exposes prik's
-internal call stack, so it is mainly useful when reporting or investigating an
-prik bug.
+internal call stack, so it is mainly useful when reporting or investigating a
+PRIK bug.
---
## Status Projection Example
-You can turn Fortran status codes into Python exceptions using the `@raises` decorator in an edited contract.
+You can turn Fortran status codes into Python exceptions using the `@raises`
+decorator in an edited contract. The source, generated contract, edited
+contract, and Python call below describe one status-projection boundary.
-**Example:**
+
+
+
+
+
+
+
+
+
+
+### Fortran source
+
+Create `status_api.f90`:
```fortran
subroutine solve(value, status, message)
integer(4), intent(in) :: value
integer(4), intent(out) :: status
character(len=32), intent(out) :: message
- ...
-end subroutine
+
+ if (value < 0) then
+ status = 1
+ message = "value must be non-negative"
+ else
+ status = 0
+ message = ""
+ end if
+end subroutine solve
```
-In your edited `.pyi`, project the hidden native outputs and then name those
-projected results in `@raises`:
+
+
+## Python Usage
```python
+import sys
+
import numpy as np
+sys.path.insert(0, "build/status")
+import status
+
try:
- api.solve(np.int32(-1))
+ status.solve(np.int32(-1))
except RuntimeError as e:
print(e)
```
+
+
+
+Result:
+
+```text
+value must be non-negative
+```
+
prik uses the projected status and message to determine the Python result: a
successful call returns `None`, while a non-success status raises
`RuntimeError` with the native message instead of returning either hidden
diff --git a/docs/user/guide/generic-interfaces.md b/docs/user/guide/generic-interfaces.md
index e220dad83..07b6b7efb 100644
--- a/docs/user/guide/generic-interfaces.md
+++ b/docs/user/guide/generic-interfaces.md
@@ -18,6 +18,19 @@ class. It does not apply implicit numeric coercion.
## Complete Example
+The three views below describe the same `convert` interface. Select a tab to
+inspect the source, generated contract, or Python call. The result stays
+visible below the example.
+
+
The semantic `.pyi` keeps the concrete procedures as private link targets.
-Each public declaration adds one candidate to `convert`:
+Each public declaration adds one candidate to `convert`.
-`@private` hides a concrete procedure from Python. `@overload` links a public
-candidate to that procedure, and `@bind` selects the public native generic when
-the concrete procedure is private in Fortran.
+`@private` hides a concrete procedure from Python. `@native_call(...)` keeps
+its native argument mapping, `@overload` links a public candidate to that
+procedure, and `@bind` selects the public native generic when the concrete
+procedure is private in Fortran.
```python
-from prik.contracts import Float64, Int32, bind, overload, private
+from prik.contracts import Addr, Arg, Float64, Int32, bind, native_call, overload, private
@private
-def convert_integer(value: Int32) -> Int32: ...
+@native_call([Addr(Arg(0))])
+def convert_integer(
+ value: Int32
+) -> Int32: ...
@private
-def convert_real(value: Float64) -> Float64: ...
+@native_call([Addr(Arg(0))])
+def convert_real(
+ value: Float64
+) -> Float64: ...
@bind("convert")
@overload("convert_integer")
-def convert(value: Int32) -> Int32: ...
+def convert(
+ value: Int32
+) -> Int32: ...
@bind("convert")
@overload("convert_real")
-def convert(value: Float64) -> Float64: ...
+def convert(
+ value: Float64
+) -> Float64: ...
+```
+
+Generate the starter contract:
+
+```bash
+python3 -m prik generate --pyi generic.f90
```
The source exports `convert`, not `convert_integer` or `convert_real`. Since
@@ -87,9 +116,9 @@ those concrete procedures are native-private,
[`@bind("convert")`](wrapping-functions.md#python-and-native-names) routes both
candidates through the public generic.
----
+
+
+Result: all assertions succeed.
## Contiguous And Strided Targets
diff --git a/docs/user/guide/raw-addresses.md b/docs/user/guide/raw-addresses.md
index c2a918e77..5a8252657 100644
--- a/docs/user/guide/raw-addresses.md
+++ b/docs/user/guide/raw-addresses.md
@@ -45,6 +45,22 @@ use storage addresses, so their `Arg(i)` entry does not need another
## Complete Example
+The source, generated contract, edited contract, and Python calls below
+describe the same raw-address boundary. The results remain visible below the
+four views.
+
+
+
+## Edited Contract
+
+Change the storage boundary so Python callers provide raw addresses. The final
+`contracts/raw/raw_api.pyi` is:
```python
from prik.contracts import Addr, Arg, Float64, Int32, String, native_call
@@ -105,6 +157,10 @@ python3 -m prik contracts/raw/__init__.pyi \
For other argument-order and result mappings, see
[Reorder Arguments and Project Outputs](../reference/pyi-contracts/calls-and-results.md#reorder-arguments-and-project-outputs).
+
+
+
+
## Primitive Address
Keep the NumPy owner in a variable for the full call:
@@ -179,6 +235,18 @@ This mutates bytes storage. It does not return a Python `str`.
Use `String[8]` with `Returns[...]` when the result should be immutable text.
Use `String[8][()]` when the wrapper should validate mutable storage.
+
+
+
+Result:
+
+```text
+4
+[[2. 4.]
+ [6. 8.]]
+b'Xlpha '
+```
+
## Safety Rules
- Keep the NumPy or ctypes owner alive until the call returns.
diff --git a/docs/user/guide/strings.md b/docs/user/guide/strings.md
index a09d7a2c5..bb115818a 100644
--- a/docs/user/guide/strings.md
+++ b/docs/user/guide/strings.md
@@ -32,6 +32,22 @@ advanced boundary covered later in the guide.
## Complete Example
+The source, generated contract, edited contract, and Python calls below
+describe the same string boundaries. The results remain visible below the four
+views.
+
+
+
+Result:
+
+```text
+4.0 6.0
+12.0
+```
## Inspect the Class
diff --git a/docs/user/guide/wrapping-functions.md b/docs/user/guide/wrapping-functions.md
index f03c26d05..5107a1a22 100644
--- a/docs/user/guide/wrapping-functions.md
+++ b/docs/user/guide/wrapping-functions.md
@@ -20,7 +20,7 @@ as Python results.
The `scale` function built in
[First Wrapped Function](../getting-started/first-wrapped-function.md) returns
-its direct result as one NumPy scalar:
+its direct `Float64` result as a NumPy `float64` scalar:
```python
import numpy as np
@@ -40,7 +40,43 @@ procedure. Use `@bind("native_name")` only when those names differ.
For example, rename the generated declaration to `multiply` and add
`@bind("scale")`. The Python name changes, while the native target remains
-`scale`:
+`scale`. The generated contract and its edited replacement are shown below.
+
+The three views below describe that one rename.
+
+
+
+Result:
+
+```text
+7.5
+```
+
`@bind` changes the native target name. It does not change the argument
contract or adapt an incompatible native interface. Matching names need no
`@bind`.
-Also update the import in the contract package's `__init__.pyi` when it
-re-exports the old Python name. Build the edited package using the
-[editable-contract workflow](../getting-started/beginner-workflow.md#4-optionally-edit-the-contract).
+If a package `__init__.pyi` re-exports the renamed declaration, update that
+import too.
The same rule applies to functions, subroutines, and methods.
@@ -84,7 +142,7 @@ the [`automatic_vector` example](arrays.md#complete-example):
import numpy as np
result = automatic_vector(np.int32(4))
-print(result) # [ 1. 4. 9. 16.]
+print(result) # [2. 4. 6. 8.]
```
---
@@ -121,7 +179,8 @@ total, count = sum_with_count(data_array)
## Important Rules
-- Always pass **exact NumPy dtypes** (`np.float64`, `np.int32`, etc.).
+- Pass exact NumPy dtypes (`np.float64`, `np.int32`, etc.) for numeric scalar
+ arguments. Boolean scalar arguments accept `bool` or `np.bool_`.
- Array results are returned as new NumPy arrays (copies).
- Projected scalar outputs follow the direct function result in the return
tuple.
diff --git a/docs/user/guide/wrapping-subroutines.md b/docs/user/guide/wrapping-subroutines.md
index 8a2bdb2cd..e9a67368a 100644
--- a/docs/user/guide/wrapping-subroutines.md
+++ b/docs/user/guide/wrapping-subroutines.md
@@ -39,6 +39,20 @@ any dummy declaration without `intent`.
## Complete Example
+The source, generated contract, and Python call describe the same output
+rules. The result stays visible below the three views.
+
+
+
+Result:
+
+```text
+-2.0 7.0
+10.0
+[3. 6. 9.]
+[1. 1. 1. 1.]
+```
## Key Rules
diff --git a/docs/user/index.md b/docs/user/index.md
index 47141a2b2..12413020e 100644
--- a/docs/user/index.md
+++ b/docs/user/index.md
@@ -22,5 +22,5 @@ extensions.
Getting Started covers installation, environment verification, the first
standalone wrapper, the first module wrapper, and the beginner edit-build-test
loop. The User Guide covers supported Fortran wrapper features, runtime
-behavior, packaging, and distribution. Performance presents the reproducible
-PRIK and f2py comparison.
+behavior, and extension builds. Performance presents the reproducible PRIK and
+f2py comparison.
diff --git a/docs/user/language-support/feature-matrix.md b/docs/user/language-support/feature-matrix.md
index 6666c4bf9..d09eb6bdf 100644
--- a/docs/user/language-support/feature-matrix.md
+++ b/docs/user/language-support/feature-matrix.md
@@ -33,70 +33,70 @@ inspection-only or partial support.
| Feature | Status | User docs | Source owner | Evidence | Limitations |
| --- | --- | --- | --- | --- | --- |
-| Scalar functions, subroutines, and baseline arrays | Supported | [Functions](../guide/wrapping-functions.md), [subroutines](../guide/wrapping-subroutines.md) | [Wrapper pipeline](../../developer/source-map.md#layer-to-layer-route) | [Verified baseline tests](../../../tests/fortran/data_types/end_to_end/test_verified_baseline.py) | Native scalar arguments require exact NumPy dtypes where documented. |
-| Generic procedure interfaces | Supported | [Generic interfaces](../guide/generic-interfaces.md) | [Feature route](../../developer/feature-to-code-map.md#workflow-feature-pointers) | [Generic interface tests](../../../tests/fortran/generic_interfaces/end_to_end/test_generic_interfaces.py) | Defined operators and assignment are tracked separately. |
-| Defined operators and assignment overloads | Supported | [Defined operators](../guide/generic-interfaces.md#defined-operators) | [Bridge and binding generation](../../developer/source-map.md#common-change-routes) | [Defined operator tests](../../../tests/fortran/generic_interfaces/end_to_end/test_defined_operators.py) | Supported operators are those covered by the wrapper guide and runtime tests. |
-| Output arguments and multiple results | Supported | [Subroutine projection](../guide/wrapping-subroutines.md) | [Ownership and lowering](../../developer/source-map.md#common-change-routes) | [Calls and results tests](../../../tests/fortran/pyi_contracts/calls_and_results/end_to_end/test_edited_call_surfaces.py), [function result tests](../../../tests/fortran/functions/end_to_end/test_documented_function_journeys.py) | Tuple ordering and caller-provided array behavior follow the wrapper guide. |
-| Optional arguments | Supported | [Optional arguments](../guide/optional-arguments.md) | [Binding generation](../../developer/source-map.md#common-change-routes) | [Optional argument tests](../../../tests/fortran/optional_arguments/end_to_end/test_optional_runtime.py) | Unsupported optional combinations fail during wrapper planning. |
-| Allocatable array handles, descriptor arguments, and owned results | Supported | [Allocatables](../guide/allocatables.md) | [Ownership policy](../../developer/source-map.md#common-change-routes) | [Allocatable runtime tests](../../../tests/fortran/allocatables/end_to_end/test_allocatable_handles.py), [scalar-derived matrix tests](../../../tests/fortran/derived_types/end_to_end/test_scalar_actual_dummy_matrix.py) | Array module/field handles borrow their owner; result handles own persistent descriptor storage. Wrapper-owned scalar-derived allocatables use typed holders; module scalar allocatables use reversible `move_alloc` transactions for compatible dummies. |
-| Pointer scalar projections and array handles | Partially supported | [Pointers](../guide/pointers.md) | [Ownership policy](../../developer/source-map.md#common-change-routes) | [Pointer handle tests](../../../tests/fortran/pointers/end_to_end/test_pointer_handles.py), [pointer policy tests](../../../tests/fortran/pointers/policy/test_pointer_ownership_policy.py), [scalar-derived matrix tests](../../../tests/fortran/derived_types/end_to_end/test_scalar_actual_dummy_matrix.py) | Descriptor arguments, module/field handles, strided views, wrapper-owned pointer-array results and outputs, scalar-derived pointer holders, and module pointer reassociation transactions are supported. Target deallocation and writable reassociation remain policy-gated. |
-| Array-valued function results | Supported | [Array results](../guide/arrays.md#array-results) | [Array lowering](../../developer/source-map.md#common-change-routes) | [Array result tests](../../../tests/fortran/arrays/end_to_end/test_array_results.py) | Ownership and dtype/shape behavior are limited to documented array result forms. |
-| NumPy array argument contracts | Supported | [Arrays](../guide/arrays.md) | [Bridge and binding generation](../../developer/source-map.md#common-change-routes) | [Array contract tests](../../../tests/fortran/arrays/end_to_end/test_array_contract_validation.py), [multidimensional tests](../../../tests/fortran/arrays/end_to_end/test_layout_and_strided_arrays.py) | Wrong dtype, rank, shape, contiguity, alignment, or mutability is rejected. |
-| Derived-type scalar boundaries and methods | Supported | [Derived types](../guide/wrapping-derived-types.md) | [Class lowering](../../developer/source-map.md#common-change-routes) | [Derived boundary tests](../../../tests/fortran/derived_types/end_to_end/test_derived_boundaries.py), [method tests](../../../tests/fortran/derived_types/end_to_end/test_type_bound_methods.py) | Derived-type arrays and some polymorphic forms are not included. |
-| Default and keyword constructors with finalizers | Supported | [Constructors and finalizers](../guide/wrapping-derived-types.md#key-concepts) | [Ownership policy](../../developer/source-map.md#common-change-routes) | [Constructor/finalizer tests](../../../tests/fortran/derived_types/end_to_end/test_default_constructors_and_finalizers.py), [borrowed finalizer tests](../../../tests/fortran/derived_types/end_to_end/test_borrowed_components.py) | Construction commits ownership only after initialization; borrowed wrappers never run an owning finalizer. |
-| Generic constructor interfaces and overloaded runtime initialization | Supported | [Constructors](../guide/wrapping-derived-types.md#custom-constructor) | [Class policy and lowering](../../developer/source-map.md#common-change-routes) | [Edited class surface tests](../../../tests/fortran/pyi_contracts/functions_and_classes/end_to_end/test_edited_class_surfaces.py), [class policy tests](../../../tests/fortran/pyi_contracts/functions_and_classes/policy/test_class_surface_policy.py) | Candidates require distinguishable completed Python signatures; incomplete or ambiguous sets are blocked before emission. |
-| Module variables, constants, saved state, and common-block procedure state | Supported | [Wrapping modules](../guide/wrapping-modules.md) | [Module state route](../../developer/feature-to-code-map.md#workflow-feature-pointers) | [Module state tests](../../../tests/fortran/modules/end_to_end/test_module_variables_and_state.py), [scalar-derived matrix tests](../../../tests/fortran/derived_types/end_to_end/test_scalar_actual_dummy_matrix.py), [common-block tests](../../../tests/fortran/modules/end_to_end/test_common_blocks.py) | Common-block storage is not exported as Python variables. Rank-zero derived module objects use direct, scoped, allocation-transaction, or pointer-transaction handoff selected before lowering. |
-| Fortran enum constants | Supported | [Enumerations](../guide/enumerations.md) | [Semantic constants route](../../developer/source-map.md#common-change-routes) | [Enum runtime tests](../../../tests/fortran/enumerations/end_to_end/test_enum_runtime.py), [enum semantic tests](../../../tests/fortran/enumerations/semantics/test_enum_semantics.py), [enum diagnostics](../../../tests/fortran/enumerations/parsing/test_enum_diagnostics.py) | No Python `Enum` or `IntEnum` classes are generated. |
-| Scalar character arguments, results, and fields | Supported | [Strings](../guide/strings.md) | [Character bridge route](../../developer/source-map.md#common-change-routes) | [Character argument tests](../../../tests/fortran/strings/end_to_end/test_character_boundaries.py), [edge-case tests](../../../tests/fortran/strings/end_to_end/test_character_edge_cases.py) | Character arrays use fixed-width NumPy bytes dtype; mutable scalar deferred-length storage is blocked. |
-| Scalar kind coverage | Supported | [Data types](../guide/data-types.md) | [Fortran type probe](../../developer/source-map.md#hotspot-index) | [Scalar kind tests](../../../tests/fortran/data_types/end_to_end/test_primitive_scalar_runtime.py) | Wider real, complex, and explicit logical storage is blocked without portable NumPy mapping. |
-| Caller-ordered multi-source builds, Makefiles, verbose mode, and output placement | Supported | [Building the shared library](../guide/building-shared-library.md) | [Wrapper orchestration](../../developer/source-map.md#common-change-routes) | [Multi-source tests](../../../tests/fortran/building_shared_library/end_to_end/test_multi_source_builds.py), [compiler verbose tests](../../../tests/fortran/building_shared_library/compiling/test_compiler_verbose.py) | prik does not discover, reorder, or resolve all external source dependencies. |
-| Visibility, naming, keyword escaping, and collision policy | Supported | [Visibility and naming](../reference/fortran-wrapper.md#visibility-naming-and-the-python-surface) | [Naming policy](../../developer/source-map.md#hotspot-index) | [Visibility/naming tests](../../../tests/fortran/pyi_contracts/exports_and_modules/end_to_end/test_visibility_naming.py) | Strict mode rejects names that default mode can normalize. |
-| Immediate call-scoped Python callbacks | Supported | [Callbacks](../guide/callbacks.md) | [Callback bridge route](../../developer/source-map.md#common-change-routes) | [Callback plan tests](../../../tests/fortran/callbacks/codegen/test_callback_planning.py), [scalar callback tests](../../../tests/fortran/callbacks/end_to_end/test_scalar_callbacks.py), [array callback tests](../../../tests/fortran/callbacks/end_to_end/test_array_callbacks.py), [combined shape tests](../../../tests/fortran/callbacks/end_to_end/test_supported_callback_shapes.py) | Direct wrapper-plan generation supports entering-thread callbacks only. Stored, optional, asynchronous, or cross-thread callbacks are unsupported. |
-| Runtime error projection, GIL policy, recursion, OpenMP path, and GNU ABI checks | Supported | [Error handling](../guide/error-handling.md) | [Runtime route](../../developer/source-map.md#common-change-routes) | [Status projection runtime](../../../tests/fortran/error_handling/end_to_end/test_status_projection.py), [status and GIL lowering](../../../tests/fortran/error_handling/codegen/test_status_error_lowering.py), [recursion tests](../../../tests/fortran/error_handling/end_to_end/test_runtime_recursion.py), [OpenMP tests](../../../tests/fortran/error_handling/end_to_end/test_openmp_runtime.py), [ABI tests](../../../tests/fortran/building_shared_library/end_to_end/test_runtime_compatibility.py) | OpenMP and ABI evidence is compiler/platform-specific; callers still own native synchronization. |
-| Fortran source wrapper builds | Supported | [Building the shared library](../guide/building-shared-library.md) | [Wrapper orchestration](../../developer/source-map.md#common-change-routes) | [Build modes](../../../tests/fortran/building_shared_library/end_to_end/test_source_build_modes.py), [runtime ABI](../../../tests/fortran/building_shared_library/end_to_end/test_runtime_compatibility.py) | Implemented for ordered Fortran source inputs. |
+| Scalar functions, subroutines, and baseline arrays | Supported | [Functions](../guide/wrapping-functions.md), [subroutines](../guide/wrapping-subroutines.md) | [Wrapper pipeline](../../developer/architecture.md#build-architecture) | [Verified baseline tests](../../../tests/fortran/data_types/end_to_end/test_verified_baseline.py) | Native scalar arguments require exact NumPy dtypes where documented. |
+| Generic procedure interfaces | Supported | [Generic interfaces](../guide/generic-interfaces.md) | [Feature route](../../developer/feature-to-code-map.md#feature-routes) | [Generic interface tests](../../../tests/fortran/generic_interfaces/end_to_end/test_generic_interfaces.py) | Defined operators and assignment are tracked separately. |
+| Defined operators and assignment overloads | Supported | [Defined operators](../guide/generic-interfaces.md#defined-operators) | [Bridge and binding generation](../../developer/codebase-map.md#cross-stage-hotspots) | [Defined operator tests](../../../tests/fortran/generic_interfaces/end_to_end/test_defined_operators.py) | Supported operators are those covered by the wrapper guide and runtime tests. |
+| Output arguments and multiple results | Supported | [Subroutine projection](../guide/wrapping-subroutines.md) | [Ownership and lowering](../../developer/codebase-map.md#cross-stage-hotspots) | [Calls and results tests](../../../tests/fortran/pyi_contracts/calls_and_results/end_to_end/test_edited_call_surfaces.py), [function result tests](../../../tests/fortran/functions/end_to_end/test_documented_function_journeys.py) | Tuple ordering and caller-provided array behavior follow the wrapper guide. |
+| Optional arguments | Supported | [Optional arguments](../guide/optional-arguments.md) | [Binding generation](../../developer/codebase-map.md#cross-stage-hotspots) | [Optional argument tests](../../../tests/fortran/optional_arguments/end_to_end/test_optional_runtime.py) | Unsupported optional combinations fail during wrapper planning. |
+| Allocatable array handles, descriptor arguments, and owned results | Supported | [Allocatables](../guide/allocatables.md) | [Ownership policy](../../developer/codebase-map.md#cross-stage-hotspots) | [Allocatable runtime tests](../../../tests/fortran/allocatables/end_to_end/test_allocatable_handles.py), [scalar-derived matrix tests](../../../tests/fortran/derived_types/end_to_end/test_scalar_actual_dummy_matrix.py) | Array module/field handles borrow their owner; result handles own persistent descriptor storage. Wrapper-owned scalar-derived allocatables use typed holders; module scalar allocatables use reversible `move_alloc` transactions for compatible dummies. |
+| Pointer scalar projections and array handles | Partially supported | [Pointers](../guide/pointers.md) | [Ownership policy](../../developer/codebase-map.md#cross-stage-hotspots) | [Pointer handle tests](../../../tests/fortran/pointers/end_to_end/test_pointer_handles.py), [pointer policy tests](../../../tests/fortran/pointers/policy/test_pointer_ownership_policy.py), [scalar-derived matrix tests](../../../tests/fortran/derived_types/end_to_end/test_scalar_actual_dummy_matrix.py) | Descriptor arguments, module/field handles, strided views, wrapper-owned pointer-array results and outputs, scalar-derived pointer holders, and module pointer reassociation transactions are supported. Target deallocation and writable reassociation remain policy-gated. |
+| Array-valued function results | Supported | [Array results](../guide/arrays.md#array-results) | [Array lowering](../../developer/codebase-map.md#cross-stage-hotspots) | [Array result tests](../../../tests/fortran/arrays/end_to_end/test_array_results.py) | Ownership and dtype/shape behavior are limited to documented array result forms. |
+| NumPy array argument contracts | Supported | [Arrays](../guide/arrays.md) | [Bridge and binding generation](../../developer/codebase-map.md#cross-stage-hotspots) | [Array contract tests](../../../tests/fortran/arrays/end_to_end/test_array_contract_validation.py), [multidimensional tests](../../../tests/fortran/arrays/end_to_end/test_layout_and_strided_arrays.py) | Wrong dtype, rank, shape, contiguity, alignment, or mutability is rejected. |
+| Derived-type scalar boundaries and methods | Supported | [Derived types](../guide/wrapping-derived-types.md) | [Class lowering](../../developer/codebase-map.md#cross-stage-hotspots) | [Derived boundary tests](../../../tests/fortran/derived_types/end_to_end/test_derived_boundaries.py), [method tests](../../../tests/fortran/derived_types/end_to_end/test_type_bound_methods.py) | Derived-type arrays and some polymorphic forms are not included. |
+| Default and keyword constructors with finalizers | Supported | [Constructors and finalizers](../guide/wrapping-derived-types.md#key-concepts) | [Ownership policy](../../developer/codebase-map.md#cross-stage-hotspots) | [Constructor/finalizer tests](../../../tests/fortran/derived_types/end_to_end/test_default_constructors_and_finalizers.py), [borrowed finalizer tests](../../../tests/fortran/derived_types/end_to_end/test_borrowed_components.py) | Construction commits ownership only after initialization; borrowed wrappers never run an owning finalizer. |
+| Generic constructor interfaces and overloaded runtime initialization | Supported | [Constructors](../guide/wrapping-derived-types.md#custom-constructor) | [Class policy and lowering](../../developer/codebase-map.md#cross-stage-hotspots) | [Edited class surface tests](../../../tests/fortran/pyi_contracts/functions_and_classes/end_to_end/test_edited_class_surfaces.py), [class policy tests](../../../tests/fortran/pyi_contracts/functions_and_classes/policy/test_class_surface_policy.py) | Candidates require distinguishable completed Python signatures; incomplete or ambiguous sets are blocked before emission. |
+| Module variables, constants, saved state, and common-block procedure state | Supported | [Wrapping modules](../guide/wrapping-modules.md) | [Module state route](../../developer/feature-to-code-map.md#feature-routes) | [Module state tests](../../../tests/fortran/modules/end_to_end/test_module_variables_and_state.py), [scalar-derived matrix tests](../../../tests/fortran/derived_types/end_to_end/test_scalar_actual_dummy_matrix.py), [common-block tests](../../../tests/fortran/modules/end_to_end/test_common_blocks.py) | Common-block storage is not exported as Python variables. Rank-zero derived module objects use direct, scoped, allocation-transaction, or pointer-transaction handoff selected before lowering. |
+| Fortran enum constants | Supported | [Enumerations](../guide/enumerations.md) | [Semantic constants route](../../developer/codebase-map.md#cross-stage-hotspots) | [Enum runtime tests](../../../tests/fortran/enumerations/end_to_end/test_enum_runtime.py), [enum semantic tests](../../../tests/fortran/enumerations/semantics/test_enum_semantics.py), [enum diagnostics](../../../tests/fortran/enumerations/parsing/test_enum_diagnostics.py) | No Python `Enum` or `IntEnum` classes are generated. |
+| Scalar character arguments, results, and fields | Supported | [Strings](../guide/strings.md) | [Character bridge route](../../developer/codebase-map.md#cross-stage-hotspots) | [Character argument tests](../../../tests/fortran/strings/end_to_end/test_character_boundaries.py), [edge-case tests](../../../tests/fortran/strings/end_to_end/test_character_edge_cases.py) | Character arrays use fixed-width NumPy bytes dtype; mutable scalar deferred-length storage is blocked. |
+| Scalar kind coverage | Supported | [Data types](../guide/data-types.md) | [Fortran type probe](../../developer/codebase-map.md#cross-stage-hotspots) | [Scalar kind tests](../../../tests/fortran/data_types/end_to_end/test_primitive_scalar_runtime.py) | Wider real, complex, and explicit logical storage is blocked without portable NumPy mapping. |
+| Caller-ordered multi-source builds, Makefiles, verbose mode, and output placement | Supported | [Building the shared library](../guide/building-shared-library.md) | [Wrapper orchestration](../../developer/codebase-map.md#cross-stage-hotspots) | [Multi-source tests](../../../tests/fortran/building_shared_library/end_to_end/test_multi_source_builds.py), [compiler verbose tests](../../../tests/fortran/building_shared_library/compiling/test_compiler_verbose.py) | prik does not discover, reorder, or resolve all external source dependencies. |
+| Visibility, naming, keyword escaping, and collision policy | Supported | [Visibility and naming](../reference/fortran-wrapper.md#visibility-naming-and-the-python-surface) | [Naming policy](../../developer/codebase-map.md#cross-stage-hotspots) | [Visibility/naming tests](../../../tests/fortran/pyi_contracts/exports_and_modules/end_to_end/test_visibility_naming.py) | Strict mode rejects names that default mode can normalize. |
+| Immediate call-scoped Python callbacks | Supported | [Callbacks](../guide/callbacks.md) | [Callback bridge route](../../developer/codebase-map.md#cross-stage-hotspots) | [Callback plan tests](../../../tests/fortran/callbacks/codegen/test_callback_planning.py), [scalar callback tests](../../../tests/fortran/callbacks/end_to_end/test_scalar_callbacks.py), [array callback tests](../../../tests/fortran/callbacks/end_to_end/test_array_callbacks.py), [combined shape tests](../../../tests/fortran/callbacks/end_to_end/test_supported_callback_shapes.py) | Direct wrapper-plan generation supports entering-thread callbacks only. Stored, optional, asynchronous, or cross-thread callbacks are unsupported. |
+| Runtime error projection, GIL policy, recursion, OpenMP path, and GNU ABI checks | Supported | [Error handling](../guide/error-handling.md) | [Runtime route](../../developer/codebase-map.md#cross-stage-hotspots) | [Status projection runtime](../../../tests/fortran/error_handling/end_to_end/test_status_projection.py), [status and GIL lowering](../../../tests/fortran/error_handling/codegen/test_status_error_lowering.py), [recursion tests](../../../tests/fortran/error_handling/end_to_end/test_runtime_recursion.py), [OpenMP tests](../../../tests/fortran/error_handling/end_to_end/test_openmp_runtime.py), [ABI tests](../../../tests/fortran/building_shared_library/end_to_end/test_runtime_compatibility.py) | OpenMP and ABI evidence is compiler/platform-specific; callers still own native synchronization. |
+| Fortran source wrapper builds | Supported | [Building the shared library](../guide/building-shared-library.md) | [Wrapper orchestration](../../developer/codebase-map.md#cross-stage-hotspots) | [Build modes](../../../tests/fortran/building_shared_library/end_to_end/test_source_build_modes.py), [runtime ABI](../../../tests/fortran/building_shared_library/end_to_end/test_runtime_compatibility.py) | Implemented for ordered Fortran source inputs. |
## Supported Inspection Features
| Feature | Status | User docs | Source owner | Evidence | Limitations |
| --- | --- | --- | --- | --- | --- |
-| Fortran parse, semantic IR, and `.pyi` inspection | Supported | [Fortran inspection recipe](../examples/recipes/inspect-fortran-api.md), [semantic IR](../reference/semantic-ir.md) | [Fortran parser route](../../developer/source-map.md#common-change-routes) | [Fortran parser fixtures](../../../tests/fortran/source_parsing/parsing/test_fortran_fixture_suite.py), [Fortran semantic tests](../../../tests/fortran/semantic_ir/semantics/) | Inspection support does not by itself prove runtime wrapper support. |
-| Semantic `.pyi` wrapper builds from explicit native artifacts | Partially supported | [Semantic `.pyi` contracts](../examples/recipes/semantic-pyi-contracts.md), [`.pyi` format](../reference/semantic-pyi-format.md) | [`.pyi` build route](../../developer/source-map.md#layer-to-layer-route) | [format and authoritative-input tests](../../../tests/fortran/semantic_pyi_format/), [multi-source contract tests](../../../tests/fortran/building_shared_library/end_to_end/test_multi_source_builds.py), [native build plan tests](../../../tests/fortran/building_shared_library/end_to_end/test_source_build_modes.py) | Current runtime parity is limited; source/generated/modified multi-source package parity is covered, and broader parity remains tracked in the checklist. |
-| Scalar inheritance and polymorphic dispatch | Partially supported | [Inheritance and polymorphism](../reference/fortran-wrapper.md#inheritance-and-polymorphism) | [Class lowering route](../../developer/source-map.md#common-change-routes) | [Inheritance tests](../../../tests/fortran/derived_types/end_to_end/test_inheritance_and_polymorphism.py) | Polymorphic results, mutable dummies, arrays, allocatable/pointer scalars, and `class(*)` are blocked. |
-| Assumed-size, assumed-rank, and lower-bound array contracts | Partially supported | [Arrays](../guide/arrays.md) | [Array bridge route](../../developer/source-map.md#common-change-routes) | [Assumed-rank tests](../../../tests/fortran/arrays/end_to_end/test_assumed_rank_arrays.py) | Assumed type and derived-type arrays remain blocked. Character arrays require fixed-width NumPy bytes dtype. |
-| Generated reference pages for modules, functions, and classes | Partially supported | [Reference index](../reference/index.md) | [Source map](../../developer/source-map.md) | [Documentation reference checks](../../../tests/docs/test_reference_and_source_map.py), [semantic contract tests](../../../tests/fortran/semantic_pyi_format/semantics/test_calls_and_projections.py) | Maintained manual references exist for generated functions, modules, classes, and generated file contracts; automated reference inventory generation has not been selected. |
+| Fortran parse, semantic IR, and `.pyi` inspection | Supported | [Fortran inspection recipe](../examples/recipes/inspect-fortran-api.md), [semantic IR](../reference/semantic-ir.md) | [Fortran parser route](../../developer/codebase-map.md#cross-stage-hotspots) | [Fortran parser fixtures](../../../tests/fortran/source_parsing/parsing/test_fortran_fixture_suite.py), [Fortran semantic tests](../../../tests/fortran/semantic_ir/semantics/) | Inspection support does not by itself prove runtime wrapper support. |
+| Semantic `.pyi` wrapper builds from explicit native artifacts | Partially supported | [Semantic `.pyi` contracts](../examples/recipes/semantic-pyi-contracts.md), [`.pyi` format](../reference/semantic-pyi-format.md) | [`.pyi` build route](../../developer/architecture.md#build-architecture) | [format and authoritative-input tests](../../../tests/fortran/semantic_pyi_format/), [multi-source contract tests](../../../tests/fortran/building_shared_library/end_to_end/test_multi_source_builds.py), [native build plan tests](../../../tests/fortran/building_shared_library/end_to_end/test_source_build_modes.py) | Current runtime parity is limited; source/generated/modified multi-source package parity is covered, and broader parity remains tracked in the checklist. |
+| Scalar inheritance and polymorphic dispatch | Partially supported | [Inheritance and polymorphism](../reference/fortran-wrapper.md#inheritance-and-polymorphism) | [Class lowering route](../../developer/codebase-map.md#cross-stage-hotspots) | [Inheritance tests](../../../tests/fortran/derived_types/end_to_end/test_inheritance_and_polymorphism.py) | Polymorphic results, mutable dummies, arrays, allocatable/pointer scalars, and `class(*)` are blocked. |
+| Assumed-size, assumed-rank, and lower-bound array contracts | Partially supported | [Arrays](../guide/arrays.md) | [Array bridge route](../../developer/codebase-map.md#cross-stage-hotspots) | [Assumed-rank tests](../../../tests/fortran/arrays/end_to_end/test_assumed_rank_arrays.py) | Assumed type and derived-type arrays remain blocked. Character arrays require fixed-width NumPy bytes dtype. |
+| Generated reference pages for modules, functions, and classes | Partially supported | [Reference index](../reference/index.md) | [Codebase map](../../developer/codebase-map.md) | [Documentation reference checks](../../../tests/docs/test_reference_and_codebase_map.py), [semantic contract tests](../../../tests/fortran/semantic_pyi_format/semantics/test_calls_and_projections.py) | Maintained manual references exist for generated functions, modules, classes, and generated file contracts; automated reference inventory generation has not been selected. |
## Unsupported Or Blocked Forms
| Feature | Status | User docs | Source owner | Evidence | Limitations |
| --- | --- | --- | --- | --- | --- |
-| Unproved pointer lifetime and ownership-changing operations | Unsupported | [Pointer safety](../guide/pointers.md#safety-checklist) | [Ownership policy](../../developer/source-map.md#common-change-routes) | [Pointer policy tests](../../../tests/fortran/pointers/policy/test_pointer_ownership_policy.py), [pointer runtime tests](../../../tests/fortran/pointers/runtime/test_pointer_handle_protocol.py) | Native targets must outlive every handle use; allocation, target deallocation, resize, and writable reassociation require explicit completed policy. |
-| Persistent callbacks and procedure pointers | Unsupported | [Callback limitations](../guide/callbacks.md#important-limitations) | [Callback route](../../developer/source-map.md#common-change-routes) | [Callback policy tests](../../../tests/fortran/callbacks/policy/test_callback_policy.py), [scalar callback tests](../../../tests/fortran/callbacks/end_to_end/test_scalar_callbacks.py) | Callbacks are valid only during the wrapped call. |
-| Advanced multi-source dependency discovery and external-library integration | Unsupported | [Multiple source files](../guide/building-shared-library.md#multiple-source-files) | [Build orchestration](../../developer/source-map.md#common-change-routes) | [Multi-source tests](../../../tests/fortran/building_shared_library/end_to_end/test_multi_source_builds.py) | prik does not infer dependency graphs, prebuilt module paths, or external library discovery. |
-| Blocked array forms | Unsupported | [Unsupported array forms](../guide/arrays.md#unsupported-forms) | [Array policy route](../../developer/source-map.md#common-change-routes) | [Array semantic tests](../../../tests/fortran/arrays/semantics/test_array_semantics.py), [diagnostics](../reference/diagnostic-codes.md) | Assumed type `type(*)`, arrays of derived types, and character arrays not representable as fixed-width bytes need missing runtime contracts. |
-| Unsupported polymorphic forms | Unsupported | [Inheritance limits](../reference/fortran-wrapper.md#inheritance-and-polymorphism) | [Class policy route](../../developer/source-map.md#common-change-routes) | [Inheritance tests](../../../tests/fortran/derived_types/codegen/test_class_surfaces.py) | Results, mutable dummies, arrays, polymorphic allocatable/pointer scalars, and `class(*)` are blocked. |
-| Ambiguous or incomplete constructor overload sets | Unsupported | [Constructor limitations](../reference/fortran-wrapper.md#constructors-initialization-and-finalizers) | [Constructor route](../../developer/source-map.md#common-change-routes) | [Constructor semantic tests](../../../tests/fortran/pyi_contracts/functions_and_classes/semantics/test_method_and_constructor_contracts.py), [class-plan validation tests](../../../tests/fortran/pyi_contracts/functions_and_classes/policy/test_class_surface_policy.py) | Candidates must have distinguishable exact runtime signatures and compatible native-owner lifecycles. |
-| Character arrays and mutable deferred-length character storage | Partially supported | [Strings](../guide/strings.md) | [Character bridge route](../../developer/source-map.md#common-change-routes) | [Character edge tests](../../../tests/fortran/strings/end_to_end/test_character_edge_cases.py) | Character arrays use fixed-width NumPy bytes dtype. Fixed and allocatable deferred element length maps to dtype itemsize; Unicode/object arrays and mutable scalar deferred-length storage are unsupported. |
-| Wider-than-supported real, complex, and logical storage | Unsupported | [Datatype limits](../guide/data-types.md#unsupported-widths-and-forms) | [Type probing](../../developer/source-map.md#hotspot-index) | [Scalar kind tests](../../../tests/fortran/data_types/semantics/test_fortran_scalar_semantics.py) | prik blocks rather than silently losing precision or Boolean storage semantics. |
+| Unproved pointer lifetime and ownership-changing operations | Unsupported | [Pointer safety](../guide/pointers.md#safety-checklist) | [Ownership policy](../../developer/codebase-map.md#cross-stage-hotspots) | [Pointer policy tests](../../../tests/fortran/pointers/policy/test_pointer_ownership_policy.py), [pointer runtime tests](../../../tests/fortran/pointers/runtime/test_pointer_handle_protocol.py) | Native targets must outlive every handle use; allocation, target deallocation, resize, and writable reassociation require explicit completed policy. |
+| Persistent callbacks and procedure pointers | Unsupported | [Callback limitations](../guide/callbacks.md#important-limitations) | [Callback route](../../developer/codebase-map.md#cross-stage-hotspots) | [Callback policy tests](../../../tests/fortran/callbacks/policy/test_callback_policy.py), [scalar callback tests](../../../tests/fortran/callbacks/end_to_end/test_scalar_callbacks.py) | Callbacks are valid only during the wrapped call. |
+| Advanced multi-source dependency discovery and external-library integration | Unsupported | [Multiple source files](../guide/building-shared-library.md#multiple-source-files) | [Build orchestration](../../developer/codebase-map.md#cross-stage-hotspots) | [Multi-source tests](../../../tests/fortran/building_shared_library/end_to_end/test_multi_source_builds.py) | prik does not infer dependency graphs, prebuilt module paths, or external library discovery. |
+| Blocked array forms | Unsupported | [Unsupported array forms](../guide/arrays.md#unsupported-forms) | [Array policy route](../../developer/codebase-map.md#cross-stage-hotspots) | [Array semantic tests](../../../tests/fortran/arrays/semantics/test_array_semantics.py), [diagnostics](../reference/diagnostic-codes.md) | Assumed type `type(*)`, arrays of derived types, and character arrays not representable as fixed-width bytes need missing runtime contracts. |
+| Unsupported polymorphic forms | Unsupported | [Inheritance limits](../reference/fortran-wrapper.md#inheritance-and-polymorphism) | [Class policy route](../../developer/codebase-map.md#cross-stage-hotspots) | [Inheritance tests](../../../tests/fortran/derived_types/codegen/test_class_surfaces.py) | Results, mutable dummies, arrays, polymorphic allocatable/pointer scalars, and `class(*)` are blocked. |
+| Ambiguous or incomplete constructor overload sets | Unsupported | [Constructor limitations](../reference/fortran-wrapper.md#constructors-initialization-and-finalizers) | [Constructor route](../../developer/codebase-map.md#cross-stage-hotspots) | [Constructor semantic tests](../../../tests/fortran/pyi_contracts/functions_and_classes/semantics/test_method_and_constructor_contracts.py), [class-plan validation tests](../../../tests/fortran/pyi_contracts/functions_and_classes/policy/test_class_surface_policy.py) | Candidates must have distinguishable exact runtime signatures and compatible native-owner lifecycles. |
+| Character arrays and mutable deferred-length character storage | Partially supported | [Strings](../guide/strings.md) | [Character bridge route](../../developer/codebase-map.md#cross-stage-hotspots) | [Character edge tests](../../../tests/fortran/strings/end_to_end/test_character_edge_cases.py) | Character arrays use fixed-width NumPy bytes dtype. Fixed and allocatable deferred element length maps to dtype itemsize; Unicode/object arrays and mutable scalar deferred-length storage are unsupported. |
+| Wider-than-supported real, complex, and logical storage | Unsupported | [Datatype limits](../guide/data-types.md#unsupported-widths-and-forms) | [Type probing](../../developer/codebase-map.md#cross-stage-hotspots) | [Scalar kind tests](../../../tests/fortran/data_types/semantics/test_fortran_scalar_semantics.py) | prik blocks rather than silently losing precision or Boolean storage semantics. |
## Planned Or Reserved Areas
| Feature | Status | User docs | Source owner | Evidence | Limitations |
| --- | --- | --- | --- | --- | --- |
-| Full semantic `.pyi` parity across all wrapper scenarios | Planned | [Semantic `.pyi` format](../reference/semantic-pyi-format.md) | [`.pyi` route](../../developer/source-map.md#layer-to-layer-route) | [semantic `.pyi` feature tests](../../../tests/fortran/semantic_pyi_format/) | Only the documented implemented subset is supported. |
+| Full semantic `.pyi` parity across all wrapper scenarios | Planned | [Semantic `.pyi` format](../reference/semantic-pyi-format.md) | [`.pyi` route](../../developer/architecture.md#build-architecture) | [semantic `.pyi` feature tests](../../../tests/fortran/semantic_pyi_format/) | Only the documented implemented subset is supported. |
| MPI examples and distribution constraints | Not implemented | [MPI example](../examples/mpi-example.md) | [Planned examples](../examples/index.md) | [Documentation navigation checks](../../../tests/docs/test_navigation.py) | No support contract or runnable evidence exists yet. |
diff --git a/docs/user/reference/configuration-files.md b/docs/user/reference/configuration-files.md
index 6cd67f5f3..5198948a9 100644
--- a/docs/user/reference/configuration-files.md
+++ b/docs/user/reference/configuration-files.md
@@ -138,7 +138,9 @@ beneath it.
`mkdocs.yml` is the documentation-site configuration. It sets `docs_dir: docs`,
sets the generated site output to the hidden `.artifacts/site/` directory,
selects MkDocs' built-in Read the Docs theme, owns the complete intended
-navigation tree, and loads the publication hook. Generated documentation is
+navigation tree, and loads the publication hook. Its local navigation template
+makes a sidebar section label open its first child page; the adjacent **+**
+control expands or collapses that section. Generated documentation is
therefore kept out of the visible repository root while remaining available
for local inspection. The theme configuration keeps
the sidebar expanded through four navigation levels. A local stylesheet keeps
@@ -148,7 +150,9 @@ screen. The same stylesheet keeps the page body adjacent to the sidebar with a
Code and result blocks use the available page width up to a consistent `56rem`
cap; long lines scroll inside the block. Local JavaScript and CSS add an
accessible copy control to every rendered code, command-output, and result
-block, with separate space reserved beside the text. The production hook
+block, with separate space reserved beside the text. The same local assets
+provide keyboard-accessible example tabs for two or more matching source,
+contract, or Python views; the result remains outside the tabs. The production hook
includes only pages whose front matter says `publication: reviewed`. A draft
lane index suppresses its complete User, Developer, or Maintainer lane. Links
from documentation pages to existing source, tests, configuration, and other
@@ -192,7 +196,7 @@ source-build Makefile behavior by
[`test_build_modes.py`](../../../tests/fortran/building_shared_library/end_to_end/test_source_build_modes.py).
Tooling configuration is covered by
-[`test_reference_and_source_map.py`](../../../tests/docs/test_reference_and_source_map.py),
+[`test_reference_and_codebase_map.py`](../../../tests/docs/test_reference_and_codebase_map.py),
[`test_examples.py`](../../../tests/docs/test_examples.py), and
[`test_check_static_analysis_versions.py`](../../../tests/tools/test_check_static_analysis_versions.py).
diff --git a/docs/user/reference/pyi-contracts/calls-and-results.md b/docs/user/reference/pyi-contracts/calls-and-results.md
index 63deff744..68e25d066 100644
--- a/docs/user/reference/pyi-contracts/calls-and-results.md
+++ b/docs/user/reference/pyi-contracts/calls-and-results.md
@@ -177,7 +177,7 @@ exception projection still run with the GIL held. Remove `@nogil` to restore
the default held-GIL behavior. This changes call behavior, not the native
procedure interface.
-If a decorated native call invokes an prik callback, the callback trampoline
+If a decorated native call invokes a PRIK callback, the callback trampoline
temporarily reacquires the GIL for Python execution. Callback contracts are
covered in the [Callbacks](../../guide/callbacks.md) guide.
diff --git a/docs/user/reference/semantic-ir.md b/docs/user/reference/semantic-ir.md
index 79699e4c6..878841c4f 100644
--- a/docs/user/reference/semantic-ir.md
+++ b/docs/user/reference/semantic-ir.md
@@ -532,8 +532,7 @@ PRIK_C_DOCS_END -->
The proposed target is Python wrappers for C libraries on a selected Linux ABI.
Its primary design requirement is that a semantic `.pyi` file plus a compiled
library be sufficient to generate a wrapper, with C header parsing used only as
-optional input generation. Related deferred policy is tracked in
-[wrapper design notes](../../developer/design/wrapper-design-notes.md).
+optional input generation.
PRIK_C_DOCS_END -->
| Prototype primitive reference | `Addr(T)` inside an intent wrapper |
| Prototype non-primitive value override | `Value(T)` inside an intent wrapper |
-All Boolean names accept and return Python/NumPy Boolean values. `Bool` is the
+All Boolean names accept `bool` or `numpy.bool_` scalar inputs and return Python
+`bool` scalar results. Boolean arrays use `dtype=numpy.bool_`. `Bool` is the
portable one-byte boundary contract and is equivalent to `Bool8` at that
boundary. A numbered name additionally records native Boolean storage bits so
language-specific lowering can preserve the native declaration without
diff --git a/docs_theme/breadcrumbs.html b/docs_theme/breadcrumbs.html
index 0962eb75d..e71562274 100644
--- a/docs_theme/breadcrumbs.html
+++ b/docs_theme/breadcrumbs.html
@@ -17,11 +17,11 @@
class="prik-repository-link"
target="_blank"
rel="noopener noreferrer"
- title="Open the prik source-code repository on GitHub"
- aria-label="Open the prik source-code repository on GitHub in a new tab"
+ title="Open PRIK on GitHub and star the project"
+ aria-label="Open PRIK on GitHub and star the project in a new tab"
>
- Source Code
+ ★ Star on GitHub
diff --git a/docs_theme/nav.html b/docs_theme/nav.html
new file mode 100644
index 000000000..f08f2a622
--- /dev/null
+++ b/docs_theme/nav.html
@@ -0,0 +1,31 @@
+{# Section labels open their first published page; the adjacent + control expands them. #}
+{%- macro first_page_url(item) -%}
+ {%- if item.is_page or item.is_link -%}
+ {{- item.url|url -}}
+ {%- elif item.children -%}
+ {{- first_page_url(item.children[0]) -}}
+ {%- endif -%}
+{%- endmacro %}
+{%- set section_landing_url = first_page_url(nav_item) if nav_item.is_section else "" %}
+{{ nav_item.title }}
+{%- set navlevel = navlevel + 1 %}
+{%- if navlevel <= config.theme.navigation_depth
+ and ((nav_item.is_page and nav_item.toc.items
+ and (not config.theme.titles_only
+ and (nav_item == page or not config.theme.collapse_navigation)))
+ or (nav_item.is_section and nav_item.children)) %}
+
+ {%- if nav_item.is_section %}
+ {%- for nav_item in nav_item.children %}
+
+ {%- include 'nav.html' %}
+
+ {%- endfor %}
+ {%- elif nav_item.is_page %}
+ {#- Skip first level of toc which is page title. #}
+ {%- set toc_item = nav_item.toc.items and nav_item.toc.items[0] %}
+ {%- include 'toc.html' %}
+ {%- endif %}
+
+{%- endif %}
+{%- set navlevel = navlevel - 1 %}
diff --git a/mkdocs.yml b/mkdocs.yml
index c4904b85b..ca0c17a6e 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -19,7 +19,9 @@ extra_css:
- stylesheets/code-copy.css
extra_javascript:
- javascripts/code-copy.js
+ - javascripts/example-tabs.js
- javascripts/faq.js
+ - javascripts/term-tooltips.js
plugins:
- search
hooks:
@@ -118,38 +120,35 @@ nav:
- Language Support:
- Overview: user/language-support/index.md
- Feature Matrix: user/language-support/feature-matrix.md
- - Contributor Documentation:
+ - Developer Documentation:
- Overview: developer/index.md
- Architecture: developer/architecture.md
- - Source Map: developer/source-map.md
- - Feature To Code Map: developer/feature-to-code-map.md
- - Testing Strategy: developer/testing-strategy.md
- - Source Packages:
+ - Architecture Components:
- Overview: developer/packages/index.md
- - Contracts: developer/packages/contracts.md
- - Compiler: developer/packages/compiler.md
+ - Pipeline: developer/packages/pipeline.md
- Preprocessing: developer/packages/preprocessing.md
- Parsers: developer/packages/parsers.md
- Semantics: developer/packages/semantics.md
- Policy: developer/packages/policy.md
- Planning: developer/packages/planning.md
- - Code Generation: developer/packages/codegen.md
+ - Code Generation:
+ - Overview: developer/packages/codegen.md
+ - C Binding: developer/packages/codegen/c-binding.md
+ - Fortran Bridge: developer/packages/codegen/fortran-bridge.md
- Printers: developer/packages/printers.md
- - Pipeline: developer/packages/pipeline.md
- - Runtime: developer/packages/runtime.md
+ - Compiler: developer/packages/compiler.md
+ - Contracts: developer/packages/contracts.md
- Naming: developer/packages/naming.md
+ - Runtime: developer/packages/runtime.md
- Utilities: developer/packages/utilities.md
- - Concepts:
- - Datatype Lifecycle: developer/concepts/datatype-lifecycle.md
+ - Codebase Map: developer/codebase-map.md
+ - Feature-to-Code Map: developer/feature-to-code-map.md
+ - Testing Strategy: developer/testing-strategy.md
- Workflows:
- Contributing: developer/workflows/contributing.md
- Quality Assurance: developer/workflows/quality-assurance.md
- - Continuous Integration And Delivery: developer/workflows/ci.md
- - Documentation Architecture: developer/workflows/documentation.md
- - Release Process: developer/workflows/release.md
- - Design:
- - Multilanguage Runtime Architecture: developer/design/multilanguage-runtime.md
- - Wrapper Open Decisions: developer/design/wrapper-open-decisions.md
+ - Pull Request Checks: developer/workflows/ci.md
+ - Documentation Maintenance: developer/workflows/documentation.md
# PRIK_C_DOCS: - Deferred C Parser Reference: developer/deferred/c-parser.md
- Roadmaps:
- Overview: developer/roadmap/index.md
diff --git a/prik/README.md b/prik/README.md
index df6f48624..a0e075f26 100644
--- a/prik/README.md
+++ b/prik/README.md
@@ -40,7 +40,7 @@ printers, bridges, and bindings must not infer missing expression semantics.
- `docs/developer/architecture.md`
- `docs/developer/packages/index.md`
-- `docs/developer/source-map.md`
+- `docs/developer/codebase-map.md`
- `docs/developer/feature-to-code-map.md`
Keep user-facing support claims in the docs backed by focused tests and, for
diff --git a/prik/codegen/__init__.py b/prik/codegen/__init__.py
index 692ab4f20..8aa81a5ef 100644
--- a/prik/codegen/__init__.py
+++ b/prik/codegen/__init__.py
@@ -1,4 +1,11 @@
-"""Wrapper backend nodes and direct C/Fortran lowering."""
+"""Public code-generation API for lowering completed wrapper plans.
+
+``CBindingGenerator`` and ``FortranBridgeGenerator`` turn a validated
+``ModulePlan`` into typed backend nodes. The selected node records and scalar
+registry re-exported here are the shared vocabulary for direct backend use and
+printers. Policy completion, plan construction, source rendering, and build
+integration remain in their owning stages.
+"""
from __future__ import annotations
diff --git a/prik/codegen/c/binding.py b/prik/codegen/c/binding.py
index 0245a37bc..61f02b651 100644
--- a/prik/codegen/c/binding.py
+++ b/prik/codegen/c/binding.py
@@ -12231,8 +12231,9 @@ def _namespace_module_name(self, module: ModulePlan, namespace: NamespacePlan) -
if __name__ == "__main__":
from prik.planning.planner import WrapperPlanner
- from prik.semantics.models import SemanticArgument, SemanticFunction, SemanticModule, SemanticType
from prik.policy.completion import complete_semantic_policies
+ from prik.printers.c import CSourcePrinter
+ from prik.semantics.models import SemanticArgument, SemanticFunction, SemanticModule, SemanticType
module = SemanticModule(
name="binding_demo",
@@ -12247,25 +12248,14 @@ def _namespace_module_name(self, module: ModulePlan, namespace: NamespacePlan) -
)
complete_semantic_policies(module)
plan = WrapperPlanner().build(module)
- function_plan = plan.namespaces[0].functions[0]
binding = CBindingGenerator()
binding.require_supported(plan)
c_module, c_header = binding.visit(plan)
wrapper = next(function for function in c_module.functions if function.name == "wrap_double_value")
- print(f"Native procedure: {function_plan.bridge.native_name}")
- print(
- "Native call slots:",
- ", ".join(f"{slot.source_kind}:{slot.native_name}" for slot in function_plan.native_call_slots),
- )
- print(f"C module: {c_module.name}")
- print(f"Header guard: {c_header.guard}")
- print("Header prototypes:", ", ".join(prototype.name for prototype in c_header.prototypes))
- print(f"Binding wrapper: {wrapper.name}")
- print(f"Return type: {wrapper.return_type}")
- print("Parameters:")
- for parameter in wrapper.parameters:
- print(f" {parameter.name}: {parameter.type_name}")
- print("Body nodes:")
- for statement in wrapper.body:
- print(f" {statement!r}")
+ printer = CSourcePrinter()
+ print("Rendered C header:")
+ print(printer.doprint(c_header))
+ print()
+ print("Rendered C binding wrapper:")
+ print(printer.doprint(wrapper))
diff --git a/prik/codegen/c/python_surface.py b/prik/codegen/c/python_surface.py
index 946ba4358..558d06c34 100644
--- a/prik/codegen/c/python_surface.py
+++ b/prik/codegen/c/python_surface.py
@@ -1,4 +1,15 @@
-"""Emit the executable Python facade embedded in a generated C extension."""
+"""Emit the executable Python facade installed by generated C initialization.
+
+``PythonSurfaceEmitter`` consumes one planned namespace and a context of
+already-selected holder and proxy identities. It renders opaque derived classes,
+overload forwarders, holder operation maps, and module-object proxy operations
+as Python source. ``CBindingGenerator`` embeds and executes that source during
+extension initialization.
+
+The emitted facade forwards to generated C helpers. It does not select public
+names, ownership, setter exposure, or lifecycle behavior; those facts are
+already fixed in the plan.
+"""
from __future__ import annotations
diff --git a/prik/codegen/checks.py b/prik/codegen/checks.py
index 2876a1296..d6851fc06 100644
--- a/prik/codegen/checks.py
+++ b/prik/codegen/checks.py
@@ -1,4 +1,4 @@
-"""Static contracts for wrapper lowering, printing, and orchestration."""
+"""Static review recommendations for wrapper generation code."""
from __future__ import annotations
@@ -42,7 +42,7 @@
@dataclass(frozen=True)
class WrapperCodegenCheckConfig:
- """Limits enforced for new wrapper-codegen implementation code."""
+ """Recommended limits for wrapper-codegen implementation code."""
max_complexity: int = 10
max_statements: int = 30
@@ -56,7 +56,7 @@ class WrapperCodegenCheckConfig:
@dataclass(frozen=True)
class WrapperCodegenViolation:
- """One static-contract violation in ``prik.codegen``."""
+ """One maintainability recommendation for ``prik.codegen``."""
path: Path
lineno: int
@@ -76,7 +76,7 @@ def check_codegen_package(
*,
config: WrapperCodegenCheckConfig | None = None,
) -> tuple[WrapperCodegenViolation, ...]:
- """Check the wrapper generation, printer, and orchestration modules."""
+ """Review the wrapper generation, printer, and orchestration modules."""
if package_root is not None:
paths = sorted(package_root.rglob("*.py"))
else:
@@ -94,7 +94,7 @@ def check_codegen_paths(
*,
config: WrapperCodegenCheckConfig | None = None,
) -> tuple[WrapperCodegenViolation, ...]:
- """Check selected wrapper-codegen modules."""
+ """Review selected wrapper-codegen modules."""
violations = []
resolved_config = config or DEFAULT_CHECK_CONFIG
tiered_limits = config is None
@@ -119,7 +119,7 @@ def _module_violations(path: Path, tree: ast.Module) -> list[WrapperCodegenViola
def _module_function_violations(path: Path, tree: ast.Module) -> list[WrapperCodegenViolation]:
return [
- _violation(path, node, "module-function", f"move production function {node.name!r} onto a class")
+ _violation(path, node, "module-function", f"consider moving production function {node.name!r} onto a class")
for node in tree.body
if isinstance(node, ast.FunctionDef)
and not (path.name == SEMANTIC_PRINTER_MODULE and node.name in SEMANTIC_PRINTER_FUNCTIONS)
@@ -128,7 +128,7 @@ def _module_function_violations(path: Path, tree: ast.Module) -> list[WrapperCod
def _visitor_class_violations(path: Path, tree: ast.Module) -> list[WrapperCodegenViolation]:
return [
- _violation(path, node, "visitor-class", f"{node.name} must inherit ClassVisitor")
+ _violation(path, node, "visitor-class", f"consider making {node.name} inherit ClassVisitor")
for node in tree.body
if isinstance(node, ast.ClassDef)
and node.name.endswith(VISITOR_CLASS_SUFFIXES)
diff --git a/prik/codegen/fortran/bridge.py b/prik/codegen/fortran/bridge.py
index 49d6ac4a5..b442a86e4 100644
--- a/prik/codegen/fortran/bridge.py
+++ b/prik/codegen/fortran/bridge.py
@@ -7973,8 +7973,9 @@ def _uses_derived_interop_symbols(self, plan: ModulePlan) -> bool:
if __name__ == "__main__":
from prik.planning.planner import WrapperPlanner
- from prik.semantics.models import SemanticArgument, SemanticFunction, SemanticModule, SemanticType
from prik.policy.completion import complete_semantic_policies
+ from prik.printers.fortran import FortranSourcePrinter
+ from prik.semantics.models import SemanticArgument, SemanticFunction, SemanticModule, SemanticType
module = SemanticModule(
name="bridge_demo",
@@ -7989,38 +7990,9 @@ def _uses_derived_interop_symbols(self, plan: ModulePlan) -> bool:
)
complete_semantic_policies(module)
plan = WrapperPlanner().build(module)
- function_plan = plan.namespaces[0].functions[0]
bridge = FortranBridgeGenerator()
bridge.require_supported(plan)
fortran_module = bridge.visit(plan)
- procedure = fortran_module.procedures[0]
- print(f"Native procedure: {function_plan.bridge.native_name}")
- print(
- "Native call slots:",
- ", ".join(f"{slot.source_kind}:{slot.native_name}" for slot in function_plan.native_call_slots),
- )
- print(f"Bridge module: {fortran_module.name}")
- print("Module uses:")
- for use in fortran_module.uses:
- only = f", only: {', '.join(use.only)}" if use.only else ""
- print(f" use {use.module}{only}")
- print(f"Bridge procedure: {procedure.name}")
- print(f"Binding name: {procedure.bind_name}")
- print(f"Procedure kind: {'subroutine' if procedure.is_subroutine else 'function'}")
- print(f"Result: {procedure.result_name} :: {procedure.result_type}")
- print("Parameters:")
- for parameter in procedure.parameters:
- attributes = f", {', '.join(parameter.attributes)}" if parameter.attributes else ""
- print(f" {parameter.name}: {parameter.type_name}{attributes}")
- print("Declarations:")
- if procedure.declarations:
- for declaration in procedure.declarations:
- attributes = f", {', '.join(declaration.attributes)}" if declaration.attributes else ""
- print(f" {declaration.name}: {declaration.type_name}{attributes}")
- else:
- print(" (none)")
- print("Body nodes:")
- for statement in procedure.body:
- print(f" {statement!r}")
- print("Internal procedures:", ", ".join(item.name for item in procedure.internal_procedures) or "(none)")
+ print("Rendered Fortran bridge source:")
+ print(FortranSourcePrinter().doprint(fortran_module))
diff --git a/prik/codegen/nodes.py b/prik/codegen/nodes.py
index ba2dad9e1..168b530d3 100644
--- a/prik/codegen/nodes.py
+++ b/prik/codegen/nodes.py
@@ -1,4 +1,15 @@
-"""Backend syntax nodes for direct wrapper-plan source generation."""
+"""Editable C and Fortran syntax nodes produced by wrapper-plan lowering.
+
+The C node family represents translation units, headers, declarations,
+functions, control flow, and CPython module machinery. The Fortran family
+represents modules, uses, interfaces, declarations, procedures, control flow,
+and native calls. Generators select and assemble these nodes from a completed
+plan; printers alone serialize them into source text.
+
+Every node is a ``StageRecord`` so it can be assembled before a printer freezes
+it. ``CodeExpression`` is a deliberate leaf for
+backend-owned syntax fragments, not a route for policy decisions.
+"""
from __future__ import annotations
diff --git a/prik/codegen/primitive_scalar_types.py b/prik/codegen/primitive_scalar_types.py
index 881921554..fa3dd3fe8 100644
--- a/prik/codegen/primitive_scalar_types.py
+++ b/prik/codegen/primitive_scalar_types.py
@@ -1,4 +1,12 @@
-"""Primitive rank-zero backend type facts shared by wrapper generators."""
+"""Backend spelling registries for resolved primitive scalar identities.
+
+``PrimitiveScalarTypeRegistry.type_for`` returns a fresh editable
+``BackendScalarType`` containing the C, Fortran, NumPy, CPython, and descriptor
+spellings required by direct lowering. ``NumpyDtypeRegistry.expression_for``
+returns the corresponding generated Python expression. Both registries consume
+an already-resolved semantic identity and fail for unknown names; neither
+infers a scalar type from source syntax or a backend condition.
+"""
from __future__ import annotations
@@ -104,7 +112,7 @@ class PrimitiveScalarTypeRegistry:
fortran_spelling="integer(c_int32_t)",
python_parse_unit="O",
numpy_type_macro="NPY_INT32",
- python_result_kind="python",
+ python_result_kind="numpy",
python_type_name=NumpyDtypeRegistry.expression_for("Int32"),
python_module_result_kind="numpy",
cfi_type_spelling="CFI_type_int32_t",
@@ -115,7 +123,7 @@ class PrimitiveScalarTypeRegistry:
fortran_spelling="integer(c_int64_t)",
python_parse_unit="O",
numpy_type_macro="NPY_INT64",
- python_result_kind="python",
+ python_result_kind="numpy",
python_type_name=NumpyDtypeRegistry.expression_for("Int64"),
python_module_result_kind="numpy",
cfi_type_spelling="CFI_type_int64_t",
@@ -137,7 +145,7 @@ class PrimitiveScalarTypeRegistry:
fortran_spelling="real(c_double)",
python_parse_unit="O",
numpy_type_macro="NPY_FLOAT64",
- python_result_kind="python",
+ python_result_kind="numpy",
python_type_name=NumpyDtypeRegistry.expression_for("Float64"),
python_module_result_kind="numpy",
cfi_type_spelling="CFI_type_double",
@@ -159,7 +167,7 @@ class PrimitiveScalarTypeRegistry:
fortran_spelling="complex(c_double_complex)",
python_parse_unit="O",
numpy_type_macro="NPY_COMPLEX128",
- python_result_kind="python",
+ python_result_kind="numpy",
python_type_name=NumpyDtypeRegistry.expression_for("Complex128"),
python_module_result_kind="numpy",
cfi_type_spelling="CFI_type_double_Complex",
diff --git a/prik/compiler/README.md b/prik/compiler/README.md
index 241a498ca..db11de094 100644
--- a/prik/compiler/README.md
+++ b/prik/compiler/README.md
@@ -88,6 +88,6 @@ policy completion. Those decisions happen before generated sources reach this pa
- Compiler package guide: `docs/developer/packages/compiler.md`
- Pipeline package guide: `docs/developer/packages/pipeline.md`
- Quality and static checks: `docs/developer/workflows/quality-assurance.md`
-- Source navigation: `docs/developer/source-map.md`, `docs/developer/feature-to-code-map.md`
+- Source navigation: `docs/developer/codebase-map.md`, `docs/developer/feature-to-code-map.md`
- Build-mode tests: `tests/fortran/building_shared_library/end_to_end/test_source_build_modes.py`
- Runtime ABI tests: `tests/fortran/building_shared_library/end_to_end/test_runtime_compatibility.py`
diff --git a/prik/compiler/compiler_profiles.py b/prik/compiler/compiler_profiles.py
index 14d7c92e2..ca55623ec 100644
--- a/prik/compiler/compiler_profiles.py
+++ b/prik/compiler/compiler_profiles.py
@@ -1,4 +1,11 @@
-"""Built-in compiler profiles for the explicit wrapper build stages."""
+"""Select coherent vendor profiles for explicit native wrapper builds.
+
+``available_compilers`` supplies separate C and Fortran settings for every
+supported vendor, including the active Python and NumPy extension inputs.
+``fortran_compiler_family()`` classifies a selected Fortran executable and
+names its matching C driver; executable lookup and command execution belong to
+``Compiler`` in :mod:`prik.compiler.compilers`.
+"""
from __future__ import annotations
diff --git a/prik/compiler/compilers.py b/prik/compiler/compilers.py
index 78c2f7088..0e8087678 100644
--- a/prik/compiler/compilers.py
+++ b/prik/compiler/compilers.py
@@ -1,4 +1,11 @@
-"""Run explicit native object and extension-link compiler commands."""
+"""Build and optionally execute explicit native compiler commands.
+
+``Compiler`` selects one vendor profile, compiles one complete
+:class:`~prik.compiler.objects.ObjectFile` request at a time, and links a
+caller-supplied ordered object list. It records every argv even in record-only
+mode. Project discovery, dependency ordering, generated imports, and wrapper
+policy remain pipeline or earlier-stage responsibilities.
+"""
from __future__ import annotations
diff --git a/prik/compiler/native_support.py b/prik/compiler/native_support.py
index 47da932ce..144e51bf0 100644
--- a/prik/compiler/native_support.py
+++ b/prik/compiler/native_support.py
@@ -1,4 +1,10 @@
-"""Install bundled native binding support for generated CPython wrappers."""
+"""Conditionally install native support for generated CPython wrappers.
+
+The pipeline supplies generated imports and an output directory. When those
+imports request ``binding_support``, this module replaces the header-only
+payload under that directory and writes its NumPy API-version header. It does
+not choose imports, artefact locations, or compilation order.
+"""
from pathlib import Path
import shutil
diff --git a/prik/parsers/README.md b/prik/parsers/README.md
index 501b9b098..c9410c40c 100644
--- a/prik/parsers/README.md
+++ b/prik/parsers/README.md
@@ -9,9 +9,10 @@ language-specific models:
Cross-language semantic interpretation belongs to `prik.semantics`, while
preprocessing and build orchestration belong to `prik.pipeline`. Stable parser
-convenience functions remain exported from the `prik` package root.
+APIs are imported from their owning language package, not from the `prik` root
+facade.
-See `docs/developer/packages/parsers.md`, `docs/developer/source-map.md`,
+See `docs/developer/packages/parsers.md`, `docs/developer/codebase-map.md`,
`docs/developer/feature-to-code-map.md`,
`docs/developer/deferred/c-parser.md`, and
`docs/user/reference/semantic-pyi-format.md` for maintained behavior.
diff --git a/prik/parsers/c/README.md b/prik/parsers/c/README.md
index f8b51ca9c..991010222 100644
--- a/prik/parsers/c/README.md
+++ b/prik/parsers/c/README.md
@@ -26,7 +26,7 @@ not own preprocessing.
- Deferred reference: `docs/developer/deferred/c-parser.md`
- User recipe: `docs/user/examples/recipes/inspect-c-api.md`
-- Source navigation: `docs/developer/source-map.md`, `docs/developer/feature-to-code-map.md`
+- Source navigation: `docs/developer/codebase-map.md`, `docs/developer/feature-to-code-map.md`
- Parser tests: `tests/c/fixtures/parser/`
- Semantic handoff tests: `tests/c/semantics/conversion/`
diff --git a/prik/parsers/fortran/README.md b/prik/parsers/fortran/README.md
index 7ac8ed2c2..f33b816c4 100644
--- a/prik/parsers/fortran/README.md
+++ b/prik/parsers/fortran/README.md
@@ -4,9 +4,8 @@ This package owns Fortran source facts before semantic conversion. It preserves
modules, procedures, declarations, derived types, visibility, and diagnostics
needed by wrapper and inspection workflows.
-Its canonical implementation namespace is `prik.parsers.fortran`. Public
-callers may also use the stable parser functions and models exported from the
-`prik` package root.
+Its public API is `prik.parsers.fortran`; the `prik` root facade does not
+re-export parser functions or models.
## Entry Points
@@ -23,7 +22,7 @@ callers may also use the stable parser functions and models exported from the
- Package reference: `docs/developer/packages/parsers.md`
- User recipe: `docs/user/examples/recipes/inspect-fortran-api.md`
-- Source navigation: `docs/developer/source-map.md`, `docs/developer/feature-to-code-map.md`
+- Source navigation: `docs/developer/codebase-map.md`, `docs/developer/feature-to-code-map.md`
- Parser tests: `tests/fortran/source_parsing/parsing/`
- Fixture suite: `tests/fortran/source_parsing/parsing/test_fortran_fixture_suite.py`
- Semantic handoff tests: `tests/fortran/semantic_ir/semantics/`
diff --git a/prik/parsers/fortran/cli.py b/prik/parsers/fortran/cli.py
index 568665ee8..2b8c261f4 100644
--- a/prik/parsers/fortran/cli.py
+++ b/prik/parsers/fortran/cli.py
@@ -1,3 +1,13 @@
+"""Render Fortran parser results and diagnostics for command-line inspection.
+
+``main`` is reached through ``python3 -m prik.parsers.fortran``. Its default
+route parses paths and formats parser-owned reports; JSON is the same result in
+a machine-readable shape. The explicit ``--semantics`` and ``--pyi`` options
+cross into semantic conversion and printing for inspection, rather than adding
+meaning to the parser itself. Read the report-building helpers before CLI
+argument handling when changing presentation.
+"""
+
from __future__ import annotations
import argparse
diff --git a/prik/parsers/fortran/models.py b/prik/parsers/fortran/models.py
index 74d6a597b..067437f3b 100644
--- a/prik/parsers/fortran/models.py
+++ b/prik/parsers/fortran/models.py
@@ -1,3 +1,13 @@
+"""Passive source-fact records returned by the Fortran parser.
+
+``FortranFile`` represents one parsed source and ``FortranProject`` adds its
+cross-file registries. Declaration, procedure, type, and unit records retain
+what the source says; they do not make compiler-target, semantic-policy, or
+wrapper-support decisions. ``FortranParseError`` is the source-located parser
+diagnostic. Read these public records before the parser visitors that populate
+them in ``parser.py``.
+"""
+
from __future__ import annotations
import inspect
diff --git a/prik/parsers/fortran/utils.py b/prik/parsers/fortran/utils.py
index 27fbcdd99..be64ba266 100644
--- a/prik/parsers/fortran/utils.py
+++ b/prik/parsers/fortran/utils.py
@@ -1,3 +1,11 @@
+"""Grammar-neutral lexical helpers for the Fortran parser.
+
+``detect_source_form`` selects fixed or free form before lexical preparation.
+``split_csv`` separates only top-level comma lists after a caller has chosen
+the relevant Fortran construct. Neither function builds parser models or
+interprets declarations; ``lexer.py`` and ``parser.py`` own those next steps.
+"""
+
from __future__ import annotations
from prik.utilities.declaration_expressions import split_top_level_expression
diff --git a/prik/parsers/pyi/README.md b/prik/parsers/pyi/README.md
index ece28db95..4b3da0e84 100644
--- a/prik/parsers/pyi/README.md
+++ b/prik/parsers/pyi/README.md
@@ -5,5 +5,5 @@ inline text or files and returns Python AST modules. Semantic interpretation is
handled by `prik/semantics/pyi2ir.py`, and combined file/text loading is handled
by `prik/pipeline/pyi.py`.
-Its canonical parser namespace is `prik.parsers.pyi`; `parse_pyi_text` and
-`parse_pyi_file` also remain stable root-level `prik` exports.
+Its public parser namespace is `prik.parsers.pyi`; the `prik` root facade does
+not re-export `parse_pyi_text` or `parse_pyi_file`.
diff --git a/prik/parsers/pyi/parser.py b/prik/parsers/pyi/parser.py
index a97869f4b..a4e8c6664 100644
--- a/prik/parsers/pyi/parser.py
+++ b/prik/parsers/pyi/parser.py
@@ -3,6 +3,11 @@
Semantic interpretation belongs to `prik.semantics.pyi2ir`; this module stays
small so the `.pyi` pipeline mirrors native source parsing:
parser -> semantic IR converter -> semantic policy completion.
+
+Its only public operations are ``parse_pyi_text`` and ``parse_pyi_file``. Both
+return ``ast.Module`` and leave PRIK contract validation to the semantic
+converter. Read the text function first; the file function is only UTF-8 input
+handling around it.
"""
from __future__ import annotations
diff --git a/prik/pipeline/README.md b/prik/pipeline/README.md
index bb7aa06fc..236173b14 100644
--- a/prik/pipeline/README.md
+++ b/prik/pipeline/README.md
@@ -21,6 +21,6 @@ Reusable compiler execution, compile objects, and linking live in
`../compiler/`. This package imports those services only while coordinating a
complete workflow.
-For cross-stage navigation, see `docs/developer/source-map.md` and
+For cross-stage navigation, see `docs/developer/codebase-map.md` and
`docs/developer/feature-to-code-map.md`. The canonical package reference is
`docs/developer/packages/pipeline.md`.
diff --git a/prik/pipeline/__init__.py b/prik/pipeline/__init__.py
index 33ea5e977..e69de29bb 100644
--- a/prik/pipeline/__init__.py
+++ b/prik/pipeline/__init__.py
@@ -1 +0,0 @@
-"""High-level source preparation and wrapper orchestration pipelines."""
diff --git a/prik/pipeline/build.py b/prik/pipeline/build.py
index db53648f1..a9564f517 100644
--- a/prik/pipeline/build.py
+++ b/prik/pipeline/build.py
@@ -1,4 +1,19 @@
-"""End-to-end Fortran-to-Python extension build pipeline."""
+"""Orchestrate source-first and contract-first extension builds.
+
+The public boundary is the build records plus ``build_fortran_extension()``,
+``build_pyi_extension()``, and ``build_pyi_extension_from_manifest()``. Each
+entrypoint prepares semantic input, completes policy, plans and renders a
+wrapper, materializes its sources, prepares native inputs, then returns a
+``WrapperBuildResult`` after compilation, source-only output, or Makefile
+generation.
+
+Private helpers are grouped by configuration, generated-wrapper materialization,
+native scheduling, source and contract inputs, `.pyi` loading and export
+projection, native planning, manifest handling, wrapper assembly, Makefile
+output, type probing, and semantic preparation. Read from a public entrypoint
+to the phase it calls; this module delegates language meaning, policy, lowering,
+printing, and compiler command construction to their owning stages.
+"""
from __future__ import annotations
diff --git a/prik/pipeline/pyi.py b/prik/pipeline/pyi.py
index 9d7e430d5..109385290 100644
--- a/prik/pipeline/pyi.py
+++ b/prik/pipeline/pyi.py
@@ -1,4 +1,11 @@
-"""Convert semantic `.pyi` text, files, and path sets into semantic IR."""
+"""Load semantic `.pyi` contracts and emit semantic stubs.
+
+``pyi_*_to_semantic_module()`` parses one contract and converts it to semantic
+IR; path-set loading additionally reconciles external type references within
+one operation-local cache. ``emit_module_stubs()`` deep-copies semantic input,
+adds missing opaque dependencies, completes policy, and renders `.pyi` text.
+The module does not construct wrapper plans or native artifacts.
+"""
from __future__ import annotations
diff --git a/prik/pipeline/type_mapping_report.py b/prik/pipeline/type_mapping_report.py
index 661501166..1d38863cc 100644
--- a/prik/pipeline/type_mapping_report.py
+++ b/prik/pipeline/type_mapping_report.py
@@ -3,7 +3,9 @@
The public functions combine compiler probes, the normal semantic converters,
and codegen's NumPy projection catalogue before rendering Markdown. This is a
cross-stage inspection pipeline, not a probe implementation or an alternative
-datatype conversion path.
+datatype conversion path. ``c_type_mapping_markdown()`` and
+``fortran_type_mapping_markdown()`` are the report boundaries; ``main()`` is
+their standalone command-line adapter.
"""
from __future__ import annotations
diff --git a/prik/pipeline/wrapper.py b/prik/pipeline/wrapper.py
index 05a76f559..188e0a38d 100644
--- a/prik/pipeline/wrapper.py
+++ b/prik/pipeline/wrapper.py
@@ -5,6 +5,11 @@
plan consistency, asks each backend to preflight and lower its completed plan,
prints the resulting C, Fortran, and header nodes, assigns stable filenames,
and returns the complete handoff consumed by build integration.
+
+Its public surface is ``GeneratedSource``, ``GeneratedWrapper``, and
+``WrapperGenerator.generate()``. The private sections first report completed-
+plan inconsistencies, then assemble the rendered wrapper; they do not infer
+semantic policy.
"""
from __future__ import annotations
diff --git a/prik/planning/README.md b/prik/planning/README.md
index 7ccdc61fb..00634f72a 100644
--- a/prik/planning/README.md
+++ b/prik/planning/README.md
@@ -12,6 +12,6 @@ Planning must not infer semantic policy or render output text. Python-facing
docstrings, C, Fortran, headers, and the generated Python class facade are
rendered by `../codegen/` from the completed plan.
-For cross-stage navigation, see `docs/developer/source-map.md` and
+For cross-stage navigation, see `docs/developer/codebase-map.md` and
`docs/developer/feature-to-code-map.md`. The canonical package reference is
`docs/developer/packages/planning.md`.
diff --git a/prik/planning/__init__.py b/prik/planning/__init__.py
index 84dd6a18b..3af51d8bc 100644
--- a/prik/planning/__init__.py
+++ b/prik/planning/__init__.py
@@ -1,4 +1,11 @@
-"""Backend-neutral wrapper-plan models and policy projection."""
+"""Public planning API for policy-completed wrapper plans.
+
+``WrapperPlanner`` projects a completed ``SemanticModule`` into an editable
+``ModulePlan``. The records re-exported here describe that plan's shared
+binding, bridge, namespace, transfer, result, lifecycle, class, and descriptor
+views. They represent completed policy for later lowering; they do not provide
+another policy-construction API.
+"""
from .models import (
ArgumentTransferPlan,
diff --git a/prik/planning/models.py b/prik/planning/models.py
index c63f24c7d..737dc39f5 100644
--- a/prik/planning/models.py
+++ b/prik/planning/models.py
@@ -1102,7 +1102,7 @@ class WrapperPlanDiagnostic(StageRecord):
if __name__ == "__main__":
- # ``plan.py`` owns the typed representation rather than semantic-policy
+ # This module owns the typed representation rather than semantic-policy
# completion or source generation. Constructing the smallest procedure
# plan is therefore its nearest deterministic stage-local demonstration.
binding_function = BindingFunctionPlan(
diff --git a/prik/policy/README.md b/prik/policy/README.md
index b1b9216c9..b94a12a42 100644
--- a/prik/policy/README.md
+++ b/prik/policy/README.md
@@ -17,6 +17,6 @@ Raw ownership and pointer-contract metadata belongs to
`../semantics/ownership_metadata.py`. Planning consumes completed records from
this package through `../planning/planner.py`.
-For cross-stage navigation, see `docs/developer/source-map.md` and
+For cross-stage navigation, see `docs/developer/codebase-map.md` and
`docs/developer/feature-to-code-map.md`. The canonical package reference is
`docs/developer/packages/policy.md`.
diff --git a/prik/policy/exports.py b/prik/policy/exports.py
index 2ebcd23ab..7088b7657 100644
--- a/prik/policy/exports.py
+++ b/prik/policy/exports.py
@@ -1,4 +1,15 @@
-"""Completed Python export paths shared by wrapper policy lanes."""
+"""Resolve Python export names for later wrapper-policy construction.
+
+``complete_python_export_policy`` walks public semantic declarations in their
+lowering order, normalizes their requested names, and reserves one name in each
+Python namespace. It writes the completed names back to semantic metadata so
+all policy constructors see the same collision-checked result.
+
+``completed_python_exports`` retrieves that metadata as immutable
+``PythonExportPolicy`` records while wrapper policy is assembled. This module
+decides Python placement only: it does not choose a wrapper mechanism or emit
+the namespace.
+"""
from __future__ import annotations
diff --git a/prik/policy/native_array_handles.py b/prik/policy/native_array_handles.py
index 43a830ab4..11b3af055 100644
--- a/prik/policy/native_array_handles.py
+++ b/prik/policy/native_array_handles.py
@@ -1,3 +1,16 @@
+"""Carry completed native-array handle policy into planning and build setup.
+
+``completion`` attaches ``NativeArrayHandlePolicy`` records to descriptor-backed
+array declarations. This module does not infer their ownership, lifetime, or
+operations. It provides immutable ABI selectors and dispatchers for lower
+stages, plus ``native_array_handle_build_requirements`` to collect generated
+header requirements from completed semantic modules.
+
+Ordinary arrays select the data-buffer ABI; native allocatable and pointer
+handles select the descriptor ABI. Missing completed policy is an error rather
+than a reason to choose a fallback.
+"""
+
from __future__ import annotations
from collections.abc import Iterable, Mapping
diff --git a/prik/preprocessing/README.md b/prik/preprocessing/README.md
index 18e395593..ad24f1ac6 100644
--- a/prik/preprocessing/README.md
+++ b/prik/preprocessing/README.md
@@ -40,6 +40,5 @@ extension. `prik.compiler` supplies reusable compiler mechanisms;
- `tests/fortran/source_preprocessing/preprocessing/`
- `tests/fortran/data_types/probes/`
- `docs/developer/packages/preprocessing.md`
-- `docs/developer/concepts/datatype-lifecycle.md`
-- `docs/developer/source-map.md`
+- `docs/developer/codebase-map.md`
- `docs/developer/feature-to-code-map.md`
diff --git a/prik/preprocessing/fortran.py b/prik/preprocessing/fortran.py
index 273d4e32d..50aa78f32 100644
--- a/prik/preprocessing/fortran.py
+++ b/prik/preprocessing/fortran.py
@@ -5,6 +5,11 @@
expands native ``INCLUDE`` statements left in the compiler-expanded stream.
It preserves generated-to-original line mappings and reports missing files or
cycles without making parser or semantic decisions.
+
+The sole public operation, :func:`expand_native_fortran_includes`, returns
+parser input together with dependency, mapping, and diagnostic records. Read
+that function first; the private helpers resolve paths and maintain the
+generated-line provenance it returns.
"""
from __future__ import annotations
diff --git a/prik/preprocessing/probes/fortran_types.py b/prik/preprocessing/probes/fortran_types.py
index 3b0d8de24..cbf35a65f 100644
--- a/prik/preprocessing/probes/fortran_types.py
+++ b/prik/preprocessing/probes/fortran_types.py
@@ -5,6 +5,13 @@
evaluates the exact expressions requested by the semantic layer with the
selected compiler and flags, caches the resulting facts, and returns values
suitable for ``FortranToIRConverter(..., compile_time_values=...)``.
+
+``FortranTypeProbeReport`` is the reusable measurement record.
+``evaluate_fortran_type_requirements`` and ``evaluate_fortran_type_facts`` are
+the semantic-facing routes; ``probe_fortran_type_expressions_cached`` is the
+general cached measurement route. The module proceeds from generated source
+and validation through execution, report loading and caching, then semantic
+consumer helpers.
"""
from __future__ import annotations
diff --git a/prik/preprocessing/source.py b/prik/preprocessing/source.py
index f6b95af5e..e0525ec84 100644
--- a/prik/preprocessing/source.py
+++ b/prik/preprocessing/source.py
@@ -7,6 +7,14 @@
declarations or makes semantic policy decisions; callers pass
:class:`PreprocessResult.source` to the appropriate parser after this stage
completes.
+
+The public route is :func:`preprocess_source`. ``PreprocessingConfig`` selects
+a direct compiler, compile database, or command template; ``PreprocessResult``
+returns the prepared stream with its recipe, mappings, dependencies, macros,
+and diagnostics. ``PreprocessingPlan`` and ``Invocation`` describe a request
+before execution. Read the module in its phase order: configuration and
+validation, adapter facades, command construction, provenance recovery, then
+execution and result assembly.
"""
from __future__ import annotations
diff --git a/prik/printers/README.md b/prik/printers/README.md
index 383c5fc9a..e0e2b12c5 100644
--- a/prik/printers/README.md
+++ b/prik/printers/README.md
@@ -15,6 +15,6 @@ two native source printers, assigns stable wrapper filenames, and returns one
generated-wrapper result. `../pipeline/build.py` writes or compiles that
result.
-For cross-stage navigation, see `docs/developer/source-map.md` and
+For cross-stage navigation, see `docs/developer/codebase-map.md` and
`docs/developer/feature-to-code-map.md`. The canonical package reference is
`docs/developer/packages/printers.md`.
diff --git a/prik/printers/__init__.py b/prik/printers/__init__.py
index 03bf1af23..157f9f7df 100644
--- a/prik/printers/__init__.py
+++ b/prik/printers/__init__.py
@@ -1,4 +1,10 @@
-"""Canonical C, Fortran, and semantic-contract printers."""
+"""Public printers for the three representations that PRIK serializes.
+
+``CSourcePrinter`` and ``FortranSourcePrinter`` render lowered backend nodes;
+``PyiPrinter`` and ``emit_module`` render semantic IR as an editable contract.
+These APIs format already-formed representations and do not construct plans,
+choose wrapper policy, write files, or compile sources.
+"""
from .c import CSourcePrinter
from .fortran import FortranSourcePrinter
diff --git a/prik/semantics/README.md b/prik/semantics/README.md
index 0684d68bc..f8493f18b 100644
--- a/prik/semantics/README.md
+++ b/prik/semantics/README.md
@@ -4,6 +4,10 @@ This package owns the language-neutral contract between native parser facts
and editable `.pyi` files. Post-IR decisions live in `../policy/`; typed wrapper
implementation plans live in `../planning/`.
+The current supported wrapper route uses Fortran parser facts and semantic
+`.pyi` contracts. `c2ir.py` remains preparatory work for a future C frontend;
+its presence does not make C wrapping supported.
+
## Entry Points
| File | Owns |
@@ -103,10 +107,9 @@ completion remains the next shared stage after those converters produce
- Semantic reference: `docs/user/reference/semantic-ir.md`
- `.pyi` reference: `docs/user/reference/semantic-pyi-format.md`
- `.pyi` wrapper checklist: `docs/developer/roadmap/semantic-pyi-wrapper-checklist.md`
-- Source navigation: `docs/developer/source-map.md`, `docs/developer/feature-to-code-map.md`
+- Source navigation: `docs/developer/codebase-map.md`, `docs/developer/feature-to-code-map.md`
- Architecture: `docs/developer/architecture.md`
- Semantics package guide: `docs/developer/packages/semantics.md`
-- Datatype lifecycle: `docs/developer/concepts/datatype-lifecycle.md`
- Semantic tests: `tests/fortran/semantic_ir/semantics/`
- `.pyi` tests: `tests/fortran/semantic_pyi_format/`
- Wrapper behavior that reaches the typed plan: `tests/fortran/`
diff --git a/prik/semantics/__init__.py b/prik/semantics/__init__.py
index 0925d8a04..958c9d33b 100644
--- a/prik/semantics/__init__.py
+++ b/prik/semantics/__init__.py
@@ -1,3 +1,12 @@
+"""Convenience imports for semantic frontend conversion.
+
+The supported wrapper route converts Fortran parser models and semantic
+``.pyi`` AST through this package. C conversion exports remain available for
+incomplete future frontend work; they do not make C wrapping a supported path.
+Import the model vocabulary and specialized helpers from their defining
+semantic modules when their local contract matters.
+"""
+
from .fortran2ir import (
collect_semantic_compile_time_requirements,
fortran_file_to_semantic_modules,
diff --git a/prik/semantics/fortran2ir.py b/prik/semantics/fortran2ir.py
index 910c1b6c3..615c2ace9 100644
--- a/prik/semantics/fortran2ir.py
+++ b/prik/semantics/fortran2ir.py
@@ -5,6 +5,12 @@
objects. They normalize types, storage, visibility, imported derived types,
and procedure projections. Ownership and wrapper-generation policy are
deliberately completed by later semantic stages.
+
+``FortranToIRConverter`` dispatches each parser model to its matching visitor.
+The public module, file, and project helpers choose the input shape and manage
+per-call compiler facts. Read container visitors first, then variable and
+declaration conversion, followed by storage/projection helpers and the
+compile-time requirement utilities at the end of the module.
"""
from __future__ import annotations
diff --git a/prik/semantics/models.py b/prik/semantics/models.py
index 63c4e40df..8944c5ad8 100644
--- a/prik/semantics/models.py
+++ b/prik/semantics/models.py
@@ -1,3 +1,13 @@
+"""Language-neutral semantic IR records shared by later stages.
+
+``SemanticModule`` is the convergence object produced by frontend conversion.
+Its declarations retain stable type, storage, projection, and provenance facts
+through ``SemanticType``, ``SemanticStorageContract``, and ``SemanticOrigin``.
+The records do not complete ownership or choose emitted mechanisms; policy and
+planning own those later decisions. Read the public dataclasses in module
+order, then the equality helpers that define structural comparison.
+"""
+
from __future__ import annotations
import re
diff --git a/prik/semantics/native_contract.py b/prik/semantics/native_contract.py
index 2622bd046..8c85998b9 100644
--- a/prik/semantics/native_contract.py
+++ b/prik/semantics/native_contract.py
@@ -1,3 +1,12 @@
+"""Prepare and validate source-free native facts declared by semantic `.pyi`.
+
+``prepare_pyi_native_contract`` attaches native origins to loaded contract
+modules. ``native_contract_issues`` reports incomplete or inconsistent native
+placement and type facts, while ``validate_pyi_native_contract`` raises the
+first issue. This module validates declared facts before policy completion; it
+does not choose ownership, support, or generated mechanisms.
+"""
+
from __future__ import annotations
from collections.abc import Iterable
diff --git a/prik/semantics/pyi2ir.py b/prik/semantics/pyi2ir.py
index 91533f9ad..c4f53dfad 100644
--- a/prik/semantics/pyi2ir.py
+++ b/prik/semantics/pyi2ir.py
@@ -5,6 +5,12 @@
projections, and return ``SemanticModule`` objects for native-contract
validation and post-IR policy completion. They deliberately do not choose
wrapper ownership or lowering policy.
+
+``convert_pyi_to_ir`` is the public single-contract boundary.
+``_PyiAstParser`` builds declarations in source order, then resolves local
+relationships that require the completed module; ``reconcile_external_type_refs``
+performs the corresponding batch pass. Read those three boundaries before the
+annotation and decorator helpers that implement them.
"""
from __future__ import annotations
diff --git a/tests/README.md b/tests/README.md
index 2463b7375..6772de29e 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -18,7 +18,7 @@ language.
| Owner | Contract | Focused command |
| --- | --- | --- |
-| [`tests/docs/`](docs/README.md) | Documentation metadata, navigation, executable examples, publication, content journeys, and source-map synchronization | `python3 -m pytest -q tests/docs` |
+| [`tests/docs/`](docs/README.md) | Documentation publication, link integrity, executable examples, and public reference synchronization | `python3 -m pytest -q tests/docs` |
| [`tests/fortran/`](fortran/README.md) | Fortran input, semantic `.pyi` wrapper contracts, generated bridge/binding behavior, and Fortran runtime features | `python3 -m pytest -q tests/fortran` |
| [`tests/c/`](c/README.md) | C input-language inspection behavior | `python3 -m pytest -q tests/c` |
| [`tests/tools/`](tools/README.md) | Maintainer commands and CI support scripts | `python3 -m pytest -q tests/tools` |
@@ -43,6 +43,12 @@ not behavior frozen by recursive layout tests. No legacy stage-first root,
shared fixture corpus, forwarding fixture, collection shim, import alias, or
path fallback is part of the maintained suite.
+Tests protect observable behavior or an explicit durable invariant. They do
+not freeze documentation prose, heading order, private symbol names, complete
+source inventories, or incidental implementation structure. A structural
+check requires a concrete risk that cannot be protected more directly through
+behavior.
+
## Final Fortran stage ownership
Within one Fortran feature, use only the stages that own real evidence:
@@ -151,26 +157,26 @@ CLI/API diagnostic test only when propagation is itself public behavior.
Feature-local fixtures live below their feature; cross-feature helpers require
an explicit infrastructure owner.
-After choosing feature ownership, mirror genuinely internal mechanisms by
-production package and module:
+After choosing feature ownership, place genuinely internal mechanisms under
+their owning production package when that makes the invariant easier to find:
```text
tests/fortran/infrastructure//test_.py
```
-Thus `prik/policy/ownership.py` uses
+For example, `prik/policy/ownership.py` uses
`infrastructure/semantics/test_ownership.py`, while
`prik/planning/planner.py` uses `infrastructure/codegen/test_planner.py`;
language source printers use `infrastructure/printers/` and the wrapper
orchestrator uses `infrastructure/pipeline/test_wrapper_generator.py`.
+This is navigation guidance, not a requirement to create one test file per
+production module.
User-visible behavior does not move to infrastructure merely because it reaches
-those modules. Retained production `if __name__ == "__main__"` demonstrations
-are cross-stage executable architecture contracts. Their output assertions are
-grouped in
-`tests/fortran/infrastructure/execution_examples/test_execution_examples.py`, with one
-explicitly named test per demonstrated production file; feature-local modules
-continue to prove the underlying parser, policy, generation, or runtime
-behavior.
+those modules. Production `if __name__ == "__main__"` demonstrations are
+maintained examples rather than a fixed cross-stage inventory. Package-guide
+command/result pairs are executed by `tests/docs/test_examples.py`, using the
+documentation itself as the expected-output source. Feature-local tests prove
+the underlying parser, policy, generation, or runtime behavior.
Shared support modules provide builders and assertions only. They do not
re-export `pytest`, standard-library modules, or production symbols.
diff --git a/tests/docs/README.md b/tests/docs/README.md
index 110dab7b4..a53a5d6be 100644
--- a/tests/docs/README.md
+++ b/tests/docs/README.md
@@ -1,12 +1,18 @@
# Documentation Tests
-This top-level feature owns repository documentation metadata, visibility,
-navigation, executable examples, publication, user-content journeys, and
-public reference/source-map synchronization.
+This top-level feature owns documentation publication metadata, visibility,
+link integrity, executable examples, and synchronization with public CLI,
+Python API, and feature-support contracts.
-Each pytest module owns one documentation invariant family. Shared parsing
-facts live in `_structure_support.py`; unrelated repository architecture,
-workflow, and product behavior tests do not belong here.
+Developer package-guide commands are discovered with their displayed results.
+The page is the sole expected-output source; there is no parallel test-file
+inventory to update when an example is added, removed, or reworded.
+
+The suite does not freeze prose, headings, reading order, page inventories,
+private names, or the source-tree layout. Those are review concerns unless a
+tool consumes the structure directly. Shared parsing facts live in
+`_structure_support.py`; workflow and product behavior tests remain with their
+own owners.
Run this owner independently with:
diff --git a/tests/docs/_structure_support.py b/tests/docs/_structure_support.py
index 497d7a6e6..b2cc8c144 100644
--- a/tests/docs/_structure_support.py
+++ b/tests/docs/_structure_support.py
@@ -14,94 +14,15 @@
FEATURE_MATRIX_PATH = DOCS_ROOT / "user/language-support/feature-matrix.md"
CLI_REFERENCE_PATH = DOCS_ROOT / "user/reference/cli-commands.md"
PYTHON_API_REFERENCE_PATH = DOCS_ROOT / "user/reference/python-api.md"
-DOCUMENTATION_CHECKLIST_PATH = DOCS_ROOT / "developer/roadmap/documentation-content-checklist.md"
DOC_PATHS = sorted(path for path in DOCS_ROOT.rglob("*.md") if "old_docs" not in path.parts)
-WEBSITE_DOCUMENTATION_PATHS = [
- DOCS_ROOT / "index.md",
- *sorted((DOCS_ROOT / "user").rglob("*.md")),
- *sorted((DOCS_ROOT / "developer").rglob("*.md")),
-]
DEFERRED_C_PAGE_PATHS = [
ROOT / "docs/developer/deferred/c-parser.md",
ROOT / "docs/user/examples/recipes/inspect-c-api.md",
]
MARKDOWN_LINK = re.compile(r"\[[^\]]+\]\(([^)#]+)(?:#[^)]+)?\)")
-NEXT_NAVIGATION = re.compile(r"^\s*(?:#{2,6}\s+Next|\*\*Next\*\*:?)\s*$", re.IGNORECASE)
-NEXT_SECTION_BOUNDARY = re.compile(r"^\s*(?:#{2,6}\s+|---\s*$|\*\*[^*]+\*\*)")
-ALLOWED_CONTEXTUAL_FORWARD_LINK_SOURCE_PREFIXES = ("user/getting-started/", "user/guide/")
-ALLOWED_CONTEXTUAL_FORWARD_LINK_PREFIXES = ("user/reference/pyi-contracts/",)
C_DOCS_START = ""
C_DOCS_DISABLED = "\s*$")
OUTPUT_MARKER = re.compile(r"^\s*\s*$")
SOURCE_MARKER = re.compile(r"^\s*\s*$")
FENCE_MARKER = re.compile(r"^\s*(`{3,}|~{3,})")
+DIRECT_PRODUCTION_COMMAND = re.compile(r"^python3 (?Pprik/(?:[A-Za-z0-9_]+/)*[A-Za-z0-9_]+\.py)$")
SHELL_OPERATORS = {"&&", "||", ";", "|", ">", ">>", "<", "2>", "2>>"}
DISALLOWED_OPTIONS = {
"--compile-commands",
@@ -46,6 +49,16 @@
C_DOCS_START = ""
C_DOCS_DISABLED = "