Skip to content

fix(engine): preserve beginning combat priority - #7080

Merged
matthewevans merged 9 commits into
mainfrom
ship/fix-engine-preserve-beginning-combat-priority
Aug 7, 2026
Merged

fix(engine): preserve beginning combat priority#7080
matthewevans merged 9 commits into
mainfrom
ship/fix-engine-preserve-beginning-combat-priority

Conversation

@matthewevans

@matthewevans matthewevans commented Aug 7, 2026

Copy link
Copy Markdown
Member

Summary

Preserves the rules-required Beginning of Combat priority window before attackers are declared, including phase stops, trigger prompts, extra combat, and controlled-combat priority semantics.

Validation failures

The engine-implementer baseline projection could not complete because the detached base revision has unrelated engine compilation failures (zone-pipeline and exhaustive-match errors). Formatting, diff checks, and pre-commit gates passed; CI/merge queue will validate this branch.

Pipeline-reviewed head: 9077f8c46a64a17c5a6be066200ede445caa36c9
Current branch head: 20f479f54052d427cac0d2223783899db08b678a
Pipeline status: historical — shipped despite baseline measurement CANNOT_ANSWER
Current-head review: none

Summary by CodeRabbit

  • New Features

    • Beginning-of-combat now consistently opens a priority window for the active player.
    • Empty combats display an attacker-declaration prompt before proceeding to post-combat main.
    • Multiple beginning-of-combat triggers now present an ordering prompt.
    • Combat actions can automatically pass through empty priority windows when using streamlined game actions.
  • Bug Fixes

    • Auto-pass is interrupted correctly when beginning-of-combat starts.
    • Priority remains with the active player, and non-mana activated abilities remain usable.
    • Combat transitions and inserted beginning-of-combat phases now behave consistently.

@matthewevans
matthewevans enabled auto-merge August 7, 2026 13:27
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@matthewevans, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 25 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6b4bd677-d056-4001-86e7-3980ed301ec4

📥 Commits

Reviewing files that changed from the base of the PR and between 24d3eb8 and 8c30ced.

📒 Files selected for processing (1)
  • crates/engine/tests/integration/issue_3279_song_of_dryads.rs
📝 Walkthrough

Walkthrough

The engine now initializes combat before trigger processing and always grants active-player priority during BeginCombat. Tests cover empty attacker declarations, inserted combat phases, trigger ordering, turn progression, scenario actions, phase-stop auto-pass interruption, and non-mana ability activation.

Changes

BeginCombat priority flow

Layer / File(s) Summary
BeginCombat processing and priority state
crates/engine/src/game/turns.rs
BeginCombat now initializes combat before processing triggers and always returns an active-player priority window. Documentation and controlled-turn assertions reflect the new priority state.
Combat phase regression coverage
crates/engine/src/game/engine_phase_trigger_regression_tests.rs, crates/engine/src/game/turns.rs
Regression tests cover empty attacker declarations, inserted BeginCombat phases, phase stops, and multiple beginning-of-combat triggers.
Turn-cycle, scenario, and auto-pass integration
crates/engine/src/game/engine_tests.rs, crates/engine/src/game/engine_auto_pass_decision_tests.rs, crates/engine/src/game/scenario.rs, crates/engine/tests/integration/*
Integration tests pass through BeginCombat, verify empty-combat progression, and verify phase-stop auto-pass interruption with non-mana ability activation. Scenario actions preserve shorthand DeclareAttackers behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GameRunner
  participant PhaseInterpreter
  participant ActivePlayer
  participant DeclareAttackers
  GameRunner->>PhaseInterpreter: enter BeginCombat
  PhaseInterpreter->>PhaseInterpreter: initialize combat state
  PhaseInterpreter->>ActivePlayer: request priority
  GameRunner->>ActivePlayer: pass priority twice
  ActivePlayer->>DeclareAttackers: submit empty attacker declaration
  DeclareAttackers-->>PhaseInterpreter: advance to PostCombatMain
Loading

Possibly related PRs

  • phase-rs/phase#6845: Both changes modify combat and DeclareAttackers handling for empty attacker declarations and BeginCombat priority.
  • phase-rs/phase#7051: Both changes cover empty-attacker behavior and phase-stop interactions in combat flow.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes preserving the Beginning of Combat priority window, which is the main change in the pull request.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ship/fix-engine-preserve-beginning-combat-priority

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/engine/src/game/turns.rs`:
- Around line 2859-2877: Update the auto_advance_skips_combat_phases test to
reflect the new BeginCombat priority window: after the first auto_advance call,
submit the active player’s priority response, then submit the empty attacker
declaration before asserting Phase::PostCombatMain. Preserve the test’s existing
empty-combat scenario and use the established turn/priority submission helpers.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: cb16744f-8266-4800-9ddc-7dd6217a03e9

📥 Commits

Reviewing files that changed from the base of the PR and between ae2fcb2 and 20f479f.

📒 Files selected for processing (4)
  • crates/engine/src/game/engine_auto_pass_decision_tests.rs
  • crates/engine/src/game/engine_phase_trigger_regression_tests.rs
  • crates/engine/src/game/engine_tests.rs
  • crates/engine/src/game/turns.rs

Comment thread crates/engine/src/game/turns.rs
@matthewevans matthewevans added the bug Bug fix label Aug 7, 2026
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

Generated for head 8c30ced6366b801e9239d7db9549ad0d3c41c454.

Parse changes introduced by this PR

✓ No card-parse changes detected.

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/engine/src/game/scenario.rs`:
- Around line 1318-1324: Update the implicit pass block in the scenario action
handling around GameAction::DeclareAttackers to require
self.state.stack.is_empty() in addition to the existing BeginCombat and Priority
conditions, so hidden passes occur only with an empty beginning-of-combat stack.
- Around line 1318-1324: Update the BeginCombat handling around
GameAction::DeclareAttackers to use the engine’s topology-aware priority-pass
sequence instead of applying exactly two PassPriority actions; otherwise
restrict this shorthand to two-player scenarios. Preserve successful
DeclareAttackers setup for multiplayer states and add a regression test covering
a three-player combat.
- Around line 1322-1325: Update the implicit-pass handling in GameRunner::act to
retain each apply_as_current result, accumulate their emitted events in order,
and prepend them to the ActionResult returned for the explicit action. Preserve
error propagation and ensure events from both GameAction::PassPriority calls,
including phase or stack events, are included.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ac0f94db-e128-43c9-a2fb-d67be70e1be0

📥 Commits

Reviewing files that changed from the base of the PR and between 20f479f and 3601f73.

📒 Files selected for processing (3)
  • crates/engine/src/game/engine_phase_trigger_regression_tests.rs
  • crates/engine/src/game/scenario.rs
  • crates/engine/src/game/turns.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/engine/src/game/turns.rs
  • crates/engine/src/game/engine_phase_trigger_regression_tests.rs

Comment thread crates/engine/src/game/scenario.rs
Comment thread crates/engine/src/game/scenario.rs Outdated

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/engine/tests/integration/issue_3279_song_of_dryads.rs`:
- Around line 97-98: Update the integration test around the duplicated
runner.pass_both_players() calls to first run an unenchanted Obuun control
through the same priority passes and assert it reaches
WaitingFor::TriggerTargetSelection or WaitingFor::OrderTriggers. Keep the Song
of the Dryads scenario’s existing assertion that no trigger prompt remains,
using the control assertion as its positive reach guard.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 577ce2e3-6ef3-438f-93d1-0ec79e7e870e

📥 Commits

Reviewing files that changed from the base of the PR and between 3601f73 and 24d3eb8.

📒 Files selected for processing (8)
  • crates/engine/src/game/engine_phase_trigger_regression_tests.rs
  • crates/engine/src/game/scenario.rs
  • crates/engine/src/game/turns.rs
  • crates/engine/tests/integration/engine_invariants.rs
  • crates/engine/tests/integration/export_runtime_canaries.rs
  • crates/engine/tests/integration/issue_3279_song_of_dryads.rs
  • crates/engine/tests/integration/json_smoke_test.rs
  • crates/engine/tests/integration/loop_shortcut.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • crates/engine/src/game/scenario.rs
  • crates/engine/src/game/turns.rs
  • crates/engine/src/game/engine_phase_trigger_regression_tests.rs

Comment thread crates/engine/tests/integration/issue_3279_song_of_dryads.rs
@matthewevans
matthewevans added this pull request to the merge queue Aug 7, 2026
Merged via the queue into main with commit 6e25f53 Aug 7, 2026
13 checks passed
@matthewevans
matthewevans deleted the ship/fix-engine-preserve-beginning-combat-priority branch August 7, 2026 17:56
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.

1 participant