feat: evolution/refractor schema migration (generated from dev) #128
No reviewers
Labels
No Label
ai-changes-requested
ai-failed
ai-merged
ai-pr-opened
ai-reviewed
ai-reviewing
ai-reviewing
ai-working
bug
enhancement
evolution
performance
phase-0
phase-1a
phase-1b
phase-1c
phase-1d
security
tech-debt
todo
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: cal/paper-dynasty-database#128
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "feat/evolution-refractor-schema-migration"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Replaces #84, which was closed due to schema drift.
What
Idempotent PostgreSQL migration generated directly from
paperdynasty_devon 2026-03-23. This captures exactly what was applied manually to dev, so running it against prod will bring prod into sync.Tables Created
evolution_trackevolution_card_state(player_id, team_id)tier state: current_tier, current_value, fully_evolvedevolution_tier_boostevolution_cosmeticbatting_season_statspitching_season_statsColumns Added
cardvariantINTEGER NULLbattingcardimage_urlVARCHAR(500) NULLpitchingcardimage_urlVARCHAR(500) NULLDifferences from PR #84
player_season_statsintobatting_season_stats+pitching_season_stats(matching actual dev schema)evolution_tier_boosthas full columns (boost_type, boost_target, boost_value) — not a stubevolution_cosmetichas full columns (cosmetic_type, css_class, asset_url) — not a stub, and has no FK toevolution_card_stateevolution_card_statehas no FK toevolution_cosmetic(cosmetics are a lookup table, not per-state)ON DELETE SET NULLforlast_game_id(stratgame)Idempotency
CREATE TABLE IF NOT EXISTSfor all 6 tablesCREATE [UNIQUE] INDEX IF NOT EXISTSfor all 10 indexesALTER TABLE ... ADD COLUMN IF NOT EXISTSfor all 3 column additionsBEGIN/COMMITtransactionImportant
Do NOT run this migration against dev — it is already applied there. Target is prod only.
AI Code Review
Files Reviewed
migrations/2026-03-23_add_evolution_refractor_schema.sql(added)Findings
Correctness
CREATE TABLE IF NOT EXISTS, all 10 indexes useCREATE [UNIQUE] INDEX IF NOT EXISTS, all 3 column additions useALTER TABLE ... ADD COLUMN IF NOT EXISTS, and the whole script is wrapped inBEGIN/COMMIT. ✓player(player_id)— correct PK forPlayermodel;team(id)— correct;stratgame(id)— correct. ✓evolution_card_stateUNIQUE on(player_id, team_id)is correct — matches the application's pack-opening hook (PR #107) which usesget_or_create(player_id=..., team_id=...)against this same UNIQUE key. ✓batting_season_statsandpitching_season_statscolumns match ORM exactly — all fields inBattingSeasonStats(db_engine.py:1053) andPitchingSeasonStats(db_engine.py:1104) are reflected in the DDL, including thelast_game_id → stratgame ON DELETE SET NULLFK. ✓card.variantadded to DB but absent from theCardORM model (db_engine.py:472). Code incards.pyalready hasCard.variantreferences commented out (lines 66, 197, 354), confirming the intent. A follow-up ORM PR is needed before those code paths can be activated.battingcard.image_urlandpitchingcard.image_urladded but ORM modelsBattingCard(db_engine.py:746) andPitchingCard(db_engine.py:815) do not include these fields. No application code references them yet — DB-first is a valid approach, but a follow-up ORM PR is required before these columns are usable.EvolutionTrack,EvolutionCardState,EvolutionTierBoost,EvolutionCosmetic) are still missing fromdb_engine.py. The evolution router (routers_v2/evolution.py:20) doesfrom ..db_engine import EvolutionTrackat call time — this willImportErroruntil ORM models are added. This is a pre-existing gap from PR #100, not introduced here. The migration correctly adds the DB tables; the ORM layer needs a separate follow-up.Security
Style & Conventions
2026-03-04_add_scout_opportunities_claims.sql) includes a rollback section withDROPstatements at the bottom. This migration omits it. Minor deviation from convention — a rollback block would be helpful for emergency recovery.evolution_trackDDL comment sayscard_type is UNIQUEbut onlynamehas a UNIQUE index. NoUNIQUEconstraint exists oncard_typein the DDL. Low risk given controlled seed data, but the comment is misleading. Either addCREATE UNIQUE INDEX IF NOT EXISTS evolution_track_card_type_key ON evolution_track (card_type)or remove the claim from the comment.Suggestions
DROPstatements at the bottom to match the convention established in the earlier migration file.card_typeuniqueness with aCREATE UNIQUE INDEX IF NOT EXISTS evolution_track_card_type_key ON evolution_track (card_type)or remove the "card_type is UNIQUE" comment from the DDL block.db_engine.py; (b)Card.variant,BattingCard.image_url,PitchingCard.image_urlfields in the ORM.Verdict: COMMENT
The SQL is correct, idempotent, and FK-safe. The ORM gaps (
evolution_*models,image_urlfields,Card.variant) are expected in a DB-first migration approach — this PR's job is to sync prod schema with dev, which it does correctly. No blocking issues.Automated review by Claude PR Reviewer
Closing as superseded by work that landed today (2026-03-23).
This PR contained an idempotent schema migration for the evolution/refractor tables. That content has since shipped via two separate PRs that have been merged to
main:The schema changes described here are already present in
main. There is nothing left to merge from this branch.The branch
feat/evolution-refractor-schema-migrationcan be deleted.Pull request closed