Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
1b75d53
Fix imported abstract interfaces and callback scalar outputs
saidctb Sep 14, 2026
195e32b
Treat an undeclared callback scalar intent as conservatively writable
saidctb Sep 14, 2026
85c5893
Prove the undeclared callback intent through a contract round trip
saidctb Sep 15, 2026
ec7002a
Resolve imported callback interfaces in their declaring module
saidctb Sep 15, 2026
b0364b8
Carry interface provenance through results, renames, and accessibility
saidctb Sep 15, 2026
9623e8c
Spell runtime extents the way a contract spells them in diagnostics
saidctb Sep 15, 2026
e0f9a19
Extract prototype binding from external reference reconciliation
saidctb Sep 15, 2026
eed7e66
Remove the Strided contract name and the dimension step
saidctb Sep 15, 2026
d362f6d
Carry a strided axis as the spelling a contract uses
saidctb Sep 15, 2026
0b9d450
Record the declaring name for a renamed re-export chain
saidctb Sep 15, 2026
f0b3c14
Build one generic interface from every block that declares it
saidctb Sep 15, 2026
ac314f3
Extend a generic interface across the modules that build it
saidctb Sep 15, 2026
dfd955f
Publish an imported procedure a module explicitly makes public
saidctb Sep 15, 2026
841575d
codex: generate relative sibling imports in Fortran leaf contracts
saidctb Sep 15, 2026
2a1dd8f
Keep native scopes bare under relative sibling imports
saidctb Sep 15, 2026
51de26f
Keep every import when a scope uses one module repeatedly
saidctb Sep 15, 2026
bf935a6
Remove an empty test module left by a probe
saidctb Sep 15, 2026
0a040df
Collect every specific a split generic binding names
saidctb Sep 15, 2026
3f7955a
Resolve a kind an interface body names for itself
saidctb Sep 15, 2026
586e4e6
Accept an overload declaration that restates a projected result
saidctb Sep 15, 2026
6ec888d
Import each name as the contract defining it spells it
saidctb Sep 15, 2026
6f439d3
Let a contract rename the entity a declaration reaches
saidctb Sep 15, 2026
fc4a32d
Record a source spelling only where Python cannot hold the name
saidctb Sep 15, 2026
08722d9
Re-export a published name only where Python holds one object
saidctb Sep 15, 2026
349ea0d
Follow a published name to its declaration, and publish only what a c…
saidctb Sep 16, 2026
8b9fc7f
State what a contract publishes in its own __all__
saidctb Sep 16, 2026
8c64482
Let a stated __all__ name a package's sub-namespaces too
saidctb Sep 16, 2026
c787c84
Own a re-export by its declaring contract, not by traversal order
saidctb Sep 16, 2026
63648fa
Say that a C export allowlist states the same surface as __all__
saidctb Sep 16, 2026
bda1c03
Say where a direct C build writes its stubs
saidctb Sep 16, 2026
80aef84
Decide a public name once, and let every stage write that one
saidctb Sep 16, 2026
c8771d5
Name the defect where one decision gets derived twice
saidctb Sep 16, 2026
664c48e
Decide a public name once, and let every stage write that one
saidctb Sep 16, 2026
773f095
codex: preserve module variable reexports
saidctb Sep 16, 2026
b35ce84
Carry the bundled helpers a namespace alias binds through
saidctb Sep 16, 2026
54e73a6
Own a re-exported variable without publishing where it is declared
saidctb Sep 16, 2026
b62216f
Name the bspline classes the way the wrapper now publishes them
saidctb Sep 16, 2026
c67df02
Let the installed environment import what the wheel depends on
saidctb Sep 16, 2026
9493296
Record a published name the way its source spells it
saidctb Sep 16, 2026
b232a0a
codex: stabilize reexports and variable ownership
saidctb Sep 17, 2026
e98c87b
codex: preserve TA-Lib reference inputs
saidctb Sep 17, 2026
338c973
codex: separate Fortran accessibility from Python exports
saidctb Sep 17, 2026
d748891
Judge a callback and an abstract interface by the same accessibility
saidctb Sep 17, 2026
d43b6de
Read a declaration's references rather than scan its text
saidctb Sep 17, 2026
5dd3a27
Accept a raw address extent built from a supported call
saidctb Sep 17, 2026
3cc89a2
Give each procedure the interfaces it declares, and read selectors as…
saidctb Sep 17, 2026
a763b31
Leave a character literal's contents out of lexical translation
saidctb Sep 17, 2026
db494aa
Carry a character selector's length apart from its kind
saidctb Sep 17, 2026
5301f35
Read a Fortran character literal rather than hand it to Python
saidctb Sep 17, 2026
dbb45b5
Read a character declaration's kind as the selector separates it
saidctb Sep 17, 2026
9ea35dc
Specialize declaration expressions, not every metadata string
saidctb Sep 17, 2026
70bf45c
Give a character model one recorder for its selector
saidctb Sep 17, 2026
31936b1
Accept a character literal that states its kind
saidctb Sep 17, 2026
33364ea
Read a character kind from the selector before the legacy field
saidctb Sep 17, 2026
e717f0b
Rename argument references without reaching inside literals
saidctb Sep 17, 2026
c2b4770
Break a continued Fortran line at the expression's own commas
saidctb Sep 17, 2026
f626c32
Publish a prototype or generic only where the module declares it
saidctb Sep 17, 2026
79f3504
Decide a generic re-export's publication where publication is decided
saidctb Sep 17, 2026
aabd16d
Apply the same resolution rule at every re-export hop
saidctb Sep 17, 2026
c0561ac
Carry an enum's enumerators as the constants they already are
saidctb Sep 17, 2026
31f8262
Weigh every route to a name, however each one entered
saidctb Sep 18, 2026
9cbe581
Assemble a generic from every interface contributing to it
saidctb Sep 18, 2026
95c3ca1
Identify a prototype by its scope, and allocate its spelling once
saidctb Sep 18, 2026
e713692
Let a contract's __all__ decide what reloading it publishes
saidctb Sep 18, 2026
45b0586
Record whether a use statement narrowed to an only list
saidctb Sep 18, 2026
78f3ee3
Identify a generic's specific by the module declaring it
saidctb Sep 18, 2026
812c934
Hold the names a module imports while naming its prototypes
saidctb Sep 18, 2026
8201022
Read a stated export surface exactly, and an empty one as stated
saidctb Sep 18, 2026
57425d2
Bind a generic's private specifics in one place
saidctb Sep 18, 2026
3307548
Keep each use statement, and read them in one place
saidctb Sep 18, 2026
112de90
Finish structural identity for a generic's specifics
saidctb Sep 18, 2026
334ecca
Hold a fix to removing an interpretation path
saidctb Sep 18, 2026
e35c976
Read one scope's use statements through one resolver
saidctb Sep 18, 2026
745228e
codex: finish scope use resolution
saidctb Sep 18, 2026
ffc26ca
Complete contract spelling once, before emission
saidctb Sep 18, 2026
1430faa
Decide every export, and define a type whether or not it is published
saidctb Sep 19, 2026
50e1ed0
Plan a contract's imports once, from what it needs to bind
saidctb Sep 19, 2026
7fbd8aa
Spell each imported name one way throughout its contract
saidctb Sep 19, 2026
0027bd2
Spell a declaration-expression call the way the contract binds its ca…
saidctb Sep 19, 2026
62e9d75
Show the generated contract from the parser CLI's --pyi
saidctb Sep 19, 2026
7f4cdae
State @pure on a pure module function in its contract
saidctb Sep 19, 2026
a2e4f7d
Check an actual against the extent a specification function declares
saidctb Sep 19, 2026
1b26c74
Skip the whole call on an extent mismatch, not only the native procedure
saidctb Sep 19, 2026
efb733e
Plan each bridge-evaluated extent once, and pin the rejection boundary
saidctb Sep 19, 2026
2798cb2
Spell prototypes in the contract ledger, not while converting source
saidctb Sep 19, 2026
8f59493
Let a generic own its export decision
saidctb Sep 19, 2026
16d6c23
Remove the retired Boolean-array copy
saidctb Sep 19, 2026
677e2f6
Reach each type in the namespace defining it, by its backend symbol
saidctb Sep 19, 2026
af51ffa
Let a type extend one another module declares
saidctb Sep 19, 2026
1886b13
codex: finish derived type contract naming
saidctb Sep 19, 2026
d347264
codex: link variable publications to their owner plan
saidctb Sep 20, 2026
ea729f8
codex: keep edited variable plan graphs coherent
saidctb Sep 20, 2026
8e89564
codex: isolate the direct C contract module name
saidctb Sep 20, 2026
c92462b
codex: preserve optional callback presence
saidctb Sep 20, 2026
fdf4f2b
codex: validate callback presence plans
saidctb Sep 20, 2026
96f78f8
codex: omit direct callback bridge adapters
saidctb Sep 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
57 changes: 57 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,63 @@ the selected plan requires a genuinely new emitted-code mechanism; those
generators should otherwise keep reusing and dispatching existing planned
paths.

A decision is read, not recomputed. Completed policy moving forward also means a
later stage must not derive the same answer a second time, which is harder to
notice than an override because the second site often calls the same helper and
so reads as reuse rather than as a second authority. When two places need one
answer, ask: **if these two call sites disagreed, which one would be wrong?** If
that has no answer, the decision has two authorities and no owner; if it has
one, the other site must read the answer rather than compute it. This applies to
derivation carrying state or a condition — a collision counter, a reservation
ledger, a language gate, a default — because that is what drifts; calling a
pure, total helper from several stages is fine. Read the owner's recorded
output: the completed policy, the shared plan, or the metadata the owner wrote.
Where a stage cannot run the owner's full completion, run the narrower
completion step for that one decision rather than deriving it again — contract
extraction must describe C that the direct-only wrapper would reject, so
`emit_module_stubs` completes public-name policy for every module and the rest
only where a build request allows it. Sharing the owner's helper is not enough
when the derivation keeps a ledger: two allocators fed the same declarations in
a different order produce the same set of names attached to different
declarations, which every per-stage test still passes.

A fix removes an interpretation path or it does not land. "The regression is
fixed and the tests pass" is half an answer; the other half is **did this delete
a way of deciding, or add one?** A representation that has to mean several
things is the usual source of these bugs, and widening it with another flag or
another fallback leaves every existing reader intact and adds a reader. So when
a record cannot express a case, replace the record; when a lookup is reached by
two key shapes, finish the migration to one; when a completed decision is
ambiguous with an absent one, make completion record it; when a consumer
special-cases what a plan should have decided, move the decision into the plan.
Introducing a record, a small class, or a named reading is the preferred move
when it lets a reader see the rule in one place, and it does not need a separate
mandate: reach for it whenever it fixes the bug in fewer lines than another
branch would, and change an existing structure freely when replacing it is what
makes the code read more simply. Prefer that to a new condition threaded through
existing paths, which each reader then has to hold in mind. The one condition is
that the new thing is accepted only if it deletes the branches and helpers it
replaces — moving them to another module, or wrapping them behind a new name,
does not count. The practical test before committing: the file you changed
should be no harder to read than before, and the count of places that answer
your question should have gone down.

Keep the regressions while doing it. The tests that pin bare, `only`, renamed
and repeated `use` forms, route accessibility, transitive re-exports, merged
generics, prototype collisions, exact `__all__`, and source-build versus
generated-`.pyi` replay are the specification of what PRIK supports; simplify
what sits under them, never by dropping the cases they cover.

Where one decision reaches users through two artifacts, a test must compare
those artifacts rather than only check each one. A built extension and the
`.pyi` contract describing it are one such pair: each had passing tests while
the names they published disagreed, because nothing asserted that they agreed.
Treat the same comparison as a recommendation, not a requirement, for internal
pairs such as a wrapper plan and the sources generated from it. Watch for a
second policy or allocator instance, for a language, route, or flag gate at the
consumer that the owner lacks, and for a `prik/printers/` helper that returns a
name, kind, or decision rather than text.

To answer an ABI question, or to decide whether something belongs in the
binding or in the Fortran bridge, first ask: **how would this work for a
`bind(C)` procedure, where there is no bridge at all?** A direct entrypoint has
Expand Down
637 changes: 637 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/developer/codebase-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ boundary; the modules are where the change lands.
| Prepared source, provenance, and target facts | [`prik.preprocessing`](packages/preprocessing.md) | `source.py`, `fortran.py`, `c.py`, `probes/fortran_types.py`, `probes/c_types.py` |
| Parsed language facts | [`prik.parsers`](packages/parsers.md) | `fortran/parser.py`, `pyi/parser.py`, `c/` |
| Shared language-neutral meaning | [`prik.semantics`](packages/semantics.md) | `models.py`, `fortran2ir.py`, `pyi2ir.py`, `c2ir.py`, `scalar_types.py` |
| Completed interoperability policy | [`prik.policy`](packages/policy.md) | `completion.py`, `construction.py`, `ownership.py`, `exports.py`, `native_array_handles.py` |
| Completed interoperability policy | [`prik.policy`](packages/policy.md) | `completion.py`, `construction.py`, `ownership.py`, `exports.py`, `contract_imports.py`, `native_array_handles.py` |
| Deterministic wrapper planning | [`prik.planning`](packages/planning.md) | `models.py`, `planner.py`, `entrypoints.py` |
| Binding, bridge, and Python-facade lowering | [`prik.codegen`](packages/codegen.md) | `c/binding.py`, `c/python_surface.py`, `fortran/bridge.py`, `primitive_scalar_types.py` |
| Generated-text serialization | [`prik.printers`](packages/printers.md) | `c.py`, `fortran.py`, `pyi.py` |
Expand Down
18 changes: 15 additions & 3 deletions docs/developer/packages/codegen.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,20 +212,32 @@ python3 prik/codegen/c/python_surface.py
Rendered Python facade:
_prik_unset = object()

_prik_ops_state = {}
_prik_ops_state_t = {}
class State:
'Opaque native state.'
__slots__ = ('_prik_capsule', '_prik_owner', '_prik_ops', '_prik_origin')
def __new__(cls, *args, **kwargs):
'Construction is disabled.'
raise TypeError('State objects come from native code.')
def _prik_wrap_State(capsule, owner=None, ops=None, origin='direct'):
def _prik_wrap_state_t(capsule, owner=None, ops=None, origin='direct'):
...
```

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.
lifecycle policy. The operation map and wrapper helper are keyed on the type's
backend symbol, which stays unique when two modules declare a type spelled
alike.

A type is defined in one namespace, and generated code taking or returning it
may live in any other. The binding therefore retains the module object of each
namespace that defines a type, and fetches the class, its wrapper helper, and
its operation maps from there rather than from the calling namespace. A
derived module variable's helpers live beside its type, so its getter reaches
them the same way. A class extending a type another namespace defines names its
base through that namespace too: module initialization creates every namespace
first, then sets them up in plan order, and binds each namespace a setup script
reaches into its dictionary before the script runs.

## Tests And Evidence

Expand Down
2 changes: 2 additions & 0 deletions docs/developer/packages/codegen/c-binding.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ plan = ModulePlan(
binding=BindingModulePlan(...),
entrypoint=NativeEntrypointModulePlan(...),
bridge=BridgeModulePlan(...),
variables=(),
namespaces=(namespace,),
)

Expand Down Expand Up @@ -196,6 +197,7 @@ plan = ModulePlan(
binding=BindingModulePlan(owner_path="demo"),
entrypoint=NativeEntrypointModulePlan(owner_path="demo"),
bridge=BridgeModulePlan(owner_path="demo"),
variables=(),
namespaces=(namespace,),
native_generated_code_groups=(
NativeGeneratedCodeGroupPlan(
Expand Down
2 changes: 2 additions & 0 deletions docs/developer/packages/codegen/fortran-bridge.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ plan = ModulePlan(
binding=BindingModulePlan(...),
entrypoint=NativeEntrypointModulePlan(...),
bridge=BridgeModulePlan(...),
variables=(),
namespaces=(namespace,),
)

Expand Down Expand Up @@ -176,6 +177,7 @@ plan = ModulePlan(
binding=BindingModulePlan(owner_path="demo"),
entrypoint=NativeEntrypointModulePlan(owner_path="demo"),
bridge=BridgeModulePlan(owner_path="demo"),
variables=(),
namespaces=(namespace,),
native_generated_code_groups=(
NativeGeneratedCodeGroupPlan(
Expand Down
17 changes: 13 additions & 4 deletions docs/developer/packages/naming.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,21 @@ choose exports, ownership, wrapper support, or emitted syntax.
## The Two Naming Routes

```text
source spelling + public namespace
source spelling + contract namespace
-> normalize Python identifier
-> reserve it or add a collision suffix
-> public export name
-> completed contract spelling

completed contract spelling + publication policy
-> zero or more public export placements

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
Contract 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.

Expand All @@ -54,7 +57,13 @@ prik/naming/
`NativeSymbolNames.compact()`. It combines a readable prefix with a hash of
the full owner identity under a requested length limit.

`NamingPolicy` retains public reservations for one construction operation.
`NamingPolicy` retains contract-namespace reservations for one policy
completion operation. Post-IR policy records the selected spelling on semantic
owners; contract emission and class-surface construction read that result and
do not create their own reservation ledgers, and neither does semantic
conversion: a prototype, too, is spelled in that ledger, keeping the case it is
declared in. Publication is separate: a withheld declaration still has a
contract spelling so annotations can name it.
`NativeSymbolNames` is stateless: the same owner, preferred spelling, and
limit always produce the same result.

Expand Down
4 changes: 3 additions & 1 deletion docs/developer/packages/parsers.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ prik/parsers/
│ ├── lexer.py
│ ├── models.py
│ ├── parser.py
│ ├── scope.py
│ ├── type_resolver.py
│ └── utils.py
├── pyi/
Expand All @@ -85,9 +86,10 @@ prik/parsers/
| [`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/scope.py`](../../../prik/parsers/fortran/scope.py) | `ScopeUses` aggregates a scope's `use` statements and is the authority for rename semantics, accessible local names, and candidate routes. Semantic consumers decide only what those routes mean for their entity category. | `use` association or scope dependency interpretation 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/fortran/cli.py`](../../../prik/parsers/fortran/cli.py) | `main()` formats parser reports and diagnostics. Its `--semantics` and `--pyi` options explicitly invoke later stages; `--pyi` emits every inspected module through `emit_module_stubs()`, so it shows the contract `prik generate --pyi` writes. | Parser CLI arguments, report layout, or diagnostic presentation changes. |
| [`prik/parsers/c/`](../../../prik/parsers/c/README.md) | `parse_c_file()` and `parse_c_project()` build `CFile`/`CProject` records; the local lexer, models, resolver, and CLI preserve C declarations, project facts, diagnostics, and report output. | C tokenization, declarations, type resolution, project assembly, or parser reports change. |
| [`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. |
Expand Down
33 changes: 27 additions & 6 deletions docs/developer/packages/planning.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ ModulePlan
│ └── NativeEntrypointSignaturePlan
├── NativeGeneratedCodeGroupPlan (zero or more)
├── BridgeModulePlan (optional; Fortran-local holder inventories)
├── ModuleVariablePlan (canonical native-variable registry)
└── NamespacePlan (root and child namespaces)
├── FunctionPlan
│ ├── ArgumentTransferPlan
Expand All @@ -72,7 +73,7 @@ ModulePlan
│ ├── NativeEntrypointProjectedSlotPlan
│ │ └── BridgeCallSlotPlan (optional adapter facet)
│ └── LifecycleActionPlan
└── ModuleVariablePlan
└── ModuleVariablePublicationPlan (namespace bindings to canonical variables)
```

Each callable, argument, and result always owns binding and entrypoint views;
Expand All @@ -83,6 +84,17 @@ projection, presence and length fields, descriptors, and hidden outputs.
Bridge records own adapter-local representation conversion and the invocation
of the original Fortran procedure.

One module-level `ModuleVariablePlan` owns each declaring native variable and
its completed getter, setter, ownership, descriptor, array, and derived-object
mechanisms. Its owner path is the declaring native module and name, independent
of Python publication. A namespace-level `ModuleVariablePublicationPlan` holds
a direct reference to that canonical plan plus the Python names published in
the namespace. Re-exporting module state therefore adds publication records
without resolving ownership from a second key, changing variable identity, or
adding accessors, support procedures, initialization, allocation state, or
pointer state. Parameters use the same structure while retaining constant-value
lowering.

`NativeEntrypointModulePlan.support_procedures` is the authoritative registry for
externally linked generated helper callables that are not ordinary wrapped
functions. Each operation stores one collision-safe key and symbol plus a
Expand Down Expand Up @@ -143,22 +155,31 @@ For each module, the planner first collects top-level and nested semantic
classes into one depth-first, source-ordered tuple. That same collection feeds
derived-type name indexing, backend-symbol allocation, and
`_ClassPolicyCatalog`, so a nested class cannot reach projection without its
symbol being registered. It projects direct functions and variables, then uses
symbol being registered. It projects direct functions and canonical variables, then uses
the catalogue 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.

Each type is defined in one namespace: the one publishing it, beside its
parent class when it is nested and unpublished, and the root otherwise.
Generated code taking or returning the type reaches its class and helpers
there, so `WrapperGenerator` rejects a plan defining one type twice
(`duplicate-derived-type-identity`). A derived module variable's private
helpers are placed in that same namespace.

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
order, except that a namespace whose classes extend a type another namespace
defines comes after that namespace. A namespace's classes are created when it
is set up, in plan order, so the base has to exist first. Finally it collects headers selected by completed descriptor-handle
plans and returns one editable `ModulePlan`.

### `models.py`: shared plans and three lowering 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
`models.py` defines editable `StageRecord` plans. `ModulePlan` is the root and
owns canonical module variables; each `NamespacePlan` groups public functions,
variable publications, derived types, classes, and overloads for one Python path. A `FunctionPlan` owns call-wide
ordering, while its transfers, results, entrypoint parameters, projected call
slots, optional adapter facets, and lifecycle actions carry the
datatype-specific details.
Expand Down
Loading
Loading