Skip to content

fix(deck): reject duplicate command-zone Oracle cards on card add - #1295

Open
KaelSensei wants to merge 1 commit into
devfrom
fix/card-add-command-pairing-20261108
Open

KaelSensei wants to merge 1 commit into
devfrom
fix/card-add-command-pairing-20261108

Conversation

@KaelSensei

Copy link
Copy Markdown
Owner

Roadmap item

I-03 Trustworthy Deck Feedback (Now) → Validate commander and partner mechanics at the deck API boundary, including imported pairs and the same Oracle card across different printings.

#1131 added the same-Oracle check to deck create (POST /api/decks) and update (PATCH /api/decks/[id]). The command-zone card row itself is written via a third boundary, POST /api/decks/[id]/cards, which accepted isCommander: true / isPartner: true with no pairing check. That meant a direct request could write a partner row that reprints the commander's Oracle card, or a commander row that reprints the saved partner's.

Change

  • src/lib/deck/commander-pairing.ts: new duplicatesOtherCommandSlot(cardId, otherSlotId). It returns false when the other slot is empty, true for the same printing without calling Scryfall, and otherwise falls back to sharesOracleIdentity.
  • src/app/api/decks/[id]/cards/route.ts: for a command-zone card, the route compares the partner with the deck's commanderId and the commander with its partnerId. A duplicate gets a 400 with the existing message, "Commander and partner must be different cards", before any row is written. Main, sideboard and maybeboard additions skip the extra lookup and the Scryfall call.

No migration, no new service and no client change. The editor's setCommander/setPartner flow already updates the deck before it adds the card, and that update is validated, so legitimate flows are unaffected.

This is one slice of the roadmap item, not all of it. Imported pairs reach the deck through the same validated PATCH and card-add path. This PR does not touch the roadmap item's checkbox, which is left to the chore/docs PR.

TDD

Red: I added src/app/api/decks/[id]/cards/route.test.ts (5 sociable route tests: Prisma, auth and Scryfall mocked) and ran npx vitest run cards/route.test before changing the route:

× rejects a partner card that reprints the commander's Oracle card        → expected 201 to be 400
× rejects a commander card that reprints the saved partner's Oracle card  → expected 201 to be 400
× rejects a partner card with the exact commander printing without asking Scryfall → expected 201 to be 400
✓ adds a partner card with a different Oracle identity
✓ adds main-deck cards without a command-slot or Scryfall lookup
Tests  3 failed | 7 passed (10)

Green: 10/10 pass after the change.

Verification

  • npx tsc --noEmit: 0 errors
  • pnpm lint: no ESLint warnings or errors
  • pnpm test: 345 files, 3515 tests passed
  • Pre-push Docker Playwright: 74 passed and 8 passed (authenticated project). The hook printed "E2E passed — push allowed".
  • pnpm sonar: not run, because there is no .env.sonar in this worktree. Sonar was left to CI.

🤖 Generated with Claude Code

POST /api/decks/[id]/cards accepted a commander or partner card that
repeats the Oracle card held by the opposite command slot, bypassing the
check deck create and update already enforce (#1131). A command-zone card
is now compared with the opposite slot by printing ID, then by Oracle
identity, and rejected with 400 before any row is written.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Nov 8, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
magic-ai-builder Ready Ready Preview Nov 8, 2026 7:17pm UTC

@chatgpt-codex-connector

Copy link
Copy Markdown
Codex Review Summary: ❌ Failed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ❌ Failed 2026-11-08T19:15:14.329526Z
We couldn’t complete this review. Comment @codex review to try again.
a1dd654 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Nov 8, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 8e90bc4d-5170-46c5-84a7-def3e263c1fa

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@sonarqubecloud

sonarqubecloud Bot commented Nov 8, 2026

Copy link
Copy Markdown

This branch was successfully deployed

1 active deployment
Preview — a1dd6543 Deployed Nov 8, 2026 by vercel[bot]
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