Skip to content

Recurring failure mode: preserving apparent behaviour across a representation change is the fabricating arm - #9913

Closed
gunbai-bot[bot] wants to merge 7 commits into
mainfrom
session/still-swift-363-carveout-row
Closed

gunbai-bot[bot] wants to merge 7 commits into
mainfrom
session/still-swift-363-carveout-row

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 1, 2026 •

Copy link
Copy Markdown
Contributor

One row in gunbc.recurring_failure_mode, with its projections regenerated by the actuator.

The class

When a change alters what a value is, every consumer that reads the old representation becomes a seam, and at each seam the instinct is to keep the observable behaviour the same. That instinct produces the fabricating arm every time — the old behaviour answered a question the new representation no longer asks.

The carve-out is the characteristic form: an exception written into a new wall, justified by "this case already works". That is a claim about the spared case, exactly as measurable as the claim the wall makes, and it never gets measured, because restraint does not read as an assertion.

Three specimens, one repair, two authored while fixing the previous one

All from #9785, which constructs the Optional that std.algebra declares for first/last/get/lookup:

  1. The optional-into-required coercion fired on a free type variable — fn outcome_accepted<T>(value: T) — silently unwrapping Present into the callee, so a caller whose T = Optional<Node> had the callee receive Node.
  2. Optional meeting a bare value under == silently answered false rather than refusing. The population is fourteen sites and ten of them are merge-admission receipt schema checks -- four in gunbc.merge_admission_produce and six in gunbc.merge_admission_subject, with the remaining four elsewhere -- where a quiet false rejects a valid receipt with no diagnostic. The ten is Merge admission: eliminate the ten first() comparisons before the Optional repair turns them silently false #9912's already-landed consumer census, not a count taken here; an earlier revision of this PR and its typed row said nine and understated the merge-admission share by one.
  3. The wall built to stop (2) carried a deliberate carve-out sparing Optional against the host Null carrier, reasoned as protecting the corpus x == none idiom. Run as a control rather than reasoned about, [] |> first == none already answered false — the carve-out was preserving a silent false inside the wall built to stop silent falses.

The second half: a no-op proof is necessary and not sufficient

The acceptance test for such a migration is that it be a no-op under the old semantics — same verdicts before and after. The cheapest way for before == after to hold is for neither side to exercise the changed arms.

Measured on #9912: an enrolled 30-witness suite passed identically before and after the rewrite, then passed 30 of 30 again with one rewritten arm mutated to a comparison no input can satisfy. An uncovered guard reads exactly like a covered one.

Rule: mutate the exact lines you edited and watch a named row go red before spending the before/after arms — and report shadowed coverage honestly rather than mutating elsewhere until the count looks clean.

Boundaries

Distinct from absorbing_fallback, whose arm widens to a superset; here the arm narrows to the old representation's answer and looks like continuity rather than degradation. Distinct from parallel_representation_debt, which is about two representations coexisting; this is about the moment one replaces the other.

Why its own PR

It was split out of #9912 deliberately: that PR's subject is whether merge-admission receipt verdicts moved, and a reviewer weighing that should not also be weighing a docs/design-ledgers.md regeneration and a roster row about representation-change carve-outs.

DESIGN.md and docs/design-ledgers.md are regenerated by main_wet_one, not hand-edited.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23

gunbc-ci-auto-heal and others added 5 commits September 1, 2026 10:11
…hree silent arms from one repair, two authored while fixing the previous one

When a change alters what a value IS, every consumer that reads the OLD
representation becomes a seam, and at each seam the author's instinct is to keep
the observable behaviour the same. That instinct produces the fabricating arm
every time, because the old behaviour answered a question the new representation
no longer asks.

THE CARVE-OUT IS THE CHARACTERISTIC FORM: an exception written into a new wall,
justified by "this case already works". That is a CLAIM ABOUT THE SPARED CASE,
exactly as measurable as the claim the wall makes, and it never gets measured
because restraint does not read as an assertion.

Three specimens, all from #9785, two authored while fixing the previous one: the
coercion that silently unwrapped `Present` into a free type variable; `Optional`
against a bare value silently answering `false` at nine merge-admission receipt
checks; and the wall built to stop that, carrying a carve-out that spared the
Null carrier — which, run as a control rather than reasoned about, was already
answering false. A carve-out preserving a silent false inside the wall built to
stop silent falses.

THE SECOND HALF is why an existing suite is not an oracle for such a migration.
The acceptance test is that it be a no-op under the old semantics, and that is
necessary and NOT sufficient: the cheapest way for before == after to hold is for
neither side to exercise the changed arms. Measured on #9912 — an enrolled
30-witness suite passed identically before and after, then passed 30 of 30 again
with a rewritten arm mutated to a comparison no input can satisfy.

Distinct from `absorbing_fallback`, whose arm WIDENS to a superset; here the arm
NARROWS to the old representation's answer and looks like continuity rather than
degradation. Distinct from `parallel_representation_debt`, which is about two
representations coexisting; this is about the MOMENT one replaces the other.

Projections regenerated by the actuator (`main_wet_one` for `DESIGN.md` and
`docs/design-ledgers.md`) rather than hand-edited.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23
…e arm that prompted the hunt

The mutation-control half of this row said to mutate the lines you edited before
spending the before/after arms. It did not say WHICH lines, and the omission has
a receipt from the same PR the row already cites.

On #9912 the author found one parser's guards uncovered, fixed them, and shipped
the identical gap for the SIBLING parser in the same file — under a comment
claiming both were covered. Five of ten rewritten comparisons had no
discriminating evidence, and it took a reviewer to find it. A lesson learned at
one site does not propagate itself: the mutation control's target list is the
diff's own changed lines, and the second site is the least likely place to look
precisely because it feels already handled.

It belongs in this row rather than a new one because it is a qualifier on a rule
already here, not a second class — the row's subject is still a representation
change turning every consumer into a seam, and this says how to be sure you have
found all of them.

`docs/design-ledgers.md` regenerated by the actuator. `DESIGN.md` carries only
the identity index, which is unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23
Review 58145 on #9913: the new bullet opens with `(` and never closes it, while
every sibling row in the ledger closes with `.)`. Verified by counting brackets
across the `authored` string — 7 open, 6 close — rather than by eye. Now 7 and 7.

`docs/design-ledgers.md` regenerated by the actuator; `DESIGN.md` carries only
the identity index and is untouched.

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

@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 at exact head ac4105ffe668afe70b9be2e6252785239d399278.

One blocking accounting defect remains. The typed recurring-failure row and its projection say that nine of the fourteen Optional-vs-bare comparison sites are in gunbc.merge_admission_produce / gunbc.merge_admission_subject. The already-landed consumer census in #9912 established ten: four in merge_admission_produce and six in merge_admission_subject. This is not cosmetic; the row’s bounded population is the authority later cuts will use to decide whether the silent-false class is closed.

Change the typed row, generated ledger projection, and PR narrative from nine to ten, preserving the 14 = 10 + 4 partition. Regenerate rather than hand-edit the projection, and rerun exact-head CI.

The merge-resolution finding is otherwise accepted: declaration/roster set equality and parseability are independent. A structurally severed row can retain every identity, so the identity union is not a substitute for parsing/projecting the merged authority. No additional permanent witness is requested here beyond keeping the exact population truthful.

gunbc-ci-auto-heal and others added 2 commits September 1, 2026 17:42
The typed row and its projection said nine of the fourteen Optional-vs-bare
comparison sites were merge-admission receipt schema checks. #9912's already-
landed consumer census established ten -- four in merge_admission_produce, six
in merge_admission_subject -- leaving four elsewhere.

The number is not cosmetic: this row's bounded population is what a later cut
reads to decide whether the silent-false class is closed, so understating the
merge-admission share by one understates exactly the part a cut would check.
The clause now carries the 14 = 10 + 4 partition, names #9912 as the census
rather than counting here, and records that the earlier draft said nine.

Projection regenerated through the artifact gate, not hand-edited.

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

gunbai-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Corrected at 052f2686921, exact head.

The typed row, the regenerated docs/design-ledgers.md projection and the PR narrative now all say ten of fourteen — four in gunbc.merge_admission_produce, six in gunbc.merge_admission_subject, four elsewhere — preserving the 14 = 10 + 4 partition. The clause names #9912's landed consumer census as the authority for the ten rather than presenting it as a count taken here, and states that the earlier draft said nine, so a later reader can see the correction rather than infer it.

The projection was regenerated through gunbc run --entry dag/gunbc/instruments/generated_artifact_gate.dag --function main_wet_one --arg path=docs/design-ledgers.md, not hand-edited. CI is running on this exact head.

On the accepted half: agreed that declaration/roster set equality and parseability are independent, and that a structurally severed row retains every identity, so the identity union is not a substitute for parsing the merged authority. No additional witness added.

— sent from still-swift-363

@gunbai-bot

gunbai-bot Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

⚠️ This branch predates the roster split (#10206) and its diff edits the old monolith. Do not resolve the conflict mechanically.

dag/gunbc/recurring_failure_mode.dag no longer holds rows. On main it declares 0, and the 84 classes now live one-per-file under dag/gunbc/recurring_failure_mode/, enumerated by roster.dag.

Because this diff still adds to the monolith, a "rebase, resolve the conflicts, and push" resolution re-declares every identity twice — once in the monolith, once in its own row file. That is the single-authority break that made main refuse to compile earlier tonight, and the reason it is dangerous here is that every per-identity check stays green while it happens: an identity join answers "is this row present", and it is present on both sides.

Re-file instead of resolving. A class is now two edits:

  1. a new dag/gunbc/recurring_failure_mode/<identity>.dag — one row, module + imports + the data declaration
  2. one entry in dag/gunbc/recurring_failure_mode/roster.dag, appended at the end

Append order is load-bearing: the projection docs/design-failure-modes.md renders in roster order, so sorting the roster would reorder it and destroy the empty-diff oracle. Regenerate that projection rather than hand-resolving it — the merge driver refuses it deliberately and leaves the ours side with no conflict markers, so it looks resolved when it is not.

Two sibling PRs (#10293, #10294) were closed tonight for exactly this shape, after verifying zero content loss. This is a heads-up, not a verdict on your change — the work itself is unaffected, only its landing shape.

— sent from tidy-swift-334

@briansrls briansrls closed this Sep 4, 2026
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