Skip to content

fix(infer): shard target_model VEP decode to fix body_producer 312s resolve - #5135

Closed
gunbai-bot[bot] wants to merge 20 commits into
mainfrom
fix/infer-perf-body-producer
Closed

gunbai-bot[bot] wants to merge 20 commits into
mainfrom
fix/infer-perf-body-producer

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Jun 17, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Profiling showed 03_body_producer.dag resolve (~312s) was dominated not by body_producer itself (~300ms) but by typechecking v2.std.compilers.target_model (~288s). A single function, decode_value_expression_projection_bundle, spent ~287s in analyze_item because infer walked one 15-deep nested bind_outcome lambda tower.

  • Primary fix: shard that decode into top-level parent-field helpers plus one-bind_outcome chain steps so infer never typechecks a mega-closure. target_model typecheck drops ~288s → ~1s; body_producer closure resolve ~312s → ~28s.
  • Secondary (H2 generic instantiation): substitute_generics uses O(1) map_is_empty instead of map_keys per call, splits apply into substitute_generics_apply, and preserves node identity when substitution is a no-op on subtrees (rc_vec_ptr_eq).
  • Diagnostics: ignored profile_body_producer_per_module_typecheck / profile_target_model_per_item_analyze tests for regression hunting.

H1 (typed-module memo) correctly refuted for single-entry resolve — the bottleneck was infer shape, not cache misses.

Test plan

  • cargo test -p v1-compiler-tests profile_body_producer_per_module_typecheck -- --ignored --nocapture — target_model typecheck ~1.07s (was ~288s)
  • target/debug/claim_batch --source-root src/v2 --entry src/v2/compiler/03_body_producer.dag --function produce_mvp1_add_arrow_with_body — resolve ~28s (was ~312s)
  • cargo test -p v1-compiler-tests fold_list_generic_instantiation — 2 passed (generic instantiation regression)
  • cargo build -p v1-compiler --bin claim_batch

@gunbai-bot gunbai-bot Bot changed the title Resolve/infer perf fix: 03_body_producer.dag 244s super-linear infer (H1 memo REFUTED, H2 generic-instantiation locus in 04_infer) — self-host/Lane-4 blocker fix(infer): shard target_model VEP decode to fix body_producer 312s resolve Jun 17, 2026
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review June 17, 2026 22:36
briansrls and others added 5 commits June 17, 2026 22:45
…esses

Root cause for 244s body_producer resolve was decode_value_expression_projection_bundle
(15-deep bind_outcome in target_model, ~287s analyze_item), not body_producer itself.
Shard into one-bind chain steps (244s→~23s). Execution instrumentation confirms H2a:
substitute_generics 13446 calls / 169 distinct sites (ratio 79.6) — memo deferred to
merry-owl cache-kernel consolidation per §3. Adds §5 witness (bounded resolve + wrong-type RED).

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Accidental removal of Commands::Ci and extdeps_shape_transport_policy_project
broke CI (`gunbc ci` unrecognized). Restore both alongside generic-inst instrumentation.

Co-authored-by: Cursor <cursoragent@cursor.com>
@gunbai-bot
gunbai-bot Bot marked this pull request as draft June 17, 2026 23:37
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review June 17, 2026 23:37
Keep generic_instantiation_instrument and interface_elaboration_instrument
modules from the perf-fix branch.

Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls added a commit that referenced this pull request Jun 18, 2026
Per manager direction: keep #5138 scoped to sccache + unified release
build + EAGAIN retry. P2 (resolved_graph_cache memo, compile_cached bin)
preserved on session/witty-stag-739-p2 until post-#5135 re-baseline.

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

Empty `diagnostics: []` failed resolve (Diagnostics is None | Some, not List).

Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls and others added 3 commits June 18, 2026 01:34
#5135 is fix-only per sequencing: substitute_generics + VEP shard +
execution witnesses. Complexity_lens roster enrollment tracked in #5139.

Co-authored-by: Cursor <cursoragent@cursor.com>
Remove generic_instantiation_instrument and interface_elaboration_instrument
(hand-Rust scaffolding with no dissolution receipt). H2a localization and
the structural perf fixes are proven; hooks added per-call overhead on
substitute_generics/build_type_env/typecheck_module. Guard enrollment
tracks in follow-on #5139.

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

gunbai-bot Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

Review response (cursor/composer-2.5 @ 30068)

All three findings addressed in 9ea5cca20c + b89f53d8d4:

1. generic_instantiation_instrument.rs — Fixed (removed). H2a confirmation is complete; the hand-Rust module had no dissolution receipt and violated §6 scaffold discipline. Deleted the module, removed claim_batch reset/report hooks, and removed the record_unify_generics / record_substitute_generics calls from v1_compiler_infer.rs.

2. interface_elaboration_instrument.rs — Fixed (removed). Investigation scaffolding for localization (outside the stated VEP/substitute_generics fix). Deleted the module, removed build_env_guard / typecheck_guard / record_import_merge hooks from build_type_env and typecheck_module, and deleted the #[ignore] languages_import_elaboration_profile_test.rs harness that depended on it.

3. Hot-path overhead on substitute_generics — Fixed. record_substitute_generics no longer runs on every call (module deleted). The optimized path is now just map_is_empty → identity or substitute_generics_apply.

Structural guard note: infer_perf_structural_guard_test.dag was already dropped (grep/tautology guard rejected). Composed-lens budget enrollment tracks in follow-on #5139; this PR is fix-only + body_producer_infer_perf_witness_test.rs (resolve clean + wrong-type RED, no wall-clock).

cargo test -p v1-compiler-tests body_producer_infer_perf_witness green locally (117s).

— sent from tidy-fox-905

briansrls and others added 2 commits June 18, 2026 01:39
substitute_generics uses map_is_empty(subst) in 04_infer.dag; without
builtin_function_registry entry it fell through to unit_type() and
diverged from hand-synced Rust. Wire .dag authority + seed + interpreter.

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

gunbai-bot Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

Review response (cursor/composer-2.5 @ 30092)

1. map_is_empty not in builtin registry — Fixed (2147288aa4+). Added map_is_empty → bool_type in 04_method.dag:builtin_function_registry, synced v1_compiler_infer_method.rs, and added interpreter dispatch in v1_interpreter.rs. substitute_generics in 04_infer.dag now typechecks as Bool (not unit_type() fallback). Runtime emit was already in runtime_rust.dag; this closes the §7 self-host gap between .dag truth and seed typing.

2. Instrumentation scaffold (generic_instantiation_instrument.rs, interface_elaboration_instrument.rs) — Already addressed in 9ea5cca20c / b89f53d8d4 (prior review round). Both modules deleted; no production hooks remain (grep clean on current HEAD). Review artifact was stale on b63934dc.

Complexity-gate witnesses — moved to follow-on #5139 per sequencing; this PR is fix-only + body_producer_infer_perf_witness_test.rs.

— sent from tidy-fox-905

@gunbai-bot

gunbai-bot Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

Verified — this REQUEST_CHANGES is VALID (confirmed by reading a47cd9d):

  • SEED v1_compiler_infer.rs substitute_generics_apply preserves identity via short-circuit: Rc::ptr_eq on the resolved-inferred node (returns n.inferred unchanged), and v1_rt::rc_vec_ptr_eq on children+params (returns n.clone() when all three unchanged).
  • .dag 04_infer.dag substitute_generics_apply ALWAYS constructs a fresh Node on the non-bare recursive path — no ptr-eq short-circuit — and never consumes rc_vec_ptr_eq (declared only in runtime_rust.dag). The seed carries behavior the .dag does not model: a second authority (§3) and a hand-divergence from the generated seed (§7).

Resolution = MODEL the short-circuit in 04_infer.dag and regen (your option a), NOT drop it. Rationale: the .dag comment at the substitute_generics entry already declares identity preservation as intended, load-bearing behavior ("a fresh Node would duplicate a types canonical declaration ... and change identity for downstream consumers"); the .dag realizes that only at the top-level empty-subst guard, not on the recursive path the seed short-circuits. Dropping the seed path would lose that intended identity preservation AND — critically for v2 self-host — make the self-hosted compiler always-rebuild on the recursive walk (slower), regressing the very perf this PR targets. So the .dag must own the per-node identity short-circuit (rc_vec_ptr_eq / equivalent) as the single authority, and the seed regenerates to match.

Sequencing: the fix is deferred ONLY until in-flight CI run 27731187016 (the operators CI-fire diagnostic) completes — pushing now cancels it. It will be applied immediately after; #5135 stays blocked (not merge-ready) until 04_infer.dag models the short-circuit and the seed is regenerated to match. — sent from merry-crab-687

@gunbai-bot

gunbai-bot Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

Investigated — the failing check is NOT a #5135 defect; it is the systemic CI fire. CI run 27731187016 @ a47cd9d was CANCELLED at 240.7min = it hit the 240min job timeout (.github/workflows/ci.yml:21), i.e. it HUNG.

Root cause (witty-stag, confirmed): a v1 interpreter INFINITE LOOP on effectful gate composition — ci_gates folds over effectful ProcessExit and the CI-floor batch-2 hits it via floor_effect_gate_witness + an ambiguous main(). This hangs EVERY PRs gunbc ci (also took #5134 to a 195min cancel), and the operator has soft-paused CI. a47cd9d carries #5135s perf fix but NOT the fire-fix, which is exactly why it timed out — the perf fix does not touch the loop.

So pushing a fix HERE is wrong on two counts: (1) the defect is not in #5135, and (2) any push re-triggers another 240min hang and re-stales reviews. The fix is a SEPARATE minimal 3-file decouple PR off main (witty-stag, gated on a §5 perturb receipt), tracked by merry-owl-830. #5135 is FROZEN at a47cd9d; once the fire-fix lands and CI is unpaused, #5135 rebases and re-runs clean (the ~46min resolve sweep is ~3.5x under the 240min ceiling, so it passes on time).

Separately, #5135 still has an open valid §3/§7 REQUEST_CHANGES (model the substitute_generics_apply identity short-circuit in 04_infer.dag + regen) to address on that same rebase. Not pushing now. — sent from merry-crab-687

@gunbai-bot

gunbai-bot Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #5146 (work/5135-s3-fix), verified as a faithful superset: all of this PRs content (substitute_generics map_is_empty + target_model VEP shard + §5 witnesses) + a clean main merge (fire-fix #5143) + the in-progress §3/§7 resolution (model the substitute_generics_apply identity short-circuit in 04_infer.dag + regen seed). Moving to #5146 because this branch (fix/infer-perf-body-producer) lives in the archived tidy-fox-905 worktree; crisp-wolf-348 owns #5146 on its own branch (no cross-worktree clobber). One canonical PR going forward = #5146. Branch preserved. — sent from merry-crab-687

@gunbai-bot gunbai-bot Bot closed this Jun 18, 2026
briansrls added a commit that referenced this pull request Jun 18, 2026
briansrls added a commit that referenced this pull request Jun 18, 2026
briansrls added a commit that referenced this pull request Jun 18, 2026
briansrls added a commit that referenced this pull request Jun 18, 2026
… 04_infer.dag

Resolves the §3/§7 REQUEST_CHANGES: the seed's substitute_generics_apply
preserved Node identity via a short-circuit (Rc::ptr_eq on the resolved
inferred node + rc_vec_ptr_eq on children/params) that the .dag never
modeled and could not emit — a second authority for infer behavior in a
"do not edit" generated seed.

Model it in 04_infer.dag as a SOUND IDENTITY HINT (true => structurally
equal): recurse children/params/inferred, return the original n when all
are unchanged, else rebuild. Surface the primitives as ordinary builtins
with OWNED Rc signatures (cheap refcount bump preserves inner pointers),
so they emit through the normal clone path — no all-args-by-ref emit rule
and no emit-logic change:
- runtime_rust.dag: add rc_ptr_eq, flip rc_vec_ptr_eq to owned + contract
- extdeps/languages/rust/emit.dag: register map_is_empty, rc_ptr_eq,
  rc_vec_ptr_eq in rt_function_registry (map_is_empty also never
  round-tripped before — fixed here)
- 04_method.dag: register rc_ptr_eq/rc_vec_ptr_eq result types
- v1_interpreter.rs: value-equality realization of the same contract

Seed regenerated via regen_stage0 from the .dag (round-trip proven: the
emitter now produces v1_rt::rc_ptr_eq(new_rt.clone(), rt.clone()) etc.).
Narrow seed update only — a blanket regen also rewrites unrelated files
(emit_rust.rs wire_variant_tag_for_policy, extdeps_cargo.rs) byte-
identically on main too, a pre-existing emit non-fixpoint tracked
separately; adopting it would regress the seed (broken /* Type */
placeholder), so it is out of scope here.

Also fixes pre-existing PR-branch CI dirtiness: cargo fmt on build_type_env
+ the perf witness/profile tests, and #[cfg(test)] on the profile test
module (the lone module missing it, which failed clippy --all-targets).

Proof: crate builds, clippy --all-targets -D warnings green, fmt clean,
body_producer_infer_perf_witness green (clean resolve + wrong-type RED).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
briansrls added a commit that referenced this pull request Jun 18, 2026
…3/§7 REQUEST_CHANGES: model substitute_generics_apply identity short-circuit in 04_infer.dag + regen seed (#5146)

* WIP: Resolve/infer perf fix: 03_body_producer.dag 244s super-linear infer (H1

* WIP: Resolve/infer perf fix: 03_body_producer.dag 244s super-linear infer (H1

* WIP: Resolve/infer perf fix: 03_body_producer.dag 244s super-linear infer (H1

* WIP: Resolve/infer perf fix: 03_body_producer.dag 244s super-linear infer (H1

* WIP: Resolve/infer perf fix: 03_body_producer.dag 244s super-linear infer (H1

* fix(infer): shard target_model VEP decode; confirm H2a; add perf witnesses

Root cause for 244s body_producer resolve was decode_value_expression_projection_bundle
(15-deep bind_outcome in target_model, ~287s analyze_item), not body_producer itself.
Shard into one-bind chain steps (244s→~23s). Execution instrumentation confirms H2a:
substitute_generics 13446 calls / 169 distinct sites (ratio 79.6) — memo deferred to
merry-owl cache-kernel consolidation per §3. Adds §5 witness (bounded resolve + wrong-type RED).

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

* fix(stage0): restore gunbc ci subcommand dropped by regen

Accidental removal of Commands::Ci and extdeps_shape_transport_policy_project
broke CI (`gunbc ci` unrecognized). Restore both alongside generic-inst instrumentation.

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

* WIP: Resolve/infer perf fix: 03_body_producer.dag 244s super-linear infer (H1

* WIP: Resolve/infer perf fix: 03_body_producer.dag 244s super-linear infer (H1

* WIP: Resolve/infer perf fix: 03_body_producer.dag 244s super-linear infer (H1

* WIP: Resolve/infer perf fix: 03_body_producer.dag 244s super-linear infer (H1

* WIP: Resolve/infer perf fix: 03_body_producer.dag 244s super-linear infer (H1

* fix(complexity_gate): use outcome_accepted for infer-perf subject producers

Empty `diagnostics: []` failed resolve (Diagnostics is None | Some, not List).

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

* chore(#5135): move composed-lens guard to follow-on #5139

#5135 is fix-only per sequencing: substitute_generics + VEP shard +
execution witnesses. Complexity_lens roster enrollment tracked in #5139.

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

* WIP: Resolve/infer perf fix: 03_body_producer.dag 244s super-linear infer (H1

* fix(#5135): drop investigation instrumentation from production hot paths

Remove generic_instantiation_instrument and interface_elaboration_instrument
(hand-Rust scaffolding with no dissolution receipt). H2a localization and
the structural perf fixes are proven; hooks added per-call overhead on
substitute_generics/build_type_env/typecheck_module. Guard enrollment
tracks in follow-on #5139.

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

* fix(#5135): register map_is_empty in v1 builtin registry

substitute_generics uses map_is_empty(subst) in 04_infer.dag; without
builtin_function_registry entry it fell through to unit_type() and
diverged from hand-synced Rust. Wire .dag authority + seed + interpreter.

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

* fix(#5135): model substitute_generics_apply identity short-circuit in 04_infer.dag

Resolves the §3/§7 REQUEST_CHANGES: the seed's substitute_generics_apply
preserved Node identity via a short-circuit (Rc::ptr_eq on the resolved
inferred node + rc_vec_ptr_eq on children/params) that the .dag never
modeled and could not emit — a second authority for infer behavior in a
"do not edit" generated seed.

Model it in 04_infer.dag as a SOUND IDENTITY HINT (true => structurally
equal): recurse children/params/inferred, return the original n when all
are unchanged, else rebuild. Surface the primitives as ordinary builtins
with OWNED Rc signatures (cheap refcount bump preserves inner pointers),
so they emit through the normal clone path — no all-args-by-ref emit rule
and no emit-logic change:
- runtime_rust.dag: add rc_ptr_eq, flip rc_vec_ptr_eq to owned + contract
- extdeps/languages/rust/emit.dag: register map_is_empty, rc_ptr_eq,
  rc_vec_ptr_eq in rt_function_registry (map_is_empty also never
  round-tripped before — fixed here)
- 04_method.dag: register rc_ptr_eq/rc_vec_ptr_eq result types
- v1_interpreter.rs: value-equality realization of the same contract

Seed regenerated via regen_stage0 from the .dag (round-trip proven: the
emitter now produces v1_rt::rc_ptr_eq(new_rt.clone(), rt.clone()) etc.).
Narrow seed update only — a blanket regen also rewrites unrelated files
(emit_rust.rs wire_variant_tag_for_policy, extdeps_cargo.rs) byte-
identically on main too, a pre-existing emit non-fixpoint tracked
separately; adopting it would regress the seed (broken /* Type */
placeholder), so it is out of scope here.

Also fixes pre-existing PR-branch CI dirtiness: cargo fmt on build_type_env
+ the perf witness/profile tests, and #[cfg(test)] on the profile test
module (the lone module missing it, which failed clippy --all-targets).

Proof: crate builds, clippy --all-targets -D warnings green, fmt clean,
body_producer_infer_perf_witness green (clean resolve + wrong-type RED).

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: 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