Skip to content

The parser never stamped a type declaration, so every type reference in the corpus was unbindable - #10166

Merged
gunbai-bot[bot] merged 10 commits into
mainfrom
session/deep-lark-560-type-decl-stamp
Sep 3, 2026
Merged

gunbai-bot[bot] merged 10 commits into
mainfrom
session/deep-lark-560-type-decl-stamp

Conversation

@briansrls

@briansrls briansrls commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

READ THIS BEFORE THE NUMBERS. "Type declarations 0 → 1243" is NOT a completeness claim and
must not be read as one. Condition 2 (exact declaration completeness) DOES NOT HOLD. The
census reports CensusUnavailable { DeclarationDomainDisagrees { missing, extra } } and REFUSES
to print a partition. This PR lands as a declared census-enabling scaffold: the instrument
that can see the problem, landing before the problem is solved, because withholding it keeps the
incompleteness invisible in everyone else's tree.

The parser never stamped a type declaration, so every type reference in the corpus was unbindable

This is the PREREQUISITE for the XL-0T cut, not the cut. It is on its own PR because it is a
change to v1.compiler.parse, which DESIGN names as load-bearing.

v1.compiler.parse stamped type REFERENCES as TypeOccurrence and never stamped a type
DECLARATION as one: ParsedOccurrenceDeclaration was produced with FieldOccurrence,
LexicalValueOccurrence, CallableOccurrence and NamespaceSegmentOccurrence only.
std.occurrence_binding_resolve admits a TypeOccurrence reference against a TypeOccurrence
declaration only, so the join had no right-hand side at all.

Measured by type_occurrence_binding_census --denominator dag/std (142 files):

reference_occurrences_by_category   = Callable 6971, Field 2830, LexicalValue 10226, Method 382, Type 9672
declaration_occurrences_by_category = Callable 1742, Field 2280, LexicalValue 6748, NamespaceSegment 142, Type 0   <- before
                                                                                                        Type 1243  <- after

Y therefore bound 0 of 9672 references before this change. That is the headline the earlier
census understated: the largest single class, OldKernel_NewUnresolved = 3136 (32.4% of the
denominator)
, was not evidence about Y's resolver at all — it was the empty declaration side
showing through.

Why the whole existing suite stayed green through it

Every fixture hand-builds its declarations with category: TypeOccurrence — exactly the shape
production never emitted — so the suite supplied the missing half of the join itself. Those
fixtures are correct about the authority's LOGIC; nothing here weakens them. They were never
SUFFICIENT, and nothing in the tree said so. DESIGN §5: a green suite that cannot see the
production population is not weak evidence, it is zero evidence, and it gets cited as coverage.

The declaration rule is three negatives, and the answer is (b)

(b): the parse tree genuinely carries no positive type-declaration marker. The parser
dispatches on the type / fn / data / service keyword and then DISCARDS which one it saw —
Node has no item-kind field, so by the time the occurrence walk runs the kind survives only as
which optional fields happen to be ABSENT. Every downstream reader (is_type_def_item,
is_function_item, is_data_def_item, is_service_def_item in
v1.compiler.emit_core_support) re-derives it from shape for the same reason.

So the rule is provisional and is written accordingly: not a bare predicate but an exhaustive
ParsedModuleItemKind match whose ModuleItemUnrecognized arm REFUSES with a located
diagnostic rather than defaulting into the type bucket. A bare predicate over three absent fields
fails open by construction, at the parser, where a wrong answer propagates into every consumer of
the occurrence transport and nothing fails when it starts being wrong (DESIGN §5: a failure arm
refuses, never widens).

What refusal does NOT fix, stated so it is not read as closed: it covers the residual that can be
EXPRESSED today. It cannot cover an item kind nobody has invented yet, because the discriminator
is absence and a new kind's absence looks identical to a type's. Terminal fix, a construction
rather than a check:
the parse constructors carry the kind they already know onto the item, at
which point this match reads a field and the emit-side shape predicates dissolve into it.

Evidence

  • src/v1/tests/claim/type_declaration_occurrence_control_test.dag — a PRODUCTION-FED control, not
    another hand-built transport. Its third conjunct is the state that was RED before this change: a
    subject with type REFERENCES and an empty declaration side. Executed: PASS.
  • It executes on NO required run — the required floor's source roots are dag and src/v2, and
    this subject is only reachable through v1.compiler.parse. Rung: mitigatable; the next-rung
    trigger (a witness home whose source roots reach src/v1) is stated in the file. Direct
    execution is evidence the assertions hold; it is never evidence that CI runs them.
  • --required-regen --source-root dag --source-root src/v2: first_generation_equal=true,
    planned=151 executed=151 adjudicated=151. Mirrors installed.
  • cargo clippy --all-targets -- -D warnings: clean. cargo fmt --all --check: clean.

The partition, all thirteen classes plus both unclassifiable arms

Instrument: type_occurrence_binding_census dag/std. Denominator 9672. Every grounding closes
exactly. Zeros are reported because a dropped zero row is indistinguishable from "not measured" —
OldKernel_NewAmbiguous = 0, OldSynthetic_NewAmbiguous = 0, OldUnresolved_NewAmbiguous = 0
together say Y introduces no new ambiguity anywhere, which is a load-bearing positive finding.

class NamespaceStructuralRoot ModuleLocalMember CrossFileProviderExported
OldAndNewAgree 2786 2786 4856
OldKernel_NewUnresolved 3136 3136 1204
OldBinds_NewUnresolved 2203 2203 20
OldSynthetic_NewUnresolved 909 909 9
OldUnresolved_NewUnresolved 367 367 367
OldSynthetic_NewBinds 250 250 1150
OldKernel_NewBinds 0 0 1932
OldAndNewDisagree 21 21 54
OldBinds_NewAmbiguous 0 0 80
OldKernel_NewAmbiguous 0 0 0
OldSynthetic_NewAmbiguous 0 0 0
OldUnresolved_NewAmbiguous 0 0 0
OldUnresolved_NewBinds 0 0 0
Unclassifiable_NoIndexEntry 0 0 0
Unclassifiable_NoModuleEnv 0 0 0
total 9672 9672 9672

OldSynthetic_NewBinds = 250 (1150 cross-file): X manufactured a synthetic identity where Y now
names an authored declaration. A synthetic id is not a declaration id and must never be netted
against one, so those are counted as their own class rather than folded into agreement.

The two module-scoped groundings are byte-identical to each other and only
CrossFileProviderExportedExposure discriminates — which is exactly what the earlier all-zero run
could not have told anyone, and retroactively confirms that the earlier byte-identical partitions
located the failure UPSTREAM of visibility rather than in the groundings.

Read the numbers with these three disclosures — they are printed by the instrument itself

  1. The X column is the POST-REWIRE persisted env, the one EMISSION reads. Pre-rewire inference
    answers are not measured; the two once disagreed on this exact subject.
  2. This is a TWO-READER COMPARISON, not correctness evidence
    (gunbc.recurring_failure_mode disagreement_census_blind_to_agreed_wrong). OldAndNewAgree
    means the cut does not MOVE this occurrence, never that it binds correctly. Both readers wrong
    together scores as agreement and is invisible here by construction.
  3. Undecided is a finding, not noise. Every New*Unresolved arm is inside the denominator.

Scope, declared so the next increment is driven by measurement

MODULE-LEVEL type declarations only. Coproduct variants and type parameters in type position stay
unstamped, so references to them stay Unbound and the census says so by name. MethodOccurrence
stands at 382 references against 0 declarations — the same gap in the same collector, not
addressed here. The cut is NOT attempted in this PR.


The seven-condition T1 bar, with the evidence for each

# condition evidence verdict
1 production source only, through tokenize → parse, no hand-built transport both new controls call parse_authored_occurrence_binding_source; the census join parses each file with parse_with_table and reads parsed.occurrence_transport HOLDS
2 exact declaration COMPLETENESS — every grammar-owned type declaration contributes exactly one occurrence exact-set join at occurrence-id grain vs. the emit-side reader. Residue 2 items in 1 module, attributed by the join to the OTHER reader (emit_core_support is_bare_leaf_item) DECLARED NOT HOLDING
3 exact SOUNDNESS — nothing else contributes one accidentally same join, extra = 0 on the merged corpus. This is the direction that caught the three resource items HOLDS
4 identity preservation — the occurrence is the declaration head's, already in the index stamp_parsed_node reads the node's existing OccurrenceMinted identity and mints nothing; the join checks every declaration id against that parse's own index (not_in_index = 0) HOLDS
5 non-vacuous binding — a production-parsed reference binds a production-parsed declaration through Y production_fed_exposure_discrimination_holds binds under CrossFileProviderExportedExposure; executed, PASS HOLDS
6 EXPOSURE DISCRIMINATION — different exposure fact, different outcome same control: same occurrences, same resolver, ModuleLocalMemberExposure → Unbound, CrossFileProviderExportedExposure → Bound; executed, PASS HOLDS
7 MUTATION CONTROL — removing the stamping reddens the production-fed witness while the hand-built suite stays green with the stamping reverted to ParsedOccurrenceUnclassified: both production-fed controls FAIL; control_one / control_two / control_three / control_api all PASS. Both halves executed HOLDS

Condition 2: declared NOT HOLDING, residue two items in one module, attributed to the other reader

The first version of this measurement said 202 grammar-owned type declarations were absent across
100 modules. That was a defect in this diff, not a corpus fact, and it was found before merge:
the ModuleItemResource arm added to fix the first fail-open keyed on properties being non-empty,
and type X sole_constructor { .. } carries a property too — so every sole-constructor type in the
corpus classified as a RESOURCE and vanished from the declaration population.

The repair excludes the modifier by an enumeration of minting sites, not by grep.
v1.compiler.parse has exactly two module-item property sources:
parsed_sole_constructor_properties (one field-init named sole_constructor, the only source every
type-item constructor passes along, four call sites) and parse_resource_entries. nominal_opaque
is dropped lexically by drop_leading_type_modifier and mints nothing;
mint_parsed_optional_int_property is confined to nested where-predicate nodes. The set of
modifiers mintable as a property on a type declaration is a closed set of one.
What breaks that
later is stated in the annotation: a second modifier that MINTS a property reintroduces this
silently and in the same direction, which no longer list can prevent.

Measured corpus-wide (type_occurrence_binding_census --establish over dag src/v2 src/v1):
modules_diverging 100 → 1, absent declarations 202 → 2, zero extras, zero duplicates,
zero index absences, zero parse failures. Both remaining absences are in that one module.

The residue is not this classifier's defect. resource Network and resource AuthContext
declare no capabilities, so with no children, body, params or connective they satisfy
v1.compiler.emit_core_support is_bare_leaf_item and the independent reader calls them type
declarations. Same class, different authority — filed, not repaired, as
gunbc.recurring_failure_mode absence_classifier_default_bucket.

The countermeasure, which is the transferable part

Those two were invisible while one classifier answered, because both readers agreed they were
types — the agreed-wrong pair a disagreement census cannot see by construction
(disagreement_census_blind_to_agreed_wrong), and no amount of running it harder finds them.
Splitting the question across two independently derived readers — absence-of-body/transport/
annotation in the parser vs. connective/params/children in the emitter — converted their agreement
into a disagreement, which is the only form the census can report.

WHERE A CENSUS COMPARES TWO READERS, A THIRD INDEPENDENTLY-DERIVED READER IS THE ONLY THING THAT
CAN FALSIFY THEIR AGREEMENT.

That split arrived here as a side effect of building the population join rather than as a design
goal, which is exactly why it is filed: reach for it on purpose when an agreed-wrong population is
suspected.

Generated artifacts are never resolved by picking a side

The four build errors on the previous head were not a partial regen from adding a module. They were
this branch resolving generated-artifact merge conflicts to --ours, which dropped main's
authority-derived bytes and left the crate root referencing modules that were still emitted but no
longer present. A generated artifact is regenerated from the merged authority, never resolved by
picking a side
— the merge driver refuses precisely to prevent this, and the loss came from
resolving past the refusal. The fourth error (Some(InferredNode::Divergent) non-exhaustive) was
stale mirror content, not an uncovered arm in the .dag.

Also worth recording: --required-regen does not project the ledger docs. It reported
first_generation_equal=true with docs/design-failure-modes.md still stale. The projection
actuator is gunbc run --source-root dag --source-root src/v2 --entry dag/gunbc/instruments/generated_artifact_gate.dag --function main_wet.

What the census now refuses to conflate

CensusUnavailable { DeclarationDomainAbsent | DeclarationDomainDisagrees { missing, extra } }
CensusObservedOnCurrentTree { joined_declarations }
CensusAdmissibleForCut { parser_carried_item_kind, joined_declarations }

"The join agrees on today's tree" and "the classifier is a durable authority" are different facts.
CensusAdmissibleForCut is unconstructible on this tree — the accepted bucket is still defined by
absence — and is modeled anyway, with a refusing arm, because leaving it unmodeled is what would
let the first be read as the second.

The resource fail-open, and the rule that generalises it

The join's first run found three items — Filesystem, Clock, Entropy in std.resources —
silently stamped as TYPE DECLARATIONS. A resource carries no body, no transport and no type
annotation, so the exhaustive match's refusing residual could not fire: a resource is not
unrecognised, it is indistinguishable from a type under a three-negatives rule. The parser's own
item error names TEN keywords, so the four-kind premise was wrong and its falsifier was in the same
file.

A RESIDUAL REFUSAL DOES NOT PROTECT A CLASSIFIER WHOSE ACCEPTED BUCKET IS DEFINED BY ABSENCE; A
NEW KIND CAN SILENTLY RESEMBLE THE DEFAULT.

ModuleItemResource repairs the known collision; it does not turn absence into a positive
authority. The terminal construction — parse constructors carrying the kind they already know — is
required before anything is cut over on this classifier.

Two instrument defects were caught before being reported as production ones: the join first read
the post-typecheck item list, whose rebuilt copies carry OccurrenceSynthetic (1077 phantom rows),
and it compared per-file parse ids against the whole-program index — two different id spaces (40
phantom absences).

Receipts

  • --required-regen: first_generation_equal=true, 155/155/155, main.rs declared divergent
  • --required-regen-fixed-point: fixed_point_equal=true (separate invocation, source roots on each)
  • cargo clippy --all-targets -- -D warnings: clean · cargo fmt --all --check: clean

🤖 Generated with Claude Code

https://claude.ai/code/session_01KLXA6u6f3UK8PR5VEJoUwm


What is verified, and what is not

Local receipts: generated_artifact_gate main_wet exit 0; --required-regen
first_generation_equal=true 155/155/155 (main.rs declared divergent);
--required-regen-fixed-point fixed_point_equal=true; clippy --all-targets -- -D warnings
clean; fmt clean; corpus-wide join 202 → 2.

CI on this head (ad9381b117): all required lanes green — required-witnesses-build,
required-witnesses-floor, rust-unit-tests, witnesses, heal-generated-artifacts and
fabric-evidence all pass; emit-copy-qualification-battery skipping. GitHub reports the head
CLEAN. (An earlier revision of this section said no required lane had executed against this head;
that was true when written and is now stale, so it is corrected rather than left standing.)

The ledger merge, and how it was resolved

The two sides of gunbc.recurring_failure_mode add disjoint rows, so main's file was taken
whole and this branch's row re-applied by insertion — no conflicted line was ever opened. That
matters on this carrier specifically: one row is one line, the longest is 16,792 characters, and
hand-composing a markered line that size loses content no diff view would show. Verified by
identity, not by rc or line count: authority 69 → 70 rows with an empty main-missing-from-mine
difference, and the projection grepped by identity string (heading count is silently null on this
file — it carries no ### markers). docs/design-failure-modes.md was regenerated from the merged
authority rather than hand-resolved, which is the only correct move on a driver-bound path.
.gitattributes is byte-identical to main, so the driver bound as intended.

A second row, and it carries an instance of itself

green_reported_over_a_population_the_instrument_does_not_own: --required-regen reports
first_generation_equal=true 155/155/155 while docs/design-failure-modes.md is stale, because
the ledger projections belong to a different actuator. A lane can file a row, run the regen, see
green, and stop — having shipped a row that exists in the authority and nowhere a reader can see it.

It is filed with both neighbours cited and the distinction stated as polarity: the same
denominator shape as incidental_denominator_as_wall with the sign reversed — theirs a filter that
accidentally creates safety (nothing wrong today, the protection uncredited), this one a filter
that accidentally destroys coverage while reporting green (something wrong today, the assurance
credited but absent).

The row records its own author committing the same shape within the hour: a claim that CI would
never run on a merge-conflicted head, drawn from six minutes of polling one branch, while three
other DIRTY pull requests were carrying six and seven check-runs each. Recency separated the
population; dirtiness did not. An instrument's silence read as a fact about a population it
never enumerated — the same shape with the sign flipped, and §5 names the tell in advance, since
"never" is the word that lets a ratchet pass as a wall.

Brian Searls and others added 5 commits September 3, 2026 01:04
…per reference

std.occurrence_binding_candidates resolve_reference_via_structural_candidates
documents that it builds the candidate index exactly once per transport, and it
does. Per reference it then called std.occurrence_binding_resolve
resolve_reference_occurrence_binding, whose first act is
occurrence_transport_validate over the WHOLE transport -- three full folds across
every index entry, declaration and reference. So the once-built index was defeated
one layer below itself and the path was O(references x population).

MEASURED, NOT REASONED, on the same subject in both directions: the census
instrument added here resolving dag/std -- 142 files, 9672 type-occurrence
references -- ran past a 45-minute wall producing nothing. After the repair the
same run over the same subject completes in 8 seconds.

THE REPAIR IS FEWER REPRESENTATIONS OF ONE FACT, NOT A CACHE.
occurrence_candidate_index_build already validates exactly once and already held
the whole ValidatedOccurrenceTransport; it kept entries_by_id and discarded the
other four fields, which is precisely what left the resolver unable to hand a
validated transport down. OccurrenceCandidateIndex now carries the
ValidatedOccurrenceTransport itself -- entries_by_id is reached through it, so
there is no second copy to drift -- and the resolver calls the ALREADY-EXISTING
resolve_reference_occurrence_binding_validated. This is DESIGN section 2's
demand-graph move (carry the value to the shared ancestor), not a memoization, and
DESIGN section 6's bare-minimum-cost standing rule settles it independently: a
proven cost-shape defect is always fixed regardless of realized n. Here n is every
type occurrence in the corpus.

BOTH SITES, because one fact with two homes is what lets a repaired path sit beside
an unrepaired one answering the same question.
std.reference_binding_observation structural_binding_resolution_from_candidates had
the identical shape and is repaired with it.

THE `transport` PARAMETER IS GONE from both entry points rather than left unused: a
second unvalidated OccurrenceTransport beside the validated one is two
representations with nothing forcing them to be the same transport, and a caller
handing in a different one would resolve silently against whichever arm read it.

BEHAVIOUR IS PRESERVED BY THE EXISTING WITNESSES, which is why this carries no new
behavioural test. resolve_type_reference_containment_binding and
structural_binding_walk keep their signatures, so
test.claim.type_reference_containment_binding_witness_test,
test.claim.type_reference_binding_context_witness_test and
test.claim.occurrence_binding_candidates_witness_test assert the same bindings
through the changed code. What changed is cost, and the instrument -- not a
transcribed number -- is what re-derives it.

WHY IT IS NOT BUNDLED WITH THE XL-0T CUTOVER IT WAS FOUND UNDER: the cut routes
every type occurrence in the corpus through this path, so switching type-position
consumers to it while it revalidates per occurrence would ship a regression even if
every binding answer were right. It is a prerequisite of that cut, and a cost
repair and an authority cutover are two subjects.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KLXA6u6f3UK8PR5VEJoUwm
…in the corpus was unbindable

MEASURED FIRST, over dag/std (142 files) with the census instrument's --denominator
mode: 9672 TypeOccurrence REFERENCES against type_occurrence_declarations=0.
TypeOccurrence appeared four times in v1.compiler.parse -- the enum member and three
ParsedOccurrenceReference sites -- and ParsedOccurrenceDeclaration was produced with
FieldOccurrence, LexicalValueOccurrence, CallableOccurrence and
NamespaceSegmentOccurrence, never with TypeOccurrence.

std.occurrence_binding_candidates buckets candidates by authored spelling and
std.occurrence_binding_resolve admits a TypeOccurrence reference against a
TypeOccurrence declaration only, so an empty declaration side made EVERY type
reference in the corpus Unbound -- not mis-bound, UNBINDABLE. The containment
authority the namespace cut resolves through was correct, executing, and had never
been fed a production population.

THE DISCRIMINATING CONTROL that located it upstream of visibility: all three
DeclarationExposureGrounding values returned BYTE-IDENTICAL partitions. Exposure
decides visibility and is the variable the census varies; a zero insensitive to it
cannot be a visibility result.

WHY NO FIXTURE COULD HAVE SHOWN THIS.
test.claim.type_reference_containment_binding_witness_test hand-builds its
declarations with `category: TypeOccurrence` -- exactly the shape production never
emitted -- so the suite supplied the missing side itself and stayed green. DESIGN
section 5's specification-without-execution boundary, sitting on the DESTINATION
authority of a migration, where a green suite is not weak evidence but zero
evidence. Those fixtures are untouched here: they test the authority's logic
correctly, they were never SUFFICIENT, and nothing in the tree said so.

THE RULE IS STATED POSITIVELY rather than as "not a function": a module item
declares a type when it has no body, no transport and no type annotation. That
admits the three authored forms -- `type X { .. }` (Conj), `type X = A | B` (Disj),
and the bare alias `type X` -- and excludes by construction the items that are
values or effects: a function has a body, a `data x: T = v` has a body AND an
annotation, a service carries a transport. Imports cannot be caught by it: they live
in the module node's params and are stamped on a different path from its children.

RESULT, same instrument, same subject, dag/std:
  type_occurrence_declarations   0 -> 1243
  Y bindings                     0 -> 3057
  partition still closes at 9672, zero unclassifiable
and the five-way census the cut needs has content for the first time: 2786
OldAndNewAgree, 2203 OldBinds_NewUnresolved, 3136 OldKernel_NewUnresolved, 909
OldSynthetic_NewUnresolved, 367 OldUnresolved_NewUnresolved, 250
OldSynthetic_NewBinds, and 21 OldAndNewDisagree -- the first real binding deltas
anyone can adjudicate.

SCOPE IS DECLARED SO THE NEXT INCREMENT IS DRIVEN BY MEASUREMENT. This stamps
MODULE-LEVEL type declarations. Coproduct VARIANTS in type position and TYPE
PARAMETERS are reachable from this walk and are NOT stamped, so references to them
stay Unbound and the census names them rather than passing over them in silence. The
same run also shows MethodOccurrence at 382 references against 0 declarations --
an independent gap in the same collector, not addressed here.

Stage0 mirror regenerated; the emitted drift is exactly v1_compiler_parse.rs.

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

CI red on the merge-blocking `cargo clippy --all-targets -- -D warnings` step: six
lints in the census binary added by the parent commit -- one very-complex-type on
the three-vector return of `inputs_for_module`, and five `clone()` calls on
`OccurrenceId` and `DeclarationExposureGrounding`, both of which are `Copy`.

The return triple is now the named `ModuleInputRows`, because a bare tuple of three
vectors says nothing about which list is which, and the five clones are dropped.
Behaviour is unchanged: cloning a Copy type and copying it are the same value.

WHY IT REACHED CI AT ALL, recorded because the tree already warns about exactly this
and I walked into it anyway. I verified the new binary with `cargo build`, and
DESIGN's Building & checks section states that
`cargo clippy --all-targets -- -D warnings` is "the only command that compiles the
integration-test and example targets, so a red there is invisible to every other
step". A new `[[bin]]` target sits in precisely that blind spot: every check I ran
was green and none of them compiled the file under the gate's lint set. The lesson is
not "run clippy too" -- it is that a named gate command is the thing to run, and a
proxy for it establishes nothing about the gate.

Verified by running the gate command itself rather than a proxy: CLIPPY_STATUS=0.

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

v1.compiler.parse stamped type REFERENCES as TypeOccurrence and never stamped a
type DECLARATION as one. Measured over dag/std (142 files) the production
transport carried 9672 TypeOccurrence references and ZERO TypeOccurrence
declarations, so every type reference in the corpus was UNBINDABLE -- not
mis-bound -- because occurrence_binding_resolve admits a TypeOccurrence
reference against a TypeOccurrence declaration only.

Every existing fixture stayed green through that because each hand-builds its
declarations with `category: TypeOccurrence` -- the shape production never
emitted -- so the suite supplied the missing side of the join itself. Those
fixtures are correct about the authority's logic and nothing here weakens them;
they were never SUFFICIENT, and nothing in the tree said so.

THE PARSE TREE CARRIES NO POSITIVE TYPE-DECLARATION MARKER. The parser
dispatches on the `type`/`fn`/`data`/`service` keyword and then discards which
one it saw: Node has no item-kind field, so the kind survives only as which
optional fields happen to be absent. A bare predicate over three absent fields
fails open by construction at the parser, so the rule is written as an
exhaustive ParsedModuleItemKind match whose ModuleItemUnrecognized arm REFUSES
with a located diagnostic rather than defaulting into the type bucket
(DESIGN section 5: a failure arm refuses, never widens). The terminal fix is a
construction, named in the annotation: parse constructors carry the kind they
already know, at which point the emit-side shape predicates dissolve into it.

Enrolled with a PRODUCTION-FED control -- not another hand-built transport --
whose third conjunct is the state that was red before this change: a subject
with type references and an empty declaration side. It executes on no required
run (the required floor's source roots are dag and src/v2, and this subject is
only reachable through v1.compiler.parse); rung mitigatable, next-rung trigger
stated in the file.

Scope, so the next increment is driven by measurement: MODULE-LEVEL type
declarations only. Coproduct variants and type parameters in type position stay
unstamped, and MethodOccurrence stands at 382 references against 0
declarations -- an independent gap in the same collector.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KLXA6u6f3UK8PR5VEJoUwm
@gunbai-bot gunbai-bot Bot changed the title XL-0T-CUTOVER: build Y — one exact declaration binding per TypeOccurrence from the containment authority — and retire #9813's module-wide precedence at the root. AUTHORING AUTHORIZED by ruling, MERGE HELD for root-cut receipts. Local use-line/qualification repairs are DEAD. The parser never stamped a type declaration, so every type reference in the corpus was unbindable Sep 3, 2026
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review September 3, 2026 02:26
Brian Searls and others added 5 commits September 3, 2026 03:20
…p stamping resources as types

THE CENSUS NOW HAS AN OUTER STATE, and building it found a live fail-open in the
change that introduced it.

TypeOccurrenceBindingCensusOutcome = CensusUnavailable { cause:
ProductionTypeDeclarationPopulationUnestablished } | CensusReady {
joined_declarations }. The thirteen classes are constructible inside CensusReady
and nowhere else. Before the stamping landed, Y never RECEIVED a declaration
population, and reporting that as OldBinds_NewUnresolved turns PRODUCER ABSENT
into a SEMANTIC RESOLUTION ANSWER -- a partition that closes over an absent input
closes over nothing.

CensusReady is constructible only after an exact-set join at OCCURRENCE-ID grain,
with uniqueness on both sides and no extra members. Not count equality, which a
compensating pair of errors satisfies. The join is against an INDEPENDENT reader:
v1.compiler.emit_core_support decides "is this item a type declaration" from
CONNECTIVE, PARAMS and CHILDREN, while the stamper decides it from the ABSENCE of
body, transport and type annotation. Different facts about the same item, so
agreement is evidence rather than measure() == measure(). New parse-only mode
`--establish` answers the obligation over the whole corpus at parse cost.

WHAT IT FOUND ON ITS FIRST RUN. Over dag + src/v2 + src/v1, exactly one diverging
module and three items: Filesystem, Clock and Entropy in std.resources. A
`resource` carries no body, no transport and no type annotation, so the
three-negatives rule stamped all three as TYPE DECLARATIONS, silently, at the
parser. The refusal arm could not fire: a resource is not merely unrecognised, it
is INDISTINGUISHABLE from a type under that rule. The parser's own item error
names TEN keywords -- alias, type, fn, func, service, resource, data, extern,
pattern, interface -- so the four-kind premise was wrong and its falsifier was in
the same file. Fixed with a ModuleItemResource arm keyed on the properties the
resource grammar attaches; the corpus-wide join now reports CensusReady.

Recorded in the annotation as a class and not a specimen: a discriminator built
from ABSENCE is only as complete as the enumeration of kinds it was derived from,
and it fails silently toward the DEFAULT BUCKET rather than toward the refusal
arm, so the refusal reads as coverage and is not.

TWO INSTRUMENT DEFECTS CAUGHT BEFORE BEING REPORTED AS PRODUCTION ONES, both
named in the annotation. The join first read the post-typecheck item list, whose
rebuilt copies carry OccurrenceSynthetic (1077 phantom "no minted occurrence"
rows); and it compared per-file parse ids against the whole-program index, two
different id spaces (40 phantom absences).

EXPOSURE DISCRIMINATION, PRODUCTION-FED. New control: one parsed source, the same
occurrences and the same resolver; under ModuleLocalMemberExposure a module-root
declaration is ModuleExposure and a consumer-module reference is UNBOUND, under
CrossFileProviderExportedExposure it is RootExposure and the same reference
BINDS. Three identical grounding columns are the signature of an absent input,
and this is what makes that signature impossible to mistake for agreement.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KLXA6u6f3UK8PR5VEJoUwm
Generated mirrors resolved to ours and REGENERATED below rather than hand-merged:
the merge driver refuses on generated-artifact paths by design, and taking a side
there drops the other side's authority-derived bytes with no conflict. The census
bin's add/add is main's earlier copy of the same file (landed by #10159's squash)
against this branch's later evolution of it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KLXA6u6f3UK8PR5VEJoUwm
… regenerated on the merge

CENSUS OUTER STATE IS NOW THREE, because two conflated two different facts.
"The join agrees on today's tree" and "the classifier is a durable authority" are
not the same claim, so:

  CensusUnavailable { DeclarationDomainAbsent | DeclarationDomainDisagrees }
  CensusObservedOnCurrentTree { joined_declarations }
  CensusAdmissibleForCut { parser_carried_item_kind, joined_declarations }

DeclarationDomainDisagrees CARRIES the missing and extra sets, so a resource
silently stamped as a type reads as a typed, located cause rather than a generic
unavailability. CensusObservedOnCurrentTree is enough to scope work and discover
disagreements. CensusAdmissibleForCut is UNCONSTRUCTIBLE on this tree and is
modeled anyway: the alternative -- leaving the distinction unmodeled -- is exactly
what would let "the join agrees" be read as "the cut is authorized". Its arm
refuses rather than falling through, so nothing quietly starts answering for it.

THE RECOGNITION RULE, carried into the annotation in the words it was ruled in:
A RESIDUAL REFUSAL DOES NOT PROTECT A CLASSIFIER WHOSE ACCEPTED BUCKET IS DEFINED
BY ABSENCE; A NEW KIND CAN SILENTLY RESEMBLE THE DEFAULT. ModuleItemResource
repairs the KNOWN collision and does not turn absence into a positive authority,
which is why the parser-carried item kind is required before anything is cut over
on this classifier rather than being an improvement to schedule later.

SEED MIRRORS REGENERATED ON THE MERGE, not hand-merged. Resolving the generated
conflicts to "ours" dropped main's authority-derived bytes and produced a stage0
crate whose root referenced modules that no longer existed there -- the four build
errors CI reported. The mirrors here are emitted from the merged authority. Two
rounds, as separate invocations with source roots on each: required-regen
first_generation_equal=true (155/155/155, main.rs declared divergent) then
required-regen-fixed-point fixed_point_equal=true. One round can report success
while the old content still stands.

AN OPEN INCOMPLETENESS, REPORTED RATHER THAN SWEPT, and the gate is what surfaced
it: over the merged corpus the join no longer closes. 202 grammar-owned type
declarations across 100 modules -- ArgvCommand, NozzleDiameter, BuildEnvelope and
others, all genuine type names in files main introduced -- are read as type
declarations by the emit-side reader and are NOT stamped. The census therefore
reports CensusUnavailable { DeclarationDomainDisagrees } and refuses to print a
partition, which is the behaviour it was built for. Which reader is right for
these shapes is NOT yet determined and is not guessed at here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KLXA6u6f3UK8PR5VEJoUwm
…ass both polarities came from

THE RESOURCE ARM I ADDED TO FIX THE FIRST FAIL-OPEN CREATED THE SECOND ONE. It
keyed on `properties` being non-empty, and `type X sole_constructor { .. }`
carries a property too -- so 202 sole-constructor type declarations across 100
modules classified as RESOURCES and vanished from the declaration population.
Over-stamping resources as types, then under-stamping types as resources: same
classifier, opposite polarity, one root -- an absence-and-presence heuristic
standing where a positive kind belongs.

THE EXCLUSION IS COMPLETE BY ENUMERATION OF MINTING SITES, not by grep. Module
items have exactly two property sources in v1.compiler.parse:
parsed_sole_constructor_properties, which mints one field-init named
sole_constructor and is the only source every type-item constructor passes along
(four call sites); and parse_resource_entries. `nominal_opaque`, the other
authored type modifier, is dropped lexically by drop_leading_type_modifier and
mints nothing. mint_parsed_optional_int_property is confined to nested
where-predicate nodes and never reaches a module item's own properties. So the
modifier set mintable as a property on a type declaration is a CLOSED SET OF ONE.
A one-member set established by construction is worth more than a longer list
found by search -- and the annotation states what breaks it: a second modifier
that MINTS a property reintroduces this silently and in the same direction, which
no longer list can prevent.

MEASURED, corpus-wide over dag + src/v2 + src/v1 with
`type_occurrence_binding_census --establish`: modules_diverging 100 -> 1, absent
declarations 202 -> 2, zero extras, zero duplicates, zero index absences, zero
parse failures. Both remaining absences are in the one diverging module.

THE RESIDUE IS NOT THIS CLASSIFIER'S DEFECT AND IS FILED RATHER THAN REPAIRED.
`resource Network` and `resource AuthContext` declare no capabilities, so with no
children, body, params or connective they satisfy
v1.compiler.emit_core_support is_bare_leaf_item and the INDEPENDENT reader calls
them type declarations. That is the same class in a different authority;
repairing it there is a separate subject and is not smuggled into a parser change.

AND THE COUNTERMEASURE, which is the transferable part. Those two were invisible
while one classifier answered, because both readers AGREED they were types -- the
agreed-wrong pair a disagreement census cannot see by construction. Splitting the
question across two INDEPENDENTLY DERIVED readers converted their agreement into
a disagreement, which is the only form the census can report. Filed as
gunbc.recurring_failure_mode absence_classifier_default_bucket with both
polarities, both specimens, and the rule: WHERE A CENSUS COMPARES TWO READERS, A
THIRD INDEPENDENTLY-DERIVED READER IS THE ONLY THING THAT CAN FALSIFY THEIR
AGREEMENT.

Receipts: required-regen first_generation_equal=true 155/155/155 (main.rs
declared divergent); generated_artifact_gate main_wet for the ledger projection;
clippy --all-targets -D warnings clean; fmt clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KLXA6u6f3UK8PR5VEJoUwm
…dger conflict exposed

RESOLVED BY CONSTRUCTION, NOT BY EDITING MARKERS. The two sides of
gunbc.recurring_failure_mode add DISJOINT rows -- this branch adds
absence_classifier_default_bucket, main adds instrument_output_read_as_subject_content,
non_execution_undifferentiated_by_what_it_silenced and
authority_merges_unprotected_while_its_projection_is_guarded -- and no row is
edited by both. So main's file was taken WHOLE and this branch's single row
re-applied by insertion. Main's 69 rows are byte-identical by construction rather
than by inspection, and no conflicted line was ever opened. That matters on this
carrier specifically: one row is one line, the longest is 16,792 characters, and
hand-composing a markered line of that size loses content no diff view would show.

VERIFIED BY IDENTITY, NEVER BY COUNT OR RC. Authority 69 rows -> 70; the
main-missing-from-mine set difference is EMPTY. Projection grepped by identity
string -- not by heading count, which is silently null on this file since it
carries no `###` markers at all -- and all five rows in play are present.
docs/design-failure-modes.md was NOT hand-resolved: it is regenerated from the
merged authority, which is the only correct move on a driver-bound path.

THE NEW ROW: green_reported_over_a_population_the_instrument_does_not_own.
`--required-regen` reports first_generation_equal=true 155/155/155 while
docs/design-failure-modes.md is STALE, because the ledger projections belong to a
different actuator (generated_artifact_gate main_wet). A lane can file a row, run
the regen, see green, and stop -- having shipped a row that exists in the
authority and nowhere a reader can see it, since DESIGN.md points readers at the
projection. Filed with its two neighbours cited and the distinction stated:
same denominator shape as incidental_denominator_as_wall with the SIGN REVERSED
(theirs a filter that accidentally CREATES safety, so nothing is wrong today and
the protection is uncredited; this one accidentally DESTROYS coverage while
reporting green, so something IS wrong today and the assurance is credited but
absent), and distinct from authority_merges_unprotected_while_its_projection_is_guarded,
which is merge-time and repaired by binding the driver to the authority path.

IT CARRIES ITS AUTHOR'S OWN INSTANCE OF ITSELF, recorded rather than quietly
dropped: within the hour of filing it, this author polled one branch for six
minutes, saw no CI run on a merge-conflicted head, and reported that GitHub never
creates runs for such a head. Three other DIRTY pull requests were carrying six
and seven check-runs each. Recency separated the population; dirtiness did not
separate it at all. An instrument's SILENCE read as a fact about a population it
never enumerated -- this row's own shape with the sign flipped, and DESIGN §5
names the tell in advance, since "never" is the word that lets a ratchet pass as
a wall.

Receipts on the merged tree: generated_artifact_gate main_wet exit 0;
required-regen first_generation_equal=true 155/155/155 (main.rs declared
divergent); required-regen-fixed-point fixed_point_equal=true. .gitattributes
byte-identical to main, so the generated-artifact driver bound as intended.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KLXA6u6f3UK8PR5VEJoUwm
@gunbai-bot
gunbai-bot Bot merged commit 2bba578 into main Sep 3, 2026
7 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/deep-lark-560-type-decl-stamp branch September 3, 2026 07:29
@briansrls
briansrls restored the session/deep-lark-560-type-decl-stamp branch September 3, 2026 07:38
gunbai-bot Bot pushed a commit that referenced this pull request Sep 3, 2026
…e rows, regenerate the projection

Both sides appended distinct rows to gunbc.recurring_failure_mode. Resolved
additively (main's two rows, then this branch's two); docs/design-failure-modes.md
regenerated rather than resolved. Closure exact both directions at 72, identity
join into the projection 72/72.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XpYuLQ4AwfSJmcFk26aPap
gunbai-bot Bot pushed a commit that referenced this pull request Sep 3, 2026
…ongside

Two subjects on one carrier, bundled deliberately rather than serialized. The
merge of main was forced (#10166 landed and made this DIRTY), it discards the
head-keyed approval either way, and every merge into this carrier costs the
fleet a regeneration — so a second window for a one-row append buys nothing.

MERGE: additive on both regions. My row plus main's two new classes
(absence_classifier_default_bucket, green_reported_over_a_population_the_
instrument_does_not_own), each present once, zero markers, projection
regenerated rather than hand-composed.

NEW ROW, assigned after the FLOOR-COST-500MS verdict came back MIS-GROUNDED:
required_floor_claim_cost.tsv declares cost_line_ms=100 on all 3534 rows while
the same run enforces 500ms. 300 rows exceed the line the FILE declares; 13
exceed the line ENFORCED — a population 23x too large, well-formed, no error
anywhere.

The row's point is not the constant, which gunbc.floor_cost_distribution
already records as a column-ORDERING hazard and which is CITED rather than
restated. It is that that note's remedy — DESIGN section 3, locate columns by
NAME not position — is correct for its own hazard and is exactly what fails
here: a reader who follows it perfectly still computes the wrong population,
because the defect is what the column SAYS, not where it sits.

Distinguished from meaning_fork in the row: that is one name with two referents
under hidden state; this is one name making one assertion that is false at every
vintage for every row, with no state to vary.

Ceiling 4, structurally impossible: the line is a fact the judge holds when it
judges, so an artifact carrying the judge's own value cannot state a different
one. Changing 100 to 500 explicitly does NOT discharge it — a second authored
literal reproduces the class the moment either moves.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RuWuQWB6MPkY7sNM4jEqAy
gunbai-bot Bot pushed a commit that referenced this pull request Sep 3, 2026
…l calls the withdrawn rows measured-out

Recomposed onto current main (db3caed), which moved through #10166's
parser/occurrence-binding change and #10175's witness/heal machinery since this
PR's last receipt. Compiler and resolution movement is material even with zero
path overlap, so the prior exact-head CI no longer speaks for this tree.

The recomposition also surfaces a contradiction that would have landed silently.
#10181 landed a memo whose plays table says serving the shared producer across
claim frames is "measured and refused", citing the same three rows this PR
reclassifies as UNMEASURED. After a merge, main would carry both sentences about
one subject -- a §3 meaning fork, and the more dangerous half is the memo,
because a negative result is exactly the artifact a later lane cites to decide
NOT to try something.

Both statements were true of different serves, which is the whole point, so the
repair is to say which serve each priced rather than to delete either:

  measured and refused AGAINST #10094's O(size) serve -- historical, still valid
  as that; this PR fires their re-enrol trigger, so their CURRENT state is
  UNMEASURED, neither admitted nor measured-out, pending a controlled
  present/absent pair nobody has run.

That keeps the memo's conclusion (the emit near-ceiling family is not a defect)
intact -- it does not rest on those three rows staying excluded -- while removing
the sentence that would have let a future lane read a stale exclusion as a
standing measurement.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019LhF5WCbZqrZHPqsnjpkYu
briansrls pushed a commit that referenced this pull request Sep 4, 2026
* Three failure-mode rows for the 2026-09-03 19:49 main outage

main was red from 19:49Z for roughly eighty minutes: gunbc.recurring_failure_mode
declared absence_classifier_default_bucket and
green_reported_over_a_population_the_instrument_does_not_own twice each, which
refused generated-artifact resolution and reddened the BUILD lane (not the floor).
#10278 (1af8892) repaired it with a four-line deletion. This files the classes;
it repairs nothing and builds no check.

ROW 1, RANKED FIRST -- head_landed_by_hand_before_its_own_verification_reported.
#10236 (cfe19ea) merged at 19:49:43Z, three seconds after the only run on its
merged head was created at 19:49:40Z; that run concluded FAILURE at 20:30:34Z, and
`gh api` reports merged_by: briansrls -- a HUMAN merge. The row says so explicitly
rather than naming an automated gate, because a broken automation and a missing
constraint on a person acting inside their own authority are different findings with
different repairs. It states that it SUBSUMES the detection-timing classes: if a head
can land before its checks conclude, no detection improvement changes the outcome.
Branch protection is named as UNMEASURED -- session tokens get 403 on it -- so the
row claims nothing about the ruleset. Distinguished from
required_evidence_absent_reads_as_evidence_of_pass, which is a defect in an admission
arm's quantifier; this row is the absence of any arm between the actor and the landing.

ROW 2 -- append_only_carrier_re_adds_what_its_own_base_already_carries. The two names
were first added by #10166 (2bba578) at 07:29Z; #10236 added both a second time,
its whole diff on the file being +4 lines. `git merge-base --is-ancestor 2bba578
cfe19ea` holds, so the branch re-added declarations its own base already carried,
and text merge reported nothing because both sides are insertions at different offsets.
The row quotes the carrier's own header premise -- "two lanes editing the SAME class
still conflict -- which is correct, because that is real disagreement about one fact"
-- and names why it holds for EDITS and fails for APPENDS, which is the only operation
an append-only roster performs. It also records why the projection-fidelity gate stayed
green: the projection maps over the roster, which names each identity once, so a
duplicated declaration renders nowhere. Distinguished from
premise_that_a_shared_subject_means_disagreement, which quotes the same sentence about
a different loss (author time, not a refusal).

ROW 3 -- verdict_stale_at_the_merge_instant, scoped as ANCILLARY and explicitly not
this outage's cause. #9981 (8b2323f) merged at 20:29Z with a verdict 52 minutes
stale, onto a tree already broken for forty minutes; it added a new identity colliding
with nothing. Filed anyway because the class is real and this specimen is clean.

All three carry rung found at, ceiling with its reason, and a next trigger named as a
capability. Rows 1 and 3 both name
`gunbc.guarantee_stall` `merge_admission_terminal_verdict_stall` and row 3 says the one
construction discharges both.

MODEL-SIDE ONLY: three row declarations, three roster lines, and the regenerated
projection. No v1 seed change.

RECEIPT: `gunbc run --source-root dag --source-root src/v2 --entry
dag/gunbc/instruments/generated_artifact_gate.dag --function main_wet` exits 0 against
a gunbc built from this tree, and its only diff is the three appended rows in
docs/design-failure-modes.md.

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

* Row 1's ceiling, answered rather than asserted: the paths split and the class takes the minimum

Review question: is the ceiling a property of OUR admission path, which we could model
and refuse on, or of GitHub's merge behavior, which we can only observe? The row said
`structurally guaranteed` on the merge-queue construction without deciding that, which
is the 4b(1) inflation of citing the strongest path while the one the incident happened
on stays silent.

It is two paths, and the row now says so.

PATH ONE, ours and on the ladder: a landing through an admission decision this
repository models -- gunbc.merge_lifecycle merge_enabled consulting
gunbc.merge_admission policy_admits, where the absent-receipt case is now an arm of the
decision rather than a fold seed. Authorable invalid state, authorable refusal,
enrollable RED. Ceiling 3 there.

PATH TWO, not ours and off the ladder: a person pressing merge in the hosting platform.
gunbc.repo_ruleset desired_ruleset_rules reads ruleset 16178731 back with no divergence
while the merge still lands, because the platform decides required contexts on what has
REPORTED at the merge instant. The honest form is a boundary obligation -- converge the
desired ruleset, observe every landing against the verdicts that existed at its merge
instant, refuse when there were none -- and today even that observation is partial,
because branch protection is unreadable from a session token.

So the row's ceiling is the boundary obligation, the minimum across its in-scope paths,
and the merge queue is recorded as the construction that DELETES path two rather than as
a proof we hold. The trigger splits to match: (a) the queue, held open by the operator's
2026-09-03 ruling, and (b) a landing observation meanwhile. The row also records that
the sibling row states structurally guaranteed on the same construction, does not amend
it, and names which direction a reader should reconcile them in.

Regenerated: generated_artifact_gate main_wet exits 0, one paragraph changed in
docs/design-failure-modes.md.

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

* Five missing commas fused six receipts into one element on the row that documents why that is load-bearing

review 59994 flagged the receipts list in
head_landed_by_hand_before_its_own_verification_reported as six adjacent string
literals with no commas, and asked whether the grammar concatenates.

BOTH HALVES OF THAT QUESTION ARE ANSWERED BY MEASUREMENT AND THE FINDING IS REAL EITHER
WAY. The grammar DOES concatenate: `gunbc run --entry
dag/gunbc/instruments/generated_artifact_gate.dag --function main_wet` exited 0 both
before and after this commit, and the regenerated docs/design-failure-modes.md is
byte-identical across it -- this diff changes no projected byte. So it was not a parse
failure. It was worse in the way this carrier specifically cares about: without the
commas the six receipts are ONE list element, which is the exact geometry
gunbc.recurring_failure_mode's own header calls load-bearing rather than style -- a
missing trailing comma drags the preceding receipt into the conflict region and destroys
the minimal three-way merge shape that two repairs of this carrier were spent buying.

Five commas added. Nothing else changed.

Recorded because it is the joke this PR did not need: a receipts list fused into one
blob, on a row about a module that failed to resolve on main, in a carrier whose header
warns that nothing enforces this shape and it is held by that paragraph alone. Nothing
enforced it here either -- the header's own next-rung trigger, a producer carrying each
declaration's source extent, is what would have refused it.

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

* Row 3 cited the pre-rename name, so its citation pointed at a symbol that no longer exists

verdict_stale_at_the_merge_instant names the outage's actual cause row, and the rename
in the merge commit left that citation naming
append_only_carrier_re_adds_what_its_own_base_already_carries -- a symbol nothing
declares any more. Now cites duplicate_declaration_arrives_through_a_clean_merge.

The one surviving mention of the old name is deliberate: the renamed row records that it
was originally filed under it, which is what lets a reader following an older reference
land somewhere rather than nowhere.

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

* chore: regenerate drifted generated artifacts (ci auto-heal)

* chore: regenerate drifted generated artifacts (ci auto-heal)

* Row 1 asserted a mechanism its own next receipt said was unmeasured

review 60183 found the contradiction and it is real: the row said the actor acted
"with no constraint that could have stopped them" while, four receipts later, saying
it does not claim protection was absent, misconfigured or bypassed. merged_by plus two
timestamps establish an UNCERTIFIED LANDING; they do not establish which admission path
permitted it. Asserting the path from that evidence is the fabrication DESIGN section 4b
keeps off the ladder as external reality.

NARROWED TO WHAT WAS OBSERVED. The invalid state is now the landing itself -- at the
instant of the landing there is no concluded run for the landed ref -- and the row says
explicitly that which path permitted it (absent constraint, a constraint that treats an
unreported required context as not-failing, or a bypass) is a separate question the
actor and timestamps do not settle.

THE ACTOR STAYS, AS AN OBSERVATION ABOUT WHO RATHER THAN ABOUT WHAT STOOD IN THE WAY. It
is worth recording because it fixes who the repair must reach: a repair aimed at an
automated arm changes nothing for a landing no automated arm performed.

AND THE UNMEASURED RECEIPT NOW SEPARATES TWO THINGS IT HAD FUSED. This filing could not
read protection (403). The REPOSITORY does record the answer, and citing it is better
than leaving a hole: gunbc.merge_lifecycle holds that gunbc.repo_ruleset
desired_ruleset_rules read ruleset 16178731 back with NO divergence, and that the merge
was admitted anyway because the platform decides required contexts on what has REPORTED
at the merge instant. On that authority a constraint EXISTED AND ADMITTED -- which is a
stronger and more useful statement than the one the review struck, and it is why the row
is about an uncertified landing rather than a missing gate.

The sibling-row distinction is restated on the same basis: that row's subject is an
admission arm's quantifier, this row's is the landed state, which is reachable by paths
that arm never touches.

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

* Row 1 carried one specimen where the module it cites carries a rate: add the 6-of-40 population

The row cited gunbc.merge_lifecycle for the ruleset reading and stopped three lines short
of the number that decides what the class IS. That module records: across the forty most
recently merged pull requests at its measurement, six had no `witnesses` run that
completed successfully on their own head before `merged_at`.

WHY IT CHANGES THE ROW RATHER THAN DECORATING IT. With one specimen a reader files this
as an incident -- a bad night, a hurried merge. With 6/40 the class is a standing
property of the landing path, roughly one merge in seven landing uncertified, and the
question the next trigger waits on -- whether the construction that deletes this state is
worth its cost -- becomes a decision about a rate. It is also the shape DESIGN section 5
asks a denominator to have: a closed, independently discovered population, not a count
read off the current tree.

CITED, NOT RE-DERIVED. Naming the module that measured it is the citation; re-counting
would mint a second authority for one fact, and the row says so, so a later reader wanting
a current figure re-runs that module's instrument instead of trusting this sentence.

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

* chore: regenerate drifted generated artifacts (ci auto-heal)

---------

Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant