Files
ARCADIA-Studio/harness/analysis-entry-producer-design-20260925/ENTRY-PROPOSAL.md
T

12 KiB
Raw Blame History

Existing retained U/M producer timing — proposal

Source 97a8703adc75467a7f8e75f5c6cb00ca542b707c; 2026-09-25. Original read-only proposal, selected by the sibling entry-producer contract. Source references are repository-relative at the pinned commit; original local worktree links are transcribed as plain paths for relocation. No build or runtime result is inferred. This is a next prerequisite for the existing private output-verification path, not an accepted-output API or all-heap accounting.

Selected-domain invariant

U remains exactly Budget.usage.entries, the existing cumulative syntax-event charge; do not relabel every allocated object or Vec push as a new U event. M remains exactly the existing conservative subtotal: F complete-file slots + significant-token-end count + unique ordinary value_ends entries + lexical-owner entries + ordinary projection slots. Its dropped value-end/token-end portions remain represented through the syntax witness as before. C is the actual retained guard's immutable Slots, never Usage. In a new explicit entry-producing mode, every selected U/M growth must first check checked C.entries + U + M + delta <= exact Limits.entries. A refused reservation installs no new U/M total. Existing occurrence and numeric work semantics do not change; text-producing checks continue independently against the same policy. The final U/M inventory must equal the existing inventory for successful input. This strengthens timing, not the metric. Token storage still uses the token bound: M has ONE token-end component, not separate charges for significant tokens and ends. Capacity, container node overhead and native stack do not become entries.

Compatibility and concrete owner

Keep legacy, carried-phase and text-only routes unchanged, including their phase timing/diagnostics. Add a fixture-only route enabling text plus entry producers from the existing opaque CarriedInput; no arbitrary baseline/profile constructor and no numeric-zero bypass. Existing text-only E146/145 and phase-only tests retain their meanings. A small optional Budget entry state can hold only carried-entry baseline and current M; U is read from existing Usage, never duplicated. Derive C directly from the guard at initialization. Initialize M=F before Traversal::new using the existing file check. No full policy copy, owner enum, new heap container or String wrapper is needed. Measure generated frames after implementation rather than spending the repaired stack margin by assumption. Use Budget::entry as the common prospective-U seam: preserve the old syntax-work check/error behavior, then perform the new aggregate check before incrementing Usage or letting the caller create its associated representation. These checks must not reset work, reinterpret references as occurrences, or add U again at final handoff. A per-file scalar pending_projection count belongs in mixed State, where ordinary grammar callbacks already meet the shared Budget. It counts future projection slots without reserving them prematurely. Keeping this scalar distinct from live M avoids charging output that has not been produced yet.

Concrete seams and ownership

Existing component Producer seam Required action / reconciliation
U ordinary events crates/oa-core/src/language.rs:1192 syntax_entry; field1321, value1357, project1513, include1613, description1637, declaration1657 All route through State::entry/Budget::entry before their current grammar event. Preserve exact event counts and caller order. No charge for every open-stack push or every Rust enum.
U typed events crates/oa-core/src/language/analysis_source/declarations.rs:261,290,476,542,611; crates/oa-core/src/language/analysis_source/syntax.rs:61,169,242 Existing pre-event calls cover declaration/field/type/dimension/override and Pratt expression/operator/argument events. Grouping mutates an existing expression and does not invent an entry. Deferred node construction uses its already reserved event. Keep the repaired iterative driver unchanged.
F file records crates/oa-core/src/language/analysis_source/mixed.rs:314–329 Initial complete-file reservation stays before traversal. Map-to-canonical-Vec consumption transfers the same logical file records; do not add another F merely for the new container.
Ordinary value-end map language.rs:1373, after successful Ast construction but before map insertion A State::remember_value_end helper checks whether the offset is new, reserves one M only for a new key, then inserts. Ast already has its U event. Replacement updates do not add a slot. Per-file reserved count must equal actual map.len before its conservative subtotal is retained/dropped.
Lexical owners language.rs:1700, before push and ordinary declaration insertion A State::push_lexical_owner helper reserves one M before its current Vec push. Count occurrences, not unique IDs. Per-file delta must equal Vec.len. Typed roots/project header do not gain fabricated ordinary-owner entries.
Token-end metadata language.rs:1032 ends collection; mixed.rs:368+ preprojection boundary Reserve exactly tokens.len once before ends creation, alongside projection below. No need to charge M during lex::tokens significant-token push: that producer belongs to the existing token-bound-only domain, and ends does not yet exist.
Ordinary projected slots language.rs:1042–1168 Positions and per-declaration construction Pre-reserve pending_projection once before any projected declaration/header/field/value allocation. Preserve seven logical slots per ordinary declaration/body/header envelope, one per field key, one per Ast-projected value; keep the node-header envelope conservative rather than revising it.

Direct map/Vec growth should remain inside the same narrow State helper as its reserve; expose no independent unchecked mutable metadata operation for the new path. The shared ordinary Parser invokes these helpers only through its existing optional mixed State. Public grammar need not acquire a new state owner.

Avoid the current counting-work Vec on the new path

The current crates/oa-core/src/language/analysis_source/mixed.rs:440+ is a postparse saturating tally with an unmetered borrowed-work Vec. Calling it before a projection reservation does not establish before-growth accounting for that Vec. Do not silently charge its scratch under the retained projection subtotal or call saturation checked arithmetic. Recommended replacement ONLY for the new route: increment checked pending_projection by7 when an ordinary declaration is created, by1 for every successful ordinary field(), and by1 for every successful ordinary value(). Nested objects/arrays are visited naturally by those existing calls; each child value and nested key contributes exactly once. Project/include/description grammar does not call field/value in that path and must not enter this projection counter. Failed whole parses need no successful-witness reconciliation. At the projection boundary, reserve pending_projection + tokens.len into M once. Maintain a scalar projection quota consumed by the actual projected producer:7 per declaration,1 per field,1 per EditValue. Check quota subtraction before the corresponding production and require zero at completion. This compares the independent grammar-derived inventory with actual projection consumption without a second AST walk or an extra collection. Static header roles are included in the existing7 envelope; do not also subtract their individual count. Legacy/carried-phase/text-only retain ordinary_position_slots and their prior behavior. The stronger path's quota hook can be an additional narrow optional callback/scalar in the existing shared projector; do not add a generic visitor framework or clone ASTs. The source review must compare grammar counting order and projection consumption coverage, including synthetic body Record handling. The synthetic per-declaration body Record is already part of7 and is NOT a second value() contribution. Ast::Object below a field is an actual value and consumes1 plus its field entries; Ast::Array consumes1 plus items. Atom/Reference/HistoricalUuid each consume1. This distinction needs explicit tests.

Transfer and final checks

After each file, compare its reserved value-end/owner counts with actual lengths and its consumed projection quota with zero. Compute the expected M increment from those lengths, tokens.len and the reconciled projection count; compare against the producer M delta instead of adding it again. Initial F is checked separately once. At final syntax return assert Budget's M equals ParsedMixedSyntax.metadata and the file inventory's checked total. Keep Usage.entries as the original U. The existing resolver still seeds C once and reserves U+M once in its distinct ledger; this is transfer/reconstruction, not an additional simultaneously retained allocation. Do not seed C+U+M and then call the unchanged additive syntax path again. Text T transfer/reconciliation remains as implemented. No new occurrence storage is allocated in this slice; C.occurrences continues its inherited checks. If a future producer introduces an auxiliary container, it is not covered by these retained counters unless explicitly inventoried.

Finite acceptance oracles and limits

  1. Empty E: C.entries1, U1, M11 (F1 + ten token ends), final syntax13; cap13 parses,12 refuses before token-end/projection creation, full resolver peak17 remains distinct. Real inherited text policy must be sufficiently large (producer E146) so text cannot preempt the entry control.
  2. Existing three-file chain: C.entries3, U3, M19 (F3 + sixteen token ends), final25; syntax25/24 and resolver29/28 remain separate cases. Verify actual file/checkpoint attribution and no double-add at transfer. Scanner raw-token work is31, not M's sixteen significant tokens.
  3. Minimal ordinary empty activity: before its first lexical-owner push C1+F1+U2=4; entry cap4 can distinguish the new owner reservation refusal. It is a negative timing control, NOT a claim cap5 admits the complete syntax. Use actual guard ownership, generous text/token limits and original declaration span.
  4. First ordinary description "" value: C1+F1+U4+one lexical owner=7 immediately before its new value-end entry; cap7 refuses before map insertion. Again cap8 only fits that prefix, not the later complete metadata. A bounded test observer or separately reviewed reserve-plus-insert helper must establish ordering; a final retained count alone cannot.
  5. Independently hand-count flat fields, nested record/array/reference/HistoricalUuid and node versus element headers: exact grammar projection counter equals old retained inventory, and actual projection quota ends at0. Invalid under/over quota and repeated map-key controls are labeled internal fault injection, not real source provenance. No AST cloning or output-derived expected model.
  6. Whole real OA/SA/multi-file outcomes and Usage/numeric parity against text-only at ample limits; explicit C0 new mode; old route cap/error behavior unchanged. Work Usage counts must not absorb C, M or projected quota events.
  7. Preserve all old 128 KiB/deep/wide controls and measure changed Budget/State/projector frames. No stack/test-size relaxation or RUST_MIN_STACK. Repeated failure must not leak a partial witness or new source authority.

Finite domain decision still required

The projector also uses a delimiter Vec at language.rs:1033–1040; traversal and ordinary open-declaration coordination likewise remain existing scratch, not retained M. The proposed contract can honestly cover U/M while leaving those named scratch producers open. It cannot claim the single N token-end reservation accounts two simultaneous N-sized containers. If the parent requires these scratch entries now, choose an explicit additional live W, reserve before each push/release on pop, and derive new peak oracles; that is a separate finite metric addition. Comparison: keep the old count walk and add bounded W for its work frontier (smaller initial grammar edits, but expands scratch policy and peak caps), versus grammar scalar + producer quota (more named seams, no new frontier/domain). Recommend the latter for this narrowly retained-inventory prerequisite. Broader scratch, final actual-output equality and accepted-owner transition remain out of scope. No additional task is proposed or started here.