Skip to content

Regen round cost: claim_executor --regen-round-cost prices one convergence round on two clocks through gunbc.regen_round_cost, and the affected-set disposition - #9735

Merged
gunbai-bot[bot] merged 9 commits into
mainfrom
session/smart-boar-394
Aug 30, 2026

Conversation

@briansrls

@briansrls briansrls commented Aug 30, 2026 •

Copy link
Copy Markdown
Contributor

Regen round cost: a named phase-breakdown instrument + affected-set scoping

Deliverable 1 — the instrument. claim_executor --regen-round-cost --source-root dag --source-root src/v2 runs ONE convergence round exactly as gunbc.generated_artifact_merge_driver generated_artifact_merge_driver_repair_steps prescribes it — seed build → the same run_required_regen the required phase runs → install of the drifted mirrors → rebuild from the installed seed → diff — and prints every phase on two clocks (wall, process-tree CPU), rendered by gunbc.regen_round_cost regen_round_cost_render through the interpreter (no Rust copy of the format). It extends the existing instrument rather than adding one: v1_rt::trace_mark (emitted from v1.compiler.runtime_rust) gains a CPU reading per mark and an armed ledger; the regen host stamps its own phase boundaries under the labels gunbc.regen_round_cost regen_round_phase_label names; compile.dag's existing marks are consumed unchanged. Receipt also lands at target/stage0-regen-round-cost.txt.

Fail-closed arms: the emitting seed must be the built seed (executable bytes digested before/after the seed build; a changed binary refuses with the reason); a refused regen stops the round at emit with no install; a failed rebuild-from-installed is carried on the receipt as a round failure (the phases before it are measured facts) and fails the exit code; an unreadable CPU clock renders na, never 0, and poisons the total.

Evidence: dag/test/claim/regen_round_cost_witness_test.dag (9 fns incl. two RED controls, all true on srv1 via the built gunbc), and two Rust lockstep tests in required_regen_host.rs (host_built_receipt_renders_through_the_model is byte-exact against the model; run remotely, green).

Two receipts, one edit (planted data row in std.content_hash, tree 677988a2, clean):

BuildBuddy runner 192.168.241.2 (6 cores, 7 GiB):

regen-round-cost: producer=claim_executor --regen-round-cost host=192.168.241.2 tree=677988a26ddb4d8c73ac3351045d8c17aa5ea660 tree_dirty=false seed_build_compiled_crates=1 rebuild_compiled_crates=1
regen-round-cost: phase=seed_build wall_ms=227832 cpu_ms=382180
regen-round-cost: phase=corpus_load wall_ms=36072 cpu_ms=36060
regen-round-cost: phase=corpus_reload wall_ms=17315 cpu_ms=17310
regen-round-cost: phase=compile.frontend wall_ms=9188 cpu_ms=9190
regen-round-cost: phase=compile.normalize wall_ms=392 cpu_ms=390
regen-round-cost: phase=compile.reconcile wall_ms=23222 cpu_ms=23220
regen-round-cost: phase=compile.analyses wall_ms=431 cpu_ms=430
regen-round-cost: phase=compile.emit wall_ms=158899 cpu_ms=158890
regen-round-cost: phase=mirror_write wall_ms=17198 cpu_ms=17480
regen-round-cost: phase=candidate_verify wall_ms=0 cpu_ms=0
regen-round-cost: phase=adjudicate wall_ms=17003 cpu_ms=17290
regen-round-cost: phase=hand_verify wall_ms=82 cpu_ms=80
regen-round-cost: phase=digest wall_ms=32961 cpu_ms=33530
regen-round-cost: phase=install wall_ms=0 cpu_ms=0
regen-round-cost: phase=rebuild_from_installed wall_ms=238766 cpu_ms=399410
regen-round-cost: phase=diff wall_ms=5 cpu_ms=0
regen-round-cost: total wall_ms=779366 cpu_ms=1095460
regen-round-cost: changed_paths=1 [src/v1/stage0/src/std_content_hash.rs]
regen-round-cost: FAIL regen: generated surface drift: std_content_hash.rs

srv1 (128 cores, load ~50 during the run):

regen-round-cost: producer=claim_executor --regen-round-cost host=srv1 tree=677988a26ddb4d8c73ac3351045d8c17aa5ea660 tree_dirty=false seed_build_compiled_crates=1 rebuild_compiled_crates=1
regen-round-cost: phase=seed_build wall_ms=373448 cpu_ms=621040
regen-round-cost: phase=corpus_load wall_ms=60478 cpu_ms=60270
regen-round-cost: phase=corpus_reload wall_ms=28377 cpu_ms=28280
regen-round-cost: phase=compile.frontend wall_ms=20599 cpu_ms=20550
regen-round-cost: phase=compile.normalize wall_ms=544 cpu_ms=540
regen-round-cost: phase=compile.reconcile wall_ms=38458 cpu_ms=38340
regen-round-cost: phase=compile.analyses wall_ms=634 cpu_ms=630
regen-round-cost: phase=compile.emit wall_ms=295857 cpu_ms=294910
regen-round-cost: phase=mirror_write wall_ms=24119 cpu_ms=24470
regen-round-cost: phase=candidate_verify wall_ms=0 cpu_ms=0
regen-round-cost: phase=adjudicate wall_ms=23892 cpu_ms=24250
regen-round-cost: phase=hand_verify wall_ms=121 cpu_ms=130
regen-round-cost: phase=digest wall_ms=46407 cpu_ms=47250
regen-round-cost: phase=install wall_ms=0 cpu_ms=0
regen-round-cost: phase=rebuild_from_installed wall_ms=366445 cpu_ms=617300
regen-round-cost: phase=diff wall_ms=15 cpu_ms=10
regen-round-cost: total wall_ms=1279394 cpu_ms=1777970
regen-round-cost: changed_paths=1 [src/v1/stage0/src/std_content_hash.rs]

Fixed-point control (no edit, tree 75bc5007, srv1): total 480.7 s wall / 480.9 s CPU, changed_paths=0, first_generation_equal=true.

What the instrument says (shape, not transcribed as a claim beyond these trees):

  • The regen process is single-threaded end to end (CPU ≈ wall in every regen phase). Emit is the largest regen phase (≈51 % of the regen process on both hosts) but only ≈20 % of a round with a real edit.
  • The two cargo builds of the seed are ≈60 % of a real round (BuildBuddy 228 s + 239 s; srv1 under load 395 s + 366 s) for a ONE-mirror change, because every mirror compiles into one crate. The change-denominated cost lives in the rebuild, not the emit — so the addendum's D3 (shard the emit) condition (“emit is the dominant share”) is NOT met and D3 was not built.
  • Cost-shape defects the receipt makes visible: the corpus is read twice (corpus_load then corpus_reload inside compile_stage0, 53 s/77 s), and rustfmt normalizes the whole population three times (mirror_write, adjudicate, digest: 67 s/97 s). Both are fixable and are not fixed here (measurement lane).
  • The two-round bootstrap is measured, not assumed: round 1 on both hosts (tree 0fe2c517) had the stale seed emit the OLD v1_rt.rs over the hand-synced one and the rebuild refused; round 2 (tree 75bc5007) reached the fixed point.

Deliverable 2 — affected-set disposition (gunbc.regen_round_cost regen_affected_set_disposition): DerivableNow from the closure the regen already builds (cli_run regen_input_sources_over_roots / extend_sources_to_both_closure_fixpoint: imports + dotted + bare refs), read in reverse from the edited module and restricted to the compared mirrors, plus the runtime template products. Evidence by identity: (1) edit v1.compiler.runtime_rust → drift {v1_compiler_runtime_rust.rs, v1_rt.rs} vs 9 predicted (v1_rt.rs is the one dependent outside the import graph: the template's product, emitted from the string baked into the emitting seed); (2) edit std.content_hash → drift {std_content_hash.rs} vs 72 predicted, on both hosts. The bound is an over-approximation; the residual is the seed's own baked mirrors as a generation-level input (the bootstrap), and exactness needs the per-module emit. The cross-module state named in the model (reference_derived_use_lines closure-wide args) stays inside the reverse closure, so it does not break the bound.

Also fixed on the way: resolved_graph_cache::transform_content_digest read current_exe(), which becomes … (deleted) after any in-process rebuild re-links the binary; it now reads /proc/self/exe (the running image) on Linux. Observed on both hosts: the in-round cargo build recompiled the v1-compiler crate once more after an identical build in the same shell (seed_build_compiled_crates=1, byte-identical output) — src/v1/stage0/build.rs declares rerun-if-changed=src; attributable, not chased here.

Not built, cited for follow-up: gunbc.witness_floor_workflow runs with cache: false deliberately (rust-cache's post step deleted other jobs' files on the shared self-hosted home; the note beside that row says ~/.cargo persists across jobs anyway). A cache row there is a candidate only for target/, and the receipts show the seed build is the dominant cost of a round, so it is worth pricing separately.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KGCnzm2zkb37mVHgrGCt9L

Brian Searls and others added 8 commits August 30, 2026 08:33
…k and an armed ledger, the regen host stamps its phases, and claim_executor --regen-round-cost prices one convergence round through gunbc.regen_round_cost

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KGCnzm2zkb37mVHgrGCt9L
…enderer and the process-tree clock

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KGCnzm2zkb37mVHgrGCt9L
…laced executable reaches the typed refusal

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KGCnzm2zkb37mVHgrGCt9L
…carried on the receipt, not a refusal of the measurement; regen the runtime template mirror (v1_compiler_runtime_rust.rs) from round 1

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KGCnzm2zkb37mVHgrGCt9L
… the start path a rebuild may have re-linked

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KGCnzm2zkb37mVHgrGCt9L
…the affected-set measurement

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KGCnzm2zkb37mVHgrGCt9L
…ash for the affected-set measurement"

This reverts commit 677988a.
…ith its residual) and the measured cost shape, from the two planted-edit rounds

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KGCnzm2zkb37mVHgrGCt9L
@gunbai-bot gunbai-bot Bot changed the title Regen round cost: a named phase-breakdown instrument for one stage0 regen round + scoping whether a change-denominated (affected-set) regen is derivable from the modeled .dag import graph Regen round cost: claim_executor --regen-round-cost prices one convergence round on two clocks through gunbc.regen_round_cost, and the affected-set disposition Aug 30, 2026
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review August 30, 2026 09:54
…t rows over std.measure Nanosecond on a named clock, never a bare Int with the unit in the field name (review 57566)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KGCnzm2zkb37mVHgrGCt9L
@gunbai-bot

gunbai-bot Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Addressed review 57566 in fce29f5: TraceMark no longer carries wall_ms: Int / CpuMs { ms: Int }. Each mark now carries durations: List<std.observation.TimedMeasurement> — one row per clock (std.measure.ClockBasis WallClock / CpuClock) whose elapsed is Measured<std.measure.Nanosecond>, so an unreadable CPU clock is MeasuredUnavailable { cause } on the model's own carrier and no unit lives in a field name. Totals fold through observation_duration_of per basis; the receipt renders milliseconds as a projection of the nanosecond value (regen_round_ms_text). The host builds the same carriers (Measure { count } / MeasuredValue / TimedMeasurement) and the byte-exact lockstep unit test plus the ten .dag witnesses (one added: an unreadable CPU row does not poison the wall total) are green on the reworked model.

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