NFL fantasy football projections: a small quantile transformer (trained on a free SageMaker Studio Lab T4) versus classical baselines, evaluated honestly with walk-forward backtests, published as a static site that updates itself weekly during the season.
Design spec: docs/superpowers/specs/2026-07-09-fantasy-football-model-design.md
python -m venv .venv # Python >= 3.10
source .venv/Scripts/activate # POSIX: source .venv/bin/activate
.venv/Scripts/python.exe -m pip install -e ".[dev]" # POSIX: .venv/bin/python
pytest # unit tests (offline)
pytest -m integration # network tests against live nflverse data
python -m ffmodel.data.pull # cache 2012-2025 data to data/raw/
python -m ffmodel.eval.run # walk-forward backtest -> models/backtests/baselines.json- Start a GPU runtime (T4; 4h/day quota) and open a terminal.
- Once:
git clone <repo-url> && cd <repo> && pip install -e ., then set your git identity (git config --global user.name "..."anduser.email "...") and authenticate for pushing — a fresh Studio Lab runtime has neither configured. Use a GitHub personal access token as the clone/push credential, or rungh auth loginif theghCLI is available. - Open
notebooks/train_studio_lab.ipynband run the cells top to bottom. Each config trains one walk-forward artifact (models/transformer/v1/through<year>/); training checkpoints every epoch, so if the session dies, restart the runtime and rerun the same cell adding--resume. - The last cell runs the full bake-off and commits artifacts + results. Note on fairness: the transformer reserves the season right before each test year as an early-stopping validation set, while the baselines are fit through that season with no holdout — a small handicap for the transformer that we call out honestly in the results rather than hide.
Local CPU training works identically (slower): same commands, no notebook needed.
Three workflows live in .github/workflows/:
ci.yml— runs the test suite (pytest -W error) on every push tomainand on every pull request.weekly-update.yml— regenerates the site JSON in-season. Runs on a cron of23 5 * 9-12,1 3(Wednesdays 05:23 UTC — overnight after Tuesday's stat finalization, ET — September through January), and can also be triggered manually (workflow_dispatch).pages.yml— deployssite/to GitHub Pages whenever a push tomaintouchessite/**, can be triggered manually, and is explicitly dispatched byweekly-update.ymlafter it pushes fresh data (bot-token pushes don't fireon: pushworkflows, so the weekly job callsgh workflow run pages.ymlitself).
Fail-safe contract: weekly-update.yml generates the site JSON before it
commits anything. If the data pull or generation step fails for any
reason, the job fails before the commit step runs, so nothing is committed
and nothing deploys — the site keeps serving last week's data, with its
"data as of" stamp still honestly showing when that data was generated.
Deployed model: the env: block at the top of weekly-update.yml
selects the model. It is set to MODEL: transformer with ARTIFACT_ROOT: models/transformer/v1 — the run root, not a through<year> directory;
the predictor appends through{last-trained-season} itself. A
comma-separated list of run roots deploys a seed ensemble.
One-time setup: these workflows are inert until the repo is pushed to GitHub. Once pushed, enable Pages once under repo Settings -> Pages -> Source: GitHub Actions.
Preseason draft-board refresh: before week 1, run weekly-update.yml
manually with the draft input checked. This regenerates only the draft
board (--draft, no --week), since the target season has no games yet
and requesting its weekly stats would fail; the weekly slate resumes once
the season starts (cron or plain dispatch, which use --week auto).
- Plan 1: data pipeline, scoring, features, eval harness, baselines
- Plan 2: quantile transformer code complete (CPU smoke-tested end-to-end on real data)
- Transformer walk-forward artifacts: pending GPU training (see Training on SageMaker Studio Lab)
- Plan 3: draft board + weekly site, GitHub Actions automation
- Site pages (draft board, weekly, about) and all three workflows complete
- First real 2026 draft board generated (xgboost) and committed under
site/data/
Remaining user tasks:
- Create the GitHub remote and push (workflows are inert until then)
- Enable Pages once: repo Settings -> Pages -> Source: GitHub Actions
- Train the transformer on Studio Lab GPU (see Training on SageMaker Studio Lab)
- Flip
MODEL/ARTIFACT_ROOTinweekly-update.ymlto the trained transformer