fix(parser): lower "if you put a [type] onto the battlefield this way" rider (Spelunking)#4704
fix(parser): lower "if you put a [type] onto the battlefield this way" rider (Spelunking)#4704dean-alley wants to merge 1 commit into
Conversation
…" rider (Spelunking)
Spelunking's ETB rider "If you put a Cave onto the battlefield this way,
you gain 4 life." was swallowed (Condition_If), dropping the GainLife
gate and marking the Modern 4-of unsupported. The active-voice
put-onto-battlefield gate combinator
(parse_you_put_onto_battlefield_this_way_clause) already existed but was
only wired into strip_if_you_do_conditional's "when " branch, never the
leading "if " path that Spelunking's rider takes.
Compose the existing active-voice combinator into
parse_outcome_this_way_condition (the shared recognizer used by both the
leading-if and trailing-suffix paths), alongside the passive-voice
parse_zone_changed_this_way_clause it already delegates to. Both voices
now lower to the identical AbilityCondition::ZoneChangedThisWay.
This unlocks the whole "if you put a [type] onto the battlefield this
way, [bonus]" fetch/ramp payoff rider class; the type token is the only
card-specific part. The already-implemented "Lands you control enter
untapped" replacement half is unchanged.
CR 608.2c (later text references an earlier instruction; "this way") +
CR 400.7j (an effect can find an object it moved to a public zone).
Tests: unit coverage for the leading-if (Cave) and suffix (creature)
active-voice gates, plus an end-to-end parse of Spelunking asserting the
GainLife sub-ability carries ZoneChangedThisWay { Cave } with no
Unimplemented node.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request adds support for parsing active-voice "put onto the battlefield this way" conditions (such as on the card Spelunking) by updating the parser to recognize both active and passive grammatical voices, accompanied by comprehensive unit tests. The reviewer's feedback points out a violation of style guide rule R6, noting that the new parser implementation lacks mandatory CR annotations (CR 608.2c and CR 400.7j) in its documentation comments.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| /// | ||
| /// Both grammatical voices of the same event are recognized here so the leading | ||
| /// (`if …, [effect]`) and suffix (`[effect] if …`) forms produce identical | ||
| /// `ZoneChangedThisWay` conditions: | ||
| /// - passive: `a Cave (is|was) put onto the battlefield this way` — | ||
| /// `parse_zone_changed_this_way_clause` | ||
| /// - active: `you put a Cave onto the battlefield this way` — | ||
| /// `parse_you_put_onto_battlefield_this_way_clause` (Spelunking's ETB | ||
| /// rider "If you put a Cave onto the battlefield this way, you gain 4 life"; | ||
| /// unlocks the whole "if you put a [type] onto the battlefield this way, | ||
| /// [bonus]" fetch/ramp payoff class). |
There was a problem hiding this comment.
[MED] Missing mandatory CR annotations on new game-rule parser implementation. Evidence:
crates/engine/src/parser/oracle_effect/conditions.rs:5024.
Why it matters: The repository style guide (R6) requires all rules-touching engine code to carry verified CR annotations to ensure strict fidelity to the MTG Comprehensive Rules.
Suggested fix: AddCR 608.2candCR 400.7jannotations to the doc comment.
///
/// CR 608.2c: Later text on a card may reference an earlier instruction in the same effect ("this way").
/// CR 400.7j: If an effect causes an object to move to a public zone, other parts of that effect can find that object.
///
/// Both grammatical voices of the same event are recognized here so the leading
/// (if ..., [effect]) and suffix ([effect] if ...) forms produce identical
/// ZoneChangedThisWay conditions:
/// - passive: a Cave (is|was) put onto the battlefield this way -
/// parse_zone_changed_this_way_clause
/// - active: you put a Cave onto the battlefield this way -
/// parse_you_put_onto_battlefield_this_way_clause (Spelunking's ETB
/// rider "If you put a Cave onto the battlefield this way, you gain 4 life";
/// unlocks the whole "if you put a [type] onto the battlefield this way,
/// [bonus]" fetch/ramp payoff class).
References
- Every rules-touching line of engine code must carry a comment of the form CR : . (link)
matthewevans
left a comment
There was a problem hiding this comment.
[LOW] Function-local imports violate the repo's no-inline-import rule. Evidence: crates/engine/src/parser/oracle_effect/conditions.rs:5036. Why it matters: the repository explicitly requires all imports at file scope, and this new parser path adds a local use inside rule-touching code. Suggested fix: move parse_you_put_onto_battlefield_this_way_clause and parse_zone_changed_this_way_clause imports to the module import section or call them through the module path.
Reviewed current head a440c57f36d693967a4e0cb08aaeaf54f21891c0.
Summary
Fixes Spelunking (LCI, Modern 4-of). Its ETB rider — "If you put a Cave onto the battlefield this way, you gain 4 life." — was swallowed (
Condition_If), which dropped theGainLifegate and marked the cardsupported: false. The rest of the card already worked on HEAD (theLands you control enter untappedreplacement half; thedraw a card, then you may put a land card…stem).Oracle text:
When this enchantment enters, draw a card, then you may put a land card from your hand onto the battlefield. If you put a Cave onto the battlefield this way, you gain 4 life.\nLands you control enter untapped.Root cause
The active-voice put-onto-battlefield gate combinator
parse_you_put_onto_battlefield_this_way_clausealready existed, but was only wired intostrip_if_you_do_conditional'swhenbranch — never the leadingifpath that Spelunking's rider takes. Soyou put a Cave onto the battlefield this wayreached only the passive-voice recognizer (a Cave is/was put …) and failed to lower.Fix
Compose the existing active-voice combinator into
parse_outcome_this_way_condition— the shared recognizer reached by both the leading-if(strip_leading_general_conditional→try_nom_condition_as_ability_condition) and trailing-suffix paths — alongside the passive-voiceparse_zone_changed_this_way_clauseit already delegated to. Both grammatical voices now lower to the identicalAbilityCondition::ZoneChangedThisWay.Parser-only, additive (a fallback
altbranch), no change to the sacrificed/exiled/discarded or passive-voice paths.Build for the class
This unlocks the whole "if you put a [type] onto the battlefield this way, [bonus]" fetch/ramp payoff rider class — the verb arm is the reusable unit and the type token (
Cave) is the only card-specific part.CR
Tests
leading_you_put_a_cave_onto_battlefield_spelunking— leading-ifactive-voice gate →ZoneChangedThisWay { Cave }.outcome_you_put_a_creature_onto_battlefield_active_voice— suffix-form active-voice gate stays in lockstep.spelunking_etb_put_cave_gains_life_conditionally— end-to-endparse_oracle_textof the full card:GainLifesub-ability carriesZoneChangedThisWay { Cave }, noUnimplementednode, replacement half still parses.cargo fmt --allclean;cargo clippy -p engine --libclean; the fullparser::oracle_effect::conditionsunit suite (95 tests) passes.🤖 Generated with Claude Code