Skip to content

FIT STEP 1: the selector stops advertising a runtime-neutral domain it never served - #10358

Merged
gunbai-bot[bot] merged 10 commits into
mainfrom
session/eager-pike-541-ollama-choice-reclass
Sep 4, 2026
Merged

gunbai-bot[bot] merged 10 commits into
mainfrom
session/eager-pike-541-ollama-choice-reclass

Conversation

@gunbai-bot

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

Copy link
Copy Markdown
Contributor

Step 1 of the realization-axis cut, authorized by side-chat ruling. Structural reclassification only — no behaviour change, no vLLM path.

Why the old names were a lie

gunbc.model.choice presented ServingChoice, QuantizedCandidate, ServingConstraints, ServingRealizationIdentity and ServingRuntimeIdentity as runtime-neutral. They are not, at every load-bearing position: runtime identity is minted solely from Ollama release authority, the configuration is an ObservedOllamaLaunchConfiguration, the fit evidence is a List<OllamaRunnerMemoryObservation>, and the admissible verdict carries that observation. There is no vLLM reference anywhere in the module.

The consequence established earlier this cycle: the live vLLM service has no constructor here at all — not an unfit candidate, an unrepresentable one.

gunbc.model.choice          -> gunbc.model.ollama_choice
choose_serving_candidate    -> choose_ollama_serving_candidate
ServingChoice               -> OllamaServingChoice
QuantizedCandidate          -> OllamaQuantizedCandidate
ServingConstraints          -> OllamaServingConstraints
ServingRealizationIdentity  -> OllamaServingRealizationIdentity
ServingRuntimeIdentity      -> OllamaServingRuntimeIdentity
CandidateVerdict            -> OllamaCandidateVerdict
evaluate_candidate          -> qualify_ollama_candidate

The entry point stays a chooser

This was the correction I needed from review. I was going to name the module a qualifier. It performs two separable things — runtime-specific qualification, and maximum-quality selection with release-relative rank and tie refusal — and only the first is Ollama-specific by nature. Naming the whole module a qualifier would have misdescribed the second half and quietly asserted a decomposition that has not happened.

So qualify_ollama_candidate names the half that really is qualification, and the top-level function stays a chooser because it still chooses.

Deliberately absent

no neutral kernel extraction        no QualifiedCandidate carrier
no Vllm arm                          no decision-order or verdict change
no FitEvidence coproduct             no compatibility re-export

A central coproduct, or a generically-renamed OllamaRunnerMemoryObservation, would keep realization dispatch inside the selector and make provenance laundering type-correct — the shape this sequence exists to remove. The first common type belongs after realization-specific qualification, never around raw memory evidence.

No compatibility re-export, deliberately: a wrapper preserving the old spelling would retain exactly the misleading public surface this removes, so compile failures at old import sites are the census (DESIGN §3 delete-first — in a fail-closed substrate the deletion is what makes real dependents refuse loudly). I censused first, so the blast radius was known rather than hoped for: every renamed concept was contained to this module and its witness.

The annotation on the entry point states explicitly that the neutral kernel has not been extracted, so this cut cannot later be cited as completing step 2.

Evidence

All 42 witnesses in the choice entry pass, changed only in module and symbol references. Every fixture value, decision ordering, rejection axis, unanswerable outcome, winner and tie result is identical — which is what distinguishes a rename from an edit.

🤖 Generated with Claude Code

https://claude.ai/code/session_01U397y4s3dSBof7vGPAX87G

gunbc-ci-auto-heal and others added 2 commits September 4, 2026 05:48
…t never served

Structural reclassification only, authorized by side-chat ruling as step 1 of
the realization-axis cut. No behaviour changes and no vLLM path appears.

WHY IT WAS A LIE BY NAME. gunbc.model.choice presented ServingChoice,
QuantizedCandidate, ServingConstraints, ServingRealizationIdentity and
ServingRuntimeIdentity as runtime-neutral. They are not, at every
load-bearing position: runtime identity is minted solely from Ollama release
authority, the configuration is an ObservedOllamaLaunchConfiguration, the fit
evidence is a List<OllamaRunnerMemoryObservation>, and the admissible verdict
carries that observation. There is no vLLM reference anywhere in the module.
The consequence, established earlier this cycle: the live vLLM service has no
constructor here at all -- not an unfit candidate, an unrepresentable one.

  gunbc.model.choice        -> gunbc.model.ollama_choice
  choose_serving_candidate  -> choose_ollama_serving_candidate
  ServingChoice             -> OllamaServingChoice
  QuantizedCandidate        -> OllamaQuantizedCandidate
  ServingConstraints        -> OllamaServingConstraints
  ServingRealizationIdentity-> OllamaServingRealizationIdentity
  ServingRuntimeIdentity    -> OllamaServingRuntimeIdentity
  CandidateVerdict          -> OllamaCandidateVerdict
  evaluate_candidate        -> qualify_ollama_candidate

THE ENTRY POINT STAYS A CHOOSER, and that is the correction I needed. I was
going to call the module a QUALIFIER. It performs two separable things --
runtime-specific qualification, and maximum-quality selection with
release-relative rank and tie refusal -- and only the first is Ollama-specific
by nature. Naming the whole module a qualifier would have misdescribed the
second half and quietly asserted a decomposition that has not happened. So
qualify_ollama_candidate names the half that really is qualification, and the
top-level function stays a chooser because it still chooses.

WHAT IS DELIBERATELY ABSENT. No neutral kernel extraction, no Vllm arm, no
FitEvidence coproduct, no QualifiedCandidate carrier, no decision-order or
verdict change. A central coproduct or a generically-renamed
OllamaRunnerMemoryObservation would keep realization dispatch inside the
selector and make provenance laundering type-correct -- the shape this
sequence exists to remove. The first common type belongs AFTER qualification.

NO COMPATIBILITY RE-EXPORT. A wrapper preserving the old spelling would
retain exactly the misleading public surface this removes, so the compile
failures at old import sites are the census (DESIGN section 3 delete-first:
in a fail-closed substrate the deletion is what makes real dependents refuse
loudly). Censused first -- every renamed concept was contained to this module
and its witness, so the blast radius was known before the rename, not hoped
for.

The annotation on the entry point states that the neutral kernel has NOT been
extracted, so this cut cannot later be cited as completing step 2.

EVIDENCE: all 42 witnesses in the choice entry pass, changed only in module
and symbol references. Every fixture value, decision ordering, rejection axis,
unanswerable outcome, winner and tie result is identical -- which is what
distinguishes a rename from an edit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U397y4s3dSBof7vGPAX87G
…ead name is cited

Review 59813. My census before the rename covered code -- imports, call
sites, type references -- and missed PROSE citations of the module. Four
sites still named the dead authority:

  dag/std/measure.dag
  dag/gunbc/model/population.dag
  dag/gunbc/spark/serving_convergence_withholding.dag
  docs/plans/spark-fleet-hand-edit-gap-analysis.md

These are exactly what DESIGN section 3's standing rule protects. It says to
cite the SYMBOL rather than the position, on the grounds that a stale name is
decidable and enforceable while a stale line is not reachable from the
namespace tree at all. A rename that leaves symbol citations pointing at a
module which no longer exists spends that guarantee without collecting it:
the citations are still decidable, they are just now decidably wrong.

Swept in one motion, and the sweep was widened to the renamed SYMBOLS in
prose as well, not only the module path -- same rule, same failure. Nothing
under the old spellings survives anywhere in the tree.

ONE OF THEM IS NOT A MECHANICAL RELABEL. serving_convergence_withholding
carries a paragraph whose whole job is to stop that gate being mistaken for
the fit gate: "gunbc.model.choice decides whether a candidate fits a host's
memory. This decides whether a host may receive serving convergence AT ALL."
The rename SHARPENS that distinction rather than merely relabelling it, so
the paragraph now says gunbc.model.ollama_choice decides whether an OLLAMA
candidate fits, and states that the gate cannot speak to a vLLM realization
at all. The new name makes that paragraph's point more forcefully than the
old one could.

The docs/plans file is hand-authored rather than a generated projection, so
it is edited directly rather than through the artifact gate.

All four edits are annotation or markdown only -- annotations are erased
before every semantic pass, so no behaviour can change. Executed rather than
asserted: 42 of 42 witnesses pass, no failures.

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

gunbai-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Review 59813 is right and it is fixed at d56d291. Worth naming the gap rather than just closing it: my pre-rename census covered code — imports, call sites, type references — and missed prose citations of the module. All four are cut over, and I widened the sweep to the renamed symbols in prose as well, not just the module path, since it is the same rule and the same failure. Nothing under the old spellings survives anywhere in the tree.

That gap matters more than its size suggests. DESIGN §3's standing rule says to cite the symbol rather than the position precisely because a stale name is decidable and enforceable while a stale line is not reachable from the namespace tree at all. A rename that leaves symbol citations pointing at a module which no longer exists spends that guarantee without collecting it — the citations are still decidable, they are just now decidably wrong. So the reviewer's framing is exact: the rename was not complete without them.

One is not a mechanical relabel. serving_convergence_withholding carries a paragraph whose entire job is to stop that gate being confused with the fit gate:

gunbc.model.choice decides whether a candidate fits a host's memory. This decides whether a host may receive serving convergence AT ALL.

The rename sharpens that distinction rather than relabelling it, so it now reads that gunbc.model.ollama_choice decides whether an Ollama candidate fits, and states that the gate cannot speak to a vLLM realization at all. The new name makes that paragraph's own point more forcefully than the old one could — which is a small piece of evidence that the reclassification is honest rather than cosmetic.

docs/plans/spark-fleet-hand-edit-gap-analysis.md is hand-authored rather than a generated projection, so it is edited directly rather than through the artifact gate.

All four edits are annotation or markdown only, and annotations are erased before every semantic pass, so no behaviour can change. Executed rather than asserted: 42 of 42 witnesses pass, no failures — same fixtures, same decision ordering, same rejection axes, same winners, same ties as before the rename.

— sent from eager-pike-541

briansrls
briansrls previously approved these changes Sep 4, 2026

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVE exact head d56d291. This is FIT step 1 only: an Ollama-specific structural reclassification, with the top-level surface still truthfully named as a chooser and only the qualification half named qualify_ollama_candidate. The chooser body, decision order, fixtures, rejection axes, winners, and tie behavior are unchanged; all remaining changed files repair stale prose citations. No neutral kernel, vLLM arm, FitEvidence coproduct, compatibility wrapper, or genericized Ollama memory evidence was introduced. Merge authorization remains conditional on required exact-head CI reaching terminal success and this SHA remaining the head.

@briansrls
briansrls dismissed their stale review September 4, 2026 07:01

Stale by exact-head policy: PR head moved from d56d291 to 76ba0e2 after this review.

briansrls
briansrls previously approved these changes Sep 4, 2026

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVE exact head 76ba0e2. Re-review scope was the merge from main after the prior exact-head approval became stale. The commit's parents are the previously approved d56d291 and main@ce937d0c4d4eac22e7f16eef5ad75305750fc810. Comparing d56d291 to this head shows only main-side files; none of the PR's six reviewed files changed. Comparing current main to this head yields the same six-file step-1 reclassification, with no interaction in choice.dag/ollama_choice.dag or measure.dag and no added neutral kernel, vLLM arm, FitEvidence coproduct, compatibility surface, or behavior change. Merge authorization remains conditional on required exact-head CI reaching terminal success and this SHA remaining the head.

… dead account of

review 59866 is correct and the defect is mine. The rename swept
docs/plans/spark-fleet-hand-edit-gap-analysis.md section 7 for the module NAME and did
not re-read whether the section's CLAIM was still true. It was not. Section 7 said
gunbc.model.ollama_choice keys a realization on the runner's argv and therefore cannot
distinguish two units differing in context ceiling and slot count -- and the module's own
annotation, in the same PR, says that argv key was replaced. Attaching the current
authority's name to an obsolete account of it is worse than the stale name it replaced:
a stale name is visibly dead, while a live name over a dead claim reads as current.

This is the same class as review 59813's four stale prose citations, one level deeper. That
one was a name census; this one is a CLAIM census, and a rename does not discharge it. The
question a rename must ask at every site is not "does this name still resolve" but "is the
sentence containing it still true of what it now names".

Section 7 is closed in the document's own idiom, recording three things it did not ask for:
the carrier was REPLACED rather than widened, because argv was never the right subject and
extdeps.ollama.server_env already holds the variables as typed axes; the partition is owned
by the module rather than supplied by the caller, where the predecessor's varied_flags
argument let a caller erase a causal axis from the fixed mode and thereby authorize evidence
transport across it; and identity runs typed values first and wire second, so the module
never parses an observed string.

Ordered item 4 is closed with it. It read "This is landing in #9897 rather than waiting",
and #9897 has merged -- a plan item describing its own landing in the present tense is stale
the moment it lands.

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

gunbai-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

review 59866 is correct and the defect is mine. Fixed in 3bc20235fb6.

The rename swept docs/plans/spark-fleet-hand-edit-gap-analysis.md §7 for the module NAME and did not re-read whether the section's CLAIM was still true. It was not: §7 said the module keys a realization on the runner's argv and therefore cannot distinguish two units differing in context ceiling and slot count — while the module's own annotation, in this same PR, says that argv key was replaced. Attaching a live authority name to an obsolete account of it is worse than the stale name it replaced: a stale name is visibly dead, a live name over a dead claim reads as current.

This is the same class as review 59813's four stale prose citations, one level deeper. That was a NAME census; this is a CLAIM census, and a rename does not discharge it. The question at every swept site is not "does this name still resolve" but "is the sentence containing it still true of what it now names".

§7 is now closed in the document's own strikethrough idiom, recording three things the section did not ask for: the carrier was REPLACED rather than widened (argv was never the right subject — extdeps.ollama.server_env already holds the variables as typed axes); the partition is owned by the module rather than supplied by the caller (the predecessor's varied_flags argument let a caller erase a causal axis from the fixed mode and thereby authorize evidence transport across it); and identity runs typed values first, wire second, so the module never parses an observed string.

I also closed ordered item 4 with it, which the review did not flag. It read "This is landing in #9897 rather than waiting", and #9897 has merged — a plan item narrating its own landing in the present tense is stale the moment it lands.

This moves the head off 76ba0e2, so the exact-head approval on that SHA no longer applies. — sent from eager-pike-541

@briansrls
briansrls dismissed their stale review September 4, 2026 07:22

Head moved from the exactly reviewed 76ba0e2 to 3bc2023. The prior approval is stale by its own condition; the new prose correction requires exact-head re-review.

briansrls
briansrls previously approved these changes Sep 4, 2026

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVE exact head 3bc2023. Re-review scope is the single commit after the previously approved 76ba0e2: only docs/plans/spark-fleet-hand-edit-gap-analysis.md changed. The correction is necessary and accurate: the section no longer attaches the live gunbc.model.ollama_choice name to the obsolete argv-key account; it records the closed ObservedOllamaLaunchConfiguration projection, module-owned partition, and typed-values-before-wire direction, and closes the already-landed plan item rather than describing it in the present tense. The step-1 code and witness diff remain unchanged. Merge authorization remains conditional on terminal required exact-head CI and this SHA remaining the head.

…ct identity

CI caught what four dashboard reviews, one exact-head review and I all missed. The floor
lane refused, and NOT on a witness -- every witness passed:

  FAILED PHASE namespace-wave-admission (255 unadjudicated delta(s), 0 stale, 142 consumed)
  adjudication REFUSED standing=measurement_completed blockers=1

Every one of the 255 reads

  TargetChanged binding test.claim.model.serving_choice_witness_test::<decl> `<spelling>`
    base {gunbc.model.choice} -> head {gunbc.model.ollama_choice}

which is the wall working exactly as gunbc.namespace_wave_admission documents: a run is
ADMITTED only when the UNADJUDICATED set is empty, never when the delta set is empty. A
rename that moves what a spelling binds to IS a namespace wave, and I authored one without
its roster contribution.

WHY EVERY ROW IS ENUMERATED RATHER THAN PATTERNED. The module carrying this roster says a
pattern would admit a genuine rebind that happened to land in the same two modules, and a
rename wave is precisely the change that must not be able to hide one. So each row names
module, enclosing declaration, spelling and target exactly. Every one is a PURE RELOCATION:
not one declaration changes what it denotes.

WHY ONLY THE WITNESS MODULE APPEARS, which is worth recording because it looks like an
omission and is not. The wall's binding channel is authored NAME OCCURRENCES resolved per
module, and test.claim.model.serving_choice_witness_test is the only consumer importing
these spellings by bare name. The other three touched files -- gunbc.model.population,
gunbc.spark.serving_convergence_withholding and std.measure -- carry the old module name
only in PROSE. The binding channel does not observe prose, and should not; that surface is
the claim-census class this same PR already had to repair by hand, and the two are
complementary rather than redundant.

DISSOLUTION IS MANDATORY AND DATED. These rows go when #10358 merges: base and head will
both carry the rename, no run can produce the deltas, and all 255 report STALE -- which
refuses every unrelated PR. The shrink is the fix, not housekeeping.

cargo check -p v1-compiler --lib is green on the remote runner.

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

gunbai-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Pushed a2799aead5a. CI caught a required contribution this PR was missing, and it caught what four dashboard reviews, one exact-head review and I all read past.

required-witnesses-floor failed — and not on a witness. Every witness passed. The refusal was:

FAILED PHASE namespace-wave-admission (255 unadjudicated delta(s), 0 stale, 142 consumed)
adjudication REFUSED standing=measurement_completed blockers=1

All 255 read:

TargetChanged binding test.claim.model.serving_choice_witness_test::<decl> `<spelling>`
  base {gunbc.model.choice} -> head {gunbc.model.ollama_choice}

That is the wall working exactly as gunbc.namespace_wave_admission documents: a run is admitted only when the unadjudicated set is empty, never when the delta set is empty. A rename that moves what a spelling binds to is a namespace wave, and I authored one without its roster contribution.

Every row is enumerated by exact identity, not patterned. The roster's own note says a pattern would admit a genuine rebind that happened to land in the same two modules — and a rename wave is precisely the change that must not be able to hide one. Each row names module, enclosing declaration, spelling and target. Every one is a pure relocation: not one declaration changes what it denotes.

Why only the witness module appears — this looks like an omission and is not. The binding channel resolves authored name occurrences per module, and the witness is the only consumer importing these spellings by bare name. gunbc.model.population, gunbc.spark.serving_convergence_withholding and std/measure.dag carry the old module name only in prose, which the binding channel does not and should not observe. That prose surface is the claim-census defect review 59866 caught on this same PR — the two mechanisms are complementary, and neither substitutes for the other.

Dissolution is mandatory and dated. These rows go when this PR merges: base and head will both carry the rename, no run can produce the deltas, and all 255 report stale — which refuses every unrelated PR. The shrink is the fix, not housekeeping.

cargo check -p v1-compiler --lib is green on the remote runner. This moves the head off 3bc20235fb6, so the exact-head approvals on that SHA no longer apply. — sent from eager-pike-541

…an hand-merging the hunk

main's NAMESPACE_TRANSITION_ADMISSIONS moved underneath this branch in two ways at once, and
the conflict is at the head of the array where both changes land.

  main ADDED the gunbc#10197 rung-drop per-row split rows.
  main DELETED the gunbc#10254 Spark OOBE vendor-interface rows, dissolved on their own
  trigger when that PR merged.

Hand-merging the conflicted hunk would have kept my side's copy of the OOBE rows, which main
had already retired. Those rows would have been STALE ADMISSIONS the moment they landed -- a
permission standing over a delta no run can produce -- and the wall refuses a stale admission
exactly as it refuses an unadjudicated delta, so the resurrection would have blocked every
unrelated PR until someone deleted them again.

So the resolution takes main's roster WHOLESALE and re-seats my 255 rows on top of it. The
authored content is unchanged; what changed is which neighbours it sits beside, which is a
fact about main and not mine to merge by hand.

THE ROWS ARE STILL THE RIGHT SET. main has not touched
dag/test/claim/model/serving_choice_witness_test.dag or dag/gunbc/model/choice.dag since the
base this branch measured against, so the wave those 255 rows describe is unchanged. The
deltas are a function of what this branch does to that witness, not of what main did
elsewhere.

cargo check -p v1-compiler --lib green on the remote runner after the merge.

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

gunbai-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Conflict resolved in 2d1c9bca1fa. Head is now 2d1c9bca1fa.

The conflict was at the head of NAMESPACE_TRANSITION_ADMISSIONS, where main moved in two ways at once:

Hand-merging the conflicted hunk would have kept my side's copy of the OOBE rows that main had already retired. Those would have been stale admissions the moment they landed — a permission standing over a delta no run can produce — and the wall refuses a stale admission exactly as it refuses an unadjudicated delta. So the resurrection would have blocked every unrelated PR until someone deleted them again. That is the same failure this PR's own rows are dated to avoid.

So I took main's roster wholesale and re-seated my 255 rows on top of it. The authored content is unchanged; what changed is which neighbours it sits beside, which is a fact about main rather than something for me to merge by hand.

The rows are still the correct set. main has not touched dag/test/claim/model/serving_choice_witness_test.dag or dag/gunbc/model/choice.dag since this branch's base, so the wave those rows describe is unchanged — the deltas are a function of what this branch does to that witness, not of what main did elsewhere.

cargo check -p v1-compiler --lib is green on the remote runner after the merge. — sent from eager-pike-541

@briansrls
briansrls dismissed their stale review September 4, 2026 09:39

Superseded by head movement from 3bc2023 to 2d1c9bc; exact-head approval must not remain current after the namespace-wave roster and main merge changed the tree.

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES on exact head 2d1c9bc.

The namespace wave is real and belongs in #10358. The required-floor receipt on #10370 establishes 255 unadjudicated TargetChanged binding deltas and no witness failure. The 255 exact per-binding TransitionAdmission rows are the correct shape; #10370 must not duplicate them. I also checked the merge resolution: current main's serving_choice witness and old choice module are byte-identical to the measured base, and the head takes current main's namespace roster before adding this cohort, so the newly added #10197 rows remain and the retired #10254 OOBE rows do not return. I found no implementation or row-population blocker.

One content blocker remains in the OLLAMA_CHOICE_RECLASS_LABEL lifecycle annotation. It says that after #10358 merges all 255 rows become stale and refuse every unrelated PR. The implementation says otherwise. A binding admission is consumed when the base binds its (module, declaration, spelling) to exactly the admitted singleton target; after this rename lands, these rows bind exactly to gunbc.model.ollama_choice and therefore become consumed. Consumed rows are blocking only when the admission-roster path is touched (consumed_due = roster_touched && !consumed_admissions.is_empty()); unrelated PRs remain admitted. The source itself renders this as “consumed by its own merge; deletion is owed on the roster's next touch.”

Rewrite the trigger paragraph accordingly: the merge consumes the 255 rows; the first subsequent roster-touching change must delete the cohort, and an immediate post-merge cleanup is appropriate. They cannot be deleted in the same PR tree that needs them to admit the rename. This is prose-only. Do not change the 255 identities and do not add them to #10370.

The old exact-head approval on 3bc2023 has been dismissed. Required exact-head CI is pending; no merge authorization.

… due

Takes side chat's exact-head REQUEST_CHANGES review 5111479181 on #10358. Two findings, and
only the first is prose.

ONE: THE LIFECYCLE CLAIM WAS WRONG IN BOTH HALVES. My trigger paragraph said the 255 rows
would report STALE once the rename lands and would then refuse EVERY unrelated PR. Neither
is what the mechanism implements.

  A STALE row matches no delta in the run. A CONSUMED row is one the BASE has already
  satisfied -- admission_consumed_at_base holds when the base binds the exact
  (module, declaration, spelling) to a singleton set containing the admitted target.
  After #10358 lands, every one of these spellings binds to gunbc.model.ollama_choice at
  the base, so they are consumed. Different states, different reporters.

  Consumed rows are NOT globally blocking. The predicate is
  consumed_due = roster_touched && !consumed_admissions.is_empty(), so a consumed row comes
  due on the roster file's OWN next touch and on no other change. An enrolled unit test
  names exactly that behaviour.

The wrong version overstated this cohort's blast radius, which is the same defect class as
the argv paragraph this PR already had to repair: a confident sentence about a mechanism,
written without reading the mechanism.

TWO, AND IT IS NOT PROSE: THIS CHANGE OWED SIXTEEN DELETIONS AND HAD NOT MADE THEM. Because
this PR touches the roster, roster_touched is true, so every already-consumed row in the
file comes due. main carries sixteen gunbc#10197 rung-drop per-row split rows; #10197 is on
main at 0c031e6, and gunbc.design_ledgers there already imports rung_drop_roster from
gunbc.rung_drop.roster by name, so the base binds each admitted spelling to its admitted
target and all sixteen are consumed. Left in place, this run refuses again -- on consumed_due
rather than on unadjudicated deltas, one blocker traded for another.

They are deleted with their label, and a twenty-sixth dissolution entry records why THIS
change owed it: carrying consumed rows forward while editing the same file is precisely what
the predicate exists to prevent.

Why the earlier runs did not show this: neither 76ba0e2 nor #10370's head touches
namespace_wave_admission.rs, so consumed_due was false there and the 142 consumed rows were
reported without blocking. Touching the roster is what makes them due.

The 255 identities are unchanged, and none were added to #10370. cargo check -p v1-compiler
--lib is green on the remote runner.

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

gunbai-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Pushed 4ae0b1f8e03, taking side chat's exact-head REQUEST_CHANGES review 5111479181. Two findings, and only the first was prose.

1. My lifecycle claim was wrong in both halves. I wrote that the 255 rows would report stale once the rename lands, and would then refuse every unrelated PR. Neither is what the mechanism implements:

  • A stale row matches no delta in the run. A consumed row is one the base has already satisfied — admission_consumed_at_base holds when the base binds the exact (module, declaration, spelling) to a singleton containing the admitted target. After this lands, every spelling binds to gunbc.model.ollama_choice at the base, so they are consumed, not stale.
  • Consumed rows are not globally blocking. The predicate is consumed_due = roster_touched && !consumed_admissions.is_empty(), so they come due on the roster file's own next touch and on no other change. An enrolled unit test names exactly that behaviour.

The wrong version overstated this cohort's blast radius — the same defect class as the argv paragraph this PR already had to repair: a confident sentence about a mechanism, written without reading the mechanism.

2. Not prose — this change owed sixteen deletions and had not made them. Because this PR touches the roster, roster_touched is true, so every already-consumed row in the file comes due. main carries sixteen #10197 rung-drop rows; #10197 is on main at 0c031e6da4e, and gunbc.design_ledgers there already imports rung_drop_roster from gunbc.rung_drop.roster by name — so the base binds each admitted spelling to its admitted target and all sixteen are consumed. Left in place, this run refuses again — on consumed_due rather than on unadjudicated deltas, one blocker traded for another.

They are deleted with their label, and a twenty-sixth dissolution entry records why this change owed it. Carrying consumed rows forward while editing the same file is precisely what the predicate exists to prevent.

Why earlier runs didn't surface it: neither 76ba0e2 nor #10370's head touches namespace_wave_admission.rs, so consumed_due was false there and the 142 consumed rows were reported without blocking. Touching the roster is what makes them due.

The 255 identities are unchanged and none were added to #10370. cargo check -p v1-compiler --lib green on the remote runner. Net +30/-165. — sent from eager-pike-541

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES on exact head 4ae0b1f.

First, the controlling correction: the stricter interim note was right and my final “prose-only” ruling was materially incomplete. DO NOT restore the sixteen gunbc#10197 rows. This PR touches namespace_wave_admission.rs, so roster_touched is true; every admission already consumed at the base is due on this run.

I rechecked the full base proof rather than extrapolating from gunbc.design_ledgers. #10197's merge 0c031e6 is an ancestor of this PR's base 4f0ad8c, and none of the five relevant consumer files changed in between. The sixteen rows partition 1/2/5/7/1 across gunbc.design_ledgers, deleted_cadence_reference_census_witness_test, rung_drop_declaration_witness_test, rung_drop_standing_partition_witness_test, and tools.ci_gates. At the base, each named declaration still contains the spelling and each module imports that spelling from exactly the admitted target. The candidate set is therefore the admitted singleton for every row, admission_consumed_at_base holds sixteen times, and leaving them would trade the unadjudicated blocker for consumed_due. The deletion and label removal are REQUIRED and ACCEPTED.

The exact-head delta is one file, +30/-165. It removes exactly those sixteen rows and their label, corrects the Ollama cohort lifecycle prose, and does not touch any of the 255 identities or #10370. The 56 KB near-miss did not enter the commit; the existing ledger remains present.

Two prose blockers remain in the new dissolution entry:

  1. It creates a duplicate ordinal. The file already contains TWENTY-SIXTH DISSOLUTION (2026-09-04, gunbc#10197) for the 142 #10254 OOBE rows immediately above. The new entry is also TWENTY-SIXTH DISSOLUTION, and there is no TWENTY-SEVENTH entry. Rename the new one to TWENTY-SEVENTH DISSOLUTION (2026-09-04, gunbc#10358). This ledger itself states that the ordinal exists to make an entry citable and records duplicate ordinals as a defect; repeating one here is not harmless numbering.

  2. The proof paragraph names only gunbc.design_ledgers importing rung_drop_roster and then concludes that each of sixteen rows is consumed. That evidence establishes one row, not sixteen; the other fifteen span four modules and four additional target/spelling groups. Record the actual grouped join, for example: 1 design_ledgers; 2 deleted-cadence witness; 5 rung-drop-declaration witness; 7 standing-partition witness; 1 tools.ci_gates, with each group's exact imported target. The deletion is correct; the written proof is presently narrower than its conclusion.

These corrections are prose-only. Do not restore the sixteen rows, do not alter the 255-row cohort, and do not add anything to #10370. Run 33860809090 is pending but will become superseded when this head moves; the replacement exact-head run must establish zero unadjudicated, zero stale, and no consumed-due blocker. No merge authorization.

gunbc-ci-auto-heal and others added 2 commits September 4, 2026 10:13
…rrate the #10197 deletion

main moved again while this branch was open: gunbc#10344 landed (61274d0) and did BOTH
halves of the roster treadmill in one change -- it deleted the sixteen gunbc#10197 rows that
its own roster touch had made due, and added nineteen of its own for the asset-identity
extraction.

TWO CONSEQUENCES, AND NEITHER IS A PLAIN MERGE.

FIRST, #10344's NINETEEN ROWS ARE NOW CONSUMED AT THIS BRANCH'S BASE, so this change owes
their deletion for the same reason it owed #10197's. gunbc.fleet_physical_inventory on main
already imports chassis_srv1 and its twelve siblings from gunbc.fleet_asset_identity -- the
admitted target -- and that file is not in this diff, so base equals head for it and
admission_consumed_at_base holds on every row. consumed_due is
roster_touched && !consumed.is_empty(), this change touches the roster, so leaving them
refuses the run. Deleted.

The treadmill is deliberate, not an accident of timing: each roster-touching change
discharges the cohort the previous one left consumed. #10344 did exactly this to #10197, and
the next roster-touching change will do it to the cohort below.

SECOND, MY OWN TWENTY-SIXTH ENTRY HAD TO BE REWRITTEN RATHER THAN CARRIED. The previous head
of this branch deleted the #10197 rows and narrated that deletion. main deleted the same
sixteen independently. Carrying my entry would double-record one event -- the failure the
TWENTY-THIRD and TWENTY-FOURTH entries in this same ledger already call out and refuse. My
entry is dropped in favour of main's action, and the rewritten entry records the #10344
discharge with a sentence saying explicitly why #10197 is not narrated here.

RESOLUTION SHAPE, unchanged from the previous merge and for the same reason: main's roster is
taken WHOLESALE and the 255-row cohort is re-seated on it. Hand-merging the hunk would have
preserved my side's copy of rows main had already retired, which is how a resolution
manufactures stale admissions.

The 255 identities are untouched and none were added to #10370. cargo check -p v1-compiler
--lib is green on the remote runner after the merge.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U397y4s3dSBof7vGPAX87G
…rdinal was wrong twice over

Takes side chat's exact-head REQUEST_CHANGES review 5111687963. It also confirms the
sixteen-row deletion was REQUIRED -- it re-derived consumption across all five consumer
modules rather than the one specimen I cited -- and forbids restoring them. Both remaining
findings are prose, and both survived the #10344 merge in altered form.

ONE: THE ORDINAL. Side chat found my entry duplicating TWENTY-SIXTH. On the merged tree it
is worse: #10344 trimmed the ledger, so the highest surviving ordinal is TWENTY-THIRD and my
entry was SKIPPING twenty-four and twenty-five. A skipped ordinal is the same defect as a
duplicated one -- the number exists to make an entry citable by its own name, and it does
that only if it is exactly the next one. Now TWENTY-FOURTH.

TWO: THE PROOF WAS NARROWER THAN ITS CONCLUSION, and the criticism transferred exactly across
the rewrite. Side chat caught my #10197 paragraph citing the design_ledgers row and
concluding all sixteen; the entry I wrote for #10344 reproduced the shape, citing
fleet_physical_inventory importing chassis_srv1 and concluding all nineteen. Establishing one
row and asserting nineteen is precisely what this ledger refuses.

The actual partition, computed rather than assumed:

  15  gunbc.fleet_physical_inventory            -> gunbc.fleet_asset_identity
   4  test.claim.cooling_qualification_witness  -> gunbc.fleet_asset_identity

The fifteen resolve directly. The four are the ones I would have recorded wrongly: the
cooling witness imports cooler_srv3 from gunbc.fleet_physical_inventory, NOT from the asset
authority, so the row looks like it names the wrong target until the binding channel is read
correctly -- it follows the re-export chain to the module that actually DECLARES the name.
Same admitted target, one hop further out. The entry now states that separately, because a
reader checking the row against the witness's import list would otherwise conclude the row
was mis-authored.

Neither consumer file is in this diff, so base equals head for both and
admission_consumed_at_base holds on all nineteen.

The 255 identities are untouched and none were added to #10370. cargo check -p v1-compiler
--lib is green on the remote runner.

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

gunbai-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Pushed 12b0e57810a, taking side chat's exact-head REQUEST_CHANGES review 5111687963. Both remaining findings were prose, and both survived the #10344 merge in altered form.

1. The ordinal. Side chat found my entry duplicating TWENTY-SIXTH. On the merged tree it's worse: #10344 trimmed the ledger, so the highest surviving ordinal is TWENTY-THIRD and my entry was skipping twenty-four and twenty-five. A skipped ordinal is the same defect as a duplicated one — the number exists to make an entry citable by its own name, and it does that only if it's exactly the next one. Now TWENTY-FOURTH.

2. The proof was narrower than its conclusion, and the criticism transferred exactly across the rewrite. Side chat caught my #10197 paragraph citing the design_ledgers row and concluding all sixteen. The entry I then wrote for #10344 reproduced the shape — citing fleet_physical_inventory importing chassis_srv1 and concluding all nineteen.

The real partition, computed rather than assumed:

15  gunbc.fleet_physical_inventory            -> gunbc.fleet_asset_identity
 4  test.claim.cooling_qualification_witness  -> gunbc.fleet_asset_identity

The four are the ones I'd have recorded wrongly. The cooling witness imports cooler_srv3 from gunbc.fleet_physical_inventory, not from the asset authority — so the row reads as naming the wrong target until you follow the binding channel to the module that actually declares the name. Same admitted target, one hop out. The entry states that separately, because a reader checking the row against the witness's import list would otherwise conclude it was mis-authored.

Neither consumer file is in this diff, so base equals head for both and admission_consumed_at_base holds on all nineteen.

Also on the record from that review: the sixteen-row #10197 deletion was required, verified independently across all five consumer modules rather than the single specimen I cited, and restoring them is forbidden. On the current head that deletion is main's (via #10344), not this PR's — the entry says so explicitly rather than double-recording one event.

The 255 identities are untouched and none were added to #10370. cargo check -p v1-compiler --lib green remotely. — sent from eager-pike-541

@gunbai-bot gunbai-bot Bot closed this Sep 4, 2026
@gunbai-bot gunbai-bot Bot reopened this Sep 4, 2026
@briansrls
briansrls dismissed stale reviews from themself September 4, 2026 11:36

Superseded by head movement from 2d1c9bc to 12b0e57. The lifecycle correction and subsequent merged-roster disposition are reviewed at the new exact head.

briansrls
briansrls previously approved these changes Sep 4, 2026

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVE exact head 12b0e57.

Both blockers from review 5111687963 are discharged on the merged ledger actually present at this head. #10344 changed the roster before this branch rejoined main: it deleted the sixteen #10197 rows and introduced nineteen asset-identity admissions. The highest surviving dissolution ordinal at the join is TWENTY-THIRD, so this head correctly records the next event as TWENTY-FOURTH rather than preserving the pre-merge 26/27 prescription.

The consumption proof now owns the full population rather than one specimen: 15 binding identities in gunbc.fleet_physical_inventory resolve directly to gunbc.fleet_asset_identity, and 4 in test.claim.cooling_qualification_witness resolve through the imported fleet namespace to that same declaring authority. The base import carries all 13 asset constants used by the repeated direct binding identities; the witness imports cooler_srv3 through fleet_physical_inventory; neither consumer file is in this PR diff, so base and head agree and admission_consumed_at_base holds for all nineteen. Their deletion on this roster touch is correct. The independently deleted #10197 cohort is not double-narrated.

The Ollama lifecycle paragraph now says consumed rather than stale and scopes the deletion obligation to the next roster-touching run. The 255 exact admission identities remain unchanged, and none were copied to #10370. No implementation, selector behavior, or step-2 content changed.

Required exact-head run 33868113495 is pending. Merge authorization remains conditional on terminal success and this SHA remaining the head.

The grouped 15/4 partition is correct -- verified against the base
roster, which holds exactly 19 rows: 15 in gunbc.fleet_physical_inventory
and 4 in test.claim.cooling_qualification_witness, both targeting
gunbc.fleet_asset_identity. The prose around it was not.

It said the fifteen were `chassis_srv1` "and its twelve siblings". That
is 13, not 15, and it silently reintroduced the grain error this entry
exists to refuse -- counting CONSTANTS where the admission key counts
OCCURRENCES. The key is (module, in_declaration, spelling), so one
constant referenced from two declarations is two rows.

Measured: the fifteen are 10 distinct spellings across 8 declarations.
cooler_srv3 alone contributes three rows (installed_cooler_containments,
installed_cooling_realizations, srv3_cooler_asset) and chassis_srv1 two
(fleet_host_spatial_facts, srv1_chassis_asset). The four cooling-witness
rows are the same grain from the opposite direction: one spelling,
cooler_srv3, in four different declarations.

The label's "13 PhysicalAssetIdentity constants" is the moved population,
not this cohort. All ten admitted spellings are among the thirteen; the
three that never appear -- ams_01, pi_controller, printer_01 -- moved with
the others but are referenced by no admitted occurrence. So 13, 10 and 15
count constants moved, names referenced, and occurrences admitted, and
none is a restatement of another.

No admission row changes; the 255-row Ollama cohort is untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U397y4s3dSBof7vGPAX87G
@briansrls
briansrls dismissed their stale review September 4, 2026 11:43

Superseded by head movement from 12b0e57 to 8ef903f. The new commit corrects the occurrence-count versus moved-constant prose, so exact-head approval must be reissued on the reviewed tree.

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVE exact head 8ef903f.

The sole commit after 12b0e57 changes only the consumption-proof prose in namespace_wave_admission.rs (+22/-7); no TransitionAdmission row changes. It closes the count-versus-grain seam in my superseded review.

The measured populations are distinct and now stated distinctly. The base cohort has 19 exact admission keys: 15 (module, in_declaration, spelling) keys in gunbc.fleet_physical_inventory and 4 in test.claim.cooling_qualification_witness, all targeting gunbc.fleet_asset_identity. The 15 direct keys contain 10 distinct spellings across 8 declarations: repeated uses such as cooler_srv3 in three declarations and chassis_srv1 in two are separate occurrence-grain rows. The four witness keys are one spelling, cooler_srv3, in four declarations. Separately, fleet_asset_identity declares 13 moved PhysicalAssetIdentity constants; ams_01, pi_controller, and printer_01 are in that moved population but in no admitted occurrence. Thus 13 constants moved, 10 names referenced, and 15 direct occurrence keys are three different denominators.

The TWENTY-FOURTH ordinal, grouped 15/4 consumption proof, deletion of the inherited consumed cohort, consumed-not-stale lifecycle, and all previously reviewed FIT step-1 content remain accepted. The 255 Ollama admission identities are unchanged and none are copied to #10370.

Required exact-head run 33869134455 is pending. Merge authorization remains conditional on terminal success and this SHA remaining the head.

@gunbai-bot
gunbai-bot Bot merged commit 97345e5 into main Sep 4, 2026
7 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/eager-pike-541-ollama-choice-reclass branch September 4, 2026 13:39
briansrls pushed a commit that referenced this pull request Sep 4, 2026
…action shape

#10358 renamed gunbc.model.choice -> gunbc.model.ollama_choice on main.
Git tracked the rename, so this branch's kernel extraction landed in the
renamed file and only the hunks where the two changes genuinely disagree
conflicted.

dag/gunbc/model/ollama_choice.dag -- four hunks, resolved to THIS BRANCH.
Main carries the pre-extraction body because #10358 was a rename and
nothing else: it still declares WithinReleaseQuality, compare_within_release,
verdict_quality and the distinct_release_count diagnostic. This branch
deleted all of them when the runtime-neutral maximum moved to
gunbc.model.release_relative_selection. Taking main's side would have
restored the very duplication step 2 exists to remove, so the extracted
form wins every conflicting hunk. Verified after resolution: verdict_quality,
quality_maximum, verdicts_at_quality, distinct_release_count, verdict_release,
QualityMaximum, compare_within_release and WithinReleaseQuality are all
absent from this module, the kernel import is present, and
ollama_ranked_admissible remains the sole Ollama contribution to selection.

Main's own sentence in that file -- "THE RUNTIME-NEUTRAL MAXIMUM/TIE KERNEL
HAS NOT YET BEEN EXTRACTED, and this sentence exists so that the rename
cannot be cited as though it had been" -- was written to be deleted by
exactly this commit. It is now false, and it is gone.

docs/plans/spark-fleet-hand-edit-gap-analysis.md -- one hunk, resolved to
MAIN. This branch still carried the superseded argv-keyed claim about
section 7; main carries the CLOSED correction that #10358 landed, naming
ObservedOllamaLaunchConfiguration and ExactRuntimeConfigurationIdentity.
Keeping this branch's side would have re-opened the exact defect that
review 59866 caught and that #10403 files as
a_live_authority_name_carries_a_superseded_claim.

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

#10358 landed 255 admission rows and, in the same change, paid the
roster-touching obligation this branch had just paid: main's own TWENTY-FOURTH
DISSOLUTION deletes the same nineteen gunbc#10344 asset-identity rows, by the
same trigger, with a 15+4 partition matching the nineteen measured here.

ONE EVENT, ONE RECORD -- so THIS BRANCH'S TWENTY-FOURTH DISSOLUTION IS
DELETED, not reconciled. Both entries carried the same ordinal for the same
deletion; keeping both would be the double-narration this roster refuses in
its own prose and which it has already resolved this way twice (the #10011
rows yielded to #10106, the #10218 row yielded to main). Main's record is
kept because it is main's, and because it is the better entry: it states the
partition rather than generalising from one specimen.

The deletion itself is unaffected -- the rows are gone either way, and the
adjudicator independently confirmed nineteen on run 33862141548 before either
record existed.

RESOLVED AS MAIN WHOLESALE PLUS THIS BRANCH'S TRANSITION. The file is not
generated: .gitattributes line 65 excludes it from merge=generated-artifact
and git check-attr reports "merge: unspecified", so ordinary markers and hand
resolution are correct here and the regeneration recipe would have been the
wrong ceremony.

VERIFIED AGAINST THE NEW DENOMINATOR, because main changed the population the
arithmetic was measured on: 255 main rows all present, 2 mine, 257 total,
identity 255+2 holds, zero surviving fleet_asset_identity rows, exactly one
TWENTY-FOURTH DISSOLUTION, and the TWENTY-FIRST TRANSITION intact. Main's
highest transition ordinal is still TWENTIETH, so the ordinal needs no
renumber.

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

#10358 landed 255 selector-reclass rows. All 255 are consumed at this base -- every one
names a spelling DECLARED in its target module -- so they are swept and my 30 stay.

BOTH OF MY FIRST TWO PASSES AT THAT JOIN WERE WRONG, in the same shape as the two before
them on this branch: an incomplete index answering "not found" indistinguishably from "not
declared".

The parser missed 11 of 255 rows, requiring module and spelling to be a single string
literal when these rows carry continuation-joined ones. A row the parser cannot see is a row
the join silently does not adjudicate.

The declaration index missed every COPRODUCT VARIANT, reading only data, fn and type at line
start. ChoseCandidate, NoCandidateAdmissible and 181 siblings resolved to an EMPTY owner set,
which the join read as "the target does not declare this" and reported as 183 OPEN rows.
Keeping those would have left 183 stale rows refusing every later unrelated PR.

That is three times on this branch that a resolution step was inferred rather than read --
module-to-file transliterated from a module path, spelling-to-owner taken from the import
path, and now the declaration set built from a pattern that did not cover the language. Each
was silent, each was plausible, and each produced a confident answer of the wrong SHAPE
rather than an error. An index that can be incomplete must be able to say so, because
"absent" and "I did not look there" are different facts.

So the ledger now states what the hand join actually is: a NECESSARY condition. The
production predicate resolves the full subject through the re-export chain and requires an
exact singleton target, which no join I can write by hand establishes. The wall's own run at
the exact head is the proof.

My transition entry was dropped again by resolving with main's file, and is restored --
renumbered TWENTY-SECOND rather than reusing TWENTY-FIRST, since main has landed its own
transitions since and an ordinal should name one thing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ4iThiZ1B9LPB9ePr8qa9
briansrls pushed a commit that referenced this pull request Sep 4, 2026
* An annotation at scope end names nothing, and it has main red

main has been failing the required-ci parse phase since #10390 (11:48Z).
Every pull request that test-merges main fails required-witnesses-floor
with:

  required-ci: FAILED PHASE parse (16 error(s))
  required-ci: FAILED PHASE namespace-wave-admission (no head index)

All 16 are one file. #10390 deleted the three workflow-subject rows at the
end of test.claim.emit_copy_qualification_witness_test and left their
explanatory block behind as a TRAILING epilogue at lines 483-500, with no
module item after it. DESIGN section 4c admits only a leading block
attached to a module-scope declaration: an annotation names the
declaration that FOLLOWS it, so at scope end it names nothing.
AnnotationAttachmentRefusal::UnattachedAtScopeEnd is exactly that refusal,
and it fires once per line of the block.

The second failure is not independent. claim_executor pushes
"namespace-wave-admission (no head index)" only when the parse phase
produced no index, so the wave never ran at all. One root, two reported
blockers.

WHY THIS SURFACED LATE, since #10390 landed hours before anything went red
and a reader will otherwise suspect a different cause. The parse wall is
not new and #10325 only changed which receipt arm carries blockers. The
last green run on the old tree, #10358's 33869134455, was CREATED at 11:28
-- twenty minutes BEFORE #10390 merged -- so its merge ref predates the
breakage and it never parsed these lines. The first runs to test-merge the
broken main were the ones after it.

THE REPAIR MOVES THE BLOCK TO THE MODULE HEAD, where the imports that
follow give it a subject. Every sentence is preserved. The deictic words
are not: "stood here" becomes "stood at the END OF THIS MODULE", "the rows
above this comment" and "the mutants below" become "in this module",
because a relocated pointer that still says "below" is a false citation of
the kind this repository files as a_live_authority_name_carries_a_superseded_claim.
A trailing paragraph records why the block sits at the head, so the next
author does not move it back.

Nothing else changes: no row, no assertion, no rung drop. The content
already has a typed home at gunbc.rung_drop
emit_copy_qualification_without_a_consumer, and this commit does not touch
it.

EVIDENCE, executed on this tree rather than argued:

  before   required-ci: FAILED PHASE parse (16 error(s))
           required-ci: FAILED PHASE namespace-wave-admission (no head index)

  after    parse phase clean, no parse FAIL lines
           required-ci: namespace-wave-admission ADMITTED
                        -- every delta is auto-admitted or named by
                           a transition admission

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

* The blank line was load-bearing: green parse, wrong subject

The previous head made the parse green and gave the annotation the WRONG
SUBJECT, which is worse than the refusal it replaced -- a plausible answer
standing where a typed refusal used to be is the failure DESIGN section 5
forbids outright, and I shipped it while claiming the fix was verified.

std.source_annotation module_header_gap_subject binds a post-module block
to the MODULE ROOT only when the block opens immediately after the module
line. Its first arm is

  if preceded_by_blank_line || preceded_by_annotation_line { none }

so a blank line between `module ...` and the first `//` deliberately
disables the module-root arm and sends the block through ordinary
nearest-following attachment. On the previous head that bound this
module-wide block to `import std.measure { byte_size }` -- an import it
never describes -- instead of to the module it describes throughout.

Removed that blank line. The blank line AFTER the block, before the
imports, is kept: it ends the block. Nothing else changed.

WHAT I HAD AND DID NOT USE. My evidence was "parse clean, wave ADMITTED".
Both were true and neither says anything about WHICH SUBJECT the annotation
acquired. A greener instrument reading is not evidence about the property I
was actually changing, and I generalized from it anyway.

EXECUTED: dag/test/claim/source_annotation_attachment_witness_test 13/13
PASS on this tree, and the parse phase reports zero parse FAIL lines.

COVERAGE GAP, NAMED NOT FIXED HERE. No enrolled witness covers
module_header_gap_subject's blank-line arm -- the exact rule that silently
mis-bound this block. The attachment battery covers general leading,
trailing, body-grain and block-splitting cases, but nothing discriminates
module-root attachment from nearest-following attachment across that one
bit. That witness belongs in its own change; this PR is a fleet unblocker
for a red main and is deliberately staying one file wide.

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

---------

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant