Commit Graph

9 Commits

Author SHA1 Message Date
NilsBriggen d3e8df96ef Recency-weighted v4 model: fast-Elo blend, Team-DC majority, nightly refit
Validated on the strict 2018-2022 window and confirmed on the untouched
2022-2026 test set (RPS 0.1703 vs 0.1721 over 4,448 matches):
- the Elo member now blends 30% of a 3x-faster Elo walk, so recent
  results move ratings much harder
- ensemble weight shifts from 75/25 toward Elo to 45/55 toward the
  time-decayed Team-DC member — the recent-form model now leads
- Team-DC refits nightly (and at boot) on the 15-year window plus every
  finished 2026 match, via a new committed-at-build dcTrain.json
  (server-only, excluded from the PWA precache)
- a recent-form goal multiplier was also tested and did NOT validate;
  it ships disabled, and backtest.json records the whole decision

buildBacktest.ts grew the experiment harness: wider xi/k grids, the
fast-Elo and form variants, a pre-registered ship bar (>=0.0005
validation RPS), and a 7-day refit-cadence check. Older ratings.json
files still work — all new model fields are optional with golden
regression coverage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 23:34:18 +02:00
NilsBriggen dda8e1ae42 v3: the lake processed + /data page + glossary terms
- scripts/processStatsbomb.ts: one pass over the 17GB StatsBomb lake (4,235
  matches) -> lakestats.json (12.82GB events / 14.9M events / 6,919 players),
  scorestate.json (goal-rate multipliers by game state — shipped as an insight,
  NOT wired into in-play: the raw effect is selection-biased toward stronger
  teams and would distort a calibrated model), fingerprints.json (40/48 nations'
  shots/xG/set-piece share from real event data). Artifacts committed; raw lake
  stays local (gitignored).
- /data page + /api/data/stats: the gigabytes made visible — lake counters,
  historical archive, live-collection counts (odds lines, frozen forecasts,
  enrichment), per-source health with freshness. Footer links.
- Term component: plain-language glossary tooltips (RPS, Brier, ECE, Elo, xG,
  de-vig, ensemble) attached where metrics appear.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 17:41:43 +02:00
NilsBriggen f3b2a69b31 v3 Phase B core: Team-DC + backtested ensemble, squad values
- src/lib/model/teamDc.ts: per-team attack/defence Dixon-Coles via weighted MLE
  (Maher iterations), exponential time-decay, shrinkage for thin histories,
  learned home multiplier; log-pool of score matrices. 7 vitest cases.
- buildBacktest.ts rewritten as a strict three-way-split bake-off: params
  pre-2018, tune (xi, k, w) on 2018-2022 validation, final scores on untouched
  2022-2026 test (4,448 matches). Result: ensemble RPS 0.1721 beats Elo-DC
  0.1726 and Team-DC 0.1801; ECE stays 0.01. Tuned: xi=0.5 k=5 w=0.75.
- Runtime now IS the backtested model: ratings.json carries teamDc+ensembleW;
  matchMatrix() pools both members for predictions, Monte Carlo and advance
  probs; ModelEngine re-rating preserves ensemble params; lambdas reported as
  matrix expectations (drives in-play).
- scripts/buildSquadValues.ts: Transfermarkt FIWC participants page -> all 48
  squad market values (France 1.52bn ... Qatar 20m). Display/availability layer
  only — June-2026 values are NOT in the backtested model (would leak).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 17:23:51 +02:00
NilsBriggen 45c0a978fc v2 Phase 3: rigorous backtest + Methodology page
- scripts/buildBacktest.ts: honest walk-forward validation — params fit on
  pre-2018 internationals, tested out-of-sample on 7,988 matches (2018-2026)
  predicting each game from prior data only. Proper scoring (Brier/log-loss/RPS/
  accuracy) vs uniform / base-rate / Elo-only baselines + a calibration analysis
  (reliability bins + ECE). Results: 60% accuracy, RPS 0.171 (beats all
  baselines), ECE 0.01 (excellent calibration).
- Methodology page (/methodology): plain-language model walkthrough, the backtest
  scorecard, a custom-SVG reliability diagram, and honest limits. Transparency is
  the differentiator — no market odds, no overclaiming.
- ReliabilityDiagram component; 'Model' nav entry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 16:12:40 +02:00
NilsBriggen 7f4838d032 v2 Phase 2: match previews + team profiles
- buildPreviewData.ts: precomputes from 150y of results → h2h.json (825 WC-team
  pairings, full records + recent meetings) + scorers.json (top-10 all-time
  scorers per team). Committed goalscorers.csv.
- server/src/preview.ts: assembles MatchPreview / TeamProfile from three layers —
  historical (h2h, scorers), DB enrichment (ESPN form/lineups/venue), live model
  (W/D/L, xG, odds, Elo). /api/preview/:num + /api/team/:name.
- Client: rich /match/:num page (model expectation, recent form chips, H2H record
  + recent meetings, lineups-or-key-players) and /team/:name profile (Elo, odds,
  standing, fixtures, all-time scorers). Match cards now link to previews;
  cross-linking between matches and teams.
- Verified: Mexico-SA preview (81% W, 2-0, form, H2H 2-1-1, Borgetti 37) and
  Argentina profile (Messi 63) render; 22 tests pass; build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 15:34:54 +02:00
NilsBriggen dd8156376d Phase 3: data-story viz — StatsBomb shot map, xG race, pass networks
- buildStatsbombViz.ts: processes the 2022 WC Final (Argentina 3-3 France) from
  StatsBomb open data → shots+xG, cumulative xG race, starting-XI pass networks,
  totals, shootout result. Output committed (11KB) to avoid build-time fetch
- Custom SVG viz (no chart lib): reusable Pitch (StatsBomb 120x80 coords),
  ShotMap (xG-sized dots, teams attacking opposite goals), XgRace (stepped
  cumulative xG with goal markers, d3-scale), PassNetwork (nodes ∝ involvement,
  links ∝ pass volume)
- StoryPage: narrative with hero scoreline, by-the-numbers bars, and the three
  visualizations with explanatory copy
- Verified in browser: all three render correctly, no console errors

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 13:34:19 +02:00
NilsBriggen d604bb14ff Phase 2: predictive model — Elo + Dixon-Coles + Monte Carlo
- buildRatings.ts: walks 49k historical results → World-Football-Elo per team,
  data-calibrated goals model (goals-per-Elo slope, mean goals) + MLE-fit
  Dixon-Coles rho. Top: Spain/Argentina/France (the real 2026 favourites)
- src/lib/model: elo, poisson/dixon-coles, predict, host-advantage, monteCarlo
  (full 48-team sim — group sampling, best-third bipartite allocation, knockout
  advance probs). 20 vitest cases incl. exact per-round count invariants
- Server ModelEngine: live Elo re-rating after each result, per-match W/D/L,
  20k-sim odds, odds-over-time history; broadcast on finished-result changes
- Client: championship board, heat-shaded odds table, lazy-loaded title-race
  chart (Recharts split to its own chunk), match-prediction bars, bracket
  advance overlay
- Verified: odds render, chart populates as injected results re-rate teams live

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 13:25:53 +02:00
NilsBriggen 9a31e9f4db Phase 1: live dashboard — fixtures, scores, group tables, bracket
- Shared domain model (types, team metadata/flags/aliases, FIFA-tiebreak standings)
- buildFixtures.ts: openfootball 2026 → normalized fixtures.json (104 matches,
  ISO-UTC kickoffs, pretty knockout placeholders)
- Fastify live layer: seed load, football-data.org poller + SofaScore enhancement
  (feature-flagged, fallback), dynamic live-window polling, WS snapshot push,
  REST /api/snapshot, dev /api/dev/score injection
- Client: tournament store (REST + WS + static-file fallback), MatchCard,
  TeamLabel, GroupTable, Live/Groups/Bracket pages, live connection indicator
- Verified: WS pushes a dev-injected result; standings recompute live in-browser

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 13:04:31 +02:00
NilsBriggen 4e4e75a1d8 Phase 0: scaffold cup26 — Vite+React+Fastify TS PWA, broadcast theme, app shell
Mirrors the TTRPG stack (strict TS, Tailwind 4, vite-plugin-pwa, esbuild server
bundle, multi-stage Dockerfile, Traefik compose). Floodlit-pitch design tokens,
UI primitives (Button/Card/Badge), TanStack Router shell with Live/Groups/
Bracket/Predict/Story routes (placeholders), dependency-free PWA icon generator.
Raw data staged: openfootball 2026 fixtures + martj42 international results CSV.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 12:49:13 +02:00