Skip to content

fix(draft): put suggested nonbasic lands on main_deck - #6711

Open
wondercreatemaster wants to merge 1 commit into
phase-rs:mainfrom
wondercreatemaster:fix/6562-draft-suggest-nonbasic-lands
Open

fix(draft): put suggested nonbasic lands on main_deck#6711
wondercreatemaster wants to merge 1 commit into
phase-rs:mainfrom
wondercreatemaster:fix/6562-draft-suggest-nonbasic-lands

Conversation

@wondercreatemaster

@wondercreatemaster wondercreatemaster commented Jul 27, 2026

Copy link
Copy Markdown

Summary

Fixes #6562: suggested drafted duals were placed in lands, but the limited deckbuilder only exposes lands for addable basics and computeRemainingPool only subtracts mainDeck. Duals stayed visible in the pool, players could add them again, and submit expanded both maps → ExceedsPoolCount (often as a silent “deck validation failed”). Drafted nonbasics now go on main_deck; lands stays basics-only. ValidationFailed Display includes per-card errors, and the submit button surfaces that message in-app.

Files changed

  • crates/draft-wasm/src/suggest.rs — admit fixing lands onto main_deck; update unit tests
  • crates/draft-core/src/types.rs — include LimitedDeckErrors in ValidationFailed Display + regression test
  • client/src/components/draft/LimitedDeckBuilder.tsx — show submit validation errors in-app

Track

Developer

LLM

Model: Composer
Tier: Frontier
Thinking: high

Implementation method (required)

Method: not-applicable — draft-wasm / draft-core / limited deckbuilder UI, not crates/engine/ game rules. No /engine-implementer path.

CR references

None — Limited deck construction / tournament UI, not MTG Comprehensive Rules game logic.

Verification

  • Gate A output below is for the current committed head.
  • Both anchors cite existing analogous code at the same seam.
  • Local cargo test deferred — no Rust toolchain in this environment; CI will run draft-wasm / draft-core tests.
  • scripts/check-parser-combinators.sh origin/mainGate A PASS (no parser files touched).

Gate A

Gate A PASS head=6f2f0093ab36e2330a21da7a701abf66fdda18f2 base=e9a268a4d5ef4db00dd903ed2e1c1f6ceebcd95a

Anchored on

  • crates/draft-wasm/src/suggest.rs — existing comment that consumers concatenate main_deck + lands (double-count hazard); nonbasics belong with drafted cards in main_deck
  • crates/draft-core/src/validation.rsLimitedDeckError already carries per-card Display text; ValidationFailed now forwards it the same way other DraftError variants surface detail

Final review-impl

Final review-impl PASS head=6f2f0093ab36e2330a21da7a701abf66fdda18f2 — non-engine draft suggest/validation Display fix; tests updated for main_deck placement and Display content.

Claimed parse impact

None.

Scope Expansion

None.

Validation Failures

None.

CI Failures

None.

Made with Cursor

Summary by CodeRabbit

  • Bug Fixes
    • Limited deck submission errors are now shown directly in the deck builder.
    • Validation messages provide detailed card-specific reasons for rejected decks.
    • Drafted nonbasic fixing lands are now correctly included in the main deck when eligible.
    • Deck suggestions continue to exclude off-color fixing lands and maintain valid deck-size totals.

Drafted duals were stuffed into `lands`, which the limited deckbuilder only
renders for addable basics — so they stayed visible in the pool, got added
again, and submit double-counted them as ExceedsPoolCount. Also surface
per-card ValidationFailed details in the error Display and submit UI.

Fixes phase-rs#6562
@github-actions github-actions Bot added the needs-maintainer AI-contribution PR requires human triage (Non-dev track or unresolved gaps) label Jul 27, 2026
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Suggested deck construction now places drafted nonbasic fixing lands in main_deck instead of lands. Deck validation errors include per-card details, and the draft UI displays submission failures inline.

Changes

Limited deck flow

Layer / File(s) Summary
Suggested deck land placement
crates/draft-wasm/src/suggest.rs
Nonbasic fixing lands are added to main_deck, while lands contains only addable basic or fixed cards; tests cover color eligibility and deck-size invariants.
Submission validation error reporting
crates/draft-core/src/types.rs, client/src/components/draft/LimitedDeckBuilder.tsx
ValidationFailed includes per-card details, and submission failures are captured and rendered in an inline alert.

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

Possibly related PRs

Suggested reviewers: matthewevans

🚥 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 is concise and accurately describes the main change to draft deck suggestion handling.
Linked Issues check ✅ Passed The PR addresses #6562 by preventing nonbasic lands from being double-counted and surfacing validation failures to users.
Out of Scope Changes check ✅ Passed The validation error display and UI error handling are in scope because they support the linked issue's submission-failure fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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: 2

🤖 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 `@client/src/components/draft/LimitedDeckBuilder.tsx`:
- Around line 366-379: Update the submission handler in LimitedDeckBuilder’s
onClick flow to guard against an in-flight submitDeck call, disable the
associated button while submission is active, and clear the guard in a finally
block. Preserve the existing error extraction and setSubmitError behavior, while
ensuring rapid clicks cannot start concurrent submissions.

In `@crates/draft-wasm/src/suggest.rs`:
- Around line 121-128: Update the suggested-deck contract around SuggestedDeck
so main_deck remains usable by existing spell-only consumers: expose a separate
engine-provided spell count or otherwise provide distinct spell and land data in
the shared contract, and update consumers to use that field. Ensure
LimitedDeckBuilder and other frontend code render the engine-provided values
without calculating or filtering card data in React.
🪄 Autofix (Beta)

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: d175a86d-ba50-44a3-9c39-72475874b139

📥 Commits

Reviewing files that changed from the base of the PR and between e9a268a and 6f2f009.

📒 Files selected for processing (3)
  • client/src/components/draft/LimitedDeckBuilder.tsx
  • crates/draft-core/src/types.rs
  • crates/draft-wasm/src/suggest.rs

Comment on lines +366 to +379
onClick={async () => {
setSubmitError(null);
try {
await submitDeck();
} catch (err) {
const message =
err instanceof Error
? err.message
: typeof err === "string"
? err
: String(err);
setSubmitError(message);
}
}}

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Prevent concurrent deck submissions.

This handler allows rapid clicks to invoke submitDeck() multiple times concurrently. Because each completion writes submitError, an older failed request can overwrite the result of a newer successful submission. Add an in-flight guard, disable the button while submitting, and clear the guard in finally.

As per path instructions, async races in frontend submission flows must be handled explicitly.

Suggested guard
+  const [isSubmitting, setIsSubmitting] = useState(false);
+
              onClick={async () => {
+                if (isSubmitting) return;
+                setIsSubmitting(true);
                 setSubmitError(null);
                 try {
                   await submitDeck();
                 } catch (err) {
                   const message =
                     err instanceof Error
                       ? err.message
                       : typeof err === "string"
                         ? err
                         : String(err);
                   setSubmitError(message);
+                } finally {
+                  setIsSubmitting(false);
                 }
              }}
-             disabled={!deckValid}
+             disabled={!deckValid || isSubmitting}
📝 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
onClick={async () => {
setSubmitError(null);
try {
await submitDeck();
} catch (err) {
const message =
err instanceof Error
? err.message
: typeof err === "string"
? err
: String(err);
setSubmitError(message);
}
}}
const [isSubmitting, setIsSubmitting] = useState(false);
onClick={async () => {
if (isSubmitting) return;
setIsSubmitting(true);
setSubmitError(null);
try {
await submitDeck();
} catch (err) {
const message =
err instanceof Error
? err.message
: typeof err === "string"
? err
: String(err);
setSubmitError(message);
} finally {
setIsSubmitting(false);
}
}}
🤖 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 `@client/src/components/draft/LimitedDeckBuilder.tsx` around lines 366 - 379,
Update the submission handler in LimitedDeckBuilder’s onClick flow to guard
against an in-flight submitDeck call, disable the associated button while
submission is active, and clear the guard in a finally block. Preserve the
existing error extraction and setSubmitError behavior, while ensuring rapid
clicks cannot start concurrent submissions.

Source: Path instructions

Comment on lines +121 to +128
let mut main_deck = spell_names;
for (name, count) in nonbasic_lands {
*lands.entry(name).or_insert(0) += count;
for _ in 0..count {
main_deck.push(name.clone());
}
}

SuggestedDeck {
main_deck: spell_names,
lands,
}
SuggestedDeck { main_deck, lands }

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.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Preserve the main_deck consumer contract.

main_deck now includes nonbasic lands, but client/src/components/draft/LimitedDeckBuilder.tsx, Line 259 still passes mainDeck.length as the spells count. Every suggested dual will therefore inflate the UI’s spell count (and any other spell-only consumer). Expose a separate engine-provided spell count or update the shared deck contract; do not filter card data in React.

As per path instructions, the frontend must only render engine-provided state and must not calculate or filter game data.

🤖 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/draft-wasm/src/suggest.rs` around lines 121 - 128, Update the
suggested-deck contract around SuggestedDeck so main_deck remains usable by
existing spell-only consumers: expose a separate engine-provided spell count or
otherwise provide distinct spell and land data in the shared contract, and
update consumers to use that field. Ensure LimitedDeckBuilder and other frontend
code render the engine-provided values without calculating or filtering card
data in React.

Source: Path instructions

@matthewevans matthewevans self-assigned this Jul 27, 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.

[HIGH] Keep main_deck's consumer contract coherent after admitting nonbasic lands. Evidence: suggest.rs:121-128 now inserts drafted duals into main_deck, while LimitedDeckBuilder.tsx:259 still passes mainDeck.length to the spells field rendered by DeckStatus as a spell count. Why it matters: every suggested nonbasic is shown as a spell, so the deck status misreports the constructed deck and any other spell-only consumer now receives a mixed card list. Suggested fix: make the shared display contract explicit—either expose the engine-owned spell count or change this UI path to render main_deck as mixed deck cards without reclassifying them in React; add a suggested-dual UI regression.

[MED] Prevent concurrent deck submissions and test the new error surface. Evidence: LimitedDeckBuilder.tsx:366-398 starts an unguarded async submitDeck for every click and writes submitError on completion; client/src/components/draft/__tests__/LimitedDeckBuilder.test.tsx has no submit rejection or in-flight test. Why it matters: rapid clicks can submit the same deck more than once and an older rejection can overwrite the state from a newer request; the PR's claimed in-app validation message is also unproven. Suggested fix: guard/disable while the promise is pending, clear it in finally, and add a component test that rejects onSubmitDeck and awaits the alert text.

@matthewevans matthewevans added the bug Bug fix label Jul 27, 2026
@matthewevans matthewevans removed their assignment Jul 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Bug fix needs-maintainer AI-contribution PR requires human triage (Non-dev track or unresolved gaps)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants