refactor(parser): Plan 05b T10c — the die-result branch table as IR (U0-45) - #6742
Merged
Conversation
The ordering doc declares itself the single authority on a sequence that is "pinned and behavior-load-bearing", but the die-result step was inserted into that sequence without appearing in it. Placing it before finalize is a real decision (CR 706.3b: the table is part of the same ability as the roll, so finalize and the anchor must see the complete effect) and was undocumented.
matthewevans
enabled auto-merge
July 28, 2026 20:19
Contributor
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (10)
📒 Files selected for processing (4)
📝 WalkthroughWalkthroughDie-roll table parsing now stores result branches in ChangesDie-roll result IR integration
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant OracleSpecialParser
participant AbilityIr
participant LowerAbilityIr
participant RollDieEffect
OracleSpecialParser->>AbilityIr: Build roll instruction and result branches
AbilityIr->>LowerAbilityIr: Pass parsed ability IR
LowerAbilityIr->>RollDieEffect: Attach lowered result branches
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Parse changes introduced by this PR✓ No card-parse changes detected. |
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.
Plan 05b T10c — converts U0-45, the CR 706 die-roll table producer, to real IR. Follows #6733.
This is the only die row that owns its whole definition. The other five mutate a definition someone else already lowered and are a strictly harder seam — they stay out. T10c ships the type; T10d spends it.
DieResultBranchIr+AbilityIr.die_resultstry_parse_die_roll_tableThe branch bodies are R1 — the identity is the function body
Each row's effect was
parse_effect_chain(effect_text, kind). That call islower_ability_ir(&parse_ability_ir_standalone(effect_text, kind))— the entire body ofparse_effect_chain, not a claim about it. Splitting it moves where lowering happens, never what it produces.Box<AbilityIr>rather thanBox<EffectChainIr>is load-bearing, not style:lower_effect_chain_irskipsfinalize_effect_chainand the owner-library anchor, both of whichparse_effect_chainruns today.CR 706.3a is the row shape; CR 706.3b decides where the table lives
That is
{min, max, effect}verbatim.So the table is not a sibling document item that happens to follow — carrying it inside the
AbilityIris what the rules describe, and the same sentence licenses the line-consumption (next_i) behaviour: those following lines are not independent abilities. Both rules were grep-verified and their text read, not existence-checked.The risk that had to be measured rather than argued
Today U0-45's definition is built by
AbilityDefinition::newand never passes throughfinalize_effect_chainorapply_owner_library_reveal_anchor_from_text. Routing it throughlower_ability_irsubjects it to both for the first time, across ~113 die cards.Both were expected inert — a one-clause chain has no continuations to finalize, and the anchor is text-driven off
source_text, which here is a"Roll a dN…"header with no owner-library reveal phrasing. But that is an R2 argument about today's corpus, not an identity. This campaign's one landed defect (#6123) passed review precisely because its byte-identity claim was true while its reach argument was untested. So it was measured.Neither mechanism fired. Three fresh generator builds, distinct target dirs,
MTGJSON_SKIP_REFRESH=1, realAtomicCards.json(158,014,511 bytes — resolved and size-checked, since the fixture population would be void evidence rather than a green).Stated rather than buried: the measured revisions differ from the shipped ones by the ten accepted
.snapfiles and commit 3's doc comment. That was verified mechanically, not asserted — every differing line is either a.snapfixture or a///line, so no generator input or code path differs and the hashes carry to the tip.Commit 1 is inert by construction
die_resultsdefaults to empty and the applier is guarded on non-empty, so every pre-existing producer lowers exactly as before — the same defer-on-default property that made the A0 shell widening byte-identical. The existingfind_terminal_roll_diewalk is reused, not duplicated; only its visibility changed.Ten
*_ir.snapfixtures moved, all the identical schema addition ("die_results": []) and nothing else. The_ir/_loweredmasking trap was handled correctly: the ten_irassertions were accepted, then the snapshot module was re-run to confirm the_loweredassertions that follow them still pass. Zero*.snap.newpending.Commit 3 — the ordering doc had gone stale, and it is the load-bearing kind
lower_ability_ir's doc declares itself the single authority on a sequence that is "pinned and behavior-load-bearing", ending "Do not reorder for elegance." Commit 1 inserted a step into that sequence without it appearing there.Attaching die results before
finalize_effect_chainis a real decision: finalize and the anchor then see the complete effect, exactly as they would for an ability whose table was printed inline. Attaching later would hand those two aRollDiewith an empty results vector and then mutate the result behind them. That reasoning now lives in the doc that claims to own the order.Gates
Scope held
The five
attach_die_result_branches_to_chaincall sites are untouched — they mutate an already-lowered definition and return an advanced line index, which is a different and harder problem. They are U0-28 (T10b) and U0-30/32/49 (T10d), and T10d inheritsDieResultBranchIrfrom here.One behaviour worth naming for a reviewer: the applier silently no-ops if the walk finds no terminal
RollDie. That mirrors the existingattach_die_result_branches_to_chain, which returns early on the same condition — house convention rather than a new failure mode, and unreachable from the single producer, which always builds aRollDieroot.Summary by CodeRabbit
New Features
Bug Fixes