Skip to content

Merge admission: eliminate the ten first() comparisons before the Optional repair turns them silently false - #9912

Merged
gunbai-bot[bot] merged 2 commits into
mainfrom
session/still-swift-363-merge-admission
Sep 1, 2026
Merged

gunbai-bot[bot] merged 2 commits into
mainfrom
session/still-swift-363-merge-admission

Conversation

@gunbai-bot

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

Copy link
Copy Markdown
Contributor

Why this exists, and why it must land before the first() repair

Ten sites in gunbc.merge_admission_produce and gunbc.merge_admission_subject compare a first() result to a bare value. dag/std/algebra.dag declares first as returning Optional<..>, so once the interpreter constructs what that row declares, every one of these compares across two representations and Value::eq cannot decide them. Measured on the branch that constructs it (#9785): ["schema-v2", "body"].first() == "schema-v2" answers false.

These are the receipt schema and blank-required-field checks on the path every lane merges through. A quiet false rejects a valid receipt with no diagnostic. They are correct today — on main the interpreter's first is items.front().cloned().unwrap_or(Value::Null), the raw element, so the comparison is String-to-String — and it is the repair that breaks them. That makes this change a precondition for #9785, not housekeeping.

What changes

Each site moves from the compared class into the match-eliminated class, the one class that already agrees under both semantics.

The Absent arm is derived, not decided. parse_receipt_wire_v2 declares -> MergeAdmissionReceiptV2? and already answers none for every malformed case it handles — wrong line count, wrong schema line, blank required field, unparseable attempt id, conclusion, gate roster hash or PR number. parse_tested_subject_wire and parse_git_object_id_wire are the same shape, and receipt_wire_v2_pr_number already carries the exact target form (match parse_int(...) { ... Absent => WirePrMalformed }). So "the receipt has no first line" is an instance of an answer these modules already give. No new refusal vocabulary is minted.

It is a no-op today — the obligation this PR has to meet

It lands on main, where first returns the raw element and no wall exists. The interpreter's match_pattern binds a Present { value: v } pattern to a raw value, so each rewritten site binds the same string it compared before and answers the same verdict. The Absent arm is unreachable under the length guard each function already applies ahead of these checks.

Measured — one binary, three arms. The change is .dag-only, so the same claim_batch build serves every arm and the delta is the source, not the tool.

arm result
pristine main, 36 witnesses 36 PASS
migrated, 36 witnesses 36 PASS, verdict-for-verdict identical
mutation control 34 PASS, 2 named FAIL

Six witnesses are added because the suite could not see these arms

Mutating the blank-field comparison to a string no field can equal left the existing 30 witnesses all passing. They reach parse_gate_roster_hash_wire and compose_walk_attempt_id directly, and feed the wire parsers only well-formed text, a trailing line and a malformed PR line. An uncovered guard reads as a covered one — without these rows the rewrite would have been "verified" by a suite blind to it. Under the same mutation the new rows go red by name.

One honest limit on that coverage. The mutation flips wire_v2_refuses_a_blank_head_sha_line and wire_v2_refuses_a_blank_base_commit_line and not the blank-roster row, because a blank roster line is independently rejected downstream by parse_gate_roster_hash_wire. That guard is shadowed rather than discriminated, and this says so rather than claiming three for three.

Each new row varies exactly one line of a wire that parses, which is the convention the existing rows in that module state, and a positive control asserts the all-correct builder still parses — otherwise every refusal row could be satisfied by a wire malformed for some other reason.

Scope

Ten of the fourteen known comparison sites in the generated-artifact gate's 944-module import closure. Those counts are lower bounds and not populations: the classification's largest non-match bucket is 31 sites where a one-line textual reader cannot decide a record-field assignment from a function argument, because the opening brace is on a previous line, so it names its own undecidability rather than guessing. The completion criterion for the wider migration is that the gate's closure LOADS, not that a count is reached — this PR asserts only that the ten named sites are repaired and verified. The other four known comparison sites (extdeps.languages.yaml.ingest, gunbc.os_install_actuator_selection, gunbc.roadmap.roadmap_dispatch_actuator, std.realization_schedule) are a separate change; the three builtin-argument sites need the builtin parameter-signature grounding and stay refusing until it lands.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23

…he guard arms the suite could not see

Ten sites in `gunbc.merge_admission_produce` and `gunbc.merge_admission_subject`
compare a `first()` result to a bare value. `dag/std/algebra.dag` declares
`first` as returning `Optional<..>`, so once the interpreter constructs what that
row declares, every one of these compares across two representations and
`Value::eq` cannot decide them -- measured on the branch that constructs it,
`["schema-v2", "body"].first() == "schema-v2"` answers FALSE. These are the
receipt schema and blank-required-field checks on the path every lane merges
through, so a quiet `false` rejects a valid receipt with no diagnostic.

Each site moves from the COMPARED class into the MATCH-ELIMINATED class, which is
the class that already agrees under both semantics. The `Absent` arm is DERIVED,
not decided: `parse_receipt_wire_v2` declares `-> MergeAdmissionReceiptV2?` and
already answers `none` for every malformed case it handles -- wrong line count,
wrong schema line, blank field, unparseable attempt id, conclusion, roster hash
or PR number -- and `parse_tested_subject_wire` and `parse_git_object_id_wire`
are the same shape. `receipt_wire_v2_pr_number` already carries the exact target
form. So "the receipt has no first line" is an instance of an answer these
modules already give, and no new refusal vocabulary is minted.

IT IS A NO-OP TODAY, AND THAT IS THE OBLIGATION THIS CHANGE HAS TO MEET. It lands
on `main`, where `first` returns the raw element. The interpreter's `match_pattern`
binds a `Present { value: v }` pattern to a raw value, so each rewritten site
binds the same string it compared before and answers the same verdict; the
`Absent` arm is unreachable under the length guard each function already applies
before these checks.

MEASURED, ONE BINARY, THREE ARMS -- the change is `.dag`-only, so the same
`claim_batch` build serves every arm and the delta is the source, not the tool.

  pristine main, 36 witnesses   36 PASS
  migrated,      36 witnesses   36 PASS, verdict-for-verdict identical
  mutation control              34 PASS, 2 named FAIL

THE SUITE COULD NOT SEE THESE ARMS BEFORE, WHICH IS WHY SIX WITNESSES ARE ADDED.
Mutating the blank-field comparison to a string no field can equal left the
existing 30 witnesses ALL PASSING: they reach `parse_gate_roster_hash_wire` and
`compose_walk_attempt_id` directly and feed the wire parsers only well-formed
text, a trailing line and a malformed PR line. An uncovered guard reads as a
covered one, and without these rows the rewrite would have been "verified" by a
suite blind to it. Under the same mutation the new rows go red by name.

ONE HONEST LIMIT ON THAT COVERAGE. The mutation flips the blank-head and
blank-base rows and NOT the blank-roster row, because a blank roster line is
independently rejected downstream by `parse_gate_roster_hash_wire`. That guard is
therefore shadowed rather than discriminated, and this states it instead of
claiming three for three.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23
gunbai-bot Bot pushed a commit that referenced this pull request Sep 1, 2026
…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
…er's four guards and a valid sha256 wire

Review of #9912 found the rows added in the previous commit exercised only
`parse_receipt_wire_v2` while the comment claimed both parsers. Five of the ten
rewritten comparisons therefore had no discriminating evidence at all -- the
subject parser's schema guard and its three blank-field guards, and the `sha256`
algorithm prefix, whose row accepted a valid sha1 wire and rejected md5 and so
never supplied a valid sha256 at all.

The finding is right and it is the same defect one parser over from the one the
mutation control caught. The lesson had been learned about the receipt parser and
then not carried across the file, which is what the comment's overclaim recorded.

SEVEN ROWS ADDED. Four for `parse_tested_subject_wire` over its own five-line
wire -- wrong schema line, blank base_ref, blank head_sha, blank base_commit_sha
-- plus a positive control that the all-correct builder parses, without which
every refusal row could be satisfied by a wire malformed for some other reason.
The object-id row is split into three: a valid sha1 wire, a valid sha256 wire,
and an undeclared algorithm refused. The overclaiming comment is corrected in
place rather than deleted, so the gap it recorded stays legible.

MUTATION CONTROL, ON EXACTLY THE FIVE THE REVIEW NAMED. Mutating the subject
parser's blank guards, its schema comparison and the sha256 prefix turns five
rows red BY NAME:

  object_id_wire_accepts_a_valid_sha256_wire
  subject_wire_refuses_a_wrong_schema_line
  subject_wire_refuses_a_blank_base_ref_line
  subject_wire_refuses_a_blank_head_sha_line
  subject_wire_refuses_a_blank_base_commit_line

THE FULL EVIDENCE, one binary across all three arms:

  pristine main, 43 witnesses    43 PASS
  migrated,      43 witnesses    43 PASS, verdict for verdict identical
  mutation control               38 PASS, 5 named FAIL

The sha256 row also earned its place before it was enrolled: the first fixture
carried a 72-character hex string and the row went red, which is the witness
discriminating on its own input rather than on the change.

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

Both findings verified and fixed in b152146. Review 58126 was right on both counts, and the second one is sharper than it may have looked.

Finding 1 — the subject parser's four guards had no rows. Correct. The rows added in the previous commit exercised only parse_receipt_wire_v2, and the comment claimed both parsers. Five of the ten rewritten comparisons had no discriminating evidence. Added four rows over parse_tested_subject_wire's own five-line wire — wrong schema line, blank base_ref, blank head_sha, blank base_commit_sha — plus a positive control that the all-correct builder parses, without which every refusal row could be satisfied by a wire malformed for some other reason. The overclaiming comment is corrected in place rather than deleted, so the gap it recorded stays legible.

Finding 2 — the sha256 comparison was uncovered. Also correct, and it is the more interesting one: the old row accepted a valid sha1: wire and rejected md5:, which reads as covering both declared algorithms while supplying a valid wire for only one. Split into three rows — valid sha1, valid sha256, undeclared algorithm refused.

Mutation control, on exactly the five you named. Mutating the subject parser's three blank guards, its schema comparison and the sha256 prefix turns five rows red by name:

FAIL object_id_wire_accepts_a_valid_sha256_wire
FAIL subject_wire_refuses_a_wrong_schema_line
FAIL subject_wire_refuses_a_blank_base_ref_line
FAIL subject_wire_refuses_a_blank_head_sha_line
FAIL subject_wire_refuses_a_blank_base_commit_line

Full evidence, one binary across all three arms (the change is .dag-only, so the delta is the source, not the tool):

arm result
pristine main, 43 witnesses 43 PASS
migrated, 43 witnesses 43 PASS, verdict-for-verdict identical
mutation control 38 PASS, 5 named FAIL

One incidental receipt worth recording: the sha256 row went red on its first run because my fixture carried a 72-character hex string. The witness discriminated on its own input before it ever discriminated on the change.

The shadowed-guard note in the body still stands unchanged — the receipt parser's blank-roster guard does not flip under mutation, because a blank roster line is independently rejected downstream by parse_gate_roster_hash_wire. That is a real property of the code rather than a gap in the rows, and it is stated rather than rounded off.

— sent from still-swift-363

gunbai-bot Bot pushed a commit that referenced this pull request Sep 1, 2026
…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
@gunbai-bot
gunbai-bot Bot merged commit 78b7109 into main Sep 1, 2026
6 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/still-swift-363-merge-admission branch September 1, 2026 17:00
briansrls pushed a commit that referenced this pull request Sep 1, 2026
#9912 squash-merged, so main carries its content while this branch carries the same
commits plus the record-field work. Resolved by taking this branch's side at all six
regions and verifying the result is byte-identical to the pre-merge file -- main added
nothing to this witness beyond #9912's own head content, checked by diffing main's
version against b152146's.
gunbai-bot Bot pushed a commit that referenced this pull request Sep 1, 2026
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
briansrls pushed a commit that referenced this pull request Sep 2, 2026
…and the parse_int argument site (#9926)

* Merge admission: eliminate the ten `first()` comparisons, and cover the guard arms the suite could not see

Ten sites in `gunbc.merge_admission_produce` and `gunbc.merge_admission_subject`
compare a `first()` result to a bare value. `dag/std/algebra.dag` declares
`first` as returning `Optional<..>`, so once the interpreter constructs what that
row declares, every one of these compares across two representations and
`Value::eq` cannot decide them -- measured on the branch that constructs it,
`["schema-v2", "body"].first() == "schema-v2"` answers FALSE. These are the
receipt schema and blank-required-field checks on the path every lane merges
through, so a quiet `false` rejects a valid receipt with no diagnostic.

Each site moves from the COMPARED class into the MATCH-ELIMINATED class, which is
the class that already agrees under both semantics. The `Absent` arm is DERIVED,
not decided: `parse_receipt_wire_v2` declares `-> MergeAdmissionReceiptV2?` and
already answers `none` for every malformed case it handles -- wrong line count,
wrong schema line, blank field, unparseable attempt id, conclusion, roster hash
or PR number -- and `parse_tested_subject_wire` and `parse_git_object_id_wire`
are the same shape. `receipt_wire_v2_pr_number` already carries the exact target
form. So "the receipt has no first line" is an instance of an answer these
modules already give, and no new refusal vocabulary is minted.

IT IS A NO-OP TODAY, AND THAT IS THE OBLIGATION THIS CHANGE HAS TO MEET. It lands
on `main`, where `first` returns the raw element. The interpreter's `match_pattern`
binds a `Present { value: v }` pattern to a raw value, so each rewritten site
binds the same string it compared before and answers the same verdict; the
`Absent` arm is unreachable under the length guard each function already applies
before these checks.

MEASURED, ONE BINARY, THREE ARMS -- the change is `.dag`-only, so the same
`claim_batch` build serves every arm and the delta is the source, not the tool.

  pristine main, 36 witnesses   36 PASS
  migrated,      36 witnesses   36 PASS, verdict-for-verdict identical
  mutation control              34 PASS, 2 named FAIL

THE SUITE COULD NOT SEE THESE ARMS BEFORE, WHICH IS WHY SIX WITNESSES ARE ADDED.
Mutating the blank-field comparison to a string no field can equal left the
existing 30 witnesses ALL PASSING: they reach `parse_gate_roster_hash_wire` and
`compose_walk_attempt_id` directly and feed the wire parsers only well-formed
text, a trailing line and a malformed PR line. An uncovered guard reads as a
covered one, and without these rows the rewrite would have been "verified" by a
suite blind to it. Under the same mutation the new rows go red by name.

ONE HONEST LIMIT ON THAT COVERAGE. The mutation flips the blank-head and
blank-base rows and NOT the blank-roster row, because a blank roster line is
independently rejected downstream by `parse_gate_roster_hash_wire`. That guard is
therefore shadowed rather than discriminated, and this states it instead of
claiming three for three.

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

* Cover the five comparisons the first cut left blind: the subject parser's four guards and a valid sha256 wire

Review of #9912 found the rows added in the previous commit exercised only
`parse_receipt_wire_v2` while the comment claimed both parsers. Five of the ten
rewritten comparisons therefore had no discriminating evidence at all -- the
subject parser's schema guard and its three blank-field guards, and the `sha256`
algorithm prefix, whose row accepted a valid sha1 wire and rejected md5 and so
never supplied a valid sha256 at all.

The finding is right and it is the same defect one parser over from the one the
mutation control caught. The lesson had been learned about the receipt parser and
then not carried across the file, which is what the comment's overclaim recorded.

SEVEN ROWS ADDED. Four for `parse_tested_subject_wire` over its own five-line
wire -- wrong schema line, blank base_ref, blank head_sha, blank base_commit_sha
-- plus a positive control that the all-correct builder parses, without which
every refusal row could be satisfied by a wire malformed for some other reason.
The object-id row is split into three: a valid sha1 wire, a valid sha256 wire,
and an undeclared algorithm refused. The overclaiming comment is corrected in
place rather than deleted, so the gap it recorded stays legible.

MUTATION CONTROL, ON EXACTLY THE FIVE THE REVIEW NAMED. Mutating the subject
parser's blank guards, its schema comparison and the sha256 prefix turns five
rows red BY NAME:

  object_id_wire_accepts_a_valid_sha256_wire
  subject_wire_refuses_a_wrong_schema_line
  subject_wire_refuses_a_blank_base_ref_line
  subject_wire_refuses_a_blank_head_sha_line
  subject_wire_refuses_a_blank_base_commit_line

THE FULL EVIDENCE, one binary across all three arms:

  pristine main, 43 witnesses    43 PASS
  migrated,      43 witnesses    43 PASS, verdict for verdict identical
  mutation control               38 PASS, 5 named FAIL

The sha256 row also earned its place before it was enrolled: the first fixture
carried a 72-character hex string and the row went red, which is the witness
discriminating on its own input rather than on the change.

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

* wip carrier-grain

* Merge admission: eliminate the five `first()` record-field assignments, and prove the receipt parser is gated on the builtin grounding

The comparison migration (#9912) is a no-op under `main` AND STILL WRONG UNDER
THE REPAIR. Executing the acceptance matrix's fourth cell -- the #9912 consumer
head composed with the #9785 repair-plus-wall head in one tree, built once and
run -- returned 34 PASS / 9 FAIL. Neither cause was the comparison class.

FIVE OF THOSE FAILURES ARE THIS CHANGE'S SUBJECT. `TestedSubject` was built with
`base_ref`, `head_sha` and `base_commit_sha` each assigned straight from a
`first()` result into a declared `String` field, and `MergeAdmissionReceiptV2`
the same with `tested_head_sha` and `tested_base_commit_sha`. That is a third
consumer class: neither compared nor eliminated, and under `main` it silently
assigns the raw element into a declared non-optional field. Each is
match-eliminated, with the `Absent` arm answering `none` -- derived from the
answer every sibling malformed arm in these modules already gives, not invented.

THE OTHER SEVEN ARE NOT CLOSABLE FROM THE CONSUMER SIDE, and the isolation is the
finding rather than a side note. After migrating the receipt parser's two record
fields as well, the failure count DID NOT MOVE -- 7 before, 7 after, all the same
single site: `receipt_wire_v2_pr_number` calling `parse_int` on a `first()`
result. A builtin carries a return type with no declared parameter list, so no
coercion can be derived for it, and one such call takes down all seven receipt
witnesses. An unchanged number is usually the least informative result available;
here it separates "more consumer work remains" from "no consumer work can help".

  cell 4, comparisons only              34 PASS,  9 FAIL
  cell 4, + subject record fields       36 PASS,  7 FAIL   subject parser GREEN
  cell 4, + receipt record fields       36 PASS,  7 FAIL   unchanged: consumer side exhausted

**The subject parser is closed under the repair. The receipt parser is gated on
the builtin parameter-signature grounding and cannot be closed by consumer
migration.** That red is the correct state to land with.

NO-OP AT CARRIER GRAIN, WHICH IS THE ONLY GRAIN THAT CAN SEE THIS CLASS. A
verdict-grain check cannot: these five bindings all keep `Present`, and a rewrite
that reads the wrong line changes the VALUE, not the verdict. So the positive
controls assert every field of every accepted class, and the mutation crosses two
adjacent bound fields rather than breaking a guard.

  baseline (#9912 head, main semantics)   43 PASS
  migrated                                43 PASS, verdict for verdict identical
  field-crossing mutation                 39 PASS, 4 named FAIL

The four are exactly the carrier-grain rows -- both roundtrip witnesses and both
new positive controls. Under a verdict-grain suite that mutation is invisible.

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

* The receipt parser was NOT gated on the builtin grounding: one unmigrated first() was

receipt_wire_v2_pr_number passed lines.skip(n: 6).first() straight into parse_int, so
the Optional reached a builtin that declares a String and refused at RUNTIME rather than
at typecheck -- which is why it read as a wall I could not move from the consumer side.
Eliminating it with a match, six lines, turns all seven red witnesses green.

Both cells measured, not argued. Under the repaired interpreter (built from
session/still-swift-363) 43/43 pass where 36/43 passed before. Under MAIN's interpreter
-- this branch's stage0 tree is byte-identical to main's, verified by diff, and rebuilt
from it -- 43/43 pass as well. So the change is correct under the repair and a no-op
under main's semantics.

I reported the unchanged seven as proof that the receipt parser was gated on the builtin
signature grounding. That was wrong, and a ruling was retracted on the strength of it.

---------

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.

0 participants