Skip to content

XL-R-3: change-denominated compile.emit -- render only affected modules; path-only lib_rs/manifest aggregates proven content-independent; text/integer stub predicates re-grounded total on the resolved graph; byte-identical planted-edit and unscoped controls - #9776

Merged
gunbai-bot[bot] merged 5 commits into
mainfrom
session/bright-seal-86
Aug 31, 2026

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 30, 2026 •

Copy link
Copy Markdown
Contributor

XL-R-3: render only the modules a change can move; derive the population-denominated answers from paths and from the resolved graph.

XL-R-2 (#9757) landed the selection and let a scoped round adjudicate only the mirrors one edit can change. Emit still rendered all 143. This makes the render itself change-denominated.

The split that makes a scoped emission a subset rather than a different answer

A scoped emit renders fewer files. Everything it declares about the whole crate must not move, or the round silently ships an E0583 in a crate nobody re-rendered.

  • emit_lib_rs_from_paths / emit_emitted_population_manifest take List<String>. Content independence is the parameter type, not a claim about the body: there is no content there to depend on. A crate's mod block is a statement about which files exist, never about what is in them.
  • The two closure-stub predicates ask the RESOLVED GRAPH. They used to scan the bytes this emission had just rendered — which cannot answer for a module that was not rendered. closure_needs_module_filename_stub is total under every scope.
  • import_refusals are observed only for rendered modules, and that is exact. An emit carrying an error diagnostic returns no files, so a committed mirror is a file some clean emit produced and the unrendered modules had nothing to say. The argument is carried by the final_files construction that makes it true, with an_emit_that_refuses_hands_back_no_files as its discriminating red.
  • The emitted-population roster moved off the returned file keys onto the manifest. Those are the same set only while emission is whole; once it isn't, every unselected mirror would read as committed_not_emitted and the population identity join would be scoped by accident — the one thing v2.workflow.required_regen says may never be scoped.

Evidence

Planted-edit control — one function added to dag/std/keyed_row.dag, both arms on the shipped emitter:

scope adjudicated compile.emit
whole WholePopulationScope 143 260 007 ms
scoped AffectedScope members=71 71 213 030 ms

diff -rq over the whole installed src/v1/stage0/src: 0 differing files. Byte-identical at identity grain across all 143 mirrors.

Two named vacuity guards run in the harness beside that table, and they are why the agreement claim means anything:

  • GUARD-1 — arm B must report regen-scope: AffectedScope members=[1-9]. A WholePopulationScope here would mean the scope never narrowed and the two arms are the same procedure compared against itself.
  • GUARD-2 — both arms must report a non-zero changed_paths. A zero would mean the planted edit moved no bytes, so both arms install nothing and the trees agree for the wrong reason.

Both fired on earlier attempts and stopped the result being reported. An empty diff is the success signal and the signature of two arms that never executed; the guards assert the preconditions for the answer to mean anything, which the answer itself cannot do.

Unscoped control — CI's whole-population regen on the .dag change reported drift in exactly the modules edited, with lib.rs and emitted_population.rs absent: the re-grounding moved no emitted byte elsewhere, and added or dropped no stub.

Five unit controls (required_regen_host::tests, running in cargo test -p v1-compiler --lib) drive RenderSelectedMirrors through compile_stage0, the real production entry. Proven discriminating rather than assumed: mutating the aggregates to derive from rendered files turns 3 red; reverting returns 18 pass.

Cost, stated against what it does not buy

compile.emit 260.0 s → 213.0 s (−18.1%); round 366.4 s → 298.9 s (−18.4%). Instrument: claim_executor --regen-round-cost, phase=compile.emit. Noise is bounded by a replicate of the whole arm on the same emitter — 256 098 ms and 260 007 ms, 3.9 s apart, against a 47 s effect.

Rendering half the modules buys 18%, so per-module rendering is about a third of the phase and build_emit_rust_context — whole-graph work no selection can narrow without losing correctness — is the rest. This does not reach the "163 s of a 465 s round" the phase's headline suggests. The decomposition is the point: per-module rendering is ~1/3 of compile.emit, build_emit_rust_context is the rest. The next target is therefore the preamble, not the fold — and that is explicitly out of this lane, a separate approved lane if it is wanted, not follow-up work implied by this PR.

A regression is included in that accounting: the first version of the resolved-graph predicate walked every module through repair_input_origin_candidates twice, costing 288 s and taking compile.emit from 258 s to 546 s. Isolated with a probe that short-circuited the predicate and left emitted bytes unchanged, then fixed exactly — a use crate::X::name line requires name to resolve through the registry to a module with filename X, so registry_declares_module_filename answers false without walking anything. Every correctness control was green for the entire life of that regression — the output was byte-perfect the whole time the phase ran at 2.1x cost. Only the round-cost receipt showed it, and I had been treating that receipt as an artifact to collect at the end rather than as an instrument to read while working. A cost-shape defect is invisible to every check that asks whether the bytes are right.

Standing limitation a reviewer should know

This PR's scoped path cannot be exercised by this PR's own CI. regen_affected_set answers WholePopulation for any edit under regen_generation_input_prefixes (v1.compiler., extdeps.languages.), and this branch edits three v1.compiler.* modules — so every round on this branch is whole-population regardless of what is planted on top. That is the bound behaving correctly. The scoped arm's standing evidence is the five unit controls plus the hand-run corpus control above; a green build lane here does not cover it.

gunbc-ci-auto-heal and others added 4 commits August 30, 2026 21:33
…om paths and the graph

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016YM4QYhNNZSapeLZUTQv6V
…s could not see

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016YM4QYhNNZSapeLZUTQv6V
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016YM4QYhNNZSapeLZUTQv6V
…e emitter's declaration

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016YM4QYhNNZSapeLZUTQv6V
@gunbai-bot
gunbai-bot Bot force-pushed the session/bright-seal-86 branch from 0f98a45 to 1736317 Compare August 31, 2026 00:43
… compile.emit paid to answer false

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016YM4QYhNNZSapeLZUTQv6V
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review August 31, 2026 01:41
@gunbai-bot
gunbai-bot Bot merged commit c62be20 into main Aug 31, 2026
5 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/bright-seal-86 branch August 31, 2026 01:52
gunbai-bot Bot pushed a commit that referenced this pull request Aug 31, 2026
gunbai-bot Bot pushed a commit that referenced this pull request Aug 31, 2026
…, XL-R-4A rebuild scope #9765, DESIGN placement plan #9769). Conflicts: 5 regen-owned stage0 mirrors taken ours from the ef328db8 converged tree — regen fixes forward; main's hand-maintained required_regen_host.rs auto-merged from main.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU
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.

0 participants