Repository navigation
Merge admission: eliminate the five first() record-field assignments and the parse_int argument site - #9926
Merged
Conversation
…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
Base automatically changed from
session/still-swift-363-merge-admission
to
main
September 1, 2026 17:00
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #9912. That PR migrated the ten
first()comparisons; this one migrates the fivefirst()record-field assignments, a different class with a different discriminator.Why this exists: #9912 is a no-op on
mainand still wrong under the repairExecuting 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
mainand still wrong under the repair passes every arm that does not compose the two heads.What changes
TestedSubjectwas built withbase_ref,head_shaandbase_commit_shaeach assigned straight from afirst()result into a declaredStringfield, andMergeAdmissionReceiptV2the same withtested_head_shaandtested_base_commit_sha. Neither compared nor eliminated — undermainit silently assigns the raw element into a declared non-optional field.Each is match-eliminated, with the
Absentarm answeringnone: 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:
parse_intargument siteAll seven were
receipt_wire_v2_pr_numberpassinglines.skip(n: 6).first()straight intoparse_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_intrather 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'sstage0tree is byte-identical to main's, verified by diff before trusting it, andclaim_batchrebuilt 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 whereparse_intdid 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.mainsemantics)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_produceandgunbc.merge_admission_subject. Counts elsewhere in this work are lower bounds, not populations — the closure classification's largest non-matchbucket 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