49 lines
9.2 KiB
Markdown
49 lines
9.2 KiB
Markdown
# Remaining parser scratch: bounded independent critique
|
||
|
||
Read-only source basis97a8703adc75467a7f8e75f5c6cb00ca542b707c. Entry-producer work is pending and is not assumed accepted or executed here. This is a recommendation for the parent to decide, not an accepted domain change or runtime finding.
|
||
|
||
## Conclusion and obligation
|
||
|
||
Yes: an output-acceptance contract can explicitly preserve existing independent file/token/grammar/numeric bounds for named remaining parser scratch instead of adding all that scratch to the carried aggregate. This is consistent with the bounded logical domain, provided the contract accurately names its timing and exclusions. It must not claim one global physical memory ceiling, aggregate before-every-allocation, or that an independent bound is a reservation against the surviving output owner.
|
||
|
||
The user need is reliable graphical/text/API editing and persistence. A physical heap meter is not a user-owned requirement identified in the domain audit. The accepted rename-plan contract's mandatory successor *does* require complete actual emitted output, exact inherited policy, surviving-output accounting, actual parse/resolve/admission, whole desired-Project equality with E scratch, documented old-owner transition, and no usable failed result. These are not waived by choosing a smaller scratch domain. That contract does not name every parser coordination stack as a new carried-ledger allocation.
|
||
|
||
The earlier `CARRIED-STORAGE-DOMAIN-AUDIT.md` calls itself a design audit, not an accepted contract. Its recommended expansion seams and question about traversal/delimiter scratch must not silently become user requirements. In particular, its suggested significant-token push charge is not the currently accepted metric: the entry contract explicitly retains token storage under the token bound, with one token-end M subtotal reserved before ends construction. The newer text contract explicitly names its retained String producers and temporary decode/result strings. Neither permits hiding a newly introduced in-scope owned output/path/equality structure as old scratch.
|
||
|
||
## What existing source actually bounds
|
||
|
||
All source references below are repository-relative at97a8703.
|
||
|
||
| Scratch | Existing guard or structural bound | Remaining limitation |
|
||
| --- | --- | --- |
|
||
| Folded path table and traversal paths | `source_project/traversal.rs:22–87` checks file count and source-text sum before its folded table; validates every supplied path. Active/visited unique paths are related to file count; pending includes to include-edge count. | File-count bounds are not total path-byte bounds. Folded Unicode path copies and canonicalization allocate outside aggregate T. `include` at149–178 resolves/copies target and location before its edge-limit refusal; it is false to describe every such temporary as guarded before growth. |
|
||
| Traversal queue/children/active stack | Same file/edge/depth policy; `next` checks depth before visited insertion; `finish_file` transfers pending children into stack (`89–186`). | Repeated include targets still consume edges and path copies. Entry count and path text can coexist with output C without debiting its aggregate ceiling. A deep/wide graph is not bounded solely by visited-file count. |
|
||
| Delimiter stack | `language.rs:1032–1040`: at most one push per opening delimiter in the already scanned significant-token sequence. Ends array is the selected M subtotal. | Delimiter stack is another collection, not prepaid by the same N ends reservation. Token guard is a separate finite bound; no aggregate C+M charge for delimiter slots exists. |
|
||
| Ordinary open declarations | `language.rs:1539–1723`: stack carries indices into the flat declaration vector. Existing declaration events/model count checks precede each declaration and its open push. | Maximum live depth is structurally at most declarations. Do not claim this vector is controlled by typed-value depth64 or by the typed Pratt frame budget; those are different controls. |
|
||
| Pratt coordination | `analysis_source/syntax.rs:18–45,60–63,154–264`: tasks/values/sequence coordination are iterative; expression/operator/argument events, raw tokens and relevant grammar-frame checks constrain growth. | Not every Vec push has its own reserve, and grammar frame count is not native stack bytes. Completed subtree values remain owned while siblings parse. Existing small-stack successes are finite evidence, not a universal stack guarantee. |
|
||
| Typed duplicate-name/ID sets | `declarations.rs:284–307,604–624` and `syntax.rs:238–249`: entries track already charged declarations/arguments/overrides. Named string clones derive from parsed reference/name text. | These clones are explicitly excluded scratch, not retained T or scanner/grammar decode W. Work count bounds their number, not independently their total copied bytes; original text/source bounds provide an additional constraint. No existing aggregate reservation covers their overlap. |
|
||
|
||
These are finite structural relationships, not exact peak formulas. With unlimited/wide configured policies, they may be practically large. UTF-8 case folding, path normalization, repeated path copies, large sequence coordination and native enum sizes are reasons not to present the logical ceiling as a process-memory bound.
|
||
|
||
## Choices
|
||
|
||
1. **Retain named independent bounds, explicitly excluded from carried W.** Smallest next step. Complete selected retained T/U/M hooks and reconciliation; retain exact existing traversal/token/grammar checks and refusal semantics; finish owning actual-output admission/equality. Document the table above in the acceptance contract. This is my recommendation for the currently stated editing objective.
|
||
|
||
2. **Add selected scratch W, starting with a demonstrated problem.** Useful if a specific unbounded or disproportionate copy threatens the intended deployment, or if the parent selects a stronger aggregate resource promise. For example, traversal path storage would require canonicalization/folded-path temporary and queue ownership decisions, with path-byte rather than just file-slot accounting. A delimiter-only W is simpler but proves nothing about the other excluded structures. Each addition needs before-growth placement, release/transfer rules and a literal peak oracle; it is not a harmless extension to current caps.
|
||
|
||
3. **Universal parser/all-heap containment.** Much larger and unsupported as the automatic next prerequisite. Allocator capacity, model/serde/validator and numeric internals are already excluded by accepted contracts. Instrumenting only parser stacks would still not establish this promise.
|
||
|
||
Do not choose option1 while retaining prose from option2 that says all parser auxiliary storage is charged against C. Conversely, do not block actual-output correctness on proving an unrequested universal bound.
|
||
|
||
## Concrete evidence needs without scope expansion
|
||
|
||
Before relying on the existing bounds, source review must establish each structural relationship and no new output-verification helper bypasses its existing checks. Reuse existing limit controls where they already cover duplicate include edges, depth, token exhaustion, declaration nesting and wide/deep expressions. A missing relevant control is a reason for one finite diagnostic test, not a generic scratch allocator framework.
|
||
|
||
The clearest risk deserving a specific design note is traversal path text: source-byte sum excludes map keys, and include canonicalization occurs before edge refusal. The accepted owned-output C already counts all emitted path keys and entry text, but that does not account folded/path queue copies. Either explicitly retain this limitation, or select a separate path-specific strengthening. Do not claim file/source limits alone provide a tight path-byte peak. No measured failure in this review requires instrumentation immediately.
|
||
|
||
New accepted-output lifetime/equality scratch is different: it is explicitly mandated and cannot be excluded as parser coordination. Preserve old B during emission, carry actual O after the documented old-owner drop, include new verification syntax/storage against O, reserve E against the correct verification live total, and drop temporary verification before returning a non-self-referential owning accepted result. An excluded raw desired/model borrow does not justify losing in-scope path/output copies. Retained mapped diagnostics continue to require their existing reservations even though transient refusal diagnostics have an escape.
|
||
|
||
Native stack risk remains empirical. Preserve existing128KiB/deep/wide controls and inspect changed prologues if new state/hooks alter frames. A stack failure is not repaired by putting vector slots in W; neither a phase check nor a token bound proves Rust stack headroom. Do not relax tests to support a stronger claim.
|
||
|
||
Suggested precise acceptance wording: “The verifier checks the declared retained syntax and auxiliary domain, plus the named temporary decode and equality domains, against the exact inherited aggregate policy including surviving output. Existing traversal, delimiter, ordinary-open, Pratt and duplicate-name scratch retain their independent file/edge/token/grammar bounds and are excluded from that aggregate metric. This is not a physical-memory or before-every-allocation guarantee.” Actual source/evidence must support the selected hooks before that wording is claimed implemented.
|