Skip to content

feat(infer): per-module resolve memo (Option B) — within-module type-grounding memo - #6779

Merged
briansrls merged 6 commits into
session/still-owl-689from
session/census-pre-resolve
Jul 17, 2026
Merged

briansrls merged 6 commits into
session/still-owl-689from
session/census-pre-resolve

Conversation

@briansrls

@briansrls briansrls commented Jul 16, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Transient per-module memo at resolve_node_bounded grain (Option B). Replaces dead Option-2 persistent census pre-resolve (OOM at corpus scale).

Measured main-tree benefit (clever-seal whole-tree RNB attribution, 1090 modules)

  • Typecheck fold 345.7s; resolve_node_bounded 43.1s = 12.5% of fold (733k calls)
  • Main is not resolve-bound in aggregate — heterogeneous by module
  • Primary customer: host_effect_realize — 70% rnb (20.0s of 28.7s module time, 108,941 calls)
  • Other modules low: ci_spec 1.2%, fleet_converge_emit 0.1%, srv3 receipt 0.7%
  • Honest standalone case: ~up to ~40s (~12%) typecheck win, concentrated in host_effect_realize, plus strip-lane bounded-call hygiene

Not the #6640 unblocker (root: peel_alias_once_for_field_access infinite loop — clever-seal peel guard). Not an 82%/434s main-wall claim.

Test plan

  • cargo test -p v1-compiler-tests per_module_resolve_memo_equivalence
  • Operator release (b): memo verified; peel loop diagnosed as root cause

Head

session/census-pre-resolve @ 9215b0a712 (rebased on still-owl-689)

@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review July 16, 2026 23:20
@gunbai-bot
gunbai-bot Bot marked this pull request as draft July 16, 2026 23:23
@gunbai-bot
gunbai-bot Bot changed the base branch from main to session/still-owl-689 July 16, 2026 23:23
@gunbai-bot gunbai-bot Bot changed the title Shared-layer cost fix for global_bare variant locals (04_infer.dag) — collapse M×K to M+K, on top of the de-fork. Base: branch fix/global-bare-shared-layer (PR #6762), which already has the de-fork (Q2 total). DO NOT redo the de-fork. THE BUG: merge_global_bare_variant_locals in src/v1/04_infer.dag census pre-resolve (Option 2): ground global-bare census once at corpus level — fixes the O(K^2) resolve_node_bounded re-grounding hang Jul 16, 2026
@gunbai-bot
gunbai-bot Bot force-pushed the session/census-pre-resolve branch 3 times, most recently from 51a5c84 to 84471e3 Compare July 17, 2026 00:57
@gunbai-bot gunbai-bot Bot changed the title census pre-resolve (Option 2): ground global-bare census once at corpus level — fixes the O(K^2) resolve_node_bounded re-grounding hang feat(infer): per-module resolve memo (Option B) — within-module type-grounding memo Jul 17, 2026
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review July 17, 2026 01:10
@cursor

cursor Bot commented Jul 17, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@gunbai-bot
gunbai-bot Bot force-pushed the session/census-pre-resolve branch from e7e22b9 to aafefa0 Compare July 17, 2026 01:15
@gunbai-bot

gunbai-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Addressed review 39138 (env-var test flakiness):

Finding valid. set_var/remove_var on GUNBC_PER_MODULE_RESOLVE_MEMO was process-global and unsafe under parallel cargo test.

Fix (aafefa03d8): thread-local PerModuleResolveMemoEnabledOverride + PerModuleResolveMemoEnabledGuard (#[doc(hidden)]). Receipt tests use PerModuleResolveMemoEnabledGuard::force(false) for the cold path; no env mutation. Production still honors GUNBC_PER_MODULE_RESOLVE_MEMO when override is None.

Style nit (generic memo helper): agreed as follow-up if seed lingers; not blocking given explicit DISSOLVE-ON to v2.std.materialize.

— sent from loyal-crab-450

@gunbai-bot

gunbai-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review 39142 (addressed in latest push):

  1. module_name excluded from BoundedMemoKey — documented invariant at BoundedMemoKey: within one install window every resolve_node_bounded call uses the same enclosing resolved_module_name; module_name labels diagnostics only and does not change the grounded resolved form for identical (env, node, depth, masked).

  2. Panic-safe scope — per_module_resolve_memo_install now flushes+log any leaked scope instead of assert!; PerModuleResolveMemoScopeGuard wraps infer+pop in typecheck_module and flushes on Drop.

Review 39143 — no findings; thanks for APPROVE.

— sent from loyal-crab-450

@gunbai-bot
gunbai-bot Bot force-pushed the session/census-pre-resolve branch from de0fac6 to 3431023 Compare July 17, 2026 01:31
@gunbai-bot

gunbai-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Release (b) verdict (operator, quiet-gull): memo layer is correct — content-key captures all distinct work (~1787 misses, then ~100% hits); re-entrancy fix holds. Does not unblock #6640: whole-tree still stalls in test.claim.bmc_bootstrap_provision_witness due to caller-level superlinear resolve_node invocation (expand_type_for_field_access → peel_alias_once_for_field_access under infer_expr), not per-call resolution cost.

Hold: do not merge as the #6640 fix. Standalone landing TBD after clever-seal re-prices main-434s gate. Receipt (a) + composite test retained.

— sent from loyal-crab-450

@gunbai-bot
gunbai-bot Bot marked this pull request as draft July 17, 2026 01:40
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review July 17, 2026 01:43
Brian Searls and others added 6 commits July 17, 2026 01:59
Within-module transient memo at resolve_node_bounded grain catches
infer_items and populate_output_provenance re-grounding without the
Option-2 persistent census roots that OOM'd. Content-identity keys
(dag_node_surface_fingerprint + depth + masked); scrutinee parallel
memo on resolve_scrutinee_type_node entry. Freed at module exit.
Receipt (a): per_module_resolve_memo_equivalence_test.

Co-authored-by: Cursor <cursoragent@cursor.com>
Makes release (b) diagnostic: bypass counts env-ptr guardrail skips
separately from fingerprint misses. Restores ptr->fp hint cache
(amortize hashing; content String remains map equality key).

Co-authored-by: Cursor <cursoragent@cursor.com>
Retain (Rc<Node>, fp) in node_surface_fp_cache so transient wrapper
addrs cannot be reused with stale fingerprints during the module scope.

Co-authored-by: Cursor <cursoragent@cursor.com>
Probe-then-compute-then-store pattern lets resolve_node_bounded recurse
through the memo wrapper without panicking. Strengthen receipt (a) with
composite Optional<ProbeCurrency> resolve under installed memo scope.

Co-authored-by: Cursor <cursoragent@cursor.com>
Replace process-global GUNBC_PER_MODULE_RESOLVE_MEMO set_var/remove_var
with PerModuleResolveMemoEnabledGuard so parallel cargo test cannot flake
the byte-identity oracle.

Co-authored-by: Cursor <cursoragent@cursor.com>
Review 39142: replace nested-install assert with leaked-scope flush+log;
add PerModuleResolveMemoScopeGuard (Drop flushes) around infer+pop.
Document why module_name is excluded from BoundedMemoKey.

Co-authored-by: Cursor <cursoragent@cursor.com>
@gunbai-bot
gunbai-bot Bot force-pushed the session/census-pre-resolve branch from 3431023 to 9215b0a Compare July 17, 2026 01:59
@gunbai-bot

gunbai-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review 39147 — dashboard relay included only (not posted — add --post to comment on the PR); full stdout body was not available here.

Verified locally against likely scope concern: branch was behind still-owl-689 (#6780 fleet_intent memory ground), so the PR diff accidentally reverted unrelated dag/gunbc/fleet_intent.dag changes. Fixed: rebased onto current origin/session/still-owl-689; PR diff is now 5 files (memo + receipt tests only). Receipt (a) still green.

New HEAD: $(cd /home/briansrls/.worktrees/loyal-crab-450 && git rev-parse --short HEAD)

If review 39147 had additional findings beyond scope, please re-post with --post so they land on-thread.

— sent from loyal-crab-450

@gunbai-bot

gunbai-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Correction: rebased HEAD is 9215b0a (prior comment had unexpanded shell fragment). — sent from loyal-crab-450

@gunbai-bot

gunbai-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review 39148 — APPROVE received; mild concern addressed (no code change):

Scope-extended env / bypass inertness: Within the install window, infer_scope.type_env is env.clone() (same Rc ptr as PerModuleResolveMemoScopeGuard::install(&env)), and peel_alias_once_for_field_access / resolve_node paths under infer_items+populate_output_provenance thread that same scope.type_env — not fresh TypeEnv allocations. Env-ptr bypass is for genuine sub-env divergence, not normal inference.

Whole-tree telemetry (operator release b on witness module): ~1787 bounded misses then hits climb linearly with ~100% hit rate (misses frozen); bypass did not dominate. Memo is active on the real hot path for that module — the remaining stall is caller-level superlinear resolve_node invocation count (documented on-thread), not memo inertness.

Will watch [resolve-memo-mod] bypass counters on clever-seal's main-434s re-price; escalation if bypass dominates is env-identity in key (already designed).

— sent from loyal-crab-450

@gunbai-bot
gunbai-bot Bot marked this pull request as draft July 17, 2026 02:17
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review July 17, 2026 02:23
@briansrls
briansrls merged commit 93a61d4 into session/still-owl-689 Jul 17, 2026
@briansrls
briansrls deleted the session/census-pre-resolve branch July 17, 2026 10:16
briansrls added a commit that referenced this pull request Jul 17, 2026
Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls added a commit that referenced this pull request Jul 17, 2026
…ecursive scrutinees

The per-module resolve memo (#6779) had two grains sharing one fp cache: a
bounded memo (resolve_node_bounded — its main within-module speedup claim) and
a scrutinee memo on resolve_scrutinee_type_node keyed by a FULL-subtree surface
fingerprint. On a self-recursive scrutinee (e.g. MarkupNode reached via
field_summary_for_type recursion) every expansion depth yields a DISTINCT
fingerprint key, so the scrutinee grain NEVER hits yet pins every intermediate
expanded subtree — measured >33GB / OOM on a 6-module closure and the whole-tree
CI floor (the #6640 integration branch's 56m OOM-kill).

Its dedup benefit cannot materialize on exactly the recursive case that makes it
expensive, so it is pure liability. Removed. The bounded grain is unaffected and
keeps #6779's speedup.

Verified: whole-tree compile-clean now completes bounded (~1.1GB RSS, ~24s) where
it previously OOM'd; per_module_resolve_memo_equivalence_test still green (3/3);
workspace builds clean. Residue count unchanged (~1448 — the namespace-migration
G1/strip residue, now finally visible because the tree completes).

Unblocks #6640 (namespace integration) and #6809 (census consolidation).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Jul 17, 2026
…ecursive scrutinees

The per-module resolve memo (#6779) had two grains sharing one fp cache: a
bounded memo (resolve_node_bounded — its main within-module speedup claim) and
a scrutinee memo on resolve_scrutinee_type_node keyed by a FULL-subtree surface
fingerprint. On a self-recursive scrutinee (e.g. MarkupNode reached via
field_summary_for_type recursion) every expansion depth yields a DISTINCT
fingerprint key, so the scrutinee grain NEVER hits yet pins every intermediate
expanded subtree — measured >33GB / OOM on a 6-module closure and the whole-tree
CI floor (the #6640 integration branch's 56m OOM-kill).

Its dedup benefit cannot materialize on exactly the recursive case that makes it
expensive, so it is pure liability. Removed. The bounded grain is unaffected and
keeps #6779's speedup.

Verified: whole-tree compile-clean now completes bounded (~1.1GB RSS, ~24s) where
it previously OOM'd; per_module_resolve_memo_equivalence_test still green (3/3);
workspace builds clean. Residue count unchanged (~1448 — the namespace-migration
G1/strip residue, now finally visible because the tree completes).

Unblocks #6640 (namespace integration) and #6809 (census consolidation).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Jul 17, 2026
…ecursive scrutinees

The per-module resolve memo (#6779) had two grains sharing one fp cache: a
bounded memo (resolve_node_bounded — its main within-module speedup claim) and
a scrutinee memo on resolve_scrutinee_type_node keyed by a FULL-subtree surface
fingerprint. On a self-recursive scrutinee (e.g. MarkupNode reached via
field_summary_for_type recursion) every expansion depth yields a DISTINCT
fingerprint key, so the scrutinee grain NEVER hits yet pins every intermediate
expanded subtree — measured >33GB / OOM on a 6-module closure and the whole-tree
CI floor (the #6640 integration branch's 56m OOM-kill).

Its dedup benefit cannot materialize on exactly the recursive case that makes it
expensive, so it is pure liability. Removed. The bounded grain is unaffected and
keeps #6779's speedup.

Verified: whole-tree compile-clean now completes bounded (~1.1GB RSS, ~24s) where
it previously OOM'd; per_module_resolve_memo_equivalence_test still green (3/3);
workspace builds clean. Residue count unchanged (~1448 — the namespace-migration
G1/strip residue, now finally visible because the tree completes).

Unblocks #6640 (namespace integration) and #6809 (census consolidation).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls added a commit that referenced this pull request Jul 17, 2026
…grounding memo (#6779)

* feat(infer): per-module resolve memo (Option B) on still-owl-689

Within-module transient memo at resolve_node_bounded grain catches
infer_items and populate_output_provenance re-grounding without the
Option-2 persistent census roots that OOM'd. Content-identity keys
(dag_node_surface_fingerprint + depth + masked); scrutinee parallel
memo on resolve_scrutinee_type_node entry. Freed at module exit.
Receipt (a): per_module_resolve_memo_equivalence_test.

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

* feat(infer): split resolve-memo counters into hit/miss/bypass

Makes release (b) diagnostic: bypass counts env-ptr guardrail skips
separately from fingerprint misses. Restores ptr->fp hint cache
(amortize hashing; content String remains map equality key).

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

* fix(infer): pin Rc in ptr->fp hint cache (ABA-safe)

Retain (Rc<Node>, fp) in node_surface_fp_cache so transient wrapper
addrs cannot be reused with stale fingerprints during the module scope.

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

* fix(infer): release RefCell borrow before memo compute (re-entrancy)

Probe-then-compute-then-store pattern lets resolve_node_bounded recurse
through the memo wrapper without panicking. Strengthen receipt (a) with
composite Optional<ProbeCurrency> resolve under installed memo scope.

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

* test(infer): thread-local memo toggle for receipt tests

Replace process-global GUNBC_PER_MODULE_RESOLVE_MEMO set_var/remove_var
with PerModuleResolveMemoEnabledGuard so parallel cargo test cannot flake
the byte-identity oracle.

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

* fix(infer): panic-safe memo scope + module_name key invariant note

Review 39142: replace nested-install assert with leaked-scope flush+log;
add PerModuleResolveMemoScopeGuard (Drop flushes) around infer+pop.
Document why module_name is excluded from BoundedMemoKey.

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

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls added a commit that referenced this pull request Jul 17, 2026
Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls added a commit that referenced this pull request Jul 17, 2026
…ecursive scrutinees

The per-module resolve memo (#6779) had two grains sharing one fp cache: a
bounded memo (resolve_node_bounded — its main within-module speedup claim) and
a scrutinee memo on resolve_scrutinee_type_node keyed by a FULL-subtree surface
fingerprint. On a self-recursive scrutinee (e.g. MarkupNode reached via
field_summary_for_type recursion) every expansion depth yields a DISTINCT
fingerprint key, so the scrutinee grain NEVER hits yet pins every intermediate
expanded subtree — measured >33GB / OOM on a 6-module closure and the whole-tree
CI floor (the #6640 integration branch's 56m OOM-kill).

Its dedup benefit cannot materialize on exactly the recursive case that makes it
expensive, so it is pure liability. Removed. The bounded grain is unaffected and
keeps #6779's speedup.

Verified: whole-tree compile-clean now completes bounded (~1.1GB RSS, ~24s) where
it previously OOM'd; per_module_resolve_memo_equivalence_test still green (3/3);
workspace builds clean. Residue count unchanged (~1448 — the namespace-migration
G1/strip residue, now finally visible because the tree completes).

Unblocks #6640 (namespace integration) and #6809 (census consolidation).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls added a commit that referenced this pull request Jul 17, 2026
…grounding memo (#6779)

* feat(infer): per-module resolve memo (Option B) on still-owl-689

Within-module transient memo at resolve_node_bounded grain catches
infer_items and populate_output_provenance re-grounding without the
Option-2 persistent census roots that OOM'd. Content-identity keys
(dag_node_surface_fingerprint + depth + masked); scrutinee parallel
memo on resolve_scrutinee_type_node entry. Freed at module exit.
Receipt (a): per_module_resolve_memo_equivalence_test.

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

* feat(infer): split resolve-memo counters into hit/miss/bypass

Makes release (b) diagnostic: bypass counts env-ptr guardrail skips
separately from fingerprint misses. Restores ptr->fp hint cache
(amortize hashing; content String remains map equality key).

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

* fix(infer): pin Rc in ptr->fp hint cache (ABA-safe)

Retain (Rc<Node>, fp) in node_surface_fp_cache so transient wrapper
addrs cannot be reused with stale fingerprints during the module scope.

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

* fix(infer): release RefCell borrow before memo compute (re-entrancy)

Probe-then-compute-then-store pattern lets resolve_node_bounded recurse
through the memo wrapper without panicking. Strengthen receipt (a) with
composite Optional<ProbeCurrency> resolve under installed memo scope.

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

* test(infer): thread-local memo toggle for receipt tests

Replace process-global GUNBC_PER_MODULE_RESOLVE_MEMO set_var/remove_var
with PerModuleResolveMemoEnabledGuard so parallel cargo test cannot flake
the byte-identity oracle.

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

* fix(infer): panic-safe memo scope + module_name key invariant note

Review 39142: replace nested-install assert with leaked-scope flush+log;
add PerModuleResolveMemoScopeGuard (Drop flushes) around infer+pop.
Document why module_name is excluded from BoundedMemoKey.

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

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls added a commit that referenced this pull request Jul 17, 2026
Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls added a commit that referenced this pull request Jul 17, 2026
…ecursive scrutinees

The per-module resolve memo (#6779) had two grains sharing one fp cache: a
bounded memo (resolve_node_bounded — its main within-module speedup claim) and
a scrutinee memo on resolve_scrutinee_type_node keyed by a FULL-subtree surface
fingerprint. On a self-recursive scrutinee (e.g. MarkupNode reached via
field_summary_for_type recursion) every expansion depth yields a DISTINCT
fingerprint key, so the scrutinee grain NEVER hits yet pins every intermediate
expanded subtree — measured >33GB / OOM on a 6-module closure and the whole-tree
CI floor (the #6640 integration branch's 56m OOM-kill).

Its dedup benefit cannot materialize on exactly the recursive case that makes it
expensive, so it is pure liability. Removed. The bounded grain is unaffected and
keeps #6779's speedup.

Verified: whole-tree compile-clean now completes bounded (~1.1GB RSS, ~24s) where
it previously OOM'd; per_module_resolve_memo_equivalence_test still green (3/3);
workspace builds clean. Residue count unchanged (~1448 — the namespace-migration
G1/strip residue, now finally visible because the tree completes).

Unblocks #6640 (namespace integration) and #6809 (census consolidation).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls added a commit that referenced this pull request Jul 17, 2026
…grounding memo (#6779)

* feat(infer): per-module resolve memo (Option B) on still-owl-689

Within-module transient memo at resolve_node_bounded grain catches
infer_items and populate_output_provenance re-grounding without the
Option-2 persistent census roots that OOM'd. Content-identity keys
(dag_node_surface_fingerprint + depth + masked); scrutinee parallel
memo on resolve_scrutinee_type_node entry. Freed at module exit.
Receipt (a): per_module_resolve_memo_equivalence_test.

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

* feat(infer): split resolve-memo counters into hit/miss/bypass

Makes release (b) diagnostic: bypass counts env-ptr guardrail skips
separately from fingerprint misses. Restores ptr->fp hint cache
(amortize hashing; content String remains map equality key).

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

* fix(infer): pin Rc in ptr->fp hint cache (ABA-safe)

Retain (Rc<Node>, fp) in node_surface_fp_cache so transient wrapper
addrs cannot be reused with stale fingerprints during the module scope.

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

* fix(infer): release RefCell borrow before memo compute (re-entrancy)

Probe-then-compute-then-store pattern lets resolve_node_bounded recurse
through the memo wrapper without panicking. Strengthen receipt (a) with
composite Optional<ProbeCurrency> resolve under installed memo scope.

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

* test(infer): thread-local memo toggle for receipt tests

Replace process-global GUNBC_PER_MODULE_RESOLVE_MEMO set_var/remove_var
with PerModuleResolveMemoEnabledGuard so parallel cargo test cannot flake
the byte-identity oracle.

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

* fix(infer): panic-safe memo scope + module_name key invariant note

Review 39142: replace nested-install assert with leaked-scope flush+log;
add PerModuleResolveMemoScopeGuard (Drop flushes) around infer+pop.
Document why module_name is excluded from BoundedMemoKey.

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

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls added a commit that referenced this pull request Jul 17, 2026
Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls added a commit that referenced this pull request Jul 17, 2026
…ecursive scrutinees

The per-module resolve memo (#6779) had two grains sharing one fp cache: a
bounded memo (resolve_node_bounded — its main within-module speedup claim) and
a scrutinee memo on resolve_scrutinee_type_node keyed by a FULL-subtree surface
fingerprint. On a self-recursive scrutinee (e.g. MarkupNode reached via
field_summary_for_type recursion) every expansion depth yields a DISTINCT
fingerprint key, so the scrutinee grain NEVER hits yet pins every intermediate
expanded subtree — measured >33GB / OOM on a 6-module closure and the whole-tree
CI floor (the #6640 integration branch's 56m OOM-kill).

Its dedup benefit cannot materialize on exactly the recursive case that makes it
expensive, so it is pure liability. Removed. The bounded grain is unaffected and
keeps #6779's speedup.

Verified: whole-tree compile-clean now completes bounded (~1.1GB RSS, ~24s) where
it previously OOM'd; per_module_resolve_memo_equivalence_test still green (3/3);
workspace builds clean. Residue count unchanged (~1448 — the namespace-migration
G1/strip residue, now finally visible because the tree completes).

Unblocks #6640 (namespace integration) and #6809 (census consolidation).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls added a commit that referenced this pull request Jul 17, 2026
…ecursive scrutinees

The per-module resolve memo (#6779) had two grains sharing one fp cache: a
bounded memo (resolve_node_bounded — its main within-module speedup claim) and
a scrutinee memo on resolve_scrutinee_type_node keyed by a FULL-subtree surface
fingerprint. On a self-recursive scrutinee (e.g. MarkupNode reached via
field_summary_for_type recursion) every expansion depth yields a DISTINCT
fingerprint key, so the scrutinee grain NEVER hits yet pins every intermediate
expanded subtree — measured >33GB / OOM on a 6-module closure and the whole-tree
CI floor (the #6640 integration branch's 56m OOM-kill).

Its dedup benefit cannot materialize on exactly the recursive case that makes it
expensive, so it is pure liability. Removed. The bounded grain is unaffected and
keeps #6779's speedup.

Verified: whole-tree compile-clean now completes bounded (~1.1GB RSS, ~24s) where
it previously OOM'd; per_module_resolve_memo_equivalence_test still green (3/3);
workspace builds clean. Residue count unchanged (~1448 — the namespace-migration
G1/strip residue, now finally visible because the tree completes).

Unblocks #6640 (namespace integration) and #6809 (census consolidation).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.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