Skip to content

Identity-bearing required-lens registration, and a closed registration/observation join at the compile door - #11004

Merged
briansrls merged 27 commits into
mainfrom
session/calm-crane-722
Sep 12, 2026
Merged

briansrls merged 27 commits into
mainfrom
session/calm-crane-722

Conversation

@briansrls

@briansrls briansrls commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Step 1 of the compile-obligation activation brief (ACT lane, work item adhoc-74a1fd50-8f9): the substrate everything else keys on — the required-lens roster names its lenses, and registration/observation is one closed, machine-checkable join.

What changed

  • One registration roster. required_compile_lens_roster carries all eight required lenses, each as CompileLens { identity: DeclarationRef, grain, gate }. required_lenses_at_grain derives the two execution partitions; always_required_lenses / always_required_root_lenses are deleted at the root and their five consumers cut over.
  • Witnesses name their producer. LensGateWitness { lens, grain, witness }.
  • The join refuses by name. join_required_lens_coverage → RequiredLensCoverageClosed { roster_digest, rows } or RequiredLensCoverageRefused { cause }, with causes RequiredLensRosterEmpty | RegistrationDuplicated | RegistrationUnobserved | ObservationUnregistered | ObservedAtWrongGrain | RootLensObservedMoreThanOnce. Root grain states exactly-one; subtree grain is at-least-one, because subtree registrations are observed once per node by construction — stating exactly-one for both would refuse every tree with more than one node.
  • The door gates on it. validate_then_compile runs each lens at its registered grain (caller-supplied lenses included — they previously ran at root whatever grain they declared), derives the coverage from the witnesses it collected, and refuses the compile when it is not closed. Validated carries the receipt.
  • Joins go through map_lookup on the display key, never map_keys (the determinism lens registered here refuses key-order reads), and are linear in the observation count.

Divergence, stated (DESIGN §3b)

The brief named a new RequiredCompileLens beside CompileLens. Requiredness is membership in the roster, not a property of the carrier — and a caller-supplied lens has the same three facts and must stamp its witnesses identically for the join to be closed at all — so one carrier gains the two fields instead of a second type being minted.

Evidence, by execution

claim_batch --source-root dag --source-root src/v2, local release build.

v2.test.lens_application.required_lens_coverage_join — 7 green:

  • required_lens_coverage_closes_on_complete_observations_holds (positive control over the real roster, digest asserted)
  • required_lens_coverage_closes_over_executed_gates_holds — runs all eight registered gates through the door's own two runners and joins the witnesses they actually stamped
  • five discriminating REDs, one per refusal arm, each asserting the cause and the lens identity

The eight touched pre-existing lens witnesses: all green (rejecting_lens_blocks_before_compile, enforce_rejecting_gate_fires, introspect_clean_tree_passes, apply_lens_introspect_rejection_is_advisory, empty_required_lenses_skip_gate, hollow_alias_blocked_via_always_required_lenses, unit_modeling_blocked_via_always_required_lenses, modeled_unit_field_admitted_via_always_required_lenses).

Not established, and not claimed (DESIGN §4b rung honesty)

An Accepted validate_then_compile carrying the receipt. No fixture in this corpus reaches Accepted through that door today — measured on fixture_add_resolved_tree in both TranslateTo (stub target) and Eval, where the refusal is upstream of the lens rosters and names neither compile_pipeline_not_realized nor compile_lens_gate_rejected. The door-grain positive control is a declared frontier whose trigger is a route that reaches Accepted through the door — the activation authority's Executed→Qualified step. The frontier is recorded in the test module header, not only here.

Side finding for the census lane: door_root_roster_runs_and_passes_clean_tree in v2.test.long.accumulator_copy_compile_gate is green on a fixture the door rejects — its assertion tolerates any rejection that is not the poly2 suspect.

Follow-ups from the brief (separate PRs): the all-lens introspection ledger, the activation authority compile_obligation_activation.dag, the complexity bundle, and receipts into promotion admission. The census join (every registration has one census row) waits on gunbc.v2_compile_obligation_census landing.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RPVTQBSK9E8j3UDQGPZN1f

Brian Searls and others added 3 commits September 11, 2026 02:10
…n/observation join at the compile door

Step 1 of the compile-obligation activation brief: make the required-lens
roster name its lenses, so "the required lenses ran" stops being a claim
about a list length.

- One registration roster (required_compile_lens_roster), partitioned by
  grain through required_lenses_at_grain, replaces the two lists
  always_required_lenses / always_required_root_lenses. Each row carries
  the DeclarationRef of the gate authority that decides it plus its grain.
- LensGateWitness carries the lens identity and the grain it was produced
  at, so every observation names its producer.
- join_required_lens_coverage closes the join bidirectionally and refuses
  by name: RequiredLensRosterEmpty, RegistrationDuplicated,
  RegistrationUnobserved, ObservationUnregistered, ObservedAtWrongGrain,
  RootLensObservedMoreThanOnce. Root grain states exactly-one; subtree
  grain is at-least-one, because subtree registrations are observed once
  per node by construction.
- validate_then_compile runs each lens at its registered grain (caller
  lenses included, which previously ran at root whatever they declared),
  derives the coverage from the witnesses it actually collected, and
  refuses the compile when it is not closed. Validated carries the
  receipt with the roster digest.

Divergence from the brief, stated: one CompileLens carrier gains the two
fields rather than a second RequiredCompileLens type. Requiredness is
membership in the roster, not a property of the carrier, and a caller
lens must stamp its witnesses the same way for the join to be closed.

Evidence, by execution (claim_batch, local release build):
- v2.test.lens_application.required_lens_coverage_join: 7 witnesses green
  - one positive control over the real roster,
  - one control that runs all eight registered gates through the door's
    own two runners and joins the witnesses they actually stamped,
  - five discriminating REDs, one per refusal arm, each asserting the
    cause AND the lens identity.
- the eight touched pre-existing lens witnesses: all green.

Not established, and not claimed: an Accepted validate_then_compile
carrying the receipt. No fixture in this corpus reaches Accepted through
that door today (measured on fixture_add_resolved_tree in TranslateTo and
Eval; the refusal is upstream of the lens rosters). That frontier is
recorded in the test module's header.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPVTQBSK9E8j3UDQGPZN1f
@gunbai-bot gunbai-bot Bot changed the title Self-host compile-obligation activation, complexity first: a new authority src/v2/compiler/self_host/compile_obligation_activation.dag (shared compile door + one explicit node per required compile lens, complexity and determinism bundles carrying their supporting obligations), identity-bearing requi Identity-bearing required-lens registration, and a closed registration/observation join at the compile door Sep 11, 2026
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review September 11, 2026 03:49
Brian Searls and others added 2 commits September 11, 2026 04:04
…iminates (test-only)

door_root_roster_runs_and_passes_clean_tree called validate_then_compile and
accepted EITHER an Accepted compile OR any Rejected whose diagnostics lacked
the poly2 suspect. Measured: the door REFUSES this fixture, so the check was
green on a refusal and would have stayed green if the root roster had stopped
running altogether — a permanently-green check cited as coverage (DESIGN §4b).

The refusal is now located, and it is neither infer nor the root roster:
infer Accepts fixture_add_resolved_tree, the root-required roster Accepts the
inferred tree, and the SUBTREE-grain roster refuses it.

So the control becomes door_root_roster_accepts_clean_inferred_tree: infer
must Accept and every root-registered gate must Accept the real inferred
tree, with no tolerance for an unrelated refusal. The module header's claim
that the fixture "passes through the root-required roster ... proving the
roster RUNS on every door call" is corrected to the root-roster claim it
actually supports, and the now-unused stub target and its imports are removed.

The door-grain positive control (an Accepted validate_then_compile carrying
its coverage receipt) stays a declared frontier in
v2.test.lens_application.required_lens_coverage_join.

Evidence: door_root_roster_accepts_clean_inferred_tree PASS. The module's
other three witnesses (gate_red_quadratic_rejects,
gate_green_identity_accepts_clean, gate_refusal_ledger_counted_not_gating)
fail on the interpreted path with "no field 'kind' on type 'NormalizedTree'"
BEFORE this change as well — verified by running them on the committed file —
so they are untouched by it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPVTQBSK9E8j3UDQGPZN1f
gunbc.witness_deferral_freeze names (entry, function) pairs at identity
grain and REFUSES a row naming a witness the tree no longer carries as a
stale freeze row. Renaming door_root_roster_runs_and_passes_clean_tree in
the previous commit made its row stale, so the roster's own wall would
fire on this branch. One field, the new name.

This also explains why the re-scoped control's three sibling witnesses in
the same entry were red without anyone noticing: the whole entry is a
LegacyFrozenPathDeferral, i.e. admitted by path policy with no executing
consumer.

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

gunbai-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

srv2 167-member closure receipt (closure-neutral; emitted compiler builds with the new 00_compile.dag root)

Provenance. main 267d69b86c; PR head at fetch 8825767f overlaid as commit 6f0c9c7b; the two later pushes (f6a16f96, e8f49dc7) differ from 8825767f only in src/v2/test/claim/long/accumulator_copy_compile_gate_test.dag and one renamed field in dag/gunbc/witness/witness_deferral_freeze.dag, neither a closure source, so this receipt carries to e8f49dc7. Producer = pinned claim_executor sha256 87a69424ab1060de built from the overlaid tree, --v2-native-route --source-root dag --source-root src/v2 (post-#11003 route). Emission: 172 files, closure bb946c9d…, emitted compiler built to sha256 85d22ab3…. Closure fold wall 283.4 s, rss 1.23 GB.

Result. 66 refusing closure members, 0 regressed, after-set IDENTICAL row-for-row to the #10988 recovery baseline on the same main (68 -> 66 vs the immutable 2fb67b41 reference is main's D1+G effect, not this PR's). The rewrite of the lens-registration roster and validate_then_compile in src/v2/compiler/00_compile.dag changes no closure member's acceptance and the emitted whole compiler still builds.

Not established here: whole-v2.test.* admission; the drop gunbc.rung_drop v2_native_route_off_the_merge_path is not retired by this receipt. Voided by any push touching src/v2/{compiler,std,lens,extdeps}, dag/std or dag/extdeps.

…prohibition forward (review 63457)

Two findings, both real, both verified against the current tree.

1. STALE CITATIONS. required_lens_grain_note was re-asserted verbatim while
both symbols it is about — always_required_lenses and
always_required_root_lenses — were deleted in the same diff, and five more
prose sites named them too. A replacement migration that cuts over at the
root owes the citation cut-over in the same motion (DESIGN §3 standing
rule). The note is rewritten to carry the same cost argument in terms of
what survives — a CompileLensSubtree registration runs per subtree node, a
CompileLensRoot registration runs once at the root, grain is a FIELD and
required_lenses_at_grain derives each execution's list — and it now also
records that a caller-supplied lens runs at its own declared grain. The
other five: v2.lens.determinism, v2.lens.mandatory_tag,
v2.lens.mandatory_tag.corpus_scan, v2.lens.machine_shape,
v2.lens.undecidable_verdict_collapse, v1.compiler.emit_rust,
gunbc.declaration_index_seed_growth, and
test.claim.computation_demand_duplication_witness.

2. DROPPED PROHIBITION. The lens_module_gate de-enrollment rationale was
deleted with the old root roster and nothing carried it forward — a standing
prohibition tied to a named red class (lying_substrate_inputs_only_stamp_census,
31 stamps). Worse, the replacement text invited the regression it warned
about ("Adding a lens is one row") with no eligibility statement. It is
carried forward in force beside the roster, plus the eligibility rule it
implies: a row must be a PURE FOLD OVER THE TREE BEING COMPILED at its
declared grain; a nullary gate, a corpus scan, or any gate reading the live
tree rather than its InferredTree argument is ineligible at either grain.

Not done, and stated rather than left silent: three test MODULES still carry
the deleted symbol in their own names
(lens_fact_density.hollow_alias_blocked_via_always_required_lenses and the two
lens_unit_modeling siblings). Renaming them is a file-and-module rename whose
citations include gunbc.live_deploy.srv1_residue_rehearsal — a RECORDED PATH
WIRE, i.e. an observation receipt — and dag/gunbc/witness/witness_row_cost_basis.tsv.
Editing a recorded observation to match a rename is not a citation repair, so
that cut is its own change.

Evidence: the coverage-join witnesses re-run green after the edits
(required_lens_coverage_closes_over_executed_gates_holds,
required_lens_coverage_refuses_unobserved_registration_holds).

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

gunbai-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Both findings in review 63457 verified against the current tree and fixed in 0230f764b75.

1. Stale citations — confirmed, and wider than the note. required_lens_grain_note was re-asserted verbatim while both symbols it is about were deleted in the same diff. git grep across the tree found five further prose sites naming them. The note is rewritten to carry the same cost argument in terms of what survives — a CompileLensSubtree registration runs per subtree node (node-local predicates, a nested walk inside the gate would stack with run_required_lens_gates_on_subtree's fold_node and be O(n²)); a CompileLensRoot registration runs once at the root (rooted whole-tree walks, where per-node invocation would be O(n²)); grain is a field, and required_lenses_at_grain derives each execution's list from the one roster, so the cost argument is carried by the row rather than by which of two lists a lens was written into. It also now records the behaviour change the diff introduced: a caller-supplied lens runs at its own declared grain.

Also cut over: v2.lens.determinism, v2.lens.mandatory_tag, v2.lens.mandatory_tag.corpus_scan, v2.lens.machine_shape, v2.lens.undecidable_verdict_collapse, v1.compiler.emit_rust, gunbc.declaration_index_seed_growth, test.claim.computation_demand_duplication_witness.

2. Dropped prohibition — confirmed, and the new text did invite the regression. The lens_module_gate de-enrollment rationale is carried forward in force beside the roster, with its named red class (lying_substrate_inputs_only_stamp_census, 31 stamps) and its honestly-stamped replacement consumer. Because "adding a lens is one row" otherwise reads as an invitation, the eligibility rule it implies is now stated explicitly: a row must be a pure fold over the tree being compiled at its declared grain; a nullary gate, a corpus scan, or any gate that reads the live tree rather than its InferredTree argument is ineligible at either grain — a corpus-grain invariant enrolls on the corpus cadence with a ReadsLiveTree stamp, never in the per-tree door.

Not done, stated rather than left silent. Three test modules still carry the deleted symbol in their own names (lens_fact_density.hollow_alias_blocked_via_always_required_lenses and the two lens_unit_modeling siblings). Renaming them is a file-and-module rename whose citations include gunbc.live_deploy.srv1_residue_rehearsal — a recorded path wire, i.e. an observation receipt — and dag/gunbc/witness/witness_row_cost_basis.tsv. Editing a recorded observation so it matches a later rename is not a citation repair, so that cut is its own change rather than a hunk in this one.

Evidence: the coverage-join witnesses re-run green after the edits (required_lens_coverage_closes_over_executed_gates_holds, required_lens_coverage_refuses_unobserved_registration_holds).

— sent from calm-crane-722

git add -A in the citation-cutover commit swept two untracked 4a files that
had followed a branch switch into the worktree: dag/std/realization_cost_fidelity.dag
and dag/test/claim/realization_cost_fidelity_witness_test.dag. Neither belongs
here — 4a's design was still undecided when they were committed, and this PR is
registration plus the citation cutover plus the de-enrollment prohibition and
nothing else. They move to their own branch and land after their own closure
receipt.

The other three files in that commit stay: declaration_index_seed_growth,
computation_demand_duplication_witness_test and v1.compiler.emit_rust are
one-to-three-line citation cutovers of the deleted roster symbols, which is
exactly what review 63457 asked for.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPVTQBSK9E8j3UDQGPZN1f
gunbai-bot Bot pushed a commit that referenced this pull request Sep 11, 2026
…465)

The SPECIMEN receipt named v2.test.lens_application.required_lens_coverage_join
as the home of the door-grain frontier. That module is declared in #11004,
which is not merged, so on this branch and on base the citation resolves to
nothing — the exact defect DESIGN §3's standing rule exists to prevent, and it
was load-bearing for the row's "wall behind that frontier" claim.

The row now states the CONSEQUENCE instead of pointing at a file: while a
mandatory gate refuses the corpus its door must admit, a door-grain positive
control is not authorable at all, so any coverage receipt attached to that
door necessarily lands with its positive control declared as a frontier. The
link is the class, not the file name, and the row says explicitly why it does
not cite the module. Nothing else changes; every remaining citation in both
rows resolves on main.

Verified: the module resolves and evaluates (gunbc run reaching `authored`'s
arity check, i.e. past parse and typecheck).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPVTQBSK9E8j3UDQGPZN1f
Both verified; both were real.

- v2.test.long.mandatory_tag_gate_witness: the file is already in this diff
  (its import moved to required_lenses_at_grain / CompileLensRoot), so its
  prose and its code disagreed inside one file. Now "the CompileLensRoot
  partition of required_compile_lens_roster".

- docs/plans/determinism-boundary-relative.md: the citation sits inside a
  block the file's own header declares "preserved verbatim" from a DESIGN.md
  row deleted on operator ruling. Rewriting a symbol inside a quotation
  falsifies the quotation, so the quoted sentence is left as authored and the
  current symbol is named beside it in brackets — the same reason the three
  test-module renames are not folded into this PR.

Remaining hits are src/v1/stage0/**, the seed's own mirror of this module,
addressed on the PR rather than edited here.

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

gunbai-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Both fixed in ced80f419a9, and one correction to the aside.

src/v2/test/claim/long/mandatory_tag_gate_witness_test.dag:24 — confirmed, and the sharpest form of the finding: the file is already in this diff (its import moved to required_lenses_at_grain / CompileLensRoot), so prose and code disagreed inside one file. Now reads "the CompileLensRoot partition of required_compile_lens_roster".

docs/plans/determinism-boundary-relative.md:8 — confirmed, fixed differently, and the difference is deliberate. That citation sits inside a block the file's own header declares "preserved verbatim from that row" (a DESIGN.md row deleted on operator ruling 2026-08-18). Rewriting a symbol inside a quotation falsifies the quotation, so the quoted sentence is left as authored and the current symbol is named beside it in brackets: always_required_root_lenses [since #11004 that roster is required_compile_lens_roster, read at CompileLensRoot grain through required_lenses_at_grain; the sentence is preserved as authored and the current symbol is named here rather than rewritten into the quotation]. §3 is satisfied — a reader greps a symbol that resolves — without editing a record. Same reasoning as the three test-module renames deferred out of this PR, whose citations include a recorded path wire.

You misread the stage0 hits, and it is worth knowing in which direction. src/v1/stage0/src/v2_compiler_compile.rs is not a generated snapshot: its own header says "Seed realization for v2.compiler.compile (Wave 2 Gate-A flip). Hand-retained Rust oracle — independent of the self-emitted artifact under test. Dissolve-on: self-emit cutover retires this module…". So it is hand-retained, and it carries the pre-PR required_lens_grain_note string verbatim — a real divergence between the .dag authority and its seed oracle, not an out-of-scope artifact.

I am not fixing it in this PR, and the reason is not scope-aversion: that module is the independent oracle this change is checked against, and editing the oracle in the same push as the subject removes the independence for exactly the run that matters. It also widens a registration change into a seed edit whose bootstrap blast radius is its own review. It is reported to the lane owner as its own item; if the call is to fold it in, say so and it is one string.

git grep -n always_required_root_lenses now returns only those stage0 hits and the bracketed editorial note above.

— sent from calm-crane-722

@gunbai-bot

gunbai-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

srv2 167-member closure receipt, re-taken at afdec358 (carries to ced80f41)

Supersedes the receipt above (which was taken on 8825767f, before the review-63457 citation cutover touched six closure-source files).

Provenance. main 0267f385 (D1+G plus the #10978 failure-mode row, which touches no closure source); PR head afdec358 overlaid as commit bb9260a0; pinned claim_executor sha256 4a065e03a7fb2fdc built from the overlaid tree, --v2-native-route --source-root dag --source-root src/v2 (post-#11003 route); emitted compiler built to sha256 c03f6e73…. Closure fold wall 284.1 s, rss 1.23 GB. ced80f41 differs from afdec358 in one test-file prose line and one docs-plan line, neither a closure source, so this receipt binds to ced80f41.

Result. 66 refusing closure members, 0 regressed, after-set IDENTICAL row-for-row to the #10988 recovery baseline (the 66-row set on the post-D1+G main). The registration roster rewrite, the citation cutover across 00_compile.dag and five lens modules, and the carried-forward de-enrollment prohibition change no closure member's acceptance, and the emitted whole compiler builds.

Not established: whole-v2.test.* admission; gunbc.rung_drop v2_native_route_off_the_merge_path is not retired by this receipt. Voided by any further push touching src/v2/{compiler,std,lens,extdeps}, dag/std or dag/extdeps.

Brian Searls and others added 2 commits September 11, 2026 05:11
…, not documentation (review 63517)

I argued the opposite an hour ago and I was wrong, for a reason worth writing
down: I reasoned from a general principle — do not edit the independent oracle
in the same push as its subject — without checking whether anything ASSERTS
EQUALITY on the string. Something does.

dag/gunbc/instruments/self_host_00_compile_shims/witness_main.rs compares
emitted::required_lens_grain_note() against seed::required_lens_grain_note()
and makes equality the Gate-A behavioral receipt. So this literal is not a
mirror of the authority for a reader's benefit; it is the value the self-host
equivalence claim is made of. Changing the .dag without it does not preserve
the oracle's independence — it falsifies the receipt my own change is supposed
to keep true. The reviewer measured the divergence (1288 vs 934) that I had
asserted away.

The seed literal is DERIVED from the .dag line rather than retyped, and
byte-equality verified programmatically: equal? True, 1288 == 1288. cargo check
on the seed lib is clean.

The oracle's header now says what it actually is — the compared value, which
cuts over with the authority — so the next reader does not repeat my reasoning
about independence.

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

gunbai-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

review 63517 is right and I am reversing my earlier position on this PR. Fixed in cd7388c36f7.

What I got wrong, and why it is worth stating rather than just patching. Earlier in this PR I argued the opposite — that the stage0 oracle should not be cut over here, because editing the independent oracle in the same push as its subject removes the independence for exactly the run that matters. That reasoning is sound in general. It is wrong for this string, and I never checked the one thing that decides it: whether anything asserts equality on it.

Something does. dag/gunbc/instruments/self_host_00_compile_shims/witness_main.rs compares emitted::required_lens_grain_note() against seed::required_lens_grain_note() and makes that equality the Gate-A behavioral receipt. So the literal is not a mirror of the authority for a reader's benefit — it is the value the self-host equivalence claim is made of. Changing the .dag without it does not preserve the oracle's independence; it falsifies the receipt my own change exists to keep true. You measured the divergence (1288 vs 934); I had asserted it away from a principle.

The fix, and how it was verified rather than eyeballed. The seed literal is derived from the .dag line programmatically rather than retyped, then byte-compared: equal? True, 1288 == 1288. cargo check --release -p v1-compiler --lib is clean.

I also changed the oracle's header to say what it actually is, so the next reader does not repeat my reasoning:

The Gate-A behavioral witness (dag/gunbc/instruments/self_host_00_compile_shims) asserts EQUALITY between the emitted artifact and this oracle, so this string is not documentation of the authority — it is the compared value, and it cuts over with it.

One note on the §7 framing, which I think is exactly right and is the part I would have missed even after fixing the string: the seed-retained oracle is the self-host differential, so "do not touch the oracle" and "the oracle must agree with the authority" are not in tension — the oracle is independent in its derivation, not in its content.

— sent from calm-crane-722

@gunbai-bot

gunbai-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

The failing check on cd7388c is not this diff, and I am deliberately not re-running it yet.

What failed: required-witnesses-build, at

error: could not compile `v1-stage0-std-surface` (lib)
  could not execute process `…/_temp/rustup/toolchains/1.93.0-aarch64-unknown-linux-gnu/bin/rustc …`
  No such file or directory (os error 2)
##[error]Process completed with exit code 101.

followed by the runner losing its own action cache:

Can't find 'action.yml' … under '…/_actions/actions-rust-lang/setup-rust-toolchain/v1.16.0'
Can't find 'action.yml' … under '…/_actions/actions/checkout/v5'

So rustc vanished mid-job and the runner's _actions/ directory went with it. On srv1-19. This is the same failure that took #11025's wet lane an hour ago on srv3-15, where the workflow's own toolchain_filesystem_probe captured the joined reading: rustc exists=no at start, ENOENT at use, exists=yes mtime=06:24:39 at end — reinstalled nine minutes after it was needed. Two hosts, same shape, which is the condition that probe's dissolve-on names ("the fleet fixes the toolchain deleter").

Why not re-run now: this PR is held from merge pending the D-train, and when it is released it must re-merge main and take a fresh closure receipt anyway — so a run started now is a run that gets superseded, on a runner pool that is currently the binding constraint for three other PRs and for main itself (main is red on the floor at c047472bf4f with 12 blockers, 11 of them interrupted_before_verdict). Spending a build cycle to produce a result that will be re-produced after the remerge is the wrong trade while the fleet is in this state.

The check will be re-run as part of the post-D4 remerge, which is the point at which its result means something about the head that will actually land.

— sent from calm-crane-722

briansrls pushed a commit that referenced this pull request Sep 11, 2026
…tree, without stopping at the first no

WORK IN PROGRESS, STACKED ON #11004, NOT FOR REVIEW HERE. It is committed so this
branch stops being a verbatim copy of #11004's head; it lands as its own PR from
main once #11004 is in.

The compile door answers a DECISION: the first refusing obligation rejects and
nothing behind it is asked. That is right for a gate and useless for a census —
knowing that one obligation refuses the compiler's own tree says nothing about
the other seven, and "repair it and see" is a serial walk of unknown length.
Complexity-first is a RANKING, and you cannot rank repairs across obligations you
have not measured.

- v2.compiler.compile: the runner gains a MODE PARAMETER rather than a twin.
  run_required_lens_gates_in_mode / _on_subtree_in_mode carry it; the existing
  entry points become thin enforcing callers, so the door's behaviour is
  unchanged. The ledger therefore shares the door's registration AND traversal
  and differs only in the mode argument — a second traversal would be a second
  answer to "what would the door say" and would drift the first time either
  moved (§3).
- v2.compiler.self_host.compile_obligation_ledger: all eight registrations over
  ONE prepared InferredTree, every answer reported, keyed by lens identity and
  grain, carrying the roster digest so two ledgers can be compared.

Four things the module states about itself, each load-bearing:
- It is NOT a gate. It decides nothing and admits nothing, and no consumer may
  read a clean ledger as an accepted compile — validate_then_compile remains the
  single gate authority.
- The tree is prepared ONCE by the caller, and there is deliberately no per-file
  entry point: the corpus roster gate's per-subject path re-tokenizes and
  re-parses every file and is CI-excluded for that cost, so a census built on it
  would be a cost defect wearing a census's name.
- ObligationLedgerUnobservable is a real arm. An observation that could not be
  made is not one that passed, because a vanished row and a holding row are
  indistinguishable in a count (§5).
- Rows stay at observation grain rather than collapsing per registration:
  collapsing discards WHERE a subtree obligation refused, which is the fact a
  repair needs.

This is the production consumer CompileLensIntrospect was built for; until now it
had only witness-level consumers.

Evidence, four witnesses green on the interpreted path — and that is the ENTRY
RUNNER's verdict, not the floor's, which is the distinction filed in #11028 and
already wrong once today in exactly this direction. The discriminating control
runs the ledger over a tree the DOOR REFUSES: there the door reports one refusal
and nothing behind it, while the ledger must report every registration, at least
one violating, and the rest still holding. The door's refusal on that tree is
executed as its own premise control, so if it ever goes green the control
announces that it has stopped discriminating.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPVTQBSK9E8j3UDQGPZN1f
briansrls pushed a commit that referenced this pull request Sep 11, 2026
… receipt and none is authored

LOCAL COMMIT, NOT PUSHED, on the step-2 ledger branch under the same terms you
approved for step 2: authored against #11004's frozen API, becomes a
branch-from-main when #11004 lands.

All eight required compile lenses are ALREADY registered and ALREADY run on every
validate_then_compile call. Nothing here adds a switch, a flag, or an enrolment
step, because none is missing. What is missing is EVIDENCE, so this authority is
a derivation from receipts to a state and the state is never authored: a data row
saying "accumulator_copy: Qualified" would be a claim with no producer, which is
the rung inflation §4b names.

THE LADDER, and only the last three are on: Registered, Reached, Executed,
Qualified, Observed, ClosureClosed, CandidateEnforced, SuccessorEnforced,
SeedIndependent. Each rung requires its own receipt AND every receipt below it,
so a late receipt supplied early cannot lift a missing foundation — which is how
an activation board comes to read higher than the system it describes.

Four things the design insists on, each with a control that withholds exactly
one receipt:

- QUALIFICATION IS TWO RECEIPTS. A gate that refuses everything refuses the
  planted red too, so a caught red alone establishes nothing; the accepted green
  is what separates a wall from a wall that is permanently down. Withholding only
  the green drops the state to Executed.
- UNCLASSIFIABLE RESIDUE CLOSES THE CLOSURE ONLY IF CARRIED BY NAME. Silent
  residue holds it open; named residue is open coverage someone can close.
- A BUNDLE REPORTS ITS WEAKEST MEMBER (§4b(1) applied to a group). Complexity is
  the accumulator-copy gate AND the realization-cost fidelity join; determinism is
  the gate AND the traversal-order facts AND non-primitive reachability, because
  absence from a declared roster is not evidence of determinism.
- THE PROGRAM IS ITS WEAKEST OBLIGATION. No average, no count, no majority: seven
  qualified and one registered is a program at Registered, because the door admits
  a program only if every required obligation admitted it.

Coverage joins both directions — a node with no registration is a board row with
no subject, a registration with no node is an obligation nobody tracks — and both
refuse rather than go quiet, exactly as the door's own registration/observation
join does.

The ledger supplies the Observed receipt and nothing else: it can raise an
obligation to Observed and can never raise it past ClosureClosed, because what it
reports is what the obligation SAID, and whether findings were repaired is a
different fact with a different producer.

Thirteen witnesses green on the interpreted path — the entry runner's verdict,
not the floor's.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPVTQBSK9E8j3UDQGPZN1f
gunbai-bot Bot pushed a commit that referenced this pull request Sep 11, 2026
…mar (review 63628)

LOCAL COMMIT, NOT PUSHED: #11026 is held and under a no-push rule. Committed so
the work does not follow a branch switch, which is how the 4a drafts leaked into
#11004 earlier today.

std.induction already owns a sum-of-products cost algebra over named parameters:
AtomicCost (PolyCost { param, exponent } / LogCost { param }), ProductBound,
SumOfProductsBound — and owns it more completely than what I wrote, since
PolynomialExponent carries fractional and log-based exponents my four-factor
grammar could not express. The equivalences are exact: cost_nlogn IS
linearithmic, and cost_graph_linear IS the concat specimen, already in the
corpus.

So I minted a second cost grammar — §2 failed decomposition, §3 nicknaming — in
the change that argued a second cost vocabulary beside a consumer is the fork §3
forbids, in a module whose subject is a cost authority disagreeing with itself. I
DFS'd CostShape and stopped there instead of following the concept DAG one step
further.

- std.algebra: CostFactor / CostTerm / StructuredCost deleted; CostShape stays,
  with an annotation recording the failed decomposition and naming CostBound.
- std.induction: AtomicCost gains CallerBodyCost { param } plus cost_iterate_body
  — the one fact genuinely absent, and the reason a projection from this
  authority could not reach ShapeIterateBody at all. Nothing outside
  induction.dag matches on AtomicCost, so the arm adds no obligation elsewhere.
- The growth derivation and the CostShape projection move to std.induction,
  beside the carrier they read: ParamGrowth { degree, logs, bodies,
  representable }, lexicographic on (degree, logs), body held out of the order,
  and representable:false for fractional exponents, log-based exponents,
  ForeverBound and ErrorBound — a real bound this reading cannot order says so
  rather than rounding.
- The join consumes CostBound and speaks its vocabulary (param_*, not operand_*):
  having renamed the authority, keeping a second name for its parameters would be
  the same defect one scale down.

Nineteen witnesses green, every verdict preserved across the migration, plus one
control that only became AUTHORABLE on the richer authority: cost_sqrt exists in
std.induction, and a fractional exponent must not round to a shape.

The specimen witness now reads cost_graph_linear(v_param: "left", e_param:
"right") — a constructor that was already there, which is the plainest statement
of what the review caught.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPVTQBSK9E8j3UDQGPZN1f
Brian Searls and others added 2 commits September 11, 2026 12:45
…L, CITED-DECLARATION-ABSENT)

required-ci: declarations FAIL CITED-DECLARATION-ABSENT
  dag/gunbc/recurring_failure_mode/stale_present_tense_coverage_claim_in_the_authority_consulted_first.dag:47:5
  cites v2.compiler.compile always_required_root_lenses, which that module does not declare

Mine, and the same class I swept eight sites of in this PR: a replacement
migration owes the citation cut-over. The reason this one was missed is worth
recording — the row did not exist when I swept. It landed on main afterwards with
#10942 (the compile-obligation census), citing a symbol this PR deletes at its
root, so the break appeared in the merge rather than in either change. Neither
lane could have seen it alone: the census cited a declaration that was live on
main, and my sweep covered every citation that existed at the time.

- The evidence decl_ref now names required_compile_lens_roster, which is what
  replaced it and what the row's argument is actually about.
- The row's prose cited the same symbol in its specimen sentence and cuts over
  with it.
- gunbc.v2_compile_obligation_census names the deleted symbol in two annotations;
  both now name the surviving roster, and the one about staleness says explicitly
  that the argument does not turn on there having been two lists.

Deliberately untouched: the census's entry/function/module_path rows for
hollow_alias_blocked_via_always_required_lenses and its two siblings. Those are
module and function IDENTITIES that still resolve, not symbol citations — their
rename is the separate cut whose citations include a recorded path wire.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPVTQBSK9E8j3UDQGPZN1f
… cuts over (review 63812)

1. MY OWN HEADER CLAIMED SOMETHING FALSE. The module said "one discriminating RED
per refusal arm" and the PR body said "five discriminating REDs, one per refusal
arm", while RequiredLensJoinCause has SIX arms. RegistrationDuplicated — the arm
whose whole job is catching a roster that acquired a second row for one identity —
had no control asserting it ever fires.

The "unreachable at the door" defence does not hold, and §4b decides it at the
fixture rather than at the door: a state unrepresentable in the accepted corpus
may still be representable as source handed to the join by a fixture, and where
the refusal is authorable there, declining it is specification without execution.
The sibling REDs already hand the join synthetic rosters, so it was one call —
append a repeated row — which is what makes the omission indefensible rather than
a judgement call. Eight controls now, and the header claim is true.

2. THE THIRD MERGE-ONLY CITATION TODAY. v2_compile_obligation_census_witness_test
names both deleted symbols in its "what is still not checked" annotation. That
file arrived with #10942 AFTER my citation sweep, so the break exists only in the
merge, exactly like the two the declarations phase caught. It now names
required_compile_lens_roster, and records that the gap it describes never turned
on how many lists there were.

Left alone deliberately, again: the entry/function/module_path rows for
hollow_alias_blocked_via_always_required_lenses. Those are identities that still
resolve, not symbol citations.

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

gunbai-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Both fixed in c6bd401a921.

1. The header claim was false, and I wrote it. RequiredLensJoinCause has six arms; the module header said "one discriminating RED per refusal arm" and the PR body said "five discriminating REDs, one per refusal arm". RegistrationDuplicated — the arm whose entire job is catching a roster that acquired a second row for one identity — had no control asserting it fires. Your grep is right: declaration, reason mapping, construction site, five => false exhaustiveness arms, and nothing that makes it go.

The "unreachable at the door" observation is true and is not a defence, and §4b settles where the question is decided: a state unrepresentable in the ACCEPTED corpus may still be perfectly representable as source handed to the compiler by a fixture… if the refusal is still authorable there, the evidence is enrollable there and declining it is specification-without-execution. The sibling REDs already hand the join synthetic rosters, so this was one call — list_append(required_compile_lens_roster(), [first_root_registration()]) — which is what makes it an omission rather than a judgement call. Eight controls now pass, and the header sentence is true for the first time.

2. The census witness citation. Cut over to required_compile_lens_roster, with the annotation now recording that the gap it describes — no identity join between the census's rows and the roster's contents — never turned on there having been two lists.

That is the third instance today of the same shape, and it is worth naming since it will keep happening: v2_compile_obligation_census_witness_test arrived with #10942 after my citation sweep, citing symbols this PR deletes at their root. Neither lane could see it alone — the census cited declarations that were live on main, and my sweep covered every citation that existed when I swept. The break exists only in the merge, which is why the declarations phase is the only thing that catches it, and only on whichever PR merges second. A row for that class is queued for after this lands.

Untouched deliberately: the entry/function/module_path rows for hollow_alias_blocked_via_always_required_lenses and siblings — module and function identities that still resolve, not symbol citations, and their rename touches a recorded path wire.

— sent from calm-crane-722

… 63827)

The rename in this PR (always_required_root_lenses -> required_compile_lens_roster)
updated seven sibling citations and missed one: the mandatory-tag scaffold comment
in the seed's cli_run.rs still named the deleted symbol as where the modeled lens
is enrolled. At this head it was the only surviving live citation -- the remaining
grep hits are witness function names and module paths, which are not citations of
the symbol.

It now names the registration as it actually stands: required_compile_lens_roster
at CompileLensRoot grain, the mandatory_tag_lens row. That is the point of the
rename -- the grain is a field on the row rather than a fact about which of two
lists a lens was written into -- so the citation has to say the row, not the list.

This is the class the PR itself edits (DESIGN 3: a stale name is decidable and
enforceable).

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

gunbai-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Review 63827's finding is correct and is fixed in c12c66c.

I verified the claim rather than taking it: at c6bd401a92, git grep always_required_root_lenses\|always_required_lenses over src/v1, src/v2 and dag leaves src/v1/stage0/src/cli_run.rs as the only surviving citation of the deleted symbol — the other hits are witness function names (hollow_alias_blocked_via_always_required_lenses_holds) and the module paths those witnesses live at, which name themselves rather than the roster. src/v1/05_emit_rust.dag had already been cut over in this PR, and the hand-retained oracle in src/v1/stage0/src/v2_compiler_compile.rs already carries the new note (it is the compared value for the Gate-A byte-equality witness, so it had to).

The comment now names the registration as it actually stands: required_compile_lens_roster at CompileLensRoot grain, the mandatory_tag_lens row. That wording is deliberate rather than a mechanical substitution — the point of the rename is that the grain is a field on the row instead of a fact about which of two lists a lens was written into, so a citation that named a list would be stale in meaning even if the symbol resolved.

Thank you for checking whether the file was a projection before recommending a hand edit; it is hand-maintained seed Rust, and had it been generated the repair would have belonged in the authority instead.

On the run at this head: the floor's measurement completed (3625 passed, 0 failed) with one identity budget-refused at 507/500 ms cpu while the host was page-thrashing at 300-400k majflt/min — an unobserved host condition rather than a result, so this push's run is the observation.

— sent from calm-crane-722

Brian Searls and others added 2 commits September 11, 2026 14:21
…ed import goes

Review 63842.

The distinction the review draws is the right one and I am keeping it: the JOIN
is consumed by execution in this change -- validate_then_compile refuses a
compile whose coverage is not closed -- so the gate was never the dangling part.
The receipt CARRIED on Validated is a separate declaration with a separate
consumer, and nothing outside this module reads it today.

The prose that was there named a consumer (the obligation census) and stated no
trigger, which is a half-classification: DESIGN section 3c admits a frontier
only with the trigger beside it, precisely so that "a later change will read
this" cannot be said indefinitely. The field now carries consumer, route and
trigger, with the trigger stated as a CAPABILITY -- the promotion path routing
its candidate through this door and refusing on a named uncovered lens,
sufficient that a candidate cannot be promoted without its coverage having been
observed on the same compile that produced it.

It also states the kill condition, because a frontier that cannot expire is not
a classification: if that capability does not land, the field is redundant work
and the honest move is to DELETE it, since the refusal is already the gate.

WholeDeclaration was imported and never used; removed. 8 join controls green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPVTQBSK9E8j3UDQGPZN1f
MEASURED FIRST, because the cut I was about to make was aimed at the wrong
thing. claim_batch over this module's four witnesses in one remote dispatch:
the three source-path rows cost 534-680ms of CPU against a 500ms per-claim
ceiling, while door_root_roster_accepts_clean_inferred_tree -- same gate area,
hand-built node fixture, no front end -- costs 50ms. Three DIFFERENT four-line
snippets spread only ~150ms over a ~530ms base, so the base is the front end
itself, not the snippets. Shrinking the planted ledger could not have moved a
680ms witness under 500ms when its two ledger-free siblings pay 534 and 618 for
the same prefix.

The consequence that matters more than the one failing row: ALL THREE
source-path witnesses here are at or over the ceiling on an unloaded runner.
gate_refusal_ledger_counted_not_gating is not defective beside three healthy
ones; it is the one 80ms above its nearest sibling. Host thrash is why it
trips today, the budget is why it would trip anyway.

THE CUT KEEPS THE SOURCE PATH. The three claims are now nullary producers
enrolled WARM in v2.workflow.floor_pure_producer_share, so the floor forces each
once during strict preparation, outside every per-claim budget, exactly as
v2.test.claim.parse.d1_declaration_grammar_parse does for the identical defect
(seven of its eight rows were interrupted at this same ceiling). Nothing about
what executes changes: same source, same tokenize, same parse, same normalize,
same tree, paid once.

The alternative -- moving the ledger assertion onto a hand-built fixture --
would have bought the budget by trading what the witness proves, ledger
behaviour on a tree the real front end produced. DESIGN 4b(1) prices that as a
rung drop, not a cost fix.

SEAM CHOICE, and it differs from the d1 precedent deliberately: that module
shares at the PARSE tree because some of its claims name normalize as their
subject, and sharing normalize would stop them executing the stage they claim.
No witness here names any front-end stage -- all three branch on the normalized
root and assert about accumulator_copy_compile_gate -- so the whole front end is
upstream of every subject in this file and the honest seam is its output.

VERIFICATION BOUND, stated because it is real: claim_batch under my invocation
refuses this module with "no field 'kind' on type 'NormalizedTree'" inside
normalize while the floor accepts it (3625 passed, 0 failed at this head), so I
cannot execute these three witnesses locally at all. What I verified is that
both modules parse in a whole-corpus index and the roster fold evaluates with
the three rows present. Whether the NormalizedProbe value reifies portably is
decided by the floor, and a warm row that refuses to store STOPS THE LINE rather
than degrading -- the precedent shares Outcome<Node>, the same shape class.

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

gunbai-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Pushed 540c92c — the per-claim cost of this PR's touched witness, cut at the place the measurement pointed rather than the place it was first assumed to be.

Why the obvious cut was wrong. The blocker is gate_refusal_ledger_counted_not_gating reaching the 500 ms per-claim CPU ceiling without a terminal verdict (three runs now; the latest log names it outcome=budget-refuse). The intuitive fix is to shrink its planted ledger. Measured with claim_batch over this module's four witnesses in one remote dispatch:

witness cpu path
gate_red_quadratic_rejects 618 ms source → tokenize/parse/normalize → gate
gate_green_identity_accepts_clean 534 ms same
gate_refusal_ledger_counted_not_gating 680 ms same
door_root_roster_accepts_clean_inferred_tree 50 ms node fixture, no front end

Three different four-line snippets spread ~150 ms over a ~530 ms base, so the base is the front end, not the snippets — and the ledger-free siblings pay 534 and 618 for the same prefix. Shrinking the ledger could not have moved a 680 ms witness under 500 ms. The larger fact: all three source-path witnesses here are at or over the ceiling on an unloaded runner. This one is not defective beside three healthy ones; it is the one 80 ms above its nearest sibling. Host thrash is why it trips today; the budget is why it would trip anyway.

The cut keeps the source path. The three claims are now nullary producers enrolled WARM in v2.workflow.floor_pure_producer_share, so strict preparation forces each once, outside every per-claim budget. Same source, same tokenize, same parse, same normalize, same tree — paid once instead of three times. The precedent is v2.test.claim.parse.d1_declaration_grammar_parse, whose annotation records seven of its eight rows interrupted at this same ceiling and repaired the same way.

I did not move the ledger assertion onto a hand-built fixture. That buys the budget by trading what the witness proves — ledger behaviour on a tree the real front end produced — which §4b(1) prices as a rung drop, not a cost fix.

One deliberate divergence from the precedent: d1 shares at the parse tree because some of its claims name normalize as their subject. No witness here names any front-end stage, so the whole front end is upstream of every subject in this file and the honest seam is its output.

Verification bound, stated plainly: claim_batch under my invocation refuses this module with no field 'kind' on type 'NormalizedTree' inside normalize while the floor accepts it (3625 passed, 0 failed), so I cannot execute these three witnesses locally. What I verified is that both modules parse in a whole-corpus index and the roster fold evaluates with the three rows present. Whether the NormalizedProbe value reifies portably is decided by the floor — and a warm row that refuses to store stops the line rather than degrading, which is the correct failure mode but is a real risk, not a formality. The precedent shares Outcome<Node>, the same shape class. That instrument-vs-floor disagreement is being filed separately as a receipt.

Review 63865's approval noted, with nothing actionable in it.

— sent from calm-crane-722

Brian Searls and others added 3 commits September 11, 2026 16:29
…rved value did not survive

MY PREVIOUS COMMIT BROKE THREE PASSING WITNESSES, and this withdraws it. The
floor at 540c92c reports all three accumulator-gate claims failing with
"no field 'kind' on type 'NormalizedTree'", cause=claim_failed. They pass when
each claim derives its own tree. That is a regression I introduced, and a budget
refusal traded for three failing witnesses is strictly worse than the budget
refusal.

WHAT THE EXPERIMENT ESTABLISHED, because it is not nothing. The netting worked
exactly as ruled: disposition=Stored for all three producers during strict
preparation, 868ms, 496ms and 571ms of front end paid outside every per-claim
budget. That is the diagnosis confirmed by execution rather than by argument --
the front end IS the per-claim cost in this module, and the shared-producer tier
does move it.

AND IT RESOLVED THE EARLIER MYSTERY IN THE OTHER DIRECTION. I had reported the
claim_batch-vs-floor disagreement on this module as an instrument quirk, because
the floor was green on the same witnesses my instrument refused. It is not the
instrument: the floor now reports the SAME error the moment the normalized tree
is produced outside the frame that consumes it. Two observations, one mechanism
-- a normalized tree does not survive being handed across that boundary. The
instrument was never the variable, and I said it was.

WHAT RETURNS THE ROWS, as a capability: a normalized tree that survives the
cross-claim serve boundary, so the value a claim is handed is the value it would
have derived. The producers stay as plain helpers -- each claim calls one and
derives its own tree, exactly as before the share -- so this file is now
behaviourally identical to the pre-cut state with the measurement recorded in it.

The per-claim front end therefore stands, and the budget question it raises is a
budget question rather than a witness question. No witness here should be moved
onto a fixture to buy it: that trades what these witnesses prove.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPVTQBSK9E8j3UDQGPZN1f
Semantic-neutral by construction: only names shrank -- module names, the list
binder, the lambda binders. The RED still copies the accumulator through
list_append inside the fold, the GREEN is still its non-copying twin, and the
ledger probe still calls a combiner no registry knows. No arm, type annotation
or call shape was touched, because each of those is what the gate reads. So the
run measures cost and nothing else.

THE PREDICTION IS STATED BEFORE THE MEASUREMENT, so it can be wrong rather than
fitted afterwards. Two points from the earlier lower-bound measurement -- 88
bytes at 534ms, 116 bytes at 618ms -- put the marginal cost near 3ms/byte and
imply about 285ms paid per claim BEFORE a single byte of snippet exists. These
cuts remove 9, 10 and 19 bytes, so the predicted saving is tens of milliseconds
against a worst row that needs 180. Projected: ~591, ~504, ~623 against a 500ms
budget.

If the floor lands them clearly under 500, this model is wrong in the useful
direction -- the front end is superlinear in source size rather than mostly
fixed -- and the sources were the defect after all. If they land near the
projection, the sources were never the defect and the budget grain is, which is
a declared-drop question rather than a witness question.

The floor decides either way: claim_batch cannot measure this module at all,
because it fails at the same serve boundary that broke the withdrawn share.

THE FIXED COST IS THE FINDING, not the saving. ~285ms of front end per claim
before any snippet exists is a section-6 bare-minimum-cost defect in its own
right, and it is the same subject as the serve-boundary work item: netting that
survives consumption is exactly what would delete it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPVTQBSK9E8j3UDQGPZN1f
Review 63901. The note asserted "Witness accumulation on the subtree fold uses
prepend-then-reverse, not append-in-step" while the fold does exactly
append-in-step: list_append(left: child_ws, right: ws) inside step copies the
child's whole accumulated list every step, with one list_reverse at the end.

TWO THINGS COMPOUND AND THE SECOND IS THE ACUTE ONE. The cost shape is real, and
it is the accumulator-copy shape THIS DOOR'S OWN LENS EXISTS TO REFUSE. But the
note is not prose: this PR's own annotation states it is the COMPARED VALUE that
the Gate-A witness asserts byte-equality on. So a false cost claim was green by
equality on both sides -- a check certifying its own wrong description.

I DID NOT "FIX" THE FOLD, and that is a decision rather than an omission.
list_append costs its LEFT operand; the carrier's rc_list_concat copies its RIGHT
one (dag/std/nat.dag already records that asymmetry as a measured cost shape).
Neither the accumulator nor a child's subtree accumulation is reliably the
shorter, so no argument order makes a fold over a tree linear -- it needs a
concat that copies neither operand, which is carrier work. Swapping the operands
would have moved the copy while letting me report the defect fixed, which is the
same species as the claim I am deleting.

So the note now states what the code does, names the shape, says why the repair
is carrier work and not an argument order, and says why it is stated in a
compared value at all. DESIGN section 6 root-causes to the language layer rather
than patching locally; section 5 forbids the fabricated claim regardless.

Byte-equality preserved: both sides carry the identical 2088-byte note, verified
by extracting the .dag string and asserting containment in the oracle rather than
by eye. gunbc compile --entry 00_compile.dag --target dag: 0 blocking errors.

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

gunbai-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Accepted-path measurement, and a correction to my own earlier reasoning on this PR.

The floor at 6b153bf8 produced real accepted-path CPU for the three source-path witnesses:

witness source bytes cpu outcome
gate_red_quadratic_rejects 116 503 ms BUDGET-REFUSED
gate_refusal_ledger_counted_not_gating 109 505 ms BUDGET-REFUSED
gate_green_identity_accepts_clean 88 525 ms BUDGET-REFUSED

The shortest snippet is the slowest. Sizes differ by 32%, costs by 4%, and the ordering is inverted — source size and cost are uncorrelated here.

That refutes the rationale in commit 87a3632. That commit cut the probe sources and predicted ~3 ms/byte, saving 27/30/57 ms. The model was fitted to two lower-bound points from claim_batch runs that died inside normalize; three clean accepted-path points destroy it. The cut is semantic-neutral and harmless, but it bought nothing and its stated premise was wrong — I'm recording that here because a squash drops branch commit messages, so this comment and the PR body are the record that survives. The cut will be reverted in the next push that has to happen anyway, rather than as a push of its own.

What the numbers actually establish, which is more useful than the cut:

  1. All three source-path witnesses are over the line, not one defective witness beside two healthy ones.
  2. The per-claim cost is ~500 ms of fixed front end — dag_language_model plus tokenize/parse/normalize — before any subject-specific work exists.

And the framing I had wrong. These three witnesses are never planned on main: v2/test/claim/long/ is a DeclinedLongModule whose cadence has been declared-unrealized since falsifier.yml was deleted, and no green floor's claim-cost artifact carries a row for this module. The 500 ms line applies here only because this PR touched the file, so the floor planned its rows as changed witnesses, which take the armed line. I was measuring a cost no green floor ever pays and reading it as a defect in the witnesses. It is neither a regression nor debt this PR created.

The corpus already carries the policy for this shape — v2.workflow.required_floor changed_witness_cost_policy implements the FLOOR-CHANGED-COST-0 ruling (a changed witness whose expensiveness is already declared debt runs CpuDeadlineObservedOnly, verdict still gating) — and it simply does not consult the long-lane classification. That is an operator decision and has been escalated; this PR is held pending it rather than working around it.

Separately, review 63901's fix is in 8c80a9a5: the grain note no longer claims prepend-then-reverse for a fold that does append-in-step. I did not swap the operands to make the claim true, because list_append costs its left operand and rc_list_concat copies its right one — no ordering makes a tree fold linear, so swapping would have moved the copy while letting me report it fixed. The repair is a concat that copies neither operand, which is carrier work and tracked separately.

— sent from calm-crane-722

@gunbai-bot

gunbai-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

The snippet cut is now falsified by a paired measurement, not just a cross-sectional one.

Same three witnesses, before and after the cut, both on the floor's accepted path:

witness 6b153bf8 (before) 8c80a9a5 (after cut) Δ bytes removed
gate_red_quadratic_rejects 503 ms 516 ms +13 9
gate_refusal_ledger_counted_not_gating 505 ms 508 ms +3 19
gate_green_identity_accepts_clean 525 ms 507 ms −18 10

Commit 87a3632558 predicted savings of 27/30/57 ms from a ~3 ms/byte marginal model. The actual result is noise in both directions, with two of three slower after removing bytes. Combined with the earlier cross-sectional finding — the 88-byte snippet was the slowest of the three — source size is not a cost term here at all. The cut bought nothing and its premise is refuted twice over; it reverts in the next push.

What the numbers do establish: the per-claim cost is a ~500 ms fixed front end — dag_language_model plus tokenize/parse/normalize, rebuilt in every claim's own evaluation frame — and it is invariant to the subject-specific work the witness actually does.

This PR needs no further fix for it. These three witnesses are never planned on an ordinary floor (v2/test/claim/long/ is a DeclinedLongModule whose cadence has been declared-unrealized since falsifier.yml was deleted; no green floor's claim-cost artifact carries a row for the module). The 500 ms line reaches them only because this PR touched their file, making them changed witnesses — so the floor is reporting interrupted_before_verdict on a cost no green run has ever paid.

The operator ruled on it (A, via fierce-lark-661): changed_witness_cost_policy already implements FLOOR-CHANGED-COST-0 for a changed witness whose expensiveness is declared debt, and simply did not consult the long-lane classification. That arm is #11073, now open. This PR remerges onto it once it lands, folding in the snippet-cut revert and review 63922's identity-join fix.

— sent from calm-crane-722

…verts

Review 63922, plus the revert the measurement earned.

THE COUNT COULD NOT FAIL. Both coverage assertions checked
`length(rows) == length(roster())`, and both sides derive from the same fold
inside join_required_lens_coverage, which emits exactly one row per registration
by construction. The conjunct was structurally green and said nothing about
WHICH lenses were covered -- while the comment beside it claimed the closed rows
are the roster's own identities, which is more than a count establishes. DESIGN
section 5: completeness is an identity join, not a count equality.

The case a count cannot see is concrete: a join that DROPS one registration and
DUPLICATES another keeps the count exactly equal. rows_join_the_roster_exactly
runs the join at (identity, grain) in BOTH directions, because the directions
fail differently -- a registration with no row is a lens that never ran, and a
row naming no registration is coverage claimed for something the roster does not
require. Grain is part of the key rather than a separate assertion: the join's
own ObservedAtWrongGrain arm exists because covered-at-the-wrong-grain is a
different fact from covered.

THE SNIPPET CUT REVERTS BECAUSE IT WAS MEASURED AND BOUGHT NOTHING. Paired
before/after on the same three witnesses: two of the three got SLOWER after
bytes were removed, and the third's gain is the same size as the noise. The
prediction in that commit -- a marginal cost near 3ms/byte -- is refuted, and
cross-sectionally too, since the shortest source is the slowest of the three.
The sources are restored to the forms that read clearly, and the annotation now
carries the measured outcome instead of the prediction: the per-claim cost is a
fixed front end, invariant to the subject-specific work, and it is closed by the
FLOOR-CHANGED-COST-0 long-home arm rather than here.

Both modules compile with 0 blocking errors.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPVTQBSK9E8j3UDQGPZN1f
gunbai-bot Bot added a commit that referenced this pull request Sep 11, 2026
…line repair one of them specifies (#11025)

* Two failure-mode rows from the compile-door measurement, and the one-line repair one of them specifies

Both classes were found by running things during the required-lens
registration work (#11004), and both are filed here rather than there
because a ledger append and a compiler change are separate merge surfaces.

mandatory_gate_refuses_the_corpus_it_is_mandatory_on — a gate registered
as mandatory on a door refuses the very corpus that door exists to admit,
so the door is unreachable and the obligation reads enforced while nothing
passes through it. Specimen, measured: on fixture_add_resolved_tree, infer
ACCEPTS, the root-grain required roster ACCEPTS the inferred tree, and the
subtree-grain roster (fact_density + unit_modeling + lifecycle_carrier)
REFUSES it — in both TranslateTo and Eval. So no fixture in this corpus
reaches Accepted through the v2 compile door. This is the wall behind the
declared frontier in v2.test.lens_application.required_lens_coverage_join,
named as one class so retiring the frontier and repairing this are the same
act. Rung 1, ceiling 2, trigger: the lens-semantics repair.

sole_constructor_wrapper_satisfies_a_typecheck_declared_for_its_payload —
a single-field wrapper value passes a typecheck written for its payload and
then dies at evaluation on a field the payload has and the wrapper does not.
Acceptance coerces, evaluation does not. Rung 1, ceiling 4 (the question is
decidable from the declaration), trigger: the compiler treating carrier and
payload identically at BOTH ends.

The site repair that row specifies lands with it: normalized_of stored the
NormalizedTree normalize returns into a field declared Node, so three
witnesses in v2.test.long.accumulator_copy_compile_gate failed at eval with
"no field 'kind' on type 'NormalizedTree'". `root: normalized.root` turns
all three green — verified red before, green after. The row and the fix land
together deliberately: a fix alone would hide the acceptance hole, a row
alone leaves a red nobody executes.

Why nobody noticed: that entry is a LegacyFrozenPathDeferral in
gunbc.witness_deferral_freeze — admitted by path policy with no executing
consumer — recorded in the row as a second, separate finding.

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

* Drop the unresolvable citation from the mandatory-gate row (review 63465)

The SPECIMEN receipt named v2.test.lens_application.required_lens_coverage_join
as the home of the door-grain frontier. That module is declared in #11004,
which is not merged, so on this branch and on base the citation resolves to
nothing — the exact defect DESIGN §3's standing rule exists to prevent, and it
was load-bearing for the row's "wall behind that frontier" claim.

The row now states the CONSEQUENCE instead of pointing at a file: while a
mandatory gate refuses the corpus its door must admit, a door-grain positive
control is not authorable at all, so any coverage receipt attached to that
door necessarily lands with its positive control declared as a frontier. The
link is the class, not the file name, and the row says explicitly why it does
not cite the module. Nothing else changes; every remaining citation in both
rows resolves on main.

Verified: the module resolves and evaluates (gunbc run reaching `authored`'s
arity check, i.e. past parse and typecheck).

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

* File the deferral finding against the class that owns it (review 63679)

The "WHY IT SURVIVED" receipt described a class that already has a home —
witness_module_absent_from_the_executed_set — from inside a row whose subject is
a coercion hole at a use site. §4b says a newly discovered class files or updates
ONE row; I updated the wrong one. The inconsistency was internal to this PR: its
other row cites [[witness_module_absent_from_the_executed_set]] by name.

The receipt moves there, and carries two things that row did not have:

- A SECOND HARM. Every instance it holds is a correct check whose green is
  wrongly cited as coverage. But a module outside the executed set is equally
  free to BREAK and stay broken: three witnesses in this PR's own subject had
  been failing at eval with "no field 'kind' on type 'NormalizedTree'" for an
  unknown length of time — loud when run, invisible because nothing runs them.
  The repair was one field; the reason it survived was membership.
- A DIFFERENT ADMISSION MECHANISM, which changes detection. The existing
  instances are modules nobody scheduled — a gap, found by joining
  modules-on-disk to modules-scheduled. This one was scheduled OUT, deliberately,
  by path policy, and the roster recording it is honest about what it is. Same
  consequence, but a deferral roster is already a written list of modules whose
  reds nobody will see, and can be read directly rather than derived.

The coercion row keeps only the acceptance hole and links the sibling, with one
line on why they compose: one made the mistake writable, the other made it
invisible, and keeping both in one row buries a membership finding behind a
coercion class where nobody looking for it would read it.

Verified the edited row resolves and typechecks.

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

* The specimen states what it measured, not the universal it was promoted to

Required repair from the landing ruling. The row said "no fixture in this corpus
reaches Accepted through the v2 compile door" on the evidence of ONE fixture in
TWO modes. That is an existential result promoted to a universal: what was
measured is that the compiler's own clean resolved add fixture is refused
upstream of emission on both paths, and the corpus was never enumerated.

THE IRONY IS THE POINT AND THE ROW NOW SAYS SO. This is the claim-wider-than-its
-evidence defect committed inside a row about evidence, in a ledger whose whole
job is to catch it. A row that overstates its own reach is worse than a missing
row, because it will be cited at the reach it claims.

WHAT THE TEXT NOW STATES, at the grain it was measured at: this fixture is
refused on both paths, and NO ACCEPTED POSITIVE CONTROL HAS BEEN PRODUCED for
the door. What it explicitly does NOT claim: that no fixture can reach Accepted.
What the universal would need is named rather than assumed -- a derived, closed
fixture population with the door executed over all of it -- and recorded as
missing measurement, which is the honest state.

The consequence sentence inherited the same over-reach and is scoped with it:
"not authorable at all" and "any coverage receipt NECESSARILY lands" become what
happened -- the obvious candidate does not produce a positive control, so the
coverage receipt attached to that door landed with its positive control declared
as a frontier rather than executed.

The ceiling and the next-rung trigger are unchanged: both were already stated
over the per-gate accepting-traversal control and the lens-semantics repair,
neither of which rested on the universal. The second row on this PR is untouched.

0 blocking errors. The run at the prior head came back success before this push.

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

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Brian Searls and others added 4 commits September 12, 2026 00:03
# Conflicts:
#	dag/gunbc/recurring_failure_mode/stale_present_tense_coverage_claim_in_the_authority_consulted_first.dag
Review 64177, both findings. No behaviour change.

1. `CompileLens.identity` is authored on the row beside `gate` and bound to
it by nothing, so swapping two rows' gates leaves the join closed and the
roster digest unchanged. The module claimed more than that in two places --
"registration and observation form one closed, machine-checkable join" and
a digest that "does not cover the gate function, which is named by the
identity it is registered under". The second sentence asserted precisely
the pairing nothing verifies.

Both now state the honest claim: a gate REGISTERED UNDER this identity ran
at this grain. The residual is recorded at MITIGATION grain with its
ceiling and its next-rung trigger beside the field, per section 4b(2). No
discriminating RED is authorable today and the annotation says why: a
control would have to recover a declaration identity FROM an opaque
function value, and one comparing the authored identity to itself would be
the permanently-green decoration section 4b warns about at the top rung --
worse than absent, because it would be cited as coverage of the gap it does
not close. The trigger is a reified declaration identity for function
values, which makes the field derived rather than authored and collapses
the pair to one fact. The witness module's own "what this does not
establish" roster now names it too, which the reviewer noted it omitted.

2. `first_root_registration` returned the LAST root-grain row: the fold
overwrites `acc` on every `CompileLensRoot`. The controls were unaffected
(they call it on both sides), but the name asserted a position the code did
not have. Renamed to `a_root_grain_registration`, claiming no position at
all, because the contract does not care -- and NOT repaired by returning
the first, since `unregistered_placeholder_lens()` is itself
`CompileLensRoot` and a keep-the-first fold would latch onto the sentinel
and never reach a real row.

Evidence: claim_batch over required_lens_coverage_join, rc=0, 8 PASS;
gunbc compile of v2.compiler.compile, the witness module and the amended
failure-mode row, 0 blocking errors each; docs_projection_gate regen is a
no-op against the committed projection.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPVTQBSK9E8j3UDQGPZN1f
Review 64196, both findings. No behaviour change.

1. The annotation above validate_then_compile said "an obligation that
silently stopped executing stops the line". That is false AT THIS DOOR, and
the reviewer is right about why: both sides of the join come from
required_compile_lens_roster() inside one call. run_required_lens_gates
folds the roster and stamps each witness with the identity and grain of the
row it is folding, so the observation list is a structural image of the
roster rather than an independent reading of it; required_lens_observations
then drops any witness that is not a registration before the join is asked.
RegistrationUnobserved, ObservedAtWrongGrain, RootLensObservedMoreThanOnce
and ObservationUnregistered therefore have no authorable RED here. What can
fire is RegistrationDuplicated and RequiredLensRosterEmpty. An obligation
stops executing by LEAVING THE ROSTER, and a join whose both sides are the
roster cannot see that by construction.

The arms are not decoration -- they are discriminated where their REDs are
authorable, in the fixture-grain suite, which section 4b explicitly
sanctions as the place a compiler's invalid states get expressed. So the
honest statement is about GRAIN: fixture-grain the join discriminates six
ways, door-grain it catches a duplicated or empty roster. The trigger for
the stronger claim is named: an independent observation channel, a receipt
carried out of the runner rather than a list re-derived from the roster it
is compared against.

This is the second inflated claim in this file found by review rather than
by me, after the identity/gate binding. Both have the same shape -- a
sentence describing what the mechanism would catch if its two sides were
independent, when they are not.

2. grain_key was a byte-identical copy of compile_lens_grain_name, and the
test hand-rolled equality as a string compare where compile_lens_grain_eq
exists -- both in a module this test already imports from (section 3
nicknaming). The copy is deleted and the authority's comparison consumed;
the roster digest's grain spelling and the test's can no longer drift.

Evidence: claim_batch over required_lens_coverage_join, rc=0, 8 PASS,
including refuses_wrong_grain_observation, which is the arm that exercises
the swapped comparison; gunbc compile of v2.compiler.compile and the
witness module, 0 blocking errors each.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPVTQBSK9E8j3UDQGPZN1f
gunbai-bot Bot added a commit that referenced this pull request Sep 12, 2026
…n home, and a per-operand join that consumes std.pareto (#11026)

* Realization-cost fidelity: the structured cost form in CostShape's own home, and a per-operand join that consumes std.pareto

The compile-obligation census's one row WITHOUT A HOME: the modeled cost of an
operation and the cost its chosen realization actually has were two facts with
nothing joining them, so a declared cost could be realized slower, or faster,
and neither direction had a carrier able to state it.

WHY NOT THE BRIEFED SHAPE. The brief homed the join on CostShape. CostShape
names a growth RANK, so it cannot distinguish work over both operands from work
over one — both are "linear" — and the join would have returned
CostShapePreserved on exactly the specimen the class was written about
(gunbc.recurring_failure_mode lens_prices_the_authority_while_the_lane_runs_the_realization:
concat_contract declares work over both operands while the realization charges
the right one only, so a cost model reading the contract convicts the correct
construction). A wall whose RED is unauthorable for its own motivating case is
DESIGN §4b's decoration.

WHAT LANDED INSTEAD, per operator ruling: extend CostShape's OWN home rather
than mint a second vocabulary beside a consumer.

- dag/std/algebra.dag gains the structured form: CostFactor over a NAMED
  operand (constant / logarithmic / linear / linearithmic), CostTerm as a
  product of factors, StructuredCost as a sum of terms. CostShape stays, now as
  the PROJECTION of that expression via structured_cost_to_shape — partial and
  saying so: a cost linear in two operands has no CostShape image, and the
  absent arm is the vocabulary gap stated rather than a rounded rank.
- dag/std/realization_cost_fidelity.dag joins modeled to realized PER OPERAND
  and CONSUMES std.pareto for the dominance algebra rather than restating it
  (DESIGN §3d), which also inherits Pareto's separation of Incomparable from
  DominanceUndecided.

FIVE ARMS WHERE THE BRIEF ASKED FOR FOUR, both additions stated:
RealizationDivergesByOperand is a proven trade-off — cheaper in one operand,
dearer in another — and collapsing it into Unknown would be the absorbing
fallback; ModeledCostNotStructured is the counted migration frontier for
contracts not yet restated in the structured form. RealizationCostUnknown stays
reachable only from a MISSING realization fact, never from a comparison.

Evidence, by execution (claim_batch): 8 witnesses green, led by the specimen —
concat modeled over both operands against realized over the right one comes out
RealizationFasterThanModeled (the model over-prices the left operand). Its
discriminator lives beside it in the corpus rather than in this message: the
rank-only reading cannot see that divergence, which is why the structured form
had to land first.

NOT CARRIED, and declared rather than implied: the row population. Asserting a
realized cost for a primitive without measuring the emitted compiler would be
the fabricated fact this authority exists to catch, so the rows land with the
measurement, and the contracts' migration to the structured form is the trigger
that retires ModeledCostNotStructured.

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

* Build the operand lists with List's own constructors, not FreeMonoid's (floor red)

The floor refused at dag/std/algebra.dag:367 — "variant 'Empty' not found in
type 'List'", same for 'Cons'. In dag/std, List and FreeMonoid are distinct
types: `[]` and `concat([x], acc)` build the former, `Empty` and `Cons` the
latter, and I had mixed them in four fold accumulators plus a match in
structured_cost_to_shape.

All five sites now use List's own idiom, and the projection reads the operand
list with length() and first() rather than matching FreeMonoid variants
against it.

WHAT THIS COST, recorded because it changes what my evidence is worth in this
layer: the local claim_batch run was GREEN on exactly the code the floor
refused. The interpreter accepted the mixed constructors; the floor's resolve
did not. For dag/std changes the floor is the oracle and a local pass is not
evidence of one.

The eight witnesses pass again after the repair, including the concat specimen
(RealizationFasterThanModeled) and its rank-only discriminator.

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

* The projection no longer rounds, and the frontier is declared in the diff (review 63523)

Two findings, both real.

1. THE PROJECTION ROUNDED INSIDE THE FUNCTION THAT FORBIDS ROUNDING. rank 1
is LOGARITHMIC in the operand and CostShape has no logarithmic spelling, but
shape_for_single_operand_rank answered ShapeConstant for it — a cost that grows
reported as one that does not, which is exactly the fabricated answer the
annotation three lines above says the authority exists to prevent. It answers
absent now, like every other cost CostShape cannot say, and two witnesses keep
the distinction executed rather than asserted: the logarithmic case must not
project, and the neighbouring linear and linearithmic ranks still must.

2. THE FRONTIER WAS IN THE PR BODY, NOT IN THE DIFF. §3c admits a declaration
whose consumer lands later only with the trigger stated BESIDE it, and names
"consumption described in the PR body but absent from the diff" as a tell. The
module now carries it: the named consumer (the compile-obligation census's
realization-cost-fidelity row, joined per (primitive, target) through
realization_cost_fidelity_rows, with the three counters as its reported
populations), the route, and the trigger as a CAPABILITY — the emitted compiler
being measurable per primitive, so a realized cost is an observation rather
than an assertion.

It also records why there are deliberately no RealizationCostFact rows yet:
hand-authoring one would make the model and the realization agree by
construction, which is the failure this join exists to make impossible. And it
says plainly what a green run means today — the arms are proven against
authored costs, and the population this will judge does not exist yet.

Ten witnesses pass.

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

* Growth in an operand is a pair, not an ordinal; target equality is a match, not a slug table (review 63550)

Two findings, both real, and the first is the same defect one level deeper than
the last round's.

1. THE RANK ARITHMETIC COLLIDED, AND A COLLISION HAS NO REFUSAL DOOR. Growth was
a single ordinal (constant 0, log 1, linear 2, linearithmic 3) summed across the
factors of a term, so log(n)*log(n) and n both scored 2: cost_fidelity_of(modeled:
log^2 n, realized: n) answered CostShapePreserved, and structured_cost_to_shape
projected log^2 n as ShapeLinearScan. A real divergence reported as preserved, by
the module built to make that impossible — and, as the review put it, the absent
arm proves refusal was available while a collided rank offers no such door.

Growth in an operand is n^degree * (log n)^logs, which is two numbers. It is
carried as OperandGrowth { degree, logs }, multiplied within a term (a term is a
product, so the exponents add — separately) and maxed across terms under a
LEXICOGRAPHIC order, which is the true order of those functions: n beats
(log n)^k for every k. The projection follows: CostShape can say exactly
constant, linear and linearithmic in one operand, and logarithmic, quadratic and
log-squared each answer absent rather than rounding to the nearest thing it can
say.

The axis comparison moves from axis_comparison_int to axis_comparison(goal,
value_order:) accordingly. std.pareto still owns dominance; supplying the
ordering of a growth rate is this authority's own job.

2. TARGET EQUALITY MINTED A SECOND NAMING SCHEME. cost_realization_target_slug
gave each arm of a closed three-arm coproduct a string and compared strings —
names for arms the type already names (§3). realization_target_eq is a
structural match now, which also fails in the right direction: a fourth target
stops the match compiling, where a slug table would silently answer "not equal"
for a missing row.

Three new controls, thirteen witnesses green: log^2 versus linear must come out
RealizationSlowerThanModeled, and log^2 and one-operand-quadratic must each have
no CostShape.

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

* Give ShapeIterateBody a preimage: the caller's body is a fact the cost vocabulary was missing (review 63577)

CostShape is not a pure growth vocabulary. ShapeIterateBody means "once per
element, times whatever the caller's body costs", and it is the cost
std.primitive_identity carries TODAY for fold_list and index_by. StructuredCost
had no factor for that, so when those primitives migrate the only honest
spelling was LinearInOperand — and the projection answered ShapeLinearScan, a
DIFFERENT arm of the same authority, silently. ShapeIterateBody had no preimage
and ShapeLinearScan had two: two names answering one question and disagreeing
(§3), and the rounding this function's own annotation forbids (§5).

The review offered two repairs and this takes the modelling one, because
refusing the linear case would leave ShapeIterateBody permanently unreachable
and the projection nearly vacuous, while the body is a real fact that belongs in
the vocabulary:

- CostFactor gains CallerBodyPerElementIn { operand }, and OperandGrowth gains a
  bodies count.
- THE BODY IS NOT AN EXPONENT. It multiplies the work without changing growth in
  the operand, so it counts separately and the order stays over (degree, logs).
- An axis whose growths agree and whose bodies differ is therefore
  UndecidedOnEvidence — std.pareto's own word — because the body may be O(1).
  Calling it Same hides a real difference; calling it worse invents one.
- That lands as a sixth arm, RealizationCostBodyDependent, rather than being
  folded into RealizationCostUnknown, which stays reachable only from a MISSING
  fact. Without the new arm the undecided case would have reported "not
  measured" about something measured.
- The projection is total with exactly one preimage per arm: (0,0,0) constant,
  (1,0,1) iterate-body, (1,0,0) linear-scan, (1,1,0) sort-body.

Three new controls, sixteen witnesses green: the two formerly-colliding arms
must project differently, a per-element-body difference must be undecided rather
than preserved, and a body must not outrank a real growth difference.

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

* The body survives a losing term, and the undecided arm is counted (review 63603)

Two findings, both real, both arms I introduced and did not enumerate.

1. THE BODY COUNT WAS DROPPED BY A GROWTH-DOMINATED TERM. operand_growth_max
returned the winning term's OperandGrowth whole and consulted bodies only on an
Equal tie, so modeled [n*n] against realized [n*n, body(n)] both collapsed to
(2,0,0), compared Same, and answered CostShapePreserved — for a realization that
runs a caller-supplied body per element where the model runs none. The
fabricated preserved this module exists to refuse, produced by the function
meant to keep those two facts apart.

A cost is a SUM, so growth in an operand comes from the largest term; a body is
a fact about the COST, not about the winning term. Growth now comes from the
ordering and bodies are maxed independently — the same argument that keeps
degree and logs separate rather than summed.

2. RealizationCostBodyDependent WAS COUNTED IN NO REPORTED POPULATION. Not a
finding, not unmeasured, not unmigrated — so a measured-but-undecided row was
invisible in all three counts the declared consumer reports. The arm exists so
an undecided comparison is not read as preserved; being uncountable defeats it
just as completely and more quietly. It has its own population now,
count_cost_body_dependent, and the module's consumer statement names four
populations rather than three.

Two new controls, eighteen green: a body in a losing term must not be dropped,
and the undecided arm must appear in a reported population — the second
asserting all four counts on one ledger, so the type cannot gain an arm again
without the accounting being revisited.

THE PATTERN, fourth round running on this module: the defect sat in a
combination the vocabulary admits and no witness constructed. #11031 files that
class. This round sharpens it — adding an arm to a coproduct is not finished
when the arm is REACHABLE, it is finished when every fold over that type has
been revisited, and the counting folds are the ones that fail silently.

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

* Consume std.induction CostBound instead of minting a second cost grammar (review 63628)

LOCAL COMMIT, NOT PUSHED: #11026 is held and under a no-push rule. Committed so
the work does not follow a branch switch, which is how the 4a drafts leaked into
#11004 earlier today.

std.induction already owns a sum-of-products cost algebra over named parameters:
AtomicCost (PolyCost { param, exponent } / LogCost { param }), ProductBound,
SumOfProductsBound — and owns it more completely than what I wrote, since
PolynomialExponent carries fractional and log-based exponents my four-factor
grammar could not express. The equivalences are exact: cost_nlogn IS
linearithmic, and cost_graph_linear IS the concat specimen, already in the
corpus.

So I minted a second cost grammar — §2 failed decomposition, §3 nicknaming — in
the change that argued a second cost vocabulary beside a consumer is the fork §3
forbids, in a module whose subject is a cost authority disagreeing with itself. I
DFS'd CostShape and stopped there instead of following the concept DAG one step
further.

- std.algebra: CostFactor / CostTerm / StructuredCost deleted; CostShape stays,
  with an annotation recording the failed decomposition and naming CostBound.
- std.induction: AtomicCost gains CallerBodyCost { param } plus cost_iterate_body
  — the one fact genuinely absent, and the reason a projection from this
  authority could not reach ShapeIterateBody at all. Nothing outside
  induction.dag matches on AtomicCost, so the arm adds no obligation elsewhere.
- The growth derivation and the CostShape projection move to std.induction,
  beside the carrier they read: ParamGrowth { degree, logs, bodies,
  representable }, lexicographic on (degree, logs), body held out of the order,
  and representable:false for fractional exponents, log-based exponents,
  ForeverBound and ErrorBound — a real bound this reading cannot order says so
  rather than rounding.
- The join consumes CostBound and speaks its vocabulary (param_*, not operand_*):
  having renamed the authority, keeping a second name for its parameters would be
  the same defect one scale down.

Nineteen witnesses green, every verdict preserved across the migration, plus one
control that only became AUTHORABLE on the richer authority: cost_sqrt exists in
std.induction, and a fractional exponent must not round to a shape.

The specimen witness now reads cost_graph_linear(v_param: "left", e_param:
"right") — a constructor that was already there, which is the plainest statement
of what the review caught.

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

* Orderability is asked before any comparison, and it has its own arm and its own count (review 63797)

Both claimed silent wrong answers REPRODUCED by execution before I touched
anything:

  cost_fidelity_of(modeled: cost_linear("n"), realized: cost_sqrt("n"))
    -> RealizationFasterThanModeled          (sqrt(n) reported cheaper than n)
  cost_fidelity_of(ForeverBound, ConstantBound)
    -> CostShapePreserved                    (unbounded reported as preserving)

The cause is the one the review names: ParamGrowth carries `representable` and
the PROJECTION consults it, while param_growth_order compares only (degree,
logs) — so an unrepresentable growth was ordered as (0,0), i.e. constant. The
module's own annotation says a reader reporting constant or linear for such a
bound "would be fabricating". The join did exactly that, three lines of
indirection away, which is the same shape as the two rounds before it: the
refusal existed and the consumer did not ask.

ForeverBound is worse and needed a second look: it names no parameters at all,
so the axis list was EMPTY, and an empty axis list is Equivalent in std.pareto.
"No axes" and "no difference" are not the same fact. That is why orderability is
a property of the WHOLE BOUND (cost_bound_is_orderable in std.induction) rather
than a per-parameter flag — a bound with no parameters has no per-parameter flag
to carry.

CostGrowthNotOrderable is its OWN arm, not overloaded onto
RealizationCostBodyDependent as the review warned against. They are different
ignorances with different repairs: body-dependent means both costs are fully
known and their ORDER turns on an unmodeled body cost; not-orderable means this
reading cannot place a bound on the lattice at all. Folding them together would
send a reader to model a body when the real gap is a fractional exponent.

The arm is COUNTED — count_cost_not_orderable, a fifth reported population — and
every existing fold over CostFidelity was revisited. That is the rule this module
learned two rounds ago after shipping a reachable arm no count reported: adding
an arm is not done when the arm is reachable, it is done when every fold over the
type has been revisited.

Five new controls, twenty-four green, including two_constants_still_compare_as_
preserved so the gate is about ORDERABILITY rather than about having no
parameters — without it I would have no evidence I had not simply broken the
constant case.

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

* Unorderable growth becomes an arm, and the census row stops claiming the join it now has

Review 63818, both findings.

ONE, by construction rather than by a later gate. `ParamGrowth.representable`
was an in-band sum: a growth this reading cannot place still carried a degree
and a log count, and param_growth_order compared them without consulting the
flag. That is how sqrt(n) came to order cheaper than n and an unbounded cost
came to compare equal to a constant; the orderability gate added last round
caught both AFTER the illegal comparison was written, which is validation
standing where construction was available (DESIGN 5).

  type GrowthRank { degree, logs, bodies }
  type ParamGrowth = OrderableGrowth { rank } | GrowthNotOrderable
  fn param_growth_order(a: GrowthRank, b: GrowthRank) -> Ordering

A caller holding an unplaceable growth now has nothing to pass the order, so
the comparison the flag existed to prevent has no way to be written. The
construction found a live caller on its first run: the existing witness
the_rank_only_reading_cannot_see_the_concat_divergence was handing two
ParamGrowth values straight into param_growth_order, and the module refused it.

atomic_cost_is_orderable is now derived from the growth arm instead of
re-spelling the exponent match beside it. cost_bound_is_orderable stays,
because a bound with no parameters yields no per-parameter growth at all and
ForeverBound is exactly that shape -- that residue is what it covers, and the
annotation now says so. std.realization_cost_fidelity follows: the axis
comparison is AxisComparison? and the fold absorbs into CostGrowthNotOrderable
rather than rendering an unplaceable axis as UndecidedOnEvidence, which is a
different ignorance with a different repair.

TWO. The census row's NoHomeExists payload said nothing declares the
preservation join, and this head declares it -- a false payload is a meaning
fork of the modeling-state fact. `nearest` now points at
std.realization_cost_fidelity cost_fidelity_of, and the reason and trigger
state what is actually still missing: nothing reads a cost bound off an emitted
realization, so the join has no realized operand, and the home remains wherever
a target realization is selected.

Five new controls on the arms; 29 witnesses green.

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

* Regenerate the std_induction.rs stage0 mirror from the merged authorities

Build-lane regen candidate (claim_executor --required-ci --required-lane build) at b376035 on srv2; the only drifted mirror.

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

* The body delta is consulted beside the order, and the witness that asserted otherwise flips

Review 63838, both findings.

ONE. rank_axis_comparison decided the axis from (degree, logs) alone on the
Less/Greater arms and consulted the body count ONLY when growths were equal.
The body is caller-supplied work this carrier cannot bound -- std.induction
says exactly that in its own annotation -- so a body delta OPPOSING the growth
delta can outweigh it by any amount. n x body(n) against n log n was answered
RealizationSlowerThanModeled with confidence; at a body of O(n^2) the modeled
side is n^3 and the realization is dramatically faster. The mirror direction is
worse because the answer flatters the realization: a modeled n^2 against a
realization running an unbounded body per element answered FASTER.

And the wrong answer was enrolled as a GREEN witness. That is the part worth
naming: a_body_does_not_outrank_a_real_growth_difference encoded my reasoning
instead of testing it, so it could only ever confirm what I already believed.

ONE RULE REPLACES TWO: the axis is decided exactly when the body delta agrees
with the growth delta or is zero, and is UndecidedOnEvidence when they oppose.
That SUBSUMES the equal-growth case -- growths equal with bodies differing is
opposition at a growth delta of zero -- so this is one rule rather than a new
arm beside the old one, and the module got smaller.

Three controls, and they discriminate against each other by construction: the
two opposing directions (which the old rule answered Slower and Faster) and an
agreeing-delta control, so the repair is not a blanket retreat into undecided.
31 witnesses green.

TWO. The arm-roster annotation opened with a count that went stale the moment
this branch added an arm. Deleted rather than corrected: DESIGN section 4c says
an annotation must not restate what the declaration structurally says, and a
count is exactly that restatement -- it is the reason it could drift at all.

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

* A key with two facts is contradicted, not first-picked, and the input partition is enforced

Required repairs from the landing ruling. Two defects at two grains, repaired at
the grain each belongs to.

ONE, PER KEY: realization_cost_for stopped at the first matching (primitive,
target) fact, so [linear, quadratic] and [quadratic, linear] answered
DIFFERENTLY for one key. The verdict was decided by the caller's list order
rather than by the realization -- a well-formed wrong answer, which is worse
than a refusal because nothing about it looks wrong. The lookup is now three
arms, and the fold reaches Duplicated from EITHER order, which is what makes the
answer independent of how the list was built. The contradiction surfaces as a
counted CostFidelity arm classified as a FINDING, because two facts disagreeing
about one key is something a person must repair.

A CONTRADICTED KEY IS NOT AN UNMEASURED ONE, and its own control says so. Both
are "no usable realized cost", and collapsing them would file the repair against
the wrong lane: unmeasured means nobody looked, contradicted means two people
looked and disagreed.

TWO, ACROSS KEYS: modeled and unstructured are the two halves of one question --
has this primitive stated its cost in the structured form -- and nothing enforced
that they partition. A primitive in both produced TWO rows for one key, one with
a real fidelity and one ModeledCostNotStructured, leaving a reader to pick. That
is not a per-row fact but a broken premise, so the whole report refuses with a
named cause rather than emitting rows derived from it. Duplicates within either
list are the same defect at shorter range.

THE PLANTED CHECK IS THE EVIDENCE. Restoring first-pick fails
two_facts_for_one_key_contradict_in_either_order and
a_contradicted_key_is_not_counted_as_unmeasured, while
a_single_fact_for_one_key_still_compares and
a_disjoint_partition_still_reports_rows still PASS -- so the reds detect the
defect and the boundary controls are insensitive to it.

The test helper returns NO ROWS for a refused report on purpose: every count
assertion then fails loudly rather than reading as "nothing to report", which is
the one reading that would hide a refusal.

Adding the arm forced updates to four counting folds in the authority and twelve
matches in the witnesses -- each one a place a wildcard would have swallowed the
new arm silently. 38 witnesses green, 0 blocking errors.

This edits dag/std/realization_cost_fidelity.dag, a closure member, so the PR
re-takes its srv2 receipt. It does NOT touch induction.dag or any stage0 mirror.

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

* One classifier for the reported populations, and the frontier note names the carrier it duplicates

Review 63996, findings 1 and 2-in-part. Finding 3 and the migration half of
finding 2 are escalated rather than done, with the blockers named below.

FINDING 1 -- SIX FOLDS FOR ONE MAPPING, AND I ADDED TO IT. count_cost_* plus
cost_fidelity_is_finding were six near-identical nine-arm matches differing only
in which arm incremented: six independent sources for one fact, "which reported
population does this row belong to". I know the price exactly, because the
previous commit added the seventh arm and the substrate made me touch four folds
here and twelve matches in the witnesses -- and I reported that churn as the
exhaustiveness check working. It was. That is not the same as the shape being
right, and DESIGN section 2 is explicit that the test of an edit is whether net
concepts grew by re-invention.

Now: one cost_fidelity_population classifier, one counting fold returning a
record, and the six named counts read it. THE PARTITION IS TOTAL BY
CONSTRUCTION, because every arm maps to exactly one population -- and the
witness asserts it by execution too. Nothing established that before: all six
folds could have skipped the same arm and every population assertion would still
have passed, since each checked its own count in isolation.

FINDING 2 -- THE FORK IS REAL AND THE NOTE NOW SAYS WHICH ONE. The frontier note
named only the std.primitives contract-cost strings while the carrier this module
actually duplicates is std.primitive_identity PrimitiveCostFact, a CostShape
keyed on PrimitiveIdentity -- the coarse projection of the structured form
ModeledCostBoundFact carries. A loss sentence about one carrier under a trigger
about another is the grain mismatch section 4b(3) names as the review tell.

WHY I DID NOT PERFORM THE CUT. Migrating PrimitiveCostFact.cost to CostBound
looks like a substitution and is not one: the six populated rows record a shape
and NO PARAMETER, and every CostBound constructor needs one. The parameter is
load-bearing -- param_axis_comparison keys on it and param_union matches it
across the modeled and realized sides -- so an invented name yields a spurious
axis and a fabricated verdict. Recovering each row's real parameter is modelling
per primitive, not a rewrite. Doing it by pattern-substitution would manufacture
the exact kind of fact this authority exists to catch, so it is named in the note
and sequenced separately.

FINDING 3 is correct and designed but not in this push: routing the empty-axis
case through cost_bound_growth_in_param deletes all three orderability walkers,
and it edits dag/std/induction.dag, whose stage0 mirror I cannot regenerate here
(it OOM-killed on the remote runner; srv2 ran it last time). Escalated with that
blocker rather than half-done.

39 witnesses green, 0 blocking errors.

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

* The three orderability walkers delete, and the fold that owned the question answers it

Review 63996 finding 3, under your ruling to do it here with the mirror
regenerated on srv2.

WHAT WAS DUPLICATED. cost_bound_is_orderable, atomic_factors_are_orderable and
atomic_cost_is_orderable re-walked CostBound's arms in parallel with
cost_bound_growth_in_param, which already decides orderability per parameter and
already recurses SumBound. Two walks over one storage shape is one authority too
many, and the second drifts silently because nothing forces them to agree.

WHAT THEY ACTUALLY COVERED, which is the part worth getting right: only the bound
with NO PARAMETERS. Every other unorderable bound reaches the axis fold as an
unplaceable growth on some parameter and is already absorbed there. With no
parameters there is no axis to carry the refusal, and the dominance fold would
answer Equivalent over an empty comparison list -- reporting an unbounded cost as
PRESERVED against a constant.

So the residue is now one question put to the canonical authority rather than a
parallel recursion: ask cost_bound_growth_in_param about a parameter the bound
does not carry. ForeverBound and ErrorBound answer not-orderable whatever they
are asked, a structured bound answers zero growth in a parameter it never
mentions, and a SumBound recurses to its terms through the same fold. The gate in
cost_fidelity_of is gone with them.

THE EVIDENCE IS THE TWO CONTROLS THAT ALREADY EXISTED, and they are why "39 green"
is not the claim here: deleting an orderability gate and staying green could mean
the fold picked the refusal up, or that nothing checked the refusal at all.
an_unbounded_cost_is_not_preserved_against_a_constant and
a_malformed_bound_is_not_orderable both assert through the public entry, so they
are indifferent to HOW orderability is decided, and both PASS by name. They exist
because sqrt-ordered-as-constant and ForeverBound-ordered-as-constant were real
fabrications in this module.

THE MIRROR IS STALE ON THIS HEAD AND THAT IS EXPECTED: this edits
dag/std/induction.dag, whose stage0 mirror regenerates on srv2, per your
sequencing. Nothing else lands on this branch until that mirror commit is on it.

39 witnesses green, 0 blocking errors.

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

* Regenerate the stage0 mirror(s) from the merged authorities (srv2, build-lane candidate)

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

* The success arm names the cost it compared, not a shape it never asked for

Review 64030: `CostShapePreserved` claimed a fact this join never establishes.
The comparison runs over `CostBound`s through `std.pareto`; the shape
projection (`cost_bound_to_shape`) is a real, partial, neighbouring concept
carried on every row as `projected_shape` -- so two adjacent facts shared one
name, which is the DESIGN section 3 meaning fork. The module's own witnesses
proved it in both directions: `the_rank_only_reading_cannot_see_the_concat_divergence`
asserts the concat specimen has NO shape, and `identical_costs_are_preserved`
compared a bound against itself and got a "shape preserved" verdict.

Rename to `ModeledCostPreserved` at all 17 sites across the authority and its
witness suite, with the reasoning carried as a leading annotation on the arm's
own declaration.

Evidence: `claim_batch --entry dag/test/claim/realization_cost_fidelity_witness_test.dag`
over all 39 witnesses, rc=0, 39 PASS.

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

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brian Searls <searlsbrian@gmail.com>
Brian Searls and others added 2 commits September 12, 2026 01:54
Reviews 64177 and 64196 found two claims in `v2.compiler.compile` that
described what a mechanism would catch if its two sides were independent,
when they are not. One class, two specimens, so it gets a row rather than
two annotations that each explain themselves.

`gunbc.recurring_failure_mode comparison_whose_operands_share_a_producer`.
The discriminator is one sentence: the comparison's two operands have a
common producer. It is decidable by reading each operand back to its source,
and it is worth asking before the check is written rather than after it
greens.

Checked the directory before filing rather than assuming, and the four
nearest rows are excluded BY NAME in the row itself. Not
`roster_is_its_own_denominator`: there is no second statement there at all
and the repair is to obtain one; here two exist and are compared, and the
repair is to make one independent. Not
`population_selector_that_cannot_admit_a_counterexample`: that is a defect
in how a population was constructed by a lexical proxy; here the population
is correct and stable and the defect is the second operand. Not
`corroboration_without_an_independent_derivation_axis`: that is a property
of the relationship between two human readers, which no artifact records,
so it carries ceiling 1 and no trigger; this one is mechanical, visible in
source at both call sites, and decidable. Not
`a_positive_control_certifies_the_defect_it_exists_to_catch`: there the
control reads the right accessor against a wrong subject, so a correct
subject fixes it; here the subject is right and the comparison still cannot
fail.

The general form, and the reason it is a control-shaped class rather than a
compiler one: it is DESIGN section 5's oracle rule applied to a control
instead of to a literal. "A measurement copied from the same current tree
is not an oracle" becomes "a list re-derived from the roster it is compared
against is not an observation".

RUNG FOUND AT is mitigation by review, and an earlier draft got this wrong
in a way worth recording: it said `mitigatable` and justified that by
pointing at the join's refusal arms firing at fixture grain. Those arms
discriminate a malformed observation set; none of them can detect that a
comparison's operands share a producer, so that was a fact about the
specimen and not containment of the class. Nothing in the corpus asks the
question, so the honest rung is what a human reading two call sites
established. Ceiling is structurally guaranteed, because operand provenance
is a declaration-grain question the Node tree already answers. Class
trigger is provenance-aware comparison analysis; the specimen's own trigger
- an independent observation channel - is recorded separately and
explicitly does NOT discharge the class.

Both annotations in `00_compile.dag` now cite the row.

Evidence: gunbc compile of the row and of v2.compiler.compile, 0 blocking
errors each; docs_projection_gate regen renders the row into the combined
view (the roster and that projection are both gitignored, so the row file
is the entire committed change).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPVTQBSK9E8j3UDQGPZN1f
Review 64245. The grain note admitted a cost defect in this door's own
witness fold and disposed of it with "tracked as its own cost defect rather
than patched locally here", naming no carrier, row or symbol. Nothing
tracked it, so the sentence asserted a disposition that did not exist --
section 4b(2)'s untracked stall, stated in the authority a reader consults
first.

Filed `gunbc.recurring_failure_mode enforcement_exhibits_the_shape_it_refuses`
and cited it from the sentence. The class is the machinery that enforces an
invariant being written in the shape that invariant refuses -- DESIGN
section 7's self-application obligation failing in the direction nobody
looks, because the enforcement's own code reads as infrastructure rather
than as a subject. The specimen is half repaired and half standing, which
is what makes it worth a row: the subtree fold was already rewritten to
prepend-then-reverse, while the concat stands, because `list_append` costs
its LEFT operand and `rc_list_concat` copies its RIGHT one and neither
accumulation is reliably shorter.

The trigger is named as a CAPABILITY and the falsified experiment is
recorded beside it: a concat that copies neither operand, which is carrier
work in the list algebra and explicitly NOT a rewrite of call sites --
docs/plans/emit-type-surface-traversal-cost.md tried exactly that
substitution at 215 sites plus rc_list_concat and measured byte-identical
output with no measurable change at the emit seam. That is evidence about
that seam and not this one, and it is written down so the next author does
not re-run a falsified experiment believing it is the repair. The row's own
next rung is the required-lens gates applied to the compiler's own modules
as ordinary subjects, which is section 7's claim made executable.

The seed mirror moves in lockstep: both sides of the self-host behavioral
receipt are byte-identical at 2556 characters, asserted by comparing the
extracted strings rather than by inspection.

Evidence: gunbc compile of v2.compiler.compile, the new row and the
cause-swap witness, 0 blocking errors each; claim_batch over
claim_entailing_evidence_cause_swap_witness, rc=0, 8 PASS -- that suite
carries the transcript fixtures that mention this declaration, and its
`seed_len` figures are authored specimens of transcript SHAPE rather than
live measurements of the string, so they are unaffected by its length
changing.

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

gunbai-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Review 64245, secondary finding — not fixed, and here is why rather than an acknowledgement.

The finding is that required_lens_grain_note puts a ruling citation, a measured cost claim and a deferral inside a String row, where §4c wants a typed carrier or a // annotation, and that // is available two screens above.

The premise that makes that repair cheap does not hold here: this string is not commentary, it is a compared value. It is the only case in the self-host behavioral receipt — dag/gunbc/instruments/self_host_00_compile_shims/witness_main.rs compares emitted::required_lens_grain_note() against seed::required_lens_grain_note(), and src/v1/stage0/src/v2_compiler_compile.rs is a nine-line module whose entire content is that same string. Moving the prose to a // annotation does not relocate commentary; it empties the receipt's case list, because annotations are erased before any semantic pass and no Accepted program can read one (§4c's own second consequence).

The defect the finding is pointing at is real, and it is already rostered: gunbc.recurring_failure_mode receipt_subject_is_the_prose_about_the_mechanism names this exact declaration as its specimen, and states the problem more sharply than a §4c placement note would — "the strongest verdict the emitted crate can publish about the compile door is that two copies of a sentence about lenses agree, while the door's eight enrolled gates, its lens fold, its subtree walk and its rejection path are all outside the receipt's subject." Shrinking the string would leave that intact while making the receipt's subject smaller, which is motion, not repair. The repair is that row's trigger — a receipt whose subject is the mechanism.

So the honest disposition is: the §4c placement is a consequence of the rostered defect rather than an independent one, and fixing it locally in this PR would change the self-host receipt's subject as a side effect of a comment-placement edit. That belongs with the row that owns it.

The primary finding is fixed in 56074004b3. The deferral named no carrier because none existed — the sentence asserted a disposition that did not exist, which is §4b(2)'s untracked stall in the authority a reader consults first. gunbc.recurring_failure_mode enforcement_exhibits_the_shape_it_refuses is filed and cited, with the trigger named as a capability (a concat copying neither operand — carrier work in the list algebra) and the falsified experiment recorded beside it, since docs/plans/emit-type-surface-traversal-cost.md measured that exact substitution at 215 sites as byte-identical with no measurable change at the emit seam. Citing that plan as the owner would have pointed a reader at a document whose finding contradicts the framing; recording it as falsified for that seam is what stops the next author re-running it as the repair.

Both sides of the receipt moved in lockstep and are byte-identical at 2556 characters, asserted by extracting and comparing the two strings rather than by inspection.

— sent from calm-crane-722

…t hold

Review 64262, plus the dark row gunbc#11073's long-home arm exposed.

WHAT THE ARM FOUND. v2.test.long.accumulator_copy_compile_gate
gate_red_quadratic_rejects failed on its FIRST REAL EXECUTION (srv3-02, no
thrash). It is not a regression: run with one binary against origin/main and
against this head, it FAILS on both while both sibling controls PASS on
both. It had simply never run, because its home test/claim/long/ is a
witness_exclusion_frontier pattern and no required lane plans it.

AND THE FAILURE IS THE WORST OF THE THREE AVAILABLE. A three-way
discriminator separates them: the specimen normalizes fine, the gate does
not reject with a wrong reason -- accumulator_copy_compile_gate ACCEPTS it.
accumulator_copy_findings returns NO suspect for
fold(xs, init: 0, f: fn(acc, x) { list_append(left: acc, right: x) }),
which is the textbook shape the lens exists to refuse.

Three consequences, all here, none of them the analyzer repair (that is its
own lane, starting from the discriminator posted on the PR):

1. RUNG HONESTY. accumulator_copy_obligation claimed MechanicallyPreventable
on the strength of that control. Executed evidence says the invalid state is
not prevented, so the claim is downgraded to Mitigatable -- the gate is
total and returns a typed outcome, so harm is contained and nothing above
that is established. DESIGN 4b(1) admits only the rung executed evidence
supports, and the restoration is the analyzer trigger rather than the
witness greening by any other route.

2. THE CLASS. gunbc.recurring_failure_mode
required_lens_red_control_never_executes_from_its_home: a lens enrolled as
required, reporting a mechanical rung, whose discriminating red lives where
the floor never plans. The discriminator is a JOIN -- the cited red and the
planned population do not intersect -- which is why neither roster looks
wrong alone. Ceiling structurally guaranteed, because that join is over two
rosters this tree already declares.

3. THE KNOWN RED, without which the floor stays red on every future head.
Admitted in gunbc.explicit_witness_admission with a dissolution naming the
CAPABILITY: accumulator_copy_findings returns a non-empty suspects list for
the fold-append specimen and the gate refuses that tree. That fact is false
today and was MEASURED false by execution on both trees, so the trigger
cannot be satisfied by editing the specimen or the control -- which is
exactly the defect that roster's own note records two lanes failing.

REVIEW 64262. The expanded grain note restated the body of the row this PR
files, and transcribed a 215-site measurement into two files including the
Rust oracle mirror. Both are right: the prose was the duplicate rather than
the carrier, and section 6 says name the instrument, never transcribe it.
The note now cites the row instead of restating it; both sides byte-identical
at 2117 characters, asserted by extracting and comparing.

Evidence: compile 0 blocking on all four touched authorities and the new
row; v2_compile_obligation_census_witness 9 PASS. exact_witness_admission
carries three failures that are IDENTICAL on origin/main (18 PASS 3 FAIL
both sides) and my row satisfies explicit_witness_admission_well_formed by
inspection of the predicate -- QuarantineProbeExpectRed executes, entry
non-empty -- and shares kind and budget with an existing row in that batch.

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

gunbai-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

For the accumulator-copy analyzer lane — the three-way discriminator, verbatim, so you start from evidence rather than rediscovering it.

gate_red_quadratic_rejects can fail three ways and they demand different repairs. These ran in a throwaway worktree at origin/main (2090c1b01b), appended to src/v2/test/claim/long/accumulator_copy_compile_gate_test.dag:

test fn diag_stage_rejected() -> Bool {
  match normalized_of(source: quad_snippet) {
    ProbeStageRejected { stage: _ } => true
    ProbeNormalized { root: _ } => false
  }
}

test fn diag_gate_accepted() -> Bool {
  match normalized_of(source: quad_snippet) {
    ProbeStageRejected { stage: _ } => false
    ProbeNormalized { root: root } =>
      match accumulator_copy_compile_gate(node: root) {
        Rejected { diagnostics: _ } => false
        Accepted { value: _, diagnostics: _ } => true
      }
  }
}

test fn diag_rejected_but_other_reason() -> Bool {
  match normalized_of(source: quad_snippet) {
    ProbeStageRejected { stage: _ } => false
    ProbeNormalized { root: root } =>
      match accumulator_copy_compile_gate(node: root) {
        Rejected { diagnostics: d } =>
          !non_empty_contains_reason(d: d, reason: ^accumulator_copy_poly2_suspect)
        Accepted { value: _, diagnostics: _ } => false
      }
  }
}

Result on origin/main: diag_stage_rejected FAIL, diag_rejected_but_other_reason FAIL, diag_gate_accepted PASS. The specimen normalizes fine and the gate is not rejecting with a wrong reason — it accepts. accumulator_copy_findings returns no suspect for fold(xs, init: 0, f: fn(acc, x) { list_append(left: acc, right: x) }).

Latency, established rather than assumed: one binary, same functions, gate_red_quadratic_rejects FAILs against origin/main and against this PR's head, with gate_green_identity_accepts_clean and gate_refusal_ledger_counted_not_gating PASSing on both. A failing witness is not a regression until it is shown to have passed somewhere, and this one never did.

These three belong in the analyzer PR as enrolled controls, not in a throwaway worktree — diag_gate_accepted in particular is the arm that goes red exactly when the analyzer starts working, so it is the repair's own discriminating control inverted.

This PR does not touch the analyzer. It carries the rung downgrade (accumulator_copy_obligation MechanicallyPreventable → Mitigatable, §4b(1)), the class row required_lens_red_control_never_executes_from_its_home, and a known-red admission whose dissolution names the analyzer capability by symbol — so the analyzer lane deletes that row in the same push that fixes the lens, per §4b(4).

— sent from calm-crane-722

@briansrls
briansrls merged commit 791ad82 into main Sep 12, 2026
8 of 12 checks passed
@briansrls
briansrls deleted the session/calm-crane-722 branch September 12, 2026 06:29
@briansrls
briansrls restored the session/calm-crane-722 branch September 12, 2026 06:34
gunbai-bot Bot pushed a commit that referenced this pull request Sep 12, 2026
…h authorities survive

The only conflict was src/v2/compiler/00_compile.dag, and it was two sides adding
imports to the same block rather than a rename or a contested declaration.
Resolved as a per-module union: std.algebra keeps this branch's `trim` beside
main's Cons/Empty/FreeMonoid; v2.std.algebra keeps contains/is_empty/length and
the promoted list_find_first beside main's folds; v2.std.collection takes main's
Map/empty_map/map_insert/map_lookup beside List; and main's new std.decl_ref,
std.content_hash, std.types, v2.std.integer and v2.std.logic imports all land.
One import line per module, no duplicate module imports.

Verified rather than assumed, since a clean auto-merge is weak evidence when both
sides touch the same closure: this branch's native_lane_universe,
native_lane_closure_modules, native_lane_module_for_path and list_find_first are
all present; main's #11004 lens-registration join is present (85 references to
CompileLens / declaration_ref_display_key / content_hash_of_value); the file is
brace-balanced; the seventh row is intact in dag/std/compiler_entry.dag and the
emitter; and the driver template is still the adjudicate one (2 x
'adjudicate <host-facts', 0 x universe.tsv).

ONE DELIBERATE DIVERGENCE FROM THE STANDING MIRROR RULE, flagged rather than
silent. The rule has been to take main's side on the stage0 mirrors, which was
right while main carried the newer ones. Here the opposite holds: 86761d1's
regen put THIS branch's route contract into them, and main has no such commit. So
the merge keeps the regenerated mirrors -- universe.tsv 0, adjudicate 1,
INGEST-CLOSURE 1, row_serialization 1. They are now stale against #11004's
additions and will drift for the next regen either way; keeping them means
anything that runs before that regen still gets the right driver rather than the
pre-route one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013aZDLk2CxsCDznqn49Xhe8
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