You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ActivatorScope in crates/sage-engine/src/ability/trigger.rs has exactly two members:
pubenumActivatorScope{/// Any player's activation, the watcher's own controller included.#[default]Any,/// Only an opponent of the watcher's controller …Opponents,}
Sarkhan's Whelp prints Whenever you activate an ability of a Sarkhan planeswalker, this
creature deals 1 damage to any target. There is no scope for "you", so sarkhan_s_whelp.json is authored "activator": "any" — and an opponent activating their own
Sarkhan fires your Whelp.
This is the eighteenth wrong card in the audit, and the only one that is a mechanic
finding rather than an authoring one: the vocabulary offers no correct answer, so no amount of
care in the JSON would have got it right.
exclusions.json does not name the gap. Its nearest entry — "Abilities that trigger on a loyalty ability specifically" — asserts in its blocker text that the activation filter
covers "who activated it", which is what makes the missing scope invisible. Per crates/sage-engine/AGENTS.md, that file "claims to name every mechanic considered and left
out of scope, so a gap that is neither built nor named makes it false."
Building it is the right fix rather than naming it, and that is also the direction #791 is
taking the exclusion registry as a whole. It is a one-variant change: ActivatorScope is a
small Copy enum consumed in one predicate.
Related: #776 item 7 notes the adjacent gap — nothing filters an observed activation by
whether it was a loyalty ability. Distinct question, same enum, and worth resolving in the
same read even if it is left to the card that needs it.
Scope
ActivatorScope gains the controller-only scope, documented alongside Any and Opponents
and scoped from the same "you" every other trigger scope is written from.
The predicate that reads it follows; it is wildcard-free, so the compiler names the site.
sarkhan_s_whelp.json is corrected.
The server's rules-text formatter renders the new scope.
exclusions.json: the loyalty entry's blocker text no longer implies the activator filter is
complete. Coordinate with Remove exclusions.json and prohibit card/mechanic denylists #791 — if the registry is being removed, this is a deletion rather
than an edit.
Acceptance criteria
An opponent activating a Sarkhan planeswalker they control does not fire sarkhan_s_whelp.
The controller activating a Sarkhan planeswalker they control does fire it, once per
activation.
A mana ability of a Sarkhan still fires nothing — the existing structural exclusion
(a mana ability never reaches the stack, CR 605.3a) is unaffected.
The rendered rules text for sarkhan_s_whelp says "you", not "a player".
exclusions.json no longer asserts the activator filter is complete.
make compat regenerated; make verify green.
Test and validation evidence
An engine test with a Sarkhan on each side, activating both, asserting one fire.
A rules-text test for the new scope's rendering.
make compat drift check; make verify.
Dependencies and sequencing
Independent of every other child of #819 and small enough to land at any point. Coordinate
with #791 on the exclusions.json half only.
Estimated scope
Small — localized change: one enum variant, one predicate arm, one formatter arm, one JSON
file.
Risks and constraints
None material. The scope is Copy, closed, and read in one place.
Non-goals
Not the loyalty-ability filter of #776 item 7 — related, and fine to do here if it is free, but
it blocks no card. Not a general rework of the trigger vocabulary.
Documentation impact
docs/card-schema.md if the trigger vocabulary's scopes are enumerated there. exclusions.json as above. No ADR.
Goal
A card that says whenever you activate an ability watches only its controller's
activations, so Sarkhan's Whelp stops firing on an opponent's Sarkhan.
Context and evidence
Parent: #819.
ActivatorScopeincrates/sage-engine/src/ability/trigger.rshas exactly two members:Sarkhan's Whelp prints Whenever you activate an ability of a Sarkhan planeswalker, this
creature deals 1 damage to any target. There is no scope for "you", so
sarkhan_s_whelp.jsonis authored"activator": "any"— and an opponent activating their ownSarkhan fires your Whelp.
This is the eighteenth wrong card in the audit, and the only one that is a mechanic
finding rather than an authoring one: the vocabulary offers no correct answer, so no amount of
care in the JSON would have got it right.
exclusions.jsondoes not name the gap. Its nearest entry — "Abilities that trigger on aloyalty ability specifically" — asserts in its blocker text that the activation filter
covers "who activated it", which is what makes the missing scope invisible. Per
crates/sage-engine/AGENTS.md, that file "claims to name every mechanic considered and leftout of scope, so a gap that is neither built nor named makes it false."
Building it is the right fix rather than naming it, and that is also the direction #791 is
taking the exclusion registry as a whole. It is a one-variant change:
ActivatorScopeis asmall
Copyenum consumed in one predicate.Related: #776 item 7 notes the adjacent gap — nothing filters an observed activation by
whether it was a loyalty ability. Distinct question, same enum, and worth resolving in the
same read even if it is left to the card that needs it.
Scope
ActivatorScopegains the controller-only scope, documented alongsideAnyandOpponentsand scoped from the same "you" every other trigger scope is written from.
sarkhan_s_whelp.jsonis corrected.exclusions.json: the loyalty entry's blocker text no longer implies the activator filter iscomplete. Coordinate with Remove exclusions.json and prohibit card/mechanic denylists #791 — if the registry is being removed, this is a deletion rather
than an edit.
Acceptance criteria
sarkhan_s_whelp.activation.
(a mana ability never reaches the stack, CR 605.3a) is unaffected.
sarkhan_s_whelpsays "you", not "a player".exclusions.jsonno longer asserts the activator filter is complete.make compatregenerated;make verifygreen.Test and validation evidence
make compatdrift check;make verify.Dependencies and sequencing
Independent of every other child of #819 and small enough to land at any point. Coordinate
with #791 on the
exclusions.jsonhalf only.Estimated scope
Small — localized change: one enum variant, one predicate arm, one formatter arm, one JSON
file.
Risks and constraints
None material. The scope is
Copy, closed, and read in one place.Non-goals
Not the loyalty-ability filter of #776 item 7 — related, and fine to do here if it is free, but
it blocks no card. Not a general rework of the trigger vocabulary.
Documentation impact
docs/card-schema.mdif the trigger vocabulary's scopes are enumerated there.exclusions.jsonas above. No ADR.