Prime Radiant · Repository Guide

The Prime Radiant Codebase

Three passes over one repository: the map, the machine, and the nervous system that runs it — ending where the project goes next: a season that starts itself.

38 modules 379 tests · 100.00% coverage 15 mutants run & killed 4 surfaces live gate: make check
01 · The map

Where everything lives

Everything interesting is one Python package plus four surfaces that consume it. The pipeline across the top row is the product; the row beneath it is the proof.

src/prime_radiant cli.py front door epi/data hub·vintages features lags·seasonal models gbm·baseline submission hub contract backtest/ rolling · report eval/ wis · scoring serve/bundle offline snapshot scores replayed over 55 origins surfaces CDC FluSight hub weekly PR · gated PyPI · prime-radiant trusted publishing HF Space dashboard gradio · no network GitHub Pages docs mkdocs material uv build serve_data/ committed docs/ describe it all
Figure 1. The package and its surfaces. Top row is the weekly product path; the middle row is the evidence machinery that replays the same code over history. Amber marks the one outward-facing, gated surface.

Reading order for a newcomer: epi/cli.py is the front door — three subcommands (forecast, validate, bundle), everything else hangs off them. epi/data gets and time-scopes the data, features/models do the machine learning, submission speaks the hub's contract, backtest + eval prove the model honest, and serve packages results for the dashboard. At the top level, tests/ mirrors all of it at 100% coverage, scripts/open_hub_pr.sh is the one shell dependency, and NOTES/ is the project's memory.

02 · The heart

What one weekly forecast computes

The load-bearing idea is vintage discipline: the model must never see data dated after the forecast origin. So the data layer is built on git archaeology — checking out the truth file as it existed on a past date — rather than "download latest".

ensure_hub_clone data/hub.py · blobless clone of the CDC hub as_of(date) data/vintages.py · git history = time machine resolve_usable_vintage — THE GUARD walk back 3→10 days · ≥52 wks history · ≤14 days fresh honest miss = NoUsableVintageError, nothing else features/ · assemble 4th-root admission rates · lags · seasonal terms lgbm_quantile pooled GBM · 23 q baseline replica · relWIS 1.0000 ensemble — what gets submitted per-quantile MEDIAN of the two shape the submission sorted integer quantiles · 8-column hub frame validate — against the LIVE hub config round · levels · locations · horizons · counts<popn · schema <saturday>-JGracey-prime_radiant.csv never "download latest" Wednesday-anchored, strictly earlier-only fallback the guard is never relaxed — not for backtests, not for shadow same feature matrix to both wins the 2025-26 three-season league: WIS 0.609 vs 0.625 contract drift on the hub side fails loudly, before any PR
Figure 2. One weekly run, top to bottom. The amber guard is the mechanism the whole design leans on: it decides what data is honestly usable, and it fails with its own exception type so nothing else can masquerade as an off-season skip.

The same run_origin function drives live forecasts and the historical backtests: backtest/rolling.py replays it across 55 past origins, eval/wis.py scores each with the hub's own metric, and serve/bundle.py snapshots the results into the offline bundle the dashboard serves. One code path — so a backtest win means something about the live path.

03 · The nervous system

How it runs itself, and where the gates are

Two cron schedules do the routine work; a human dispatch — behind four simultaneous conditions — is the only way anything reaches the hub. The design rule throughout: every gate is structure, not prose, and each structural claim has a test that a mutant provably fails.

cron · Tue 22:17 weekly-forecast.yml manual dispatch a human, deliberately cron · daily 13:23 hub-config-watch.yml dry-run job forecast auto → validate → render metadata artifact CSV + metadata yml live-submit job open_hub_pr.sh · freshness gate · idempotent retry PR → cdcepi hub bundles metadata if needed ALL FOUR REQUIRED dispatch · live=true LIVE='1' · PAT secret shadow job forecast --shadow current week · guard unrelaxed truth stale → exit 3 green skip + summary note truth fresh → commit shadow-output/ baseline season baseline arms itself · no action watcher rounds beyond 2026-05-30? zero parsed = RED, not quiet ONE open issue the go-live checklist unlocks missing PAT = RED, never silent-green weekly fires ~Sep
Figure 3. The automation. Cron reaches only the honest paths; the hub PR sits behind four simultaneous conditions, and the one scary failure mode — quietly looking fine — is engineered out at each step.

This layer was adversarially reviewed by a four-refuter panel; every demonstrated defect was fixed with a regression test and a mutant proof:

Demonstrated findingStructural fix
Hub schema drift (a KeyError) masqueraded as an eternal "off-season skip" The guard's miss is its own exception type; drift now fails red
No freshness gate — a live dispatch would have submitted a months-stale round, green The PR script refuses any reference date outside 0–13 days out
A same-week retry after a partial failure dead-ended on the stranded fork branch Force-push to the disposable branch; skip create if the PR exists
A hub config restructure read as "no news", green, forever Zero parsed dates now fails the watcher red
04 · The next step

The season starts itself

Nothing can forecast the current week until the hub's own truth data resumes — dormant since July 9, and by three seasons of precedent it wakes in September, the same week the new season's config lands. Everything below the line is already running; everything above it waits on exactly one person.

now shadow + watcher running weekly / daily ~September config drop · precedent Sep 5–30 watcher files its issue baseline starts landing mid–late October earliest real submission if windows open · 2 of 3 years ~Nov 18 guaranteed open explicit go only
Figure 4. The road to the first live submission. Green is autonomous and already in motion; amber requires a deliberate human dispatch through the four gates.
WhenWhat firesWhose action
NowShadow job green-skips weekly; watcher checks the hub config dailynone
~SepConfig lands → watcher opens its issue; truth resumes → shadow CSVs land in shadow-output/none
The gapPAT + LIVE=1 set; dry-run dispatched against a real new-season roundoperator
First windowFirst real submission — explicit go onlyoperator
~Nov 18Guaranteed open: mass season startoperator