Repository navigation
The wave-admission wall: adjudicate closure, subject-membership and binding deltas before a namespace change merges - #9365
Conversation
… ratchet by symbol
Opened by operator ruling 2026-08-26: v2 self-hosts the ENTIRE v2 corpus, started
from scratch, superseding the 2026-08-16 root-partition document whose evidence
base was bankrupted (all ten probe links dangling, census a month stale, its
instrument deleted).
The plan is a .dag Plan carrier rather than a hand-authored .md so that its claims
are joined to symbols a machine checks: v2_corpus_self_host_ratchet_bindings names
the ratchet, the measurement instrument, the hosting admission and the emission
phase as DeclarationRefs, which the ingestion-time citation wall resolves on every
required run. A section that goes stale because its mechanism was renamed refuses
here instead of reading as current -- the failure mode that killed the last anchor.
Records two findings the program depends on: the required v2-emission phase never
invokes cargo ("stopping before cargo"), so no required check measures rustc; and
the whole-corpus compile IS hostable on a CI runner, correcting a report that no
host could run it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The plan landed with both a .dag Plan carrier and a hand-authored docs/plans .md. That is a second representation of one fact with no authority over it -- the §2/§3 parallel-representation debt -- and it would drift from the carrier silently, since nothing joins them. Evidence the .md is not required: gunbc.plans.branch_merge_admission_model is a registered plan with no docs/plans markdown at all. The Plan type already carries plan_to_document, so the markdown is DERIVED where it is wanted rather than authored beside the source it restates. Operator steer 2026-08-26: design doc changes are .dag changes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Second anchor requested by the operator alongside the v2-corpus-self-host plan. Material supplied by the owning session (snappy-dove-250) on request. Bound to two symbols only -- gunbc.namespace_cut_landing_order current_landing_order and namespace_cut_grammar_last_ruling -- both verified to resolve before authoring. Everything else is marked as prose in the text rather than given a citation it cannot support. A long half-bound roster would assert that the ingestion-time citation wall is checking claims it is not checking. Three things the plan deliberately does not smooth over: - The strip measurement is STALE AS A POPULATION and current only as a CLASS TAXONOMY. The corpus sha256 is the anchor, not the commit line. - smart-wolf-868's placement at Step 2 is ASSUMED, not measured, and is labelled so where it appears. - Whether the namespace cut blocks v2 self-compile or the reverse is an OPEN QUESTION carried to the operator, not a position taken here. It changes wave ordering in both plans. Ordering claims bind to the carrier, never to a document sentence: the execution document is superseded on ORDER only (operator, 2026-08-25), which is why grammar deletion lands LAST rather than first. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Four fixes, all from review rather than from me. 1. S1 asserted #9346 was "still OPEN with conflicts ... contrary to a report that both had merged". #9346 is MERGED (2026-08-26T19:06:10Z, 7fcdbdc, verified an ancestor of main). The line did not merely carry a stale fact -- it instructed the reader to distrust an accurate source, in an ACTIVE anchor. Fixed by DELETING the assertion rather than updating it, and recording the rule: a plan carrier must not assert the open/closed state of a PR. It rots in hours, it is free to re-derive at read time, and nothing refuses when it goes stale. This is the one class the evidence-bankruptcy rule could not have caught, since it is not a measurement at all. 2. The seed partition table is a TRANSCRIPTION with no entry point. An independent re-run of the described procedure on the same commit reproduced every figure exactly except emitted lines: 166,834 vs 166,727, the total carrying the same delta. No conclusion turns on 107 lines; the finding is that a described procedure and an instrument are different things, which is what name-the-instrument predicts. Named as the gap it is. 3. The superseded census's CONCENTRATION is restated as a hypothesis with a test attached. Its two halves do not decay alike: the magnitude is inert without a board, but the concentration is a claim about the emitter's failure distribution and the emitter has been changed for a month by lanes whose purpose is moving it. A magnitude drifts; a concentration can invert, and sequencing by a stale one puts effort where the wins are already taken. 4. Import/namespace section 5 no longer claims the eleven classes "are still the right partition". Nothing has tested that. The taxonomy is what survives; its COMPLETENESS is unverified, since a class of breakage introduced since the measurement would not appear in it. Staleness is now stated as MEASURED -- the anchor recipe re-run gives a different corpus hash on a tree behind main. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The rule against asserting PR state in a carrier was filed against #9346, which had merely gone stale. A stronger receipt arrived the same night on #9349: three readings within minutes -- dashboard reporting failing from a superseded run, a peer re-deriving green at check-run level, and a third check finding the head had moved again and the PR was mid-run. Each was correct when taken; none described the PR when quoted. That is the case #9346 could not make. There a correct measurement never existed; here there was a correct measurement at BOTH ends and the shared conclusion was still wrong. The mechanism is that a PR-state sentence has no spelling for AS OF WHICH HEAD, so a true reading and a stale one become indistinguishable the moment either is passed on -- which is precisely what CORRECTING the line would have reproduced, and why it was deleted. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Operator ruling 2026-08-26 answered the sequencing question both plans had open, and answered it at a different grain than it was asked: neither program blocks the other whole. Self-host's proof envelope blocks the FIRST namespace semantic wave; namespace completion blocks self-host's IRREVERSIBLE retirement step. A braid, not a total order -- and collapsing it back to a program order yields a different plan in either direction. The ruling closed with an explicit instruction to carry the precedence edges ONCE and not duplicate them as prose in both carriers, which is §3 applied to a fact with two natural homes: two copies are one fact with two authorities, and they diverge on the first amendment. So gunbc.compiler_frontend_program_interlock owns the relation and both plans cite it; their prose renders it. milestone_prerequisites is a TOTAL FUNCTION over a closed milestone variant, not a list of edges. A list is satisfied by omission -- a milestone nobody wrote an edge for silently has no prerequisites and the failure is invisible. The exhaustive match makes an unstated prerequisite fail to compile (§5, construction over validation). Same shape for the admission predicate, which admits on UNADJUDICATED delta being empty rather than delta being empty: expected cut motion may occur, unevaluated motion may not. A wall demanding zero delta would refuse the cut itself and then be repaired by weakening it. Executable consequence recorded in the namespace plan: its disclosed "no CI mechanism" gap becomes a BLOCKER gating Step 1 by name, with preparatory work explicitly unaffected. Its section 7 stops being an open question and becomes a projection of the carrier. Two corrections from the operator's exact-head review: - The ratchet clause said counts are "display only and decide nothing". The ratchet owner measured that as literally false. Replaced with their wording: no cardinality is a gate oracle, but emptiness decides whether a population is inhabited or evaluated -- including the distinction between an empty roster and an identified roster with no failures -- and the roster DIGEST, not its count, is its identity. - The status block claimed "no transcribed instrument output" while the next section explicitly carries a transcription and names its missing producer. It no longer claims both states. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The build lane's parse phase refused:
module index refused: 1 unparseable .dag source(s)
dag/gunbc/plans/import_namespace_program.dag:8636-9127:
expected expression, found Unknown
My error, and it is an escaping-layer mistake rather than a .dag one. I
authored the section through a Python here-doc and wrote \\' inside a
triple-quoted Python string to protect the apostrophe from PYTHON. Python
emitted a literal \' into the .dag file, where a double-quoted string needs
no escape for an apostrophe and \' is not a valid escape -- so the lexer
produced Unknown and the parser refused at the enclosing expression.
Four occurrences across three lines, all in the one file the index named;
the other two new modules parsed clean, which is why the refusal counted
exactly one source.
Worth noting the wall worked as designed: this was caught by the parse
sweep in the build lane, at the phase DESIGN records as sweeping src/v1,
dag and src/v2 from one roster, before anything downstream consumed it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two findings, and the first splits rather than landing whole. FINDING 1 -- predicate dissolution. The rule is real and I verified its scope before acting: std.execution_mode records that the 2026-07-12 dissolution deleted SINGLE-VARIANT NICKNAMES (is_hermetic/is_record), and that a predicate deciding a SEMANTIC PARTITION survives it -- execution_mode_is_wet_dispatch groups three variants into two because Wet and Record share dispatch semantics, keeping one authority instead of an inline match at every consumer. namespace_change_admitted_before_wall: two variants mapped one-to-one onto true/false. That is a nickname for a variant test. DELETED. Its distinction already lives in NamespaceChangeClass, which consumers match on, and the plan's citation is repointed to the type. delta_disposition_auto_admitted: nine dispositions partitioned three-to- six on whether the wall auto-admits them. That is the surviving shape, on the grounds std.execution_mode records by name. RETAINED, with the argument written beside it so the next reader does not re-litigate it. FINDING 2 -- prose drift. Upheld. Section 7 enumerated both precedence edges while asserting the carrier was their only home, which is worse than either alone: a symbol citation verifies a declaration EXISTS and never that prose about it still AGREES with it, so enumerated edges beside a citation are precisely the drift single authority prevents. The prose now renders the relation without restating it, says explicitly that it is not authority for the edges, and points at milestone_prerequisites for the gate condition instead of repeating it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…orrected Two narrow semantic checks raised on 620a118. 1. The ruling gates the first namespace wave on S2 + S3 + S4. The closed milestone SelfHostCargoRatchetEnrolled named S3 and S4 and left the S2 whole-corpus census implicit inside the phrase "proof envelope". That is a real gap rather than a naming preference, and the reason is worth stating because it is a limit of the construction this carrier leans on: the closed variant makes an omitted MILESTONE fail to compile, but it cannot make an omitted FACT fail to compile when that fact hides inside a composite name. Totality protects the enumeration, never the contents of an element of it. So a required precondition had become unenforceable in the very carrier built to enforce preconditions. Fixed by adding SelfHostWholeCorpusPopulationDerived as its own variant rather than by renaming the composite, since renaming would have left the fact implicit and merely better labelled. NamespaceFirstSemanticWave now requires all three. The general rule is recorded beside it: when a construction derives its guarantee from exhaustiveness, every fact the guarantee must cover has to be its own element -- a composite element is a place for a fact to hide from the check that makes the construction worth having. 2. Section 9 announced the ordering relation as retired and then closed by counting "Four gaps". Now three live gaps plus one retired question, with the retired bullet kept only so a reader of an earlier revision does not hunt for an answered question. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Deleted delta_disposition_auto_admitted, and the reason is independent of the question it was reviewed under. THE REVIEW'S STATED GROUND DOES NOT HOLD. The finding cites "the exact predicate/walker-dissolution shape prohibited by DESIGN.md". DESIGN.md contains zero occurrences of "walker", and its only predicate clauses say that a general fn(T) -> Bool refinement does not lift to proof and that a caller-supplied validator is defeasible -- both claims about the guarantee ladder, neither a prohibition on Bool projections. The predicate-dissolution rule is real but lives in the corpus, at std.execution_mode, and that row states the surviving case explicitly: a two-variant semantic partition is kept where a single-variant nickname is deleted, because deciding a partition once keeps one authority instead of an inline match at every consumer. DELETED ANYWAY, ON A GROUND THAT DOES HOLD: it had no consumer. Measured -- the only reference in the tree was a DeclarationRef in this PR's own plan. The wave-admission wall that would classify deltas does not exist yet, and DESIGN section 6 names a new artifact with no final consumer as experimental residue. A partition nobody computes over is a guess about what a future consumer will want, and the surviving-partition argument presupposes consumers that would otherwise inline the match. There are none, so the argument does not apply to this predicate either. The operator's ruled partition is preserved as an annotation, where it cannot be mistaken for an executing mechanism, and the plan's citation is repointed to NamespaceDeltaDisposition. The type stays: it carries the ruled vocabulary and the wall will match on it directly. Bool is dropped from the imports. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
review 56376 found that SelfHostCargoRatchetEnrolled carried no prerequisite while its own label named S4, and the plan defines S4 as enrolment against S2's population. The typed interlock therefore permitted enrolling the ratchet before the population it ratchets against exists. The review offered two repairs. Adding S2 as a prerequisite to the fused variant is the wrong one: S3 (enrol a cargo-executing phase) genuinely has no prerequisite, so that repair closes the permissive half by introducing a false-blocking half. The variant is composite, and its two halves have different prerequisites, so a single prerequisite list must state either the minimum or the maximum and both are wrong. The repair is the split. This file's own annotation already stated the rule -- a composite element is a place for a fact to hide from the exhaustiveness check that makes the construction worth having -- and this instance was left standing in the same diff that wrote it down. The annotation now carries the second instance, since a rule with one instance reads as a repair and a rule with two reads as a rule. Prerequisites are direct edges rather than the transitive closure: S2 is not repeated on NamespaceFirstSemanticWave because S4 now carries it, so a later correction to S4 cannot leave a stale duplicate standing (DESIGN section 2). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…f one shape loyal-lark-254 found that SelfHostRatchetEnrolled was itself composite. It fused enrolling the ratchet as an OBSERVATION -- taken, persisted, never able to fail a merge -- with enrolling it as a GATE. Their prerequisites differ: an observation needs no population to be about, since what it refuses is the inability to take or persist it; a gate is meaningless without the identity-grain population it gates against. Fused, the variant read as a prerequisite over both. That would have blocked observation work an operator ruling had already authorised, via a carrier that landed after the ruling -- a single-authority collision committed by the file built to prevent them. NamespaceFirstSemanticWave now depends on the GATE form, since what the namespace plan says gates Step 1 is an enforcing mechanism over the import population, and an observation cannot enforce. Three instances of one shape in one file is the finding, not three repairs. Each was a variant fusing two facts whose prerequisites differ, and each was invisible to the exhaustiveness check that is this construction's whole reason for existing. The annotation now carries the standing obligation that follows: the match already forces prerequisites to be stated, so the question a new milestone must answer is whether it carries two facts that would state DIFFERENT prerequisites if separated. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
loyal-lark-254 pointed out that a review reports one instance because it found one instance -- a property of the reviewer's attention, never a census -- and that the standing obligation this file had just written down should be RUN over every variant rather than applied at the reported site. Running it found NamespaceTerminalEndState fusing Steps 1-5 into one "terminal end state". The namespace plan marks Step 5, the grammar and parse deletion, as LAST, and gives the reason: deleting the grammar first makes every unrepaired module unparseable at once, converting a fix-forward program into a flag day. So the fused variant erased its own ordering constraint, and the constraint it erased is the one that keeps the program survivable. Split into NamespaceFixForwardComplete (Steps 2-4) and NamespaceGrammarRetired (Step 5, downstream of it). Seed retirement is now downstream of the grammar deletion rather than of a composite. Four instances of one shape in one file, and only the last was found by census. The first three were each reported by someone who had run into them. That is the difference between a repair and a wall: repairing reported sites converges on reviewer attention, enumerating the shape converges on the corpus. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…struction snappy-dove-250 measured what crisp-crab-430 is actually building rather than reading its session title, and it is a PRE-DELETION BASELINE INSTRUMENT: a content-addressed, past-tense record of what the legacy resolver actually selected over one exact base. It must precede Step 1, because once the cut lands that record is unrecoverable. That is the strongest kind of ordering constraint there is -- violating it destroys evidence rather than merely reordering work -- and it was not in this carrier at all. The graph therefore showed an active, ungated session as blocked on prerequisites its work does not have. The four earlier findings in this file were FUSIONS, and a census over the declared variants found the last of them. This one is an OMISSION and no such census could have found it. Exhaustiveness forces prerequisites to be stated for every milestone declared; it cannot force a milestone to be declared. So the match makes an unstated prerequisite unwritable and leaves an unstated MILESTONE invisible -- totality protecting the enumeration and not its completeness, one level up from the rule this file already records. The annotation states plainly that finding a missing variant requires joining this file against the programs it claims to describe, that no mechanism performs that join today, and that the annotation is not one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ion/nimble-moth-416
Both lanes failed on ONE cause. The floor lane reported it as `FAILED PHASE parse (8 error(s))` against the two plan carriers; the build lane reported it as `v2-emission EmissionRefused ... produced 8 hard diagnostic(s)` against src/v2/compiler/00_compile.dag. They are the same eight §4c violations, addressed by line in one and by byte offset in the other. The annotations sat inside `data ... = [ ... ]` list literals, labelling groups of decl_ref rows. §4c admits only standalone leading `//` blocks attached to module-scope declarations, so an annotation inside a declaration body refuses. Each group label is hoisted into the leading block above its declaration, which keeps the grouping legible without inventing a grain the realization does not model. The build lane's attribution is worth knowing before anyone chases it: an annotation defect in dag/gunbc/plans/ surfaces as an emission refusal naming the v2 compiler entry, because that entry's census sweeps the corpus. The named subject is the entry, not the offending file; the offending file appears only in the diagnostic payload. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…s own plan review 56390 joined this carrier against the self-host plan and found that SelfHostSeedRetirement depended on NamespaceGrammarRetired ALONE. The plan requires two further conditions before S6: that the emitted Rust compiles, and that behavioral equivalence to the seed is re-established. Neither existed as a milestone, so the authoritative carrier permitted the one irreversible step in either program on weaker conditions than the plan it claims to sequence. Added as two milestones, not one, on the plan's own distinction: a rustc-clean corpus permits S6 to be PLANNED, it does not AUTHORIZE it. Compiling is a property of the emitted text; equivalence is a property of what that text does. Fusing them would have been this file's characteristic defect committed while repairing its mirror image. This is the sixth defect of the same family and the second OMISSION. It is also the first one found by the join the file's own annotation says nothing performs -- a reviewer performed it. That is evidence for the stated limit rather than against it: no census of this file could have surfaced this, because there was no variant to enumerate. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…inding deltas before a namespace change merges gunbc.plans.import_namespace_program section 9 records that no CI mechanism enforces any of it, and the 2026-08-26 ruling at gunbc.compiler_frontend_program_interlock makes that a BLOCKER gating NamespaceFirstSemanticWave on NamespaceWaveAdmissionEnrolled by name. This is that milestone: a required namespace-wave-admission phase in claim_executor --required-ci, witnesses lane, riding the parse sweep that already runs. The base index is the head index with the diff applied in reverse at file grain, so only changed files are parsed twice while closure and bindings are recomputed over both whole graphs. The change class is DERIVED from the measured delta rather than declared by an author. The wall admits when the UNADJUDICATED delta is empty, never when the delta is empty. Closure is a pure function of membership, so an arm for "closure moved and membership did not" would be permanently green by construction. It is measured and attributed to its generators instead -- each delta names its blast radius. The grain is authored containment identity (module, enclosing declaration, LEAF segment), because v2.workflow.legacy_binding_delta establishes that no admissible cross-compile occurrence key exists without a transformation to emit one, and there is none between a merge base and a head. Row values are candidate SETS, so shadowing widens a set rather than picking a winner. The leaf rather than the whole spelling is a fixture finding: keyed on spellings, requalifying a reference reads as NewUnresolvedness, and requalification is the namespace program's own core motion. The binding channel reads every authored name occurrence from the parse tree rather than import members, so it does not go blind on the cut it gates. Evidence: 14 fixture-boundary arms in tests/namespace_wave_admission.rs, every refusing arm one mutation of the auto-admitted control, plus a two-directional vocabulary join between the host enum and the .dag coproduct it realizes, whose absent-authority arm refuses. The admission roster is empty, which is the correct landing state; the coarse class-admission carrier is deliberately not built, and the constraint on its shape -- bounded by enumerated identity, never by predicate -- is recorded in gunbc.namespace_wave_admission. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…uld delete the CLI emit_main_rs produces 552 lines against the committed 1318. Absent from the emitted form: the whole Ci subcommand, Converge, Serve, and --entry on compile. Measured by execution 2026-08-21 and accepted then as a program-level correction. No number of regenerations closes it. It is a distinct milestone because it is invisible to both milestones beside it. It never appears in a rustc error count, so SelfHostCorpusEmitsCleanly can be fully satisfied while it stands -- errors-to-zero is necessary and not sufficient -- and it is not a behavioral difference between two producers, so equivalence does not reach it either. It is the absence of a producer, and neither of the other two can express that. Its executable home already exists: EmitterProducedDivergentRegistration in v2.compiler.self_host.stage0_crate_layout, enforced in three directions so a row cannot outlive its producer. The milestone is that no such row remains. This is the seventh defect of one family in this file and the third omission, and it indicts the method rather than extending the list: it was not discovered. It was already known, recorded, and accepted as a correction to this very program a week before this carrier was authored, and the carrier was still written without it. The join that finds omissions is not merely unmechanized -- it is not reliably performed even by someone holding the fact. None of the three omissions was found by reading this file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ion/nimble-moth-416
…fields and this one carried five Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… body: a body is not an authority Records what the milestone delivers -- two adjudicated walls, a measured closure blast radius attributed to its generators, and one declared stall -- so a reader of NamespaceWaveAdmissionEnrolled cannot take it for a third wall over closure or for occurrence grain. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… the class admission arrives one grain down Three facts measured against the carriers by the owning program's session rather than against intent (snappy-dove-250, 2026-08-26): A requalification wave prepends the declarer's path and leaves the declarer fixed, so it changes the authored spelling and leaves the last segment invariant BY CONSTRUCTION. This wall's key is therefore invariant under exactly the operation the cut performs, and the reduction has a named authority already: v1.05_emit_rust rust_fn_sig_leaf_name_dotted_note names qualified_last_segment. Recorded as an invariant rather than as a finding, because a finding invites re-litigation. TargetChanged firing on a symbol move is signal, not tax: the owning program splits requalification and relocation into separate diffs, so that refusal reports a mis-shaped wave. No exemption, threshold or allowance is admitted. LegacyBindingObservationRow carries only an occurrence identity and an outcome, so a class admission must project down to this wall's key -- through an authored_name that carries dots and reduces only through qualified_last_segment, a trap that fails silently because on an unqualified reference the spelling and the leaf are identical. The grain note also said 'spelling' where the implementation keys on the leaf; that is corrected here rather than left to drift. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…te, and argue the residue per declaration The operator ruled that a request to add hand Rust is the occasion to migrate or delete hand Rust. This change answers at DECLARATION grain rather than as a count, and it does not buy the count down by shrinking the wall. DELETED, measured rather than argued: - `leaf_of` was a NICKNAME for `v1.00_core` `qualified_last_segment`, which `v1.05_emit_rust` `rust_fn_sig_leaf_name_dotted_note` names as the single authority for taking an authored spelling to its last segment. The wall now calls that mirror. This is the stronger construction as well as the smaller one: the reduction the wall keys its rows on is now the corpus authority instead of a local respelling of it. - `render_set`, inlined at its two call sites. - `claim_executor` carried a BYTE-IDENTICAL PRIVATE COPY of `git_stdout`. The wall needed the same helper, so rather than land a third spelling the lib owns the one copy and the bin's is deleted. Net minus one PRE-EXISTING hand declaration. Four inherent methods became free functions, because `std.decl_ref` offers only `WholeDeclaration` and `NamedField` -- a method on an impl block is UNCITABLE, so as methods they were items the seed-growth roster structurally could not enumerate. The module now carries no impl block. The roster went 25 -> 33 rows, which is the honest direction: it was JOINED against the module's actual declaration population instead of listed from memory, and six declarations were missing from the first draft. `gunbc.seed_growth` already warns that `hand_authored_declarations` is an authored obligation roster rather than a derived denominator; this is that warning firing on its own first use. The residue is argued per class, not asserted as irreducible. Class A (28 declarations) is a pure fold whose INPUT TYPE is host-only: `ModuleDeclarationRecord` and `DeclarationIndex` have no `.dag` carrier, and authoring one here would be the second representation `gunbc.declaration_index_seed_growth` already owns -- so this roster follows that carrier's first step rather than forking it. Class B (4 declarations) is blocked on a typed repository-read transport, which is the scm lane's subject. Verified: `cargo check -p v1-compiler --bin claim_executor` clean, 14/14 fixture arms pass, `cargo fmt --all --check` clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`claim_executor` imported `std::path::Path` for its own copy of `git_stdout`, which the previous commit deleted in favour of the lib's. Bare `Path` was then reachable only from one `#[cfg(test)]` site, and the build lane runs with `-D warnings`, so `unused_imports` is an ERROR there and both lanes refused. The import is narrowed to `PathBuf` and the single test site spells the type in full, matching the ten other `std::path::Path` uses already in the file. WHY MY OWN CHECK DID NOT SEE IT, recorded because the check was not wrong, it answered a different question: I verified with `cargo check -p v1-compiler --bin claim_executor` and no RUSTFLAGS. The gate runs `cargo build --release -p v1-compiler --bins` with `-D warnings` -- more targets AND warnings promoted -- so a green check under weaker flags is not evidence about the gate. Any DELETION of host Rust can strand an import, so the deletion half of the operator's directive is exactly where this class fires. Verified: RUSTFLAGS="-D warnings" cargo check -p v1-compiler --bins, fmt clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ring Review 56411 (non-blocking) noticed that folding the two copies together left the function on `trim_end` where the private copy used `trim`. The behaviour is right; the doc comment above it still said "trimmed stdout", which is the sentence a future caller reads before choosing this helper. The asymmetry is deliberate and now says so: one caller asks for the CONTENT OF A FILE at a ref, and a `.dag` module whose first line is indented would arrive with that indentation eaten -- a different file from the committed one, compared against a head side read from disk intact. Checked per caller rather than asserted: `rev-parse`, `merge-base` and `diff --name-only` carry no leading whitespace; `status --porcelain` re-trims at both of its use sites AND is the one worth noticing, because its lines BEGIN with the two-column XY code -- a leading `trim` would have corrupted a status read rather than tidied it. So the pre-existing caller is not merely unharmed by the change, it is better served by it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ones by their generators Main moved three times while this PR sat at the approval floor and #9352 landed as a SQUASH, so this branch carried its original commits against main's flattened one. THE SPLIT IS TWO AUTHORED AND THREE GENERATED, not one and four. `claim_executor.rs` LOOKS like a stage0 mirror by its path and is not: it has no `// Generated by v1 compiler` header and no `.gitattributes` entry, while a real mirror announces itself. Nothing generates it, so waiting for a generator to resolve it would have waited forever. AUTHORED, resolved by hand: - `seed_growth_admission.dag` -- both sides ADDED a roster entry, so it is a union rather than a choice: mine plus main's `target_invocation`, import list re-sorted. - `claim_executor.rs` -- both sides DELETED different things in one region. Main deleted two test mods whose production symbol `witness_walk_flags` no longer exists; this branch deleted the duplicate `git_stdout`. Verified against main that neither mod survives and only `git_stdout` sat between the surrounding braces, so the region collapses to nothing. GENERATED, resolved by regenerating -- the driver REFUSES these rather than picking a side, and it was right to: the ours side carried this branch's `namespace_wave_admission` row and had silently DROPPED main's `target_invocation_host`. Taking either side loses the other's authority-derived content with no conflict to show for it. `--required-regen` named exactly one drifted file, `gunbc_stage0_crate_layout_generated.rs`, installed from the candidate tree; the confirming pass ran a binary REBUILT FROM THE INSTALLED SEED and reported `first_generation_equal=true` (the single `declared_divergent [main.rs]` is the standing declared divergence). One pass alone can self-verify at divergence 0 for the wrong reason, which is why the rebuild is not optional. TWO MAIN-DRIFT FACTS SURFACED AND ARE DELIBERATELY NOT LANDED HERE. `DESIGN.md` is registered `merge=generated-artifact`, but #9366 edited DESIGN.md alone with no `.dag` authority change -- its new 4b(3) clause exists in no module under `dag/` or `src/v2/` -- so a faithful regeneration REVERTS it. Separately the generator adds three `.gitattributes` rows main lacks. Both files are restored to the merge result: #9366's clause is preserved here, and repairing the underlying drift belongs to whoever owns it rather than buried in a wall PR. Verified: RUSTFLAGS="-D warnings" cargo check -p v1-compiler --bins clean, 14/14 fixture arms pass, fmt clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both findings in review 56449 are confirmed by reading the code, and my own doc comment on `base_records` carried the erroneous rationale verbatim -- "that is the conservative direction: it can only make the wall quieter" -- which is exactly the empty-observation narrow DESIGN names: bottom-as-answer conflated with bottom-as-ignorance, strictly worse than the widen section 5 forbids, because a widen is merely expensive and a narrow is silently uncovered. Two fixes, one per finding: `base_records` returns `Result<Vec<ModuleDeclarationRecord>, String>` and refuses when the base-side parse produced any diagnostic. A source that does not parse at the base revision has no readable declarations; it does not have zero of them. Reading it as empty made every declaration in the head revision look new, so the wall adjudicated a baseline it had never observed. The base-side loop establishes absence from `git ls-tree -r --name-only <base>` -- an authoritative listing of what the base revision contains -- rather than inferring it from a `git show` failure. A path missing from that listing was genuinely added by this change; a path present in it whose content cannot be read, or whose content does not parse, now returns `NotEvaluated` with the reason, so "could not compare" can never render as "nothing changed". Mutation receipt, one mutation, restored between: baseline 15/15 green; revert `base_records` to `Ok(Vec::new())` on the diagnostic arm; 14 passed, 1 failed, and the one red is `a_base_side_source_that_does_not_parse_refuses_instead_of_reading_as_empty` -- it fails alone. Restored, 15/15 green, `--bins` clean under `-D warnings` with `forwarding env: RUSTFLAGS` confirmed on the dispatch. The new arm carries its own positive control on the same function: a well-formed baseline still reads a non-empty record set, so the arm cannot pass by refusing everything. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Review 56449 (codex/gpt-5.6-sol, REQUEST_CHANGES) — both findings confirmed and fixed in fdf66e2. They were correct, and the rationale for the defect was sitting in my own doc comment on Finding 1 — base-side parse diagnostics read as an empty record set. Finding 2 — every Mutation receipt (one mutation, restore between): baseline 15/15 green → revert |
Review 56459 (non-blocking) found a 26-space run mid-string in the namespace-wave-admission NOT RUN message. It was a line-wrap artifact rather than deliberate spacing, and it reaches the operator's terminal verbatim, so the one diagnostic a reader sees when the phase declines to adjudicate was the least legible line the phase can print. Repaired with a `\` continuation so the rendered text reads `did not produce an index`; the wording, the `phase_failures` push and the fail-closed behaviour are untouched. Checked with the build lane's own flags: `cargo check -p v1-compiler --bins` under `-D warnings`, with `forwarding env: RUSTFLAGS` confirmed on the dispatch, since a check weaker than the gate on either the target set or the warning level carries no information about the gate. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review 56471 is correct. `run_required_wave_admission` read `git diff --name-only` as BOTH sides of the comparison, and rename detection is on by default, so a detected rename is reported as its destination alone. The source path therefore never entered the base-side re-read -- it is not in the list -- and the destination is absent from the base tree, so the module's entire baseline vanished: every declaration in it read as newly added, and a required wall could refuse an ordinary `.dag` rename over a delta it had invented. That is the same class as the two defects review 56449 found, one level out: an observation that could not express what happened rendered as a verdict about what happened. `diff_sides` reads `git diff --name-status -z -M` and routes each entry to the two sides SEPARATELY: a rename contributes its destination to the head-touched set and its source to the base side, an addition contributes only a head path, a deletion only a base path, and an ordinary modification the same path to both. Scope is applied per side, because a rename can cross the sweep boundary in either direction and the two sides must be measured by one instrument. The parse is a pure function over the diff text, so the RED is authorable at the fixture boundary and is authored there rather than argued in a comment. Mutation receipt, one mutation, restored between: baseline 16/16 green; revert the rename arm to push the destination onto both sides -- exactly the shape `--name-only` forced on the old code -- and the result is 15 passed, 1 failed, the single red being the rename arm. It fails alone, and the A/D/M controls beside it stay green under that mutation, so the arm discriminates the one distinction the review named rather than asserting the parse's shape. Restored: 16/16 green, fmt clean, `--bins` clean under `-D warnings` with `forwarding env: RUSTFLAGS` confirmed on the dispatch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Review 56471 (codex/gpt-5.6-sol, REQUEST_CHANGES) — confirmed and fixed in 7b135fd. The finding is right, and it is the same class as the two in review 56449 one level out: an observation that could not express what happened rendered as a verdict about what happened. Fix. Mutation receipt (one mutation, restore between). The parse is a pure function over the diff text, so the RED is authorable at the fixture boundary and is authored there rather than argued in a comment. Baseline 16/16 green → revert the rename arm to push the destination onto both sides, exactly the shape Also in this push: 450f351 repairs the whitespace nit from review 56459 — a line-wrap artifact left a 26-space run inside the namespace-wave-admission — sent from nimble-moth-416 |
…ut of NewPoolCoincidenceResolution (#9495) * `0 -> 1` was two states: split AuthoredReferenceResolution out of NewPoolCoincidenceResolution The wave-admission wall (#9365) classified every binding whose candidate set went from empty to one member as `NewPoolCoincidenceResolution`, refusing unless an operator admission names it. `binding_disposition` compares candidate SETS only, and its own header says that arm means "a name that began denoting something WITHOUT ANYONE AUTHORING A REFERENCE — resolution arriving from a pool". That is one of two states sharing the symbol, and they have opposite owners and opposite repairs: - the TARGET grew a name this module was already reaching for — the coincidence the containment rule exists to remove, cause in another module; - this module's own author wrote the import that resolves a name it was already spelling — the exact repair the wall was built to want. The wall was refusing the second while naming it the first. Found by gunbc#9485, a one-line import repair (5 blocking diagnostics -> 0) that the wall would not let merge, and it could not be admitted either: `NAMESPACE_TRANSITION_ADMISSIONS` is a `const &[TransitionAdmission]` over a `DeltaSubject` carrying `String` fields, so a row naming an actual module is E0015 — that half is escalated separately and is not repaired here. The discriminator is the module's own source, and it was already in hand: the membership arm one function over consults `membership_supported`, which admitted the membership edge of the very change whose bindings were refused. `locally_authored_claim_added` answers it from the two `ModuleDeclarationRecord`s alone — deliberately index-free, because consulting either index reintroduces the conflation (a blanket import whose target grew the leaf would read as authorship). False is the fail-closed answer: it leaves the delta on the refusing arm. The new disposition auto-admits, amending the 2026-08-26 operator partition on `gunbc.compiler_frontend_program_interlock` per the 2026-08-27 ruling relayed through swift-badger-524. The `.dag` coproduct is the authority and the host enum is one realization; the vocabulary-join tests (host <-> ruling, both directions) gate the pair and pass. EXECUTED EVIDENCE. The test file asserted `NewPoolCoincidenceResolution` over a head that authored `import probe.home { widget }` — it planted the repair and named it the coincidence, which is why the conflation survived review. That fixture is re-derived as the authored arm, and a real coincidence is authored for the other: consumer source byte-identical across sides, reaching the target through a blanket import, target grows the name. Both arms mutation-checked: forcing `locally_authored_claim_added` true reds the coincidence arm alone, forcing it false reds the authored arm alone. 20/20 green restored. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TrqmnrTJvHxHxJuJFBED8k * Scope the blanket-import arm to the leaf: an unrelated new blanket import was laundering a pool coincidence Review 56882 on this PR, before it merged. `locally_authored_claim_added`'s member-list and self-declaration arms name the leaf in the source and were scoped to it; the blanket-import arm names no leaf at all, and the first revision admitted authorship whenever ANY blanket target was new. So an unrelated new blanket import elsewhere in the same module auto-admitted a genuine pool coincidence beside it — a fail-open widening, in the one direction this function must never move, and directly opposite the docstring's own "false is the fail-closed answer". THE ARM IS NOW A CONJUNCTION AND THE ORDER OF ITS HALVES IS THE POINT: the claim must be NEW IN THIS MODULE'S SOURCE **and** the head target must actually supply the leaf. Asking the second alone is exactly the conflation this function exists to discriminate — an unchanged blanket import whose target grew the leaf would read as authorship. Gating it behind the first makes the index consultation safe rather than forbidden: a claim the author did not write cannot reach the surface check, whatever the target did. So the docstring's index-free claim is corrected rather than restated; it was true of the leaf-named arms and never of this one. A target absent from the index answers false. EXECUTED EVIDENCE, both directions of the scoping: - an_unrelated_new_blanket_import_does_not_launder_a_pool_coincidence — the reviewer's scenario. `probe.home` grows `widget` with its blanket import UNCHANGED; the author adds a blanket `probe.other`, which does not supply `widget`. Must stay NewPoolCoincidenceResolution and must stay refused. Restoring the leaf-blind arm reds this test ALONE. - a_new_blanket_import_that_does_supply_the_leaf_is_an_authored_reference_resolution — so the scoping is not a narrowing to nothing: when the NEW blanket target is the one supplying the leaf, it auto-admits like any other authored reference. 22/22 green, fmt clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TrqmnrTJvHxHxJuJFBED8k * extdeps.container.oci.manifest uses three media_types symbols it never imported (#9485) `accept_image_manifest` reads `oci_image_schema_version`, `media_type_oci_image_manifest_v1` and `media_type_oci_image_config_v1`, all declared in `extdeps.container.oci.media_types`, with no import of that module — five BLOCKING name-resolution diagnostics standing on main. Adds the one import. This is a live specimen of the DESIGN row declaring the blocking-diagnostic population uncounted and unbounded: no required phase emits over a closure reaching this module, so nothing refused. Claude-Session: https://claude.ai/code/session_01TrqmnrTJvHxHxJuJFBED8k Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ge chain, deletion-subject roster, derived wave-wall enrolment The manager ledger said the wave-admission wall was unbuilt while #9365 had landed it as a required phase. This makes the control plane derive instead of declare: - gunbc.required_ci_phase_roster: substrate authority for required-CI phase identity and lane ownership (the census's own named next rung). The workflow emission consumes its lane vocabulary (fabric_witness_run lane words are now derived), and every --required-ci run joins the host RequiredCiPhase enum against the declaration's variant set in both directions and refuses on divergence (claim_executor phase_roster_findings, the vocabulary_findings shape). Lane-match parity is declared residue under the census's atomic-deletion trigger. - gunbc.namespace_cut_stage: the NAMESPACE-XL serial chain (F-0, XL-0..XL-7, ACT-0) as a closed variant with TOTAL stage_prerequisites and stage_milestone_prerequisites (ACT-0 carries the interlock triple, by operator ruling), plus the activation-receipt gate carrier. - gunbc.namespace_cut_subject_roster (+ live sibling gunbc.namespace_cut_subject_observation): every authority scheduled to disappear as string-identity probes (authored decl_ref literals would refuse at ingestion the moment a wave deletes a target), each with a total observation rule: Present/Absent by runtime declaration-ref resolution, Unobservable (typed, with trigger) for host Rust items and ambiguity. Executed: all substrate probes PRESENT, per-root acquisition after a measured union-walk OOM. - compiler_frontend_program_status: NamespaceWaveAdmissionEnrolled derived from the phase roster (CLEAR); NamespaceBaselineObservationComplete Outstanding from the capture capability's blocked reasons; the three deletion milestones derived from the subject roster at declared-row grain; the stage chain rendered in where_are_we with standings and startability; instrument roster updated (three rows retired by delivery, cargo-execution fact and XL-3 spelling census added, conditionally-awaited roster for the CaptureAvailable contract). - plan repoints: import_namespace_program section 9 gap closed by carrier citation; namespace-cut-replacement-plan.md carries a current-state authority banner instead of stale enrolment prose. Verified by execution (BuildBuddy + local): parse sweep 4328 files clean; where_are_we renders the exit shape (wall CLEAR, baseline OUTSTANDING, later stages blocked on named prerequisites); subject_roster_report green in 1m49s; falsifiers executed mutate/red/restore/green (roster row removal reads Outstanding; planted stage and subject variants refuse to compile at every total match); status witnesses 30/30 PASS, observation witnesses 4/4 PASS. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GpYEk9gSYmMkwL1489D79U
…ge chain, deletion-subject roster, derived wave-wall enrolment (#9698) * F-0: truthful namespace control plane — phase roster, NamespaceCutStage chain, deletion-subject roster, derived wave-wall enrolment The manager ledger said the wave-admission wall was unbuilt while #9365 had landed it as a required phase. This makes the control plane derive instead of declare: - gunbc.required_ci_phase_roster: substrate authority for required-CI phase identity and lane ownership (the census's own named next rung). The workflow emission consumes its lane vocabulary (fabric_witness_run lane words are now derived), and every --required-ci run joins the host RequiredCiPhase enum against the declaration's variant set in both directions and refuses on divergence (claim_executor phase_roster_findings, the vocabulary_findings shape). Lane-match parity is declared residue under the census's atomic-deletion trigger. - gunbc.namespace_cut_stage: the NAMESPACE-XL serial chain (F-0, XL-0..XL-7, ACT-0) as a closed variant with TOTAL stage_prerequisites and stage_milestone_prerequisites (ACT-0 carries the interlock triple, by operator ruling), plus the activation-receipt gate carrier. - gunbc.namespace_cut_subject_roster (+ live sibling gunbc.namespace_cut_subject_observation): every authority scheduled to disappear as string-identity probes (authored decl_ref literals would refuse at ingestion the moment a wave deletes a target), each with a total observation rule: Present/Absent by runtime declaration-ref resolution, Unobservable (typed, with trigger) for host Rust items and ambiguity. Executed: all substrate probes PRESENT, per-root acquisition after a measured union-walk OOM. - compiler_frontend_program_status: NamespaceWaveAdmissionEnrolled derived from the phase roster (CLEAR); NamespaceBaselineObservationComplete Outstanding from the capture capability's blocked reasons; the three deletion milestones derived from the subject roster at declared-row grain; the stage chain rendered in where_are_we with standings and startability; instrument roster updated (three rows retired by delivery, cargo-execution fact and XL-3 spelling census added, conditionally-awaited roster for the CaptureAvailable contract). - plan repoints: import_namespace_program section 9 gap closed by carrier citation; namespace-cut-replacement-plan.md carries a current-state authority banner instead of stale enrolment prose. Verified by execution (BuildBuddy + local): parse sweep 4328 files clean; where_are_we renders the exit shape (wall CLEAR, baseline OUTSTANDING, later stages blocked on named prerequisites); subject_roster_report green in 1m49s; falsifiers executed mutate/red/restore/green (roster row removal reads Outstanding; planted stage and subject variants refuse to compile at every total match); status witnesses 30/30 PASS, observation witnesses 4/4 PASS. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GpYEk9gSYmMkwL1489D79U * Adjudicate the RequiredCiLane move: two exact TargetChanged admissions The required namespace-wave-admission phase refused #9698 with exactly two unadjudicated deltas: BuildLane and WitnessesLane in the census's required_ci_host_verdict_rows now bind through gunbc.required_ci_phase_roster instead of the census itself — the declaration move this PR performs on purpose, at the census's own named next rung. Two exact-identity admission rows adjudicate them, per the roster's rule (enumerated identity, never a predicate). They go stale when this PR merges and are owed removal in the follow-up, exactly as the roster's three prior shrinks record. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GpYEk9gSYmMkwL1489D79U --------- Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The wave-admission wall: the enforcement mechanism the namespace plan names as a BLOCKER
gunbc.plans.import_namespace_program§9 records, in its own words, that "no CI mechanism enforces any of this — no ratchet, no phase, no gate over the import population", and the 2026-08-26 operator ruling carried atgunbc.compiler_frontend_program_interlockconverts that disclosure into a BLOCKER:milestone_prerequisitesgatesNamespaceFirstSemanticWaveonNamespaceWaveAdmissionEnrolledby name. This PR is that milestone.The plan's own sentence is the acceptance condition, and it is the one I built against: a plan that reads as governed when it is not is worse than one that reads as unguarded. So the deliverable is not assurance added to a governed program — it is closing the gap between what the plan CLAIMS and what is true.
What runs
A new required phase,
namespace-wave-admission, inclaim_executor --required-ci, witnesses lane, ordered afterparse.run_dag_parse_sweepalready parses every authored.dagon every required run; that index is the wall's HEAD side. The BASE index is the head index with the diff applied in reverse at file grain — only the files the change touched are parsed again, from their base blobs — while closure and bindings are recomputed over both whole graphs, because a module whose own text did not move can still have its subject moved by one that did.NamespaceChangeClasssplits preparatory work from work that alters membership or binding; nothing asks an author which they wrote.PreparatoryNoSemanticMotionis a measured property of a diff, not a claim in a PR body.NoSubject(a push whose baseline IS its head — main after a squash merge) compared nothing and admits nothing.NotEvaluated(a baseline that does not resolve) refuses, per the ruling's partition: I could not see what changed and nothing changed are different states.The three deltas, and the one that is not a wall
Closure is a pure function of membership, so the closure moved and no membership moved is not a state any fixture can author. An arm for it would be permanently green by construction — the decoration §4b calls worse than absent. So closure is measured and attributed, never separately adjudicated: each delta carries the number of modules whose subject it moves, so a refusal names its blast radius, and the adjudication happens at the generators. Saying so is the difference between a scope statement and an inflated one.
Two design decisions that took the whole shape
1. The grain is authored containment identity, and that is a CLOSED result.
v2.workflow.legacy_binding_deltaestablishes it for its own subject and the argument transfers unchanged:std.occurrence_identity's scope law forbids filename, span, authored name, structural equality and content hash as identity inputs, and anOccurrenceIdis a monotone counter consumed in walk order, so it encodes POSITION. A cross-compile correspondence is something a transformation emits — and between a merge base and a PR head there is no transformation to emit one. An occurrence-grain delta between two arbitrary trees is therefore unavailable by construction, not a better key waiting to be found. The wall uses the identitylegacy_binding_observationlegacy_subject_identityalready folds: module path, enclosing declaration, and the leaf segment of the reference. A row's value is the SET of declaring identities, never a winner — so a local declaration arriving beside an imported one widens the set to two and reportsNewAmbiguityrather than silently picking the nearer, which is the mechanism the namespace authority exists to delete.The leaf rather than the whole spelling is a fixture finding, not a preference: keyed on spellings,
widgetandprobe.home.widgetare two rows, so requalifying a reference reads as one name losing its declaration — and requalification is the namespace program's own core motion. A wall keyed on spellings would refuse the program in its entirety.2. The binding channel is not the import channel. A wall reading bindings only through import members would observe the import-name universe being deleted and then see nothing at all — blind on precisely the change it gates. So it reads every authored name occurrence in a module's own parsed tree and resolves it independently (dotted spelling by longest module prefix; bare spelling against the module's own declarations and its import claims, following re-exports to the module that actually DECLARES the name). It survives the cut because it never depended on the construct being cut, and the function is identical on both sides, so a base measured before a cut and a head measured after it are measured by one instrument. It is parse-then-derive over the
Nodetree, not the raw-text scanner DESIGN ruled a heuristic.The RED is the deliverable — and it caught a wall that would have refused the program it exists to admit
The headline is not the seven mutations, it is the two arms that failed on their FIRST run. One of them was this: keyed on the whole spelling rather than the leaf segment, requalifying a reference reads as
NewUnresolvedness— and qualification is precisely what the namespace program's projection does. The wall would have refused the only program it exists to admit. Nothing about the code was inconsistent, so no amount of reading would have found it; a fixture going red did.adjudicatetakes two indexes and no git, so the fixture boundary — which is where §4b says reachability is judged — authors a base tree and a head tree and reads back the exact disposition. Every refusing arm is one mutation of the auto-admitted control.Measured by running each mutation ALONE against the production predicate, with a restore between and a re-run confirming the restore returns to green with no residue (
cargo test -p v1-compiler --test namespace_wave_admission, remote runner):NewUnresolvednessarm →TargetChangeda_spelling_that_stops_denoting_anything_refuses_as_new_unresolvednessNewPoolCoincidenceResolutionarm →TargetChangeda_spelling_that_begins_denoting_something_refuses_as_pool_coincidenceNewAmbiguityarm →TargetChangeda_second_declarer_on_the_chain_refuses_as_new_ambiguity,a_local_declaration_beside_an_import_is_a_two_member_set_not_a_winnermembership_supportedalways trueremoving_membership_nothing_bound_through_is_admitted_as_unusedan_admission_naming_a_different_subject_does_not_admit_and_reports_staledropping_an_import_for_a_qualified_spelling_keeps_the_declarer_and_is_admittedauto_admittedreturns true for every dispositionBaseline green before the first mutation; green again after every restore; 14 arms, 0 failures. Two mutations red more than one arm and both are the same branch or the same partition covered from two directions — no arm is red under a mutation that does not reach it.
Two arms failed on their first run and both were real findings in the production code, not fixture defects: the leaf-keying correction above, and a fixture whose "unused" import supplied a leaf the module reached by another route — a malformed plant reading as a wrong verdict, now guarded by a plant assertion.
The vocabulary join
The host
NamespaceDeltaDispositionis a second representation of the.dagcoproduct. The exhaustivematchprotects this file's internal consistency and says nothing about the carrier: a variant added to the ruling and not here compiles perfectly. So the phase runs a set-equality join in both directions against the authority's own parsed variants, before any verdict — and an absent authority refuses, because that is the state in which nothing is checking the vocabulary.What this does NOT claim
GuaranteeStall, with its blocker stated as the closed result above rather than as effort..dagunder the three sweep roots is observed.SeedGrowthJustificationwith reason, trigger and current boundary, and classified against the v1 freeze on the same purpose testdeclaration_indexlanded under — but that is my classification, offered as evidence for a reviewer, not a permission I hold. An author who can write a scaffold can equally write a row claiming it was approved (DESIGN, 2026-08-10). warm-hawk-909 is taking it to the operator alongside Replace hostile-writer shell scaffold with typed host effect #9363's, so both are decided against one test. A reviewer telling me the classification is sound is not the same as admitting the growth.Cost
Measured on the live corpus (4,099 modules) on the remote runner:
parse sweep (already paid by the
parsephase): 21.1sidentity arm — the same corpus on both sides: 4.2s, 0 deltas, over
modules_compared=4099,membership_edges_head=21940,binding_rows_compared=724873. The denominator is the other half of that zero: a green that cannot say what it covered is an instrument failure wearing coverage's clothes.a live RED, on a real module: taking
dag/gunbc/accelerator_demo_plan.dagwith its one real import removed as the head, the wall reports exactly one delta over the same 724,873 rows —and refuses (
unadjudicated=1). Note what it did not report: thestd.realizationmembership edge SURVIVES, because that module reaches it by dotted spelling at five other sites, so the edge is genuinely still there. The wall said only the true thing.Corpus integrity after the change, from the standalone sweep at this head:
4099 file(s) parse-clean; declarations modules=4099 declared=78825 import_members=82277 citations=1552 debt=42 in_fixtures=173 outside_index=174 kernel_named=2041 lens_modules=70— zero findings, so the new carrier's imports and every one of its citations resolve. Rust suite (not in CI, run remotely):namespace_wave_admission14/14,declaration_index_integrity25/25.So the phase costs about 4 seconds on top of a parse the required run already performs, and it acquires no second corpus.
Its first catch was its own dispatcher
While measuring the wall over the real corpus I found that the branch this one stacks on — #9352,
session/warm-hawk-909ata5a4110b7b— failed the required parse phase on eight//annotations authored insidedata … = [ … ]initializers, which §4c does not admit. Reported, and fixed by that session at233c358ee3before this PR merged their updated head.It is worth recording for a reason beyond the fix: the previous
.dagwalk would have returned CLEAN on all eight, becausetokenizeroutes//into the annotation channel and grain is decided later — DESIGN carries that receipt. A check that existed, ran, and could not see the thing it appeared to cover is exactly the failure mode this wall is built not to be.It has executed on the real path
Not a local measurement — the phase running inside
witnesses.yml, floor lane. Taken from run33023922255, all three jobs green (build,floor,witnesses), on this PR's currenthead
930ef47a0.State the provenance exactly, because the wall's own subject depends on it: the phase reports
head=a946db44, which is the PR merge ref GitHub constructs, not the branch tip. That isthe correct subject — the question the gate asks is what this change does when merged — and
saying so is the difference between a receipt and a number.
Read what that says, because it is the whole design executing on its own diff:
NotEvaluatedarm is not the one this repository lands in — the risk I could not close from a remote runner (which fetches at depth 1 and has noorigin/main) is closed here.ExplicitlyEvaluatedZeroDelta, derived from the fact that a name the module authors reaches into the target. Nobody classified them; the wall did.closure_rows_moved=741, with blast radii of 356, 356 and 29. This is the part that would have been a third wall: the closure motion is real and large, it is attributed to the three membership edges that generate it, and it is adjudicated at those generators rather than 741 more times.An earlier revision of this section reported run
33020161158at headde1445990ce8, and said sounder a caveat that the RUN had been cancelled while the PHASE completed first. That caveat is no
longer needed and the numbers are replaced rather than annotated: two receipts for one claim is two
accounts of one fact.
Stacking
This branch merges
session/warm-hawk-909(#9352), because the wall consumesgunbc.compiler_frontend_program_interlock's disposition vocabulary and citing it from main would resolve to nothing. Those four files are #9352's, not this PR's. When #9352 merges I will merge main and the diff narrows to this change alone.Independence
Dispatched outside the program it gates — snappy-dove-250 declined ownership on the ground that a program parented over its enforcement grades its own homework. I took the domain semantics from them (all three answers changed the design) and kept what counts as ADMISSIBLE here.
🤖 Generated with Claude Code
Hand Rust: the growth, and what it bought back
Operator, relayed: "yes we need to stop adding hand rust asap" and "use it as an opportunity to migrate/delete hand rust". Answered at declaration grain, in
gunbc.namespace_wave_admissionnamespace_wave_admission_seed_growth_justification, so the argument is a typed carrier rather than a PR-body claim.(2) What this PR deletes or migrates — measured, not argued.
leaf_ofDELETED. It was a nickname forv1.00_corequalified_last_segment, the symbolv1.05_emit_rustrust_fn_sig_leaf_name_dotted_notenames as THE authority for taking an authored spelling to its last segment. The wall now calls that mirror. This is the stronger construction as well as the smaller one: the reduction the wall keys every row on is now the corpus authority instead of a local respelling — a §3 fork this change had introduced and removed before landing.render_setDELETED, inlined at its two call sites.git_stdout: a NET REDUCTION of one pre-existing hand declaration.claim_executorcarried a byte-identical private copy. The wall needed the same helper; rather than land a third spelling, the lib owns the one copy and the bin's is deleted and imported.std.decl_refoffers onlyWholeDeclarationandNamedField. A method on an impl block is uncitable — as methods they were items the roster structurally could not enumerate. The module now carries no impl block.(1) Can any of the residue be modeled instead? Per class, with the blocker named.
adjudicate,binding_rows,binding_disposition,declaring_candidates,declarer_of,closure_of,membership_map,direct_membership,module_prefix_of,membership_supported,blast_radius,disposition_label,disposition_auto_admitted,delta_subject_render,report_unadjudicated,render_delta,vocabulary_findings, and the types and constants they fold over). Every one is a pure function of two indexes and needs no host effect. They are Rust for exactly one reason, and it is not effort: their input type is host-only.ModuleDeclarationRecordandDeclarationIndexare produced by a host walk and have no.dagcarrier. Authoring one here would be a second representation of a typegunbc.declaration_index_seed_growthalready owns — the §3 violation this wall exists to refuse elsewhere — so the correct move is to follow that carrier's migration rather than fork it. Its own trigger already names this class ("the record builder and every finding function follow it"); this roster is one of those consumers.git_stdout,in_sweep_scope,base_records,run_required_wave_admission). Named separately because they are blocked on a different grounding: there is no typed repository-read transport a.dagfold can call to obtain a file's text at a ref. That is the scm lane's subject, not a surface this change could have authored.(3) The count went UP, 25 → 33, and that is the honest direction. The roster was joined against the module's actual declaration population instead of listed from memory; six declarations were missing from the first draft.
gunbc.seed_growthalready warns thathand_authored_declarationsis an authored obligation roster rather than a derived denominator — this is that warning firing on its own first use, caught here rather than by a reviewer.What was NOT done: the wall's coverage was not shrunk to lower the number. A smaller wall that adds less Rust spends correctness to buy a metric, which is the ratchet failure DESIGN names from the other direction.
A trap worth naming, met while resolving the merge
/usr/local/bin/gunbcis a June 26 binary. Running the generated-artifact gate through itfails with a wall of
error: function 'X' not found in scope— includingfold, thesubstrate's core catamorphism. That reads as corpus breakage and is not: the symbols are absent
from the old binary's view, not from the tree. If
foldwere genuinely missing, nothing wouldcompile.
Build the current one and invoke it by path:
It must be local: BuildBuddy runners are linux/amd64 and the session container is arm64, so a
remote build yields a binary that cannot execute here — and the regenerated files have to land in
this worktree anyway.
Recorded here rather than left in two people's heads, because anyone hitting it cold will file a
bug against the tree.