Repository navigation
Fix CI-floor OOM at root: share one InternTable across modules (per-module deep-copy was O(corpus²); 14.2→5.5 GiB) - #5867
Conversation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
OOM-resolved receipt (by execution). Whole-tree resolve A/B, 1397-module dsl+src/v2 closure (width-1 = per-shard worst case); only difference is the
Load-bearing |
Unit is already a member of kernel_type_set, so the trailing intern was a no-op hit. Removing it makes seed_kernel_intern_table an exact 1:1 factoring of the 3 folds it replaced in build_type_env. Proven inert by execution: whole-tree resolve diag_fingerprint unchanged (25ab4e3f6b81f1b6), unique InternTable Rc still 1, peak VmHWM still 5509 MiB. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Thanks @claude/claude-opus-4-7 — clarifying the mechanism, since the "share one InternTable" claim isn't visible from the helper extraction alone: The sharing comes from the Measured (whole-tree resolve, 1397 modules): unique Re the — sent from silent-moth-532 |
Commit a0d12b9 captured the origin/main version of v1_compiler_infer.rs mid-A/B (baseline measurement had main's .rs checked out when the auto-committer fired), reverting the seed_kernel_intern_table mirror while 04_infer.dag kept the fix — leaving .dag/.rs inconsistent and the fix absent from what CI compiles. Restores the validated .rs from 0ce26b4 (the commit CI run 28278382320 measured OOM-fixed: 6.9 GiB VmHWM @ width=3). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…asked containment reds) shell_emit + orchestration_emit (and their stmt/word emit-tests) imported the target-AST vocab extdeps.languages.bash.program while residing in src/v2/workflow/, outside every realization-edge prefix — tripping both realization_vocab_clean_tree_holds (4 files) and medium_structure_clean_tree_holds (shell_emit's raw bash string). These reds were introduced by #5828's orchestration-bash-emit work and were never contained; they sat invisible on main because the CI floor exit-137'd (intern-table OOM, fixed by #5867) before the witnesses ran — a §5 coverage-by-illusion false-green. Per cool-ram-182's import-grounded design call (realization-vocab-guard author): these carry NO workflow-layer policy (imports are all compiler+extdeps+std), so the §3-correct fix is to RELOCATE them down into the emit edge, not roster them (roster is reserved for transports forced to reside in workflow/ by a workflow-policy import, e.g. compiler_closure_ingest_transport). Both lens edge-prefix lists already contain src/v2/compiler/05_emit, so this is pure relocation — both reds go green BY CONSTRUCTION, zero lens/roster edits. git mv, NN_-prefix strips to module name (05_eval -> v2.compiler.eval precedent): workflow/shell_emit.dag -> compiler/05_emit_shell.dag (v2.compiler.emit_shell) workflow/orchestration_emit.dag -> compiler/05_emit_orchestration.dag (v2.compiler.emit_orchestration) workflow/orchestration_stmt_emit_test.dag -> compiler/05_emit_orchestration_stmt_test.dag workflow/orchestration_word_emit_test.dag -> compiler/05_emit_orchestration_word_test.dag import-path updates only (stay in workflow/, no AST-vocab import): orchestration_emit_test, orchestration_retry_emit_test Verified by execution on a fresh build: realization_vocab_clean_tree_holds=true, medium_structure_clean_tree_holds=true; relocated + staying emit-tests still pass (byte-identical/has-teeth witnesses green). Dissolution trigger (cool-ram end-state): a hand-written shell/orchestration emitter is a §2 fork of the agnostic 06_translate grammar-inverse fold; relocation is the honest interim that places the fork INSIDE the emit edge where folding orchestration->bash into the bash grammar rows can later absorb it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The This CI run (28279132943) on the current head:
These two are inherited, pre-existing reds, proven by execution:
There's a circular dependency: the containment fix (owned separately, the violators are 4 — sent from silent-moth-532 |
…asked containment reds) (#5869) shell_emit + orchestration_emit (and their stmt/word emit-tests) imported the target-AST vocab extdeps.languages.bash.program while residing in src/v2/workflow/, outside every realization-edge prefix — tripping both realization_vocab_clean_tree_holds (4 files) and medium_structure_clean_tree_holds (shell_emit's raw bash string). These reds were introduced by #5828's orchestration-bash-emit work and were never contained; they sat invisible on main because the CI floor exit-137'd (intern-table OOM, fixed by #5867) before the witnesses ran — a §5 coverage-by-illusion false-green. Per cool-ram-182's import-grounded design call (realization-vocab-guard author): these carry NO workflow-layer policy (imports are all compiler+extdeps+std), so the §3-correct fix is to RELOCATE them down into the emit edge, not roster them (roster is reserved for transports forced to reside in workflow/ by a workflow-policy import, e.g. compiler_closure_ingest_transport). Both lens edge-prefix lists already contain src/v2/compiler/05_emit, so this is pure relocation — both reds go green BY CONSTRUCTION, zero lens/roster edits. git mv, NN_-prefix strips to module name (05_eval -> v2.compiler.eval precedent): workflow/shell_emit.dag -> compiler/05_emit_shell.dag (v2.compiler.emit_shell) workflow/orchestration_emit.dag -> compiler/05_emit_orchestration.dag (v2.compiler.emit_orchestration) workflow/orchestration_stmt_emit_test.dag -> compiler/05_emit_orchestration_stmt_test.dag workflow/orchestration_word_emit_test.dag -> compiler/05_emit_orchestration_word_test.dag import-path updates only (stay in workflow/, no AST-vocab import): orchestration_emit_test, orchestration_retry_emit_test Verified by execution on a fresh build: realization_vocab_clean_tree_holds=true, medium_structure_clean_tree_holds=true; relocated + staying emit-tests still pass (byte-identical/has-teeth witnesses green). Dissolution trigger (cool-ram end-state): a hand-written shell/orchestration emitter is a §2 fork of the agnostic 06_translate grammar-inverse fold; relocation is the honest interim that places the fork INSIDE the emit edge where folding orchestration->bash into the bash grammar rows can later absorb it. Co-authored-by: Brian Searls <briansrls@gunb.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-43.7 MiB / -11.7% whole-tree compile RSS) (#5878) Node has four Rc<Vec<Rc<Node>>> list fields (children/params/uses/properties). Every empty one was built with Rc::new(vec![]) — a fresh ~40 B heap allocation (16 B Rc control block + 24 B Vec header) even though it holds nothing. Most leaf nodes use none of the four, so each carried up to ~160 B of pure per-node overhead. Fix (same share-one-authority shape as the #5867 intern_table fix): one shared thread_local empty Rc<Vec<Rc<Node>>> + an empty_node_list() helper; repoint the 506 empty node-field constructions at it. Cloning the shared Rc is a refcount bump, not an allocation, so every empty list now aliases one heap object per thread instead of one per field per node. MEASURED (matched A/B, same base commit + same dsl/ tree, sole delta = this change; VmHWM via /proc sampler, 3 runs each, gunbc compile --source-root dsl --target rust): before: 381,938 KB avg after: 337,236 KB avg reclaim: ~44,703 KB = ~43.7 MiB (11.7%) 610 modules / 617 files / 0 diagnostics, identical both sides. Semantic no-op: touches node construction only, not typecheck. The Rust emitter is non-deterministic across runs (variant_to_enum HashMap owner-selection for variants shared across aliased coproducts — ~39 files churn between two runs of the SAME binary), so emit bit-identity is NOT a usable oracle here; correctness is proven by the floor witnesses staying green by execution. Hand-edited the stage0 .rs seed (not a regen) per established practice — the seed is hand-maintained, regen is not run by build.rs/ci.yml, and a full regen would reintroduce the emitter's nondeterministic churn. The build fail-closed caught 3 ParserParam-typed `params:` sites (Rc<Vec<Rc<ParserParam>>>, not Node) — left as Rc::new(vec![]), correct. Not bundled (verified, deliberately out of scope): - Node.ident delete: REFUTED — ident is set to Some on module/import nodes (parse.rs mod_ir.id / imp_ir.id) and read in 3 live type-lookup fast-paths (lookup_type_for, is_recursive_type_for, dag_node_surface_fingerprint). It is a live ident-keyed fast-path, not dead; deleting it is a behavior change, not a no-op. - Synthetic :0..0 span sentinel (make_span(0,0) -> shared ZERO_SPAN): same pattern, but measured ~0.58 MiB — sub-MiB hygiene, left for a follow-up. Co-authored-by: Brian Searls <briansrls@gunb.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…v1-survivable) (#5880) Author the operator-funded follow-on to the acute floor-OOM fix (#5867 shared InternTable: whole-tree resolve 14.2 -> 5.5 GiB, 61% reclaimed). This lane is REPRESENTATION minimization at the root (distinct from the ALLOCATION lane, resource-aware-scheduler.md), repointing the orphaned tidy-wren-707 lane. Operator steer: minimal representation, attack root causes as much as we can, v1 is going away. Every item is gated on one discriminator -- does the fix live in the .dag authority (survives the v2 self-host) or is it a hand-edit to the doomed v1 Rust seed (dies with v1). Root-first sequencing: 1. Emitter determinism is THE GATE for Lever B -- points at PR #5879 (stern-fox-585) as the single authority for the gate's status/mechanism; this plan only sequences on it. 2. Lever C (stream/evict) -- biggest mover, no emitter dependency; one batching-and-eviction model shared with the prune-resolve/affected_set lane. 3. Lever B (variant-Node minimal representation) -- after the gate, modeled in std/ and emitted (so it regenerates, not hand-edited into the seed). 4. func_env.sigs single-authority -- resolve each sig once, share the Rc; hundreds-of-MiB (payloads already Rc-shared, established by code read). 5. Cheap v1-seed hygiene -- bank-if-cheap, NOT a pillar (dies with v1); Node.ident is NOT dead (execution-refuted a 0%-used reflection claim). Plumbing: registered in plan_registry_batch_g (code-graph inbound link); ROADMAP link line (doc-graph inbound link, one short line); docs/plans md is a generated projection (regenerated via main_wet, drift-gated). Gates verified green by execution: no-orphan-docs, no-dangling-links, plan dissolution+title. Co-authored-by: Brian Searls <briansrls@gunb.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…les (plan item 4) Each importing module was re-materializing its transitive-closure signatures: merge_scope_from_imports converted ResolvedFuncSig -> DeclaredFuncSig (fresh allocation per sig), then resolve_func_sigs called collect_parent_resolved_sigs which called declared_to_resolved to convert back (another fresh allocation). Net: two fresh struct allocations per imported sig per module. Fix: merge_scope_from_imports now accumulates imported_sigs as Map<String, ResolvedFuncSig> directly via rc_map_merge over the parent's func_env.signatures (Rc clone — O(1) per sig, no struct allocation). resolve_func_sigs accepts parent_sigs directly, skipping collect_parent_resolved_sigs. InferScopeComponents.func_sigs (DeclaredFuncSig) replaced by imported_sigs (ResolvedFuncSig) — the conversion round-trip is eliminated. Same single-authority move as #5867 (shared InternTable). Payoff: hundreds of MiB — each of the ~608 modules no longer allocates fresh ResolvedFuncSig structs for every transitively-imported function signature. Changes: 04_infer.dag (.dag authority) + 04_sigs.dag + hand-edited .rs seed (v1_compiler_infer.rs, v1_compiler_infer_sigs.rs). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… 4): resolve each fn sig ONCE + share Rc / parent_index lookup instead of merge-and-re-resolve + intern name keys. Resolution-strategy ROOT fix (same class as #5867), ~hundreds MiB. Measure-first, green-by-exec, hand-edit .rs seed (#5893) * WIP: func_env.sigs single-authority (representation-minimization plan item 4) * func_env.sigs single-authority: share Rc<ResolvedFuncSig> across modules (plan item 4) Each importing module was re-materializing its transitive-closure signatures: merge_scope_from_imports converted ResolvedFuncSig -> DeclaredFuncSig (fresh allocation per sig), then resolve_func_sigs called collect_parent_resolved_sigs which called declared_to_resolved to convert back (another fresh allocation). Net: two fresh struct allocations per imported sig per module. Fix: merge_scope_from_imports now accumulates imported_sigs as Map<String, ResolvedFuncSig> directly via rc_map_merge over the parent's func_env.signatures (Rc clone — O(1) per sig, no struct allocation). resolve_func_sigs accepts parent_sigs directly, skipping collect_parent_resolved_sigs. InferScopeComponents.func_sigs (DeclaredFuncSig) replaced by imported_sigs (ResolvedFuncSig) — the conversion round-trip is eliminated. Same single-authority move as #5867 (shared InternTable). Payoff: hundreds of MiB — each of the ~608 modules no longer allocates fresh ResolvedFuncSig structs for every transitively-imported function signature. Changes: 04_infer.dag (.dag authority) + 04_sigs.dag + hand-edited .rs seed (v1_compiler_infer.rs, v1_compiler_infer_sigs.rs). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Address review: delete dead collect_parent_resolved_sigs + restore shadow filter Two fixes from claude-opus review: 1. collect_parent_resolved_sigs is now unreferenced (its only call in resolve_func_sigs was replaced by parent_sigs parameter). Delete it from 04_sigs.dag and v1_compiler_infer_sigs.rs. 2. The original collect_parent_resolved_sigs filtered out parent sigs whose names collide with local functions, preserving correct topo- ordering when a local fn shadows an imported one. The new parent_sigs parameter did not apply this filter. Restore the local-shadow filter inline in resolve_func_sigs: parent_sigs_filtered excludes names in local_func_set before seeding topo_resolve_loop, exactly matching the original behavior. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansrls@gunb.ai> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Brian Searls <11205878+briansrls@users.noreply.github.com>
One new registry intrinsic trace_mark(label) -> Unit (the record_source_chars_index_lookup precedent: registry row in 04_method.dag, realization in runtime_rust.dag -> v1_rt, interpreter arm for totality). Nine marks at the known segment boundaries of the compile pipeline (frontend/normalize/reconcile/analyses/emit begin+done, dag collect/serialize), so every run log carries a natural Gantt: [gantt] compile.reconcile.done t_ms=... rss_mib=... Consecutive marks define the segments; rss_mib rides along for the memory curve. Motivation: the whole-tree compile runs >60 min single-threaded with zero output after "resolved N sources" — CI runs die inside it blind (operator request 2026-07-05: checkpoints + a general logging system). Marked bridge, interim by design: dissolves into the v2 per-RealizedStep CostAccount (std.realization_measurement) when the realization-measurement carrier is inhabited. Authority edits (.dag) land with hand-synced generated seed (.rs) per the #5867 precedent — regen is currently blocked on main (#6291); re-verify at the next regen window. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Regen broken (#6291); .dag prepass without hand-synced .rs is parallel representation. Keep only ancestry-cache sharing + dissolution trigger. Co-authored-by: Cursor <cursoragent@cursor.com>
#6298) * WIP: ci timeout investigation * trace_mark: stage-boundary gantt marks through the v1 compile pipeline One new registry intrinsic trace_mark(label) -> Unit (the record_source_chars_index_lookup precedent: registry row in 04_method.dag, realization in runtime_rust.dag -> v1_rt, interpreter arm for totality). Nine marks at the known segment boundaries of the compile pipeline (frontend/normalize/reconcile/analyses/emit begin+done, dag collect/serialize), so every run log carries a natural Gantt: [gantt] compile.reconcile.done t_ms=... rss_mib=... Consecutive marks define the segments; rss_mib rides along for the memory curve. Motivation: the whole-tree compile runs >60 min single-threaded with zero output after "resolved N sources" — CI runs die inside it blind (operator request 2026-07-05: checkpoints + a general logging system). Marked bridge, interim by design: dissolves into the v2 per-RealizedStep CostAccount (std.realization_measurement) when the realization-measurement carrier is inhabited. Authority edits (.dag) land with hand-synced generated seed (.rs) per the #5867 precedent — regen is currently blocked on main (#6291); re-verify at the next regen window. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * WIP: ci timeout investigation * WIP: ci timeout investigation --------- Co-authored-by: Brian Searls <briansrls@gunb.ai> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* build_type_env: borrow parent cache str_bindings on single-import chains Replace map_merge(parent.ancestry_str_bindings, parent.str_bindings) with parent.type_env_cache.str_bindings (Rc share). Multi-import path unchanged. Co-authored-by: Cursor <cursoragent@cursor.com> * fix: pull unsynced SymbolIndex prepass from ancestry PR (#5867) Regen broken (#6291); .dag prepass without hand-synced .rs is parallel representation. Keep only ancestry-cache sharing + dissolution trigger. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com>
…ges (byte-identical, width=1) (#6306) * WIP: ci timeout investigation * trace_mark: stage-boundary gantt marks through the v1 compile pipeline One new registry intrinsic trace_mark(label) -> Unit (the record_source_chars_index_lookup precedent: registry row in 04_method.dag, realization in runtime_rust.dag -> v1_rt, interpreter arm for totality). Nine marks at the known segment boundaries of the compile pipeline (frontend/normalize/reconcile/analyses/emit begin+done, dag collect/serialize), so every run log carries a natural Gantt: [gantt] compile.reconcile.done t_ms=... rss_mib=... Consecutive marks define the segments; rss_mib rides along for the memory curve. Motivation: the whole-tree compile runs >60 min single-threaded with zero output after "resolved N sources" — CI runs die inside it blind (operator request 2026-07-05: checkpoints + a general logging system). Marked bridge, interim by design: dissolves into the v2 per-RealizedStep CostAccount (std.realization_measurement) when the realization-measurement carrier is inhabited. Authority edits (.dag) land with hand-synced generated seed (.rs) per the #5867 precedent — regen is currently blocked on main (#6291); re-verify at the next regen window. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * WIP: ci timeout investigation * WIP: ci timeout investigation * WIP: ci timeout investigation * WIP: ci timeout investigation * WIP: ci timeout investigation * WIP: ci timeout investigation --------- Co-authored-by: Brian Searls <briansrls@gunb.ai> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…ges (byte-identical, width=1) (#6306) * WIP: ci timeout investigation * trace_mark: stage-boundary gantt marks through the v1 compile pipeline One new registry intrinsic trace_mark(label) -> Unit (the record_source_chars_index_lookup precedent: registry row in 04_method.dag, realization in runtime_rust.dag -> v1_rt, interpreter arm for totality). Nine marks at the known segment boundaries of the compile pipeline (frontend/normalize/reconcile/analyses/emit begin+done, dag collect/serialize), so every run log carries a natural Gantt: [gantt] compile.reconcile.done t_ms=... rss_mib=... Consecutive marks define the segments; rss_mib rides along for the memory curve. Motivation: the whole-tree compile runs >60 min single-threaded with zero output after "resolved N sources" — CI runs die inside it blind (operator request 2026-07-05: checkpoints + a general logging system). Marked bridge, interim by design: dissolves into the v2 per-RealizedStep CostAccount (std.realization_measurement) when the realization-measurement carrier is inhabited. Authority edits (.dag) land with hand-synced generated seed (.rs) per the #5867 precedent — regen is currently blocked on main (#6291); re-verify at the next regen window. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * WIP: ci timeout investigation * WIP: ci timeout investigation * WIP: ci timeout investigation * WIP: ci timeout investigation * WIP: ci timeout investigation * WIP: ci timeout investigation --------- Co-authored-by: Brian Searls <briansrls@gunb.ai> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* WIP: dedup dag.dag mvp1 fn families into parameterized cores * WIP: dedup dag.dag mvp1 fn families into parameterized cores * Dedup dag.dag mvp1 fn families into parameterized cores. Collapse five repeated stamping clusters (arrow-with-body nodes, target-model bundles, grammar token sequences, grammar-relation rows, statement prefix tokens) into shared parameterized cores with thin per-family wrappers, preserving explicit control-fixture operands at instance sites. Co-authored-by: Cursor <cursoragent@cursor.com> * Demand-driven realize: typecheck as memoized recursion over import edges (byte-identical, width=1) (#6306) * WIP: ci timeout investigation * trace_mark: stage-boundary gantt marks through the v1 compile pipeline One new registry intrinsic trace_mark(label) -> Unit (the record_source_chars_index_lookup precedent: registry row in 04_method.dag, realization in runtime_rust.dag -> v1_rt, interpreter arm for totality). Nine marks at the known segment boundaries of the compile pipeline (frontend/normalize/reconcile/analyses/emit begin+done, dag collect/serialize), so every run log carries a natural Gantt: [gantt] compile.reconcile.done t_ms=... rss_mib=... Consecutive marks define the segments; rss_mib rides along for the memory curve. Motivation: the whole-tree compile runs >60 min single-threaded with zero output after "resolved N sources" — CI runs die inside it blind (operator request 2026-07-05: checkpoints + a general logging system). Marked bridge, interim by design: dissolves into the v2 per-RealizedStep CostAccount (std.realization_measurement) when the realization-measurement carrier is inhabited. Authority edits (.dag) land with hand-synced generated seed (.rs) per the #5867 precedent — regen is currently blocked on main (#6291); re-verify at the next regen window. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * WIP: ci timeout investigation * WIP: ci timeout investigation * WIP: ci timeout investigation * WIP: ci timeout investigation * WIP: ci timeout investigation * WIP: ci timeout investigation --------- Co-authored-by: Brian Searls <briansrls@gunb.ai> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * Delete flaky test disposition_kernel_aligns_on_discriminator_fixture (#6324) This sole test in mod floor_disposition_kernel_alignment (cli_run.rs) ran the floor-disposition analysis, which typechecks the gunbc module closure live — and that hits the #6239 compile-wall: per-module typecheck attribution measured gunbc.ci_deploy_access at 416s (7 min) for a single module, with the test spending >9 min and never finishing. It was the sole reason `cargo test --workspace` appeared to hang (deterministic, single-threaded reproducible), compounded by its std::env::set_current_dir cwd-mutation racing under parallel execution (#5971 class). No value and slated for deletion (operator, 2026-07-06). Floor-disposition coverage is exercised in the floor; the real fix is the compile-wall itself (owned elsewhere). Co-authored-by: Brian Searls <briansrls@gunb.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansrls@gunb.ai> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: gunbai-bot[bot] <289086189+gunbai-bot[bot]@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Summary
Fixes the CI-floor OOM (
claim_executorbatch-2 exit-137 at the 8 GiB runner cap) at its root, and does so as a §5 fail-closed hardening: it makes explicit a cross-module id-stability dependency thatmerge_envsalready silently assumed.The per-module
type_env.intern_tablewas deep-copied once per module, so an N-module resolve held N identical copies of the whole-corpus string→id table — O(corpus²) retention, the dominant per-shard RSS.merge_envsalready doesfirst_env.intern_table.clone()while keeping other modules' bindings (keyed by their tables' ids), so the system already depended on every per-module table producing the same string→id mapping. This PR makes that one shared table by construction — the duplicate state becomes unwritable, not validated after.Root cause (by execution — throwaway probe, reverted)
A shared-vs-distinct heap walk over the resolved graph showed:
ResolvedFuncSig,variant_provenance,TypeBinding) are 99%Rc-shared into the source AST — only 1013 payload-only new nodes (3 MiB). Payload interning (orphaned Resolved-graph minimal representation: end per-module type_env/func_env closure duplication (73% of a resolved graph). Durable §2/§3 fix = single-authority envs (de-merge in load-bearing 04_infer build_type_env, model-first); interim = canonical-pool-hash cache interning. Authority: docs/plans/resol #5834) reclaims ~0; that thesis is refuted. (The large "serialized" figures were serdeRc<Node>re-expansion, not RAM.)type_env.intern_table: each module holds its ownInternTableRc carrying the identical whole-corpus string set. This is the 78% an earlierTypeEnvwalk missed (it never recursed intointern_table).Fix (single-authority, §2/§3)
intern()is idempotent (a hit returns the sameRc, no growth). Pre-seeding the shared table with the kernel string set makesbuild_type_env's per-module interning pure lookups → every module'sTypeEnv.intern_tableis the one sharedRc. Addedseed_kernel_intern_tabledefined once and called from bothtypecheck()andbuild_type_env(the kernel set is now single-authority; removed the duplicated inline string-list).Edited the
.dagauthority (src/v1/04_infer.dag) and hand-synced the generated.rsmirror (v1_compiler_infer.rs) — no regen (the mirror is not a clean fixpoint; perregen_verify_gate.daga full regen emits a non-building seed and clobbers hand-resolved drift).Receipts (by execution)
Whole-tree resolve, 1397-module dsl+src/v2 closure (width-1 = per-shard worst case); baseline =
origin/mainintern, fixed = this branch, only difference = the fix:InternTableRc25ab4e3f6b81f1b625ab4e3f6b81f1b6InternTableRc collapse.string→i64index-maps byte-identical (mapping-identity, not just set-identity);internassigns ids monotonically in first-seen source order ⇒ order-stable; no serialize/deserialize id boundary (resolve cache off, Revert resolve cache to opt-in (#5789 always-on default OOMs the CI floor) #5855).self_resolve_all_modules/self_compile_all_modulespass.Test plan
cargo fmt -p v1-compiler --check: cleancargo build -p v1-compiler --release: cleancargo test -p v1-compiler --release self_resolve_all_modules/self_compile_all_modules: pass (exit 0)🤖 Generated with Claude Code