Skip to content

Partial: Doom's Time Platform - #7022

Merged
matthewevans merged 5 commits into
phase-rs:mainfrom
JacobWoodson:card/dooms-time-platform
Aug 9, 2026
Merged

Partial: Doom's Time Platform#7022
matthewevans merged 5 commits into
phase-rs:mainfrom
JacobWoodson:card/dooms-time-platform

Conversation

@JacobWoodson

@JacobWoodson JacobWoodson commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes a parse-fidelity defect on Doom's Time Platform.

Issue: "with two time counters on it" should place two time counters on the exiled card (enter_with_counters), but is parsed as a target-filter requiring the card to already have >=2 time counters, dropping the counter placement.

Files changed

  • crates/engine/src/parser/oracle_effect/mod.rs
  • crates/engine/src/parser/oracle_effect/imperative.rs
  • crates/engine/src/parser/oracle_effect/tests.rs
  • crates/engine/tests/integration/doom_s_time_platform_exile_with_time_counters.rs
  • crates/engine/tests/integration/main.rs

CR references

  • CR 122.1
  • CR 122.2
  • CR 400.7
  • CR 702.62a

Track

Developer

LLM

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

Tier: Frontier

Verification

  • cargo fmt --all — pass (exit 0, clean)
  • ./scripts/check-parser-combinators.sh (Gate A) — pass (Gate G PASS + Gate A PASS, exit 0; ran with real python3 at /c/msys64/mingw64/bin/python3 by removing the WindowsApps stub from PATH, so Family-D genuinely ran rather than skipped)
  • cargo clippy-strict — pass (exit 0, clean)
  • cargo test -p phase-engine — fail (exit 101; 18516 passed, 1 failed): game::engine::stage2_injector_tests::the_cr_603_5_prompt_census_is_pinned_so_a_sixth_producer_is_a_counted_event at engine.rs:15178 - deterministic Windows-only path-separator artifact, unrelated to the card, in a shared file not part of card work; not modified per multi-agent safety
  • cargo export-cards data --output client/public/card-data.json --stats --sidecar-dir client/public && cp -> data/card-data.json — pass (exit 0; corrected recipe in-loop by adding --output since the literal recipe dumps to stdout and would copy a stale file; fresh 98142340-byte file regenerated from this branch's engine)
  • cargo coverage — pass (exit 0; Doom's Time Platform supported:true gap_count:0)
  • cargo semantic-audit data — pass (exit 0; Doom's Time Platform present in audited data, 0 findings)

Scope Expansion

None.

Validation Failures

See review/cross-check notes.

CI Failures

  • cargo test -p phase-engine: 1 failing test 'game::engine::stage2_injector_tests::the_cr_603_5_prompt_census_is_pinned_so_a_sixth_producer_is_a_counted_event' (crates/engine/src/game/engine.rs:15178). Root cause is a Windows-only path-separator mismatch: the test derives file paths via Path::display() (producing backslashes, e.g. 'game\effects\mod.rs') and asserts equality against hardcoded forward-slash literals (e.g. 'game/effects/mod.rs'); the arrays are otherwise byte-identical. Deterministic (re-run confirmed identical failure), so retries cannot resolve it. The file is NOT part of the card's working-tree changes and the test is unrelated to Doom's Time Platform; not modified per CLAUDE.md multi-agent safety rules on shared files. All 18516 other engine tests pass. This is the only reason passed=false; both card-specific gates (coverage and semantic-audit) are clean.

Summary by CodeRabbit

  • Bug Fixes

    • Improved parsing of exile effects that move cards from the graveyard, hand, or library while adding counters.
    • Preserved target descriptions while applying counters when cards enter exile.
    • Kept battlefield counter conditions unchanged.
    • Ensured cards receive the intended counters during exile effect resolution.
  • Tests

    • Added coverage for counter parsing across card zones.
    • Added an integration test verifying cards are exiled with the correct number of time counters during gameplay.

Parse-diff review

Current parser artifact measured 3 affected cards / 5 signatures: Doom’s Time Platform, Altaïr Ibn-La’Ahad, and The Animus. The shared pre-target with <N> <counter> rider is the intended class; the regression matrix covers library, hand, battlefield, and non-counter siblings.

@github-actions github-actions Bot added the needs-maintainer AI-contribution PR requires human triage (Non-dev track or unresolved gaps) label Aug 5, 2026
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@matthewevans, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 5 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8bbaa621-8834-4b84-9281-0262da8f2106

📥 Commits

Reviewing files that changed from the base of the PR and between 658fe3f and 5aa771c.

📒 Files selected for processing (1)
  • crates/engine/src/parser/oracle_effect/tests.rs
📝 Walkthrough

Walkthrough

Exile parsing now separates trailing counter clauses from descriptive targets in counterless zones. The parser applies those counters when cards enter exile and preserves battlefield counter filters. Parser and integration tests cover both behaviors.

Changes

Exile counter parsing

Layer / File(s) Summary
Parse counterless-origin exile counters
crates/engine/src/parser/oracle_effect/mod.rs, crates/engine/src/parser/oracle_effect/imperative.rs, crates/engine/src/parser/oracle_effect/tests.rs
The parser extracts counter clauses from graveyard, hand, and library targets. It applies them as enter-with-counters values and preserves battlefield counter filters.
Validate exile trigger resolution
crates/engine/tests/integration/main.rs, crates/engine/tests/integration/doom_s_time_platform_exile_with_time_counters.rs
The integration test verifies that Doom’s Time Platform exiles a graveyard card with two time counters and remains on the battlefield.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Combat
  participant Doom's Time Platform
  participant Graveyard
  participant Exile zone
  Combat->>Doom's Time Platform: resolve attack trigger
  Doom's Time Platform->>Graveyard: target a nonland card
  Doom's Time Platform->>Exile zone: exile the card with two time counters
Loading

Possibly related PRs

  • phase-rs/phase#6661: Both changes modify oracle-effect exile parsing, but this PR addresses counter suffix extraction.
  • phase-rs/phase#6698: Both changes modify oracle-effect parsing and counter handling, but they address different parser functions.
  • phase-rs/phase#6735: Both changes modify shared counter parsing and target-filter logic.

Suggested labels: bug, needs-maintainer

Suggested reviewers: matthewevans

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title identifies the affected card and indicates that the pull request provides a partial implementation, matching the parser fix and integration coverage.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/engine/src/parser/oracle_effect/tests.rs`:
- Around line 35589-35664: Complete the regression matrix around the existing
exile counter tests, covering graveyard, hand, library, battlefield, and a
non-counter “with …” clause. In each origin-sensitive case, assert the parsed
target preserves the expected origin via origin or FilterProp::InZone, while
confirming only graveyard/hand/library lift counters to enter_with_counters and
battlefield retains FilterProp::Counters. Use the existing parse_effect_chain
and target pattern in the named tests.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f4dbb2a0-05a7-42fd-beb8-f57e4fa53cb4

📥 Commits

Reviewing files that changed from the base of the PR and between dd6ab09 and 0178039.

📒 Files selected for processing (5)
  • crates/engine/src/parser/oracle_effect/imperative.rs
  • crates/engine/src/parser/oracle_effect/mod.rs
  • crates/engine/src/parser/oracle_effect/tests.rs
  • crates/engine/tests/integration/doom_s_time_platform_exile_with_time_counters.rs
  • crates/engine/tests/integration/main.rs

Comment thread crates/engine/src/parser/oracle_effect/tests.rs
@matthewevans matthewevans self-assigned this Aug 5, 2026
@matthewevans matthewevans removed their assignment Aug 5, 2026
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

Generated for head 5aa771cba36a95f4860308e76fd8d888cad3cfa4.

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

🟡 Modified fields (5 signatures)

  • 2 cards · 🔄 ability/ChangeZone · changed field enter_with_counters: [(Generic("memory"), Fixed { value: 1 })]
    • Affected (first 3): Altaïr Ibn-La'Ahad, The Animus
  • 1 card · 🔄 ability/ChangeZone · changed field enter_with_counters: [(Time, Fixed { value: 2 })]
    • Affected (first 3): Doom's Time Platform
  • 1 card · 🔄 ability/ChangeZone · changed field target: in graveyard 1+ memory counters you control creature Assassinin graveyard you control creature Assassin
    • Affected (first 3): Altaïr Ibn-La'Ahad
  • 1 card · 🔄 ability/ChangeZone · changed field target: in graveyard 2+ time counters you control card non-landin graveyard you control card non-land
    • Affected (first 3): Doom's Time Platform
  • 1 card · 🔄 ability/ChangeZone · changed field target: legendary in graveyard 1+ memory counters creaturelegendary in graveyard creature
    • Affected (first 3): The Animus

11 card(s) had Oracle-text changes (errata/reprint) — excluded as non-parser.
New cards in head: 138.

@matthewevans matthewevans self-assigned this Aug 5, 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.

Request changes — the implementation is a three-card parser-class change, but the public scope and regression evidence still describe only Doom's Time Platform.

🟡 Required before merge

  1. Scope/impact disclosure. crates/engine/src/parser/oracle_effect/mod.rs:34513-34527 lifts the rider for every inferred Graveyard | Hand | Library origin, not only Doom's Time Platform. The current-head parse-diff artifact for b4d57fe4ec336db44b8fc89fb720174bb8441c0f measures five modified signatures across Doom's Time Platform, Altaïr Ibn-La'Ahad, and The Animus. Please update the PR body to state this exact three-card impact/class (or constrain the implementation to the intended scope) so review and future regressions are honest.

  2. Complete the origin regression matrix. crates/engine/src/parser/oracle_effect/tests.rs:35589-35664 exercises library lifting but does not assert its origin/InZone preservation; it has no Hand case and no non-counter-rider case. Add parser regressions for graveyard, hand, library, battlefield, and a non-counter with … clause. Each origin-sensitive case should assert the retained origin semantics; only graveyard/hand/library should lift counters, while battlefield and non-counter clauses must remain their respective filter/unparsed forms. This confirms the parser's new class-level gate rather than just the Doom fixture.

CodeRabbit independently raised the test-matrix gap on this head's predecessor; it remains present at the current head: #7022 (comment).

Recommendation: update the stated impact and add the complete regression matrix, then request re-review on the new head.

@matthewevans matthewevans added the enhancement New feature or request label Aug 5, 2026
@matthewevans matthewevans removed their assignment Aug 5, 2026
@matthewevans matthewevans removed the needs-maintainer AI-contribution PR requires human triage (Non-dev track or unresolved gaps) label Aug 6, 2026
@matthewevans matthewevans self-assigned this Aug 9, 2026
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@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.

Changes requested — the counterless-entry splitter drops a rules-bearing counter filter from persistent graveyard targets, and the parse-diff artifact is not bound to this head.

[HIGH] split_counterless_enter_counters treats every graveyard, hand, and library phrase as a counterless-entry context and strips the trailing with counters filter. Evidence: crates/engine/src/parser/oracle_effect/mod.rs:34669-34708 includes Graveyard in its counterless set before removing the phrase. That is not generally sound: CR 122.1a (docs/MagicCompRules.txt:1180) expressly permits a creature card in a non-battlefield zone to have counters. Why it matters: an instruction that targets a persistent graveyard card with counters loses FilterProp::Counters, widening the target set and producing rules-incorrect selection. Suggested fix: preserve the counter filter for graveyard (and other persistent zone) targets unless the surrounding grammar positively establishes an entry-with-counters rider; add a regression covering a graveyard card target whose counter predicate survives.

[MED] Parser-surface evidence is stale. Evidence: the only parse-diff receipt is bound to b4d57…, not current head 658fe3fa0313a1740c79453a8f7c79a009813133. Why it matters: the review cannot establish the current parser blast radius. Suggested fix: push/run CI until the <!-- coverage-parse-diff --> artifact names this exact head, then reconcile every resulting card/signature change.

@matthewevans matthewevans removed their assignment Aug 9, 2026
@matthewevans matthewevans self-assigned this Aug 9, 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.

Changes requested — this revision still conflates a persistent-zone counter predicate with an entry-with-counters rider, and its regression no longer proves that non-counter qualifiers survive.

[HIGH] split_counterless_enter_counters strips the trailing counter predicate whenever the inferred origin is Graveyard | Hand | Library (crates/engine/src/parser/oracle_effect/mod.rs:34669-34708). Graveyard is not generically counterless: CR 122.1a permits a creature card in a non-battlefield zone to have counters. The current parse receipt confirms the resulting target widening for Altaïr Ibn-La'Ahad, Doom's Time Platform, and The Animus. Preserve FilterProp::Counters for persistent-zone target grammar; lift counters into enter_with_counters only when the surrounding syntax positively establishes an entry rider. Add a regression in which a graveyard counter predicate survives, alongside grammar-positive entry-rider coverage.

[MED] The latest test change removes the FilterProp::WithKeyword(Flying) assertion from the shared parser case (crates/engine/src/parser/oracle_effect/tests.rs:35855-35889). That lets the suite pass even if the splitter drops a non-counter with … qualifier. Restore a non-counter qualifier assertion (or an equivalent dedicated regression) so the test discriminates between extracting only counters and discarding the whole suffix.

Please update on a new head with the counter filter preserved for persistent graveyard targets and the non-counter regression restored; then request re-review.

@matthewevans matthewevans removed their assignment Aug 9, 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.

Verified current head: the parser regression matrix now covers the required origin and non-counter cases; CI is green.

@matthewevans
matthewevans added this pull request to the merge queue Aug 9, 2026
Merged via the queue into phase-rs:main with commit 0292903 Aug 9, 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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants