Repository navigation
Conversation
…threaded through the plan/apply spine The one fabric execution slot in the fleet -- srv3-06 -- is declared in gunbc.runner_slot_allocation and could not be converged: gunbc.runner_lifecycle refuses it, because a fabric cell is not a GitHub runner with pieces removed, and nothing else answered for it. This lands the family that does, and threads it through fleet converge so it is a fact the spine carries rather than a model nothing consumes. TWO HALVES, ONE PR, BECAUSE EITHER ALONE IS ANOTHER UNCONSUMED MODEL. A family with no spine integration is a model nothing reads; a spine population with no family has nothing to put in it. WHAT THE MEMBER GRAIN IS, AND WHY NOT A CELL-WIDE DIGEST. Three resource addresses -- cell root, attempt-state root, resource boundary -- following the Spark serving family rather than inventing a second shape beside it. One digest over the whole cell produces a wrong REMEDY, not merely a coarse report: a drifted cgroup and a missing directory would hash differently and both select "provision the cell", so a host needing only its limits reapplied pays for a full installation. The boundary's desired digest CONSUMES gunbc_runner_slot_desired rather than re-spelling it, so a change to the fleet's per-slot row surfaces as MemberChanged at exactly one address. runner_lifecycle KEEPS REFUSING, AND THAT IS DELIBERATE. Its fabric arm is renamed FabricSlotHasNoGitHubAddSequence -- the old name asserted that fabric provisioning was unmodeled, which this change falsifies -- but it stays a refusal. A sibling family here PLUS a success arm there would be two provisioning authorities for one cell: the single-authority violation arrived at by addition rather than by nicknaming, which is the harder form to see because neither half looks like a duplicate alone. THE OBSERVED SIDE IS A TYPED POPULATION, NOT A LIST, AND THAT IS THE LOAD-BEARING CHOICE. The sibling families take List<Member>, so a caller with no observer passes [] and reconcile reads it as "the host has none of these" and answers with a full install plan. For a family whose resources are a cgroup and two directories that is the empty-observation narrow with real consequences: a host nobody read is planned as a host with nothing on it. FabricCellPopulation makes unread and empty different values; the refused arm contributes its OWN baseline row, so the two hash differently and a plan approved under one cannot admit under the other. No observer exists yet, so the CLI passes the typed refusal -- which stops the family at the plan boundary, renders a line the reviewer sees, and is counted beside the other families' refusal counts. A degradation nobody counts is one nobody ranks for fixing. CONTRADICTION REFUSES RATHER THAN RESOLVING BY ORDER. Every observation of an address is folded and any doubt dominates: refusal beats contradiction beats absence beats presence. A first-match fold would let a favourable observation win by arriving first, and the witness fixture authors the favourable observation FIRST precisely so that implementation would go green on it. WHAT THIS DELIBERATELY DOES NOT CLAIM. "Substrate provisioned" means the root, the attempt root and the boundary exist as declared. It does NOT mean an executor is ready: there is no fabric agent in this tree, no executable entry, and nothing that could observe one running. An earlier revision of this module enumerated an agent service identity, a control-plane binding, materialization endpoints and a supervised-dormant agent as provisioning steps; naming them would have made "provisioned" mean "an executor is ready" while the only establishable facts are a directory, a directory and a cgroup -- the rung inflation DESIGN 4b calls worse than sitting low, because an inflated claim never ranks for climbing. They are removed with a named trigger, not abbreviated. No SupplierOffer, no Demand, no Attempt, no ExecutionGrant, no process start, and the apply shell emits the resolved membership as COMMENTS rather than host effects -- derived from the same typed resolution the reviewer read, so the realization replaces a projection that already had to be correct. GREEN BY EXECUTION, 15 of 15 new rows, this tree: 11 fabric cell model rows (dag/test/claim/fabric_cell_converge_witness_test.dag) 4 spine acceptance controls (dag/test/claim/fleet_converge_plan_witness_test.dag) The load-bearing one is witness_fabric_cell_population_moves_the_member_set_fingerprint: a converged population and an empty one produce DIFFERENT member-set fingerprints, and the same population produces the same one. It is also the mutation control for the threading -- delete the fabric rows from observed_baseline_text and it goes red, because the two populations then differ in nothing the fingerprint reads. Compile: 0 blocking diagnostics; the only advisories naming these files are the standard where-refinement-unenforced class every `as NonEmptyStr` cast produces. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…e narrow, the unrealizable plan, the refusal baseline review 55284 and a product-direction review found five real problems in the first head. None were style; two were live fail-opens, one was latent on the next change, one falsified an extension claim this module makes about itself, and one was a fingerprint collision. Each is fixed where it originates rather than patched at the call site, and each carries a discriminating row. 1. THE FOLD TOOK THE FIRST OBSERVED MEMBER AND CALLED IT AGREEMENT. first_observed_member returned the first AddressObserved and never compared the rest, so two attesters reporting different digests for one address resolved to whichever arrived first -- sitting directly underneath an annotation asserting that presence requires every observation to agree. One ordering yielded Provisioned and the reverse yielded Unprovisioned on the same readback. The witness did not catch it because its contradiction fixture paired an observation with an ABSENCE, which was always caught; the conflicting-POSITIVE case had no row, and it is the likelier readback of the two -- a stale reader and a fresh one both see the resource and disagree about its value. Agreement is now computed through a typed ObservedDigestAgreement where one disagreement collapses to Conflict permanently. 2. FOUR BOOLEAN PREDICATES IN THE AUTHORITY. disposition_is_present, disposition_blocks_verdict, disposition_member and fabric_cell_address_matches_desired each matched the whole disposition coproduct and answered a Bool or a list. That is the predicate-dissolution shape, and it is the rule I invoked defending gunbc#9069 -- where the predicate sits in a WITNESS and the authority carries none. These were authority-side, so the objection lands here. They are replaced by one descent, FabricCellAddressStanding, with three named outcomes; a new disposition arm now fails to compile in one place instead of silently inheriting whichever Bool three separate matches gave it. 3. AN UNOBSERVED ADDRESS COUNTED AS AN ABSENT ONE. AddressUnobserved mapped to the non-blocking standing, so a readback holding NO observations produced FabricCellPopulationObserved with an empty member list -- and reconcile reads an empty observed population as "the host has none of these" and answers with three ADDs. The typed population closed the empty-observation narrow at the caller and this reopened it one layer in. MissingOnHost and Unobserved are now on opposite sides: one is an observation that the resource is absent, which reconcile may act on; the other is the absence of an observation, which is not a fact about the host at all. THE VERDICT MOVED WITH IT and a witness that encoded the wrong answer is corrected: an empty readback reports ObservationRefused, not Unprovisioned. The distinction I was protecting -- our evidence versus the host refusing -- is real and survives in the DISPOSITION, where AddressUnobserved and AddressUnreadable stay separate arms with different remedies. It does not belong in the verdict, because both are the same answer to the question the verdict asks. Unprovisioned was a claim about a host nobody looked at. 4. A PLAN WITH WORK DUE AND NO REALIZER REPORTED ZERO REFUSALS. An observed-empty population produced three MemberAdded actions, three ADD lines, a zero refusal count, and an apply shell that emits them as comments: "three additions due, zero refusals, zero host effects, apply completes" -- work reported as due against a plan that will not do it. Latent only because the CLI has no observer; landing one would have turned it live on the first honest empty read. The family has a third arm, FabricCellFamilyRealizationUnavailable, carrying the actions it refused to realize. Each renders REFUSED-REALIZATION and counts as one refusal, because the deficit is per unit of work owed. It is an arm rather than a check, so the converged-looking-but-unrealizable state has no spelling. 5. THE REFUSAL BASELINE WAS ONE ROW. A single fabric-cell-observation-refused line made two hosts blocked for different reasons at different addresses hash identically, so a plan approved while the cgroup was unreadable would admit later while the attempt root was unreadable instead. Each blocked disposition now contributes a row naming its slot-qualified address and cause. Same class as finding 3, one layer out: an observation that cannot express what it saw, rendered as a verdict. ALSO, FROM THE SAME REVIEW: the population is host-scoped, matching the host-scoped desired side, instead of carrying one CellId that its observed arm ignored and its unobserved constructor filled with a synthetic "fabric-cell-population" identity naming nothing. Dispositions carry a slot-qualified FabricCellAddressRef, so "resource-boundary unreadable" can say WHICH cell -- which makes this module's extension claim true rather than aspirational: a second fabric identity now reaches the blocked path named. VERDICT ON THE TYPED POPULATION, since it was the one thing I flagged as a deliberate deviation: keep it, do not match the sibling List<Member> signatures. A bare list cannot distinguish "the observer proved there are no members" from "no usable observation was produced", and spark and slots should move toward this shape rather than pulling fabric back into their ambiguity. GREEN BY EXECUTION, 13 of 13 model rows on the settled tree, including the three new discriminators: conflicting-positive observations contradict (the favourable reading authored FIRST, so a first-match implementation goes green and only a comparing fold goes red); agreeing duplicates stay present (without which the fix could be "any second observation contradicts", turning a redundant probe into an outage); empty readback refuses. Compile: 0 blocking diagnostics. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…th it
review 55308 found fabric_cell_ids defined at 549 and 591 and
fabric_cell_population_unobserved at 580 and 608 -- an append that never deleted
what it replaced. The trailing block is removed, one definition each remains,
and the observer-refusal cause is back to a single authority.
THE REVIEW'S ONE UNVERIFIED INFERENCE IS THE INTERESTING PART, AND IT IS WRONG
IN THE DIRECTION THAT MATTERS. It says "this will fail to parse/typecheck". It
does not. Measured on a standalone two-function module through our own binary:
fn which_one() -> Bool { false } <- first
fn which_one() -> Bool { true } <- second
=> PASS (returned true: the SECOND definition bound)
control, order swapped:
fn which_one() -> Bool { true } <- first
fn which_one() -> Bool { false } <- second
=> FAIL (returned false: the SECOND definition bound)
The result flips with the order, so it is not a constant and not a harness
artifact. Silent last-definition-wins for module-local functions: no refusal, no
diagnostic, no advisory.
WHICH COPY WAS LIVE, AND IT WAS THE BAD ONE. Last-wins means the second
definition bound -- the copy inlining the cause string, not the one consuming the
fabric_cell_no_observer_cause data row. The parallel-representation violation
riding on top of the redefinition was executing rather than latent, and every
caller was getting the copy this module's own annotations argue against.
WHY THE VERIFICATION MISSED IT, SAID PLAINLY. The compile was not skipped and did
not predate the duplicating edit: it ran on exactly that tree, after every edit,
and reported zero blocking errors with 880 advisories, and grepping its log for
duplicate/redefin/already-defined/shadow returns nothing. So "compile: 0 blocking
diagnostics" was a true quotation and worthless as evidence -- the compiler's
silence was cited as support for a property the compiler does not check. That is
the failure this very module's annotations describe: total at the level examined,
blind one level below. The check that would have caught it is the one that found
it, a grep for two definitions of one name, and it is now what this commit's
verification rests on rather than the compile.
CLASS, NOT FILED HERE ON PURPOSE: this is the shape DESIGN records for imports --
a census-ambiguous name resolving by silent last-import-wins instead of refusing
-- one layer down at module-local function definitions, found in production
rather than in a fixture, and below the ordinary compiler floor DESIGN names
first. The gap analysis entry deserves its own change with the fixture enrolled
as evidence, not a paragraph smuggled into a fabric cut.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…that let a member disagree with its own slot The runner_lifecycle annotation named gunbc.fabric_cell_converge fabric_cell_provision_sequence_for as the fabric slot's provisioning sequence. That symbol does not exist: the same PR deleted the step vocabulary and replaced it with a membership model, so the annotation described the shape the work started from. Its next-rung trigger was wrong the same way — it named a desired population that the host-exact fold already satisfies, which would have marked the row done while both real gaps stayed open. FabricCellMember carried host beside slot, and RunnerSlotIdentity already contains the host, so member.host = srv4 beside member.slot.host = srv3 was representable. Derived rather than stored: unrepresentable, not validated. observation_targets compared two rendered instance names; the identity authority is runner_slot_identity_equal.
…answer for a host The population was host-scoped in name and produced by a constructor that evaluated ONE slot's three addresses. Correct only while srv3 declares exactly one fabric cell; the moment it declares two, the second cell's resources are unobserved and a host-scoped population reports them ABSENT, so reconcile plans them against a host nobody read. Sealing that constructor would have made the single-cell assumption the sanctioned path. So: FabricCellHostReadback carries one entry per cell read, and completeness is decided against fabric_execution_slot_identities rather than against what the caller supplied. Only then is the member list sealed behind a sole_constructor carrier, so observed-empty cannot be asserted by literal. Two identities that could disagree are gone with it: FabricCellReadback carried a CellId beside the slot every interpreter took separately, and FabricCellMember carried the ownership that licenses its own teardown.
|
HOLD — do not merge during the #9102 → #8282 window. Computed against #8282's changed-file set: this PR intersects it on 6 file(s), including:
Under the operator's #9059 ruling — "not a category judgment about emission work; it is a direct subject-overlap constraint" — an intersecting PR must not land between the prerequisite (#9102) and the cut cohort (#8282): it alters the cut's conflict set and invalidates its prepared subject. Nothing is wrong with this change and its approvals stand. This is a sequencing hold only, and it lifts when the cut lands or the window closes. Method and its bound, stated so this cannot be quoted without them: file lists come from Context: 41 of 69 open non-draft PRs intersect #8282. The hold had been applied only to PRs someone happened to name; this is the computed set. Two of us have already been caught not applying it to our own PRs. — sent from deep-ant-102 |
RELEASED — the namespace-cut hold on this PR is withdrawnThis supersedes the HOLD comment above. Normal merge policy resumes for this PR. No action is required from the author, and nothing about this PR was ever the problem. Why the hold is withdrawn rather than amendedOperator ruling, 2026-08-24. Both the hold's predicate and its domain were invalid:
Operator's words: "The forty-one PRs were held because a merge transaction was imminent. That transaction no longer exists. The possibility of a future transaction is not a present hold." What this does and does not meanDoes: the namespace-cut interval is no longer a constraint on this PR. Does not: mean this PR must merge. Ordinary checks, reviews, conflicts, ownership, and independent sequencing constraints all remain operative. #8282 itself remains excluded and stays draft. If this PR touches
|
|
Superseded by #9122 and closed. Main advanced past this branch (#9070 landed and pulled a link out from under the stack), which put all three of #9081, #9105 and #9109 into CONFLICT simultaneously. Rather than resolve the same conflict three times in order, the whole stack is consolidated onto one branch off current main. Nothing is lost: all three heads are ancestors of Closing rather than leaving open, because a conflicting PR carrying an approval for work that has moved elsewhere is a decoy — the approvals here are already dead, since the heads moved. — sent from silent-bear-842 |
Stacked on #9081 (branched from
8c4520bce9), so the diff shows that PR's commits until it merges. This PR is the last commit only.What this closes, and one thing it deliberately does not do first
A side-chat review of #9081 flagged that
FabricCellPopulationObservedis publicly constructible — the type names the distinction between "the host was read and holds nothing" and "no usable observation was produced" without controlling who may assert it. The spine witness in fact asserted observed-empty by raw literal, with no observation anywhere behind it.The obvious fix is
sole_constructoron the member list. That fix alone would have been wrong, and the same review caught why: the population was host-scoped in name, but produced bywhich evaluates one slot's three addresses and labels the result the observation for the whole host. That is correct only while srv3 declares exactly one fabric cell. The moment it declares two, the second cell's resources are unobserved, a host-scoped population reports them as absent, and reconcile plans them as additions against a host nobody read — the empty-observation narrow reintroduced at cell grain, underneath the very type that exists to prevent it. Sealing that constructor would have made the single-cell assumption the sanctioned construction path.
So the grain is fixed first, then sealed:
FabricCellHostReadback { host, cell_readbacks }is the observation subject, andfabric_cell_populationtakes it alone.fabric_execution_slot_identitiesfiltered to the host ×fabric_cell_resource_addresses. A slot the caller did not read folds to an observation-less readback → every addressAddressUnobserved→StandingBlocked→ the refused arm.FabricCellObservedMembersissole_constructor, minted only by that fold. A cross-module record literal is refused at compile time.The module states the wall's real scope rather than overclaiming it:
sole_constructorconfines who constructs, not what is true of the value (gap analysis item 1a). It is exactly right here because the fold is the module's own fixed law with no caller-supplied predicate — every member came from aStandingSatisfied, and blocked standings divert the whole population before the carrier is reached.Two writable identity pairs deleted with it
FabricCellReadback.cell— aCellIdcarried beside the slot that every interpreting function took separately, with nothing comparing them. A readback branded srv4-06 could carry observations about srv3-06 and return a verdict naming srv4-06. The readback now carriesslot, andCellIdis derived.FabricCellMember.ownership— reconcile consultsfabric_cell_member_ownershipwhen deciding whether an observed extra may be removed, so an observed member authored the fact licensing its own teardown. The namespace is closed (RunnerSlotIdentity × FabricCellResourceAddress, both authority-owned), soOwnedis derived.Evidence
14/14 model rows PASS, including the new one:
It supplies a complete, fully-converged readback for a slot that is not a declared fabric member of the host. The expected subject srv3-06 therefore has no readback, folds to unobserved, and the population must refuse. A fold trusting the supplied list would see one complete cell readback, find nothing blocked, and answer
PopulationObservedwith the real cell silently missing.Mutation receipt — the row is discriminating, not decorative. With
fabric_cell_host_standingstemporarily folding overreadback.cell_readbacksinstead of the expected slots:Restored, it passes. The other 13 rows pass in both trees, which is why this one had to be added rather than relying on them.
What this row does not cover, stated rather than implied: the two-declared-cells case, where one is read and the other is not.
fabric_execution_slot_identitiesdeclares exactly one fabric slot today, so that input is not authorable without adding a second slot to the authority. The guard is reachable and currently unoccupied — a quiet guard, not a dead one — and this row exercises the same mechanism through the one input the authority does admit.The spine witness's
fabric_cells_observed_emptynow builds a real readback of explicitAddressAbsentobservations and runs the production fold, which also delivers the "three explicit absences → observed-empty → exactly three ADDs" control that review asked for. Read-and-empty plans every member; unread plans nothing.Still open after this
Fingerprint under permutation is neither canonicalized by member key nor declared unsupported — the current stability row compares two identically-ordered constructions, which proves determinism rather than permutation-stability. That is the next one, ahead of the observer.
— sent from silent-bear-842