fix(parser): recognize "dealt damage to another creature this turn" intervening-if#5726
Conversation
There was a problem hiding this comment.
Code Review
This pull request extends the parser in crates/engine/src/parser/oracle_nom/condition.rs to support parsing damage dealt to creatures (e.g., "another creature", "a creature") in addition to players and opponents, and adds corresponding unit tests. The review feedback suggests renaming the extended function parse_source_dealt_damage_to_opponent_this_turn to reflect its broader scope, and adding sibling coverage for planeswalker targets to ensure completeness.
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.
| // player/opponent/creature this turn" — the *dealing* direction (source = the | ||
| // ability's own permanent). "it" is the source anaphor for triggered-ability |
There was a problem hiding this comment.
[MEDIUM] Misleading function name after extending target types. Evidence: crates/engine/src/parser/oracle_nom/condition.rs:403. Why it matters: The function now parses players, opponents, and creatures, making the "to_opponent" suffix in the name misleading and harder to find. Suggested fix: Rename the function to parse_source_dealt_damage_this_turn and update its call sites.
References
- Pillar 1: Idiomatic Rust — uses the type system, ownership model, and standard library idioms to their fullest. Clean, accurate naming is essential for maintainability. (link)
| value( | ||
| TargetFilter::Typed(TypedFilter::creature().properties(vec![FilterProp::Another])), | ||
| tag("another creature"), | ||
| ), | ||
| value( | ||
| TargetFilter::Typed(TypedFilter::creature()), | ||
| alt((tag("a creature"), tag("creature"))), | ||
| ), |
There was a problem hiding this comment.
[MEDIUM] Missing sibling coverage for planeswalker targets. Evidence: crates/engine/src/parser/oracle_nom/condition.rs:427. Why it matters: To ensure composable building blocks (Pillar 3) and complete sibling coverage (L2), the parser should also support damage dealt to planeswalkers, which are also damageable permanents. Suggested fix: Add similar parser arms for "another planeswalker" and "a planeswalker" / "planeswalker".
References
- Pillar 3: Composable building blocks — every new enum variant, parser arm, effect handler, or filter handles a category of cards, not a single card. No special cases dressed as primitives. (link)
Parse changes introduced by this PR · 1 card(s), 1 signature(s) (baseline: main
|
matthewevans
left a comment
There was a problem hiding this comment.
Request changes — the parser extension is on the existing damage-history seam, but this behavioral fix needs an end-to-end trigger test and the current head fails Rust lint.
🔴 Blocker
crates/engine/src/parser/oracle_trigger_tests.rs:1501-1503failsclippy::doc_lazy_continuationin the current CI run: the doc lines followingWolverine'sare interpreted as an unindented list. Please make the comment a valid paragraph (or use normal//comments) and rerun the required lint gate.crates/engine/src/parser/oracle_trigger_tests.rs:1505-1544proves only the parsedTriggerDefinition. This change governs an intervening-if's trigger detection and resolution, so add aGameScenario/actual apply-path regression: Wolverine deals damage to another creature → its end-step trigger puts the counter on Wolverine, plus a negative case where it dealt no qualifying damage and no counter is placed. Parser-shape tests alone would still pass if that runtime path stopped evaluatingDamageDealtThisTurn(SelfRef → Another creature).
🟡 Non-blocking
crates/engine/src/parser/oracle_nom/condition.rs:400still names the now-broader helperparse_source_dealt_damage_to_opponent_this_turn; rename it to describe its source-dealt-damage scope.
✅ Clean
- The parse-diff artifact for this head shows exactly the intended one-card condition change (Wolverine), and the new
Anotherfilter is evaluated source-relatively by the existing damage-record matcher.
Recommendation: request changes — fix CI and add the discriminating runtime regression, then rebase onto current main for a fresh review.
33613ab to
ed8a005
Compare
…ntervening-if
Wolverine, Best There Is ("At the beginning of each end step, if Wolverine
dealt damage to another creature this turn, put a +1/+1 counter on him")
parsed with condition: null -- the intervening-if was swallowed, so the
counter was placed unconditionally.
Extend the dealing-direction source-dealt-damage condition combinator
(renamed parse_source_dealt_damage_this_turn) target axis with "another
creature"/"a creature" (Typed{Creature, [Another]}), alongside the existing
player/opponent targets. The clause lifts to TriggerCondition::QuantityComparison
over QuantityRef::DamageDealtThisTurn(SelfRef -> another creature) >= 1; the
runtime damage-record target matcher already handles creature targets.
Tests: 2 parser AST tests + a GameScenario runtime regression (Wolverine deals
combat damage to a creature -> end-step trigger places the counter; negative:
damage to a player only -> no counter).
CR 120.1 (source of damage), CR 603.4 (intervening-if).
ed8a005 to
cb09bcd
Compare
matthewevans
left a comment
There was a problem hiding this comment.
Approved — the current head resolves the prior blockers and is ready for the merge queue.
🔴 Blocker
- None.
🟡 Non-blocking
- Gemini's planeswalker suggestion is intentionally not expanded here: the official Scryfall exact-phrase searches return no cards, while the current parse artifact is exactly Wolverine.
✅ Clean
- The helper was renamed for its widened source-damage scope.
- The current parse artifact changes exactly Wolverine's intervening-if condition.
- The paired
GameScenarioregressions prove both the qualifying creature-damage path and the non-vacuous player-damage negative path through end-step trigger resolution. - All required current-head GitHub checks are green.
Recommendation: approve and enqueue through the merge queue.
Bug: Wolverine, Best There Is ("At the beginning of each end step, if Wolverine dealt damage to another creature this turn, put a +1/+1 counter on him") parsed with
condition: null— the intervening-if was swallowed, so the counter was placed unconditionally.Fix: Extend the dealing-direction source-dealt-damage condition combinator's target axis with
"another creature"/"a creature"(Typed{Creature, [Another]}), alongside the existing player/opponent targets. The clause now lifts toTriggerCondition::QuantityComparisonoverQuantityRef::DamageDealtThisTurn(SelfRef → another creature) ≥ 1; the runtime damage-record target matcher already handles creature targets. A pure-addition extension of one existing combinator — no new variant, no runtime change. Verified locally: both new parser tests pass, 96dealt-family sibling tests stay green, clippy clean.CR 120.1 (source of damage), CR 603.4 (intervening-if).