Skip to content

Fix The Boulder, Ready to Rumble#5881

Open
mike-theDude wants to merge 2 commits into
phase-rs:mainfrom
mike-theDude:fix/issue-4729-earthbend-object-count
Open

Fix The Boulder, Ready to Rumble#5881
mike-theDude wants to merge 2 commits into
phase-rs:mainfrom
mike-theDude:fix/issue-4729-earthbend-object-count

Conversation

@mike-theDude

Copy link
Copy Markdown
Collaborator

Summary

Fixes the "where X is <object count>" earthbend misparse for The Boulder, Ready to Rumble.

parse_earthbend_count_expr only recognized the where X is <counter count>
shape. For an object-count X ("the number of creatures you control with power 4
or greater"), it fell through to the bare-X branch, which bound X to
QuantityRef::Variable{X} — resolving to 0 for a triggered ability — and
mis-read the leftover "where X is…" text as an explicit target, degrading it to
TargetFilter::Any. The trigger fired but resolved to nothing.

The where-clause handler is generalized to route any "where X is
<dynamic quantity>" through the shared building blocks parse_quantity_ref
(object counts incl. P/T restrictions, subtype counts, player-counter counts)
then parse_event_context_quantity (mana spent to cast). A matched where-clause
now always resolves to default_earthbend_target() ("target land you control"),
so no unsupported shape can re-degrade the target. Covers the whole class: The
Boulder, Rockalanche ("Forests you control"), and Toph, Greatest Earthbender
("the amount of mana spent to cast her").

Closes #4729

Files changed

  • crates/engine/src/parser/oracle_effect/imperative.rs
  • crates/engine/src/parser/oracle_tests.rs

CR references

  • CR 701.66a — Earthbend
  • CR 107.3 — an ability defines the value of X

Implementation method (required)

Method: /engine-implementer

Track

Developer

LLM

Model: claude-opus-4-8
Thinking: high

Tier: Frontier

Verification

  • Required checks ran clean, or the exact CI-owned alternative is stated below.

  • Gate A output below is for the current committed head.

  • Final review-impl below is clean for the current committed head.

  • Both anchors cite existing analogous code at the same seam.

  • cargo fmt --all — clean

  • parser combinator gate (Gate A + Gate G) — PASS

  • parser lib tests — 8191 PASS

  • cargo clippy -p engine --lib — clean

  • earthbend tests — 15 pass, 5 new (object-count-with-power-restriction,
    subtype count, mana-spent, unrecognized-where-clause-keeps-default-target,
    end-to-end The Boulder synthesis: Animate→land target + PutCounter→ObjectCount count)

Gate A

Gate A PASS head=68cb1e61531c53f036fbad592dc048f7cae26a04 base=c0d7e0f3a5d65c22b475491f0556a2655777980f

Anchored on

  • crates/engine/src/parser/oracle_effect/imperative.rs — sibling parse_earthbend_params already delegates a dynamic count to parse_quantity_ref; the new where-clause branch mirrors that building-block delegation
  • crates/engine/src/parser/oracle_effect/mod.rs — try_parse_earthbend_clause threads the parsed (target, count) into Effect::Animate.target + Effect::PutCounter.count; the fix changes only what the count parser returns, reusing this wiring unchanged

Final review-impl

Final review-impl PASS head=68cb1e61531c53f036fbad592dc048f7cae26a04

Claimed parse impact

  • The Boulder, Ready to Rumble
  • Rockalanche
  • Toph, Greatest Earthbender

Validation Failures

None.

CI Failures

None.

🤖 Generated with Claude Code

…d keeps the land target (phase-rs#4729)

The Boulder, Ready to Rumble ("earthbend X, where X is the number of
creatures you control with power 4 or greater") only recognized the
counter-count where-clause shape. Object counts fell through to the
bare-X branch, binding X to Variable{X} (resolves to 0 for a triggered
ability) and mis-reading the trailing "where X is …" text as an explicit
target, degrading it to TargetFilter::Any.

Generalize parse_earthbend_count_expr to route any "where X is <quantity>"
through the shared parse_quantity_ref (object counts incl. P/T
restrictions, subtype counts, player-counter counts) then
parse_event_context_quantity (mana spent to cast). A matched where-clause
now always resolves to default_earthbend_target(), so no unsupported
shape can re-degrade the target. Covers The Boulder, Rockalanche, and
Toph, Greatest Earthbender.

CR 701.66a (Earthbend) + CR 107.3 (an ability defines the value of X).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the needs-maintainer AI-contribution PR requires human triage (Non-dev track or unresolved gaps) label Jul 15, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the MTG engine's parser for earthbend effects to properly handle general 'where X is ' clauses in accordance with CR 701.66a and CR 107.3. Instead of degrading the target to TargetFilter::Any and failing to parse complex quantities, the parser now routes the clause through shared quantity parsers (parse_quantity_ref and parse_event_context_quantity) and correctly preserves the default earthbend target ('target land you control'). Comprehensive unit and integration tests have been added to verify these changes. There are no review comments to assess, and no additional feedback is provided.

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.

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown

Parse changes introduced by this PR · 6 card(s), 1 signature(s) (baseline: main b81c77f71e86)

6 card(s) · ability/Animate · field target: any targetyou control land

Examples: Beifong's Bounty Hunters, Bumi's Feast Lecture, Rockalanche (+3 more)

1 card(s) had Oracle-text changes (errata/reprint) — excluded as non-parser.

@matthewevans matthewevans left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: Changes requested

🔴 Blocker

  • parse_earthbend_count_expr now accepts every Earthbend X, where X is … clause, but an unrecognized quantity is deliberately lowered to QuantityRef::Variable("X") (crates/engine/src/parser/oracle_effect/imperative.rs:561-572). In triggered abilities that variable has no announced spell-cost X and resolves to 0, so the card is reported as parsed/supported while applying the wrong number of counters. The new glorbs test codifies that silent fallback (imperative.rs:14999-15023). Keep the default land target, but preserve an Effect::Unimplemented/strict-failure marker when the where-body cannot be parsed, rather than accepting the full clause with a fake X value.

🟡 Non-blocking

  • None.

✅ Clean

  • No additional findings.

Recommendation: Please address the unsupported-where-clause fallback, then request re-review.

@matthewevans matthewevans added the bug Bug fix label Jul 15, 2026
…gap, not a fake Variable{X} (phase-rs#4729)

Addressing matthewevans's review on PR phase-rs#5881: parse_earthbend_count_expr
accepted every "earthbend X, where X is …" clause, lowering an
unrecognized quantity to QuantityRef::Variable("X"). In a triggered
ability that X has no announced spell-cost value and resolves to 0, so the
card was reported as parsed/supported while applying the wrong number of
counters — a well-typed lie.

parse_earthbend_count_expr now returns Option; a present-but-unparseable
where-body yields None, and try_parse_earthbend_clause surfaces an honest
Effect::unimplemented("where_x_binding", …) gap so coverage counts the
card as unsupported until the quantity is handled. Recognized quantities
(object counts incl. P/T restrictions, subtype counts, player-counter
counts, mana-spent-to-cast) and the genuine bare "earthbend X" spell-cost
path are unchanged. The prior test that codified the silent Variable{X}
fallback now asserts the strict failure, plus an end-to-end assertion that
the clause lowers to Effect::Unimplemented.

CR 107.3 (an ability defines the value of X).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mike-theDude

Copy link
Copy Markdown
Collaborator Author

Addressed the blocker in aaa3606d4.

What changed: parse_earthbend_count_expr no longer accepts an unparseable where X is … body with a fabricated Variable{X}. It now returns Option, and a present-but-unrecognized where-body yields None. try_parse_earthbend_clause turns that None into an honest Effect::unimplemented("where_x_binding", …) gap, so coverage counts the card as unsupported until the quantity is handled — no more well-typed lie where a triggered ability silently applies 0 counters.

Unchanged: recognized quantities (object counts incl. the power 4 or greater restriction, subtype counts, player-counter counts, mana-spent-to-cast) still bind their typed value against default_earthbend_target(); and the genuine bare Earthbend X spell-cost path still resolves to Variable{X} (that X is announced at cast time, so it's correct there).

Tests: the glorbs test now asserts the strict None failure instead of the silent fallback (imperative.rs), plus a new end-to-end assertion that Earthbend X, where X is <unrecognized> lowers to Effect::Unimplemented (oracle_tests.rs).

Verification on the new head: cargo fmt clean · parser combinator gate PASS · 8192 parser lib tests pass · cargo clippy -p engine --lib clean · 16 earthbend tests pass.

Ready for re-review.

@matthewevans matthewevans self-assigned this Jul 15, 2026

@matthewevans matthewevans left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: Changes requested

🔴 Blocker

  • The new coverage is still parser/AST-only for The Boulder. Please add one runtime witness that parses the card's actual attack trigger, extracts the Earthbend PutCounter.count, and resolves it against a board with exactly two qualifying friendly creatures (power 4 and 6), one non-qualifying friendly creature (power 3), and an opponent's qualifying creature. Assert 2. This must fail for the prior unbound-X behavior (0), for a dropped power restriction (3), and for a dropped controller restriction (4). counters::resolve_add consumes this quantity through resolve_quantity_with_targets, so this protects the reported counter-resolution behavior rather than merely its AST shape.

🟡 Non-blocking

  • Update the parse_earthbend_count_expr dispatch-order doc comment: it still says unknown shapes become Fixed { value: 0 }, but the implementation now returns None for an unrecognized present where X is … body and the caller emits Effect::Unimplemented.

✅ Clean

  • The strict-failure change itself is correct: recognized bodies route through the shared quantity parsers, preserve the default target land you control, and no longer silently accept an unknown where X is … quantity as an unbound X.

Recommendation: Add the focused runtime witness and align the contract comment, then request re-review.

@matthewevans matthewevans removed their assignment Jul 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Bug fix needs-maintainer AI-contribution PR requires human triage (Non-dev track or unresolved gaps)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The Boulder doesn't Earthbend on attack — The Boulder should be letting me Earthbend X on attack, and the trigger does…

3 participants