Skip to content

Drift is a CHANGE, not an ADD: split the standing that held two states with opposite remedies - #9159

Merged
briansrls merged 5 commits into
mainfrom
fabric/drift-is-change-not-add
Aug 25, 2026
Merged

briansrls merged 5 commits into
mainfrom
fabric/drift-is-change-not-add

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Repairs a wrong-remedy defect that shipped to main in #9122 with two approvals and a green required floor.

The defect

fabric_cell_address_standing mapped two different physical states to one arm:

  • AddressMissingOnHost → StandingUnmet — the resource is absent
  • AddressPresent with a mismatched digest → StandingUnmet — the resource exists with the wrong value

fabric_cell_population's observed-member fold then kept only StandingSatisfied; its StandingUnmet arm was => acc. So both states produced an identical observed population, membership_reconcile answered MemberAdded for both, and MemberChanged was unreachable for a drifted address.

The model therefore chose CREATE against a resource that already exists, which inverts the entire reason the membership is resource-addressed: missing → ADD/create, present-but-drifted → CHANGE/repair. The distinction was collapsed one step before the fold that exists to consume it.

The annotation directly above the defect already stated the correct intent — "a resource carrying the wrong value, and the remedy is a repair rather than a create." The prose was right and unexecutable; only the fold decided.

Why nothing caught it

The fold was total over FabricCellAddressStanding — every arm matched, no wildcard, no warning. There was no missing case for a reviewer or a lens to see. The distinction that picks the remedy lived inside the arm's disposition, which the fold bound and discarded — and the discarded disposition still carried the member. Two approvals and a green required floor stood behind it simultaneously.

This is the repository's total at the level examined, blind one level down class, and it now has a receipt.

The existing suite had a row for drift — witness_fabric_cell_drifted_digest_is_unprovisioned — and it passed throughout, because "unprovisioned" is true on both sides of the distinction being collapsed.

The repair

State-space split rather than a filter tweak:

StandingSatisfied      { address, member }
StandingObservedDrift  { observed_member, disposition }   // new
StandingExplicitlyAbsent { disposition }                  // new
StandingBlocked        { disposition }

Observed members are Satisfied plus ObservedDrift, excluding only explicit absence. The collapsed form now has no spelling: a fold that wants to drop absent members must name the drift arm to drop it too, so it fails to compile here rather than being tested against.

Witnesses assert the ACTION KIND, in both directions

A row asserting only "unprovisioned" passes on both sides of the very distinction being repaired. Each new row therefore names the action it requires and the action it forbids for the same address:

  • witness_fabric_cell_drifted_address_plans_change_and_never_add — exactly one CHANGE, zero ADD
  • witness_fabric_cell_absent_address_plans_add_and_never_change — exactly one ADD, zero CHANGE
  • witness_fabric_cell_drifted_and_absent_are_different_observations — pins the divergence at the population the reconcile consumes, one layer below the rendering

The fixture drifts one address and leaves the other two agreeing, so the rows prove something about that address rather than about a wholesale mismatch.

Mutation receipt

Reintroducing the defect (drift arm back to => acc, split type kept):

FAIL witness_fabric_cell_drifted_address_plans_change_and_never_add
PASS witness_fabric_cell_absent_address_plans_add_and_never_change

The drift row goes red; the absent row stays green as the control proving the mutation is narrow rather than breaking the fixture wholesale. Restored → both green. The rows' green is caused by the repair, not coincident with it.

Test plan

  • 3 new rows: PASS. Mutation: drift row RED, absent row green. Restored: PASS.
  • Existing rows most exposed to the change — witness_fabric_cell_converged_population_plans_nothing, witness_fabric_cell_refusal_is_rendered_and_counted_not_silent: PASS.
  • Model suite spot-check — family_is_exactly_the_declared_member, converged_readback_is_provisioned, drifted_digest_is_unprovisioned, absent_address_is_unprovisioned_not_refused, empty_readback_is_observation_refused, unreadable_address_refuses_rather_than_reading_as_absent: all PASS.
  • gunbc compile --entry dag/gunbc/fabric_cell_converge.dag: 0 blocking, 672 advisory.
  • Not claimed: a full fleet_converge_plan entry compile — it exceeded a 1200s local timeout (exit=124), which is an unfinished measurement, not a pass. The witness runs interpret that closure end to end.

🤖 Generated with Claude Code

Brian Searls and others added 4 commits August 25, 2026 02:32
…s with opposite remedies

A resource that is MISSING and a resource that is PRESENT WITH THE WRONG VALUE
both mapped to StandingUnmet, and the observed-member fold kept only
StandingSatisfied. So both produced an identical observed population,
membership_reconcile answered MemberAdded for both, and MemberChanged was
unreachable for a drifted address -- the model chose CREATE against a resource
that already existed, inverting the reason the membership is resource-addressed.

The annotation directly above the defect already stated the correct intent ("a
resource carrying the wrong value, and the remedy is a repair rather than a
create"). The prose was right and unexecutable; only the fold decided.

Split into StandingObservedDrift { observed_member, disposition } and
StandingExplicitlyAbsent { disposition }; observed members are Satisfied plus
ObservedDrift, excluding only explicit absence. The collapsed form now has no
spelling: a fold that drops absent members must NAME the drift arm to drop it
too, so it fails to compile rather than being tested against.

Witnesses assert the ACTION KIND in both directions -- drifted gives exactly
one CHANGE and zero ADD for that address, absent gives exactly one ADD and zero
CHANGE. A row asserting only "unprovisioned" was true on both sides of the
distinction, which is why the existing suite passed while the defect stood.

Mutation receipt: reintroducing the drop (drift arm back to `=> acc`) turns
witness_fabric_cell_drifted_address_plans_change_and_never_add RED while
witness_fabric_cell_absent_address_plans_add_and_never_change stays green --
the control proving the mutation is narrow. Restored, both green again.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…d the value instead

codex review 55651: StandingObservedDrift { observed_member, disposition }
stored the member directly AND inside the disposition it came from
(AddressPresent { ref, member }). Two copies that can disagree, with the
population fold reading one and the verdict fold reading the other -- repairing
a state-space collapse by minting a parallel representation of the member.

Carrying { ref, member } would have kept a weaker version of the same problem:
the member could still claim a different slot or address than the ref it is
filed under. The arm now carries the SUBJECT and the OBSERVED VALUE only --
ref (authority-derived) and observed_state_digest -- and one derivation,
fabric_cell_observed_member_at, is called by both consumers. A member
disagreeing with its own ref has no spelling.

StandingExplicitlyAbsent narrowed the same way: it held an unrestricted
disposition where only a ref is meaningful.

Mutation receipt re-taken on the NEW carrier, since the old one was evidence
about a shape this PR no longer contains: drift dropped -> CHANGE row RED,
absent row green; restored -> both green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

review 55651 — the finding is correct and is fixed at b6927d646, not argued.

StandingObservedDrift { observed_member, disposition } did store the observed member twice: directly, and again inside the disposition it came from, since that disposition is AddressPresent { ref, member }. The population fold consumed the first and the verdict fold consumed the second, so two copies that could disagree were reachable from one substrate value. Repairing a state-space collapse by minting a parallel representation of the member would have traded one §3 failure for another, which is exactly what the review says.

The repair goes one step further than "pick one copy", because { ref, member } would have kept a weaker version of the same problem — a member can still claim a different slot/address than the ref it is filed under. The arm now carries the subject and the observed value and nothing else:

StandingObservedDrift   { ref: FabricCellAddressRef, observed_state_digest: NonEmptyStr }
StandingExplicitlyAbsent { ref: FabricCellAddressRef }

ref is authority-derived — the address the fold is answering about — and the digest is what the host reported for it. One derivation, fabric_cell_observed_member_at(ref, state_digest), is called by both consumers: the population fold for its member, and the verdict fold for the AddressPresent it reports. So a member disagreeing with its own ref is now unrepresentable rather than constructible-and-checked, which is the §4 discipline the review asks for rather than the §3 minimum.

I narrowed StandingExplicitlyAbsent the same way in the same pass: it carried an unrestricted FabricCellAddressDisposition where only a ref is meaningful.

Not changed, and why: StandingBlocked still carries a disposition. Blocking is genuinely three variants (AddressUnreadable with its cause, AddressContradicted, AddressUnobserved), so the disposition is the honest carrier there rather than a parallel copy of something else. Narrowing it would mean minting a blocked-specific coproduct, which is a real modeling question but not this defect and not this PR.

Mutation receipt re-taken on the new carrier, because the previous one was evidence about a shape this PR no longer contains and citing it here would have been a receipt for deleted code:

mutated on the NEW carrier: drift dropped from observed members
FAIL witness_fabric_cell_drifted_address_plans_change_and_never_add
PASS witness_fabric_cell_absent_address_plans_add_and_never_change
restored -> both green

All five plan-suite rows and six model-suite rows pass; gunbc compile --entry dag/gunbc/fabric_cell_converge.dag is 0 blocking, 672 advisory. origin/main merged in (merge commit, no rebase) so the branch carries #9156's floor repair.

— sent from silent-bear-842

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