Skip to content

One tree, one resolve: floor stages consume the compile-clean computation (levers 2/3/8 of #7106) - #7122

Merged
briansrls merged 19 commits into
mainfrom
claude/ci-compilation-caching-xn4ynp
Jul 23, 2026
Merged

briansrls merged 19 commits into
mainfrom
claude/ci-compilation-caching-xn4ynp

Conversation

@briansrls

@briansrls briansrls commented Jul 23, 2026 •

Copy link
Copy Markdown
Contributor

One tree, one resolve: the floor's later stages consume the compile-clean computation (levers 2, 3, 8 of #7106)

Baseline: #7106's TSVs (docs/probes/ci_floor_{phase_attribution,redundancy_ledger_skeleton,lever_ranking}_2026-07-23.tsv) — merge #7106 first; this branch carries its docs-only baseline until then (a main-merge after #7106 lands collapses the overlap).

STEP 1 — Model (the code below is derived from this)

The consumable fact, associated — not minted. The compile-clean pass's output is modeled where the floor's duplicate-computation debt already lives: gunbc.ci_materialization's counted-resolve law (ci_floor_resolve_receipt_note, Receipt 5). FloorCompileCleanReceipt::Compiled means the main-thread process_shared_index — the typed resolved-graph store the compile-wall-endgame W3 lane names, and the duplicate-work/ComputationIdentity census already rows as PROCESS_RESOLVE_STORE — is warm for witness_layer_roots. Later floor stages consume that store. In ComputationIdentity vocabulary: the whole-tree resolve is ONE materialization; every later same-input resolve in the same process is Share at StructurallyIdentical grade (fixed snapshot, same roots — the purity assumption walk_memo and typed_module_cache already ship on); a stage that cannot be served is a counted necessary-first-touch, never a silent re-walk. The module-identity lane contributes the key language (path⇄module binding, content-hash SourceRef) — joined, never fused, per its own §6 alignment note.

Stage classification (the #7106 redundancy ledger's own vocabulary):

stage was now how
compile-clean receipt (eager install) necessary necessary-first-touch (THE one whole-tree materialization) unchanged
cheap gates batch 0 — entry resolve duplicated (cold spawned-thread re-resolve of the same entry the memo path resolves) consumes-receipt FIX 1: memo-lane colocation
cheap gates batch 0 — gate-body claim rows (layering ×7, extdeps ×5 child processes) duplicated (one cold pool build per claim row) necessary-first-touch, pooled (one pool build per call) FIX 2: pooled transport
compile gate consume (batch 1) necessary (verify) consumes-receipt (walk-memo hit, zero resolve) FIX 1 side effect
emit-host consumes-receipt (walk-memo hit) unchanged —
discovery corpus duplicated per-entry (#6848 walk) unchanged — out of mandate (lever 1, namespace §PR-5b) —
source_root_ingest — bin scans + manifest supply necessary kernel (host-read bytes: provenance coverage receipt, corpus content-hash, V2Tree/DagTree tagging, v2-modeled ingest activation over host-supplied bytes — facts the v1 compile receipt cannot carry by design) unchanged —
source_root_ingest — 12 per-claim child re-resolves duplicated necessary-first-touch, pooled (4 calls → 4 pool builds; overlay-manifest roots are genuinely composed input) FIX 2
reads_real_bytes duplicated heavy resolve (#7030 routes to shared index; entry resolve stays counted) unchanged — its counted resolve is declared debt —
compile-clean scope on src/v2-only deep diffs duplicated (whole-tree where scoped admissible: roster ⊂ compiled tree) scoped by construction (roster ≡ compiled tree) FIX 3

Each fix is an extension of ONE existing authority:

  • FIX 1 (lever 3) extends gunbc.ci_materialization's counted-resolve law: declared count 4 → 3 (Receipt 5, the note's own "the rewire PR declares the count's drop consciously" discipline). Realization: claim_executor batch_unit_lane clause (c) — any resolve-group sharing an (entry, execution_mode) that some batch resolves on the memo path is colocated there, so one entry resolves exactly once per walk, against the store the eager compile-clean install warmed. Derived from the plan's declared profiles only — no schedule fact added or reordered (CI fail-fast: cheap-gate early batch (SIMPLE declared membership + dissolution trigger) + event-scoped stop policy #7088's batch-0 ordering untouched; witness_cheap_gates_only_in_early_batch still pins it).
  • FIX 2 (lever 2, and the child-process half of lever 3) extends the transport discipline (tools.host_prelude; the ingest gate's walk is the module-identity lane's named cost): run_gunbc_claims pools one child per call via claim_batch's pre-existing --entry/--function group grammar (argv authority tools.host_prelude.claim_batch_claims_argv, shape pinned by the typed_claim_batch_pooled_argv_shape_holds witness — no new claim grammar minted; see R1) instead of one child per claim row. Verdict-identical by construction: claim_batch's own loop runs every row (no short-circuit), each failure a named FAIL <function> line, exit nonzero iff any failed — the same conjunction the per-process fold computed. Residue named, counted, with dissolve-on: one pool build per call + one closure resolve per distinct entry (ledger rows), dissolving on the W3 cross-process content-keyed store.
  • FIX 3 (lever 8) extends the partition authority (tools.dag_compile_clean_partition): the boundary derives from ALL witness_layer_roots — exactly the tree the whole-tree gate compiles — never .first(). This closes BOTH directions of the roster⊂compiled-tree asymmetry: src/v2-only .dag diffs no longer widen to whole-tree (the baseline run 29976989996's exact shape), and a dag/std touch now selects its affected src/v2 importers on scoped runs (previously covered only by the falsifier cold control). Every fail-closed arm unchanged: non-selectable paths, departed paths, affected-set refusals, and the no-shard-intersection residue all still widen to whole-tree loudly; the cold control still forces whole-tree.

Hard rules held

  • Falsifier cadence untouched: no edits to falsifier.yml, gunbc_falsifier_batches, or the cold-control envs. The cold control (GUNBC_CI_COMPILE_CLEAN_COLD_CONTROL=1) still forces whole-tree and remains the standing staleness detector for exactly the selection this PR widens.
  • No cap/width changes (lever 5 out of mandate): governor untouched.
  • No witness verdict changes: FIX 1 moves a resolve between threads of one process (resolve is a pure function of (source_roots, entry) — the BatchUnit doc's own construction argument); FIX 2 preserves the per-row run_claim semantics and the call-level conjunction; FIX 3 only widens/narrows which entries COMPILE, with all refusal arms intact. Acceptance oracle: verdict-identical floors.

Test plan

  • cargo test -p v1-compiler --bin claim_executor — lane promotion + RED control (without the heavy same-entry declaration the group spawns, the pre-fix behavior) + mode-keying
  • cargo test -p v1-compiler --lib — floor_fast_plan_scopes_src_v2_entries_both_directions (live tree: src/v2-only touch → Scoped incl. its own entry; dag/std touch → selects src/v2 importers); existing whole-tree guards (mixed .rs, departed, docs-only) unchanged
  • Local pooled claim_batch execution: ONE child, 4 entries, 10/10 PASS (FIX-3 witnesses + pooled-argv shape witnesses); RED control: unknown function → named FAIL no_such_claim_zzz line, later rows still reported, exit 1
  • gunbc ci regen (declared-count line) — drift gate stays green
  • CI floor green (run 29995111208, pull_request): resolves_total 3 == declared 3; cheap 10.15→4.65, consume 27s→8ms, ingest 12.15→5.24
  • Phase-attribution TSV row + ledger flips with evidence run id (5b9e08a)
  • Falsifier condition replaced per R3 (see rework addendum): the standing red is capacity-class (exit 137 at the 16 GiB memory.max, 4 consecutive runs predating this branch), disjoint from selection staleness — hold released; re-arms if a future red is selection-class
  • R4: fresh TSV row from the post-rework run 30009199696 (appended in 1b68104): floor step 49.5 min — fits the 55-min cap; ci job 99.2→61.1 min; batch-4 collapse delivered (wet 53.20→10.82); resolves_total 3 == declared 3; peak 15.0 GiB. Cheap 3.08 and ingest 6.90 MISS the ≤2-min targets — counted residue rows in the redundancy ledger, mechanism named (see R4 below), never silence

Rework addendum (R1–R4, 2026-07-23)

R1 — child-pool lever adopted (the §9 cold-child class). run_gunbc_claims' realization is now ONE pooled claim_batch child per call (claim_batch's own pre-existing --entry/--function group grammar — no new claim grammar; the interim gunbc run --claim flag, gunbc.Cli.RunClaims op, and the ENTRY::FUNCTION spec grammar this PR had introduced are deleted as a §3 duplicate of that pre-existing surface). The cheap-gate transports consolidate to one call per GATE: layering 7 rows → 1 child (was 7 children), extdeps 5 rows → 1 child (was 5); ingest keeps one child per overlay root-set (4 — composed inputs). Walls honored: (a) the pooled child stays a separate process — never in-executor evaluation (the executor is the 16 GiB-pinned process of the crawl; the child dies and frees); (b) per-claim verdicts survive pooling via claim_batch's own loop — every row runs (no short-circuit), each failure is a named FAIL <function> line, exit nonzero iff any failed. Pooling deliberately removes the old cross-call && short-circuit inside a gate (a clean-tree failure previously skipped the scanner receipts): strictly more reporting, stated in the transport notes rather than landed silently.

R2 — batch-4 anomaly: typed disposition, named at the witness grain. The 53.2 min wet wall's dominating row is interp_recorded_fixture_witness_test.dag::interp_recorded_fixture_keystone_holds (2556 s on run 29995111208). Mechanism at source grain: the witness drives ~13+ claim_batch children each invoked with --source-root <workspace root> — every child cold-indexes the entire repo, serially. That is a cold corpus-scan on the merge path (my earlier comment's attribution to "#7107's native-routing flip" is retracted — the PR-name was polluted squash-message history; the receipt now names the witness and its transport class, not a PR). Disposition per the enrollment discipline: too heavy for the falsifier wet lane's 600 s per-receipt budget as-is, so the per-PR enrollment reverts to OfflineLocalRecipe with a dissolve-on naming the re-enrollment precondition (fixture-scoped roots / pooled lifecycle children, measured under the destination lane's budget).

R3 — falsifier hold released, replaced with the class-named check. The red's class from the failed job log of run 29999281277 (main@63feea0): exit 137 — cgroup kill at floor_peak_post=17179869184, exactly the 16 GiB memory.max, during the predict-only cold corpus; 4th consecutive red (21:12/03:16/06:32/11:59), all on trees predating this branch. Disjointness from this diff: the class is memory-capacity on the falsifier's whole-corpus cold walk; this PR (a) removes a duplicate co-resident whole-tree index (memory-reductive), (b) reduces child-process count, (c) leaves the falsifier's compile-clean cold control forced-whole-tree (its env arm precedes selection). It is not a selection-staleness signal — the class the window exists to catch — so the hold is released; if a future falsifier red is selection-class (a counted divergence), the hold re-arms and merge-recommend waits on it.

R4 — re-measure (run 30009199696, all green). Floor step 49.5 min — under the 55-min cap; ci job 99.2 → 61.1 min; wet wall 53.20 → 10.82 (the interp de-enrollment, surviving pools 20+54 rows at 9.35 min eval); resolves_total 3 == declared 3; peak 15.0 GiB cgroup-post. The two R1 targets miss and land as counted residue (ledger rows updated in 1b68104):

  • cheap gates 4.65 → 3.08 min (target ≤2, miss by 1.1): the two pooled children measured ~88 s (layering) + ~64 s (extdeps) + ~33 s node eval — each claim_batch child pays a corpus-denominated MultiEntryIndex build regardless of roster size (the full pool is load-bearing for bare-reference binding today, Import strip residual: 2 lens test files + FunctionCall homonym qualification (full src/v2 strip gated on loader repoint) #6985 Class B, so it cannot be narrowed per-roster).
  • ingest 5.24 → 6.90 min (target ≤2, regression +1.66 vs the interim vehicle): 4 pooled children at ~102/118/82/111 s — the 4 overlay root-sets are genuinely composed inputs, so 4 processes are structural; the per-child delta vs the deleted gunbc run --claim vehicle (~78 s/child) is a claim_batch loader-parity gap (~25–30 s/process), named in the ledger row.

Dissolve-on for both: the W3 cross-process content-keyed store (or claim_batch loader parity with the gunbc-run entry path). Net-vs-baseline both levers remain wins (cheap 10.15→3.08, ingest 12.15→6.90).

🤖 Generated with Claude Code

https://claude.ai/code/session_01F2Rc3TWb8FFexdVQDNbb44

briansrls and others added 11 commits July 23, 2026 04:46
Log-diff receipts on fleet runs decompose workflow vs ci-job wall time and name discovery resolve, self-host gates, and #7030 effectful recovery as the dominant buckets.

Co-authored-by: Cursor <cursoragent@cursor.com>
Re-derive run 29976989996 and five comparison arms; name per-stage duplicate work (per-entry resolve walks, ingest re-scan, cheap gates after compile) and price top levers in minutes without floor behavior changes.

Co-authored-by: Cursor <cursoragent@cursor.com>
Unblocks doc_reachability pre-push gate for the measurement-only audit PR.

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

The layering batch-1 red on 652ec65 was caused by our redundant cli_run.rs
NFR backfill (already landed on main as #7114), which forced a whole-tree
compile-clean on .rs and a heavier batch-1 path. doc_graph_roots bind row
checked: import-bearing file, module_path in string literal — no new
layering edge (not 7080-class). PR diff vs main is now docs + doc_graph only.

Co-authored-by: Cursor <cursoragent@cursor.com>
…tion (redundant-work ledger levers 2/3/8)

STEP-1 model (gunbc.ci_materialization ci_floor_resolve_receipt_note, Receipt 5):
the compile-clean receipt's typed store — the main-thread process_shared_index the
eager install warms — is the consumable fact; later floor stages consume it, and a
stage that cannot be served is counted, never a silent re-walk. Declared
cold-resolve count 4 -> 3 consciously (the note's own rewire discipline); ci.yml
regenerated to match.

Lever 3 (executor realization): batch_unit_lane clause (c) — a resolve-group
sharing an (entry, execution_mode) some batch resolves on the memo path is
colocated there, so the batch-0 cheap-gate group rides the store the eager
compile-clean install warmed instead of re-deriving the same closure cold on a
spawned thread (where thread-local process_shared_index is invisible); the
compile anchor and emit-host then consume its walk_memo context as hits. No
schedule fact added or reordered (#7088 batch-0 ordering untouched).

Lever 2 (transport realization): run_gunbc_claims pools ONE gunbc child per call
(gunbc.Cli.RunClaims; argv grammar gunbc.cli_invoke.cli_claim_spec
'ENTRY::FUNCTION', decoder parse_pooled_claim_spec — one grammar, both
directions) instead of one child per claim row: N rows over K distinct entries
pay one pool build + K entry resolves against the child's per-process shared
store (resolve_entry_graph), full-ledger conjunction preserved by construction.
Residue (one pool build per call; overlay manifests are composed input) counted
in the redundancy ledger; dissolve-on the W3 cross-process content-keyed store.
Dead per-claim argv helper gunbc_claim_run_args deleted (zero consumers).

Lever 8 (partition authority): CompileCleanPartitionBoundary.entry_roots =
witness_layer_roots — the roster enumerates exactly the tree the whole-tree gate
compiles, never witness_layer_roots.first() ('dag' only). Closes both directions
of the roster-subset asymmetry: src/v2-only .dag diffs scope to their entry
closures instead of falling to the no-shard-intersection whole-tree baseline
(run 29976989996's shape), and a dag-rooted touch now selects affected src/v2
importers on scoped runs. Totality glob follows the boundary (both roots; join
fixed for newline-trimmed shell stdout). Every fail-closed arm unchanged.

Proven by execution: executor lane tests (promotion + RED control + mode
keying); pooled claim-spec grammar tests; floor_fast_plan_scopes_src_v2_entries_
both_directions on the live tree; live-tree shard totality over both roots;
pooled overlay run of the real_ingest leg (3/3 PASS — stub supersession through
the pooled resolve path); typed-op witnesses incl. RunClaims red control;
cargo fmt clean.

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

cursor Bot commented Jul 23, 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.

Copy link
Copy Markdown
Contributor Author

CI-trigger anomaly + dispatched run. GitHub created no pull_request workflow run for this PR — not at open (08:32Z), not on a synchronize push (0a24597, empty). Sibling claude/* PRs trigger within seconds (e.g. #7102's branch), so the plausible delta is that this PR modifies .github/workflows/ci.yml (the regenerated declared-count line — required, else the drift gate reds) and the branch is pushed through the session proxy's app credential; the push is accepted but the PR-event run never materializes.

Workaround in place: workflow_dispatch run 29992450742 on the branch head is in progress — it exercises the full floor (dispatch = FullLedger stop policy, unconditional regen, whole-tree compile-clean scope via the .rs-touch arm, resolve-receipt gate at declared 3) and will source the acceptance TSV row. Merge admission will still want the required PR-event checks; if the dispatch run is green, a maintainer re-run/close-reopen — or whatever grants the pushing app workflows scope — should let the PR-event run materialize.


Generated by Claude Code

claude added 2 commits July 23, 2026 09:23
…the bin_witness_wet roster

typed_witness_invocation_test.dag is discovery-excluded by pattern; every fn
in it rides the explicit bin_wet roster. The two pooled-op witnesses added
with gunbc.Cli.RunClaims landed excluded-but-unrostered and the floor refused
loudly (WITNESS ADMISSION REFUSAL cause=UnexecutedDeferredWitness count=2,
run 29993198712) — the admission invariant working as designed; these rows
give them their executing consumer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F2Rc3TWb8FFexdVQDNbb44
…dence (run 29995111208)

Green pull_request floor on this branch, same probe format as the #7106
baseline: compile_clean 3.58 -> 2.89, cheap gates 10.15 -> 4.65, compile-gate
consume 27s -> 8ms (walk-memo hit), ingest 12.15 -> 5.24, reads_real_bytes
3.30 -> 3.13, discovery unchanged by design (lever 1 out of mandate);
resolves_total 3 == declared 3 (the resolve-receipt gate's own green line).
Ledger rows cheap_gates_batch1 / compile_gate_consume flip to
consumes-receipt; source_root_ingest_gate to necessary-first-touch (pooled),
each with this run id as evidence. Batch-4 exec-corpus anomaly (52min, the
interp_recorded_fixture row) is footnoted in the row's class and attributed
in the PR thread — not a mandated stage; bisection in progress.

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

Copy link
Copy Markdown
Contributor Author

Acceptance receipts — run 29995111208 (pull_request, green, srv1-04) vs baseline 29976989996:

phase baseline this run mandate
compile-clean (eager whole-tree) 3.58 2.89 necessary-first-touch, unchanged
cheap gates (batch 1) 10.15 4.65 lever 3 — consumes-receipt
compile-gate consume 0.45 0.00 (8 ms walk-memo hit) lever 3
discovery 12.80 14.66 lever 1, out of mandate
source_root_ingest 12.15 5.24 lever 2 — pooled, residue counted
reads_real_bytes 3.30 3.13 declared debt, unchanged
resolves_total 4 3 == declared 3 (gate's own green line) Receipt 5 closed on first measure

TSVs updated on the branch (5b9e08a): phase row appended, ledger rows flipped with this run id, lever ranking 2/3/8 marked landed. Lever 8's scoped-admissible proof is floor_fast_plan_scopes_src_v2_entries_both_directions (this run itself is .rs-touch → whole-tree by arm 3, correct).

One anomaly, not in any mandated stage: batch 4's 55-row exec corpus went 1.3 → 53.2 min, dominated by interp_recorded_fixture_keystone_holds at 2556 s (PASSED — slow, not red; floor_skip_discovery 265 s and cross_shard_seam 201 s next). Evidence on attribution: (a) the row ran in seconds on every green CI baseline whose tree ≤ #7094; (b) nothing in this PR touches its call graph (it replays recorded fixtures by driving claim_batch --record/--hermetic children — not the pooled transport, not the executor lane, not the roster); (c) the one substantive tree delta in between is #7107 — per its squash message actually the native-routing flip (NativeRouted family legs that cargo-build, toolchain-keyed cache roots that deliberately cold-rebuild) — whose main-side cold controls have never completed (its main push run was cancelled; the first falsifier carrying it, run 29999281277, has been in progress 3.5 h+); (d) a local A/B was attempted and discarded honestly — the row is ≥25 min in this container even at pre-#7107 c0e5732, so local walls are environment-dominated and cannot discriminate. The running falsifier on main@63feea0 is the real control: if its wet lane shows the same row slow, the regression is main-side (#7107-class), not this PR's.

Merge-readiness per the brief: floor green ✓, verdict-identical ✓ (all gates/witnesses PASS; the one prior red was the Phase-0(b) admission wall correctly catching two unrostered rows, fixed in 38d5075), TSV + ledger receipts ✓. The remaining acceptance condition — falsifier green through one full cadence window — is currently blocked by main-side state, not this PR: the falsifier was red on main for 3 consecutive runs before this branch existed (21:12/03:16/06:32, trees ≤ #7094), and the current run is the first to carry #7107. Will report when it completes; not merge-recommending until that window is readable.


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

#7120 interaction (branch now carries it via 4eeb5f1): the floor step cap is now 55 min, sized off recent green main floors (~47-51 min) — runs that did not yet carry the batch-4 anomaly measured above (53.2 min alone; the first main-side control with #7107 aboard, falsifier run 29999281277, is still in progress after 4 h). If that anomaly is real on main, the arithmetic is: pre-#7122 floor ≈ 48 + 52 ≈ 100 min → timeout; with this PR's levers ≈ 34 + 52 ≈ 86 min → still over the 55 cap. So this PR's next synchronize run (and main's first affected deep run) may red on the floor-step timeout for a cost this PR reduces but does not own. Reporting here when the falsifier lands either way.


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

Falsifier landed: red, main-side, OOM. Run 29999281277 (main@63feea0, the first carrying #7107) failed at 11:59Z with exit 137 — cgroup kill at floor_peak_post=17179869184, exactly the 16 GiB memory.max (a censored lower bound per the calibration label; killed on srv3-04 after ~93 min). That is the 4th consecutive falsifier red (21:12 / 03:16 / 06:32 / 11:59), all on trees predating this branch — a standing main-side capacity condition, not a divergence signal, and this PR's memory effect is reductive (the memo-lane colocation removes a duplicate whole-tree index that previously co-resided on a spawned thread).

Two consequences: (1) the batch-4 anomaly attribution stays open — the OOM kills the falsifier before its corpus can read the interp_recorded row, so the first completed main-side cold control is still outstanding; (2) the brief's acceptance condition "falsifier green through one full cadence window" is unsatisfiable by anything in this PR's mandate while main's falsifier OOMs. Everything else in the acceptance is green and receipted (floor green, verdict-identical, resolves 3==declared 3, TSV row + ledger flips with evidence run id). Holding merge-recommend per the brief; the falsifier window is the sole open condition and it is operator-territory (capacity/#7107-class, the falsifier-alert lane's jurisdiction).


Generated by Claude Code

claude added 3 commits July 23, 2026 12:21
…-caching-xn4ynp

# Conflicts:
#	docs/plans/ci-floor-time-45-72-band-attribution.md
#	docs/probes/ci_floor_lever_ranking_2026-07-23.tsv
#	docs/probes/ci_floor_phase_attribution_2026-07-23.tsv
#	docs/probes/ci_floor_redundancy_ledger_skeleton_2026-07-23.tsv
briansrls pushed a commit that referenced this pull request Jul 23, 2026
…agent history sweep, receipts throughout)

docs/plans/resolve-regression-journey.md answers the operator's 2026-07-23
question ('what fundamentally keeps regressing? we have fixed resolve
several times and it comes back worse') from a 65-event dated fix ledger
over origin/main since 2026-06-25 plus the in-tree receipt docs, with an
adversarial verification pass:

- The measured trajectory: ~8m floor (pre-flip) -> discovery flip x12
  demand (#6438, 2026-07-09) -> timeout bounce 30..270 raised to fit ->
  #6848 (+18m time AND the 1GB/process parse baseline, RSS 6.5->20GB,
  2026-07-20) -> mechanism-correct follow-ups recovering less than priced
  (M1 ~0% on capped hosts) -> the 4h memory.high crawl -> #7120/#7122/#9.
  Three mechanisms wear one trend line: added demand, retention to the
  cap, cap lost.
- The five grains of one duplication (per-thread/-entry/-run/-process/-PR),
  discovered serially, fixed independently, no shared already-computed
  authority — instance-patching as validation where construction
  (ComputationIdentity) is the fix.
- Verified: NO floor-time regression gate exists (the 5s law is enforced
  but scoped to eval; the regression mass lives in the exempted infra
  carve-out); 5+ merges since 07-01 added corpus-denominated work with
  zero merge-time cost pricing.
- What ends it, in order: the cost wall (budget refusal + regression
  gate), the identity authority, the retention lane, cost pricing at
  merge.

Registered in doc_graph_roots (reachability suite 7/7 PASS by execution).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016fdkaGGLUKpLRwwqxp5sLg
claude added 2 commits July 23, 2026 12:58
…hild class); interim gunbc-run claim grammar deleted as a duplicate; interp_recorded per-PR enrollment reverted

R1 (child-pool lever, walls honored): run_gunbc_claims realizes as ONE
claim_batch child per call — claim_batch's own pre-existing pooled
--entry/--function grammar, one shared MultiEntryIndex per process, per-claim
verdicts NAMED by its PASS/FAIL-per-function loop, no short-circuit, exit
nonzero iff any failed. The gunbc run --claim flag, gunbc.Cli.RunClaims op,
and the ENTRY::FUNCTION spec grammar this branch had introduced are deleted:
claim_batch already owned the pooled-claims surface (one grammar, not two).
Cheap-gate transports consolidate to one call per GATE (layering 7 rows -> 1
child, was 7 cold children; extdeps 5 -> 1, was 5; the former cross-call &&
short-circuit inside a gate is deliberately removed — every claim reports on
every run, stated in the transport notes). The pooled child stays a SEPARATE
process by design — never in-executor evaluation (the executor is the
16GiB-pinned process; the child dies and frees). extdeps' private roots datum
dissolved into witness_layer_roots (a nickname).

R2 (batch-4 disposition at the witness grain): interp_recorded_fixture's
per-PR enrollment REVERTED to OfflineLocalRecipe — its ~13+ claim_batch
children each cold-index the whole workspace root (2556s on run 29995111208,
the dominating row of the 53.2min batch-4 wall); too heavy for the falsifier
wet lane's 600s receipt budget as-is, so local-recipe with a pooled/scoped
re-enrollment dissolve-on rather than an enshrined nightly refusal.

Proven by execution: pooled child 10/10 PASS over 4 entries in one process
(incl. the argv-shape witness pinning claim_batch_claims_argv's exact
output); RED control exit 1 with the failing claim NAMED and later rows still
reporting; ingest overlay leg 3/3 through the claim_batch loader (stub
supersession held); whole-tree --target dag compile green; artifact drift
clean; cargo fmt clean; executor lane + scope-plan test batteries green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F2Rc3TWb8FFexdVQDNbb44
…5m fits the 55m cap; wet 53.2->10.82; cheap 3.08 and ingest 6.90 land as counted residue vs the 2min targets)

Fresh phase-attribution row from the post-rework pull_request run
30009199696 (head 6fe8d02, all gates green, resolves_total 3 == declared
3, peak 15.0GiB cgroup-post): ci_job 99.2->61.1min, floor step 49.5min
under the 55min cap; wet wall 53.20->10.82min from the interp_recorded
de-enrollment (surviving pools 20+54 rows, eval 9.35min serial).

The two R1 acceptance targets MISS and are recorded as counted residue
in the redundancy ledger, mechanism named per row: cheap gates
4.65->3.08min (2 pooled children at ~88s/~64s — each claim_batch child
pays a corpus-denominated MultiEntryIndex build regardless of roster
size); source_root_ingest 5.24->6.90min, a +1.66min REGRESSION vs the
interim vehicle (4 children at ~82-118s; the claim_batch child costs
~25-30s/process more than the deleted gunbc-run vehicle — loader-parity
gap on top of the shared corpus-denominated index). Dissolve-on for
both: the W3 cross-process content-keyed store (or claim_batch loader
parity), never a silent re-widen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F2Rc3TWb8FFexdVQDNbb44
@briansrls
briansrls merged commit baca5f4 into main Jul 23, 2026
2 checks passed
@briansrls
briansrls deleted the claude/ci-compilation-caching-xn4ynp branch July 23, 2026 15:11
briansrls pushed a commit that referenced this pull request Jul 24, 2026
…ections

Verification pass before operator review (2026-07-24): (1) D1 already
LANDED on main — #7122 + #7128 pooled the 26 cold children to 6, verified
by counting readiness probes in run 30052571652's ci log; plan re-framed,
in-process activation split off as deferred D1b with its fail-open
confirmed by direct read of cli_run.rs:9580. (2) D4 audit deletion now
BLOCKED on falsifier health — the cadence is red 5/5 by crawl-timeout
(run 30044928186: cgroup 16.1G pinned, swap saturated, 170m cap), so the
per-PR audit is currently the only working selection control. (3) The 5s
threshold reuses the existing fast-lane law carrier (thread-CPU budget,
typed refusal) — no second authority. §10 checklist: 14 rows, each with
status + how verified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016fdkaGGLUKpLRwwqxp5sLg
briansrls added a commit that referenced this pull request Jul 24, 2026
… apart, two operator rulings recorded (#7132)

* Roadmap 2b: interpreter-deletion endgame lane — the three deletions named apart, two operator rulings recorded (zero hand-maintained Rust; effects as emitted per-language providers)

New section group 2b (Track B past strong self-host), reconciled against the
verified state on main rather than memory:

- ts-interp-endgame: the delete-v1 conflation split into its three finish
  lines — compiler (§1 gates, undisturbed), interpreter (2a bulk arc + this
  lane), host-physics (pinned v2-EMITTED kernel per seed census).
- ts-zero-hand: operator ruling 2026-07-23 — hand-MAINTAINED Rust goes to
  exactly zero; the pinned kernel is emitted from cited models; the hand
  roster (25 files + module_path_index, growing) becomes a counted burn-down
  frontier with a new-additions-need-dissolution-triggers review bar; names
  the two doc contradictions to fix (interpreter-kernel-d collapse-vs-pin
  either-or resolves to collapse-then-emit; witness-realization P4's
  claim_executor not-an-emit-target corrected to not-YET per census).
- ts-effects-providers: operator ruling — effects are per-language library
  models (effect providers) emitted like everything else; TargetModel
  runtime_row class carries the interface; 2 of ~9 host-effect families
  landed (#7099), rest are rows not architecture.
- ts-store-econ: the durable BUDGETED artifact-store tier + floor
  consultation is the single gate on the 2a flip (every family retained on
  no_cached_no_evict_carrier); resolved_graph_cache and #7129 eviction
  dissolve INTO it per kernel-D.
- ts-material-ci: materialization kernel in CI (the fold both substrates
  consume); unkeyed-collapse watch-flag (0.6 percent vs historic 47).
- ts-interp-delete: the terminal conditions, with the 2a re-pricing (loud
  in-PR agreement, no drip-feed windows) and cli_run hollowing explicitly
  OFF the interpreter critical path.

Also: ts-native-flip-revert row updated with the landed divergence carrier
receipt (v2.std.native_agreement) — re-flip now gated only on the store.

ROADMAP.md regenerated via main_wet (only ROADMAP.md + authority changed;
all other artifacts byte-identical). roadmap_authority witnesses green
(frame/reset/subgroup/emit-refs).

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

* Roadmap 2b rework per review: bind to v1_deletion_plan authority, real dependency edges, corrections + new 2c lens-enforcement group

Every review claim was verified against the tree before accepting; all
load-bearing ones held. Changes:

- 2b is now explicitly a PROJECTION of gunbc.v1_deletion_plan (which
  exists and declares itself the plan authority — the prior block was a
  partial fork); new ts-authority-converge row extends the carrier with
  the execution-track bricks (observation contract, divergence root
  cause, materialization-provider interface, evaluator completeness,
  executor seams, quarantine rehearsal) instead of restating them here.
- Edges now encode the actual dependency graph (RoadmapEdge is
  dependency-gating per roadmap_spawner node_dep_done, not containment):
  store-econ -> material-ci and the 2a flip; observation-contract ->
  flip; evaluator/effects/material/seams -> quarantine -> delete;
  zero-hand after delete as its own terminal milestone.
- ts-native-flip-revert corrected: re-flip is NOT gated only on the
  store — the frontier dissolve_on requires the divergence root-caused
  with member + both values named plus a fresh warm per-host receipt
  (the loudness carrier names failures, it does not resolve them).
- ts-effects-providers: the three conflated populations named apart
  (2 EmittedEffectFamily variants / 9 witness families / ~35 host-fed
  entries); work item is a typed operation-keyed census; boundary
  enforcement (host_run_boundary_admission pending) called out so the
  agency problem does not move into generated providers.
- ts-store-econ: provider-interface-first ordering; artifact store,
  resolved_graph_cache, and #7129 schedule-retention become SIBLING
  provider rows under the materialization kernel, never one merged store.
- ts-material-ci: eval/realize/materialize kept distinct (materialize is
  analysis-side per its own note; realize_pack advisory); the 0.6 percent
  unkeyed receipt bounded properly (run 30027001708 partial-run vs
  committed whole-run ~47.6 — different denominators, record not reprice).
- New rows: ts-observation-contract, ts-evaluator-complete (reject arms +
  missing CPU-deadline/call-depth guards), ts-executor-seams (critical
  slice vs full hollowing), ts-quarantine (deletion dress rehearsal).
- New group 2c (operator request): lens enforcement live in CI —
  per-lens disposition + receipt (zero inert lenses, not 55-blocking;
  complexity is AuditOnly/NoConsumerWitness today), fn-body visibility
  as the real dependency (42 contracts pending reflection; space
  complexity re-homes off src/v1 before terminal deletion), coverage
  re-enrollment priced through the D5 budget wall.

ROADMAP.md regenerated via main_wet (only ROADMAP.md + authority
changed); roadmap_authority witnesses green.

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

* Roadmap 2b/2c: absorb the #7135 adversarial pass — synthesis of both review sets, with two claims adjudicated against the tree

Integrates every verified correction from the adversarial pass (stacked
as #7135 on the pre-rework commit, now absorbed here):

- 9-of-11 precision on the frontier retention reasons (complement +
  meet_join at agreement_red_on_main; the store gates the other nine
  families' FIRST flip, not the reverted pair's re-flip).
- Cache-root truth: ci.yml pins GUNBC_NATIVE_CACHE_ROOT to the runner
  tool-cache (durable, R2-keyed); what's missing is budget/eviction
  authority + the executor-grain consult, not 'no store at all'.
- Gate-1 gloss corrected to the carrier definition (GateEmitterFixedPoint
  = the emitter re-emits itself) + prereq_drift_ruling_2026_07_23 cited.
- interpreter_surviving_roles named as the roles carrier; the un-rostered
  wet-workflow surfaces (serve/belt, main_wet, gunbc ci, pre-push, probe
  bins) become an enrollment obligation AND a delete condition.
- Third carrier contradiction recorded (^hand_queue_drain: 7-files prose
  vs live 25-file roster; pins-not-drain-targets vs the collapse ruling).
- 2a census staleness: 876 entries not 744, first_error_class still
  CensusPending; totality denominator must be derived (group 5a).
- ts-store-econ SIZED (IntricacyHigh/VolumeMedium) with Accept + RED,
  provider shape as ONE CacheLookupResult contract with N sibling
  provider rows (store tier, resolved_graph_cache, recorded_fixture,
  #7129 schedule-retention, W3).
- 2c upgraded to the five-row v2-door lane (M-L1 door / M-L2 treewide
  store-priced / M-L3 contract truth / M-L4 complexity scope), keeping
  this branch's disposition taxonomy and the space-complexity re-home
  rider; cross-edge ts-lens-treewide -> ts-store-econ.

Two adjudications where the reviews conflicted, settled by direct read:
(1) Filesystem Delete/List EXIST (filesystem_io.dag operation Delete;
artifact_fs_delete/artifact_fs_list in the fs transport) — review 1 was
right; the artifact_store_fs transport NOTE is the stale artifact, and
ts-store-econ now says wiring-counted-eviction, not modeling. (2) the
zero-hand edge direction: full zero-hand stays AFTER the delete (its own
terminal milestone); the narrower ^hand_queue_drain brick precedes
QUARANTINE per the carrier's prereq ruling — both encoded, neither
review's blanket edge taken.

ROADMAP.md regenerated via main_wet; roadmap_authority witnesses green.

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

* Roadmap 2b/2c: apply the 9bfe09c re-review — safe ordering edges, converge-gated execution track, hardened store REDs, link-grain quarantine, 2c totality wall + terminal

- Edges: flip now child of census + seams + flip-revert (root-cause
  precedes the bulk flip); quarantine child of flip; evaluator-complete /
  executor-seams / effects-providers child of authority-converge (option
  b: the projection claim true by construction until the carrier gains
  its bricks).
- Hand-drain contradiction resolved: the kernel-D/hand_queue_drain
  carrier FIXES are ts-authority-converge's deliverable; material-ci
  re-pointed; terminal zero-hand burn-down stays after the delete.
- Census literals de-literalized: histogram carrier is the denominator
  authority (876->880 in one day proved the point); snapshots dated.
- ts-store-econ RED battery hardened: verdict-equality primary +
  byte-purity on the keyed artifact (sound per C.2 #6576 seed emitter
  map_keys-free by construction), same-key corruption refuses on read
  (content_verified_on_read flips true), concurrent puts atomic; the row
  named as the ForciblySerial bottleneck (2a flip + lens M-L2 + kernel
  converge on it).
- Quarantine at LINK grain: v1_interpreter omitted from the built
  artifact (cfg/feature or crate split) — source-inaccessible proves
  nothing about a linked module.
- 2c: anchor precision (no lens on the compile DOOR; witnesses run
  elsewhere); M-L1 scoped to all THREE seed-path compile sites (PR gate,
  falsifier cold control, regen); M-L2 names W3 typed-module tier as the
  specific provider; M-L3 counts verified (55 ids / 47 contracts / 44
  AuditOnly / 9 uncovered incl. the LIVE Determinism gate) + the
  registry-contract totality wall first; ts-lens-terminal added as the
  fan-in node with edges from treewide + contract-truth +
  complexity-scope.

Verification pushbacks recorded: authored_wi sizes with
acceptance: ManualAcceptance (not empty — the belt cannot dispatch
bar-less); the seed emitter HAS a determinism guarantee by construction
(C.2 #6576), so the byte-purity oracle stands on the keyed artifact.

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

* Roadmap 2b/2c: apply the green-verification review — five fixes, none structural

1. Flip-revert row twice-corrected: the pair's re-flip gate is EXACTLY
   the frontier's own dissolve_on (root-cause + fresh warm receipt, NO
   store clause — the pair rides the cached leg); my earlier correction
   over-gated in the opposite direction from the original under-gate.
   One authority: the carrier's strings, never a roadmap paraphrase.
2. ts-effects-providers: the stale ~35 host-fed literal replaced with
   the classified truth (6 so far, 700 pending, eventual count unknown;
   histogram carrier is the authority).
3. M-L3 counts reconciled: 46 contracts (44 AuditOnly + 2 Blocking),
   consistent with 55 − 9; the 47 was a grep over-count.
4. Wet-surfaces roles-roster enrollment now OWNED: added to
   ts-authority-converge's brick list (it was delete-blocking with no
   owner).
5. Dispatchability: ts-authority-converge sized (IntricacyMedium/
   VolumeMedium — it is the sprint's entry point and concrete carrier
   work); the 2c anchor-grouping edges removed so ts-lens-door is not
   gated behind an umbrella that never completes (edges are for real
   deps only — the 2b block already followed this rule).

Trivia: evaluator module path corrected to v2.extdeps.runtimes.*;
cli_run line-count de-literalized (~28k and growing); 2b label reframed
'decoupled from strong self-host' to match the content.

Regen byte-idempotent; roadmap_authority witnesses green.

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

* Roadmap 2d + plan doc: progress & observation — process→outcome discipline, one event model, N renderers

docs/plans/progress-observation-design.md: the five operator-signed laws
(process→outcome no orphans; heartbeat carries identity; recursive dwell
escalation; quiet at arm's length; every response true), the P0 event
model (Refused distinct from Failed; BlockedOn DERIVED from governor
facts; one glyph/material authority incl. the reward-animal rows), and
per-context FORMAT CONTRACTS: CI log (append-only, heartbeat+escalation
first-class — the reference implementation's gap), interactive TTY,
receipt/JSONL (replayable; existing receipts become derived views),
dashboard (schema-only), pipe. Reference implementation gunb-ai/gunb.ai
tools/terminal studied BY EXECUTION (tests green; driven live in
TTY/CI/failure modes): lift contention/nesting/boxes/reward; fix CI
silence, Failed/Refused conflation, hand-mirrored emoji duals.

Roadmap 2d: ts-obs-anchor + sized ts-obs-model (P0) + sized
ts-obs-ci-renderer (P1, flagship = re-render the captured crawl window
of run 30044816605) + ts-obs-tty (P2) + ts-obs-census-wall (P3), edges
encoding P0→P1/P2→P3. Doc-graph bind added; reachability witnesses 4/4
and roadmap witnesses green; ROADMAP.md regenerated via main_wet.

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

* Plan: CI two-tier placement redesign — the 5-second rule

Records the 2026-07-24 operator decisions: placement by measured warm cost
(≤5s rides the PR path, wet admissible if fast + hermetic-classified),
DELETE the per-PR selection-control audit step (falsifier cadence is the
surviving control), Rust seed stays tested-by-execution in CI. Dependency
order D0–D5 with the post-merge #7129 P1s folded into D0 and the
run_claims_in_process activation blockers into D1. Doc bound to
gunbc.ci_spec.gunbc_ci_spec; dissolves when D3's placement axis lands.

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

* Plan: single-PR delivery structure + expectation sheet + sign-off checklist

Operator directive 2026-07-24: no staged drag-out — pre-PR probe does all
measurement, one redesign PR lands D1+D3+D4+D5 atomically (single revert),
D0 close-out routed to the #7129 worker and sequenced first (shared
cli_run.rs). Before/after sheet with falsification bounds per row; §9
decision checklist for reviewer sign-off.

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

* Plan: issue-closure checklist worked through by execution; three corrections

Verification pass before operator review (2026-07-24): (1) D1 already
LANDED on main — #7122 + #7128 pooled the 26 cold children to 6, verified
by counting readiness probes in run 30052571652's ci log; plan re-framed,
in-process activation split off as deferred D1b with its fail-open
confirmed by direct read of cli_run.rs:9580. (2) D4 audit deletion now
BLOCKED on falsifier health — the cadence is red 5/5 by crawl-timeout
(run 30044928186: cgroup 16.1G pinned, swap saturated, 170m cap), so the
per-PR audit is currently the only working selection control. (3) The 5s
threshold reuses the existing fast-lane law carrier (thread-CPU budget,
typed refusal) — no second authority. §10 checklist: 14 rows, each with
status + how verified.

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

* Plan + roadmap: apply the #7132 review round — fourth carrier contradiction, staleness, D5 brief in-tree

All five findings verified against the tree before applying: (1) parity_window
required_consecutive_green_windows=3 + frontier dissolve_on strings contradict
the 2a re-pricing (no first flip writable with the falsifier red) — joins
ts-authority-converge's stale-prose deliverables as the FOURTH contradiction;
(2) ts-store-econ's '#7129 in flight' corrected to merged + PR-0 close-out;
(3) rust-suite disposition miscite fixed at its authorities (design_document,
ci_spec — DESIGN.md reprojects; actual decl commit_gate_rust_suite_removed_disposition);
(4) roster rows corrected to post-pooling reality (6 = 1 union + 4 ingest-overlay
by construction per ingest_pool_separation_note + 1 reads-class; batch-6 414s not
12.15m); zero-hand tag repointed at ts-seed-interim; (5) D4 leaves PR-1 — fast-follow
micro-PR gated on first green cadence (§9.7). Implementer round folded in: D1b
scope refinement (plain resolve_entry_graph — spawns removed, per-entry resolves
not), 5s threshold-vs-mechanism caveat (§9.1), and §11 lands the DiffBaseline
brief in-tree (previously chat-only). ROADMAP.md regenerated via main_wet.

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

* Split hub-file token fixes out of this PR; record the batch-3 budget finding

Run 30063529282 refused batch 3 at 24m59s vs the 22m budget: the one-token
miscite fixes in ci_spec.dag + design_document.dag are hub files, so
selection legitimately ran the full corpus (2,315 witnesses, ALL PASS,
RSS healthy) — the honest full-corpus wall exceeds the budget. Attribution
clean: same branch without the hub files was green (0d54cdc). Fixes
reverted here to ride PR-1 (which pays full corpus anyway); DESIGN.md
re-projected from its reverted authority. Systemic implication recorded:
PR-1 necessarily touches CiSpec and will face the same wall — §9.8 decision
(receipt-noted raise sized by the D2 probe) + checklist row 15. The budget
wall itself worked as designed; no widen.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
briansrls pushed a commit that referenced this pull request Jul 29, 2026
Attribution of where a gunbc run / claim_batch invocation actually spends
wall clock, measured on the fleet and re-derived locally by stack sampling.

Headline, from run 30485116707 job 90691769205 re-derived to the second:
the merge-admission gate spends 108.1s to perform 0.09s of work. 103.7s of
that is spent BEFORE the declaration begins evaluating — 38.8s of source
load, 4.3s of compile, and a 64.9s gap between compile.analyses finishing
and the declaration starting.

The tax is fixed, not entry-dependent. A probe module whose entire body is
ExitSuccess, resolving 9 sources with 82ms of total compile, costs 80.6s
CPU-bound against --source-root dag. Adding a 16x larger entry closure
(9 -> 144 sources) moves the wall ~7%. Widening the source roots to 2,677
files measured FASTER than 1,428, so the cost is not file-count-linear.

gdb sampling (24 stacks) attributes it to two whole-corpus passes that run
before the entry's sources are touched: build_module_path_index_uncached ->
parse_module_binding -> tokenize (~40%, full-tokenizes every .dag file to
read one module header line), and extend_sources_to_both_closure_fixpoint ->
tree_bare_census_for_root -> pool_parse -> tokenize plus
census_with_resolved_fn_sigs (~55%, the #6848 bare-reference fixpoint, still
live, a whole-tree parse plus inference per invocation). Both caches are
process-local, so every new process pays in full.

The same disease appears at the per-entry grain inside the floor: ~33.5s
between affected-set arming and witness verdict (four consecutive cycles:
33.52/33.73/33.23/33.6s) of which compile is ~0.64s and the witness
evaluation itself is 0.1-0.5 milliseconds.

Corrects ci-floor-time-45-72-band-attribution.md section 9 on mechanism:
its "~25 serial cold children" is historical — run_gunbc_claims now batches
claims into one claim_batch invocation, so #7122's pooling landed. That
doc's rank-1 lever was already marked STALE and its section 4 asked for a
re-diagnosis of the discovery walk; section 4 here is that re-diagnosis.
Pricing levers against the old mechanism would repeat the exact staleness
failure that doc closes with.

Measurement only — no behavior change in this note. Scoping stated: the CI
attribution to those two passes is by analogy to the local sample, not
measured on a fleet host; confirming it needs a sampler on the runner.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N7LfCpidMuDjV3FxYUHv1K
briansrls added a commit that referenced this pull request Jul 30, 2026
…7446)

* Demote the affected-set selection control to the falsifier cadence

Measured on the per-PR ci job: 10m09s median (n=6 green runs, range
8m41s-10m32s) — 29.9% of the ci job and 22.4% of the PR critical path,
against the 80s local figure gunbc_ci_selection_control_step_note cited
when the step was wired per-PR in 2026-07-10. The gap is the fleet-pressure
envelope becoming the realized cost, not an outlier.

The suite is hermetic: both diff channels are injected fixtures
(GUNBC_CI_DIFF_UNIFIED / GUNBC_CI_DIFF_NAME_STATUS), so it reads no
per-PR state — running it per-PR and running it on a schedule test the
same thing. That is what makes it cadence-relocatable at all.

It now rides gunbc.falsifier_workflow beside the compile-clean and
native-cache cold controls, ordered BEFORE ci_floor_peak_pre_step so its
residency is not attributed to the floor's cgroup peak receipt, and before
the 170m falsifier step so a broken selector reds in minutes.

Coverage delta, stated rather than elided: a reintroduced widen (the
cli_run.rs entry_file_touched class) now reds within one 4h cadence window
instead of before its own merge — the same window ci_spec_discovery_flip_note
already accepts as the bound on a selection miss, on the same lane.

This is a RETURN TRIGGER, not a dissolution: re-enroll per-PR when the
suite runs in seconds. The cost is the 25-cold-child class
(ci-floor-time-45-72-band-attribution.md section 9), so per-gate pooled
children or witness-realization to native bins is what buys it back.

Backstops stay the exact step-sum + prelude on both sides: ci 115 -> 100,
falsifier 290 -> 305.

Witnessed by execution: selection_control_rides_falsifier_not_per_pr_ci
(asserts the step name is present in expected_falsifier_yml and absent
from expected_ci_yml) with a discriminating RED control — re-adding the
step to the ci job steps list fails the witness, reverting greens it.
ci_workflow_witness_holds pins the ci backstop at 100 and explicitly
rejects the old 115; falsifier_backstop_is_step_sum_plus_prelude carries
the relocated term. Generated-artifact drift gate green (byte-idempotent
fixed point); both workflow YAMLs parse.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N7LfCpidMuDjV3FxYUHv1K

* Measurement receipt: the pre-evaluation whole-corpus invocation tax

Attribution of where a gunbc run / claim_batch invocation actually spends
wall clock, measured on the fleet and re-derived locally by stack sampling.

Headline, from run 30485116707 job 90691769205 re-derived to the second:
the merge-admission gate spends 108.1s to perform 0.09s of work. 103.7s of
that is spent BEFORE the declaration begins evaluating — 38.8s of source
load, 4.3s of compile, and a 64.9s gap between compile.analyses finishing
and the declaration starting.

The tax is fixed, not entry-dependent. A probe module whose entire body is
ExitSuccess, resolving 9 sources with 82ms of total compile, costs 80.6s
CPU-bound against --source-root dag. Adding a 16x larger entry closure
(9 -> 144 sources) moves the wall ~7%. Widening the source roots to 2,677
files measured FASTER than 1,428, so the cost is not file-count-linear.

gdb sampling (24 stacks) attributes it to two whole-corpus passes that run
before the entry's sources are touched: build_module_path_index_uncached ->
parse_module_binding -> tokenize (~40%, full-tokenizes every .dag file to
read one module header line), and extend_sources_to_both_closure_fixpoint ->
tree_bare_census_for_root -> pool_parse -> tokenize plus
census_with_resolved_fn_sigs (~55%, the #6848 bare-reference fixpoint, still
live, a whole-tree parse plus inference per invocation). Both caches are
process-local, so every new process pays in full.

The same disease appears at the per-entry grain inside the floor: ~33.5s
between affected-set arming and witness verdict (four consecutive cycles:
33.52/33.73/33.23/33.6s) of which compile is ~0.64s and the witness
evaluation itself is 0.1-0.5 milliseconds.

Corrects ci-floor-time-45-72-band-attribution.md section 9 on mechanism:
its "~25 serial cold children" is historical — run_gunbc_claims now batches
claims into one claim_batch invocation, so #7122's pooling landed. That
doc's rank-1 lever was already marked STALE and its section 4 asked for a
re-diagnosis of the discovery walk; section 4 here is that re-diagnosis.
Pricing levers against the old mechanism would repeat the exact staleness
failure that doc closes with.

Measurement only — no behavior change in this note. Scoping stated: the CI
attribution to those two passes is by analogy to the local sample, not
measured on a fleet host; confirming it needs a sampler on the runner.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N7LfCpidMuDjV3FxYUHv1K

* Receipt: the invocation tax is allocation throughput, not repeated work

Second measurement pass, correcting this note's own first pass and its
lever ordering.

Reading the corpus is not the cost: 8,505,296 bytes across 1,428 files
in 0.044s cold (193 MB/s). Parsing the same content runs at ~0.5 MB/s on
real corpus files and ~0.16 MB/s on dense generated code — 400-1200x
slower than reading it, against 50-500 MB/s for a competent tokenizer.

Three hypotheses tested and refuted by execution:
- Quadratic in file size: NO. Holding content constant at ~4,800 fn decls
  and varying granularity, a 30x file-size increase costs 1.5x, not 900x
  (8x600=2.23s, 24x200=1.86s, 80x60=1.57s, 240x20=1.45s, 800x6=1.61s).
  Cost is linear in total bytes at a bad constant.
- Linear in file count: NO, it tracks bytes.
- The non-ASCII is_ascii() fallback: NOT DOMINANT. Corpora differing only
  in one marker character inside a string literal measure 1.339s vs 1.264s
  and 2.681s vs 2.857s — a 0-7% penalty, though 35% of real .dag files take
  that path.

What it actually is: allocation. 15 of 18 resolved innermost-frame samples
(~83%) land in the allocator or memcpy — _int_malloc, libc_free,
tcache_get_n, malloc_consolidate, checked_request2size, memcpy_avx512, and
Arc::make_mut. char_at returns a heap-allocated String PER CHARACTER and is
called per character from the scan loop, alongside im::Vector persistent
collections doing copy-on-write. This is the model/realization fork at the
string layer: modeled value semantics transliterated into the seed instead
of realized as byte-cursor operations over a UTF-8 slice.

That reframes the is_ascii() branch (11 sites in the seed, 8 in v1_rt.rs).
It is a silent content-dependent performance fallback — nothing typed,
counted, or located, so the slow arm's frequency is zero by construction
and never ranks for fixing — and a second representation of "index into a
string". Deleting the fallback buys ~7%; deleting what it is a fallback
FOR, the String-per-character interface, is the ~400x lever. Same edit, and
a byte cursor is encoding-correct for both arms so the branch disappears
rather than being optimized.

Lever ordering corrected accordingly: caching the whole-corpus passes was
the wrong first move — it would preserve a 0.16 MB/s parser behind a hit
rate. DESIGN section 6's bare-minimum-cost standing rule says a proven
cost-shape defect is always fixed regardless of realized n; this is that
proof. Fix the constant, then cache what remains.

Section 10 records this note's own corrections, including that two earlier
probe configurations were measuring a parse abort rather than a parse (a
'//' comment before the first item declaration panics
for_each_parsed_module_binding); every timing in 4.1 is now guarded by an
explicit parsed/PARSE-ABORT assertion.

Measurement only; no behavior change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N7LfCpidMuDjV3FxYUHv1K

* Root-cause the parse quadratic: one unmigrated function, not the .dag move

Supersedes section 4.1's "linear, not quadratic; non-ASCII ~7%". Those
probes used generated files with NO string literals, so they exercised only
the migrated scan path. Re-measured with one literal per file, warmed, the
per-doubling ratios approach 4x (2.41, 2.80, 3.06, 3.59) and non-ASCII is a
consistent ~2.1x on top; throughput collapses 627 -> 134 KB/s ASCII and
430 -> 63 KB/s non-ASCII.

The .dag migration is correct and should not be reverted. src/v1/01_tokenize.dag
carries SourceRef with a pre-decoded code-point array, and the whole main
scan (source_code_point, source_len, source_substring, source_scan_while,
source_skip_ws) indexes it directly — O(1) per step, no ASCII special case.
Emission is faithful: the model's 6 char_at sites map one-to-one onto the
generated .rs.

What did not come along is process_escapes_loop, which takes source: String
rather than SourceRef/source_chars. Per character it calls string_length and
char_at, each rescanning the whole literal (is_ascii, then byte index or
chars().nth(pos)) giving O(L^2) per literal with the non-ASCII arm O(pos) and
un-SIMD; and it does list_push(acc, ch) into an im::Vector (v1_rt.rs aliases
Vector as Vec), so each push is copy-on-write through Arc::make_mut. It runs
unconditionally on every string literal from all six scan_string arms.

Why this corpus loads it: 30% of corpus bytes (5,841,277 of 19,732,620) are
inside string literals; 38 files carry a literal over 2,000 chars; the worst
is 14,178 chars in design_document.dag, and all top-10 are non-ASCII because
they are prose notes with em-dashes. 15 of the 20 largest files are non-ASCII.

Why no wall caught it: 01_tokenize.dag is in no lens roster (it appears only
as a NameResolutionGap frontier row in a plan doc), though a recursive
list_push accumulator is exactly the complexity_accumulator_copy class. And
the text_lookup_work_counter instrumentation — itself emitted from .dag, with
an honest cost model naming the quadratic — is feature-gated to src/v1/tests
and is called from substring only (v1_rt.rs:287,291), never from char_at. The
counter watches the migrated path; the quadratic lives in the unmigrated one.

Fix shape recorded: give process_escapes_loop the interface the rest of the
file already uses, fold the accumulator, then point the counter at char_at and
roster the module so the next unmigrated interface reds by execution.

Measurement only; no behavior change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N7LfCpidMuDjV3FxYUHv1K

* Receipt: the complexity lens is drivable per-file, infeasible corpus-wide

Answers whether the repo's own complexity lens can be run manually over
src/v1 and src/v2 entirely. Mechanically yes, at current cost no.

Driving it: v2.lens.complexity_accumulator_copy.roster_gate takes an
arbitrary live-tree path (file_gate / file_suspect_count / file_refusal_count)
via the offline_roster_gate_claim_batch_recipe shape. The probe module used
was deliberately not committed — any *_test.dag under a source root is picked
up by CI's discovery walk, so landing it would add ~3-minute live-tree
witnesses to every PR.

Result by execution: file_suspect_count("src/v2/compiler/01_tokenize.dag") == 0
FAILS. The lens finds copied-accumulator suspects in the v2 tokenizer,
confirming section 11's static reading of lex_repeat_step / lex_delimited_step,
where list_append(left: state.lexeme, right: consumed) runs once per character
giving O(L^2). Not obtained: exact counts and the src/v1 figures — the
bracketing run was stopped before completion and is recorded as such.

Cost: 34,208 ms resolve plus 184,828 ms witness (3m05s) to analyze ONE
556-line file. Extrapolated serially that is ~67 hours for src/v1+src/v2
(1,298 files) and ~140 hours for the whole corpus (2,726) — and linear
extrapolation understates it, since cost is superlinear in file size and the
largest file is 12,961 lines against a 237-line mean. This is the unstated
reason the roster gate is operator-ruled OFFLINE with a two-file roster; the
scope was cut to what the cost allowed and that reduction is not legible as a
coverage gap anywhere.

The self-referential finding: ingest_findings parses its target with the v2
parser interpreted under v1, so every audited file pays both quadratics at
once. The complexity lens cannot be run over the corpus because of the
complexity defect it exists to detect — which settles sequencing, since fixing
the parsers is what makes whole-corpus enforcement affordable.

Two coverage gaps named: Unclassifiable refusals ride the Accepted channel and
never gate (which would explain how the v2 tokenizer compiles while the lens
still finds something in it), and src/v1/*.dag never reaches the gate at all
because the seed is compiled by v1 via regen_stage0 rather than through v2's
compile door — the latter stated as a topology hypothesis, not yet executed.

Measurement only; no behavior change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N7LfCpidMuDjV3FxYUHv1K

* Accept review corrections: retract the char_at-per-character claim in place

External review of this note landed five corrections. Four accepted and
applied AT THE POINT OF THE CLAIM rather than appended, because an error that
is only superseded in a later section still misleads whoever reads the earlier
one.

1. char_at is NOT called per character by the ordinary tokenizer scan. Verified
   by inspection: all six char_at sites in src/v1/01_tokenize.dag are
   process_escapes_loop (3) plus all_hex_upper_in_range,
   sentinel_prefix_matches, sentinel_suffix_matches. The ordinary scan converts
   once via chars(source) and indexes SourceRef.source_chars through
   source_code_point / source_scan_while. Section 4.1's sentence claiming
   per-character char_at from tokenize_loop/scan_next_token is retracted in
   place. The consequence is load-bearing: the dense-code benchmark has no
   meaningful string-literal content and still measures ~0.16 MB/s, so char_at
   cannot explain the ordinary path's cost at all.

2. "Allocation-bound, not algorithm-bound" was too broad. Corrected: the
   ordinary path is allocation-bound and linear; the string path is
   allocation-bound AND quadratic.

3. The first lever is renamed from "byte-cursor ops" to frontend CONSTRUCTION
   realization. Rc<Token>, Rc<ScanResult>, make_token's text clone, per-token
   owned String, and the Rc<im::Vector> path-copying accumulator are distinct
   allocation sources the char_at framing obscured.

4. The "fix the constant, then reduce invocations" sequence was too serial and
   is retracted. The cost model is multiplicative, so deleting exact duplicate
   producers (merge-admission fusion, the doubled regen_stage0 --verify, no-op
   heal) proceeds in parallel. The distinction kept: deleting duplicated work is
   always in order; persisting the result of slow work is what should wait.

The fifth is accepted with a scope note. The 0-7% non-ASCII figure is measured
on the ordinary path, which never calls char_at; on the path that does, section
11 measures 46% at L=4,000 and 111% at L=64,000, growing with literal length as
an O(pos) chars().nth predicts. Both figures are needed.

Also contributes a resolve-split receipt from the section 12 lens run, which is
differently shaped from the ~96%-reconcile_assembly diagnosis the review cites:
load=34,651ms dominates with parse=1,400ms and reconcile_assembly=3,253ms on a
cold single-entry claim_batch leg. Recorded rather than reconciled — it supports
the review's own point that cold process starts and pooled floor entries are
separate lanes, and demonstrates why every probe must record binary, execution
leg, source roots, and corpus identity.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N7LfCpidMuDjV3FxYUHv1K

* Register ci-invocation-fixed-tax-attribution in the doc graph

The run 30503392667 ci job red was exactly 3 doc-reachability witnesses:
the receipt doc landed with no in-edge, so doc_graph_has_no_orphan_docs
(both surfaces) and doc_graph_is_clean returned false — the no-parallel-
ledger wall doing its job on this branch's own addition.

The bind row anchors the doc to gunbc.ci_workflow's
gunbc_ci_selection_control_step_note — the demotion disposition this
receipt is the measurement basis for — with the dissolution trigger the
doc's own header declares (pre-evaluation passes persisted or derived
from the containment tree; the demotion's return trigger consumes its
measurements).

Verified by execution locally: doc_graph_has_no_orphan_docs PASS on both
dag/test/claim and src/v2/lens surfaces, doc_graph_is_clean PASS,
ci_workflow_witness_holds PASS, falsifier_backstop_is_step_sum_plus_prelude
PASS. Generated artifacts byte-stable under main_wet regen with a binary
rebuilt from this tree (which also carries origin/main merged in, clearing
the heal skew on this branch and picking up the upstream BUILT_FROM heal
remedy).

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

* Correct the demotion's carrier claims, pin placement structurally, condense the receipt

Accepts the operator review of this branch. Three corrections to claims that
were stated more strongly than the evidence supports, plus the structural
witness the presence test could not express.

DETECTION WINDOW. The note claimed a reintroduced widen "reds within one 4h
cadence window". That is too strong and is retracted. The falsifier is
queue-not-cancel with a 230-minute job backstop class, and the selection
control sits after the prelude and release build, so a change landing just
after a run has passed that control waits for that run's remainder, plus
queued-run startup, plus the prelude and build in the next run — a sum that
can exceed one cadence period. The honest contract is "detected by the next
COMPLETED falsifier control", with the worst case derived from those terms.
What bounds the damage is unchanged and restated: a widen is bounded by the
status quo, and the divergence is counted when detected, never absorbed.

RETURN TRIGGER. It named a mechanism — "per-gate pooled children" — that had
already landed while the suite still measured minutes, so the note was
prescribing a stale fix as its own re-entry condition. Replaced with an
OUTCOME: re-enrol per-PR once a named receipt shows the entire control step,
spawn to verdict, on the CI fleet rather than a local host, consistently
below a seconds-scale ceiling across a full falsifier window. Whichever
mechanism buys that is the lane's business, not this note's.

STRUCTURAL PLACEMENT WITNESS. The existing test asserts the step name appears
in falsifier.yml and not ci.yml. That proves the cadence moved but passes for
every permutation of the same steps, while the placement is load-bearing
twice over: the control must sit AFTER the release build, because it executes
the release-built floor_skip_discovery_witness and has nothing to run before
it, and BEFORE the cgroup peak pre-read, because that pair brackets the
floor's memory measurement and a step inside the bracket attributes its own
residency to the floor's peak receipt.

Three witnesses now pin it over the Step LIST, reusing step_display_name —
the accessor gunbc.ci_materialization already reads steps through — rather
than re-matching the Step coproduct. Exactly-once is asserted in both
directions: one occurrence on the falsifier, zero on the per-PR ci job.

Proven discriminating by execution, both defects injected:
  - control moved inside the peak bracket: the two order witnesses FAIL while
    the old presence test still PASSES — the review's point demonstrated
  - control enrolled twice: the exactly-once witness FAILS while the old
    presence test still PASSES

RECEIPT CONDENSED, 592 -> 198 lines. Its ranked-lever table had gone circular,
naming byte-cursor string work as lever 1 while its own later sections had
both located the real root in one unmigrated frontend function AND explicitly
accepted "frontend construction, not byte-cursor ops" as the correct lever
name. The ordering is now frontend construction first, with byte-cursor
realization named as downstream of it and the fuller lever (SourceCursor,
TokenBuilder, FrozenTokenStream, span-carrying token text) stated rather than
hidden behind the char_at framing. Every accepted correction is preserved in
place, including the retracted char_at-in-ordinary-scan claim, the
allocation-bound scope split, the two-sided is_ascii figures, the parse-abort
probe discipline, and the contributed resolve-split. The six-pass
investigation remains in this file's git history.

The doc-graph dissolution text is updated to the outcome-based trigger so the
bind row and the carrier agree.

Verified: doc_graph_has_no_orphan_docs, doc_graph_is_clean,
ci_workflow_witness_holds, falsifier_backstop_is_step_sum_plus_prelude,
falsifier_concurrency_queues_not_cancels, falsifier_yaml_projection_evaluates,
falsifier_artifact_path_is_workflow_file, and the four selection-control
witnesses all PASS. Generated artifacts byte-stable: no workflow yaml drift.

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

---------

Co-authored-by: Claude <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.

2 participants