Repository navigation
Runner width is derived-or-unresolved-with-cause; unknown stops reading as zero - #11762
Conversation
…ng as zero
gunbc.runner_slot_allocation gunbc_runner_slots_per_host is DELETED. The canonical
committed-width answer is gunbc_runner_committed_width -> RunnerWidthResolution
(RunnerWidthDerived { slots } | RunnerWidthUnresolved { cause }), and every
production call site carries or refuses the cause instead of reading an Int. The
Int API's own note declared this gap on 2026-09-19 and named this type as its
capability trigger; this is that change, landed in one motion because half of it
mints one silent default per un-migrated site.
WHY IT WAS URGENT RATHER THAN OWED. srv2's session reservation is unestablished,
so its envelope was zero, its width was zero, and it contributed no members to
fleet_committed_slot_identities -- which made every srv2 registration decode as
RegistrationNamesNoCommittedSlot. gunbc.runner_capacity_plan folds the WHOLE org
roster for every host it plans, so once #11711 wired the planner to the live read
(roster observed 2026-09-19: srv2-02 and srv2-05 present), EVERY host's plan
refused with "resolves to no committed fleet slot" -- a true sentence about the
derivation and a false one about the fleet, blocking planning on the three hosts
with nothing wrong with them.
The carriers that could only say "empty" now say which: CommittedSlotPopulation,
RunnerSlotMembership gains SlotMembershipWidthUnresolved, RegistrationSlotDecoding
gains RegistrationHostWidthUnresolved, ObservedGitHubSlotPopulation gains
GitHubSlotPopulationHostWidthUnresolved, FabricCellDiscoveredSubject gains
DiscoveredHostWidthUnresolved, RunnerSlotEnumerationPostcondition and
host_converge_slice1's cross-check gain unresolved arms, the census REFUSES rather
than retiring every unit on a host it cannot enumerate, and the capacity panel's
fleet total carries its unresolved hosts rather than understating silently.
Two nicknames dissolve with it: gunbc.fleet_host_budget gunbc_runner_pool_budget_for
was gunbc_runner_slice_cap_declared(host) and nothing else, and both re-derived a
width their caller had already resolved -- the cap is now
gunbc_runner_slice_cap_for_width(slots). gunbc_committed_host_runner_slot_allocation
returns a standing, so srv2 has no allocation row at all and the wall's
"zero-or-unestablished" disjunct is replaced by construction.
Witnesses are re-derived, not weakened. Three were asserting literals the fleet had
left behind (21 where the 26/25 GiB row commits 17, memory admission 29 where it is
17, "bound by cores" where memory binds since the one-core-per-slot ruling); each is
re-stated as the relation it was for. The held-width row is deleted with its subject
and replaced by one asserting srv2's width comes back UNRESOLVED naming its
denominator.
Evidence: claim_executor --required-regen on this tree and on origin/main both
refuse with the SAME 11 pre-existing diagnostics, none in any file this change
touches -- so declarations and names resolve. That instrument does NOT cover the
floor's parse phase, and no witness executes locally on this tree (gunbc run
refuses whole-corpus resolve over 48 pre-existing Optional diagnostics in untouched
modules), so witness execution is CI's.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Ledger-Repair-Judged: docs/design-rung-drops.md Heal-Candidate-Run: 35480431739
… and the panel
Addresses the source-hold findings RW-1..RW-4 on this PR, plus two type errors the
dashboard review found in witness files that --required-regen cannot see.
RW-1 THE UNRESOLVED OBLIGATION SURVIVES THE PROJECTION. transition_required_retirees
answered [] for an unresolved target and argued the empty set was the safe direction.
It is not: "do not interrupt anything" and "the retirement prerequisite is satisfied"
are different conclusions, and the consumers receive only the list. RequiredRetirees =
RetireesKnown { units } | RetireesUnresolved { host, cause }; runner_slot_retirement,
runner_slot_provision and host_effect_realize each withhold on the unresolved arm
(evidence absent, no actuation, cap raise withheld) rather than reading it as nothing
to do. The cap side had the second instance: runner_slot_service_units_for_host is now
RunnerSlotServiceUnits, and cap_converge_decision refuses a target set it cannot derive
instead of constructing CapConvergeAuthorized around an empty one.
RW-2 FABRIC DISCOVERY NO LONGER TURNS AN INCOMPLETE SEARCH INTO "foreign". The fleet
fold that dropped unresolved hosts is deleted; fabric_cell_observe reads
fleet_committed_slot_identities' standing and answers DiscoveredHostWidthUnresolved for
a name an unresolved host could own, by the same host-prefix necessary condition the
registration decoder uses. srv2-02 observed on srv4 is undecidable; srv3-99 stays
foreign; positive cross-host matches from derived populations still win.
RW-3 runner_capacity_realize's reapply predicate answers false rather than deriving zero
additions from a population it could not derive; build_cache_endpoint_observe carries the
width cause into OwnerContextUndecided instead of discarding and re-describing it; the
panel's withdrawn line reports the amount as unestablished rather than disappearing when
an unresolved host contributes zero to both totals.
RW-4 The launch-environment control now requires the CONCRETE slot population to be
derived and nonempty before the template is added (the template was supplying the
nonemptiness). The -1 and *_or_zero adapters are gone: a row that needs a live derived
width matches the resolution and fails on unresolved, and the two srv2 rows in
fleet_show_effective_read are re-derived -- srv2 declares no width, so they assert that
and keep the comparison coverage by supplying the expectation. The #11708 tripwire and
the root srv2 witness now require the reservation policy's own sentence to survive into
the rendered refusal.
ORDER CORRECTION IN ci_runner_placement: the width resolves AFTER the session slice and
BEFORE the conservation wall. Resolving it first refused srv2 with the derived cause and
left SessionReservationUnestablished with no production producer.
Ledger: gunbc.recurring_failure_mode.state_space_conflation gains RUNNER-WIDTH-1 --
a neutral element is as good a conflation as an Option, the count of readers is the count
of wrong answers, and a refusal correct at ONE consumer does not make a sentinel a refusal.
Two witness type errors from dashboard review 68767 (observed_prefix folding the new
coproduct, host_fabric_slot_count compared to an Int) and one drifted annotation from
review 68802 (runner_host_deploy still saying the width authority "answers zero slots for
an unknown host") are fixed.
INSTRUMENT NOTE: --required-regen does NOT compile dag/test/claim -- measured with a
deliberately undefined function in a witness, which it passed. Witness closures are
checked with `gunbc compile --entry <witness> --target dag`, which caught both review
findings, five body-position annotations and two non-exhaustive matches.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
All four source-hold items and both dashboard reviews are addressed in RW-1 — the unresolved obligation now survives the projection, in both of its instances
The cap instance is repaired at its own decision boundary, as asked: The discriminator you asked for is enrolled in the direction that is authorable, and the other half is stated rather than implied. srv4's derived target yields its real prior-minus-target obligation ( RW-2 — the cross-host mislabel is gone
RW-3 — all three
RW-4 — the three false-positive paths
One order correction you did not ask for, reported because it changes a refusalResolving the width at the top of Reviews 68767 and 68802Both correct, both fixed: Ledger
Evidence, and a measured instrument boundary worth passing on
One unplanned receipt: CI's auto-heal regenerated — sent from snappy-crab-140 |
Correction to my own evidence claim in this PRMy PR body and my reply above both said witness execution is CI's. That is false, and I measured it rather than assuming it.
The fourth check, So no
I am stating this rather than letting the earlier sentence stand, because the whole subject of this change is a value that read as an answer when nothing had been asked, and "CI runs the witnesses" would be the same defect in my own evidence. Two things follow that are not mine to decide. DESIGN.md §Building & checks still describes — sent from snappy-crab-140 |
Ledger-Repair-Judged: docs/design-rung-drops.md Ledger-Rows-Repaired: docs/design-rung-drops.md namespace_wave_admission_wall_removed Heal-Candidate-Run: 35485937836
…discriminate
Addresses the second source hold on this PR. RW-2 and RW-3 were discharged; these
are the four remaining items plus the PR body correction.
THE REFUSAL SCRIPTS ARE BUILT AS COMMANDS, NOT CONCATENATED AS TEXT. The unresolved
arm this change added to obligation_withheld_scripts spelled `echo '<message>' >&2`
by joining strings, with the diagnostic interpolated INSIDE the opening quote -- and
the fixed text "this host's retirement obligation" alone terminated the quoted
argument, so /bin/bash -n and /bin/sh -n both refuse the projected script with an
unterminated-quote error. The cause is DATA from gunbc.session_reservation_policy,
whose sentences are prose, so this is the injection shape regardless of today's
string. Both new renderers now go through gunbc.shell_command_text: the message is a
WORD (POSIX single-quote is the serializer's structural job), the stderr redirection
is the modeled ^bash_production_fold_redir_stdout_to_stderr, and the deploy refusal's
exit is bash_build_exit.
The three renderers that were ALREADY hand-spelled in runner_slot_provision go with
them. They carry the same defect for the same reason, and leaving them beside a
serialized sibling would be the second spelling DESIGN 3 forbids.
THE UNRESOLVED ARMS NOW HAVE DISCRIMINATING CONTROLS, supplied rather than waited
for. transition_required_retirees_at takes the target width, and
transition_population_agreement_over takes the obligation; the production wrappers
read them from the authority and are asserted separately as the real path -- the same
separation fleet_capacity_withdrawn_line_over already uses. The previous control was
vacuous: `obligation_is_unresolved(srv2) == false || match ...` was TRUE because srv2
has no transition row, so the assertion held whatever the decision answered.
AND THE ANNOTATION THAT DEFENDED IT WAS WRONG. It claimed the type prevented the arm
being reintroduced as an empty list. `RunnerWidthUnresolved { cause: _ } =>
RetireesKnown { units: [] }` is well-typed: a coproduct makes the distinction
expressible, only a control establishes that the producer chose the right arm.
TWO STALE SPECIMENS CORRECTED. a_surplus_inside_the_manifest_agrees supplied
srv4-13, which was inside the manifest when srv4's obligation ran 13..21; at the
26/25 GiB width the requirement is 18..21, so the row asserted agreement against a
decision that correctly disagrees. It now reads the first member of the live
obligation, so it stays inside the manifest at any width and fails if the obligation
stops resolving. The recorded interruption authorization is NOT edited to match:
permission to interrupt and an obligation to retire are different facts.
host_allocation_conservation's live_runner_pool_for is deleted. It mapped an
unresolved width to byte_size(0) and fed that to the conservation arithmetic, where a
zero runner charge makes conservation EASIER to satisfy -- the same substitution the
production code stopped making, reappearing in the test that checks it. The row now
supplies a deliberate fixture charge and consults no live width.
PR BODY CORRECTED: it said the executed evidence is "CI's floor run". No .dag witness
executes in CI on any trigger; the body now states what is closed by typecheck and
that no assertion in the diff has been executed anywhere.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
docs/design-rung-drops.md is a projection of gunbc.rung_drop and this branch authors no rung-drop row, so the conflict resolves to main's regeneration; the drift gate re-derives it if that is stale.
Review 68966 (non-blocking, correct): the change minted runner_slot_instance_name_prefix as the single authority for the PREFIX and then forked the RELATION over it -- starts_with in fleet_runner_connectivity, string_contains in fabric_cell_observe. One concept, two implementations, and they disagree observably: `backup-srv2-01` was a candidate under contains and not under starts_with. Both drift toward refusal so nothing failed open, but a fork gets consolidated later at interest (DESIGN 3). gunbc.build_cache_instance slot_name_could_belong_to_host is that relation, beside the prefix it reads, with the fail-closed direction stated: a true answer says the name COULD belong to that host, never that it does. THE RENDERING DIFFERENCE THAT MOTIVATED `contains` IS HANDLED WHERE IT BELONGS. A registration is named `srv2-01`; a fabric cell slice is named `fabric-cell-srv2-01.slice`. The caller renders the host prefix the way ITS names are rendered and the comparison stays one function, so the slice case compares against `fabric-cell-srv2-` rather than searching for `srv2-` anywhere in the string. That required spelling the slice lead once: fabric_cell_slice_name_prefix and fabric_cell_slice_name now both read fabric_cell_slice_name_lead, so the observer cannot render a prefix that drifts from the name the converger builds. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Second correction on the same subject, and the last one: the witnesses execute now, and they passI said earlier in this PR that no CI evaluates the merge ref, so this PR gets that job even though my branch's own copy of So the evidence line for this PR is now: executed, on the merge ref, green. Not "typecheck only", and not the "CI's floor run" I claimed before measuring. I have corrected the PR body rather than leaving either version standing in it. One earlier red on this PR is also worth attributing correctly: the floor job failed on head Review 68966Its one finding is correct and is fixed in The rendering difference that motivated — sent from snappy-crab-140 |
Review 68988 (non-blocking, correct, and both findings are this change failing its own stated rule): fabric_cell_fleet_population was a wrapper whose body was exactly the imported symbol -- a second name for one concept, which is what this PR deleted gunbc_runner_pool_budget_for for. The call site reads fleet_committed_slot_identities directly and the prose moves with it. fleet_hosts was left imported with no consumer once its fold was deleted in this diff, and FleetCommittedSlotPopulation was imported only to annotate the wrapper's return. Both are gone (DESIGN 3c: a declaration with no call site in the closure). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ivable obligation Review 69018 found a production call site the cutover missed, and it is the one that matters most: runner_host_file_converge builds the subject whose retired_units is what this module TELLS A HOST TO TEAR DOWN. It still wrote required_retirees_for_host(host: host) into a List<NonEmptyStr> field, so on a host whose committed width does not resolve it would have converged the files against "nothing is retiring" -- the silence this change removes everywhere else, surviving in the module that decides teardown. The constructor is already an admission with a refusal arm, so the obligation joins the two conditions it already refuses on: no deploy row, and no desired slot. WHY THE CENSUS MISSED IT, since that is the part worth not repeating: this module arrived from main in a merge AFTER I enumerated the consumers of required_retirees_for_host, and a signature migration's census is only valid against the tree it was taken on. I re-ran the census over every symbol this change retypes, against the current tree: this was the only production miss. One dangling import is removed with it (gunbc.live_deploy.emit imported runner_slot_service_units_for_host and never called it). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Review 69018's finding is correct and is fixed in
Why the census missed it, since that is the part worth not repeating. I did enumerate the consumers of So I re-ran it against the current tree, over every symbol this change retypes — On your framing of the alternative: it is the first arm, not the second. — sent from snappy-crab-140 |
…retiring The #11762 resolution replaced the function body in place and left the old closing brace behind, so the module index refused with one unparseable source at runner_slot_retirement.dag:31175 and every witness importing it returned no verdicts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
review 69200 is right: git grep returns only the definition line. The fold's consumer was zero_width_cause, which this branch deleted in the #11762 merge when the zero-width arm adopted main's causeless variant -- main refuses an unresolved width one link earlier, so a zero reaching that arm genuinely means zero and has no cause to render. The fold should have gone with its consumer and did not. Its annotation asserted the opposite ("this fold is the seam that carries them out"), which is the same 4b(1) inflation review 69079 caught in this file, so the note is deleted rather than reworded. What the fold was for is now a stated frontier at admit_or_refuse_zero_width with its trigger named: the rendering seam returns when MemoryDenominatorStanding keys on the envelope resolution rather than on session_reservation_bytes alone, and not before. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…le's resolve after #11762 Side-chat changes on #11842: the argv claim keeps only its own subject (length(retired) > 0, the argv literal, portable_remote_words admission); every_desired_srv1_unit_is_outside_the_retirement_manifest plants the whole desired roster beside the real retirees and requires transition_population_agreement to name exactly the desired roster. Also repairs main: #11762 deleted gunbc_runner_slots_per_host while #11800 added it as an import here, so every claim in this file refused to resolve. srv1_width() now reads gunbc_runner_committed_width (Int?; the unresolved arm yields an empty listing, and the two pure-refusal consumers gain a length > 0 conjunct so an empty listing cannot pass vacuously). The new TransitionPopulationUndecidable arm closes to false. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…#11762, #11740) runner_host_file_converge_witness_test imported gunbc_runner_slots_per_host, deleted by #11762 in favour of the RunnerWidthResolution answer; the test's srv1 boundary reads the per-axis derivation gunbc_derived_runner_slots_per_host, whose Int is srv1's committed width because srv1's reservation is the established one (a fabricated 0 for the unresolved arm is refused). v2.lens.reference_derived_residency_reading (#11740) declared no construction_justification; it is a second reader of a declaration the residency qualification could consume directly, so WallAfterGrounding { dissolves_to: SingleAuthority }. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The authorability sentence cited gunbc_runner_slots_per_host and transition_required_retirees, both superseded by #11762; it now names transition_required_retirees_at and the slot: target + 1 range start the evidence run actually mutated. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rt home review 69306, both correctness rather than doctrine. ZeroRunnerWidth is nullary on this head -- the module reverted to main's causeless variant during the #11762 merge and this fixture did not, so it still constructed it with a cause field that no declaration carries. The annotation eight lines from the declaration says the arm is "honestly bare"; the witness contradicted it. RunnerSlotIdentity was imported from gunbc.runner_slot_allocation, which does not declare it. Its one home is gunbc.build_cache_instance, which is what every other consumer cites -- an import is reachability, not re-export. Imported from the declaring module. I checked the rest of the imports this branch added against their declaring modules; the other seven are correct. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…where Third instance of the same class review 69306 named: residue from the #11762 hand-merge. main deleted the held-width arm with the Int width API on 2026-09-12 and dropped the name from this import block; my resolution of that block took the union and kept it. The only other mention is the annotation recording the deletion, which is correct as written. Found by scanning every import this branch touched against its declaring module rather than by waiting for the next review. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…oted review 69341. The note said "NO WIDTH FIGURE IS QUOTED HERE ON PURPOSE" and then quoted two -- a derived width of 12 and CPU as the binding axis -- both falsified by the 2026-09-19 cores_per_slot ruling that this file's own authority row records and that the allocation witness executes (committed == host_memory_admitted_width on srv1/srv3/srv4). Correcting a transcribed number by transcribing two more is the failure DESIGN 6 names, performed inside the sentence warning against it. The figures are gone. The pointer is repointed too: the note sent readers to gunbc_runner_slots_per_host, which #11762 deleted, so the instruction named a symbol that no longer resolves. It now names gunbc_runner_committed_width, which refuses rather than answering for a host whose inputs are unestablished. Swept the rest of this branch's prose for the same stale pointer; every other mention is past-tense history and correct as written. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…#11762, #11740) runner_host_file_converge_witness_test imported gunbc_runner_slots_per_host, deleted by #11762 in favour of the RunnerWidthResolution answer; the test's srv1 boundary reads the per-axis derivation gunbc_derived_runner_slots_per_host, whose Int is srv1's committed width because srv1's reservation is the established one (a fabricated 0 for the unresolved arm is refused). v2.lens.reference_derived_residency_reading (#11740) declared no construction_justification; it is a second reader of a declaration the residency qualification could consume directly, so WallAfterGrounding { dissolves_to: SingleAuthority }. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit 43b4697)
…d-red, with their cause and trigger, so the sealed floor adjudicates instead of greening over them Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
What this is
gunbc.runner_slot_allocationgunbc_runner_slots_per_hostis deleted. The canonical committed-width answer isgunbc_runner_committed_width -> RunnerWidthResolution(RunnerWidthDerived { slots }|RunnerWidthUnresolved { cause }), and every production call site carries or refuses the cause instead of reading anInt.That Int's own note declared this gap on 2026-09-19 and named this type as its capability trigger, adding that landing half of it would mint one silent default per un-migrated site. So it lands in one motion: 22 production call sites across 13 modules, plus the carriers downstream of them.
Why now — the conflation stopped being latent
Chain, re-derived from the root rather than from the symptom:
host_runner_memory_envelope_bytes→ 0 for srv2 (session reservation unestablished) →host_memory_admitted_width0 → width 0 → srv2 contributes no members tofleet_committed_slot_identities→decode_registration_slotanswersRegistrationNamesNoCommittedSlotfor every srv2 registration →accumulate_decoded_registration→GitHubSlotPopulationForeignRegistration→plan_runner_capacity_hostrefuses with "resolves to no committed fleet slot".That fold runs over the whole org roster for every host it plans, and it is not filtered by host. The live roster read landed in #11711, and the 2026-09-19 org read (runs 35450620333, 35458738938) shows srv2-02 (251463) and srv2-05 (251484) present. So every host's plan — srv1, srv3, srv4 included — refused, citing a sentence that is true about the derivation and false about the fleet: a registration on a host whose width does not resolve is not established as surplus.
What changed, by carrier
Each of these could previously say only "empty", which reads as a positive claim:
committed_slot_identitiesCommittedSlotPopulation= Derived |CommittedPopulationWidthUnresolvedRunnerSlotMembershipSlotMembershipWidthUnresolvedRegistrationSlotDecodingRegistrationHostWidthUnresolved { registration_name, host, cause }ObservedGitHubSlotPopulationGitHubSlotPopulationHostWidthUnresolvedFabricCellDiscoveredSubjectDiscoveredHostWidthUnresolvedRunnerSlotEnumerationPostconditionRunnerSlotEnumerationWidthUnresolvedhost_converge_slice1cross-checkHostConvergeSlice1EnumerationCrossCheck(3 states, was anOption)gunbc_committed_host_runner_slot_allocationHostRunnerSlotAllocationStanding— srv2 has no allocation row at allfleet_committed_slot_identitiesunresolved_hostsbeside its membersfleet_committed_slot_total(panel)unresolved_hosts; renders "(incomplete: srv2 unresolved)"HostRunnerDeploymentRefusal(placement)CommittedWidthUnresolved { cause }runner_slot_lifecycle_forRunnerSlotLifecycle?— the caller already hadOwnerContextUndecidedThe most dangerous one was the census: with an empty desired set every running unit classifies as
RetiringSlot, so a host whose width did not resolve would have been converged to zero runners by a fold that never saw anything wrong. It now REFUSES.The two constraints from the side chat, and where they are met
PlanReadyfor that roster.RosterObservedPartialtakes for a page that fails. A missing allocation answer becomes neither an empty population nor an instruction to delete.Two nicknames dissolve with it (DESIGN §3)
gunbc.fleet_host_budgetgunbc_runner_pool_budget_forwasgunbc_runner_slice_cap_declared(host: host)and nothing else — one concept, two names, and it was the name the conservation wall read, so the wall and the deploy row reached the width by two routes kept agreeing by hand. Both are replaced bygunbc_runner_slice_cap_for_width(slots), which takes the width its caller already resolved.fleet_desired_width_totalis deleted: it had no consumer (§3c).One climb: the allocation wall's
a.slots_per_host > 0 || !host_memory_width_is_established(host: a.host)disjunct is gone. It was validation re-stating, per row, the condition under which the row should not exist; the refused host now has no row, so the conjunct is just> 0and the discriminating red is unchanged.Witnesses re-derived, and three were already stale
the_whole_org_corpus_is_refused_while_srv2_holds_unaccounted_registrations(#11708, in the required gate) is re-derived rather than weakened: it still requires a refusal naming srv2-01, and now also requires the refusal to name the host and cause and not to say "resolves to no committed fleet slot". Red in both directions.Three rows were asserting literals the fleet had left behind, each re-stated as the relation it was for:
witness_srv3_srv4_committed_width_agrees_with_the_derivationpinned 21 on all four conjuncts; the 26/25 GiB row commits 17.srv4_commits_memory_width_disk_gated_at_applypinned memory admission 29 and committed 21; both are 17.srv1_is_axis_bound_while_srv2_is_heldpinned "bound by cores"; the 2026-09-19 one-core-per-slot ruling put srv1 back on memory.The held-width row is deleted with its subject (
host_held_runner_widthhad one arm returningnone, so its red was unauthorable — DESIGN §4b) and replaced by one asserting srv2's width comes back UNRESOLVED naming its denominator.runner_slot_allocation_unknown_host_refuses_a_widthasserted== 0and called that a refusal — the conflation written down as the expected answer; an unknown host now yields a cause.Evidence, and its boundary
claim_executor --required-regen --source-root dag --source-root src/v2, run locally on this tree after merging main: compile.frontend / normalize / reconcile / analyses green, zero diagnostics. Declarations, names and types resolve across all 35 changed files.std/extdepsfiles this change never touches, fixed by the.first()-Optional work that landed in the meantime. Merged main; they are gone.gunbc compile --source-root dag --source-root src/v2 --entry <witness> --target dag, which is the only instrument that readsdag/test/claimat all.--required-regendoes not compile it — measured with a deliberately undefined function planted in a witness, which it passed. The compile-per-closure caught two type errors a reviewer also found, five body-position annotations and two non-exhaustive matches.0dd2892),.github/workflows/witnesses.ymlhad three jobs —compiler(acargo build),clippy, and a 3-second job namedwitnessesthat was an aggregator over those two and ran no witness — so I wrote that no assertion in this diff had been executed anywhere. gunbc#11791 landed afloorjob on main at 05:18 that runsclaim_executor --required-ci --source-root dag --source-root src/v2 --required-lane witnesses, and because CI evaluates the merge ref this PR gets it even though my branch's own copy of the workflow predates it. On head710cedcthat job passes, itsNominal witnesses (one prepared subject, one fold)step succeeds, and itsjudged-module-identitiesroster includes six modules this change rewrites:gunbc.runner_slot_allocation,gunbc.ci_runner_placement,gunbc.fleet_capacity_panel,gunbc.fleet_host_budget,gunbc.fleet_runner_connectivity,gunbc.runner_lifecycle. So the claim in this bullet's earlier version — first that CI executed the witnesses, then that nothing did — is replaced by the measurement: it did not, then the gate landed, and now it does and is green.Finding reported separately to deep-owl-720: the mislabel is a semantic loss, not a string, and the fix belonged at the width authority rather than at
runner_capacity_plan's refusal text (DESIGN §6b: the symptom link is not the earliest unjustified boundary).🤖 Generated with Claude Code