---
title: Paper Dynasty Database Release — 2026.3.17
description: Database migration and schema changes for Paper Dynasty on 2026-03-17.
type: reference
domain: paper-dynasty
tags: [paper-dynasty, deployment, release-notes, database]
---

# Paper Dynasty Database Release — 2026.3.17

**Date:** 2026-03-17
**Branch:** next-release → main (PR #100, 27 commits)
**Repo:** cal/paper-dynasty-database
**Server:** pddev.manticorum.com:816

## Release Summary

Major release adding the evolution system foundation, render pipeline improvements, query performance fixes, and infrastructure hardening. This is the first release cut from the next-release branch for this repo.

## Evolution System (Card Evolution Phase 1)

The core backend for the card evolution feature. Cards can now progress through tiers based on accumulated player stats across seasons.

- **Season stats model** (`app/models/season_stats.py`): `BattingSeasonStats` and `PitchingSeasonStats` Peewee models for per-player, per-team, per-season stat accumulators. Originally a single `PlayerSeasonStats` model, refactored mid-cycle to split batting/pitching and rename `so`→`so_batter`, `k`→`so_pitcher` for clarity.
- **Season stats CRUD** (`app/routers_v2/season_stats.py`): Full REST endpoints for reading/writing season stats.
- **Track catalog API** (`app/routers_v2/evolution.py`, WP-06): `GET /api/v2/evolution/tracks` and `GET /api/v2/evolution/tracks/{id}` endpoints serving the three universal tracks (Batter, SP, RP) with tier thresholds.
- **Formula engine** (`app/services/formula_engine.py`, WP-09): Computes evolution value from career stats. Handles batter OPS-based formula and pitcher ERA/WHIP/K-based formula with split weighting.
- **Evolution seed data** (`app/seed/evolution_tracks.py`, WP-03): Seed script and JSON for the three base tracks with t1-t4 thresholds.

### Tests Added
- `tests/test_formula_engine.py` — 188 lines covering batter/pitcher value computation
- `tests/test_evolution_seed.py` — 119 lines validating seed data structure and idempotency
- `tests/test_evolution_track_api.py` — 132 lines for track catalog endpoints
- `tests/test_season_stats_model.py` — 451 lines for the stats model CRUD

## Render Pipeline

- **Persistent browser instance** (WP-02, `#89`): Playwright Chromium browser is now launched once at startup via FastAPI lifespan hooks and reused across all card render requests. Eliminates ~1-1.5s per-request launch/teardown overhead. Uses `asyncio.Lock` to prevent concurrent launch races and error-tolerant shutdown.
- **Dockerfile optimization**: Multi-stage build, switched to `python:3.11-slim-bookworm` for Playwright compatibility, pinned base image.

## Query Performance

- **Batch Paperdex lookups** (`#17`): Replaced N+1 per-player Paperdex queries with a single batch `WHERE player_id IN (...)` query in both `get_players` and `get_random_player` endpoints.
- **Materialize queryset** (`get_random_player`): Added `list()` call before double-iteration to prevent queryset exhaustion.

## Bug Fixes

- **Pitcher OPS split weighting** (`#6`): Use `max()` instead of incorrect weighting for pitcher OPS formula
- **Remove stub endpoint** (`#11`): Deleted unimplemented `live_update_pitching` endpoint that returned 501
- **Docker build fixes**: Removed Docker Hub registry cache (blob limits), pinned base image for Playwright compatibility

## Infrastructure

- `pyproject.toml` added for ruff configuration
- `requirements.txt` pinned all dependency versions (`#64`)

## Merge Conflict Resolution

**Files:** `app/main.py`, `app/routers_v2/players.py`
**Cause:** Main had the Phase 0 render pipeline optimization (PR #94 — asyncio.Lock, `--no-sandbox` args, error-tolerant shutdown). Next-release had an earlier version of the same persistent browser feature (`#89` — simpler, no lock, no error handling).
**Resolution:** Kept main's version (the more robust implementation) for all browser-related code. Added the evolution router import/inclusion from next-release.

## Open PRs Still Targeting next-release

After this release, 5 PRs remain open against next-release:

| PR | Title | Status |
|----|-------|--------|
| #84 | SQL migration for evolution tables (WP-00) | Conflict |
| #95 | Phase 0 benchmark script | Mergeable |
| #96 | Self-hosted WOFF2 fonts | Mergeable |
| #98 | WP-08 evaluate endpoint | Conflict |
| #99 | Lifespan hooks for browser pre-warm | Conflict |

PRs #98 and #99 conflict because they contain earlier versions of code already in main (evaluate endpoint and browser lifespan). PR #84 conflicts on shared test infrastructure files. These should be rebased or have conflicts resolved before merging into next-release.
