Skip to content

Ward: PayCostsReq routing + multi-trigger + Countered affectorId #178

@delebedev

Description

@delebedev

Confidence: HIGH — full wire sequence from proxy recording (2026-03-21_23-56-57, Sheltered by Ghosts ward 2 vs Bushwhack).

Finding

Ward triggers use PayCostsReq (promptId=11) routed to the spell controller (not ward owner). Multiple ward triggers from one creature fire independently — paying one doesn't satisfy others.

Wire sequence

  1. Targeting submitted → two AbilityInstanceCreated (one per ward trigger) spawn simultaneously
  2. Both go to Pending zone, then Stack (LIFO: [trigger2, trigger1, spell])
  3. First trigger resolves: PayCostsReq → opponent auto-taps → ResolutionComplete
  4. Second trigger resolves: no PayCostsReq (opponent already tapped out) → auto-counters spell
  5. Spell → GY with ZoneTransfer(category="Countered"), affectorId=wardTriggerIid

Code gaps

  1. PayCostsReq for ward must route to spell controller, not ward owner — check BundleBuilder.payCostsBundle() seatId
  2. affectorId on ward-countered ZoneTransfer must be the ward trigger instanceId
  3. Multiple ward triggers from one creature not tested

Additional observation (2026-03-22_13-39-53)

Ward trigger observed on Nervous Gardener (ability 141939 "Ward {o2}") when targeted by Pacifism. TriggeringObject pAnn fires with affectorId=ward ability iid, affectedIds=[targeting spell, targeted creature]. PayCostsReq sent to opponent (promptId=11). Ward cost was paid and Pacifism resolved. Consistent with prior findings.

Wire spec

docs/plans/2026-03-21-ward-counter-wire-spec.md

refs #37

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestprotocolArena protocol/proto issue

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions