Skip to content

Merge admission: eliminate the five first() record-field assignments and the parse_int argument site - #9926

Merged
briansrls merged 6 commits into
mainfrom
session/still-swift-363-record-fields
Sep 2, 2026
Merged

briansrls merged 6 commits into
mainfrom
session/still-swift-363-record-fields

Conversation

@gunbai-bot

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

Copy link
Copy Markdown
Contributor

PREPARED, NOT READY — THIS PR HAS NO CI. It is based on #9912's branch rather than main, so the
witness workflows do not trigger and none will until #9912 lands, at which point this rebases onto
main and is re-run. A PR with no CI is not assessable however good its local evidence is, so please
do not count it among things waiting only on review. The stack is deliberate: basing on main would
put #9912's ten comparisons back into this diff and destroy the separate reading the split exists to buy.

Stacked on #9912. That PR migrated the ten first() comparisons; this one migrates the five first() record-field assignments, a different class with a different discriminator.

Why this exists: #9912 is a no-op on 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. A rewrite that is a no-op under main and still wrong under the repair passes every arm that does not compose the two heads.

What changes

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. Neither compared nor eliminated — 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.

RETRACTED: the receipt parser was never gated on the grounding

An earlier revision of this PR claimed the receipt parser could not be closed by consumer migration and was blocked on the builtin parameter-signature grounding. That was wrong. It was one unmigrated first() call, six lines from green, and the claim was relayed onward and cost a sibling lane a retracted ruling before it was caught. It is corrected here rather than quietly dropped.

The isolation itself was sound and is kept, because it located the site exactly:

cell 4 arm result
comparisons only (#9912) 34 PASS, 9 FAIL
+ subject record fields 36 PASS, 7 FAIL — subject parser green
+ receipt record fields 36 PASS, 7 FAIL — unchanged
+ the parse_int argument site 43 PASS, 0 FAIL

All seven were receipt_wire_v2_pr_number passing lines.skip(n: 6).first() straight into parse_int. What I inferred from that — no consumer work can help — did not follow from it.

Why the wrong inference was available. Builtin arguments bind positionally and nothing judges them, so a builtin site fails at runtime, from inside the callee, while a user-function site fails at typecheck, at the call. I had migrated every site that refused at typecheck, saw the remainder still red, and read "the consumer side is exhausted" off a diagnostic pointing into parse_int rather than at my own line. The unchecked surface hid the site, and then the same unchecked surface got blamed for it.

Both cells measured for the new site, not argued. Under the repaired interpreter (built from session/still-swift-363): 43/43, where 36/43 passed before. Under main's interpreter — this branch's stage0 tree is byte-identical to main's, verified by diff before trusting it, and claim_batch rebuilt from it — 43/43 as well. Correct under the repair, no-op under main's semantics.

What remains unmigrated, named rather than left. About a dozen other argument-position first() sites survive in these two modules: walk_attempt_id(raw: …first()), parse_check_conclusion(raw: …), git_object_id_from_untagged_hex(hex: …), head_sha: …first(). All 43 witnesses pass under both interpreters with them in place, so they are not currently wrong — but they are the same class, and I do not know why they survive where parse_int did not. Recorded as unknown rather than explained.

No-op at carrier grain, the only grain that can see this class

A verdict-grain check cannot see it: all five bindings 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.

arm result
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.

Scope

Five record-field assignments in gunbc.merge_admission_produce and gunbc.merge_admission_subject. Counts elsewhere in this work are lower bounds, not populations — the closure classification's largest non-match bucket is 31 sites whose position a one-line reader cannot decide. The completion criterion for the wider migration is that the gate's closure loads, not that a count is reached.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HsALPpj3hERxcuCfK6Cc23

gunbc-ci-auto-heal and others added 4 commits September 1, 2026 09:57
…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
…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
…s, 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
@gunbai-bot
gunbai-bot Bot marked this pull request as draft September 1, 2026 11:26
Base automatically changed from session/still-swift-363-merge-admission to main September 1, 2026 17:00
gunbc-ci-auto-heal added 2 commits September 1, 2026 17:01
#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.
…ated 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.
@gunbai-bot gunbai-bot Bot changed the title Merge admission: the record-field class, and the proof that the receipt parser needs the builtin grounding Merge admission: eliminate the five first() record-field assignments and the parse_int argument site Sep 1, 2026
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review September 1, 2026 17:27
@briansrls
briansrls merged commit 42d8b99 into main Sep 2, 2026
6 checks passed
@briansrls
briansrls deleted the session/still-swift-363-record-fields branch September 2, 2026 04:46
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