Skip to content

v2 interpreter symbol interning, CONTINUATION (ctrl#1533 phase 3; predecessor session archived, item re-dispatched 2026-06-13): finish replacing String identity carriers in src/v2/stage0/src/v2_interpreter.rs with an interned representation. START FROM the preserved WIP branch origin/session/deep-ea - #4799

Merged
briansrls merged 14 commits into
mainfrom
session/quick-ant-784
Jun 13, 2026

Conversation

@briansrls

Copy link
Copy Markdown
Contributor

Auto-opened by session-dashboard for session quick-ant-784.
Pushing to session/quick-ant-784 advances this PR.

Worker attestation

Before flipping this PR to ready for review, confirm each item:

  • Title describes the change (not the session id or branch).
  • PR body summarises what and why (replace the TODO below).
  • Tests run: name the command (e.g. npm test, cargo test) and the result.
  • If this closes a work item, the body contains a Closes #N directive.
  • No commits on this branch are surprises (no fork/cherry-pick I did not make).
  • No secrets / credentials / large binaries staged.

Summary

TODO: replace this paragraph with one or two sentences naming the change and its motivation. Reviewers read this first.

Test plan

  • TODO: list the commands that ran (or "no tests changed; relied on CI") and the outcome.

Brian Searls and others added 7 commits June 12, 2026 22:51
Replace String identity carriers with per-context Symbol ids in Value/Env,
add sym_eq/field/with_active_context for host transports, and update
cli_run, claim_executor, and receipt tests to resolve interned names.

Co-authored-by: Cursor <cursoragent@cursor.com>
@briansrls
briansrls marked this pull request as ready for review June 13, 2026 01:48
Brian Searls and others added 3 commits June 13, 2026 02:55
… accounting

Restore ACTIVE_CTX via Drop guard on unwind, hoist FreeMonoid symbol
lookups in free_monoid_to_vec, and account the symbol intern table heap
in account_retained_memory.

Co-authored-by: Cursor <cursoragent@cursor.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Review responses (quick-ant-784)

cursor/composer-2.5 (APPROVE, no findings) — Verified against 12cc5dbbac: scope is v2 interpreter + host wiring only; Symbol carriers, InterpContext intern table, with_active_context for display/eval, and explicit ctx.sym_eq / ctx.field in claim_executor, cli_run::classify_exit, and the typescript receipt test. No code change required.

claude-opus-4-7 (REQUEST_CHANGES) — Addressed in 12cc5dbbac:

  1. with_active_ctx panic safety — ActiveCtxGuard restores the prior thread-local on Drop (including unwind), so a panicking closure cannot leave a dangling *const InterpContext.
  2. free_monoid_to_vec hot path — Hoisted Empty/Cons/head/tail symbol lookups once before the loop (no per-Cons active_ctx() churn; no unused match bindings).
  3. Memory accounting — SymbolInterner::heap_bytes() plus (interner) line in account_retained_memory so name bytes are not silently dropped after the String→Symbol conversion.

CI re-run is in flight on 12cc5dbbac (prior 7bf186d0 aggregator failure was ci_floor_parity cancelled at the 60m job timeout, not a compile/test regression).

— sent from quick-ant-784

Brian Searls and others added 2 commits June 13, 2026 03:05
Count symbol-intern-table bytes once at the start of
account_retained_memory via accounting_first_visit, matching the review
follow-up on phase-3 memory receipts.

Co-authored-by: Cursor <cursoragent@cursor.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Addressed all three review findings in 12cc5db + $(git rev-parse --short HEAD):

  1. with_active_ctx panic safety — valid. ActiveCtxGuard now restores the prior thread-local in Drop, so an unwind through f() cannot leave a dangling *const InterpContext behind.

  2. free_monoid_to_vec hot path — valid. Hoisted the four Empty/Cons/head/tail symbol lookups before the loop and removed the unused arm bindings that would trip -D warnings.

  3. Interner heap accounting — valid follow-up. SymbolInterner::heap_bytes() counts the strings vec + index key payloads; account_interner runs once at the start of account_retained_memory under the shared visited set.

— sent from quick-ant-784

@briansrls

Copy link
Copy Markdown
Contributor Author

Correction on prior note: fixes landed in 12cc5db + 75640c9 (panic-safe ActiveCtxGuard, hoisted free_monoid_to_vec symbols, account_interner heap pass).

— sent from quick-ant-784

Brian Searls and others added 2 commits June 13, 2026 03:07
The prior run hit the 60m job ceiling during the v3 census ratchet step
after parity + build succeeded; all parity/census tests pass locally.

Co-authored-by: Cursor <cursoragent@cursor.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

Addressed the diagnostic-surface regression in 4a8e65d:

  • run_claim / claim_executor post-eval formatting: added InterpContext::format_value (wraps with_active_ctx + Display) and routed ClaimOutcome::NotBool { got } and claim_ref_from_value field/type mismatch errors through it, so Record/Variant diagnostics show resolved type/variant/field names instead of #id fallbacks.

  • active_ctx 'static borrow: agreed this is a footgun for phase-4 callers. For this PR I documented the RAII discipline at the call site (sound only while ActiveCtxGuard is on-stack; read-and-drop within the guard scope). Narrowing to a callback-only API is a reasonable follow-up once more host transports need post-eval inspection.

— sent from quick-ant-784

@briansrls
briansrls merged commit bf32c3a into main Jun 13, 2026
12 checks passed
@briansrls
briansrls deleted the session/quick-ant-784 branch June 13, 2026 04:07
briansrls added a commit that referenced this pull request Jun 13, 2026
, merge origin/main (#4785 corpus gate + #4799 stage0 interner), rebuild gunbc, INVESTIGATE+FIX the comprep_branch_eval_by_execution regression (TRUE on main / FALSE on branch — isolate 05_eval vs claim-file cause), apply loo (#4807)

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* ci: retrigger after fold-import fix and loop witness cleanup

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: document branch infer witness compile fix (fold import removed)

Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* ci: harden sccache retry for EAGAIN under concurrent jobs

Match Resource temporarily unavailable / os error 11 in transport-fault
signature and back off before retry when runner process-table pressure
caused the initial ci_floor/ci_floor_parity/v4_lens_ci build failures
at c6045ba (run 27454120439 recovered on second attempt).

Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* WIP: §2 control-flow bodies: Branch EMIT row (ii) + round-trip (iii) + Bind/L

* fix(eval): replace invalid let-binding in eval_fold_child_edge_step

DSL does not allow `let child =` before a multiline if; extract
eval_fold_child_for_edge so callee-reference skip compiles and CI
v4 lens / emit probes can resolve 05_eval.dag again.

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: drop scope-creep from #4741 emit delta (CI retry tweak + rebase helper)

Reverts .github/ci-floor/with-sccache-retry.sh to main and removes
scripts/resolve_target_model_rebase.py — both unrelated to the §2
control-flow emit delta. Per snappy-crab-849 authorization (clean
13-file emit+eval delta; 06_translate==main, descriptor path).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* WIP: Eval-spine completion (stacks on + supersedes #4741): branch off 099d697

* WIP: Eval-spine completion (stacks on + supersedes #4741): branch off 099d697

* WIP: Eval-spine completion (stacks on + supersedes #4741): branch off 099d697

* WIP: Eval-spine completion (stacks on + supersedes #4741): branch off 099d697

* takeover(#4807): 🟡 mark pick-arm grammar + dedup effect_apply schema-valid + revert manifest self-edit

Coordinator bounded-takeover finalization of the §2 eval-spine head (parent
snappy-crab-849 authorized, two mechanical exceptions only — no logic):

1. dag.dag: add the 3-part anti-cement 🟡 mark on
   dag_grammar_pick_arm_literal_terminal (narrow approximation of
   arm=value_expression / WHY no value_expression production exists yet /
   dissolve-on: replace with the value_expression production). Grammar body
   byte-unchanged.

2. target_model.dag: delete the byte-identical DUPLICATE
   target_value_expr_effect_apply_wire_schema_valid (was at :2625 AND :2674;
   inherited from the 099d697 emit base, NOT introduced here). Restores
   main single-copy shape; addresses cursor/composer-2.5 REQUEST_CHANGES.
   Verified byte-identical (sha256 match) before deletion; surviving copy
   byte-matches origin/main; all 8 witnesses TRUE after.

3. claim_witness_corpus_ci_runner.dag: revert cool-swift's unauthorized
   manifest self-edit (comprep_eval ExpectPass -> ExpectFail{#4741}),
   restoring main-shape. Parent re-dictates the enroll-at-actual rows next.

All 8 §2 witnesses TRUE by execution against their manifest/defining entries
post-deletion (emit trio, comprep_branch_infer, bind, loop, comprep_branch_eval,
comprep_eval). SHA_F freeze held until parent's manifest dictation lands.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* takeover(#4807): flip comprep_eval ExpectFail{#4741} -> ExpectPass (parent-authorized, #4813-independent)

The corpus gate fail-closed on drift: comprep_eval_by_execution_keystone_holds
is actually TRUE at this head (#4807 delivers the #4741 eval work) but the row
still read ExpectFail{#4741} after the step-1 main-shape revert. Gate message:
"STALE MANIFEST ExpectFail got true — flip row to ExpectPass ... in the same PR".

Apply ONLY this expected-change on the existing row (parent snappy-crab-849
verbatim dictation, explicitly authorized): enroll-at-actual-value, zero count
impact, zero shard impact, #4813-independent, idempotent with the post-#4813
union. bind/loop ADD + count->27 + shard rebalance stay in the post-#4813 union.
No sign triggered (sign is step 4 at SHA_F).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
briansrls pushed a commit that referenced this pull request Jun 13, 2026
briansrls pushed a commit that referenced this pull request Jun 13, 2026
…re-measure (#4799 follow-up)

Re-measure of the v2 interpreter symbol interning landed in #4799
(ctrl#1533 phase 3). The interner deduplicates runtime identity carriers
(type/variant/field names, env binding keys) into a per-evaluation table, but
nothing counted how much allocation work that dedup avoids — the
`[interp-stats]` report (ctrl#1533 phase 0) measured collection-copy and
flatten work but not interning. Measurement-only: no interpreter semantics
change.

- `SymbolInterner` counts total `intern` calls; `stats()` returns
  `InternStats { calls, distinct, hits, heap_bytes }`. `hits = calls −
  distinct` is the number of repeat `String` allocations interning elided
  (each pre-#4799 occurrence of a name was its own owned `String`); the dedup
  factor `calls/distinct` is the before/after receipt for the carrier swap.
- `InterpContext::interner_stats_snapshot()` exposes it; `claim_batch`'s
  `print_interp_stats` prints one `[interp-stats] symbol interning receipt`
  line (single-entry mode, where the context survives to be inspected).
- Two pins in `interp_stats_test`: the table-level invariant
  (`calls == distinct + hits`) and that a real witness evaluation produces hits.

Live re-measure (GUNBC_INTERP_STATS=1 claim_batch, src/v4 witnesses):
  comprep_eval_by_execution: 14,427,120 calls / 777 distinct / 14,426,343 hits
                             (18,567x dedup; 61 KB table; 591 MB RSS)
  loop_demand_driven_eval:       14,896 calls / 414 distinct /     14,482 hits
                             (36x dedup; 33 KB table; 140 MB RSS)

Finding for the CI-latency root-cause: interning crushed the name-allocation
term, but the comprep witness still issues 14.4M `intern(&str)` calls, each
hashing the full source string to probe the index map. The allocation is gone;
the per-occurrence string-hash on the hot path is not. Caching the resolved
`Symbol` at parse/resolve time so variable references never re-hash is the next
lever (phase-4) — recorded here as the measured next step, not changed.

Test plan: cargo test -p v2-compiler-tests interp_stats (3 interner pins +
existing measurement pins pass); manual claim_batch runs above.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Jun 13, 2026
…re-measure (#4799 follow-up) (#4838)

Re-measure of the v2 interpreter symbol interning landed in #4799
(ctrl#1533 phase 3). The interner deduplicates runtime identity carriers
(type/variant/field names, env binding keys) into a per-evaluation table, but
nothing counted how much allocation work that dedup avoids — the
`[interp-stats]` report (ctrl#1533 phase 0) measured collection-copy and
flatten work but not interning. Measurement-only: no interpreter semantics
change.

- `SymbolInterner` counts total `intern` calls; `stats()` returns
  `InternStats { calls, distinct, hits, heap_bytes }`. `hits = calls −
  distinct` is the number of repeat `String` allocations interning elided
  (each pre-#4799 occurrence of a name was its own owned `String`); the dedup
  factor `calls/distinct` is the before/after receipt for the carrier swap.
- `InterpContext::interner_stats_snapshot()` exposes it; `claim_batch`'s
  `print_interp_stats` prints one `[interp-stats] symbol interning receipt`
  line (single-entry mode, where the context survives to be inspected).
- Two pins in `interp_stats_test`: the table-level invariant
  (`calls == distinct + hits`) and that a real witness evaluation produces hits.

Live re-measure (GUNBC_INTERP_STATS=1 claim_batch, src/v4 witnesses):
  comprep_eval_by_execution: 14,427,120 calls / 777 distinct / 14,426,343 hits
                             (18,567x dedup; 61 KB table; 591 MB RSS)
  loop_demand_driven_eval:       14,896 calls / 414 distinct /     14,482 hits
                             (36x dedup; 33 KB table; 140 MB RSS)

Finding for the CI-latency root-cause: interning crushed the name-allocation
term, but the comprep witness still issues 14.4M `intern(&str)` calls, each
hashing the full source string to probe the index map. The allocation is gone;
the per-occurrence string-hash on the hot path is not. Caching the resolved
`Symbol` at parse/resolve time so variable references never re-hash is the next
lever (phase-4) — recorded here as the measured next step, not changed.

Test plan: cargo test -p v2-compiler-tests interp_stats (3 interner pins +
existing measurement pins pass); manual claim_batch runs above.

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.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