Skip to content

fix: filter uncompletable AI target proposals - #7254

Merged
matthewevans merged 11 commits into
mainfrom
ship/fix-filter-uncompletable-ai-target-proposals
Aug 12, 2026
Merged

fix: filter uncompletable AI target proposals#7254
matthewevans merged 11 commits into
mainfrom
ship/fix-filter-uncompletable-ai-target-proposals

Conversation

@matthewevans

@matthewevans matthewevans commented Aug 12, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • Bug Fixes

    • Outdated “Resolve All” actions are now handled silently without unnecessary error messages.
    • Other “Resolve All” rejections continue to provide actionable notifications.
    • AI decisions now exclude spell and ability targets that cannot be paid for, while retaining valid targets.
    • Target selection no longer reuses stale options when no legal targets remain.
  • Tests

    • Expanded coverage for stale and recoverable “Resolve All” responses.
    • Added payment-aware target-selection validation for spells and activated abilities.

@matthewevans
matthewevans enabled auto-merge August 12, 2026 00:16
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The adapter now classifies stale Resolve All responses separately and suppresses their notifications. AI decision contracts now filter final targets that cannot satisfy payment requirements.

Changes

Resolve All rejection handling

Layer / File(s) Summary
Rejection classification and adapter wiring
client/src/adapter/types.ts, client/src/adapter/ws-adapter.ts, client/src/adapter/__tests__/ws-adapter.test.ts
Resolve All maps the exact priority rejection to STALE_ACTION and keeps other rejections as recoverable ACTION_REJECTED errors.
Stale failure dispatch behavior
client/src/game/dispatch.ts, client/src/game/__tests__/dispatchResolveAll.test.ts
Stale Resolve All errors now clear state without logging or notifying. Ordinary failures remain observable.

AI final target validation

Layer / File(s) Summary
Final target reducer validation
crates/engine/src/ai_support/context.rs, crates/engine/src/ai_support/mod.rs, crates/manabrew-compat/src/lib.rs, crates/phase-ai/src/search.rs
Every target-selection state now uses reducer validation. Fixtures cover populated and empty optional slots, stale targets, and reducer-validated action selection.
AI decision contract scenarios
crates/engine/tests/integration/ai_decision_contract.rs
Integration tests cover payable and unpayable targets for spells and activated abilities, including dynamically skipped optional slots.

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

Sequence Diagram(s)

sequenceDiagram
  participant WebSocketAdapter
  participant resolveAllRejectionError
  participant dispatchResolveAll
  participant Notifications
  WebSocketAdapter->>resolveAllRejectionError: classify ResolveAllRejected reason
  resolveAllRejectionError->>dispatchResolveAll: return AdapterErrorCode
  alt STALE_ACTION
    dispatchResolveAll->>dispatchResolveAll: clear Resolve All state
  else ACTION_REJECTED
    dispatchResolveAll->>Notifications: log and show rejection
  end
Loading
sequenceDiagram
  participant AiDecisionContract
  participant TargetSelection
  participant Reducer
  participant ManaState
  AiDecisionContract->>TargetSelection: enumerate target choices
  TargetSelection->>Reducer: validate each choice
  Reducer->>ManaState: check payment feasibility
  Reducer-->>AiDecisionContract: retain payable targets
Loading

Possibly related PRs

Suggested labels: bug

Suggested reviewers: lgray, ntindle, codeoptimist

🚥 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 summarizes the primary change: filtering AI target proposals that cannot be completed.
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-filter-uncompletable-ai-target-proposals

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.

@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown

Generated for head 2891e45c5d37b0ab424f1cd2ab71eb2eaf2cd8a8.

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: 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/ai_support/mod.rs`:
- Around line 6201-6216: The target-selection fixtures use an empty optional
suffix, which is skipped and cannot exercise genuinely non-final progression. In
crates/engine/src/ai_support/mod.rs lines 6201-6216, update the later
target-selection slot to contain a legal target, then add a separate regression
fixture covering an empty-tail final-validation case. In
crates/manabrew-compat/src/lib.rs lines 5283-5298, mirror the non-empty
later-slot change in the interaction-projection fixture.
🪄 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: 59af5024-ca81-420f-9ad2-06557bb315b1

📥 Commits

Reviewing files that changed from the base of the PR and between b065c21 and 2bf1ae6.

📒 Files selected for processing (2)
  • crates/engine/src/ai_support/mod.rs
  • crates/manabrew-compat/src/lib.rs

Comment thread crates/engine/src/ai_support/mod.rs

@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/ai_decision_contract.rs`:
- Around line 157-158: Update the borrow of state.waiting_for in the surrounding
test setup to use a mutable reference, so pending_cast and target_slots can be
modified as required. Preserve the existing target constraint assignment and
TargetSelectionSlot construction.
🪄 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: 86411b21-d1cd-48bc-8366-c1d9cebc12f3

📥 Commits

Reviewing files that changed from the base of the PR and between 2bf1ae6 and c392f8a.

📒 Files selected for processing (4)
  • crates/engine/src/ai_support/context.rs
  • crates/engine/src/ai_support/mod.rs
  • crates/engine/tests/integration/ai_decision_contract.rs
  • crates/manabrew-compat/src/lib.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/manabrew-compat/src/lib.rs

Comment thread crates/engine/tests/integration/ai_decision_contract.rs

@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/phase-ai/src/search.rs`:
- Around line 8878-8880: Strengthen the regression assertion around the AI
decision in the target-selection test to require Some(GameAction::ChooseTarget {
target: Some(_) }), rather than accepting any action or CancelCast. Keep the
existing reducer clone-count and contract-membership checks, but ensure the test
fails when the target prompt is canceled while legal targets remain.
🪄 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: 76314179-bdf3-4440-b3b8-ae799ba8471c

📥 Commits

Reviewing files that changed from the base of the PR and between 480257c and 2891e45.

📒 Files selected for processing (3)
  • crates/engine/src/ai_support/mod.rs
  • crates/engine/tests/integration/ai_decision_contract.rs
  • crates/phase-ai/src/search.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/engine/src/ai_support/mod.rs
  • crates/engine/tests/integration/ai_decision_contract.rs

Comment on lines +8878 to +8880
counters.state_clone_for_legality, 3,
"every target choice and CancelCast must pass through the reducer before the \
AI receives the engine-issued decision domain"

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Require a forward target action in this regression.

The clone count does not prove that the AI selected a target. The later action.is_some() and contract-membership assertions also accept GameAction::CancelCast. If the unmodeled-target path cancels while legal target candidates remain, this test stays green and the AI drops the spell instead of resolving the target prompt. Assert Some(GameAction::ChooseTarget { target: Some(_) }).

Proposed assertion
-        assert!(
-            action.is_some(),
-            "a required target slot with legal choices must always retain a forward action"
-        );
+        assert!(
+            matches!(
+                action.as_ref(),
+                Some(GameAction::ChooseTarget { target: Some(_) })
+            ),
+            "a required target slot with legal choices must select a concrete target"
+        );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
counters.state_clone_for_legality, 3,
"every target choice and CancelCast must pass through the reducer before the \
AI receives the engine-issued decision domain"
assert!(
matches!(
action.as_ref(),
Some(GameAction::ChooseTarget { target: Some(_) })
),
"a required target slot with legal choices must select a concrete target"
);
🤖 Prompt for 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.

In `@crates/phase-ai/src/search.rs` around lines 8878 - 8880, Strengthen the
regression assertion around the AI decision in the target-selection test to
require Some(GameAction::ChooseTarget { target: Some(_) }), rather than
accepting any action or CancelCast. Keep the existing reducer clone-count and
contract-membership checks, but ensure the test fails when the target prompt is
canceled while legal targets remain.

@matthewevans
matthewevans added this pull request to the merge queue Aug 12, 2026
Merged via the queue into main with commit 3784828 Aug 12, 2026
18 of 19 checks passed
@matthewevans
matthewevans deleted the ship/fix-filter-uncompletable-ai-target-proposals branch August 12, 2026 02:57
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.

1 participant