feat: SQL migration for evolution tables and variant/image_url columns (#69) #84
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#84
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "ai/paper-dynasty-database#69"
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?
Closes #69
Summary
migrations/2026-03-12_add_evolution_tables.sql— idempotent PostgreSQL migration wrapped inBEGIN/COMMITthat creates 5 new tables and adds 3 columns to existing tables.tests/test_evolution_migration.py— 16 unit tests validate SQL file structure; 6 integration tests annotated for PostgreSQL execution (auto-skipped whenPOSTGRES_HOSTis not set).tests/__init__.pyandtests/conftest.pyadded (shared test harness needed by this and future test modules).Tables Created
player_season_statsevolution_trackevolution_card_stateevolution_tier_boostevolution_card_stateevolution_cosmeticevolution_card_stateColumns Added
cardvariantINTEGER NULL DEFAULT NULLbattingcardimage_urlVARCHAR(500) NULLpitchingcardimage_urlVARCHAR(500) NULLIdempotency
Every DDL statement uses
IF NOT EXISTS— running the migration twice is safe:CREATE TABLE IF NOT EXISTSfor all 5 tablesCREATE [UNIQUE] INDEX IF NOT EXISTSfor all 4 indexesALTER TABLE ... ADD COLUMN IF NOT EXISTSfor all 3 column additionsSchema Notes
player_season_stats: UNIQUE index on(player_id, team_id, season); non-unique indexes on(team_id, season)and(player_id, season)— matches theModelIndexpattern in WP-02.evolution_track.card_typehas aUNIQUEconstraint (batter/sp/rp).evolution_trackcolumns uset1_threshold…t4_thresholdnaming (matching the WP-01/WP-02 Peewee model).player_season_stats.kstores pitcher Ks (renamed fromsoto avoid collision with battingso).Test Results
Other observations
tests/conftest.pyis identical to the one introduced in the WP-02 branch (ai/paper-dynasty-database#67) which has not yet been merged intonext-release. If WP-02 merges first, there may be a trivial merge conflict on this file — content is identical so it will resolve cleanly.AI Code Review
Verdict: REQUEST_CHANGES
(Gitea self-review restriction prevented posting as a formal review — submitting as comment instead.)
Files Reviewed
migrations/2026-03-12_add_evolution_tables.sql(added)tests/__init__.py(added, empty)tests/conftest.py(added)tests/test_evolution_migration.py(added)Findings
Correctness
Migration SQL — correct:
REFERENCES player(player_id)(Player uses a non-standard PK name),REFERENCES team(id),REFERENCES stratgame(id)— all verified againstdb_engine.py.player_season_statsmatches the WP-02 Peewee model exactly: UNIQUE on(player_id, team_id, season), non-unique on(team_id, season)and(player_id, season).evolution_track → evolution_card_state → evolution_tier_boost/evolution_cosmeticdependency order is correct.IF NOT EXISTS; wrapped inBEGIN/COMMIT. Idempotency is thorough.ALTER TABLEstatements (card.variant,battingcard.image_url,pitchingcard.image_url) match what the Peewee models are missing and what the PR describes.Missing
pg_connfixture — REQUEST_CHANGES:tests/test_evolution_migration.pycontains 6 integration tests that acceptpg_connas a fixture parameter (e.g.def test_integration_fresh_migration_creates_all_tables(pg_conn)). Nopg_connfixture is defined anywhere intests/conftest.pyor in the test file itself.When
POSTGRES_HOSTis set, the@pytestmark_integrationskip is lifted and pytest collects these tests — at which point all 6 will immediately fail withfixture 'pg_conn' not found. The PR body explicitly presents integration test coverage as a deliverable, so the fixture must ship with the PR.Minimal fix for
tests/conftest.py:Security
No issues. No
[REDACTED]regressions, no hardcoded credentials, no user-controlled SQL input.Style & Conventions
Migration style is consistent with
2026-03-04_add_scout_opportunities_claims.sql(header comment,BEGIN, DDL,COMMIT, verification block, rollback block). ✓Suggestions
test_integration_existing_data_preserved: assertscount >= 0for each of the three tables — trivially always true. A more useful assertion would verify new columns areNULLon existing rows (e.g.SELECT variant FROM card LIMIT 1→ expectNULL). Minor — not a blocker on its own.Summary
The migration SQL is solid: schema is correct, FK references verified against Peewee models, idempotency is complete, matches the WP-02 PlayerSeasonStats model. The 16 SQL unit tests are thorough.
The single blocker is the missing
pg_connfixture. As soon asPOSTGRES_HOSTis set, all 6 integration tests fail with a fixture error before they can run. Add the fixture totests/conftest.py.Automated review by Claude PR Reviewer
Review Feedback Addressed
Addressed the single blocker from the REQUEST_CHANGES review:
Added
pg_connfixture totests/conftest.py(commit094f445)The 6 integration tests in
test_evolution_migration.pyall acceptpg_connas a fixture parameter but no such fixture existed anywhere. WhenPOSTGRES_HOSTis set, pytest collects these tests and they immediately fail withfixture 'pg_conn' not foundbefore any test body executes.The added fixture:
POSTGRES_HOST,POSTGRES_DB,POSTGRES_USER,POSTGRES_PASSWORD,POSTGRES_PORT)No other changes were made.
AI Code Review
Files Reviewed
migrations/2026-03-12_add_evolution_tables.sql(added)tests/__init__.py(added, empty)tests/conftest.py(added)tests/test_evolution_migration.py(added)Note: This is a re-review. The previous REQUEST_CHANGES (2026-03-12) identified a blocker: the 6 integration tests referenced a
pg_connfixture that was not defined anywhere. That issue is now fixed.Findings
Correctness
pg_connfixture — blocker resolved.conftest.pynow definespg_connas asession-scoped psycopg2 fixture. The fixture runs the migration, yields the connection, then rolls back and closes at teardown. The previous blocker is fully resolved.Partial rollback risk in
test_integration_idempotent_rerun. This test callspg_conn.commit()directly, which permanently commits the second migration run. Theconn.rollback()in the fixture teardown only undoes work after that commit — schema changes from initial setup are already committed in the fixture. In effect, the integration tests always leave schema changes in the dev database. Mitigated by the migration being idempotent. Not a blocker.test_integration_existing_data_preservedassertion is still trivially true.assert count >= 0on an integer row count can never fail. Noted in the previous review. Suggestion only.Skip logic does not use
pytest.mark.integration. The module docstring instructspytest tests/test_evolution_migration.py -m integrationbutpytestmark_integrationispytest.mark.skipif(...), notpytest.mark.integration. Filtering with-m integrationcollects zero tests. The skip-when-no-POSTGRES_HOST mechanism works correctly, but the documented invocation does not. Minor documentation inaccuracy.SQL migration — no issues. FK references correct (
player(player_id),team(id),stratgame(id),evolution_track(id)). All 5CREATE TABLE IF NOT EXISTS, 4CREATE [UNIQUE] INDEX IF NOT EXISTS, and 3ALTER TABLE ... ADD COLUMN IF NOT EXISTSstatements present.BEGIN/COMMITwraps the forward migration correctly.16 unit tests — correct. Comment-stripping in
_load_sql()prevents false positives on rollback DROP statements. The word-boundary pattern\bk\bfor the pitcher Ks column is well-considered. Index column coverage tests parse the actual index definition lines.Security
No issues. No user input paths, no credential exposure, no
[REDACTED]regressions.Style & Conventions
No issues. Migration follows the date-prefixed filename convention.
conftest.pydocstring explains the DATABASE_TYPE injection rationale clearly. Test docstrings cover both what and why.Suggestions
test_integration_existing_data_preserved: Replaceassert count >= 0with a meaningful assertion — snapshot the count before and after migration, or assertcount > 0if the dev DB is expected to have data.-m integrationmarker: Addpytestmark = pytest.mark.integrationat module level so thatpytest -m integrationworks as documented.Fixture docstring accuracy: The
pg_conndocstring says the migration "is not persisted to the dev database between test runs" butconn.commit()in fixture setup permanently writes the schema. Update the docstring to reflect that the migration is persisted (acceptable given idempotency).Verdict: APPROVED
The previous blocker (
pg_connfixture not defined) is resolved. The migration SQL is correct and idempotent. The 16 unit tests are thorough. Integration tests work correctly whenPOSTGRES_HOSTis set. The remaining items (trivial assertion,-m integrationmarker mismatch, fixture docstring inaccuracy) are suggestions that do not block merging.Automated review by Claude PR Reviewer
AI Code Review
Files Reviewed
migrations/2026-03-12_add_evolution_tables.sql(added)tests/__init__.py(added)tests/conftest.py(added)tests/test_evolution_migration.py(added)Findings
Correctness
1.
conftest.py—pg_connfixture will NOT roll back the migration (critical)The migration SQL file contains its own
BEGIN; ... COMMIT;block. Whenpg_connrunsconn.cursor().execute(fh.read())followed byconn.commit(), theCOMMITinside the SQL file executes first, permanently committing the schema changes to the dev database. The subsequentconn.rollback()in teardown only rolls back any DML issued after that point — the DDL is already durable.The docstring says "The connection is rolled back and closed at session teardown so that the migration is not persisted to the dev database between test runs" — this claim is false. The integration tests will permanently mutate the dev schema on every run.
Options: strip the
BEGIN/COMMITwrapper before executing in the fixture, or accept that integration tests are run-once and update the docstring to reflect reality. Either way the current state is a lie in the docstring with a broken teardown promise.2.
player_season_stats—inningscolumn replaced byoutswithout documentationThe PRD (06-database.md) defines
innings NUMERIC(5,1) NOT NULL DEFAULT 0for tracking pitcher innings pitched. The migration instead usesouts INTEGER NOT NULL DEFAULT 0with no explanation in the PR body or a code comment. Storing outs-recorded as an integer is a valid, lossless alternative to the decimal innings format, but this is a silent schema deviation from the locked spec. If WP-02 (the Peewee model) already usesouts, then the migration is correct — but this PR should explicitly call out the discrepancy so the reviewer can confirm alignment with WP-02's model fields.3.
evolution_card_state— missingprogress_sincecolumnThe PRD defines
progress_since TIMESTAMP NOT NULLonevolution_card_stateto record the earliestcard.created_atfor the player+team pair. This column is used by the evaluator to scope which game records are eligible. It is absent from the migration. If it is intentionally deferred, the PR body should say so.4.
image_formatcolumn missing frombattingcard/pitchingcardThe PRD (06-database.md §6.2) specifies adding both
image_url VARCHAR(500)andimage_format VARCHAR(10) NULL DEFAULT 'png'to both card tables.image_formatdistinguishes static PNG from animated APNG cards (relevant to the cosmetics revenue model). The migration adds onlyimage_url. Ifimage_formatis deferred, it needs its own migration later; if it was simply overlooked, it should be added here.5.
evolution_milestoneandevolution_progresstables absentThe PRD defines two additional tables (
evolution_milestone,evolution_progress) as core to Phase 1. The PR body explains the two stub tables (evolution_tier_boost,evolution_cosmetic) but does not explain the absence ofevolution_milestone/evolution_progress. If these are handled by a separate WP, note it explicitly. If they are intentionally excluded from Phase 1, that is a departure from the PRD that needs acknowledgement.Security
No issues found. No user input reaches this file. FKs use
ON DELETE CASCADE/ON DELETE SET NULLappropriately. No hardcoded credentials.Style & Conventions
The migration format (date prefix,
BEGIN/COMMIT,IF NOT EXISTSthroughout, verification queries, rollback section) is consistent with the existing migration2026-03-04_add_scout_opportunities_claims.sql. Good.One minor inconsistency: the existing migration does not include a
-- Dependencies:header line; the new migration does. Not a problem, just an addition to the convention.FK column name correctness (good catch): The migration correctly uses
REFERENCES player(player_id)to matchPlayer.player_id = IntegerField(primary_key=True). The PRD SQL examples incorrectly writeREFERENCES player(id)which would fail — the migration fixed this silently and correctly.Test Coverage
The 16 unit tests are well-structured and appropriately thorough for a migration file. Pattern matching against the stripped SQL is a sound approach. The
test_player_season_stats_columnstest uses are.DOTALLblock extraction which will correctly scope column checks.One gap: there is no unit test asserting that
player_season_statsusesREFERENCES player(player_id)rather thanREFERENCES player(id). Given that the PRD has the wrong column name and someone could cargo-copy the PRD, a test pinning the correct FK column would prevent regression.Verdict: REQUEST_CHANGES
Four issues need resolution before merge:
pg_connfixture's rollback behaviour. The integration test teardown does not do what the docstring claims.outsvsinnings NUMERIC(5,1)is intentional and aligned with the WP-02 Peewee model.progress_sinceonevolution_card_stateandimage_formaton the card tables — either add the columns or note the deferral with an issue reference.evolution_milestone/evolution_progresstables.Issues 2–4 can be addressed as PR body updates if the omissions are genuinely intentional WP-scope decisions; only issue 1 requires a code change.
Automated review by Claude PR Reviewer
@ -0,0 +52,4 @@-- Pitching statsgames_pitching INTEGER NOT NULL DEFAULT 0,outs INTEGER NOT NULL DEFAULT 0,PRD §6.1 specifies
innings NUMERIC(5,1) NOT NULL DEFAULT 0here. Usingouts INTEGERis a lossless alternative (1 IP = 3 outs) but it is an undocumented divergence from the locked spec. Please confirm this matches the WP-02 Peewee model field name and add a comment explaining the choice (e.g.-- stored as outs to avoid NUMERIC; 1 IP = 3 outs).@ -0,0 +97,4 @@CREATE TABLE IF NOT EXISTS evolution_card_state (id SERIAL PRIMARY KEY,player_id INTEGER NOT NULL REFERENCES player(player_id) ON DELETE CASCADE,team_id INTEGER NOT NULL REFERENCES team(id) ON DELETE CASCADE,PRD §6.1 defines
progress_since TIMESTAMP NOT NULLonevolution_card_state— the earliestcard.created_atamong all card instances of this player on this team. This scopes which game records count toward evolution progress. It is absent here. Intentionally deferred?@ -0,0 +133,4 @@-- ---------------------------------------------- 7. Add battingcard.image_url column-- --------------------------------------------ALTER TABLE battingcardPRD §6.2 specifies
image_format VARCHAR(10) NULL DEFAULT 'png'alongsideimage_urlon bothbattingcardandpitchingcard. This column distinguishes static PNG from animated APNG cosmetics and is part of the image lookup logic described in the PRD. Is this intentionally deferred? If so, please note the tracking issue.@ -0,0 +34,4 @@port=int(os.environ.get("POSTGRES_PORT", "5432")),)conn.autocommit = Falsemigration_path = os.path.join(The migration SQL contains
BEGIN; ... COMMIT;. When this fixture callsconn.cursor().execute(fh.read())and thenconn.commit(), theCOMMITinside the SQL fires during execute and permanently durably commits the DDL. Theconn.rollback()at teardown has no effect on the already-committed schema changes.The docstring promise — "The connection is rolled back and closed at session teardown so that the migration is not persisted to the dev database between test runs" — is incorrect as written.
Fix options:
BEGIN;/COMMIT;from the SQL before executing, so the transaction is under the fixture's control.AI Code Review
Files Reviewed
migrations/2026-03-12_add_evolution_tables.sql(added)tests/__init__.py(added)tests/conftest.py(added)tests/test_evolution_migration.py(added)Findings
Correctness — BLOCKING
The migration creates a table that no longer exists in the ORM.
The migration creates a single
player_season_statstable (lines 30–70 of the SQL file). However, thecard-evolutionbase branch has since been refactored across multiple merged PRs to split this into two separate tables:batting_season_stats—BattingSeasonStatsmodel,table_name = "batting_season_stats"pitching_season_stats—PitchingSeasonStatsmodel,table_name = "pitching_season_stats"Running this migration on the dev or prod database will create
player_season_stats, which is an orphaned table. The ORM will never read from or write to it, so evolution evaluation depending on season stats will silently produce no results (or errors if it tries to query a non-existent table).Additionally, the column layout in the migration no longer matches what the ORM expects:
sostrikeoutsgames_battinggamessac,ibb,gidp,games_started,runs_allowed,earned_runs,hbp(pitching),wild_pitches,balkskstrikeouts(PitchingSeasonStats)bb_allowedbb(PitchingSeasonStats)The migration was authored against an earlier schema design. It needs to be rewritten to match the current ORM state on
card-evolution.The conftest.py in this PR conflicts with the one already on the base branch.
The base branch (
card-evolution) already has atests/conftest.pythat includes apg_connfixture (added in the merge of PR #108). The conftest.py in this PR addspsycopg2imports and thepg_connfixture as if they are new — but the base already has them. If this PR is merged, the file will overwrite the version that is already in use by the other test files oncard-evolution. This is a merge conflict risk noted in the PR body, but the content is not identical to the current base — the base version already evolved past what this PR ships.Security
No issues found. No credentials, no user-controlled input in the migration.
Style & Conventions
The SQL migration structure follows the established project pattern set by
migrations/2026-03-04_add_scout_opportunities_claims.sql—BEGIN/COMMITwrapper,IF NOT EXISTSguards, verification and rollback comment blocks, and date-prefixed filename. This is well-executed.The unit test structure (file-content regex checks without a live DB) is a reasonable pattern for a SQL migration. The tests are well-documented with docstrings explaining both "what" and "why," which matches project conventions.
Suggestions
batting_season_statsandpitching_season_stats, the unit tests intest_evolution_migration.pywill also need updating — particularlytest_player_season_stats_columns()and all integration tests that referenceplayer_season_stats.conftest.pyshould be compared carefully against what already exists oncard-evolutionbefore overwriting — specifically around thepg_connfixture scope and teardown behavior.evolution_tier_boostandevolution_cosmeticneed any additional columns before this migration ships, since adding columns to stub tables later requires another migration.Verdict: REQUEST_CHANGES
The migration creates
player_season_stats, a table the ORM no longer uses. The base branch has already landed a refactor (PRs #105, #106, and subsequent merges) that split this intobatting_season_statsandpitching_season_statswith different column names. Running this migration as written creates dead schema and the evolution evaluation system will not function correctly. The migration file needs to be rewritten to match the current ORM state before this can merge.Automated review by Claude PR Reviewer
Schema Drift Review — Migration Does NOT Match the ORM
The previous review that flagged schema drift was correct. After a line-by-line comparison of the migration SQL against the Peewee models in
app/db_engine.pyon thecard-evolutionbase branch (shab68e280), I found five concrete mismatches. The migration cannot be merged as-is.Issue 1 (Critical) —
player_season_statstable should not existThe migration creates a single monolithic
player_season_statstable combining batting and pitching columns. The ORM oncard-evolutionhas two separate tables:BattingSeasonStats→table_name = "batting_season_stats"PitchingSeasonStats→table_name = "pitching_season_stats"These are defined at lines 1053 and 1104 of
db_engine.py. The migration'splayer_season_statstable would leave Peewee pointing at nonexistent tables and the actualbatting_season_stats/pitching_season_statstables would not exist in the database.Required fix: Replace the single
player_season_statsDDL block with two separateCREATE TABLE IF NOT EXISTS batting_season_statsandCREATE TABLE IF NOT EXISTS pitching_season_statsblocks, with columns matching each ORM model exactly. The three-index pattern (unique on player/team/season, non-unique on team/season, non-unique on player/season) applies to both.Issue 2 (Critical) —
evolution_tier_booststub is missing all real columnsThe migration creates
evolution_tier_boostas a stub with onlyid+card_state_id. The ORM model (EvolutionTierBoost, line 1249) has:There is also a unique index on
(track, tier, boost_type, boost_target). None of this is in the migration. Thecard_state_idFK in the migration doesn't exist in the ORM at all —EvolutionTierBoostreferencesEvolutionTrack, notEvolutionCardState.Required fix: Replace the stub with the full column set and the composite unique index.
Issue 3 (Critical) —
evolution_cosmeticstub has wrong FK and missing columnsThe migration's
evolution_cosmeticstub has onlyid+card_state_id FK → evolution_card_state. The ORM model (EvolutionCosmetic, line 1274) has:There is no
card_state_idcolumn in the ORM —EvolutionCosmeticis a standalone lookup table, not keyed to a card state. The migration's FK is fabricated.Required fix: Replace the stub with the full column set; remove the erroneous
card_state_idFK.Issue 4 (Minor) —
evolution_trackis missing the UNIQUE constraint onnameThe ORM defines
name = CharField(unique=True)onEvolutionTrack. The migration definesUNIQUEoncard_typebut has no unique constraint onname. This means a duplicate track name could be inserted in SQL even though the ORM would reject it at the application layer.Required fix: Add
name VARCHAR(255) NOT NULL UNIQUE(or a separateCREATE UNIQUE INDEX) forevolution_track.name.Issue 5 (Minor) —
card.variantcolumn not present in theCardORM modelThe migration adds
ALTER TABLE card ADD COLUMN IF NOT EXISTS variant INTEGER NULL DEFAULT NULL. TheCardmodel oncard-evolution(line 472) has novariantfield. This column addition is either premature (the ORM hasn't been updated yet) or targeting the wrong table —variantalready exists as a non-nullIntegerFieldonBattingCardandPitchingCard.If this column is genuinely intended for
Card, the ORM model needs to be updated on the branch before or alongside this migration. If it is not intended, the ALTER should be removed.What IS correct
evolution_trackcolumn set (name, card_type, formula, t1–t4_threshold) matches the ORM.evolution_card_statecolumn set and the UNIQUE index on (player_id, team_id) match exactly.battingcard.image_urlandpitchingcard.image_urladditions are fine as migration-ahead-of-ORM columns (safe with IF NOT EXISTS).Summary
The schema drift is real and substantial. Issues 1–3 are blocking: the migration would produce a database that the ORM cannot operate against. Issues 4–5 are minor but should be resolved in the same pass. The fix requires rewriting the
player_season_statsblock into two tables, replacing both Phase 2 stubs with their actual column definitions, and adding the missing unique constraint onevolution_track.name.@ -0,0 +26,4 @@BEGIN;-- ---------------------------------------------- 1. player_season_statsThis table does not match the ORM. The base branch (
card-evolution) defines two separate models:BattingSeasonStats(tablebatting_season_stats) andPitchingSeasonStats(tablepitching_season_stats). This single combined table will leave both ORM models pointing at nonexistent tables.@ -0,0 +84,4 @@id SERIAL PRIMARY KEY,name VARCHAR(255) NOT NULL,card_type VARCHAR(255) NOT NULL UNIQUE, -- batter / sp / rpformula VARCHAR(255) NOT NULL,The ORM defines
name = CharField(unique=True)onEvolutionTrack, but the migration only defines UNIQUE oncard_type. A UNIQUE constraint onnameis missing.@ -0,0 +105,4 @@last_evaluated_at TIMESTAMP NULL);CREATE UNIQUE INDEX IF NOT EXISTS evolution_card_state_player_team_uniqStub is missing all real columns. The
EvolutionTierBoostORM model has:track(FK to evolution_track),tierINTEGER,boost_typeVARCHAR,boost_targetVARCHAR,boost_valueDOUBLE PRECISION, plus a unique index on (track, tier, boost_type, boost_target). Thecard_state_idFK here does not exist in the ORM at all.@ -0,0 +114,4 @@CREATE TABLE IF NOT EXISTS evolution_tier_boost (id SERIAL PRIMARY KEY,card_state_id INTEGER NOT NULL REFERENCES evolution_card_state(id) ON DELETE CASCADE);Stub is missing all real columns and has the wrong FK. The
EvolutionCosmeticORM model is a standalone lookup table with:nameVARCHAR UNIQUE,tier_requiredINTEGER,cosmetic_typeVARCHAR,css_classVARCHAR NULL,asset_urlVARCHAR NULL. There is nocard_state_idreference in the ORM model.@ -0,0 +123,4 @@id SERIAL PRIMARY KEY,card_state_id INTEGER NOT NULL REFERENCES evolution_card_state(id) ON DELETE CASCADE);The
CardORM model on this branch does not have avariantfield. If this column is intentional, theCardmodel needs to be updated. If not, this ALTER should be removed —variantalready exists onbattingcardandpitchingcardas a non-null column.Closing — the migration was already applied to dev manually. The SQL in this PR has schema drift (single player_season_stats vs split batting/pitching tables, incorrect stubs for tier_boost and cosmetic). Creating a fresh migration PR generated from the actual dev schema.
Pull request closed