Skip to content

fix(parser): quote-aware choice-list splitter so nested-token abilities aren't a modal choice (#4230)#4635

Merged
matthewevans merged 2 commits into
phase-rs:mainfrom
minion1227:minion_4230
Jun 30, 2026
Merged

fix(parser): quote-aware choice-list splitter so nested-token abilities aren't a modal choice (#4230)#4635
matthewevans merged 2 commits into
phase-rs:mainfrom
minion1227:minion_4230

Conversation

@minion1227

Copy link
Copy Markdown
Contributor

Problem

Reef Worm (#4230) creates a single cascading token:

When this creature dies, create a 3/3 blue Fish creature token with "When this token dies, create a 6/6 blue Whale creature token with 'When this token dies, create a 9/9 blue Kraken creature token.'"

The HEAD parser misread this as a modal token choiceEffect::ChooseOneOf over three distinct tokens (Fish / Whale / Kraken) — instead of one Fish token carrying a quoted death-triggered ability. At runtime that offers the player a choice of which single token to make, so the cascade never happens.

Root cause

try_parse_create_token_choice uses split_choice_list_items to split create A, B, or C token into ChooseOneOf branches. The splitter's item combinator was not quote-aware: parse_choice_list_separator matched the , inside the quoted granted ability ("When this token dies, create …"), severing one cascading token into three bogus branches (and double-emitting create).

Fix

The choice-list item combinator now consumes a double-quoted span as one opaque unit, so a ,/or inside quoted granted-ability text can never fabricate extra branches. With Reef Worm there is no separator outside the quotes, so the splitter yields a single item, try_parse_create_token_choice declines (needs ≥2), and the normal single-token-with-quoted-ability grammar parses the cascade correctly.

  • Genuine unquoted token/counter disjunctions (create a Food token or a Treasure token; counter-choice lists) are unchanged — they contain no double quotes.
  • A real disjunction where one branch carries a quoted ability still splits correctly (covered by test).
  • Bare apostrophes (possessives like owner's) are untouched — only double-quoted spans are special-cased, and the nested single quotes here are always inside a double-quoted span.

CR 608.2d (choose-one token instructions) + CR 113.3 (granted abilities).

Tests

  • split_choice_list_items_is_quote_aware — building-block test: a quoted ability with an inner comma stays one item; genuine disjunctions still split; a mixed list (one quoted branch) splits at the real separator.
  • reef_worm_nested_token_is_not_modal_choice — Reef Worm parses to a single Effect::Token { name: "Fish", .. }, not ChooseOneOf.

Full engine lib suite green (14227 passed, 0 failed); clippy -D warnings clean.

Closes #4230

🤖 Generated with Claude Code

…es aren't a modal choice (phase-rs#4230)

Reef Worm creates a single cascading Fish token whose quoted death-triggered
ability itself creates a Whale (which creates a Kraken). `split_choice_list_items`
split on the `, ` inside that quoted ability text, so `try_parse_create_token_choice`
misread one cascading token as a `ChooseOneOf` of three distinct tokens
(Fish/Whale/Kraken). The choice-list item combinator now consumes a double-quoted
span as one opaque unit, so a `,`/`or` inside quoted granted-ability text never
fabricates extra branches. Genuine unquoted token/counter disjunctions are
unchanged, and bare apostrophes (possessives) are untouched.

CR 608.2d (choose-one token instructions) + CR 113.3 (granted abilities).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@minion1227 minion1227 requested a review from matthewevans as a code owner June 30, 2026 06:14
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@matthewevans matthewevans self-assigned this Jun 30, 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.

Reviewed the parser change at the updated head. The fix is at the shared choice-list splitter, preserves top-level token/counter disjunction behavior, and covers the Reef Worm nested quoted-token regression with a discriminating parser test.

@matthewevans matthewevans added the bug Bug fix label Jun 30, 2026
@matthewevans matthewevans enabled auto-merge June 30, 2026 06:18
@matthewevans matthewevans removed their assignment Jun 30, 2026
@matthewevans matthewevans added this pull request to the merge queue Jun 30, 2026
@github-actions

Copy link
Copy Markdown

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

3 card(s) · ability/ChooseOneOf · removed: ChooseOneOf

Examples: Fable of the Mirror-Breaker, Reef Worm, Wolf's Quarry

1 card(s) · ability/Token · added: Token (token=+2/+2 Red Goblin Shaman (Creature Goblin Shaman))

Examples: Fable of the Mirror-Breaker

1 card(s) · ability/Token · added: Token (token=+3/+3 Blue Fish (Creature Fish))

Examples: Reef Worm

1 card(s) · ability/Token · added: Token (token=3× +1/+1 Green Boar (Creature Boar))

Examples: Wolf's Quarry

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

Merged via the queue into phase-rs:main with commit 90c1ff9 Jun 30, 2026
11 checks passed
@minion1227 minion1227 deleted the minion_4230 branch July 2, 2026 11:05
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.

reef worm — not working properly.

3 participants