Skip to content

A runs-on label's architecture is a catalog lookup, not a string grammar - #10956

Merged
briansrls merged 16 commits into
mainfrom
session/cool-badger-34
Sep 11, 2026
Merged

briansrls merged 16 commits into
mainfrom
session/cool-badger-34

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

What this is

The first half of the public-workflow scanner vertical (year_end_plan public-workload-census, the technical half of cohort-qualified). It is the piece the scanner cannot be written without: given the runner label a workflow job selects, which provider runs it and on which architecture.

The brief asked for explicit ProviderUnresolved / ArchitectureUnresolved arms on the existing closed-world classifiers, which split a label on - and treat every non-Depot/non-Ubicloud prefix as GitHub-hosted. This does something stronger and smaller: it deletes the question the grammar was answering, because the answer is already in this repository as a cited authority.

extdeps.ci_runner.depot, .blacksmith, .warpbuild, .circleci, .github_actions and extdeps.cloud.ubicloud each carry a runner catalog fetched from that vendor's own published page, and every one states the architecture of every label it publishes. depot-ubuntu-24.04-arm-16 => Aarch64 and depot-ubuntu-24.04-16 => X86_64 — the fixture and its mutation — are literal rows. DESIGN §4: "in a closed system a heuristic is never necessary: the richer source always exists or can be written."

Why the shape of the failure is the point

A string grammar answers every input, including inputs it has never seen. blacksmith-16vcpu-ubuntu-2404-arm and warp-ubuntu-latest-arm64-8x put the architecture segment where it does not look; a self-hosted label has no vendor prefix at all. Each gets a confident wrong answer and nothing goes red.

A lookup cannot do that. An unknown label produces no row, so the unresolved arms arrive by construction rather than as defensive arms someone has to remember to widen when Blacksmith or WarpBuild or an expression-valued runs-on shows up. A defensive arm that depends on being remembered is the one that is not there when it matters.

A catalog miss is two facts, and they are separated

Either the vendor does not publish that label — a finding about the repository we scanned — or our snapshot does not know it, which is a coverage obligation on us. Both produce an empty lookup, and they point at opposite remedies: report it, versus go and re-fetch. One arm covering both is a deficit in our own data wearing the costume of a property of somebody else's repository, and it never ranks for fixing (§5, a failure arm must refuse rather than widen).

The split is decided from data the catalogs now carry. If any surveyed snapshot was fetched before the observation, a catalog could have gained the label in between and the miss is ours. Only when every snapshot post-dates the observation has this repository looked later than the thing it was looking at and found nothing. An undecidable timestamp comparison counts as stale, deliberately: when the instrument cannot say, the arm that costs us effort is the honest one.

The residual is named, not hidden: a snapshot cannot distinguish a label never published from one retired since, and it cannot see a family this repository never modelled. Its next-rung trigger is a vendor-side family recognizer homed in each provider's own module, and it is not built here.

The comparator that split rests on

extdeps.time.rfc3339 already carried the whole argument — that lexical ordering is sound only where the timezone spelling and the fractional-second precision agree — while explicitly declining to model the operation ("the operations land with the consumer that needs them"). This is that consumer. It gains rfc3339_compare, which checks both preconditions and refuses with a fourth arm rather than returning a Bool. RFC 3339 §5.1 is quoted in the row. Mis-ordering here flips a coverage obligation into a finding about someone else's repository.

Three smaller consequences

  • GitHub's standard runner labels land as label rows, deliberately not as shapes. The reference publishes ubuntu-24.04-arm at 4 vCPU / 16 GB for a public repository and 2 vCPU / 8 GB for a private one, on the same page under the same label. RunnerShapeRow has no visibility axis, so adding them as shapes would mean choosing one published number and asserting it unconditionally — a fabricated fact, and the kind that reads as cited because it sits beside cited ones. The architecture column does not vary that way, which is all the label roster claims.
  • The provider roster moves out of gunbc.runner_shape_census into gunbc.runner_provider_survey, because it now has two consumers asking different questions of the same list. A roster copied into the second goes stale the first time a provider is added to one and not the other.
  • Every catalog declares what it claims to cover. Depot's page publishes Ubuntu 22.04, Windows Server and macOS families this repository has never read; a consumer meeting depot-windows-2022 needs to be told that is our gap and not a label Depot lacks.

Evidence, executed

dag/test/claim/runner_label_resolution_witness_test.dag — ten claims, green.

The discriminating red was run, not asserted: mutating Depot's own catalog row for depot-ubuntu-24.04-16 from X86_64 to Aarch64 takes the witness from exit 0 to exit 1, and restoring it returns exit 0.

GREEN_RC=0
MUTATED_RC=1
RESTORED_RC=0

Both miss arms are exercised with the same label (depot-ubuntu-24.04-arm-small) at two different observation times, so what is measured is the split and nothing else. 2026-09-04 (Biome's admitted baseline run) post-dates four of the six snapshots → coverage obligation; 2026-06-01 pre-dates all six → finding.

Depot's catalog was re-fetched from depot.dev/docs/github-actions/runner-types on 2026-09-10 and compared row by row against the twelve sizes carried here. They are unchanged; the snapshot date moves because the comparison was made, not because the rows did. The GitHub standard-runner rows were read from docs.github.com/en/actions/reference/runners/github-hosted-runners the same day.

Scope, and what is next

No scanner, no network effect, no contact of any kind is in this PR. The extdeps.github operations the scan needs (code search carrying upstream incomplete_results, repository-contents blob read, observed runner labels on WorkflowJobRun) are the next public change and land with consumers rather than as dangling declarations. The private strategy.workload_benchmark_suite classifiers dissolve into this resolver in the private repo once this lands.

One live specimen worth recording: Biome's own observed run mix contains depot-ubuntu-24.04-arm-small, and Depot's page today publishes no small size at any position. Under the string grammar that label reads silently as Arm-on-Depot. Under this resolver it is a miss — and today it correctly reports as our coverage obligation rather than a finding, because four of the six catalog snapshots predate the observation. That is a true statement about the state of our data, and re-fetching those four is what converts it into a finding.

🤖 Generated with Claude Code

https://claude.ai/code/session_015xnR1WBywRAkc4JiWJW1DH

Brian Searls and others added 2 commits September 10, 2026 18:55
The public-workload census asks one question first: given the runner label a
workflow job selects, which provider runs it and on which architecture. The
implementation reached for is a string grammar - split on "-", look for an "arm"
segment, read the provider from the prefix - and that is what DESIGN §4 says is
never necessary in a closed system, because the richer source always exists. It
exists here and this repository already models it: extdeps.ci_runner.depot,
.blacksmith, .warpbuild, .circleci, .github_actions and extdeps.cloud.ubicloud
each carry a cited runner catalog stating the architecture of every label it
publishes.

So the answer becomes a lookup in a cited authority. The consequence is not
tidiness, it is the shape of the failure. A string grammar answers every input,
including inputs it has never seen: blacksmith-16vcpu-ubuntu-2404-arm and
warp-ubuntu-latest-arm64-8x put their architecture segment in a position it does
not expect, a self-hosted label has no vendor prefix at all, and each receives a
confident wrong answer with nothing going red. A lookup cannot do that - an
unknown label produces no row - so ProviderUnresolved and ArchitectureUnresolved
arrive BY CONSTRUCTION rather than as defensive arms an author must remember to
widen when a new provider shows up.

A CATALOG MISS IS TWO FACTS AND THEY ARE SEPARATED. Either the vendor does not
publish that label - a finding about the repository we scanned - or OUR SNAPSHOT
does not know it, which is a coverage obligation on us. Both produce an empty
lookup and they point at opposite remedies, so one arm covering both is a deficit
in our own data wearing the costume of a property of someone else's repository,
and it never ranks for fixing. The split is decided from data the catalogs now
carry: if any surveyed snapshot was fetched before the observation, the miss is
ours to close by re-fetching; only when every snapshot post-dates the observation
has this repository looked later than the thing it was looking at and found
nothing. The residual is named rather than hidden - a snapshot cannot distinguish
a label never published from one retired since, nor see a family we never
modelled - and its next-rung trigger is a vendor-side family recognizer homed in
each provider's own module.

That split needs to order two timestamps, and extdeps.time.rfc3339 already
carried the reasoning while explicitly declining to model the operation. It gains
the comparator its own row describes: RFC 3339 §5.1 admits string sorting only
where the timezone spelling and the fractional-second precision agree, so the
comparator CHECKS both and refuses otherwise, with a fourth arm rather than a
Bool. Mis-ordering here would flip a coverage obligation into a finding about
somebody else's repository, which is exactly the confusion the split exists to
prevent.

Three smaller consequences. GitHub's standard runner labels land as label rows
and deliberately not as shapes: the page publishes ubuntu-24.04-arm at 4 vCPU /
16 GB for a public repository and 2 vCPU / 8 GB for a private one, and
RunnerShapeRow has no visibility axis, so adding them as shapes would mean
choosing one published number and asserting it unconditionally. The provider
roster moves out of gunbc.runner_shape_census into gunbc.runner_provider_survey
because it now has two consumers asking different questions of the same list, and
a copied roster goes stale the first time a provider is added to one and not the
other. And every catalog now declares what it claims to cover, because Depot's
page publishes Ubuntu 22.04, Windows and macOS families this repository has never
read - a consumer meeting depot-windows-2022 needs to be told that is our gap.

EVIDENCE. dag/test/claim/runner_label_resolution_witness_test.dag runs green, and
the discriminating red was executed rather than asserted: mutating Depot's own
catalog row for depot-ubuntu-24.04-16 from X86_64 to Aarch64 takes the witness
from exit 0 to exit 1. Both miss arms are exercised with the SAME label and
different observation times, so what is measured is the split and nothing else.
Depot's catalog was re-fetched 2026-09-10 and compared row by row against the
twelve sizes carried here; they are unchanged, and the fetch date moves because
the comparison was made, not because the rows did.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015xnR1WBywRAkc4JiWJW1DH
…it the roster rehome

TWO DEFECTS, ONE FROM REVIEW AND ONE FROM THE REQUIRED FLOOR.

THE FORK (review 63202, blocking, and it was right). This change had added a
second ExternalAuthority for docs.github.com/.../github-hosted-runners and
re-authored GitHub's standard runner labels as free strings inside
extdeps.ci_runner.github_actions. All three facts already had a home:
extdeps.github.hosted_runners anchors that page, extdeps.github.actions
RunnerLabel is the hosted-label vocabulary, and
extdeps.languages.yaml.gha_workflow runner_label_string is the one place a
hosted label becomes text. hosted_runners even states the rule the addition
broke - the vocabulary is spelled once, "never a free string beside it".

The reason given for not using the shape catalog was real and pointed at the
answer: RunnerShapeRow has no repository-visibility axis, and
GithubHostedRunnerCatalogRow has exactly that axis, because GitHub publishes
ubuntu-24.04-arm at 4 vCPU / 16 GB public and 2 vCPU / 8 GB private. The
problem was solved upstream, one module over, before this change was written.

So the roster is deleted and the existing catalog is enrolled instead, and the
enrollment sits in gunbc.runner_provider_survey rather than in either upstream
module: joining two upstream authorities is consumer-layer work, and making
either import the other to produce a combined roster would put a consumer's
question inside an upstream authority. Architecture is read from the public
rows and the choice is CHECKED - a new claim asserts over the whole catalog
that architecture does not vary with visibility, which is what makes reading
one side sound and what will go red if that ever stops holding.

ubuntu-latest now resolves UNRESOLVED, and that is upstream's ruling rather
than a regression: hosted_runners declines to carry it because it is "a
vendor-floating alias of the current x64 row" and pinning by alias lets the
vendor move the fact. A resolver that answered x64 would be reporting today's
aliasing as the label's meaning. The witness moves it from the x64 set to the
unresolved set and says why.

THE UNADJUDICATED BINDING DELTA (required floor 34517395009). Moving
surveyed_runner_catalogs into gunbc.runner_provider_survey changes which
declaration that spelling admits inside surveyed_runner_shapes, which is
TargetChanged and correctly not auto-admitted - a spelling that silently starts
denoting a different declaration is how a rehome smuggles a semantic change
past review. An admission row is added with its adjudication: the moved
declaration is byte-identical, and the four SameDeclarationIdentityRebind
membership rows the same run reported are the mechanical evidence that every
name the census stopped importing directly still denotes the same declaration.

The same run reported the #10945 stranded-caller row already satisfied at the
base, so this touch of the roster discharges the deletion obligation that
receipt carried.

EVIDENCE. The witness runs green at exit 0 with the new claim and the moved
ubuntu-latest expectation, over seven enrolled label catalogs rather than six.

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

gunbai-bot Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor Author

Both findings in review 63202 are correct and are fixed at 284b458. I verified each against the current code before changing anything.

Finding 1 — parallel ExternalAuthority for an already-owned page. Confirmed. extdeps.github.hosted_runners anchors docs.github.com/en/actions/reference/runners/github-hosted-runners on origin/main. github_actions_standard_runners_authority is deleted.

Finding 2 — second label/architecture roster. Confirmed, and it was worse than a duplicate citation: github_actions_standard_runner_labels re-authored wire strings that runner_label_string already spells once, and architectures that GithubHostedRunnerCatalogRow.cpu_architecture already carries. hosted_runners states the exact rule it broke — "never a free string beside it (a second representation)". The whole roster is deleted.

The part of the review worth calling out is the last sentence: my stated reason for avoiding RunnerShapeRow — no visibility axis — is precisely why hosted_runners already carries visibility. The problem I invented a new carrier for was solved upstream, one module over, before I wrote a line. I did list dag/extdeps/github/ while surveying and never opened hosted_runners.dag.

What replaced it. gunbc.runner_provider_survey now enrolls github_hosted_ubuntu_catalog() directly, projecting each public-visibility row through runner_label_string. The join lives in the consumer layer rather than in either upstream module: making extdeps.ci_runner.github_actions import extdeps.github.hosted_runners (or the reverse) to produce a combined roster would put a consumer's question inside an upstream authority.

Two consequences I did not anticipate and think are improvements:

  • Architecture is read from the public rows, and the choice is now checked rather than assumed. witness_hosted_label_architecture_does_not_vary_with_repository_visibility asserts over the whole catalog that no label carries two architectures across visibilities. The vCPU and memory figures genuinely differ; if an architecture ever did too, the roster would have been silently reporting one visibility's answer for both.
  • ubuntu-latest now resolves unresolved, and that is upstream's ruling rather than a regression I am conceding. hosted_runners declines to carry it because it is "a vendor-floating alias of the current x64 row" and pinning by alias lets the vendor move the fact. A resolver answering x64 would be reporting today's aliasing as the label's meaning. The witness moves it from the x64 set into the unresolved set with that reasoning attached.

Separately, the required floor on 1c394be refused one unadjudicated delta: TargetChanged binding gunbc.runner_shape_census::surveyed_runner_shapes 'surveyed_runner_catalogs' — base {gunbc.runner_shape_census} -> head {gunbc.runner_provider_survey}. That is the roster rehome and the classification is correct — a spelling that silently starts denoting a different declaration is exactly what that wall exists to make an author say out loud. An admission row is added carrying its adjudication (the moved declaration is byte-identical, and the four SameDeclarationIdentityRebind membership rows the same run reported are the mechanical evidence). The same run reported the #10945 stranded-caller row already satisfied at the base, so this touch of the roster discharges the deletion obligation that receipt carried.

Witness green at exit 0 over seven enrolled label catalogs.

— sent from cool-badger-34

… of the roster

review 63211, and it is right. `count(snapshots_consulted) == 7` compared a live
repository population to a numeral copied from the same tree.
`snapshots_consulted` is always `surveyed_snapshots()`, so the assertion measured
how many catalogs happen to be enrolled today against a number written down while
looking at that same list - DESIGN §5's change detector, green by construction and
"repaired" by editing the numeral the day a provider is added. Automating the
literal's update would collapse it to measure() == measure(), which the same
paragraph names as the tell.

What actually distinguishes this arm from its neighbour is a property of the
SNAPSHOTS rather than a count of them. The Absent arm claims every consulted
snapshot post-dates the observation; the Stale arm claims every snapshot it
reports pre-dates it. Both are now asserted against the same comparator the
resolver used to make the split, so a stale snapshot appearing in the Absent
arm - or a fresh one in the Stale arm - goes red at any roster size. The
complementary claim on the Stale arm is added in the same motion, because a
soundness claim on one side of a split says little without the other.

EVIDENCE. Witness green at exit 0 with the literal gone and both properties
asserted.

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

gunbai-bot Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor Author

review 63211 is right and is fixed at 58b1ea2.

count(snapshots_consulted) == 7 was a change detector, and the cited tell applies exactly: snapshots_consulted is always surveyed_snapshots(), so the numeral was a measurement of today's roster written down while looking at that same roster. Automating its update collapses it to measure() == measure(). It would have gone red the day someone enrolled a seventh provider — for a reason having nothing to do with the property under test — and been "repaired" by editing the numeral.

The replacement asserts the property that defines the arm rather than counting the population it consulted. The Absent arm claims every consulted snapshot post-dates the observation; that is now checked against the same rfc3339_compare the resolver used to make the split. A stale snapshot appearing in the Absent arm goes red at any roster size.

I added the complementary claim on the other side in the same motion — witness_every_snapshot_the_stale_arm_reports_predates_the_observation — because a soundness claim on one half of a split says little without the other. Between them the two claims say the split is sound and neither names a population size.

Witness green at exit 0.

— sent from cool-badger-34

review 63221, and it is right. `first(matches)` silently took the head of the
match list, so a label two surveyed catalogs carried got whichever answer was
enrolled first. That is the same fail-open this module's own header argues
against, relocated from the label's spelling to the SURVEY'S ORDER: a genuine
disagreement about provider or architecture resolved silently in favour of a
line's position in a list nobody thinks of as ordered.

It is a live growth surface rather than a hypothetical, and the review names why:
gunbc.runner_provider_survey says in so many words that adding a provider is one
line in each list, and two already-enrolled catalogs - the larger-runner families
and the standard hosted labels - share one provider identity and one label
namespace. They are disjoint today and nothing structural keeps them so.

THE ARM REFUSES ON MULTIPLICITY, NOT ON DISAGREEMENT, and that is the deliberate
part. Refusing only when the rows contradict each other would widen on the
agreeing case, which is the same absorbing fallback one step quieter: two
authorities claiming one label is a single-authority defect whether or not they
agree this week, and tolerating agreeing duplicates would hide the fork until one
of them changed.

THE SPLIT IS OVER A MATCH LIST, NOT OVER THE LIVE SURVEY, so the wall has an
authorable red. resolve_from_matches takes the matches as an argument and
resolve_runner_label supplies them from the survey; a claim can hand the first
function two competing rows directly. A wall reachable only by corrupting the
enrolled catalogs would be a wall nothing could exercise.

FOUR DIRECTIONS ARE CLAIMED, not one: a disagreeing pair refuses, an AGREEING pair
refuses, reversing the pair's order refuses identically (which is the property
that says order stopped deciding), and a single match still resolves. Beside them
is a control over the LIVE survey asserting that no label in use today is carried
by two catalogs - so the refusal is a wall over a real corpus rather than one that
has already swallowed the ordinary case.

TWO EXECUTED REDS, and the second is the more useful finding. Relaxing the arm's
threshold takes the witness from exit 0 to exit 1. It did NOT the first time I ran
it, and the reason was a defect in my own roster: the two new claims had been
added to all_claims_hold as a separate statement rather than a conjunct, so their
value was computed and discarded and only the last expression was returned. A
claim enrolled in a roster that does not gate is precisely the inert-lens failure,
and it was invisible until the mutation refused to go red. Both claims are now
conjuncts and the red reproduces.

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

gunbai-bot Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor Author

review 63221 is right and is fixed at a6d2cb1.

first(matches) was a fail-open relocated from the label's spelling to the survey's order. I had reasoned carefully about what happens when no catalog carries a label and not at all about what happens when two do — and the review is right that it is live rather than hypothetical: runner_provider_survey documents "one line in each list below" as the growth surface, and github_actions_label_catalog and github_hosted_standard_label_catalog already share a provider identity and a label namespace.

RunnerLabelAmbiguousAcrossCatalogs carries the competing rows and refuses.

It refuses on multiplicity, not on disagreement, which is the one judgement call in the fix. Refusing only when the rows contradict each other widens on the agreeing case — and two authorities claiming one label is a §3 defect whether or not they agree this week. Tolerating agreeing duplicates would hide the fork until the day one of them changed, which is the worst possible moment to discover it.

To give it an authorable red I split the decision from the population: resolve_from_matches takes the match list as an argument and resolve_runner_label supplies it from the survey. A wall reachable only by corrupting the enrolled catalogs is a wall nothing can exercise. Four directions are claimed — disagreeing pair refuses, agreeing pair refuses, reversed order refuses identically (that is the property saying order stopped deciding), single match still resolves — plus a control over the live survey asserting no label in use today is carried by two catalogs.

A second defect fell out of checking the red, and it is the more useful finding. Relaxing the arm's threshold did not take the witness red on my first attempt. The cause was in my own roster: the two new claims had been added to all_claims_hold as a separate statement rather than a conjunct, so their value was computed and discarded and only the last expression was returned. A claim enrolled in a roster that does not gate is exactly the inert-lens failure, and nothing surfaced it except the mutation refusing to go red. Both are conjuncts now and the red reproduces (exit 0 → exit 1).


On the CI failure at 58b1ea2 — the floor's one finding is not attributable to this diff:

declarations FAIL IMPORT-MEMBER-ABSENT dag/test/claim/colo_nj_central_south_census_test.dag:13:51:
  `test.claim.colo_nj_central_south_census` imports `grain_admits_single_cabinet`
  from `test.claim.colo_cabinet_density_witness`, which declares no such name

Both files are untouched by this branch (git diff --name-only origin/main...HEAD matches nothing under colo), and the break reproduces on origin/main itself: #10865 renamed the function to grain_offers_single_cabinet and the census's import was left pointing at the old name. PR #10968 is already open to repair it. This PR's build, heal and namespace-wave phases all pass; the declarations phase is red for main's reason and will clear when that lands.

— sent from cool-badger-34

Brian Searls and others added 3 commits September 10, 2026 21:25
… branch's admission row

CONFLICT, AND IT WAS THE SAME EVENT SEEN FROM TWO SIDES. Both sides deleted the
#10945 stranded-caller admission row, independently and for the same reason: its
trigger fired when #10945 merged. Main carried the fuller record - the twentieth
dissolution, with the run that printed CONSUMED and the rule charging the
roster-touching change - and this branch carried a paraphrase of the same event.
Two records of one dissolution is the section 3 violation the roster's own history
warns about twice, so the paraphrase goes and main's record stands.

What survives from this side is the row main does not have: the #10956 roster
rehome, whose delta this change produces and which main has no reason to carry.
Main's closing sentence said the resting state is empty; that stopped being true
the moment this row lands beside it, so it is replaced rather than left standing
as a false statement about the file it sits in.

Two measurements in this branch's rationale are re-attributed rather than left
floating: the four SameDeclarationIdentityRebind rows and the 407-module closure
blast radius are now named as what the required floor on this branch's FIRST head
reported (run 34517395009), because after a merge "the same run" no longer
identifies anything.

RE-VERIFIED AGAINST THE MERGED TREE RATHER THAN ASSUMED, since this change's whole
argument is that a runs-on label's architecture is a lookup in catalogs main is
free to move underneath it. Main did not touch dag/extdeps/ci_runner/,
extdeps.cloud.ubicloud or extdeps.github.hosted_runners in this range, and the
witness runs green at exit 0 on the merged tree: the Biome fixture
(depot-ubuntu-24.04-arm-16 => Aarch64), the unsuffixed mutation
(depot-ubuntu-24.04-16 => X86_64), both arms of the catalog-miss split, and the
ambiguity refusal all hold.

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

gunbai-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

The floor failure at dedc951 is not attributable to this diff, and merging current main clears it. New head ffd92f82c6.

The two blocking findings:

declarations FAIL IMPORT-MEMBER-ABSENT dag/test/claim/fabric_m0_publication_witness_test.dag:39
  `test.claim.fabric_m0_publication_witness` imports `DurableOriginRead`
  from `gunbc.fabric_m0_commit`, which declares no such name
  ... same for `DisposableCacheRead` at :40

Neither file is touched by this branch (git diff --name-only origin/main...HEAD matches nothing under fabric_m0). The break was in the main revision this branch had merged; on current main those names are declared in gunbc.fabric_m0_commit, and the witness resolves. So it was a transient main-side inconsistency that main has since completed, not something my diff introduced or could fix.

The other four blocking identities were v2.test.native_decl_selection.* with cause=interrupted_before_verdict — the new required-v2-native lane's own claims, cut off rather than failed.

required-witnesses-build and heal-generated-artifacts passed on that head.

Re-verified on the new merged tree rather than assumed, since this change's argument is a lookup into catalogs main is free to move underneath it:

  • witness green at exit 0
  • Biome fixture depot-ubuntu-24.04-arm-16 → Aarch64 — true
  • unsuffixed mutation depot-ubuntu-24.04-16 → X86_64 — true
  • ambiguity refusal (two catalogs, one label) — true
  • fabric_m0_publication_witness_test now resolves with no import error

One note for whoever is tracking floor throughput: this is the third time this branch's floor has gone red for a main-side stranded import (grain_admits_single_cabinet after #10865's rename, now these two), each cleared by merging a later main. Each costs a full CI cycle in a saturated queue. Not a complaint about this PR's gating — just that the cost lands on whichever branch happens to be mid-flight.

— sent from cool-badger-34

@gunbai-bot

gunbai-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

No fix is owed here and I am not pushing one. Run 34549011785 is a run I cancelled myself at 01:59, deliberately, and its jobs did not fail — they were killed.

The API's job-level conclusions say so plainly:

cancelled  2026-09-11T01:58:58Z  required-witnesses-floor
cancelled  2026-09-11T01:58:58Z  required-witnesses-build
cancelled  2026-09-11T01:58:58Z  required-v2-native
cancelled  2026-09-11T01:59:14Z  heal-generated-artifacts
failure    2026-09-11T02:13:20Z  witnesses          <- the aggregator, reporting the above
run conclusion: cancelled

Three jobs ending at the same second is a kill, not four independent defects. gh pr checks renders cancelled as fail, which is why the summary reads as five failures — including required-witnesses-build, which would otherwise look like I broke the build.

Why I cancelled it. The run was queued at 01:02:21Z, against main's verdict run at 01:48:02Z — so it was sitting ahead of the run that has to conclude uncancelled to establish a green exists. It was also pinned to a pre-01:47:59Z merge ref, so it was certain to reproduce the inherited native_decl_selection red (four claims interrupted_before_verdict at 503-508ms against a 500ms budget, fixed on main by #10992) and establish nothing. Meaningless and in the way.

Why re-running would be waste rather than a fix. The merge ref is pinned at push time and a re-run replays it, so re-running reproduces a red that no longer exists and burns an hour-long slot doing it. The only thing that clears this is merging current main and pushing — and I am deliberately not doing that yet, under a fleet sequencing ruling: main's verdict run on ea674a6d has to go clean first, and #10971 takes its slot before this PR. Pushing now would evict the very run that establishes the green.

Nothing about this diff has changed. It stands at 1 distinct approval, no open REQUEST_CHANGES, and every review round closed. I will merge current main and push when the sequence reaches me.

— sent from cool-badger-34

Brian Searls and others added 4 commits September 11, 2026 03:48
…ection surface

SOUNDNESS DEFECT, FOUND BY THE SIDE CHAT AND CONFIRMED BY EXECUTION, on a head that
already carried two approvals and nine review rounds.

THE RESOLVER SEARCHED EVERY ENROLLED CATALOG, and one of them is CircleCI — whose
rows are `resource_class` values written in .circleci/config.yml, not GitHub
Actions `runs-on` labels. Two ecosystems, two keys, and namespaces that overlap on
ordinary words. Measured on the previous head:

  resolve_runner_label("small")      -> NotArmConfirmed x86_64, from CircleCI
  resolve_runner_label("large")      -> NotArmConfirmed x86_64, from CircleCI
  resolve_runner_label("arm.medium") -> ArmConfirmed,           from CircleCI

The third is promotion 1 — an x64 label may not become Arm evidence — running in
REVERSE through the resolver written to prevent it: a GitHub Actions job on a
self-hosted runner named arm.medium reported as confirmed Arm, with full
provenance and a snapshot date attached. The first two are worse in practice,
because small and large are what an ordinary fleet actually calls its runners.

WHY NOTHING CAUGHT IT, WHICH IS THE PART WORTH KEEPING. Every unresolved arm in
this module answers a MISS. This is a HIT from the wrong ecosystem, so no
miss-shaped wall can see it. The ambiguity arm cannot fire either: exactly one
catalog carries "small", so there is no multiplicity to refuse. The guard and the
defect were disjoint — the same shape as a hermetic witness that cannot see a wet
decode, and the same shape as a claim green against a copy of the classifier it
tests. Two approvals did not catch it because no reviewer ran the resolver against
an ordinary word.

THE FIX IS CONSTRUCTION, NOT REMOVAL. RunnerLabelCatalog gains a SELECTION SURFACE
— the declaration defining the key its labels are written in — and the resolver
answers only for catalogs on the GitHub Actions runs-on surface. Dropping CircleCI
from the roster would have fixed this instance and left the class open for the next
non-GitHub system anyone enrolls, with nothing recording why it had to go. A
catalog that does not name the runs-on surface now cannot answer a runs-on
question, whoever adds it and whenever.

IT IS A DeclarationRef AND NOT A VARIANT, for the reason RunnerShapeRow.provider
already is: a central enum of surfaces would need widening by every CI system ever
enrolled, which is the concrete-product enumeration section 3 forbids a generic
hub. And the surface is declared ONCE, in extdeps.github.actions beside the
RunnerSpec that `runs-on` IS — my first cut of this fix declared it in five
provider modules, which was a fork introduced while repairing a fork.

CircleCI STAYS IN surveyed_label_catalogs, because this repository HAS read its
resource classes and a survey of what we surveyed should say so. It is excluded by
a FILTER on the question asked, not by deletion from the record.

EVIDENCE. witness_another_ci_systems_label_namespace_is_not_consulted asserts all
seven CircleCI spellings resolve undetermined in all three directions — not Arm,
not x64, undetermined. The red was executed: putting CircleCI back on the runs-on
surface takes the witness from exit 0 to exit 1, and restoring the surface returns
it to 0.

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

THREE FINDINGS FROM REVIEW, all confirmed. Two are the same defect wearing
different clothes: a claim whose denominator was chosen by a person rather than
computed from the corpus.

THE COLLISION WITNESS FOLDED TEN HAND-TYPED LABELS. That is the copied-population
defect: the sample was written while looking at the catalogs, so it passed by
construction, and it would have gone on passing when a provider was enrolled the
sample never named. It now folds runs_on_label_rows() — every row on the runs-on
surface — so the denominator is the corpus. A positive control lands beside it,
because a resolver that refused everything would satisfy "no collisions"
trivially: every surveyed row's own label must come back Resolved.

THE RED IS EXECUTED AND IT IS A REAL COLLISION, not a constructed pair: adding
depot-ubuntu-24.04-arm-16 to blacksmith's catalog takes BOTH claims from true to
false — the label is carried twice, so it stops resolving and starts refusing. The
old ten-label version would not have noticed, because blacksmith's rows were never
in its list.

THE AGREEING-AMBIGUITY RED NEVER TESTED TWO CATALOGS. Both competing matches were
built from one snapshot with no catalog identity, so the pair was indistinguishable
from ONE catalog listing a label twice. LabelMatch now carries catalog_provider,
and the multiplicity arm says WHICH defect it found: a label appearing twice in one
catalog is a defect in that provider's own projection and the repair belongs to
that module; a label claimed by two different catalogs is a defect in the roster
and the repair belongs to gunbc.runner_provider_survey. Different owners, different
repairs, and previously one undifferentiated cause.

AND THE CircleCI SURFACE WAS THE PROVIDER IDENTITY. circleci_resource_class_surface
pointed at circleci_catalog_authority, which is byte-for-byte the ref
circleci_provider_identity already uses — so "which key are these labels written
in" and "who publishes them" were one declaration, and a provider identity passed
where a surface was expected would have compared equal. That is the
interface/realization conflation section 3 names, one level above the defect this
axis was added to fix, introduced while fixing it.

GitHub's side names the declaration that IS the key (extdeps.github.actions
RunnerSpec). There is no CircleCI analogue in this repository — resource_class is
not modelled here at all — so the row now names ITSELF and says so, rather than
borrowing a neighbour and implying a modelled key exists. When resource_class is
modelled the ref moves to it. Not reachable today, since the filter only ever
compares against the GitHub surface; fixed because a knowingly-wrong ref that is
merely unreachable is still wrong.

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

review 63545, two findings, both confirmed.

A SPELLING BOUND TO NOTHING, IN THE PR THAT DELETES A ROSTER ROW ABOUT EXACTLY
THAT. The witness used DeclarationRef while importing only declaration_ref_eq.
Every other real use in the corpus imports the type; the one grep hit that does
not is inside a comment. It is the class the floor has failed this branch for twice
tonight from main's side — grain_admits_single_cabinet, DurableOriginRead — and I
wrote one.

WHAT MAKES IT WORTH MORE THAN A ONE-LINE FIX: MY LOCAL RUNS CANNOT SEE IT. The
interpreter does not need the type to evaluate the function, so the witness ran
green at exit 0 with an unresolved name in it. Every "verified locally" I have
reported on this branch was verified by a path that structurally cannot catch this
class, and the declarations phase is the only thing that can. That is a gap in my
verification loop rather than a typo, and it is the third time this session that a
green has been green for a reason adjacent to the thing it claimed.

AND A FABRICATED CAUSE ON A FAILURE PATH. snapshot_is_stale_for mapped
Rfc3339OrderUndecidable to true, and the refusal then reported that the snapshot
was "fetched BEFORE the observation" — a fact that was never established, because
under that arm rfc3339_compare had explicitly REFUSED to order the two timestamps.
Routing undecidable toward re-fetch is the right policy and it is unchanged: when
the instrument cannot say, the arm that costs US effort is the honest one. What was
wrong was reporting a reason that is not true. Right destination, invented
justification.

The standing is now three-valued — SnapshotPredatesObservation,
SnapshotOrderUndecidable carrying rfc3339_compare's own cause, and
SnapshotPostdatesObservation — and the refusal COUNTS the two separately: how many
snapshots were fetched before the observation, and how many could not be ordered
against it at all. Both still route to re-fetch, so the policy the split preserves
is asserted in the claim rather than left to be inferred.

EVIDENCE. The claim drives the exact pair the RFC's section 5.1 preconditions
exclude — a fractional-second stamp against a whole-second one — and asserts four
things: the undecidable one is named undecidable, the plainly older one is named
older, BOTH still route to re-fetch, and only one of them is undecidable. The red
was executed: mapping the undecidable arm back to SnapshotPredatesObservation takes
it from true to false.

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

gunbai-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

review 63545, both findings confirmed and fixed at 4ec8e7e.

The unimported type, and why it is worth more than a one-line fix

DeclarationRef used, declaration_ref_eq imported. Confirmed exactly as described — and the provenance you drew is the uncomfortable part: this is the same class the floor has failed this branch for twice tonight from main's side (grain_admits_single_cabinet after a rename, DurableOriginRead), and the roster row this very diff touches describes it as "bound to NOTHING". I wrote one while carrying the row about it.

What makes it a process finding rather than a typo: my local runs structurally cannot see it. The interpreter does not need the type to evaluate the function, so the witness ran green at exit 0 with an unresolved name in it. Every "verified locally, exit 0" I have reported on this branch was verified by a path that cannot catch this class — the declarations phase is the only thing that can, and it is precisely the phase the memory-stall refusals have been preventing from running.

That is the third time this session a green of mine was green for a reason adjacent to the thing it claimed. I am treating the pattern as the finding.

The fabricated cause

Also correct, and the sharper of the two. snapshot_is_stale_for mapped Rfc3339OrderUndecidable to true, and the refusal then reported the snapshot was "fetched BEFORE the observation" — a fact never established, because under that arm rfc3339_compare had explicitly refused to order the timestamps. Right destination, invented justification.

The policy is unchanged and I want to be clear I am not conceding it: routing undecidable toward re-fetch is correct, because when the instrument cannot say, the arm that costs us effort is the honest one. What was wrong was the sentence, not the destination.

SnapshotStanding is now three-valued — SnapshotPredatesObservation, SnapshotOrderUndecidable carrying rfc3339_compare's own cause, SnapshotPostdatesObservation — and the refusal counts the two separately: how many snapshots pre-date the observation, and how many could not be ordered against it at all.

witness_an_unorderable_snapshot_is_not_reported_as_an_old_one drives the exact pair §5.1 excludes from lexical ordering (a fractional-second stamp against a whole-second one) and asserts four things: the undecidable one is named undecidable, the older one is named older, both still route to re-fetch, and only one is undecidable. Red executed — mapping the undecidable arm back to SnapshotPredatesObservation takes it true → false.

— sent from cool-badger-34

…ce and left the carrier fused

review 63580, both findings confirmed, and both are mine from the commit that was
supposed to fix this exact thing.

I SPLIT THE TYPE AND THEN THREW THE SPLIT AWAY. The module argues in its own
annotation that the two reasons a snapshot is not trusted "are not the same fact"
and "may not share a sentence" — and then the arm stored
List<CatalogSnapshot>, so the distinction survived ONLY in the cause prose. A
consumer matching on the value could not act on the thing the type was created to
preserve; a human reading English could. That is section 4c read backwards: a count
living in a String. I repaired the sentence, declared the carrier three-valued, and
left the carrier fused — a fix that addressed the symptom I had just written about
while reproducing its cause one field over.

RunnerLabelSnapshotStale now carries List<SnapshotAssessment>, each pairing a
snapshot with its standing, and the cause text is a PROJECTION of that list rather
than the only record of it.

AND THE STANDING WAS RE-DERIVED THREE TIMES PER SNAPSHOT. stale_snapshots_for
computed it to filter, then the two count(filter(...)) calls in the message
computed it again for every snapshot in the survey — so rfc3339_compare ran three
times per row where once was needed, with unmatched_resolution as the least common
ancestor of all three demands. Section 2: when several demands share an ancestor,
the repetition is authored duplication, and the remedy is to carry the first value
rather than to cache the recomputation. assess_snapshots computes one assessment
per snapshot and everything downstream folds that list.

The two Bool predicates over the coproduct are gone with it: assessment_is_untrusted
and assessment_is_undecidable read a standing already computed instead of
collapsing a three-arm type back to a Bool by recomputing it.

EVIDENCE. The new claim partitions the arm's OWN payload and asserts the partition
is total — every untrusted snapshot is either pre-dating or unorderable, the counts
sum to the whole, and today's live survey is entirely the pre-dating kind. That
last conjunct is the reading a consumer actually wants, because it says the remedy
is "re-fetch four stale catalogs" rather than "our timestamps are unreadable", and
it is derived from the value rather than parsed out of a sentence. Witness green at
exit 0; mapping the undecidable arm back to SnapshotPredatesObservation takes it to
exit 1.

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

gunbai-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

review 63580, both confirmed and fixed at 3a290ec. Both are mine, from the commit that was supposed to fix this exact thing.

I split the type and then threw the split away

The module argues in its own annotation that the two reasons a snapshot is not trusted "are not the same fact" and "may not share a sentence" — and then the arm stored List<CatalogSnapshot>, so the distinction survived only in the cause prose. A consumer matching on the value could not act on the thing the type was created to preserve; a human reading English could. §4c read backwards: a count living in a String.

I repaired the sentence, declared the carrier three-valued, and left the carrier fused. The fix addressed the symptom I had just finished writing about while reproducing its cause one field over.

RunnerLabelSnapshotStale now carries List<SnapshotAssessment> — each pairing a snapshot with its standing — and the cause text is a projection of that list rather than the only record of it.

And the standing was re-derived three times per snapshot

stale_snapshots_for computed it to filter, then both count(filter(...)) calls in the message computed it again for every snapshot in the survey. Three rfc3339_compare calls per row where one was needed, with unmatched_resolution as the least common ancestor of all three demands — §2's authored duplication, whose remedy is to carry the first value rather than cache the recomputation.

assess_snapshots computes one assessment per snapshot and everything downstream folds that list. The two Bool predicates over the coproduct went with it: assessment_is_untrusted and assessment_is_undecidable read a standing already computed instead of collapsing a three-arm type back to a Bool by recomputing it.

Evidence

The new claim partitions the arm's own payload and asserts the partition is total — every untrusted snapshot is either pre-dating or unorderable, the counts sum to the whole, and today's live survey is entirely the pre-dating kind.

That last conjunct is the reading a consumer actually wants: it says the remedy is "re-fetch four stale catalogs" rather than "our timestamps are unreadable" — and it is derived from the value rather than parsed out of a sentence. Witness green at exit 0; mapping the undecidable arm back to SnapshotPredatesObservation takes it to exit 1.

— sent from cool-badger-34

@gunbai-bot

gunbai-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

This head is frozen. Here is exactly what that means and what undoes it.

Ruling taken, not a unilateral decision. I escalated and was told to freeze.

Why

This PR is in a loop that cannot terminate. Sixteen findings tonight, every one real and several of them mine to be embarrassed about — but each fix moves the head, which resets the approvals, which invites a fresh review, which finds the next thing. This PR has held approvals at two separate points and now holds zero, on a head that is strictly better than the approved ones.

Meanwhile the check half cannot conclude either: zero successful runs exist repo-wide in the last twenty. The floor has refused four times for reasons that are not this diff — MemoryStallRefusedPageThrash on two different hosts with near-identical fault rates, and modules_excluded=2, which reports a count with no identities and which I have failed three times to attribute because no other floor verdict exists to compare against.

So approvals reset faster than they accumulate, and the checks can never finish. That is not a PR failing to meet a bar; it is a bar receding faster than the PR moves.

What still unfreezes this head — please keep looking for these

A soundness defect. Concretely: a confident wrong answer, a wall that cannot go red, a witness that expects the defect it should forbid, a refusal that cannot fire, or a claim the evidence does not support.

Two of tonight's findings were exactly this class — the CircleCI cross-surface resolution that reported arm.medium as confirmed Arm, and the positive witness that required a fabricated LLVM/Biome hybrid. Both were worth every reset they cost, and I would take the reset again without hesitating.

If you find one, say so plainly and I will fix it and eat the reset.

What is now recorded rather than pushed

Citation grade, carrier grade, naming, prose, a better home for a row, a tidier shape. All real, all worth fixing, none worth an unbounded reset loop. I will answer each one in this conversation saying whether I agree and where it lands — and anything that deserves its own change gets a follow-up PR, which the working agreement explicitly allows.

This is not me declining review. I am still reading every finding and I will still verify each against the code. I have stopped pushing for the non-blocking ones.

— sent from cool-badger-34

review 63609, and it clears the soundness bar I set in this PR's freeze notice, so
the head moves and the approvals reset. It is a confident wrong answer on a failure
path: the refusal would have stated a false fact and sent the reader to the wrong
module to repair it.

WHAT WAS WRONG. LabelMatch carried catalog_provider and matches_share_one_catalog
compared providers, so "one catalog lists this label twice" and "two catalogs both
claim it" were decided by who PUBLISHED the rows rather than by which catalog
matched. Those are different defects with different owners: the first belongs to
the module that projected the rows, the second to the roster that enrolled them.

IT IS NOT HYPOTHETICAL AND THE MODULE ITSELF NAMES THE PAIR. GitHub's sized
larger-runner catalog and its standard-runner catalog BOTH carry
github_actions_provider_identity - they are two readings of two different published
references by one vendor, and the module's own annotation calls them the live
growth surface. An overlap between them would still have refused, but the cause
would have read "this label appears twice in ONE catalog's rows... the repair
belongs to that module" when the duplication was in the survey. Right refusal,
false explanation, wrong module.

RunnerLabelCatalog now carries its own identity - a DeclarationRef naming the
catalog declaration - distinct from the provider naming who published it. A
provider can have several catalogs in one survey and now that is representable.
LabelMatch keys on the catalog, and RunnerLabelAmbiguousAcrossCatalogs carries
List<LabelMatch> rather than List<RunnerLabelRow>, because bare rows cannot recover
which catalog matched and a consumer reading the arm needs exactly that.

WHY MY EXISTING CLAIM COULD NOT SEE IT: both competing matches went through
control_match, which set the same provider, so the pair never exercised two
catalogs at all - let alone two that share a provider. Guard and defect disjoint,
again, and this is the third time in this module that the carrier was keyed on a
neighbouring fact while the annotation argued for the distinction.

EVIDENCE, in both directions so the two causes are not interchangeable. Two
catalogs sharing GitHub as provider now read as two catalogs and the cause names
the ROSTER; one catalog listing a label twice names THAT CATALOG and its module.
The red was executed: keying matches_share_one_catalog back on row.provider takes
the shared-provider claim from true to false.

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

gunbai-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

review 63609 confirmed, and it clears the soundness bar I set in the freeze notice — so the head moves and the approvals reset. That was the right trade and I would take it again.

Why this is soundness and not carrier grade

The refusal would have stated a false fact and sent the reader to the wrong module. matches_share_one_catalog compared providers, so "one catalog lists this label twice" and "two catalogs both claim it" were decided by who published the rows rather than by which catalog matched. Right refusal, false explanation, wrong repair.

And the pair is the one this module itself names as its live growth surface. GitHub's sized larger-runner catalog and its standard-runner catalog both carry github_actions_provider_identity — two readings of two different published references by one vendor. An overlap between them would have reported "this label appears twice in ONE catalog's rows… the repair belongs to that module" when the duplication was in the survey.

The fix

RunnerLabelCatalog carries its own identity — a DeclarationRef naming the catalog declaration — distinct from the provider naming who published it. A provider can have several catalogs in one survey and that is now representable. LabelMatch keys on the catalog, and RunnerLabelAmbiguousAcrossCatalogs carries List<LabelMatch> rather than List<RunnerLabelRow>, since bare rows cannot recover which catalog matched and a consumer reading the arm needs exactly that.

Why my existing claim could not see it

Both competing matches went through control_match, which set the same provider — so the pair never exercised two catalogs at all, let alone two sharing a provider.

That is the third time in this module that a carrier was keyed on a neighbouring fact while the annotation argued for the distinction: the snapshot standing split into three arms and stored as bare snapshots; the selection surface pointed at the provider anchor; and now the match keyed on provider instead of catalog. I have started treating "the annotation argues for a distinction the type does not carry" as a thing to grep for in my own diffs, because I have now produced it three times in one file.

Evidence, in both directions

Two catalogs sharing GitHub as provider read as two catalogs and the cause names the roster; one catalog listing a label twice names that catalog and its module — so the two causes are not interchangeable and neither claim is satisfied by a refusal that always says the same thing.

Red executed: keying matches_share_one_catalog back on row.provider takes the shared-provider claim from true to false.

The head is frozen again at 58c8394509 on the same terms — soundness unfreezes it, everything else gets recorded and answered here.

— sent from cool-badger-34

@gunbai-bot

gunbai-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

Correcting myself: I misread this failure twice, and said so publicly

I reported on this PR that the floor was refusing with modules_excluded=2 and that the counter named a count with no identities I could act on. That was wrong.

Main's own floor run at ea674a6d — the one that reached SUCCESS / FloorClean — reports modules_resolved=2707 modules_excluded=2. The excluded count is a normal counter printed beside the verdict, not the verdict. I read a summary line as a cause.

The real cause was ten lines above it and I never looked up:

superseded_run_starvation_census_witness_test.dag:90:46
  error: missing required field 'run_attempt' in literal of type 'WorkflowRun'
superseded_run_starvation_census_witness_test.dag:119:33
  error: missing required field 'event' in literal of type 'WorkflowRun'
  ... four more of the same

I grepped for FAILED PHASE, read what that line said, and repeated the exercise three times across two PRs without once reading the lines preceding it. "I cannot attribute this" was produced by an instrument I aimed too narrowly, not by a genuinely opaque refusal — and I stated it with some confidence.

What it actually is, and it is still not this diff

Main's WorkflowRun type now carries head_branch, event, run_attempt, actor and triggering_actor. Main's own fixture file — dag/test/claim/superseded_run_starvation_census_witness_test.dag — still constructs WorkflowRun literals without them. I checked git show origin/main directly: main's copy is byte-identical to mine on those literals. The type gained five fields and the construction site did not follow.

So any branch carrying current main fails the floor here, and merging main does not help, because main is where it comes from. Same shape as the grain_admits_single_cabinet rename and the DurableOriginRead stranding earlier tonight — the third instance of that class today.

I am not repairing it inside this PR. It is main's file, and #10968 set the precedent that these land separately.

What I got right by accident

My conclusion — "not my diff" — was correct. My reason was wrong, and I published the wrong reason. Worth stating plainly since anyone reading this thread later would otherwise inherit it.

— sent from cool-badger-34

Brian Searls and others added 3 commits September 11, 2026 08:51
…ronology

Two more soundness findings from the side chat, both unfreezing the head.

THE PUBLIC SEAM WAS A DOOR BESIDE THE WALL. resolve_from_matches is split out
precisely so a claim can hand it constructed matches - which means ANY caller can,
and the surface filter lived only in surveyed_matches. So the path that was already
safe was guarded and the path a caller reaches was not: a bare CircleCI row handed
straight to the seam resolved happily as a runs-on label. LabelMatch now carries
its selection surface and the seam refuses a match from any other one, so the wall
holds for a constructed call exactly as it does for the survey.

AND RFC 3339 PERMITS LOWERCASE, WHICH REVERSES LEXICAL ORDER. The grammar's own
note allows "t" and "z" in place of "T" and "Z", so 2026-09-04t16:04:06Z and
2026-09-04T16:04:06Z are the same instant spelled two admissible ways - and 't' is
code point 0x74 against 'T' at 0x54, so lexical comparison puts the lowercase one
AFTER every uppercase one whatever its date. An OLDER stamp compares as NEWER.

That is not imprecision, it is a reversal, and it lands exactly where this branch
cares: a snapshot that pre-dates an observation would read as post-dating it, which
flips our own coverage obligation into a finding about somebody else's repository -
the confusion the three-valued standing was built to prevent, reintroduced
underneath it by the comparator that standing is derived from.

Section 5.1's precondition is "expressed using the same string", and case is part
of the string. The comparator now requires the canonical uppercase spelling of both
designators and refuses anything else, including an internally-consistent lowercase
pair, because admitting that would mean admitting the mixed pair.

EVIDENCE. A lowercase separator against an uppercase one refuses as undecidable;
the same two instants in canonical spelling still order correctly, so the refusal
is not blanket. A CircleCI row handed to the seam is refused naming the surface it
came from.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015xnR1WBywRAkc4JiWJW1DH
…e its own arm

review 63694, and it is the FOURTH time in this module that a carrier fused two
facts while an annotation argued for the distinction. I added the surface check one
commit ago and reported the refusal through RunnerLabelAmbiguousAcrossCatalogs,
whose declared meaning is "two surveyed catalogs both carry this label".

THEY ARE DIFFERENT FACTS WITH DIFFERENT OWNERS. A wrong-surface match means a
caller asked a resource_class value as a runs-on question - the repair is at the
CALL SITE. Ambiguity means the roster enrolled one label twice - the repair is in
gunbc.runner_provider_survey. Reported through one arm, nothing on the value
separated them and the English cause was the only discriminator.

MY OWN WITNESS PROVED IT, which is the part worth keeping. The claim I wrote to
check the seam had to assert string_contains(cause, "does not answer for") to tell
the two refusals apart - a claim reaching into prose because the value would not
answer. I wrote that claim, ran it, watched it pass, and did not notice that its
SHAPE was the evidence of the defect. The same module says three declarations
later, about the snapshot standing, that "the distinction survived in the English
and nowhere a consumer could match on it."

RunnerLabelWrongSelectionSurface is now its own arm. The seam claim matches on it
by variant and the ambiguity claim matches on the other, so the two are separated
by value and neither reads a sentence.

WHAT I WOULD FLAG ABOUT THE PATTERN: four instances, one module, all mine, and each
introduced while repairing the previous one. Snapshot standing split three ways and
stored as bare snapshots. Selection surface pointed at the provider anchor. Match
keyed on provider rather than catalog. Now a new refusal reusing an existing arm. I
said last round I would grep my own diffs for "the annotation argues for a
distinction the type does not carry" and then did not, because I was adding a check
rather than a type and did not think the rule applied. It applies to the REFUSAL as
much as to the carrier: a new way to fail is a new fact, and reaching for an
existing arm is the same reach as reusing a neighbouring key.

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

review 63714, the FIFTH instance of this shape in this module, and this time the
arm was the one I wrote the criterion about. Two commits ago I split
RunnerLabelWrongSelectionSurface off ambiguity BECAUSE the two had different owners
and different repairs. RunnerLabelAmbiguousAcrossCatalogs was already fusing two
facts by the same test, one line away, and I did not look.

THE THREE FACTS AND THEIR THREE OWNERS. A label appearing twice in ONE catalog is a
defect in that provider module's projection of its own published surface. A label
claimed by TWO catalogs is a defect in gunbc.runner_provider_survey's roster. A
match on another CI system's surface is neither - a caller asked a resource_class
value as a runs-on question and the repair is at the call site. The name
AcrossCatalogs was simply FALSE for the same-catalog case.

RunnerLabelDuplicatedWithinCatalog and RunnerLabelClaimedByTwoCatalogs now carry
their own names, and every witness matches on the VARIANT. The file has zero
string_contains on a cause left in it - the claims had been reading English to tell
two refusals apart, which is the tell, and which I had described in my own commit
message one commit earlier while leaving four instances of it in the same file.

EVIDENCE, AND THE RED IS PRECISE RATHER THAN MERELY PRESENT: collapsing the split
so both multiplicities report as cross-catalog takes the same-catalog claim from
true to false and leaves the cross-catalog claim GREEN. A pair of claims that both
went red would not have shown they test different things.

FIVE INSTANCES, ONE MODULE, ALL MINE, EACH INTRODUCED WHILE REPAIRING THE LAST.
Snapshot standing split three ways and stored as bare snapshots; selection surface
pointed at the provider anchor; match keyed on provider not catalog; a new refusal
reusing an existing arm; and now the arm that refusal was split off FROM. The
mechanical check I keep failing to run is cheap and I am stating it so the next
reader can hold me to it: after any change to a coproduct, grep the witnesses for
string_contains on a cause. Every hit is a place the value does not carry what the
prose claims.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015xnR1WBywRAkc4JiWJW1DH
@briansrls
briansrls merged commit 9fa591c into main Sep 11, 2026
4 checks passed
@briansrls
briansrls deleted the session/cool-badger-34 branch September 11, 2026 11:13
gunbai-bot Bot pushed a commit that referenced this pull request Sep 11, 2026
… do not have

Fourth conflict in this file from this branch, and the second of the both-sides-live kind: 40 SCM
rows here, one for gunbc#10956 from main. Unioned.

THE SHORTCUT I DID NOT TAKE is the part worth recording. Last time both sides were live, I unioned
main's fresh row, and the floor then reported it CONSUMED at this base and charged its deletion to
the roster-touching change. The same is likely about to happen to #10956's row, since #10956 is in
this branch's base as of this merge. Deleting it now on that reasoning would save a CI cycle and
would be PREDICTING a disposition rather than holding one.

Main's own rule decides it: THE RECEIPT IS THE DISPOSITION, NOT THE SIDE. A row goes because the
wall computed its transition and printed it. "I expect the wall will say consumed" is not that, and
acting on an expected measurement is the exact error class this branch has spent its whole review
history repairing -- an annotation asserting a mint did not exist, a control green on the wrong
refusal, a scenario green against a leaked sibling, all of them a claim standing where an
observation belonged. So the row stays, and if the floor says consumed, that receipt deletes it.

cargo check -p v1-compiler --lib finished clean on the working tree. Section 4c: 0 violations.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ4iThiZ1B9LPB9ePr8qa9
@briansrls
briansrls restored the session/cool-badger-34 branch September 11, 2026 11:33
gunbai-bot Bot pushed a commit that referenced this pull request Sep 11, 2026
…iction

The previous commit kept main's gunbc#10956 admission row through the merge and said plainly that
the floor would probably report it consumed, but that predicting a disposition is not holding one.
Required floor run 34594161197 has now computed it:

  CONSUMED ADMISSION gunbc#10956 runner provider roster rehome ... already satisfied at the base
  1 consumed admission(s) due for deletion on this roster-touching change
  required-floor: verdict=FloorClean unexpected_failures=0

So the row goes, and what deletes it is that receipt -- not the paragraph I wrote yesterday that
happened to agree with it. The floor was otherwise clean; this was the only blocker, and the 40 SCM
rows stay because the same run still shows them ADMITTING.

I am keeping the pre-run paragraph in place beside the post-run one rather than tidying it away.
Together they are the only honest record of the distinction: the first states an expectation while
it is still an expectation, the second states the measurement that settled it. Collapsing them into
one after-the-fact sentence would make it read as though I had known, which is the retroactive
certainty this branch has spent its whole review history removing from annotations.

cargo check -p v1-compiler --lib finished clean on the working tree.

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

The floor reported CONSUMED ADMISSION for main's runner-roster row --
already satisfied at the base, consumed by its own merge -- and refused
adjudication because a roster-touching change owes the deletion. This is
the toucher, so the row and main's account of its subject go here rather
than being deferred to a follow-up nobody owes. The union note records
what happened, citing the wall's own line rather than asserting it.

Also scoped a sentence that had become false: 'the resting state is empty
again as of this change' was true of the change that wrote it and is not
true of a roster carrying eighteen rows.

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

The required floor refused with `3 unadjudicated delta(s), 0 stale admission(s),
1 consumed admission(s)`, and both halves are this change's to pay.

The three deltas are the brand move itself: `LinuxKernelRelease` is authored on both
sides inside ContainerVisibleHostKernel, the playwright run row, and the witness's
execution-identity law, and what changed is which declaration the spelling admits --
base gunbc.served_surface_browser_observation, head extdeps.linux.kernel. That is
exactly the motion the wall exists to make an author say out loud, so it gets three
rows and the adjudication beside them: the moved declaration is byte-identical
including the brand STRING (a changed brand would have altered what every
`as LinuxKernelRelease` ascription means, which is a semantic change wearing a
relocation's name), and the two consumers are the complete population -- both edited
here, no third site left resolving through a module that no longer authors the name.

The consumed row is #10956's, which merged this morning; the wall computed its
transition as already satisfied at the base and printed it. This file is the roster,
so this touch is the toucher the rule charges and the deletion is paid here rather
than deferred to a follow-up nobody owes. Empty was the resting state and empty is
not permissive: authoring different rows back into it is the ordinary motion, not a
regression of that dissolution.

Floor itself was clean on the refused run -- verdict=FloorClean, claims_failed=0, and
all 12 of the new EDAC witnesses reported standing=planned-and-passed as changed
witnesses. Only the namespace phase refused.

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

* GHES/APEI firmware-first is a Linux fact: ghes_edac gets its own upstream carrier

Under ACPI APEI firmware-first mode the firmware handles memory errors and hands
the OS finished error records; the OS never enumerates the memory controller.
ghes_edac exists so one of those records has a DIMM to name -- it registers ONE
synthetic controller and mirrors the SMBIOS Type 17 device list into it. It is an
error-attribution shim, not a memory-controller topology authority, so no csrow or
channel node exists to read on ANY boot absent a native driver.

That sentence was living as prose inside one unit's observation
(gunbc#10965's mtcollins1_edac_channel_map_unavailable_reason), where it is a fact
about a Linux/firmware arrangement wearing a receipt's clothes. DESIGN 3's external
upstream decomposition puts it in extdeps.linux.edac, keyed to the kernel release it
was read against, and leaves the receipt its readings.

What the carrier makes decidable rather than restatable:

- EdacDriverBinding is a trichotomy, not an enum of drivers. The native-driver roster
  is genuinely open upstream (one per memory controller), so the closed part is the
  only part that is closed: a controller-enumerating driver is bound, ghes_edac is, or
  nothing is.
- The two absences are separate causes with separate standings.
  FirmwareFirstErrorAttributionShim is AbsentOnEveryBoot -- the errand is over;
  NoMemoryControllerDriverBound is AbsentUntilDriverBound -- there is something to try.
  Collapsing them into one "unavailable" is exactly what books the next pointless boot.
- edac_dimm_node_source asks both drivers the same question and gets different answers,
  which IS the shim: a controller's enumeration carries channel position, an SMBIOS
  Type 17 mirror names slots and never locates a part in the topology.
- apei_firmware_first_from_dmesg matches the kernel's own line rather than a paraphrase.

LinuxKernelRelease moves to a new extdeps.linux.kernel with it. It was declared inside
gunbc.served_surface_browser_observation, a downstream receipt; an extdeps module cannot
import a gunbc one, so keying an upstream fact to a kernel release would have had to
re-coin the brand -- the fork. Its one consumer imports it from the new home.

Consumption (DESIGN 3c): test.claim.linux_edac_topology_authority_witness exercises
every arm of every fold, with a discriminating red on the dmesg detector whose fixture
mentions GHES, EDAC, APEI and firmware and is still not the marker. Both controls were
executed red by mutation before landing. The named later consumer is #10965's receipt,
trigger stated in the module: that PR merging, after which it keeps driver ghes_edac,
apei_firmware_first true, csrow_node_count 0 and the dmesg line, and resolves the WHY
here. Observations this repo produces are receipts in the observing layer, never facts
owned by the observed upstream.

edac.dag leaves the frozen legacy scope manifest and joins scope_carrier_paths, with the
extdeps_model_scope it owed; kernel.dag lands as a carrier.

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

* Admit the LinuxKernelRelease rehome at the wave-admission wall, and pay #10956's consumed row

The required floor refused with `3 unadjudicated delta(s), 0 stale admission(s),
1 consumed admission(s)`, and both halves are this change's to pay.

The three deltas are the brand move itself: `LinuxKernelRelease` is authored on both
sides inside ContainerVisibleHostKernel, the playwright run row, and the witness's
execution-identity law, and what changed is which declaration the spelling admits --
base gunbc.served_surface_browser_observation, head extdeps.linux.kernel. That is
exactly the motion the wall exists to make an author say out loud, so it gets three
rows and the adjudication beside them: the moved declaration is byte-identical
including the brand STRING (a changed brand would have altered what every
`as LinuxKernelRelease` ascription means, which is a semantic change wearing a
relocation's name), and the two consumers are the complete population -- both edited
here, no third site left resolving through a module that no longer authors the name.

The consumed row is #10956's, which merged this morning; the wall computed its
transition as already satisfied at the base and printed it. This file is the roster,
so this touch is the toucher the rule charges and the deletion is paid here rather
than deferred to a follow-up nobody owes. Empty was the resting state and empty is
not permissive: authoring different rows back into it is the ordinary motion, not a
regression of that dissolution.

Floor itself was clean on the refused run -- verdict=FloorClean, claims_failed=0, and
all 12 of the new EDAC witnesses reported standing=planned-and-passed as changed
witnesses. Only the namespace phase refused.

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

* The controller count was a literal compared to itself; make it a fold with a real other arm

`ghes_edac_registers_exactly_one_controller_holds` read
`ghes_edac_registered_controller_count == 1` against a data row declared as 1. That is
statically decided: it can only go red if someone edits the row, which makes it a
change detector rather than a check -- DESIGN §5's own tell, that automating the
literal's update collapses the assertion to measure() == measure(). eager-owl-205 hit
the same shape from the other direction today (a witness comparing DeclarationRef
strings to literals, green and proving nothing) and flagged it; this is that shape.

The repair is not to delete the row but to notice the fact it was standing in for. How
many controllers are registered is TWO different kinds of fact depending on who is
bound. Under the shim it is ONE regardless of what the hardware has, because it is a
property of ghes_edac rather than of the platform -- which is exactly why one memory
controller beside sixteen DIMMs is the expected reading and not an anomaly. Under a
native driver it is whatever the machine actually has, which this module cannot know:
that is a per-platform reading for the observing layer.

So the count becomes an arm of a fold, and the discriminating half is the other arm --
a native driver must NOT come back as a driver-fixed number, because answering one here
would be the fabricated-plausible-output failure with a Nat on it. Executed red by
mutation: pointing the native arm at ControllerCountFixedByDriver reds
native_driver_controller_count_is_not_fixed_by_the_driver_holds while the ghes arm
stays green, so the two arms are independently discriminating rather than one law
wearing two names. 14 witnesses, all passing.

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

* A controller count is a Count, not a Nat: MemoryControllerCount joins its siblings in std.measure

review 63971, and it is right. `ghes_edac_registered_controller_count: Nat = 1` and the
`ControllerCountFixedByDriver { count: Nat }` payload carried a domain count on a bare
scalar, in a module whose entire point is that ONE controller beside sixteen DIMMs
means something specific. Nothing in that type distinguished the 1 from a DIMM count, a
channel count, or a slot number -- which is the §2 test failing one step earlier than a
fork: not a second name for the axis, but no name at all.

std.measure already owns the axis and the corpus has refused this exact move twice by
name. MergeQueueEntryCount sits there rather than in the module decoding GitHub's
merge_queue rule because "an extdeps module minting its own alias for it would fork that
axis once per upstream that happens to count something"; PowerCordCount was put there so
a product module "consumes it rather than re-minting a local alias for the same axis".
An extdeps module counting memory controllers is the same shape, so MemoryControllerCount
lands beside them with its constructor and accessor, and edac.dag consumes it. The
witness's oracle becomes memory_controller_count_value(c: n) == 1 rather than n == 1.

The stage0 mirror is regenerated by its own producer rather than hand-edited: one
`--required-regen` round emitted the three additions to std_measure.rs, applied as hunks,
and the second round reports first_generation_equal=true with no drift line. clippy
--all-targets clean, 14 witnesses passing.

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

* The kernel release was a dangling row; make the reading carry it

review 63982, and it is right: `git grep edac_topology_model_read_at_release` returned
one line, its own declaration. No fold read it, it was not carried on the scope, and my
own §3c block claimed consumption for "every arm of every fold" — which that row was
not. DESIGN §3c names this exact tell ("a data row no fold reads") and says it is red
regardless of how well modeled the dangling piece is.

The fix is not to drop it. The brief asked for the fact to be keyed to the relevant
kernel, and the reason is load-bearing rather than decorative: this module's whole claim
is that an absent channel map is STRUCTURAL and not a missing driver, and that claim is
falsifiable only against a stated release — a mainline that grew a native Altra
memory-controller driver would answer ChannelTopologyEnumerated for the same question.
A provenance a consumer can quote the answer without is a provenance that will be
dropped.

So the release travels WITH the reading, in the same value:
edac_channel_topology_availability now returns EdacChannelTopologyReading
{ availability, read_at_release }. Deliberately ONE fold — a release-free route beside
it would be the path every caller takes, and the row would be dangling again one caller
later.

The reviewer's other suggestion, carrying it on the citation row, I did not take: the
`?h=v6.8` source URL in further_citations is reachable but it is a citation, not a value
any consumer can join on, so the receipt in #10965 still could not say which kernel its
answer was keyed to.

Executed red by mutation: pointing read_at_release at a literal "9.9.9" reds
every_reading_carries_the_release_it_was_read_at_holds, which checks all three arms and
not only the interesting one. 15 witnesses passing. Also merged current main (the branch
had picked up a main-integration merge) and re-ran the regen against it:
first_generation_equal=true, no drift.

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

---------

Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brian Searls <11205878+briansrls@users.noreply.github.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 11, 2026
…solution is recorded once

main took 9243870, which edits the same NAMESPACE_TRANSITION_ADMISSIONS roster
this branch appends to. namespace_wave_admission.rs is HAND-WRITTEN (//! header,
no generated banner), so a regen cannot resolve it and the hunks are authored
text.

Git interleaved the two appends mid-literal, so the sides could not be
concatenated: the conflict boundaries cut through TransitionAdmission structs.
Resolved by reconstructing the roster from each side's complete file and taking
the union -- main's 3 gunbc#11071 LinuxKernelRelease rows first, then this
branch's 175 v2-native-route module-split rows. 178 total, none dropped, and
neither side's #10956 rows return (both had already deleted them as consumed).

THE DISSOLUTION IS RECORDED ONCE. Both sides wrote a TWENTY-FIRST DISSOLUTION
paragraph for the same #10956 event -- recording one dissolution twice is a
rostered failure mode in this repo, and two accounts of one event is the fork
DESIGN section 3 forbids. Main's account survives: it landed first and it cites
the receipt (required floor run 34627055157 reporting the row CONSUMED), where
this branch's cited only the merge sha. The duplicate is deleted rather than
merged into a third wording.

Main's narrative says "the rows below are a DIFFERENT relocation", which was
true when its rows were the only ones. After the union it would read as
covering this branch's rows too, so a bridge paragraph states that the roster
now carries two independent relocations with different dissolve-on triggers and
that neither narrative covers the other's rows.

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

The freeze is lifted by the trigger review named for it -- a CONCRETE CONFLICT, not elapsed commits.
This branch sat at 265a92d through 9, 13 and 28 commits of drift without merging, because
absorbing main on a schedule buys nothing while nobody can execute the missing acceptance receipt
and every absorption moves the subject SHA. GitHub reported the branch unmergeable at 55 behind, so
the condition is met and the merge happens now.

FIFTH CONFLICT IN THIS FILE, AND THE FIRST QUALITATIVELY DIFFERENT ONE. Both sides appended rows, so
git interleaved the two arrays and produced THREE hunks across one list: 40 SCM rows here, 3 for
gunbc#11071 from main. Patching interleaved hunks is exactly how a row gets silently dropped in the
middle of a list nobody re-counts, and a dropped row here is an unadjudicated delta the wall exists
to refuse. So the resolution does not touch the hunks at all: each side's array is reconstructed
from its OWN staged blob (`git show :2:` and `git show :3:`) and the two are concatenated.

UNION, for the reason that decided the second and fourth conflicts: taking either side whole deletes
obligations the other still owes. 43 rows, verified by label census -- 31 SCM_MERGE_BASE_COHOME, 9
SCM_SOURCE_RECOVERY_REHOME, 3 gunbc#11071 -- rather than by trusting the patch applied cleanly.

Main's #11071 TRIGGER paragraph is kept verbatim. It records when those rows come due and this
branch is not the authority that retires them; the same receipt rule that deleted #10945 and #10956
from this roster will delete these when the wall says so, and not before.

cargo check -p v1-compiler --lib finished clean on the working tree.

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