A full, honest look under the hood: how scores go from ESPN to your standings, the visual bracket logic, the search for what predicts a good draft pick, and the tradeoffs behind decisions like skipping a traditional database backup. This is the implementation-level follow-on to Big Picture, which stays the at-a-glance summary.
Scoring is fully automated: the system checks ESPN for updates every five minutes during active tournament windows, without anyone needing to press a button. It's built as a lightweight, self-managed process rather than a dedicated job-scheduling service — a pragmatic choice for the current scale (see Big Picture §01), safeguarded so that only one process is ever checking scores at a time. Once a game finishes, ESPN's result is matched to the correct teams, players, and picks in our system, and every affected player's standing updates automatically. As a safety net, results are re-checked once an hour even after a game is marked final, and admins have a manual "run now" button plus a one-click repair tool if ESPN's own data ever needs correcting. A separate "daily simulation" mode lets the team test the scoring logic against real, in-season games before the tournament starts, without affecting live bracket data. The admin dashboard's own long-running actions (an ESPN import, Run All Steps) use a related but separate technique to show live progress in the browser: a background thread writes to a shared log table while the page polls a small partial on a short interval — no websockets, just polling. Full detail on that mechanism is in the admin-only build docs, not here.
Two APIs, two directions. "API" shows up twice in how a score gets here, in opposite directions: app/espn.py above is outbound — this app is the client, fetching team info and rosters, resolving each player's season points-per-game from ESPN's athlete-stats API, and pulling full box scores per game, explicitly excluding NCAA-tournament games from the season-schedule fetch (games are fetched without seasontype=3) so regular-season analytics never accidentally mixes in tournament games. app/blueprints/worker_api.py is the other direction — inbound, this app as the server — letting the Spark queue's worker process claim a pending job and post progress and results back over HTTP, without ever holding a database credential. It's the newer of the two, built as part of Spark Queue v2 and proven working end to end in dev: a real job ran the full queue-and-poll loop against real MySQL and a real local Ollama with correct event ordering. SPARK_ENABLED stays off in production until that path is turned on there — see AI: Foundation vs. Open-Weight for the mTLS transport and the rest of the queue's engineering detail.
This is the centerpiece feature players see: a full tournament bracket that colors in as the tournament unfolds, showing at a glance who's still alive and who's out. It does more than display results — it projects the entire bracket forward, even for games that haven't been played yet.
There's also a side-by-side comparison view, so two players can see their brackets projected next to each other.
This logic now has automated test coverage as well (see Deploy) — the exact scenarios above (a confirmed result overriding a projection, a projection favoring the viewer's own pick, and the earliest-collision math) are each checked automatically on every change.
This is a predictive question, not a bracket simulator: given everything known about a player, which factors actually predict how many points they'll score in the tournament — and can that help players draft smarter? The active approach is a dedicated analytics warehouse, covered in full on its own page.
An earlier attempt at this same question exists in the codebase (app/blueprints/analytics.py) — a self-contained pipeline that pulled nine years of ESPN box scores, built a per-player feature profile (seed, scoring average, rebounds, assists, team strength, national ranking, hot streaks), and trained a gradient-boosting model to rank likely top scorers. It's fully built but was shelved — the blueprint is present but not registered, so none of its routes are reachable. It's kept as reference for feature ideas rather than revived, since the warehouse-based approach gives a cleaner, more reproducible foundation to build the same answer on.
This is a deliberate call rather than a gap, given what the data actually is and what it costs to lose.
| Component | Role |
|---|---|
| Claude / Anthropic + the self-hosted open-weight model | Powers the optional admin daily-commentary feature via direct API calls to both a hosted foundation model (Claude) and a self-hosted open-weight model — see AI: Foundation vs. Open-Weight for the full comparison. |
| Amazon SES (Simple Email Service) | The only other production AWS service in use besides the server itself — sends account emails such as password resets |
| Traffic protections | Built-in safeguards against request flooding and cross-site form abuse, applied across the whole site |
These three items are not gaps discovered after the fact — they're known architecture tradeoffs, made deliberately, and already scoped as planned work rather than open risk. 2026 delivery prioritized shipping on a fixed, non-negotiable deadline — the tournament starts when it starts — on top of infrastructure already proven to work. That's the right call under a hard timeline, and it also means these three specific improvements were consciously deferred, not missed. All three are scoped for the offseason ahead of Tournament 2027, when they can be made outside the pressure of live tournament delivery.
| Planned item | What it adds |
|---|---|
| Real database migration tool | Replaces the current startup-time approach (see Deploy) with a standard, versioned migration tool — giving every schema change a reviewable, reversible history instead of relying on application code |
| Deploy rollback path | A way to revert a bad release to the last known-good version directly, rather than the current approach of pushing a new fix commit forward |
| Monitoring and alerting | Active notification (uptime checks, error alerts) if a core process — like the scoring scheduler — stops running, instead of relying on someone noticing |
4 of 5