14 KiB
Mixed typed occurrence index: successor contract
Accepted bounded implementation contract, 2026-09-24, after parent source
inspection and independent critique.
This is a design decision, not an implemented or verified index. Implementation facts refer to
aaec78fcc9b273d1485497126392afdd1fb2e54e, not the Windows prerelease.
This continues the complete-Project contract,
especially section 7, and the original-span composition review.
Issue 7 owns scope/status; issue 37's frozen source is unaffected.
The requested end state remains complete graphical/textual/API parity for quantities, calculations and constraints, with preservation, checked persistence and usable workflows. A private typed occurrence index is a dependency, not that end state. Ordinary occurrence indexing, update composition, public source8, structural editing, migration, UI and transport acceptance remain required.
Current evidence and problem
language/analysis_source/mixed/project.rs:18owns one admitted complete Project, originalParsedMixedSyntax, warnings, static limits/usage, retained expression/occurrence arenas and their aggregate storage ledger. Only Project and warnings are exposed read-only. It does not provide an editing index.language/analysis_source/mixed.rs:39retains the exact borrowed SourceBundle, caller ProjectLimits, canonical file table, full-buffer tokens, original typed declarations and ordinary syntax positions. Numeric file keys belong to this table; equal offsets in different files are unrelated locations.- Existing typed-only
analysis_source/index.rs:122-243owns names and occurrence/ expression maps but borrows a caller numeric source map. Its private builder combines an ordinary Project with separate Lowered model maps. Feeding the complete mixed Project into that path unchanged duplicates typed globals. Its local map-size checks do not account for the retained mixed ledger. analysis_source/update.rsaccepts the typed-only Index in its standalone Plan and opaque Composition/OriginalEdits adapter. Those APIs do not establish complete SourceBundle entry/path/profile authority for mixed input.- Public
source_project.rs:93-117exposes mutable bundle/model/index fields;update_bundle_with_identity_maprecompiles and compares all three before editing (640 onward). Its ordinary collector applies edits, then runs the structural updater, then recompiles and compares the complete intended Project (868 onward). This later-coordinate structural pass cannot be relabeled as original-coordinate mixed composition. That public contract is unchanged here.
Accepted choice
Criteria are exact original ownership, complete semantic coverage within the declared index scope, aggregate resource accounting, compatibility and avoiding two divergent implementations of structural verification.
| Candidate | Evidence / tradeoff |
|---|---|
| Shared private verification/maps with distinct provenance wrappers | Reuses the existing structural-path, token, owner and call-label checks. Requires explicit source/declaration/site views and storage reservations. Preferred if the extraction remains small and typed-only behavior is preserved. |
| Separate copy of the typed index for mixed input | Simpler initial access to mixed fields, but duplicates the nontrivial syntax-edge and call-label verifier and would need every later correction twice. Reject unless extraction exposes a concrete incompatible invariant. |
| Reparse mixed fragments into the old numeric-map Index | Loses complete bundle/profile authority, repeats accounting and can lose original coordinates. Reject. No substring, masked-source or canonicalized bridge. |
Adopt the first candidate with the consumed mixed wrapper below. The critique's two findings are resolved here: storage domains are fixed by the existing contract, and reference completeness is distinguished from runtime expression verification. Revisit only for a demonstrated incompatible verifier invariant or a concrete requirement for multiple independently retained index owners.
Do not add a public generic indexing framework. Shared helpers may consume private borrowed inputs only inside the authenticated constructors. There must be no public or sibling-callable API that treats arbitrary Lowered sites and caller-replaced token/location maps as an authenticated mixed index.
Ownership and construction invariant
The proposed mixed constructor consumes ResolvedMixedProject<'s> and returns
an opaque IndexedMixedProject<'s> owning that witness plus its index maps.
Names are illustrative API identifiers. The output borrows the original bundle
through its retained witness; it contains no self-references. Its read-only
views borrow the output. Construction either succeeds completely or returns
diagnostics with no usable partial index.
Consuming the witness prevents creating multiple independently retained indexes while charging only one to its ledger. If a borrowed-construction alternative is chosen, it must prove reservation lifetime/release and simultaneous-index bounds; extra reservation lease machinery is not justified without a demonstrated need.
The mixed wrapper must not dereference/convert to the old Index or implement an
adapter accepted by old Plan::renames, Plan::apply or Composition::renames.
Read-only access to names/locations does not grant edit authority. A later
compositor must bind the full original entry, file set, canonical paths, bytes,
limits/profile and complete target, not merely compare touched file bytes.
Build from retained full-file tokens/declarations and the existing expression/
occurrence arenas without reparsing, lowering again or duplicating Project
records. Iterate typed declarations with their canonical numeric file keys;
do not clone them into old owned Units. Derive global names exactly once from
the complete Project, including project, definitions, elements, relations,
diagrams, placements, artifacts and traces. Add calculation parameters under
(calculation_id, parameter_id); a parameter UUID reused by another calculation
or a global remains distinct. Parameter spelling is calculation scoped.
Reuse existing expression/occurrence key semantics: file-qualified locations, owner, binding field, structural child path, token role and qualified target. Headers and all typed reference roles must be included. Ordinary targets may appear in the catalog and typed references, but this view does not invent an ordinary declaration/reference occurrence index. Document that distinction in the read-only API and tests.
Verify owner containment, UTF-8 source boundaries, exact token spelling and token classification, uniqueness of physical token ownership and qualified keys, parent-before-child/path/depth rules, and call-target/parameter-label agreement. Check structural edges against retained authored syntax, not only internally consistent arena claims. Keep file ownership when reporting errors; use an explicit invariant-error location fallback when no one file is justified.
Live storage and failure policy
Continue the retained ledger and Budget/profile; do not initialize a fresh permissive budget or recharge original source/token/exact-number parsing. Reserve checked aggregate additions before allocation, combining the existing syntax/sites/warnings baseline with new retained maps and all live scratch.
The implementation must inventory names and owned name bytes, occurrence and
expression map entries, unique persistent Path nodes, and temporary owners,
physical locations, path lookup vector, call map, global/parameter spelling
lookups, syntax-site lookup and iterative walk slots. An Arc clone shares a path
node but still occupies its enclosing map/vector slot. No copied path vectors
are needed to construct keys. If Project::identities() is used, account for
its temporary Vec (model.rs:1763); a streaming traversal avoids that allocation.
Retained lowerer occurrences and newly retained occurrence-map entries coexist. Preserve the preceding contract's dimensions: lowerer occurrence records retain their occurrence-slot reservations; new index map/vector/set entries and unique Path nodes consume entry slots. Separately owned names consume text bytes. Both representations count once in their respective domains; neither record is charged twice merely because it is called an occurrence. Do not reset or release the old arena's reservation while its vectors remain live. Release scratch reservations only after the corresponding allocations are dropped. Preserve prior logical-slot scope: this is not an allocator-capacity/RSS or raw model/validator-heap bound.
For the current three-map design let G be complete global-plus-scoped names,
H typed declaration headers, O retained lowerer occurrences, E expression sites,
and P nonroot expression sites. Added retained storage is entry slots
G + (H + O) + E + P, occurrence slots zero, and text bytes the sum of copied
names' UTF-8 lengths. The prior baseline still contains E raw expression entries
and O occurrence slots. One Path Step is allocated per nonroot expression; any
additional retained representation requires an explicit additional reservation.
Peak scratch additionally includes owner map H, physical-token set H+O, arena-position/path/depth vector E, call-site map C, borrowed reverse-name maps G, syntax-site lookup E and live iterative walk slots W. Count any allocated file/declaration adapter table too. Drop owners/physical tokens after occurrence validation, and paths/calls after argument-child validation before syntax-edge work where possible; otherwise sum their overlapping reservations. A popped work item releases one logical slot. The scalar visited count consumes no allocated entry per visited node. Path-node reservations survive dropping the temporary vector while retained map keys still share those nodes.
Budget errors abort construction. Existing depth checks may update deepest-frame usage; this is not reparsing or Exact-work recharge. Warning retention and prior static admission metadata stay unchanged. Neither indexing nor failure recovery repeats complete model admission or constructs replacement source. Rejection and destruction must retain the existing bounded-stack policy; no production depth128 enablement is implied by a narrow private test.
Required evaluators before implementation acceptance
The independently enumerated rich-fixture oracle
provides concrete names, keys, spans and retained-storage totals. Parent raw-byte
verification passes all 36 original and 36 transformed Unicode/CRLF spans using
the adjacent check_oracle_bytes.py, without running the parser, lowerer, index
or compiler. This validates the test data's byte arithmetic, not implementation.
- Hand-enumerated OA and SA mixed bundles: entire name catalog plus every typed declaration/reference/expression key, full-file span and spelling. Include interleaved ordinary declarations, cross-file references in both semantic directions, Unicode/CRLF and coincident offsets. The expected index must not be generated by the builder, formatter or lowerer under test.
- Reuse the complete-Project repeated/reordered-call fixture with shared parameter UUIDs in distinct calculations; compare all qualified labels and structural paths, including repeated identical expression text.
- Internal corruption controls: swapped file ownership, wrong owner/field, parent cycle/forward edge, structurally wrong but internally consistent child, duplicate physical token, missing/extra expression, duplicate occurrence, wrong call label/target, missing required argument label, and wrong token classification/spelling. Every control must reach its intended existing structural/token check rather than an unrelated earlier parse refusal. Complete reference occurrence emission remains an invariant of the sealed lowerer, tested by the independent exhaustive oracles in items 1 and 2. The existing syntax-edge checker verifies the expression arena; it does not prove all parameter-declaration or non-expression type-reference occurrences are present. Do not claim arbitrary omitted occurrences are runtime-rejected or introduce an unreviewed duplicate full syntax-reference verifier.
- Hand-counted live-storage cap and cap-minus-one cases: retained baseline plus names/paths/maps, peak overlapping scratch, copied-name bytes, and simultaneous occurrence representations. Check unchanged parse/numeric counters and exact intended refusal phase; no success by clearing the baseline.
- Read-only provenance and lifecycle: exact entry/path/file/byte retention, unchanged whole Project/warnings/admission metadata, no old-updater-compatible conversion, and no usable failed result. Exercise complete success/drop and representative late rejection/drop on the existing small-stack harness.
- Existing typed-only index/update/export tests and full inherited compatibility dispositions must remain accounted for after shared-helper extraction. Strict core Clippy and current-source checks remain required. Private full library source8 failures are not to be suppressed or called passed.
After this dependency, integrate real ordinary and typed original-coordinate edit producers, combined preflight/emission, output recompile/admission and whole intended-Project equality. Extend to structural edits, identity changes, missing-ID stabilization and checked-save/history before claiming the required editing parity. This proposal does not authorize a smaller final product.