Skip to content

fix(engine): preserve mana-spent snapshots across spell ETB (#1156)#3735

Merged
matthewevans merged 5 commits into
phase-rs:mainfrom
kiannidev:fix/issue-1156-coin-of-mastery
Jun 18, 2026
Merged

fix(engine): preserve mana-spent snapshots across spell ETB (#1156)#3735
matthewevans merged 5 commits into
phase-rs:mainfrom
kiannidev:fix/issue-1156-coin-of-mastery

Conversation

@kiannidev

Copy link
Copy Markdown
Contributor

Summary

  • Snapshot and restore mana_spent_source_snapshots, colors_spent_to_cast, and related cast-payment fields in CastLinkSnapshot during stack-to-battlefield delivery.
  • Ensures Coin of Mastery ETB replacements can count artifact-source mana spent to cast the entering creature.

Fixes #1156

Test plan

  • cargo test -p engine --lib artifact_mana_spent_on_self
  • Cast a creature using Treasure mana with Coin of Mastery on the battlefield and verify extra +1/+1 counters

Made with Cursor

…#1156)

Extend CastLinkSnapshot so creature spells keep mana_spent_source_snapshots
and related cast-payment fields when resolving from the stack to the
battlefield, letting Coin of Mastery count artifact mana spent to cast.

Co-authored-by: Cursor <cursoragent@cursor.com>
@kiannidev kiannidev requested a review from matthewevans as a code owner June 18, 2026 17:48

@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 updates CastLinkSnapshot in crates/engine/src/game/zone_pipeline.rs to include fields for tracking details about the mana spent to cast, such as mana_spent_to_cast, mana_spent_to_cast_amount, colors_spent_to_cast, and mana_spent_source_snapshots. These fields are also correctly copied and restored within the deliver_replaced_zone_change function. As there were no review comments provided, I have no feedback to evaluate.

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 the bug Bug fix label Jun 18, 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.

[MED] This does not demonstrate a fix for the Coin of Mastery failure, and the added snapshot fields appear to be at the wrong/no-op seam. Evidence: crates/engine/src/game/zone_pipeline.rs:1558 now snapshots/restores the mana-spent fields around zones::move_to_zone, but GameObject::reset_for_battlefield_entry clears cast provenance/kicker/convoke at crates/engine/src/game/game_object.rs:1336-1352 and does not clear mana_spent_to_cast_amount, colors_spent_to_cast, or mana_spent_source_snapshots. The Coin-style ETB counter quantity is resolved before the move in extract_etb_counters_from_effect using QuantityContext { entering: Some(object_id), ... } (crates/engine/src/game/replacement.rs:3988-4018), and source-qualified mana reads the entering object snapshot list at crates/engine/src/game/quantity.rs:789-802; those snapshots are already populated during mana payment at crates/engine/src/game/casting.rs:10188-10220. The PR also changes only zone_pipeline.rs, so there is no fail-on-revert regression for issue #1156. Why it matters: this can merge a no-op while the reported “mana from an artifact source spent to cast it” path remains broken or unproven. Suggested fix: first add a regression that fails on origin/main for Coin of Mastery (or an equivalent Moved replacement using CastManaSpentMetric::FromSource { source_filter: Artifact }) through the real cast/payment/replacement path, then put the fix at the seam that makes that test pass; if the delivery snapshot is genuinely necessary, the test should fail when these four new CastLinkSnapshot fields are removed.

Confidence: high from code inspection; contradictory evidence would be a regression test that fails on origin/main and passes only with this CastLinkSnapshot expansion.

…e-rs#1156)

Revert the no-op CastLinkSnapshot mana-spent expansion in zone_pipeline.
Coin-style ETB counters resolve before the battlefield move via
extract_etb_counters using the entering spell's payment-time source
snapshots (casting.rs), not post-delivery snapshot restore.

Co-authored-by: Cursor <cursoragent@cursor.com>
@kiannidev

Copy link
Copy Markdown
Contributor Author

Thanks for the review — you were right that the CastLinkSnapshot mana-spent expansion is a no-op seam.

What I verified

  • extract_etb_counters_from_effect resolves CastManaSpentMetric::FromSource { Artifact } against the entering spell via QuantityContext { entering: Some(object_id), ... } before zones::move_to_zone.
  • pay_mana_cost already records mana_spent_source_snapshots at payment time (casting.rs ~10188–10220).
  • reset_for_battlefield_entry clears cast provenance/kicker/convoke but does not clear mana_spent_source_snapshots (or mana_spent_to_cast_amount).
  • Reverting the four CastLinkSnapshot fields does not change behavior.

What changed in 90ebcba

  • Reverted the zone_pipeline.rs CastLinkSnapshot mana-spent snapshot/restore.
  • Added integration tests driving cast → stack → resolve → ETB replacement with Treasure-tagged pool mana (issue_1156_coin_of_mastery.rs).
  • Added a replacement-layer unit test artifact_mana_spent_on_self_resolves_against_entering_object mirroring Coin’s ChangeZone + FromSource { Artifact } shape.

Test plan

  • cargo test -p engine --test integration coin_of_mastery
  • cargo test -p engine --lib artifact_mana_spent_on_self_resolves

These pass on origin/main without the CastLinkSnapshot expansion, which matches the analysis: the correct seam is payment-time snapshot recording + pre-move replacement quantity resolution, not post-delivery snapshot restore.

@matthewevans

Copy link
Copy Markdown
Member

VERDICT: approve-pending-CI

Re-reviewed follow-up head 90ebcba05b539cec62cbb756f3b0a9bc04490933, then pushed maintainer fixup 9ff322b68cf886ee84cb9b43db2b81c3886e6406 to move the new unit-test imports to module scope.

Prior blocker status: ADDRESSED. The wrong-seam CastLinkSnapshot implementation was removed. The remaining diff is regression coverage: the integration tests drive the real GameScenario cast → stack commit → resolve → ETB replacement path with artifact-tagged pool mana, and the replacement-layer unit test covers the CastManaSpentMetric::FromSource { Artifact } quantity against the entering object snapshot. CR citations for 122.6/122.6a, 614.1c, and 601.2h check out against docs/MagicCompRules.txt.

Holding formal approval/enqueue until CI is green on the pushed head and the normal repush guard passes.

@matthewevans matthewevans added the test Add tests label Jun 18, 2026
@matthewevans matthewevans self-assigned this Jun 18, 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 after re-review of the current head: the wrong-seam CastLinkSnapshot path was removed, the artifact-mana regression now exercises the real cast/commit/resolve flow, the required category labels are present, and GitHub checks are green at 64a818bb1dee42fc2cbc2abf4f420b9f274d071a.

@matthewevans matthewevans added this pull request to the merge queue Jun 18, 2026
@matthewevans matthewevans removed their assignment Jun 18, 2026
@kiannidev

Copy link
Copy Markdown
Contributor Author

@matthewevans Re: the zone-pipeline snapshot concern — agreed that expanding CastLinkSnapshot at move_to_zone was the wrong seam. Follow-up on this branch reverted that path and added regression coverage through the existing cast/payment/replacement route instead. CI is green on the latest run; please take another look when you have a moment.

Merged via the queue into phase-rs:main with commit e10dac4 Jun 18, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Bug fix test Add tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Coin of Mastery Not Triggering — [[Coin of Mastery]] does not proc its first ability of creatures entering with a +1/+1…

2 participants