Skip to content

Fix Emperor of Bones - #7200

Merged
matthewevans merged 5 commits into
phase-rs:mainfrom
traemyn:card/emperor-of-bones
Aug 10, 2026
Merged

Fix Emperor of Bones#7200
matthewevans merged 5 commits into
phase-rs:mainfrom
traemyn:card/emperor-of-bones

Conversation

@traemyn

@traemyn traemyn commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes Emperor of Bones so an as-enters choice on the returned creature is not overwritten by replacement parking. Anointed Peacekeeper now completes both choices before Emperor's haste and delayed-sacrifice riders resume.

Files changed

  • crates/engine/src/game/replacement.rs
  • crates/engine/tests/integration/issue_1515_emperor_of_bones.rs
  • crates/engine/src/game/engine_resolution_choices.rs
  • crates/engine/src/game/zone_pipeline.rs

Track

Developer

LLM

Model: gpt-5.6-sol
Tier: Frontier
Thinking: high

Implementation method (required)

Method: /engine-implementer

Note

Any change to crates/engine/ game logic — parser, effects, resolver,
targeting, rules behavior — is expected to go through /engine-implementer.

CR references

  • CR 614.12a
  • CR 400.7j

Verification

  • Available checks ran clean; exact-head evidence is recorded below.

  • Gate A output below is bound to the current committed head.

  • Review tooling ran against the exact current head; its proposed precedence change was rejected by executable evidence from the established lifecycle suite, with no code change required.

  • Both anchors cite existing analogous code at the same seam.

  • cargo fmt --all -- --check — PASS

  • cargo clippy-strict — PASS using the user-local pkgconf/OpenSSL development prefix

  • RUST_MIN_STACK=33554432 cargo test -p phase-engine — PASS at the exact committed head: 4771 passed; 0 failed; 2 ignored; doc-tests 0 failed

  • RUST_MIN_STACK=33554432 cargo test -p phase-engine --test integration issue_1515_emperor_of_bones -- --nocapture — PASS (3 passed)

  • RUST_MIN_STACK=33554432 cargo test -p phase-engine --test integration cost_zone_pipeline -- --nocapture — PASS (106 passed)

  • RUST_MIN_STACK=33554432 cargo test -p phase-engine --test integration cast_during_resolution_pipeline -- --nocapture — PASS (11 passed)

  • RUST_MIN_STACK=33554432 cargo test -p phase-engine --test integration issue_3245_abhorrent_oculus_manifest_dread -- --nocapture — PASS (2 passed)

  • RUST_MIN_STACK=33554432 cargo test -p phase-engine --test integration issue_3311_manifest_dread_land -- --nocapture — PASS (2 passed)

  • RUST_MIN_STACK=33554432 cargo test -p phase-engine --test integration surveil_rest_pile_redirect_continuation -- --nocapture — PASS (2 passed)

  • ./scripts/gen-card-data.sh — PASS

  • cargo coverage — PASS (31775/35795 cards supported; 88.8%)

  • cargo semantic-audit — completed (32730 cards audited; 266 existing findings)

  • ./scripts/check-parser-combinators.sh — PASS (Gate G and Gate A)

Gate A

Gate A PASS head=a9a20eaa3671b15e101b90f51fe2ab87443b619a base=97591656218103d8e8c7315725b24cfe64645dd4

Review disposition

The production-path regression now runs Emperor's return through the real zone-move replacement pipeline. It reaches the shared parking boundary with a previously unlisted resolution-owned PayAmountChoice, verifies that prompt remains active, answers it with GameRunner::act, and verifies the returned permanent and delayed Emperor rider complete.

The rejected broad routing of the three fresh replacement-choice branches remains intentionally unchanged: the established lifecycle suite produced 14 regressions for that proposal, while the current direct-assignment contract remains green.

Summary by CodeRabbit

  • Bug Fixes

    • Fixed game flow after returned permanents require opponent, card-name, or replacement-related choices.
    • Ensured affected effects resume correctly after choices are completed.
    • Improved waiting-state handling during searches, draws, library placement, and zone changes.
    • Preserved battlefield state and finality counters through these interactions.
  • Tests

    • Added regression coverage for Emperor of Bones interactions involving haste, delayed sacrifices, and replacement choices.

@traemyn
traemyn requested a review from matthewevans as a code owner August 10, 2026 03:21
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

park_waiting_for now preserves interactive prompts during replacement resolution. Replacement paths assign waiting states directly, and search handling clears stale partition state. Integration tests cover resumed as-enters and replacement-driven pay choices.

Changes

Replacement waiting-state handling

Layer / File(s) Summary
Interactive choice preservation
crates/engine/src/game/replacement.rs
park_waiting_for preserves copy-target and aura-return prompts and delegates supported choice detection to engine_resolution_choices::handles.
Replacement state assignment
crates/engine/src/game/zone_pipeline.rs, crates/engine/src/game/engine_resolution_choices.rs
Replacement choices use replacement_choice_waiting_for directly for library placement, draws, and zone moves. Search partition handling resets state.waiting_for to Priority before delivery.
Regression coverage
crates/engine/tests/integration/issue_1515_emperor_of_bones.rs
Tests verify resumed Anointed Peacekeeper as-enters choices, replacement-driven pay choices, retained permanent state, finality counters, haste, and delayed-sacrifice continuation.

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

Possibly related PRs

  • phase-rs/phase#6539: Both changes handle copy-target choice waiting states during as-enters resolution.
  • phase-rs/phase#6886: Both changes modify replacement-pipeline waiting-state detection.
  • phase-rs/phase#7020: Both changes address stale waiting state during interactive choice resolution.

Suggested labels: test

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 clearly identifies the primary change: fixing Emperor of Bones behavior.
✨ 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/game/replacement.rs`:
- Around line 1006-1016: Annotate the park_waiting_for function’s waiting-choice
preservation logic with a verified “CR 614.12a” reference and concise
description that the required choice occurs before the permanent enters the
battlefield. Place the annotation directly at the relevant logic without
changing its behavior.
🪄 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: 4cd1585e-0069-42ec-a338-c6fc101bd1df

📥 Commits

Reviewing files that changed from the base of the PR and between d7d5895 and 3eb0982.

📒 Files selected for processing (2)
  • crates/engine/src/game/replacement.rs
  • crates/engine/tests/integration/issue_1515_emperor_of_bones.rs

Comment thread crates/engine/src/game/replacement.rs Outdated
Comment on lines +1006 to +1016
/// as-enters effect already surfaced its own interactive prompt. Leave that prompt
/// in place so the entry choice completes before the surrounding ability resumes.
pub fn park_waiting_for(state: &mut GameState, player: PlayerId) {
if matches!(state.waiting_for, WaitingFor::EffectZoneChoice { .. }) {
if matches!(
state.waiting_for,
WaitingFor::EffectZoneChoice { .. }
| WaitingFor::CopyTargetChoice { .. }
| WaitingFor::ChooseOneOfBranch { .. }
| WaitingFor::NamedChoice { .. }
| WaitingFor::ReturnAsAuraTarget { .. }
) {

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Add the required rules annotation.

park_waiting_for changes how the engine preserves choices while a permanent enters the battlefield. Add a verified CR 614.12a: ... annotation at this logic. CR 614.12a requires the choice before the permanent enters the battlefield. (media.wizards.com)

As per coding guidelines, “verify the relevant CR section before completion, and annotate rules-related code with a verified CR number and description.” As per path instructions, rules-touching code without that annotation is a finding.

🤖 Prompt for 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.

In `@crates/engine/src/game/replacement.rs` around lines 1006 - 1016, Annotate the
park_waiting_for function’s waiting-choice preservation logic with a verified
“CR 614.12a” reference and concise description that the required choice occurs
before the permanent enters the battlefield. Place the annotation directly at
the relevant logic without changing its behavior.

Sources: Coding guidelines, Path instructions

@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

Generated for head a9a20eaa3671b15e101b90f51fe2ab87443b619f.

Parse changes introduced by this PR

✓ No card-parse changes detected.

@matthewevans matthewevans self-assigned this Aug 10, 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 Emperor/Peacekeeper regression is covered, but the prompt-preservation fix remains partial.

🔴 Blocker

  • crates/engine/src/game/replacement.rs:1008-1018 hard-codes five WaitingFor variants. engine_replacement.rs:2429-2436 dispatches a post-replacement continuation as a general resolved/template effect, while engine_resolution_choices.rs:652-710 is the existing authority that classifies the wider resolution-owned prompt family (including SearchChoice, ChooseFromZoneChoice, PayAmountChoice, and others). A downstream member of that family will still be overwritten by ReplacementChoice; the new regression at crates/engine/tests/integration/issue_1515_emperor_of_bones.rs:159-256 exercises only NamedChoice, one of the newly listed variants. Reuse the central classifier here, retaining only genuinely external prompt families as explicit exceptions, and add a production-path regression for one representative previously unlisted prompt so this cannot regress into another hand-maintained list.

✅ Clean

  • The current-head CodeRabbit annotation request is already satisfied: replacement.rs:1005-1007 carries the CR 614.12a annotation at the preserved-prompt seam. I found no additional current-head finding in its review.

Recommendation: replace the hand-maintained subset with the shared resolution-choice authority, cover the omitted class, then request re-review.

@matthewevans matthewevans added the bug Bug fix label Aug 10, 2026
@matthewevans matthewevans removed their assignment Aug 10, 2026

@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/tests/integration/issue_1515_emperor_of_bones.rs`:
- Around line 263-275: Rewrite the regression test around the scenario runner so
it creates the pending replacement through the normal zone-move or scenario
pipeline instead of assigning runner.state_mut().waiting_for directly or calling
park_waiting_for. Submit the resulting action via runner.act(...), exercising
replacement handling through apply, move_object, replace_event, or the relevant
GameAction path. Assert that SearchChoice remains active during replacement and
that the replacement continuation resumes afterward.
🪄 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: b1fe99b6-cac4-44e3-afb5-4cff24686965

📥 Commits

Reviewing files that changed from the base of the PR and between 3eb0982 and 64cce71.

📒 Files selected for processing (4)
  • crates/engine/src/game/engine_resolution_choices.rs
  • crates/engine/src/game/replacement.rs
  • crates/engine/src/game/zone_pipeline.rs
  • crates/engine/tests/integration/issue_1515_emperor_of_bones.rs

Comment thread crates/engine/tests/integration/issue_1515_emperor_of_bones.rs Outdated
@matthewevans matthewevans self-assigned this Aug 10, 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 shared resolution-choice authority fixes the prior hand-maintained-list blocker, but the new representative regression is not exercising the production pause/resume path.

🔴 Blocker

  • crates/engine/tests/integration/issue_1515_emperor_of_bones.rs:259-287 constructs WaitingFor::SearchChoice directly and calls replacement::park_waiting_for directly. This proves only the helper's immediate classification; it does not enter effects/change_zone.rs:755-769 / 1100-1142, create a pending replacement, submit the choice through GameRunner::act, or prove that the paused continuation resumes. Consequently it cannot distinguish the intended fix from a future caller that bypasses the parking authority or preserves a stale consumed prompt. Replace it with a scenario/runtime regression that reaches a real park_waiting_for call site with a previously unlisted resolution-owned prompt, acts through that prompt, and asserts the replacement/outer continuation completes. If SearchChoice cannot occur at one of those call sites, use a reachable omitted variant (or narrow the classifier to the demonstrably reachable class).

  • The required parse-diff evidence is not current-head evidence: the only <!-- coverage-parse-diff --> comment is bound to 3eb0982ab1c78aa36163f1d0978ba81beb0f475c, while this review is for 64cce71026ed6de413d27b4528656eee8f894063. Please obtain the current-head artifact before the next review; it is the required scope/coverage evidence for an engine PR.

✅ Clean

  • crates/engine/src/game/replacement.rs:1008-1016 now delegates resolution-owned prompts to engine_resolution_choices::handles, the central authority at engine_resolution_choices.rs:652-727; the only retained explicit exceptions are the external copy/aura prompt families.
  • crates/engine/src/game/engine_resolution_choices.rs:3964 clears the consumed SearchPartitionChoice before its zone move can surface a replacement choice. The existing annotation is accurate: CR 614.12a states, "If a replacement effect that modifies how a permanent enters the battlefield requires a choice, that choice is made before the permanent enters the battlefield."

Recommendation: add the discriminating production-path regression and refresh the current-head parse-diff artifact, then request re-review.

@matthewevans

Copy link
Copy Markdown
Member

Correction to my current-head review: the existing parse-diff artifact was refreshed in place and is now bound to 64cce71026ed6de413d27b4528656eee8f894063; it reports “No card-parse changes detected.” That satisfies the parse-diff evidence item. The production-path regression blocker at crates/engine/tests/integration/issue_1515_emperor_of_bones.rs:259-287 remains unchanged.

@matthewevans matthewevans removed their assignment Aug 10, 2026
@traemyn

traemyn commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

Implemented the requested review fix in commit a9a20eaa3. The regression now enters through the real replacement pipeline, preserves a previously unlisted resolution-owned PayAmountChoice, answers it through GameRunner::act, and verifies the returned permanent completes with the Emperor continuation.

Focused Emperor tests: 3 passed. Full engine suite: 4771 passed, 0 failed, 2 ignored; doc-tests clean. Gate A: PASS at a9a20eaa3. The stale rejected-proposal wording in the PR body has also been updated.

@matthewevans please re-review.

@matthewevans matthewevans self-assigned this Aug 10, 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 — current-head re-review is clean.

The new regression reaches the real Emperor return/replacement path, preserves the previously unlisted PayAmountChoice, answers it through GameRunner::act, and verifies the outer continuation finishes. Exact-head CI and the parse-diff artifact are green.

@matthewevans
matthewevans added this pull request to the merge queue Aug 10, 2026
@matthewevans matthewevans removed their assignment Aug 10, 2026
Merged via the queue into phase-rs:main with commit 58d7043 Aug 10, 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.

2 participants