263 lines
19 KiB
Markdown
263 lines
19 KiB
Markdown
# Public mixed read: bounded implementation map
|
||
|
||
Proposal only, source `0c07f53ab517626f536f79dbaa2885a587bf1db7` inspected read-only.
|
||
No production changes, compiler invocation or acceptance claim. Parent's ordinary
|
||
compatibility gates remain authoritative. Paths below are repository-relative to
|
||
that private source commit. This proposal needs independent critique and selection.
|
||
|
||
## Smallest coherent next outcome
|
||
|
||
Provide an explicitly separate public **complete-bundle, read-only mixed checker**.
|
||
It serves host applications/automation that already own source documents and can
|
||
validate typed calculations alongside ordinary architecture without formatting or
|
||
building an incomplete edit index. Do not silently replace ordinary `parse`,
|
||
`compile_bundle`, or CLI `prepare(Check)` with this path.
|
||
|
||
Suggested surface in a small `source_project`-adjacent public module:
|
||
|
||
```rust
|
||
pub fn check_mixed_bundle<'s>(
|
||
source: &'s SourceBundle,
|
||
limits: ProjectLimits,
|
||
) -> Result<CheckedMixed<'s>, Vec<SourceDiagnostic>>;
|
||
pub struct CheckedMixed<'s> { /* private resolved witness */ }
|
||
impl CheckedMixed<'_> {
|
||
pub fn project(&self) -> &Project;
|
||
pub fn warnings(&self) -> &[SourceDiagnostic];
|
||
}
|
||
```
|
||
|
||
The wrapper contains `ResolvedMixedProject<'s>` directly; no cloned Project,
|
||
self-reference, second desired lifetime, trait framework, or duplicated policy.
|
||
It is not Clone and supplies no mutable model, into_project, index, formatter,
|
||
save or update conversion. Borrowed immutable source cannot change/drop while the
|
||
result lives. The result owns its parsed/model/diagnostic auxiliaries and drops
|
||
them normally; source bundle remains caller-owned. Holding a full resolved witness
|
||
costs more retained auxiliary memory than moving only the model; it is the smallest
|
||
honest authority with existing cleanup and ledger semantics. Later extraction is
|
||
an independent lifecycle design, not required for read-only checking.
|
||
|
||
A caller can explicitly clone a public Project and misuse an unrelated formatter;
|
||
Rust cannot prevent that through an immutable accessor. Documentation must state
|
||
that this result grants validation only and does not qualify legacy source save.
|
||
|
||
## Actual code seams and invariants
|
||
|
||
- `language.rs:8` currently gates the whole analysis_source module under cfg(test).
|
||
Parser's mixed field and hooks are separately gated at1218–1753. Activating only
|
||
the root module is insufficient. Inventory and enable the required parser hooks
|
||
coherently, retaining None for every existing ordinary caller (483/919).
|
||
- `language/analysis_source.rs:3–13` includes index/update/write as well as parsing;
|
||
`mixed/project.rs:25` links ordinary_index and carried.rs:5 links PendingRename.
|
||
Do not expose or ship all edit machinery merely to silence unused-code warnings.
|
||
Audit the minimal production dependency cone; cfg-gate edit-only items or narrow
|
||
module wiring, preserving their existing test build. This is actual required
|
||
integration work, not an assumption that private tests already compile publicly.
|
||
- `mixed.rs:279–308` derives source8 Limits from ProjectLimits then invokes legacy
|
||
phase parsing. That route does NOT select both producer checks. Prefer a narrow
|
||
internally constructed borrowed C=0 CarriedInput selecting
|
||
`carried::parse_entry_producers` (carried.rs:153–168), then project::resolve.
|
||
The Borrowed backing already binds bundle/policy (carried.rs:21–26); its existing
|
||
constructors are fixture-only. A production constructor must derive policy from
|
||
the same bundle/ProjectLimits call, not accept arbitrary Slots/profile authority.
|
||
- Exact ProjectLimits survive; source8 internal Limits are derived once using the
|
||
existing source8 profile, including caller byte/reference restrictions. No policy
|
||
resets between parse and resolve. C=0 excludes externally owned source strings;
|
||
U/M and retained text producer checks stay active, plus resolver accounting once.
|
||
This explicitly stronger new route may refuse earlier than legacy phase checks;
|
||
it must not alter existing ordinary/text-only/phase entry-point acceptance.
|
||
- `mixed/project.rs:453` consumes syntax and seeds its ledger from guard slots once;
|
||
complete construction/lowering follows;596–665 performs complete validation,
|
||
mapped diagnostics and warnings. No typed-only Index, ordinary-index phase,
|
||
RenamePlan, PendingRename, equality-to-desired, or AcceptedRename is needed for
|
||
fresh read-only source admission. Those are output-edit lifecycle authorities.
|
||
- Preserve canonical complete-bundle validation, original byte spans, Unicode
|
||
columns, include ownership, full validation/admission, and warnings in order.
|
||
Return existing Failure.diagnostics on rejection; never convert errors to warnings
|
||
or return a model alongside a failed admission. On success warnings are non-errors.
|
||
No migration is implied: mixed entry requires8; ordinary3–7 callers retain their
|
||
separate migration path. Explicit UUIDs are required for the project, every
|
||
ordinary/typed declaration and every typed parameter: missing IDs are errors,
|
||
never generated or stabilized (language.rs:1295; mixed.rs:252). Detached supplied
|
||
files are rejected by Traversal::finish (traversal.rs:185–200; mixed.rs:503).
|
||
|
||
## Why existing CLI check is not a free consumer
|
||
|
||
`oa-cli/src/lib.rs:213–310` loads DiskProject, lints ordinary raw text, performs
|
||
ordinary declaration analysis and compile_bundle, even for Operation::Check.
|
||
Prepared (175ff) retains a save-capable compiled result. Reusing that pipeline
|
||
would reject typed input before the new checker, or falsely manufacture an index.
|
||
|
||
`source_files.rs:329` calls discover_missing;495 calls inspect_includes,529 compiles
|
||
ordinary reachable source. `source_project.rs:207–245` inspect_includes invokes
|
||
ordinary language::parse_unit. Valid mixed files therefore cannot currently use
|
||
that loader unchanged. Preserve path containment, include budgets, encoding,
|
||
physical aliases, missing files and interrupted-save handling; do not bypass these
|
||
by recursively scanning include strings or silently filtering parse failures.
|
||
|
||
If an actual executable consumer is required in the same milestone, choose a
|
||
separate read-only `check-mixed` operation with no Prepared/save authority, plus
|
||
an explicitly selected mixed include-inspection/discovery adapter using the shared
|
||
parser. This is larger than the core bundle checker and requires its own finite
|
||
file-system contract. Do not claim the existing loader already solves discovery.
|
||
An explicit manifest of all files could avoid parser discovery, but adds a new
|
||
user workflow/format for little value; reject it absent a real caller need.
|
||
|
||
Full compile_bundle adoption is substantially larger: `source_project.rs:111,287`
|
||
returns stable source/index authority used by update/save. It needs typed identity
|
||
stabilization, complete SourceIndex/update semantics, complete formatter coverage,
|
||
loader integration, and downstream caller review. Read-only validation does not
|
||
need these dependencies and should not hold that useful slice hostage to them.
|
||
|
||
## Finite acceptance and exclusions
|
||
|
||
1. External, non-cfg(test) consumer checks exact rich OA and SA multi-file literals;
|
||
assert independently authored complete Project and every mapped warning. Same
|
||
source bytes/maps remain identical, no UUID insertion/migration/formatter path.
|
||
2. Include Unicode/CRLF diagnostics, forward references/scoped parameter collisions,
|
||
typed wrong-kind/unresolved/error cases, malformed syntax, missing/cyclic includes,
|
||
noncanonical paths and detached-file policy exactly as existing mixed contract.
|
||
3. Ordinary8-only complete models agree with public ordinary semantics for explicit
|
||
IDs; legacy public3–7 migration and ordinary8 six-test roundtrips remain unchanged.
|
||
Both long analysis constructors and malformed typed syntax retain intended errors.
|
||
4. Exercise inherited source/file/edge/depth/final-model restrictions and selected
|
||
strong producer exact caps using C=0 expectations, not pending O-based152/151
|
||
numbers. Logical auxiliary entries/text are not an allheap/RSS promise; existing
|
||
model/serde/raw validator exclusions and numeric policy remain explicit.
|
||
5. Borrow/lifetime compile checks prevent escaping result after source dies; scoped
|
||
success/failure destruction controls and existing small-stack suite unchanged.
|
||
Audit stack prologues if public wiring changes frames. DEPTH_128_VALIDATED stays
|
||
false; user-deferred Linux and unresolved full-pipeline limitations are not waived.
|
||
6. If CLI included: actual non-test executable, real three-file mixed fixture,
|
||
exact report diagnostics/exit codes, unchanged directory and file bytes, and
|
||
explicit refusal of write/rename/stabilize flags. No accepted save artifact.
|
||
|
||
Decision required: core read-only bundle API first (recommended minimal useful
|
||
slice) versus adding disk discovery/CLI consumer immediately. Select explicit new
|
||
strong C=0 producer policy and production cfg cone before implementation. No public
|
||
editing, repeated-owned adoption, output formatting or universal heap instrumentation
|
||
is a prerequisite for the recommended core slice.
|
||
## Item-level production wiring refinement
|
||
|
||
This is a proposed bounded wiring plan, not permission for blanket dead_code
|
||
suppression or wider public visibility. Line references remain source0c07.
|
||
|
||
| Item | Production read requirement / proposed treatment |
|
||
| --- | --- |
|
||
| language::analysis_source root and Parser mixed hooks | Compile privately in production; preserve ordinary None paths. Mixed selection remains constructor-controlled. |
|
||
| analysis_source budget, cursor, declarations, lex, lower, syntax, mixed | Required shared parse/lower dependency cone; keep private. |
|
||
| analysis_source index, update, write; model_oracle | Gate entire modules cfg(test) for this milestone. Existing private edit tests still compile their complete chain. |
|
||
| analysis_source::parse standalone expression wrapper (analysis_source.rs:107) | Test-only; real mixed parser uses syntax::binding through declarations. Gate wrapper, not shared Binding/Expression types. |
|
||
| lower::Unit, lower::lower (lower.rs:273), Tables::ordinary | Legacy typed-only adapter; gate these items cfg(test). Keep Tables, insert, typed, lower_bodies and actual lowering representation in production. |
|
||
| mixed::parse / parse_with_profile | Existing phase-only fixtures/tests: cfg(test) wrappers; keep parse_impl shared. Factor the unchanged source8 policy derivation into a small private helper reused by new borrowed constructor and old fixture wrapper. |
|
||
| carried SnapshotPolicy, CarriedInput, CarriedGuard | Required; only borrowed source authority is production in this slice. Policies transfer into existing Budget and ParsedMixedSyntax once. |
|
||
| carried PendingRename import, SnapshotBacking::Pending, GuardBacking::Pending, from_pending and corresponding match arms | cfg(test): private emitter/acceptance remains a tested internal dependency, not public read's production dependency. |
|
||
| carried RetainedSnapshot type, both Retained variants and corresponding match arms | cfg(test): only fixture construction owns this snapshot. Keep existing fixture methods/modules gated. |
|
||
| carried Borrowed variant, into_parts, guard slots/check, parse_entry_producers | Production: actual constructor derives policy from ProjectLimits and borrows actual complete bundle; slots returns zero. Do not flatten Some(Borrowed) into None. |
|
||
| carried parse_carried / parse_text_producers | Test-only historical phase/text-only entry paths. No extra production entry-point that bypasses selected strong mode. |
|
||
| mixed/project ordinary_index module | cfg(test), retaining complete rename/emission/acceptance tests unchanged. |
|
||
| IndexedMixedProject, ResolvedMixedProject::index, its impl/accessors; IndexInput and impl; Failure::index | cfg(test). Failure::typed/ordinary and mapped diagnostics remain production. |
|
||
| ResolvedMixedProject project/warnings | Required accessors used by public read wrapper. |
|
||
| ResolvedMixedProject syntax, expressions, occurrences, storage | Keep all real ownership and ledger retention in production: they back accounted auxiliaries even though read consumers do not inspect them. Do not drop early just to remove warnings or invent reads. |
|
||
| ResolvedMixedProject static_limits/static_usage | Immutable admission evidence already computed by resolve; choose retaining it with precise field-level explanation rather than public methods just for lint. Admission itself is always executed. |
|
||
|
||
Some shared lower representation fields are produced for retained expression/
|
||
occurrence evidence and read only by cfg(test) index. Implementation must inspect
|
||
actual production lint output item-by-item rather than turn off lint for lower.rs.
|
||
Prefer cfg(test) on truly test-only methods; for ownership/evidence fields that
|
||
must survive, a **field-level** cfg_attr(not(test), allow(dead_code), with a nearby
|
||
reason identifying the retained allocation/evidence) is justified. Do not apply
|
||
this to entire structs/modules or change the represented storage inventory. A
|
||
private retained-owner substruct with underscore ownership field is an alternative,
|
||
but would require touching existing destructures/test access for no runtime value;
|
||
prefer narrowly documented existing fields. No fake runtime reads/assertions or
|
||
public accessors solely to placate lint. Exact surviving field list is compiler-
|
||
verified during implementation, not a promise source inspection caught every lint.
|
||
|
||
### Opaque wrapper placement and privacy
|
||
|
||
Place public CheckedMixed in `mixed/project.rs`, beside the only constructor that
|
||
can obtain ResolvedMixedProject, with private field `resolved`. Its constructor
|
||
accepts source+ProjectLimits, calls the selected strong private parse route and
|
||
resolve, and maps Failure.diagnostics. Public project/warnings methods delegate.
|
||
`CheckedMixed` is public as a type but its underlying module remains private;
|
||
re-export only this type and the checker function through analysis_source then
|
||
language (`pub use ...`). Offer the canonical user-facing path
|
||
`language::check_mixed_bundle` / `language::CheckedMixed`; this avoids making
|
||
analysis_source/mixed/project modules public or widening ResolvedMixedProject.
|
||
Reexports through private module ancestors are legal when the final exported type
|
||
itself is pub; no public signature mentions a private ledger/syntax/guard type.
|
||
Do not simultaneously publish duplicate source_project aliases without caller need.
|
||
This chooses concrete placement over the original tentative adjacent-module wording.
|
||
|
||
Production API is read-only and borrow-bound, with explicit IDs for every project,
|
||
ordinary declaration, typed declaration and typed parameter. Finite negative tests
|
||
must independently remove each class's UUID, not merely one project UUID. A supplied
|
||
unreachable file is an error even when syntactically valid; no ignored detached
|
||
payloads. Non-test integration tests exercise the exported path and strong producer
|
||
checks; unit cfg(test) tests alone cannot establish public wiring correctness.
|
||
## Public policy and finite mode evidence (final bounded question)
|
||
|
||
Preserve exactly `Limits::source8(ParseLimits { max_source_bytes:
|
||
limits.model.max_source_bytes, max_step_references:
|
||
limits.model.max_step_references, ..ParseLimits::UNLIMITED })`.
|
||
Budget.rs:16–26 therefore derives bytes=min(caller bytes,64MiB),
|
||
tokens=min(bytes,1,048,576), entries=262,144 (NOT caller max_records),
|
||
references=min(caller references,500,000), frames256 and numeric work50,000,000.
|
||
The separate original ProjectLimits.model still enforces actual final graph/record
|
||
admission. No new public numeric profile or arbitrary carried baseline knob.
|
||
|
||
A proportionate evidence set is:
|
||
|
||
1. **Actual production constructor selection (private observation, real route).**
|
||
Construct from the same public-input bundle and ProjectLimits, invoke exactly
|
||
the production strong parse helper used by check_mixed_bundle, and observe
|
||
`carried=Some(Borrowed)` with slots0, producer_text Some((T,0)),
|
||
producer_entries Some(metadata). Inspect every derived limit including entries
|
||
=262144 while caller max_records is deliberately small but sufficient for the
|
||
fixture. Compare complete model/warnings, Usage and numeric work with the old
|
||
zero-carry reference on the same explicit-ID OA/SA fixture. No mutation/reset,
|
||
second policy argument, fabricated owner or public instrumentation accessor.
|
||
The external integration test calls the actual exported checker; the private
|
||
observation is narrowly labeled wiring evidence, not an independently observed
|
||
external producer refusal.
|
||
2. **Public input-byte boundary.** Minimal explicit-ID E source is78 bytes. Public
|
||
caller max_source_bytes78 accepts that input if later full admission fits;
|
||
77 refuses input before Traversal, with `invalid_source` and
|
||
`Source8 index/output byte limit exceeded.` at main0..1 (corrected by the
|
||
independent acceptance review). E's C0 grammar UUID
|
||
overlap is only44 (=alias1+name7+UUID36), scanner36 and retained text8. Thus a
|
||
hypothetical44/43 producer boundary is unreachable through this public policy:
|
||
both reject the78-byte input earlier. Pending output's152/151 includes carried
|
||
owned-output bytes and is categorically inapplicable here. Likewise the escaped
|
||
fixture's existing C0 producer peak must be compared with its source length;
|
||
do not transplant owned-C491/490 as public checker evidence.
|
||
3. **Public include policy.** Use the already authored explicit-ID three-file chain
|
||
for exact max_files3/2, include edges2/1 and its actual include-depth definition
|
||
(count entry root per Traversal, not an invented number). Pin path/span/error
|
||
order from existing implementation. Reuse full bundle expected model/warnings;
|
||
original complete bytes unchanged. This tests public policy, not entry262144.
|
||
4. **Final-record/graph and reference policy.** A small independently authored
|
||
valid typed+ordinary model exercises exact final-record and graph counts versus
|
||
one less; a real reference-bearing typed fixture exercises declared reference
|
||
limit. Counts must distinguish authored source-reference work from final model
|
||
ordered-step admission, both constrained through the same caller setting.
|
||
Do not assume setting max_records13 sets syntax entry cap13: it does not.
|
||
5. **Selected-mode mechanisms are already separately discriminated.** Existing
|
||
carried/entry_producer.rs zero-C11/12 and prefix owner/value refusal controls,
|
||
text_producer.rs zero-C inventory/phase parity, checked arithmetic and scanner
|
||
ordering remain unchanged. Add only the actual production-constructor bridge
|
||
above, not duplicate all those profiles through an unsupported public knob.
|
||
Keep existing explicit frame/depth controls and add external refusal coverage
|
||
at supported policy limits without implying depth128 platform qualification.
|
||
|
||
The public byte policy masks the independently derived producer boundary for the
|
||
minimal E and existing small examples; this is a concrete ordering fact, not a
|
||
proof that every possible valid multi-file input has auxiliary text <= source.
|
||
Repeated owned key copies can make other inventories larger. Finding a genuinely
|
||
producer-dominant *valid* public fixture could later strengthen external evidence,
|
||
but is not a reason to fabricate an input profile or block the bounded constructor
|
||
selection + existing mechanism + external policy tests. If such a fixture is used,
|
||
handderive its peak, verify earlier source/UUID/scanner/catalog phases fit and
|
||
assert exact refusal site before claiming independent producer-cap isolation.
|