Skip to content

✨ feat(card): add CardIdentity.ruleboxType + Ace Spec detection#533

Merged
jbourdin merged 1 commit into
developfrom
feature/card-identity-ace-spec
May 7, 2026
Merged

✨ feat(card): add CardIdentity.ruleboxType + Ace Spec detection#533
jbourdin merged 1 commit into
developfrom
feature/card-identity-ace-spec

Conversation

@jbourdin
Copy link
Copy Markdown
Owner

@jbourdin jbourdin commented May 7, 2026

Summary

Foundation for issue #532 (Staple Cards). Lands the CardIdentity.ruleboxType schema change cleanly so PR-2 can build on top.

  • New CardIdentity.ruleboxType (nullable VARCHAR(30)) captures the card's rulebox mechanic — Ace Spec, V/VMAX/VSTAR, ex/EX, GX, BREAK, Mega/Mega-classic, Radiant, Prism Star. Modeling rationale: rulebox is intrinsic to the card (one-per-deck rule for Ace Spec, etc.), not to the staple-cards curation, so it belongs on the canonical card-identity row rather than a feature-local table. Other future features (deck validation, archetype enrichment) can read it for free.
  • New App\Constants\RuleboxType enumerates 13 known rulebox types as named constants. The class docblock maps each to its detection signal (rarity check vs name suffix vs name prefix) with edge-case notes — modern Mega coexists with the ex suffix and must be checked first; classic Mega's strongest signal is stage = 'MEGA' (currently absent from the TcgdexCard struct, flagged for a future struct extension).
  • Modern Mega and classic Mega tracked separately: POKEMON_MEGA for the S&V-era "Mega Charizard X ex" pattern, POKEMON_MEGA_CLASSIC for the XY-era "M Charizard EX" pattern. Same era split as POKEMON_EX vs POKEMON_EX_CLASSIC — the two mechanics aren't interchangeable.
  • CardIdentityResolver detects Ace Spec only in this PR via the new public-static detectRuleboxType() helper (mirrors the visibility of computeAbilitySignature / computeAttackSignature). Detection runs during findOrCreateIdentity() for new identities, and backfills ruleboxType on existing ones with null values — same pattern as the existing trainerType backfill.
  • Migration Version20260507204712 adds the column and backfills the 4 currently-known Ace Spec identities (Brilliant Blender, Megaton Blower, Secret Box, Unfair Stamp) by joining card_identity to card_printing.rarity = 'ACE SPEC Rare'. The auto-generated drift from unrelated tables (banned_card index renames, sessions BLOB type, etc.) was stripped — this migration only touches card_identity.
  • 6 new resolver tests: direct method (Ace Spec / regular rarity / null rarity), new-identity-set, existing-backfill, no-overwrite, plus a markTestSkipped 27-row data-provider test enumerating the future detection cases for V/VMAX/VSTAR/ex/EX-classic/Mega/Mega-classic/G/GX/BREAK/Radiant/Prism plus collision and false-positive guards. The future-cases suite is the green target for the next PR that extends detection.

Detection of the other 12 rulebox types is deferred to follow-up PRs. Most are name-pattern based; the constants file documents the canonical signals so the next implementer doesn't have to re-derive them.

Refs #532

Test plan

  • CI green on this PR.
  • After merge + migration runs locally on dev DB: SELECT name, rulebox_type FROM card_identity WHERE rulebox_type IS NOT NULL returns exactly Brilliant Blender / Megaton Blower / Secret Box / Unfair Stamp, all ace_spec.
  • Existing card-resolution flows are unaffected: enrich a non-Ace-Spec deck via the dev environment and confirm the new ruleboxType stays null on the resolved identities.
  • Re-enrich a deck that contains an Ace Spec card and confirm the existing identity gets ruleboxType = 'ace_spec' via the backfill path (not just new-create).
  • make phpstan is green at level 10.
  • make test.unit is green; the future-cases data-provider test reports as 27 skipped (one per row).

Foundation for issue #532 (Staple Cards). Adds a nullable ruleboxType
column to CardIdentity capturing the card's rulebox mechanic — Ace Spec,
V/VMAX/VSTAR, ex/EX, GX, BREAK, Mega/Mega-classic, Radiant, Prism Star.

Modeling rationale: rulebox is intrinsic to the card identity (one-per-deck
rule, banned-card cross-cutting concerns), not specific to staple-cards
curation, so it lives on CardIdentity rather than on a feature-local table.

PR-1 detects Ace Spec only, from tcgdex_card.rarity = 'ACE SPEC Rare'.
Detection of the other 12 rulebox types is deferred to follow-up PRs;
a markTestSkipped data-provider test enumerates 27 future cases as the
green target for those PRs.

Migration backfills the 4 currently-known Ace Spec identities (Brilliant
Blender, Megaton Blower, Secret Box, Unfair Stamp) by joining card_identity
to card_printing rows whose rarity matches.

Refs #532
@sentry
Copy link
Copy Markdown

sentry Bot commented May 7, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@jbourdin jbourdin merged commit 11bd063 into develop May 7, 2026
6 checks passed
@jbourdin jbourdin deleted the feature/card-identity-ace-spec branch May 7, 2026 22:05
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