Skip to content

Restore --v2-native-route: the emitted driver does not build on main - #11216

Merged
gunbai-bot[bot] merged 1 commit into
mainfrom
session/deep-cat-655-route-repair-v2
Sep 13, 2026
Merged

gunbai-bot[bot] merged 1 commit into
mainfrom
session/deep-cat-655-route-repair-v2

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 12, 2026 •

Copy link
Copy Markdown
Contributor

--v2-native-route is broken on main as landed (6c7b081961e286d60124a2415e879d35eda3349d). This restores it.

The defect on main

main's emitted driver refuses at its own build:

V2-NATIVE REFUSAL cause=EmittedCompilerBuildFailed — Completed status=101
error: value assigned to `module_prepare_nanos` is never read
error: could not compile `gunbc-emitted-closure-src-v2-compiler-00-compile-dag`
       (bin "gunbc-emitted-closure-src-v2-compiler-00-compile-dag") due to 1 previous error
RUSTFLAGS="-D warnings"

Observed independently three times before this PR: SUCC5 and a closure capture on one host, and one compile-proof route run on another. (Two further route runs of mine never reached the emitted build at all — they refused earlier at TestedTreeUnobservable, for the reason described below — so they are not counted here.) Nothing on the merge path consumes the route, which is why #10940 was landed with this standing and fixed forward.

Where it came from

#10940 closed the preparation span per arm so that prepare would stop containing its module's eval intervals. Two things are worth keeping apart here, because an earlier version of this paragraph ran them together.

The overlap is established from the source: on an accepted module the prepare interval enclosed that module's eval intervals, and both were added to the exclusive sum, so eval was counted twice.

The net excess a run reports is not that overlap. A full-corpus run returned NativeDriverCostOverAttributed with the exclusive sum exceeding the parent by 110,368,734 ns while its eval row was 207 ms; a reduced-population run over-attributed by 3,200,648 ns against an eval of 3,925,291 ns. The excess is what remains after the double-counted eval is set against work inside parent_span that no exclusive row covers, so it is smaller than eval on the full corpus and close to it on the reduced one. Removing the overlap is therefore necessary for a coherent partition and is not by itself sufficient for one; the tolerance is unchanged and no run is admitted by widening it.

The repair assigned an outer let mut module_prepare_nanos: u128 = 0; from each arm. Every path assigns before any read, so the initialiser is a dead store — and the emitted crate builds under -D warnings, where a dead store is an error.

The repair

The close is the arm's value, not an assignment into an outer binding:

let (outcome_label, module_prepare_nanos) = match &*resolution {
    …ContextRowsDecided { rows } => { let this_prepare = span_nanos(prepare_started); … ("context_refused", this_prepare) }
    …ResolveRowsDecided { rows } => { let this_prepare = span_nanos(prepare_started); … ("resolve_refused", this_prepare) }
    …Resolved { resolved }       => { … let this_prepare = span_nanos(prepare_started); match &*preparation { … } }
};

No outer binding to overwrite, nothing dead to warn on. No allow(unused_assignments) and no warning downgrade — a toggle whose only effect is to proceed as if the refusal had not fired is the escape hatch DESIGN §5 forbids, and this refusal was correct: the dead store was real.

The exclusivity #10940 established is unchanged. Every close still precedes the evaluation loop, so prepare never contains its module's eval intervals.

The control, and what it cannot do

the_preparation_span_closes_before_any_declaration_is_evaluated now asserts exactly three closes — one per arm — and that the last precedes where evaluation opens. The count is load-bearing: collapsing the arms back onto one outer assignment reds on the count before it reds on the order.

It reads the emitted driver's source text and cannot establish that the text compiles. The only consumer that compiles it is a route run — gunbc.source_root_eval_driver_seed_growth names that boundary explicitly. Two questions, two instruments, which is why this PR's receipt is a route run's own build line rather than a green test. A source-text assertion passing on a driver that does not build is exactly how the defect above reached a pushed head.

Two failure modes this PR is the receipt for

TestedTreeUnobservable is the arm working. The first two attempts at a compile proof appeared to succeed and had not run at all. The check was "does target/release/gunbc-emitted-closure-* exist" — which matched a binary from fifteen hours earlier and reported a compile proof one second after the route started. With that removed, the real cause surfaced: the route was refusing immediately with

V2-NATIVE REFUSAL cause=TestedTreeUnobservable — GITHUB_SHA is unset, so the tree this run
describes cannot be observed. The receipt's tested_tree carries an admission clause, so a
placeholder would green it and assert a tree that was never tested.

It was right about the tree specifically: the worktree held the repair uncommitted and so corresponded to no commit. Supplying a plausible GITHUB_SHA would have been precisely the fabricated identity the clause rejects. The proof instrument now deletes stale artifacts before the run, watches for the producer's own emitted crate built … exit_status=0 warning_count=0 line, and reports BIN only when its mtime is at or after the route start.

The projection lesson, by symbol (gunbc.rung_drop native_lane_closure_walk_unkeyed_membership). Review 64576 caught an invented member in that row's population; review 64797 caught the same population's projection asserting a live consumer of native_lane_module_named after the symbol was deleted. claim_executor --required-regen's candidate tree contains no docs projection, so a docs-affecting change reports first_generation_equal=true and drifts silently — the authority row was fixed and the artifact was not. tools.docs_projection_gate regen is the instrument that covers it, and CI's auto-heal regenerated the line independently; the gate reproduces that heal byte-for-byte.

Acceptance against the run that proved this head

The compile proof for this change was first taken on 4011bf9d, a commit branched before main's last two merges. The tree this PR carries differs from it in six paths, and each is determined on its own terms rather than by a class exemption:

  • dag/gunbc/recurring_failure_mode/admitted_reclaim_charged_by_first_touch.dag
  • dag/gunbc/recurring_failure_mode/gate_closure_narrower_than_the_closure_its_merge_governs.dag
  • dag/gunbc/recurring_failure_mode/gate_population_covers_only_new_subjects.dag

Each of the three is a new failure-mode row file: not named in any manifest, carrying no test declaration, and introducing no bare name that collides with an existing symbol. Their only structural effect is on the derived roster, whose import edge is unchanged. The remaining three paths — an artifacts/ BMC log, one regenerated line in docs/design-rung-drops.md, and a docs/probes/ note — are outside the route's inputs entirely. Nothing under src/v1, src/v2, or any Cargo file differs.

The independent check on that reasoning is that the emitted driver built from this head has the same sha256 as the one built from 4011bf9d on another host: three builds, two hosts, one artifact.

Receipt

  • tools.docs_projection_gate regen on this head — result reported in the thread as observed
  • cargo test --release -p v1-compiler-tests --lib native_driver_cost — against a mirror verified to carry the change before the test ran
  • claim_executor --v2-native-route on this exact head — the route's own emitted-crate build line, BIN sha256, and mtime at or after the run's start

🤖 Generated with Claude Code

https://claude.ai/code/session_013aZDLk2CxsCDznqn49Xhe8

main's emitted driver refuses at its own build:

  V2-NATIVE REFUSAL cause=EmittedCompilerBuildFailed — Completed status=101
  error: value assigned to `module_prepare_nanos` is never read
  could not compile `gunbc-emitted-closure-src-v2-compiler-00-compile-dag`
  (RUSTFLAGS="-D warnings")

Observed independently four times: SUCC5 and the closure capture on srv2, and two
compile-proof route runs on srv1. Nothing on the merge path consumes the route,
which is why #10940 landed with this standing; this PR restores it.

WHERE IT CAME FROM. #10940 closed the preparation span per arm so prepare would
stop containing the module's eval intervals -- a real defect, observed as
NativeDriverCostOverAttributed with the exclusive sum exceeding the parent by the
size of eval. Each arm assigned an outer `let mut module_prepare_nanos: u128 = 0;`.
Every path assigns before any read, so the initialiser is a dead store, and the
emitted crate is built under -D warnings where a dead store is an error.

THE REPAIR: the close is the ARM'S VALUE.

  let (outcome_label, module_prepare_nanos) = match &*resolution {
      ..ContextRowsDecided { rows } => { let this_prepare = span_nanos(prepare_started); ..; ("context_refused", this_prepare) }
      ..ResolveRowsDecided { rows } => { let this_prepare = span_nanos(prepare_started); ..; ("resolve_refused", this_prepare) }
      ..Resolved { resolved }       => { ..; let this_prepare = span_nanos(prepare_started); match &*preparation { .. } }
  };

There is no outer binding to overwrite and nothing dead to warn on. No
allow(unused_assignments) and no warning downgrade: a toggle whose only effect is
to proceed as if the refusal had not fired is the escape hatch DESIGN section 5
forbids, and this refusal was correct -- the dead store was real.

The exclusivity #10940 established is unchanged. Every close still precedes the
evaluation loop, so prepare never contains its module's eval intervals.

THE CONTROL now asserts exactly THREE closes, one per arm, and that the last
precedes where evaluation opens. The count is load-bearing: collapsing the arms
back onto one outer assignment reds on the count before it reds on the order.

WHY THE CONTROL COULD NOT CATCH THIS. It reads the emitted driver's SOURCE TEXT
and cannot establish that the text compiles; the only consumer that compiles it is
a route run (gunbc.source_root_eval_driver_seed_growth names that boundary). Two
questions, two instruments -- which is why this PR's receipt is a route run's own
build line rather than a green test.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013aZDLk2CxsCDznqn49Xhe8
@gunbai-bot
gunbai-bot Bot merged commit 5f18d9f into main Sep 13, 2026
4 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/deep-cat-655-route-repair-v2 branch September 13, 2026 00:21
@gunbai-bot

gunbai-bot Bot commented Sep 13, 2026 •

Copy link
Copy Markdown
Contributor Author

Closure receipt n — head 6511f69cda40fdac563174d0055a7d4fba0ffcc1 (post-landing acceptance; merged as main 5f18d9f).

Binding: overlay 20e65f0ab3eff5006b5ddaba920a859202b3b4cd of the head on main 6c7b081961e286d60124a2415e879d35eda3349d (PR base = that main; the receipt executed on this recorded B composition, and its applicability to realized main — which also carries #11110, merged after this capture began — rests on the bounded per-path #11110 delta determination below, not on whole-tree identity. Bounded identity that IS established: the emitted closure binary sha256 542a5c4e… is byte-equal on this overlay, on the PR head 6511f69, and on realized main 5f18d9f); producer claim_executor_pinned sha256 a9a541e39a7ccf18…; instrument closure_pr.sh sha256 b8190c19bf0b54b5…; host srv2; the emitted closure compiler BUILT on this composition (this is the first closure capture that could build since #10940 landed: captures on d85ba9c / 343949c refused at EmittedCompilerBuildFailed); fold census dag src/v2, _terminal: complete, EXIT=0, wall 400.96 s.

Extraction (path, fatal_reason): 15 rows — 14 parse_g0_tokens_remain, 1 normalize_reason_post_normalize_not_well_formed; sha256 d153a911ccc2201d…. Manifest 176 entries, sha256 a53a47fbb49581e4….

Joins:

Executed-vs-classified: a census fold (front-end refusals only; no resolve, no evaluation) — closure membership and parse-grain refusals, not test execution. Full-N execution on this content is SUCC6 (running, driver exe sha256 542a5c4e… = this head's emitted binary), reported separately.

— sent from eager-raven-113

Edited 2026-09-13 ~01:40Z: replaced the 'content-identical to the squash' claim with the B-composition/applicability statement (side-chat correction). — sent from eager-raven-113

briansrls pushed a commit that referenced this pull request Sep 13, 2026
…t per file

The context attribution left one question open and named the instrument for it: the fold costs a
flat ~840 us per token with 80% in parse, and nothing printed says whether that is a memo that
never hits or genuine per-token work in the combinators. ParseTable already tracked memo_hits /
memo_misses / memo_lookup_calls and parse_table_memo_stats already existed; nothing carried them
out of the parse, so nothing could read them.

NOT A FIELD ON ParseArtifact, WHICH WAS THE SHORTER CHANGE, FOR TWO REASONS. ParseArtifact answers
WHAT was parsed; the counters answer HOW that parse executed, which is a realization fact about one
run and not a property of the tree -- DESIGN section 3 keeps interface and realization as two facts,
and a counter field would make every consumer of a parse result carry a measurement it has no use
for. The second reason is decisive rather than stylistic: an Outcome's Rejected arm carries no
ParseArtifact, so a field there would lose the accounting exactly on the files that spend seconds
in parse and THEN refuse -- 9.8% of the fold, and the expensive case this instrument exists to read.

SO THE CARRIER HOLDS BOTH. ParseProductionMeasured carries the outcome and the accounting side by
side, and both refusal arms report. The unmeasured entry points are retained as PROJECTIONS of the
measured fold -- parse_production_prepared, parse_module_prepared and
program_assembly_phase_parse are `.outcome` of it -- so there is one implementation, no caller pays
a second parse to be measured, and the five existing parse_module_prepared test callers are
untouched.

ONE ARM IS SPELLED OUT RATHER THAN REUSED, and the reason is stated beside it:
program_assembly_phase_parse_measured cannot route through bind_outcome, because bind_outcome
cannot carry a second value out of the bound function. Its Rejected arm passes the diagnostics
through untouched and reports EMPTY accounting -- zero because no parse ran, which is an answer and
not a missing measurement -- and its Accepted arm merges through bind_outcome_accepted, which is
what bind_outcome itself calls. A void grammar likewise reports empty rather than absent stats, so
a void parse is distinguishable from a parse whose stats were dropped.

The driver prints the three counters per file in [native-context-split] and their totals in
[native-context-partition], read OUTSIDE every phase span so they price none of them.

NOT YET COMPILED AS AN EMITTED CRATE. Both modules typecheck under the whole dag + src/v2 closure
and required-regen reaches first_generation_equal, but the emitted crate build -- the only check
that catches the boxed-carrier class this branch already filed -- needs the route to build on main,
which waits on #11216. No measurement is claimed from this commit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019gufjy7FmMzjTRwAnUgZcZ
@gunbai-bot

gunbai-bot Bot commented Sep 13, 2026 •

Copy link
Copy Markdown
Contributor Author

Full-N route receipt SUCC6 (post-landing acceptance for this repair). Subject 4011bf9dbf8f3b9e545d86887f0b47a6eb43f783 (tree c0b0607e…), applicable to the landed head 6511f69c by the listed tree diff (src/ subtree identical at tree cbc8793f…; the three recurring_failure_mode rows each dispositioned: not in the closure manifest, not test declarations, no bare-name collisions); host srv2; driver exe sha256 542a5c4e7abfdb13… (= this head's emitted binary and the srv1 proof); spawn 22:40:59Z, route exit rc=1 at 00:36:47Z; host-facts sha256 1911114e… identical at spawn and termination.

Verdict: REFUSED RemainderExceedsTolerance { residual 244,833,742 ns, tolerance 50,000,000 } — this execution no longer produces the previous net over-attribution result (the exclusivity of the repaired preparation endpoint rests on its source justification, not on any per-row size observation, which cannot show non-overlap), and the residual is now a measured quantity.

Partition (parent 6,894.737 s): prepare 4,639.503 s · context 2,140.000 s · receipt_admission 97.461 s · universe_derivation 17.123 s · eval 0.229 s · load 0.100 s · row_serialization 0.075 s · module_release 0.002 s. prepare_ok 138 / refused 576; unique_modules 714; identities 3,629; closure 2,237; corpus_reads 5,579.

Semantic result: rows file 3,841 lines, sha256 3dbd84e00e4a6916… — byte-identical to SUCC3 (45a9105) and SUCC4 (85dd87a): 1 identity executed with a verdict (the literal-bodied smoke test), 3,628 refused-classified (prepare 2,827 / eval 328 / context 473), 212 file refusals.

Readings: module_release measures 1.9 ms, so the release hypothesis for the residual is falsified by measurement (the row stays as a real span; it does not explain the ~245 ms; the SUCC3 and SUCC6 residuals differ by 6.33 ms (~2.7%) — two observations, corroborating a recurring omitted operation, not a stability characterization). universe_derivation fell from ~123 s (SUCC3/SUCC4) to 17.1 s on the same population — the keyed lookups from review 64753. The unattributed ~240 ms is to be named as further measured rows in a follow-up; the tolerance is unchanged.

— sent from eager-raven-113

Edited 2026-09-13 ~01:40Z: narrowed the exclusivity and stability sentences (side-chat corrections); the ~343 µs/module figure elsewhere in this thread is a conditional average under the relay hypothesis, not an observed emission cost, and no residual figure is a quota. — sent from eager-raven-113

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