Skip to content

fix(engine): fire ETB observers when an as-enters-choice permanent enters (#830) - #3167

Merged
matthewevans merged 1 commit into
mainfrom
fix/830-doomwake-etb-pipeline
Jun 13, 2026
Merged

fix(engine): fire ETB observers when an as-enters-choice permanent enters (#830)#3167
matthewevans merged 1 commit into
mainfrom
fix/830-doomwake-etb-pipeline

Conversation

@matthewevans

Copy link
Copy Markdown
Member

Summary

Fixes #830 — when a permanent enters carrying an "As it enters, choose …" replacement (e.g. Valgavoth's Lair → "choose a color"), the entry pauses on WaitingFor::NamedChoice instead of WaitingFor::Priority. The canonical priority-time trigger collection was skipped, so every ETB observer (constellation like Doomwake Giant, Soul Warden, etc.) was silently dropped for that entry.

Root cause

run_post_action_pipeline collects ETB triggers only on a WaitingFor::Priority result; an as-enters-choice entry returns NamedChoice, so the entering permanent's ZoneChanged never reached process_triggers.

Fix

Generalize the existing state.deferred_entry_events mechanism (previously gated to copy-target / counter choices) to capture as-enters NamedChoice { source_id: Some(_) } entries, and replay them on choice resolution through a shared replay_deferred_entry_events helper that surfaces interactive OrderTriggers/DistributeAmong pauses. CR 614.12a (the choice is made before the permanent enters).

Double-fire fix (engine_priority.rs)

The CastSpell path (creature/enchantment via stack resolution) does not skip run_post_action_pipeline the way PlayLand does, so an as-enters-choice creature's ETB observer was collected twice — once from the still-present entry ZoneChanged in events, once from the deferred replay. The trigger scan now excludes events already in deferred_entry_events while leaving them in events for frontend animation (a "two readers, one writer" contract). This also eliminates a pre-existing latent double-fire on the copy-target-choice path.

Class coverage

Engine-pipeline-level fix covering ~280 as-enters-choice permanents × the entire ETB-observer class — both PlayLand (lands) and CastSpell (creatures/enchantments) entry paths.

Tests (constellation_enters_with_choice.rs, 3/3)

  • as_enters_choice_land_fires_constellation — land path repro (toughness 2→1; discriminates zero-fire AND double-fire).
  • plain_enchantment_still_fires_constellation — regression guard for the untouched Priority path.
  • as_enters_choice_creature_fires_soul_warden — creature-via-stack double-fire discriminator (life +1, not +2).

Plan reviewed clean. Implementation reviewed clean twice (the second review, after the double-fire fix, adversarially verified copy-path safety, hot-path perf N≈0, GameEvent PartialEq soundness, and double-fire completeness). Full test-engine suite green (12791 passed). CR numbers grep-verified.

@matthewevans
matthewevans enabled auto-merge June 13, 2026 21:21

@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 addresses issue #830 where enters-the-battlefield (ETB) observers failed to trigger for permanents with 'As it enters, choose...' replacement effects. The solution consolidates deferred battlefield-entry event replay logic into a single helper, replay_deferred_entry_events, and extends mid-entry choice capture to support NamedChoice events. This ensures ETB triggers are deferred and replayed exactly once against the fully realized post-choice object. Comprehensive integration tests have been added to verify the fix and guard against regressions. No review comments were provided, so there is no feedback to address.

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.

@matthewevans
matthewevans added this pull request to the merge queue Jun 13, 2026
Merged via the queue into main with commit c8b4019 Jun 13, 2026
10 checks passed
@matthewevans
matthewevans deleted the fix/830-doomwake-etb-pipeline branch June 13, 2026 21:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Doomwake Giant - not triggering from enchantments — Doomwake Giant - not triggering from enchantments or enchantment la…

1 participant