Repository navigation
The parser never stamped a type declaration, so every type reference in the corpus was unbindable - #10166
Merged
Conversation
…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
…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 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
This was referenced Sep 3, 2026
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
6 tasks
This was referenced Sep 3, 2026
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.parsestamped type REFERENCES asTypeOccurrenceand never stamped a typeDECLARATION as one:
ParsedOccurrenceDeclarationwas produced withFieldOccurrence,LexicalValueOccurrence,CallableOccurrenceandNamespaceSegmentOccurrenceonly.std.occurrence_binding_resolveadmits aTypeOccurrencereference against aTypeOccurrencedeclaration only, so the join had no right-hand side at all.
Measured by
type_occurrence_binding_census --denominator dag/std(142 files):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 thedenominator), 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 shapeproduction 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/servicekeyword and then DISCARDS which one it saw —Nodehas no item-kind field, so by the time the occurrence walk runs the kind survives only aswhich optional fields happen to be ABSENT. Every downstream reader (
is_type_def_item,is_function_item,is_data_def_item,is_service_def_iteminv1.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
ParsedModuleItemKindmatch whoseModuleItemUnrecognizedarm REFUSES with a locateddiagnostic 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, notanother 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.
dagandsrc/v2, andthis subject is only reachable through
v1.compiler.parse. Rung: mitigatable; the next-rungtrigger (a witness home whose source roots reach
src/v1) is stated in the file. Directexecution 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 closesexactly. Zeros are reported because a dropped zero row is indistinguishable from "not measured" —
OldKernel_NewAmbiguous = 0,OldSynthetic_NewAmbiguous = 0,OldUnresolved_NewAmbiguous = 0together say Y introduces no new ambiguity anywhere, which is a load-bearing positive finding.
OldSynthetic_NewBinds= 250 (1150 cross-file): X manufactured a synthetic identity where Y nownames 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
CrossFileProviderExportedExposurediscriminates — which is exactly what the earlier all-zero runcould 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
answers are not measured; the two once disagreed on this exact subject.
(
gunbc.recurring_failure_mode disagreement_census_blind_to_agreed_wrong).OldAndNewAgreemeans 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.
New*Unresolvedarm 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.
MethodOccurrencestands 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
parse_authored_occurrence_binding_source; the census join parses each file withparse_with_tableand readsparsed.occurrence_transportemit_core_support is_bare_leaf_item)extra = 0on the merged corpus. This is the direction that caught the threeresourceitemsstamp_parsed_nodereads the node's existingOccurrenceMintedidentity and mints nothing; the join checks every declaration id against that parse's own index (not_in_index = 0)production_fed_exposure_discrimination_holdsbinds underCrossFileProviderExportedExposure; executed, PASSModuleLocalMemberExposure→ Unbound,CrossFileProviderExportedExposure→ Bound; executed, PASSParsedOccurrenceUnclassified: both production-fed controls FAIL;control_one/control_two/control_three/control_apiall PASS. Both halves executedCondition 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
ModuleItemResourcearm added to fix the first fail-open keyed onpropertiesbeing non-empty,and
type X sole_constructor { .. }carries a property too — so every sole-constructor type in thecorpus 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.parsehas exactly two module-item property sources:parsed_sole_constructor_properties(one field-init namedsole_constructor, the only source everytype-item constructor passes along, four call sites) and
parse_resource_entries.nominal_opaqueis dropped lexically by
drop_leading_type_modifierand mints nothing;mint_parsed_optional_int_propertyis confined to nested where-predicate nodes. The set ofmodifiers 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 --establishoverdag src/v2 src/v1):modules_diverging100 → 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 Networkandresource AuthContextdeclare no capabilities, so with no children, body, params or connective they satisfy
v1.compiler.emit_core_supportis_bare_leaf_itemand the independent reader calls them typedeclarations. 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.
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'sauthority-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) wasstale mirror content, not an uncovered arm in the
.dag.Also worth recording:
--required-regendoes not project the ledger docs. It reportedfirst_generation_equal=truewithdocs/design-failure-modes.mdstill stale. The projectionactuator 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
"The join agrees on today's tree" and "the classifier is a durable authority" are different facts.
CensusAdmissibleForCutis unconstructible on this tree — the accepted bucket is still defined byabsence — and is modeled anyway, with a refusing arm, because leaving it unmodeled is what would
let the first be read as the second.
The
resourcefail-open, and the rule that generalises itThe join's first run found three items —
Filesystem,Clock,Entropyinstd.resources—silently stamped as TYPE DECLARATIONS. A
resourcecarries no body, no transport and no typeannotation, 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.
ModuleItemResourcerepairs the known collision; it does not turn absence into a positiveauthority. 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.rsdeclared 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_wetexit 0;--required-regenfirst_generation_equal=true155/155/155 (main.rsdeclared divergent);--required-regen-fixed-pointfixed_point_equal=true;clippy --all-targets -- -D warningsclean;
fmtclean; 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-artifactsandfabric-evidenceall pass;emit-copy-qualification-batteryskipping. GitHub reports the headCLEAN. (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_modeadd disjoint rows, so main's file was takenwhole 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.mdwas regenerated from the mergedauthority rather than hand-resolved, which is the only correct move on a driver-bound path.
.gitattributesis 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-regenreportsfirst_generation_equal=true155/155/155 whiledocs/design-failure-modes.mdis stale, becausethe 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_wallwith the sign reversed — theirs a filter thataccidentally 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.