--- title: "Card Evolution Phase 1a — Schema & Data Foundation (dev branch)" description: "Phase 1a implementation details for Card Evolution on paper-dynasty-database card-evolution branch: 5 work packages, Peewee models, migration, seed data, season stats service" type: context domain: paper-dynasty tags: [paper-dynasty, evolution, database, peewee, migration, development] --- # Card Evolution Phase 1a — Schema & Data Foundation **Status:** Merged into `card-evolution` dev branch (PR #104, 2026-03-18) **NOT deployed to production** — sitting on long-lived `card-evolution` branch on paper-dynasty-database repo. **Project plan:** `card-creation/docs/prd-evolution/PHASE1_PROJECT_PLAN.md` ## What was implemented (5 work packages, 25+ tests) ### WP-01: Evolution Peewee Models - 4 new models in `app/db_engine.py`: `EvolutionTrack`, `EvolutionCardState`, `EvolutionTierBoost`, `EvolutionCosmetic` - Uses `ModelIndex` + `add_index()` for composite unique constraints - Follows existing BaseModel pattern in the monolithic db_engine.py ### WP-02: PlayerSeasonStats Model - 25 stat columns (14 batting + 11 pitching), all `IntegerField(default=0)` - FK to `StratGame` for `last_game` tracking (double-count prevention) - 3 indexes: unique (player, team, season) + 2 query indexes ### WP-03: Track Seed Data - `app/seed/evolution_tracks.json` — 3 tracks (Batter, SP, RP) with formulas and thresholds - `app/seed/evolution_tracks.py` — idempotent `seed_evolution_tracks()` using get_or_create + update on rerun - Uses `logging.getLogger(__name__)` (not print) ### WP-04: SQL Migration - `migrations/2026-03-17_add_evolution_tables.sql` — 5 new tables + 3 ALTER TABLE columns - `IF NOT EXISTS` pattern, `BEGIN/COMMIT` wrapping - **Critical fix:** FK references use `player(player_id)` not `player(id)` — Player PK is `player_id` ### WP-05: Season Stats Service - `app/services/season_stats.py` — `update_season_stats(game_id)` entry point - Dual-backend upsert: PostgreSQL `ON CONFLICT ... DO UPDATE EXCLUDED` / SQLite `get_or_create` + field addition - Aggregates StratPlay rows into batting/pitching groups, merges Decision records - Double-count prevention via `last_game` check ## Test infrastructure - `conftest.py` updated with all 5 new models in `_TEST_MODELS` and shared fixtures (`track`, extended `player`, `team`) - `ruff.toml` added with F403/F405 ignore for peewee star imports in db_engine.py - Tests use `DATABASE_TYPE=postgresql` env var + SQLite rebind pattern ## Key technical decisions - **Player PK is `player_id`**, not `id` — all FKs must reference `player(player_id)` - **Career-scoped tiers** — permanent once earned, progress accumulates across seasons - **No retroactive backfill** — evolution launches fresh at Season 11, all T0 - **Single metric per track** with escalating thresholds (no multi-milestone tiers) ## What's next: Phase 1b — API & Evaluation Engine - WP-07: Card State API endpoints (issue #72) - WP-08: Evaluate endpoint / formula engine (issue #73) - WP-10: Pack opening hook — evolution_card_state init (issue #75) - WP-07 and WP-08 can be parallelized