Skip to content

fix(engine): attach Copy Enchantment when it enters as a copy of an Aura (#4782)#5824

Merged
matthewevans merged 3 commits into
phase-rs:mainfrom
mike-theDude:fix/issue-4782-copy-enchantment-aura-attach
Jul 14, 2026
Merged

fix(engine): attach Copy Enchantment when it enters as a copy of an Aura (#4782)#5824
matthewevans merged 3 commits into
phase-rs:mainfrom
mike-theDude:fix/issue-4782-copy-enchantment-aura-attach

Conversation

@mike-theDude

Copy link
Copy Markdown
Collaborator

Summary

Fixes #4782. Copy Enchantment entering as a copy of an Aura (e.g. Level Up / a Class) never got attached and died to the CR 704.5m unattached-Aura state-based action before its copied ability could function.

Root cause: Copy Enchantment (You may have this enchantment enter as a copy of any enchantment on the battlefield) enters as a plain enchantment, then its BecomeCopy replacement realizes it into an Aura after it is already on the battlefield. The normal aura-attach slot in move_object (the aura_enchant_filter consult in zone_pipeline.rs) had already run while the object was still its pre-copy, non-Aura self, so it was skipped — the copy sat unattached and check_unattached_auras (CR 704.5m) sent it to the graveyard on the next SBA check.

Fix: Resolve the entering Aura's attachment once the copy is realized and layers are flushed. New reusable building block zone_pipeline::resolve_entering_aura_attachment (reusing the existing aura_enchant_filter + legal_aura_attachment_targets + attach_to/attach_to_player primitives):

  • CR 303.4f — auto-attaches to a sole legal host.
  • CR 303.4g / 704.5m — leaves an Aura with no legal host unattached, so the SBA moves it to the graveyard.
  • Pauses on WaitingFor::ReturnAsAuraTarget for a multi-host controller choice.

It is called at the end of finish_copy_target_choice_entry — after entry-trigger replay and batch drain — so a multi-host pause has nothing left to strand.

Tests

Three integration tests covering the building block across the 0/1/many-host branches:

  • copy_enchantment_becomes_aura_copy_auto_attaches_and_survives_sba — single host → auto-attach + survives SBA.
  • copy_enchantment_becomes_aura_copy_with_no_host_dies_to_sba — no host → graveyard.
  • copy_enchantment_becomes_aura_copy_multi_host_prompts_then_attaches — multi-host → ReturnAsAuraTarget prompt → attach + survives SBA.

Verification

  • cargo fmt --all clean
  • cargo clippy -p engine --all-targets clean (zero warnings)
  • cargo test -p engine --lib16591 passed, 0 failed, 7 ignored

Reviewer notes (non-blocking, no BUG/RULES BUG)

  1. The shared liminal copy-token caller would drop a token continuation on a multi-host aura pause — no real card reaches this intersection today (mirrors the existing replay_deferred_entry_events pause); documented inline with a pointer for the next card that does.
  2. Attach runs after entry-trigger placement but completes before any trigger resolves, so observable outcomes match the normal aura-entry path for every real card.
  3. A hostless token aura briefly exists on the battlefield before SBA cleanup (CR 303.4g "if a token, it isn't created"); net end state is correct.

🤖 Generated with Claude Code

@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 implements CR 303.4f and CR 303.4g to correctly handle cases where a permanent (such as Copy Enchantment) enters the battlefield and becomes a copy of an Aura post-entry. It introduces resolve_entering_aura_attachment to handle the attachment of the newly realized Aura after layers are flushed, along with comprehensive tests. The review feedback identifies an important edge case where the object might leave the battlefield during intermediate triggers or replacement effects before attachment resolution, and suggests defensively guarding against this by ensuring the object is still in the battlefield zone.

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/game/zone_pipeline.rs
@github-actions

Copy link
Copy Markdown

Parse changes introduced by this PR

✓ No card-parse changes detected.

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

Blocked — copied “enchant player” Auras cannot complete the multi-host attachment choice.

🔴 Blocker

  • crates/engine/src/game/zone_pipeline.rs:1379-1393 deliberately includes TargetRef::Player in the legal Aura hosts, and resolve_entering_aura_attachment forwards any multi-host set through WaitingFor::ReturnAsAuraTarget at :1470-1473. The resume path then rejects TargetRef::Player outright at crates/engine/src/game/engine.rs:5527-5533. CR 303.4f requires the controller to choose a legal object or player; the current implementation therefore turns a valid copied enchant-player Aura with multiple legal players into InvalidAction instead of attaching it. The new tests cover only Enchant creature object hosts (engine_replacement.rs:5010, :5210).

🟡 Non-blocking

  • None.

✅ Clean

  • The current head correctly incorporates the prior battlefield-residency guard before it attempts attachment (zone_pipeline.rs:1442-1449), addressing the earlier review finding. The parse-diff artifact for this head also reports no card-parse changes.

Recommendation: extend the shared ReturnAsAuraTarget resume/finalization path to carry and attach TargetRef::Player, then add a production-pipeline Copy Enchantment regression covering multiple legal player hosts (and retain the existing object-host cases).

@mike-theDude

Copy link
Copy Markdown
Collaborator Author

Addressed matthewevans review blocker in 9650259.

Added a production-pipeline Copy Enchantment regression for a copied Enchant player Aura with multiple legal player hosts. The test drives the real enter-as-copy replacement, verifies ReturnAsAuraTarget offers both TargetRef::Player hosts, chooses PlayerId(1), and asserts the copy attaches to that player and survives the unattached-Aura SBA.

Focused verification run locally:

  • cargo fmt --all
  • cargo test -p engine copy_enchantment_becomes_enchant_player_aura_prompts_then_attaches_to_player
  • cargo test -p engine copy_enchantment_becomes_aura_copy_multi_host_prompts_then_attaches

The existing generic Effect::Attach resume branch already dispatches TargetRef::Player through attach_to_player; this regression locks down the reviewed copied Aura path specifically.

@matthewevans matthewevans self-assigned this Jul 14, 2026
mbriningstool and others added 3 commits July 14, 2026 15:49
…ura (phase-rs#4782)

Copy Enchantment ("You may have this enchantment enter as a copy of any
enchantment on the battlefield") enters as a plain enchantment, then its
`BecomeCopy` replacement realizes it into an Aura (e.g. Level Up) *after*
it is already on the battlefield. The normal aura-attach slot in
`move_object` (the `aura_enchant_filter` consult) had already run while the
object was still its pre-copy, non-Aura self, so it was skipped — the copy
sat unattached and was destroyed by the CR 704.5m unattached-Aura SBA
before its copied ability could ever matter.

Resolve the entering Aura's attachment once the copy is realized and layers
are flushed. New reusable building block
`zone_pipeline::resolve_entering_aura_attachment` (reusing the existing
`aura_enchant_filter` + `legal_aura_attachment_targets` + `attach_to`
primitives) auto-attaches a sole legal host (CR 303.4f), leaves an Aura with
no legal host unattached for the CR 303.4g/704.5m SBA, or pauses on
`ReturnAsAuraTarget` for a multi-host controller choice. Called at the end of
`finish_copy_target_choice_entry` — after entry-trigger replay and batch
drain — so a multi-host pause has nothing left to strand.

Adds three integration tests covering the 0/1/many-host branches (auto-attach
+ SBA survival, no-host → graveyard, multi-host prompt → attach).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…bjects

Address Gemini review: `resolve_entering_aura_attachment` now returns
`NotApplicable` if the realized copy is no longer on the battlefield. It runs
as the last step of `finish_copy_target_choice_entry`, after entry-trigger
replay and batch drain; if an intermediate trigger/replacement moved the Aura
off the battlefield, attaching it or prompting for a host of a non-battlefield
Aura would be invalid state (CR 303.4 / CR 704.5m attachment applies only to a
battlefield Aura).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@matthewevans
matthewevans force-pushed the fix/issue-4782-copy-enchantment-aura-attach branch from 9650259 to 62339f3 Compare July 14, 2026 22:50

@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 copy-entry attachment path now handles object and player Aura hosts without losing the post-entry continuation.

🔴 Blocker

  • None.

🟡 Non-blocking

  • The contributor-template artifacts are audit-only and incomplete; current-head CI plus the real replacement/choice/SBA regression supply the evidence.

✅ Clean

  • engine_replacement.rs calls the single resolve_entering_aura_attachment authority after copy realization; zone_pipeline.rs handles zone safety and player/object single hosts.
  • The regression drives the real Copy Enchantment pipeline, selects TargetRef::Player, and verifies both attachment and SBA survival.
  • Current-head CI is green; the parser-diff reports no changes.

Recommendation: approve and enqueue.

@matthewevans matthewevans added the bug Bug fix label 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 d1cfa32 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

bug Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Copy Enchantment not able to level up — When playing [[copy enchantment]] and making it enter as a copy of a Class, in…

3 participants