Skip to content

fix(parser): UNSUPPORTED seam: Each-player simultaneous choice of a left-neighbor's creature + copy-#5767

Merged
matthewevans merged 2 commits into
phase-rs:mainfrom
ntindle:fix/who-misparse-114-unsupported-seam-each-player
Jul 14, 2026
Merged

fix(parser): UNSUPPORTED seam: Each-player simultaneous choice of a left-neighbor's creature + copy-#5767
matthewevans merged 2 commits into
phase-rs:mainfrom
ntindle:fix/who-misparse-114-unsupported-seam-each-player

Conversation

@ntindle

@ntindle ntindle commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes a parser misparse affecting 1 card(s) in the Doctor Who Commander precons.

Root cause: UNSUPPORTED seam: Each-player simultaneous choice of a left-neighbor's creature + copy-token with an added ability

Cards corrected

  • Caught in a Parallel Universe

Fix

Implemented cluster 114 (Caught in a Parallel Universe) per the approved plan by parameterizing the single hardcoded eligibility axis of Effect::EachPlayerCopyChosen with a new typed leaf enum CopyChooseScope { Chooser, Neighbor { direction: SeatDirection } } and extending the whole-body parser to recognize the seat-relative choose clause.

Layers touched: (1) types/ability.rs — added CopyChooseScope enum (documenting the deliberate divergence from ControllerRef: generative battlefield enumeration bypasses the controller_ref_player filter-predicate path, and adding a seat variant to ControllerRef's ~177 exhaustive arms would cost every unrelated subsystem for a 2-card class) plus a #[serde(default)] choose_scope field on the variant; (2) types/game_state.rs — mirrored choose_scope onto WaitingFor::EachPlayerCopyChosenSelection and PendingEachPlayerCopyChosen for live revalidation and replacement-pause resume; (3) game/effects/each_player_copy_chosen.rs — new pool_controller() resolving scope+chooser via the existing players::neighbor CR 102.1/103.1 authority, threaded through compute_eligible / is_live_eligible_choice / CopyChosenParams / make_pending; (4) game/engine_resolution_choices.rs — SelectTargets round-trip threads choose_scope; (5) parser/oracle_target.rs — new shared pub(crate) parse_neighbor_seat_direction combinator (accepts their|your × left|right) with the two inline TargetFilter::Neighbor arms refactored to delegate (Boy-Scout dedup); (6) parser/oracle_effect/mod.rs — controller-clause dispatch via composed nom alt (they control -> Chooser, controlled by the player to their L/R -> Neighbor), fail-closed; (7) full-field arm updates in ability_scan.rs and ability_rw.rs; (8) frontend types.ts optional choose_scope field (modal ignores it).

The parser is nom-combinator-only (no string dispatch added). oracle-gen export confirms Caught now lowers to EachPlayerCopyChosen{choose_scope: Neighbor{Left}, copy_modifications:[AddKeyword(Menace)], min:1, max:1}, player_scope All, sub_ability None, with no Unimplemented.

Tests: converted the locked deferred-gap trigger test into a positive test asserting the true post-fix shape; updated the Human—Time Lord full-field destructure to assert CopyChooseScope::Chooser; added a parser building-block test (Neighbor{Right} + flying, class-level not card-level); added a parse_neighbor_seat_direction unit test (both possessives x both directions + fail-closed); added a 3-player resolver direction-correctness runtime proof (each token copies the left neighbor's distinct creature — a Left->Right swap would fail it) and a 2-player neighbor-pool prompt + CR 608.2c live-revalidation runtime proof.

Verification (worktree runs cargo directly, no Tilt): cargo fmt clean; cargo clippy -p engine -p phase-ai -p engine-wasm -- -D warnings finished clean (no --all-targets per disk ceiling, still compiles the phase-ai/engine-wasm libs where non-exhaustive matches surface); cargo test -p engine each_player_copy_chosen = 13 passed incl 3 new; caught/neighbor/existing-target tests pass; cargo test -p phase-ai passes; check-parser-combinators.sh exit 0; parser diff gate clean (only a typed Vec::contains in a test assertion). CR annotations grep-verified against docs/MagicCompRules.txt: 101.4 (APNAP), 102.1, 103.1, 707.2, 608.2c. Deviation: cargo coverage / cargo semantic-audit not run due to the worktree disk ceiling (100% used, ~3-4GiB free; they recompile under different feature flags and risk ENOSPC) — their signal for this card (no Unimplemented) is confirmed directly by the oracle-gen full-card export. No stop-and-return items, no CR ambiguity, no scope expansion. Changes left uncommitted.

Files changed

  • crates/engine/src/types/ability.rs
  • crates/engine/src/types/game_state.rs
  • crates/engine/src/game/effects/each_player_copy_chosen.rs
  • crates/engine/src/game/engine_resolution_choices.rs
  • crates/engine/src/game/ability_scan.rs
  • crates/engine/src/game/ability_rw.rs
  • crates/engine/src/parser/oracle_target.rs
  • crates/engine/src/parser/oracle_effect/mod.rs
  • crates/engine/src/parser/oracle_effect/tests.rs
  • crates/engine/src/parser/oracle_trigger_tests.rs
  • client/src/adapter/types.ts

CR references

  • CR 101.4
  • CR 102.1
  • CR 103.1
  • CR 707.2
  • CR 608.2c
  • CR 312.5
  • CR 205.4
  • CR 702.111a

Verification

  • cargo fmt --all — clean — no files changed, nothing to commit
  • check-parser-combinators.sh (base=7e1ddc9b merge-base upstream/main) — Gate A PASS, exit 0
  • cargo clippy -p engine -p phase-ai -p engine-wasm -- -D warnings — clean, exit 0 — all four crates (engine, phase-ai, seat-reducer, engine-wasm) checked, no warnings; exhaustive matches over EachPlayerCopyChosen variant compile
  • cargo test -p engine -p phase-ai — exit 0 — all tests passed, 0 failed across every suite
  • oracle-gen data --filter 'caught in a parallel universe' — parses correctly — AST matches oracle text
    Cards confirmed re-parsed correctly: caught in a parallel universe

🤖 Generated with Claude Code

@ntindle
ntindle requested a review from matthewevans as a code owner July 13, 2026 23:55
@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!

@github-actions

Copy link
Copy Markdown

Parse changes introduced by this PR · 1 card(s), 2 signature(s) (baseline: main 7e1ddc9b778c)

1 card(s) · ability/EachPlayerCopyChosen · added: EachPlayerCopyChosen

Examples: Caught in a Parallel Universe

1 card(s) · ability/choose · removed: choose

Examples: Caught in a Parallel Universe

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

@matthewevans matthewevans self-assigned this Jul 14, 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 left/right eligibility scope is parameterized at the existing copy-choice seam and has discriminating multiplayer coverage.

🔴 Blocker

  • None.

🟡 Non-blocking

  • None.

✅ Clean

  • each_player_copy_chosen.rs:835-912 uses a three-player ring with distinct powers, so reversing left/right would fail; the companion prompt test verifies live revalidation rejects the chooser's own creature and accepts the neighbor's.
  • oracle_effect/mod.rs:23680-23783 composes the existing nom seat-direction parser, and CopyChooseScope is carried through waiting, resume, and adapter state. The current parse artifact affects only Caught in a Parallel Universe as claimed.

Recommendation: approve and enqueue as an enhancement.

@matthewevans matthewevans added enhancement New feature or request quality For high-quality minimal to no-churn PRs labels Jul 14, 2026
@matthewevans
matthewevans added this pull request to the merge queue Jul 14, 2026
@matthewevans matthewevans removed their assignment Jul 14, 2026
Merged via the queue into phase-rs:main with commit efe7409 Jul 14, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request quality For high-quality minimal to no-churn PRs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants