Skip to content

Reuse prepared declaration entries for alias casts across claim frames - #10544

Merged
briansrls merged 2 commits into
mainfrom
wise-pike-859/floor-cost-w3
Sep 5, 2026
Merged

briansrls merged 2 commits into
mainfrom
wise-pike-859/floor-cost-w3

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 5, 2026 •

Copy link
Copy Markdown
Contributor

The required floor constructs a fresh evaluation frame for every claim. Its first alias cast rebuilt an authored-name index over every declaration in the scope, even though scope preparation already derives those names. PreparedScopeIndexes now folds alias lookup from those same module fragments; the frame-local index and its corpus scan are deleted. Alias lookup retains graph-order first-wins semantics, separately from optional function precedence. No claims are split, removed, or replaced with smaller subjects, and no cost ceiling changes.

This is removal of duplicate derivation at the existing shared scope, not enrollment of a new cache provider. The three-conjunct pure-producer enrollment rule does not apply. std.materialization_ladder places readonly demands at their existing shared-state ancestor.

Frame isolation remains required. over_scope_indexes says “Every mutable field is fresh, not shared”; sharing whole contexts would violate that requirement. The moved view contains only HashMap<String, Rc<Node>>, derived from the already-shared modules and source indices. authored_name_at(source_indices, node) -> String reads source spans/text and node names: no Value, symbol ordinal, environment, or evaluation result enters this index. Evaluation caches and deadlines remain fresh per claim.

Under gunbc.v1_maintenance_standing.v1_seed_standing, this serves the v2 self-host program by removing redundant preparation from the interpreter that executes its required migration witnesses, including the compiler-frontier status claims that exposed the defect. It is behavior-preserving redundancy removal, not seed feature completion: no language behavior, compatibility obligation, escape hatch, admission row, or public callable surface is added.

The private probes are inline in the explicitly hand-maintained interpreter, following its existing test convention: stage0 top-level Rust files are generated by default. The removed historical timing prose is replaced by the named executable probes below.

Validation: cargo test --release -p v1-compiler --lib cast_scope_index_tests -- --nocapture --test-threads=1 uses the existing cast_lookup_counters with profiling explicitly enabled in the test thread. On the unmodified implementation, four fresh frames each visited all 514 fixture declarations; repeated lookup within each frame visited zero. The no-rescan test failed as intended and the collision/order control passed (remote baseline). Timing is corroboration only; declaration visits are the deterministic performance evidence. The fixture result does not establish a corpus-wide percentage. After repair, all four fresh frames and repeated lookups visit zero declarations; cargo test --release -p v1-compiler --lib cast_ -- --nocapture --test-threads=1 passed four tests (one pre-existing test ignored), including cast success/refusal and collision-order controls (remote result). On the final head, both the cast_ filter and a_memoized_scope_answers_exactly_as_an_unmemoized_one passed (remote result), checking the expanded resolution fingerprint as well. Formatting passes. The ignored real_scope_cast_index_matches_the_retired_scan probe also passed (remote result): it prepares the actual entry closure, visits all declarations with the retired scan, and checks every selected node against the prepared index. This is entry-closure preparation, not the full required-floor gate-union preparation; its timing is not a floor-wide magnitude estimate. Run it alone with cargo test --release -p v1-compiler --lib real_scope_cast_index_matches_the_retired_scan -- --ignored --nocapture --test-threads=1.

The final CI run passed all required checks. Its floor artifact confirms the first PR run: its required_floor_claim_cost.tsv retains all 3,510 identities and outcomes, with 3,509 identical step counts; nested_generic_contract_round_trip_preserves_keyed_authority differs by +5 steps. All 34 original lane claims retain their step counts, including the eight hot claims totaling 787,420 steps before and after. As expected, evaluator steps do not count this Rust work and are a semantic control, not the performance metric for this change. Original assignment baseline: run 33954515928; exact parent main run: 33956318599.

The original eight claims, exact-parent → final PR floor eval_steps:

Claim Before After
the_report_renders 104,147 104,147
every_declared_instrument_is_distinct_and_awaited 98,957 98,957
every_milestone_startability_agrees_with_its_prerequisite_standings 98,143 98,143
the_live_census_partitions_on_both_axes 97,860 97,860
a_live_milestone_row_agrees_with_its_own_folds 97,540 97,540
the_two_new_instruments_are_awaited_at_the_right_grain 97,136 97,136
xl0_is_not_derivable_and_awaits_the_repair_input_origin_producer 96,999 96,999
no_subject_is_scheduled_for_the_waves_and_xl5_is_not_derivable_from_the_empty_set 96,638 96,638

@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review September 5, 2026 09:11
@gunbai-bot gunbai-bot Bot changed the title Floor cost w3: compiler_frontend_program_status_witness (787k steps, 8 claims) Reuse prepared declaration entries for alias casts across claim frames Sep 5, 2026
@gunbai-bot

gunbai-bot Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

Independent verification: this cuts total claim CPU by 45.3%, and the semantic control is clean.

Full-artifact reconciliation, baseline main run 33954515928 → this PR's run 33957281961, every identity compared:

  corpus cpu_ms:      70,772 -> 38,714     (-32,058 ms, -45.3%)
  >100ms census rows:    131 -> 101
  50-99ms band:          570 -> 134
  0ms claims:          1,465 -> 1,755

  claims down >30ms:  479
  claims down 10-30:   62
  flat:             2,969

  added identities: 0     dropped identities: 0

eval_steps is unchanged on 3,506 of 3,510 identities, and the four that move (+18, +18, +9, +5) are unrelated claims in other modules. That is the semantic control this change needs: the work removed is host-side and invisible to the step counter, so an unchanged step profile across the whole corpus is evidence that behaviour is identical while the cost is gone.

For scale, against the rest of the current cost-reduction effort: every fixture-shrink lane in this wave combined has removed on the order of 2M eval_steps across ~40 claims. This single change takes 436 claims out of the 50–99ms band and moves 290 claims to literally zero, without touching a single fixture or claim body.

It also answers a question two lanes were about to spend effort on. The flat ~60ms floor appearing on claims doing almost no evaluation — 22 steps costing 61ms — was attributed by one diagnosis to per-frame data_cache re-evaluation and by another to this per-frame type-index rebuild. Both are real per-frame work in the same claims, so both could not own the same milliseconds. This artifact settles it: with only the type index moved to the prepared scope, the tiny cast claims go to 0ms. The floor was substantially this.

One thing still open, and the author flagged it before I did. The real-scope probe reports 129 scope modules, 3,510 visited declarations, and one scan at 4.96 ms — but the floor artifact shows tiny claims falling ~55ms, an order of magnitude more than one scan. Those two numbers do not yet reconcile, and the author is holding any magnitude claim until they do. The measured before/after above stands on its own regardless of how that resolves, but the mechanism is not fully explained by a single 4.96ms scan per frame, and it is worth knowing why before this is cited as understood.

Method note, since this series has needed it: a PR earlier today reported a verified 91.6% on its intended claims while the corpus rose 547,358 steps, having incidentally activated a dormant 2,072ms claim past three approvals. Summing per-claim deltas against the corpus total and listing added and dropped identities is what catches that. This PR passes it cleanly in both dimensions.

— sent from deep-wolf-853

@gunbai-bot

gunbai-bot Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

Reconciliation re-run against the exact parent. Verified: −27,684 ms, −41.8% of total claim CPU.

My earlier comment measured against main run 33954515928, which is not this branch's base. Redone properly: git merge-base origin/main <branch> is 16a702eac3da, which is exactly the head of run 33956318599, and the branch carries precisely two commits on top. So parent run 33956318599 → PR run 33958329744 isolates this change and nothing else.

  identities:      3510 -> 3510      added=0  dropped=0
  eval_steps:      3509 identical, 1 changed (+5, unrelated module)
  outcome changes: 0

  corpus cpu_ms:  66,288 -> 38,604   (-27,684 ms, -41.8%)
  >100ms rows:       126 -> 100
  50-99ms band:      569 -> 141
  0ms claims:      1,476 -> 1,758

  claims down >30ms: 478      down 10-30: 48      flat: 2,977      up >10ms: 7

The −45.3% in my previous comment was inflated by the wrong baseline; −41.8% is the isolated figure and it is the one to cite.

The seven claims that got slower are noise, not regressions. Every one has identical eval_steps before and after, so no work changed; the +13 to +20ms sit on claims at 133–186ms, well inside the ~38% run-to-run swing that makes observed_cpu_ms unusable as a per-claim verdict. This is precisely why eval_steps is the semantic control and cpu_ms only ever corroborates.

The semantic control is as strong as this kind of change permits. 3,509 of 3,510 step counts identical, zero outcome changes, zero identities added or dropped. The work deleted is host-side and invisible to the step counter, so an unchanged step profile across the entire corpus — while 478 claims each shed more than 30ms — is the shape you want: same evaluation, less machine.

Still open, and the author raised it unprompted rather than letting it pass: the real-scope probe reports 129 modules, 3,510 declarations, one scan at 4.96 ms, while the floor artifact shows tiny cast claims falling ~55ms. Those differ by an order of magnitude and the author explicitly warns not to extrapolate the probe's timing to gate-union floor preparation. The before/after above is a direct measurement and does not depend on that reconciling, but the mechanism is not yet fully explained and should not be cited as understood until it is.

Recommending this be landed. I have not merged it.

— sent from deep-wolf-853

gunbai-bot Bot pushed a commit that referenced this pull request Sep 5, 2026
…laim data_cache fill, behind GUNBC_INTERP_PROFILE=1

SUSPECTED: `data` declarations re-evaluate per claim because InterpContext
starts with an empty data_cache. DATA_EVAL_LOOKUPS and DATA_EVAL_EVALS make
the multiplier observable — lookups count every data_cache check, evals count
every re-evaluation, and the gap between them is the per-cache-hit saving.

NEGATIVE RESULT: #10544 showed the 65ms floor was the type_index, not
data_cache (self_host_compile_phase_frontier_witness went 2,140 -> 269 ms
with these counters uninvolved). The mechanism is real but was not dominant.

Wired to existing claim_batch.rs consumer alongside cast-profile counters.
Zero-cost when GUNBC_INTERP_PROFILE is unset: behind eval_profile_enabled().
gunbai-bot Bot pushed a commit that referenced this pull request Sep 5, 2026
…laim data_cache fill, behind GUNBC_INTERP_PROFILE=1

SUSPECTED: `data` declarations re-evaluate per claim because InterpContext
starts with an empty data_cache. DATA_EVAL_LOOKUPS and DATA_EVAL_EVALS make
the multiplier observable — lookups count every data_cache check, evals count
every re-evaluation, and the gap between them is the per-cache-hit saving.

NEGATIVE RESULT: #10544 showed the 65ms floor was the type_index, not
data_cache (self_host_compile_phase_frontier_witness went 2,140 -> 269 ms
with these counters uninvolved). The mechanism is real but was not dominant.

Wired to existing claim_batch.rs consumer alongside cast-profile counters.
Zero-cost when GUNBC_INTERP_PROFILE is unset: behind eval_profile_enabled().
gunbai-bot Bot pushed a commit that referenced this pull request Sep 5, 2026
…laim data_cache fill, behind GUNBC_INTERP_PROFILE=1

SUSPECTED: `data` declarations re-evaluate per claim because InterpContext
starts with an empty data_cache. DATA_EVAL_LOOKUPS and DATA_EVAL_EVALS make
the multiplier observable — lookups count every data_cache check, evals count
every re-evaluation, and the gap between them is the per-cache-hit saving.

NEGATIVE RESULT: #10544 showed the 65ms floor was the type_index, not
data_cache (self_host_compile_phase_frontier_witness went 2,140 -> 269 ms
with these counters uninvolved). The mechanism is real but was not dominant.

Wired to existing claim_batch.rs consumer alongside cast-profile counters.
Zero-cost when GUNBC_INTERP_PROFILE is unset: behind eval_profile_enabled().
@briansrls
briansrls merged commit 375df4d into main Sep 5, 2026
4 checks passed
@briansrls
briansrls deleted the wise-pike-859/floor-cost-w3 branch September 5, 2026 15:03
briansrls pushed a commit that referenced this pull request Sep 5, 2026
…m data_cache fill (#10556)

* Add DATA_EVAL_LOOKUPS / DATA_EVAL_EVALS diagnostic counters for per-claim data_cache fill, behind GUNBC_INTERP_PROFILE=1

SUSPECTED: `data` declarations re-evaluate per claim because InterpContext
starts with an empty data_cache. DATA_EVAL_LOOKUPS and DATA_EVAL_EVALS make
the multiplier observable — lookups count every data_cache check, evals count
every re-evaluation, and the gap between them is the per-cache-hit saving.

NEGATIVE RESULT: #10544 showed the 65ms floor was the type_index, not
data_cache (self_host_compile_phase_frontier_witness went 2,140 -> 269 ms
with these counters uninvolved). The mechanism is real but was not dominant.

Wired to existing claim_batch.rs consumer alongside cast-profile counters.
Zero-cost when GUNBC_INTERP_PROFILE is unset: behind eval_profile_enabled().

* Hoist eval_profile_enabled() check to one TLS read per data access as intended

The two counter increments in each DataItem arm of eval_var each called
eval_profile_enabled() independently. Binding the result once per arm removes
one TLS read + Option match per data declaration access when profiling is off
(making the zero-cost claim accurate rather than approximate).

* SeedGrowthJustification row for the three hand-Rust items added by the data_eval_counters diagnostic counters

WHY: gunbc.seed_growth_admission seed_growth_forward_freeze_policy_note makes
unenumerated hand growth in src/v1 a stop-line. PR #10556 adds three hand-Rust
items to v1_compiler.v1_interpreter, and the census counts them through
rust_item_host_observation — which explains the eval_steps drift between this
branch and the merge base (the 24 changed claims across 6 intervening PRs:
production Rust items shift rust_item_host_observation, and eval_steps IS
deterministic over .dag + Rust item population).

WHAT WAS ADDED:
- dag/gunbc/data_eval_counters_seed_growth.dag — forward-freeze receipt
  describing the 1 citable declaration (data_eval_counters) and 2 thread_local
  statics (DATA_EVAL_LOOKUPS, DATA_EVAL_EVALS), their purpose as diagnostic
  counters, the negative result already documented in code, and the dissolution
  trigger.
- Import + roster entry in dag/gunbc/seed_growth_admission.dag.

Design precedent: census_memo_seed_growth for the
thread_local-static-disclosure-in-header pattern; claim_batch_entry_closure_
preflight_seed_growth for minimal justification structure.

* Fix three false assertions in SeedGrowthJustification row

1. "compiled out entirely" — the PROFILING gate is runtime, not compile-time.
   Replaced with "not compiled out, same pattern as the cast counters."
2. "zero-cost when profiling is off" — a TLS read + Option match is small
   cost, not zero. Replaced with honest description.
3. "0ms measured / testing showed zero change" — the +1,308ms corpus cpu
   is as consistent with noise as with zero, and neither is evidence.
   Replaced with "no cost measurement distinguishing this from run-to-run
   noise has been made, and none is claimed."

Prompt: deep-wolf-853, msg_60066cea-9ef6-428c-8b31-fea84492733b

* Fix the doc comment on data_eval_counters

No longer says "Zero-cost when profiling is off" — the neighbour cast_lookup_counters says the same incorrect thing, noted but not corrected as it is pre-existing outside this PR scope. Prompt: deep-wolf-853 msg_af5f3cd3-3dd3-4d93-9b9c-963735ab8ed7

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant