fix(parser): lower the next-cast copy in the possessive word order (CR 603.7) - #5720
Merged
Conversation
…R 603.7)
Twinferno's "When you CAST YOUR NEXT instant or sorcery spell this turn, copy
that spell." produced no delayed trigger at all — the copy was dropped outright,
and its "You may choose new targets for the copy" sentence was left as an honest
`orphaned_copy_retarget` residual. The orphan was the symptom, not the disease:
the retarget clause was correctly refusing to bind to a copy that did not exist.
`try_parse_when_next_event` dispatched on `alt((tag("when you next cast a "),
tag("when you next cast an ")))`. Magic prints this one clause in two word orders
and we only accepted the adverbial one:
"when you NEXT CAST a[n] <spell> this turn" Galvanic Iteration, Doublecast
"when you CAST YOUR NEXT <spell> this turn" Twinferno
Add the possessive opening to that `alt`. The payload after either opening is the
same "[type-phrase] spell [post-modifier]" shape, so `extract_when_next_spell_filter`
and every downstream stage are untouched — this parameterizes the opening rather
than proliferating a second parser for the same clause.
Filed under #62, whose premise this partly FALSIFIES: the task described Twinferno
as a MODAL-nesting gap ("copy not lowered inside a modal delayed trigger"). It is
not. Modes are irrelevant — the identical text outside a mode fails the same way,
and the identical text in the adverbial word order inside a mode works. The gap is
purely the opening's word order.
Honest scope, measured rather than assumed: "cast your next" appears on 3 cards in
the pool, but Flaming Fist Duskguard and Valiant Farewell print it inside a quoted
boon with no " this turn, " delimiter, so they stay gapped and this fix does not
claim them. The measured delta is 1 face.
Full-pool dual export (35,396 faces), whole-face structural diff — every face's
ENTIRE tree compared, not just the copy-retarget channel:
faces with ANY structural change: 1
twinferno retargets=[] orphans=1 -> retargets=[MayChooseNewTargets] orphans=0
Zero regressions. Positive controls Galvanic Iteration and Doublecast unchanged.
Pool-wide `orphaned_copy_retarget` residuals: 7 -> 5.
matthewevans
enabled auto-merge
July 13, 2026 04:03
Contributor
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
Parse changes introduced by this PR · 1 card(s), 2 signature(s) (baseline: main
|
matthewevans
added a commit
to jaytbarimbao-collab/phase
that referenced
this pull request
Jul 13, 2026
… parity rows it exposes (CR 603.3b + CR 603.4) (phase-rs#5732) `integration_cards.json` is a cached subset of the card-data export, but it was last FULLY regenerated at b9685cc (phase-rs#5695). Nineteen parser/types PRs merged since then; every fixture touch in between was surgical (phase-rs#5672 +1, phase-rs#5679 +2, phase-rs#5727 2 entries), so the parse values silently drifted. Regenerated from the export at 8c35dc5 (oracle-gen, MTGJSON 5.3.0+20260629). Population (json deep-equality, not line counts — the file is one line): committed 2658 entries -> 2726. 70 added, 2 removed, 44 changed values. Attribution of the 44 changed (causal: exports built at phase-rs#5720 / phase-rs#5717 / phase-rs#5730 and compared, NOT shape-guessing): phase-rs#5723 (P02-U3b shared condition grammar) ...... 3 archive trap, temple of civilization, thaumaton torpedo (all gained the comparator/lhs/rhs/qty/scope condition shape) phase-rs#5721 + phase-rs#5719 (where-X quantity channel + ..... 21 restriction grammar; both merged BEFORE phase-rs#5717 — merge order != PR-number order) bellowsbreath ogre, cryptex, deadly rollick, deflecting swat, desert, dread wanderer, esquire of the king, flesh, fraying sanity, gloomlake verge, great desert hellion, gutterbones, officious interrogation, once upon a time, potioner's trove, ribald shanty, rock jockey, second little pig, shifting woodland, snuff out, starport security phase-rs#5695..phase-rs#5720 no-regen window (bloc) ........... 20 Stale already at phase-rs#5720, so attributable to the 19-PR window above the b9685cc anchor, not to any single PR: alrund god of the cosmos, animal friend, approach of the second sun, cavernous maw, fblthp the lost, from father to son, hour of revelation, increasing vengeance, jodah the unifier, mana reflection, misty salon, puca's eye, ram through, reidane god of the worthy, secrets of the key, sevinne's reclamation, temple of the dead, the dining car, unleash the flux, valgavoth terror eater The 70 added keys are new test-source card references the generator collects; phase-rs#5729 (tests-only) contributed zero parse delta, as expected. Corrected premise: 44 entries are truly stale, not 7. Six of the seven originally reported reproduce; `osteomancer adept` is NOT stale (committed == fresh). The regen turns `ordering_parity_sweep` red, so the gate's evidence rows ship ATOMICALLY with it. Both rows are population entries, not ordering regressions: the sweep skips Unimplemented-bearing triggers, so a card only enters it once its parse binds. great desert hellion -> BATCH_GENUINE_ROWS. Its LTB Draw was Unimplemented until phase-rs#5721/phase-rs#5719 bound Intensity{Source}. Each co-departing Hellion draws off its OWN intensity but discards the SHARED hand, so the second trigger discards the cards the first just drew: with intensities a != b the final hand, graveyard and library differ by order. The members are not identical functions, so commutation genuinely fails and the new prompt is the CR 603.3b choice the legacy serde walk wrongly auto-ordered (CR 603.5: each "may" is chosen on resolution). planar collapse -> DOCUMENTED_OVER_PROMPT (L8-held family). New fixture key. Upkeep ObjectCount(Creature) >= 4 intervening-if x DestroyAll + self-Sacrifice: the first copy's sweep drives the census to 0, so the sibling's CR 603.4 re-check is false and it does nothing. Monotone and self-limiting — identical siblings commute up to relabeling, so the prompt is conservative, fail-closed and rules-correct. Neither row weakens the gate: both are direction-gated over-prompts (an under-prompt is never suppressible), and both are consumed by the ledger's exact-set asserts (over_prompt_hit 18->19, batch_genuine_hit 1->2), so a misclassification still trips the STRICT PROOF-GATE. Verification: engine lib 16481/16481 pass (was 16480 + 1 red); integration 2929/2929 pass. Co-authored-by: matthewevans <matthewevans@users.noreply.github.com>
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.
Twinferno's "When you CAST YOUR NEXT instant or sorcery spell this turn, copy
that spell." produced no delayed trigger at all — the copy was dropped outright,
and its "You may choose new targets for the copy" sentence was left as an honest
orphaned_copy_retargetresidual. The orphan was the symptom, not the disease:the retarget clause was correctly refusing to bind to a copy that did not exist.
try_parse_when_next_eventdispatched onalt((tag("when you next cast a "), tag("when you next cast an "))). Magic prints this one clause in two word ordersand we only accepted the adverbial one:
"when you NEXT CAST a[n] this turn" Galvanic Iteration, Doublecast
"when you CAST YOUR NEXT this turn" Twinferno
Add the possessive opening to that
alt. The payload after either opening is thesame "[type-phrase] spell [post-modifier]" shape, so
extract_when_next_spell_filterand every downstream stage are untouched — this parameterizes the opening rather
than proliferating a second parser for the same clause.
Filed under #62, whose premise this partly FALSIFIES: the task described Twinferno
as a MODAL-nesting gap ("copy not lowered inside a modal delayed trigger"). It is
not. Modes are irrelevant — the identical text outside a mode fails the same way,
and the identical text in the adverbial word order inside a mode works. The gap is
purely the opening's word order.
Honest scope, measured rather than assumed: "cast your next" appears on 3 cards in
the pool, but Flaming Fist Duskguard and Valiant Farewell print it inside a quoted
boon with no " this turn, " delimiter, so they stay gapped and this fix does not
claim them. The measured delta is 1 face.
Full-pool dual export (35,396 faces), whole-face structural diff — every face's
ENTIRE tree compared, not just the copy-retarget channel:
faces with ANY structural change: 1
twinferno retargets=[] orphans=1 -> retargets=[MayChooseNewTargets] orphans=0
Zero regressions. Positive controls Galvanic Iteration and Doublecast unchanged.
Pool-wide
orphaned_copy_retargetresiduals: 7 -> 5.