fix(parser): thread the counter rider into the 'exile one of them face down' fusion#5701
Conversation
|
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), 5 signature(s) (baseline: main
|
Match rustfmt canonical output for three spots the PR left unformatted: - wrap the Some(A | B) or-pattern in continuation_is_exile_producer - break the vec![AbilityDefinition::new(..)] call in the new fusion test - collapse the !matches!(..) assert (fits within fn_call_width) Co-authored-by: Cursor <cursoragent@cursor.com>
matthewevans
left a comment
There was a problem hiding this comment.
Request changes — the counter-rider fusion is at the right parser seam, but no runtime regression proves the counter reaches the player-selected exiled card instead of the Saga/source.
🔴 Blocker
parser/oracle_effect/sequence.rs:9389-9447constructsDig → HideawayConceal → PutCounter { ParentTarget }, and the added coverage only inspects that shape. The reported failure is resolution behavior: “Exile one of them face down with a hatching counter on it” must select one looked-at card, exile that card face down, and put the hatching counter on that card—not on The Dragon-Kami Reborn or a discarded sibling. Add aGameScenario/resolution-path regression that drives the choice and asserts the selected exile object’s counter plus the Saga’s continued zone. This must fail when the fusion or the counter-target binding is reverted.
🟡 Non-blocking
- The optional rider uses the shared counter-suffix combinator and correctly preserves the bare Gonti form; keep that generalization.
✅ Clean
parse_exile_one_of_them_face_downnow rejects only nonmatching clauses and distinguishes a bare match from a match with counter entries.- The current parse artifact is contained to The Dragon-Kami Reborn across five expected signatures; no unrelated card changed.
Recommendation: request changes — add the discriminating real-resolution regression, then re-review this as a bug fix.
…e chosen exile Adds a runtime resolution regression (addresses the PR review request): it resolves chapters I–II, answers the DigChoice, and asserts the player-selected card is exiled face down with exactly one hatching counter while the Saga stays on the battlefield with no counter. Fails when the fusion is reverted (the peek Dig surfaces no DigChoice) or when the counter-target binding is reverted (the counter rides the source Saga instead of the chosen card). Co-authored-by: Cursor <cursoragent@cursor.com>
matthewevans
left a comment
There was a problem hiding this comment.
Approve — the counter-rider fusion now has a discriminating real-resolution regression at the existing Dig continuation seam.
🔴 Blocker
- None. The prior missing runtime test is addressed on
dade59e: it resolves the full chapter, submitsDigChoice, and proves the chosen card—not the Saga—receives the hatching counter.
🟡 Non-blocking
- Gemini is quota-limited this session; the independent local/adversarial review was completed against the current head instead.
✅ Clean
- The shared counter-suffix combinator keeps the bare Gonti form intact while covering the counter-rider class.
- The current parse artifact is contained to The Dragon-Kami Reborn (one card, five expected signature changes).
- Current CI is green, and the runtime test would fail if the fusion or
ParentTargetbinding were reverted.
Recommendation: approve and enqueue as bug.
Closes #5631
Summary
The Dragon-Kami Reborn's chapters I–II read: "…Look at the top three cards of
your library. Exile one of them face down with a hatching counter on it,
then put the rest on the bottom of your library in any order."
Coverage reported this card as supported (zero
Unimplementednodes), but itresolved wrong — a silent misparse of the #1146 class. The
parse_exile_one_of_them_face_downrecognizer required end-of-clause immediatelyafter
"face down", so the CR 122.1 counter rider ("with a hatching counter on it") made it decline. With the recognizer declining, the Hideaway-stylefusion never fired: the
Digshort-circuited as akeep_count: 0pure-peek and asibling
ChangeZone { ParentTarget }exiled the trigger source itself (theSaga, with a hatching counter) instead of one of the three looked-at cards.
Per the issue, this is a recognizer extension, not new engine work: the fix
lets the recognizer accept an optional counter rider between
"face down"and theclause end, captures those counters, and threads them onto the chosen dug card
in the fused exile.
Changes
oracle_effect/sequence.rs,parse_exile_one_of_them_face_down)— now returns
Option<Vec<(CounterType, QuantityExpr)>>instead ofbool.Some(entries)signals a match (empty = the bare Gonti form; non-empty = therider's counters). The optional rider is parsed by delegating to the shared
parse_counter_suffix_body_combinator, so the whole class of"with <count> <type> counter(s) on it"shapes (a/two/X,+1/+1, keyword,named) is covered — not just
"a hatching counter".oracle_ir/ast.rs) —ContinuationAst::ExileOneOfThemFaceDowngains a
enter_with_counters: Vec<(CounterType, QuantityExpr)>field(
#[serde(default, skip_serializing_if = "Vec::is_empty")]keeps the bare-formserialization byte-stable).
oracle_effect/sequence.rs,apply_clause_continuation) — after theexisting
append_conceal_sub_ability, a newappend_counter_riders_sub_abilitiesappends a
PutCounter { target: ParentTarget }chain at the deepest sub. Becausethe
DigChoiceresolution binds the chosen (exiled) card onto the continuationchain's targets and
ParentTargetsub-abilities inherit the parent's target(mirroring
lower_put_counter_list), the counters land on the one card theplayer selected, not the Saga.
ContinuationAstmatch/matches!sites (produces_sibling_def,the
dig_continuation_*helper inoracle_effect/mod.rs) updated to the newstruct-variant shape (no wildcard fallbacks).
Why this is the right shape
enter_with_counterswas already parsed correctly onto the (buggy, discarded)sibling
ChangeZone; the only defect was that the recognizer'seofgaterejected the rider so the fusion never ran.
Digcarries no counter field andHideawayConcealcarries only a target, so the rider is applied with the existingPutCounterbuilding block chained onto the sameParentTargetthe concealalready uses — no new engine variant or field, and
apply_counter_additionalready places counters on objects regardless of zone (exile included).
Affected cards
"exile one of them face down"matches 5 cards in the full-pool sweep; 4 alreadyfired the recognizer correctly, and The Dragon-Kami Reborn was the sole decline.
The generalized rider combinator also future-proofs any later choose-one exile
that attaches a counter.
Tests
exile_one_of_them_face_down_with_counter_rider_captures_counters(the hatching rider is captured),
exile_one_of_them_face_down_bare_form_has_no_counters(bare form is a match with an empty rider), plus the updated
exile_one_of_them_without_face_down_is_not_gonti_continuation/delver_pure_peek_is_not_gonti_continuationscope guards.exile_one_of_them_face_down_counter_rider_appends_put_counter_after_conceal— asserts the fused chain is
Dig(keep_count:1, Exile) -> HideawayConceal(ParentTarget) -> PutCounter(hatching, ParentTarget).Test plan
cargo fmt --allclippy/test-enginegreen (Tilt)card-dataregenerates cleanly (The Dragon-Kami Reborn now parses to thechoose-one exile + conceal + hatching-counter shape, not a source self-exile)