Skip to content

fix(parser): compose Class-level trigger conditions instead of overwriting them (#5638)#6021

Merged
matthewevans merged 2 commits into
phase-rs:mainfrom
nghetienhiep:fix/issue-5638
Jul 16, 2026
Merged

fix(parser): compose Class-level trigger conditions instead of overwriting them (#5638)#6021
matthewevans merged 2 commits into
phase-rs:mainfrom
nghetienhiep:fix/issue-5638

Conversation

@nghetienhiep

Copy link
Copy Markdown
Contributor

fix(parser): compose Class-level trigger conditions instead of overwriting them (#5638)

parse_class_oracle_text gated level-2+ triggers by unconditionally
assigning trigger.condition = ClassLevelGE, which silently dropped any
printed intervening-if already parsed onto the trigger. Intermediate
Chirography's level-3 ability ("if a modified creature died under your
control this turn") lost its death check entirely and always created
a token at end step. Compose with TriggerCondition::And instead,
mirroring the existing static/replacement class-level wrappers.

Closes #5638

…iting them (phase-rs#5638)

parse_class_oracle_text gated level-2+ triggers by unconditionally
assigning trigger.condition = ClassLevelGE, which silently dropped any
printed intervening-if already parsed onto the trigger. Intermediate
Chirography's level-3 ability ("if a modified creature died under your
control this turn") lost its death check entirely and always created
a token at end step. Compose with TriggerCondition::And instead,
mirroring the existing static/replacement class-level wrappers.

Closes phase-rs#5638

@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 fixes a bug where class-level triggers with printed intervening-if conditions had their conditions unconditionally overwritten by the class level gate. The fix introduces wrap_trigger_with_class_level to compose both conditions using TriggerCondition::And instead of overwriting, and updates the corresponding tests and fixtures. The review feedback suggests flattening nested TriggerCondition::And structures to improve composability and using structured fields instead of fragile substring matching in tests.

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.

Comment thread crates/engine/src/parser/oracle_class.rs
Comment on lines +424 to +428
.find(|t| {
t.description
.as_deref()
.is_some_and(|d| d.contains("end step"))
})

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.

medium

Locating the trigger by searching for the substring "end step" in its description is a bit fragile. This could break if the description text is changed in the future. A more robust approach would be to match on the structured TriggerDefinition fields, such as mode and phase, which are less likely to change.

            .find(|t| {
                t.mode == crate::types::triggers::TriggerMode::Phase
                    && t.phase == Some(crate::types::phase::Phase::End)
            })

@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown

Parse changes introduced by this PR · 4 card(s), 4 signature(s) (baseline: main f627d925ccdf)

1 card(s) · trigger/Phase · field condition: class level ≥ 2class level ≥ 2 and cards in hand (scoped player) ≤ 1

Examples: Bandit's Talent

1 card(s) · trigger/Phase · field condition: class level ≥ 3class level ≥ 3 and modified in battlefield you control creature zone changes this turn (Some(Battlefield)->Some(Gravey…

Examples: Intermediate Chirography

1 card(s) · trigger/Phase · field condition: class level ≥ 3class level ≥ 3 and you control power ≥4 in battlefield you control creature

Examples: Hunter's Talent

1 card(s) · trigger/SpellCast · field condition: class level ≥ 3class level ≥ 3 and mana spent to cast (TriggeringSpell, FromSource { source_filter: Typed(TypedFilter { type_filters: …

Examples: Alchemist's Talent

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

…evel trigger

Addresses Gemini review feedback on PR phase-rs#6021 (issue phase-rs#5638):
- wrap_trigger_with_class_level now flattens into the existing And's
  conditions vec instead of nesting a new And around it, matching the
  composability convention used elsewhere in this module.
- the level-3 trigger regression test now locates the end-step trigger
  by its structured mode/phase fields instead of a fragile substring
  match on the rendered description.
@matthewevans matthewevans self-assigned this Jul 16, 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.

Approved: the Class-level gate now composes with each printed intervening-if at the parser authority, and the current parse-diff is limited to the four expected Class triggers.

@matthewevans matthewevans added the bug Bug fix label Jul 16, 2026
@matthewevans
matthewevans added this pull request to the merge queue Jul 16, 2026
@matthewevans matthewevans removed their assignment Jul 16, 2026
Merged via the queue into phase-rs:main with commit d967ef6 Jul 16, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Intermediate Chirography: live Duration_ThisTurn swallow warning, untriaged — 'died under your control this turn' condition

2 participants