Skip to content

Commit bca8bb0

Browse files
valvesssclaude
andcommitted
feat(worldcup): flag/W-D-L/scoreline card redesign + rename block 41→52
Makes the "next match" widget the fun, less-technical part: - team flags (flagcdn) + favourite highlighted, a 3-way W/D/L probability bar, plain-language verdict, and the predicted skewness beside a payoff-shape viz. - a recent-results strip: scorelines + flags + ✓/✗ (favourite won / upset). - predict_worldcup emits per-fixture 3-way probs, flags, and recent games. Also renames analysis/41_worldcup.py → 52_worldcup.py to clear the block-number collision with 41_model_battery (refs in README + WORLDCUP.md updated), and adds a Goals nav link + the goals README annex. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 58eb1ed commit bca8bb0

8 files changed

Lines changed: 420 additions & 70 deletions

File tree

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,27 @@ result lands. It updates during the 2026 tournament. Annex:
7878
[skew-dynamic.coldcodelabs.com/worldcup](https://skew-dynamic.coldcodelabs.com/worldcup).
7979

8080
```bash
81-
python study/analysis/41_worldcup.py # the analysis
81+
python study/analysis/52_worldcup.py # the analysis
8282
python study/analysis/export_worldcup_data.py # regenerate the page data
8383
python study/analysis/predict_worldcup.py # predict next games + reconcile ledger
8484
```
8585

86+
## Annex — Goals: the over/under ladder
87+
88+
The same law, dialled by the **line** instead of by who's playing. Each total-goals
89+
line is a two-point Over bet with `p = P(total > L)`; sweeping the line sweeps
90+
`(1−2p)/√(p(1−p))` across its **full range** (skew −3.0 → +3.6), far past the
91+
1X2 favourite. The over-probability comes **odds-free** from a Poisson goals model;
92+
the one line with real odds (2.5) anchors it — model **48%** ≈ market **49%**
93+
reality **49%**, calibrated within a point at every line. Annex:
94+
[`study/docs/GOALS.md`](study/docs/GOALS.md) · page:
95+
[skew-dynamic.coldcodelabs.com/goals](https://skew-dynamic.coldcodelabs.com/goals).
96+
97+
```bash
98+
python study/analysis/53_goals_ladder.py # the ladder + 2.5 anchor
99+
python study/analysis/export_goals_data.py # regenerate the page data
100+
```
101+
86102
## The paper
87103

88104
Working draft (RSOS target): [`study/docs/paper/draft.md`](study/docs/paper/draft.md).

site/src/components/Nav.astro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const links = [
99
['Timeline', '#timeline'],
1010
['Reproduce', '#reproduce'],
1111
['World Cup', '/worldcup'],
12+
['Goals', '/goals'],
1213
];
1314
---
1415
<nav class="nav">

site/src/data/wc_live.json

Lines changed: 194 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@
1818
"skew_pred": -0.2255,
1919
"win_payoff": 0.8,
2020
"lose_payoff": -1.0,
21-
"verdict": "neg"
21+
"verdict": "neg",
22+
"p_home": 0.556,
23+
"p_draw": 0.252,
24+
"p_away": 0.192,
25+
"home_flag": "br",
26+
"away_flag": "jp"
2227
},
2328
"upcoming": [
2429
{
@@ -33,7 +38,12 @@
3338
"skew_pred": -0.2255,
3439
"win_payoff": 0.8,
3540
"lose_payoff": -1.0,
36-
"verdict": "neg"
41+
"verdict": "neg",
42+
"p_home": 0.556,
43+
"p_draw": 0.252,
44+
"p_away": 0.192,
45+
"home_flag": "br",
46+
"away_flag": "jp"
3747
},
3848
{
3949
"match_id": "2026-06-29|Germany|Paraguay",
@@ -47,7 +57,12 @@
4757
"skew_pred": -0.5087,
4858
"win_payoff": 0.6,
4959
"lose_payoff": -1.0,
50-
"verdict": "neg_strong"
60+
"verdict": "neg_strong",
61+
"p_home": 0.6233,
62+
"p_draw": 0.2285,
63+
"p_away": 0.1483,
64+
"home_flag": "de",
65+
"away_flag": "py"
5166
},
5267
{
5368
"match_id": "2026-06-29|Netherlands|Morocco",
@@ -61,7 +76,12 @@
6176
"skew_pred": 0.0764,
6277
"win_payoff": 1.08,
6378
"lose_payoff": -1.0,
64-
"verdict": "flat"
79+
"verdict": "flat",
80+
"p_home": 0.4809,
81+
"p_draw": 0.2712,
82+
"p_away": 0.2479,
83+
"home_flag": "nl",
84+
"away_flag": "ma"
6585
},
6686
{
6787
"match_id": "2026-06-30|France|Sweden",
@@ -75,7 +95,12 @@
7595
"skew_pred": -1.3352,
7696
"win_payoff": 0.29,
7797
"lose_payoff": -1.0,
78-
"verdict": "neg_strong"
98+
"verdict": "neg_strong",
99+
"p_home": 0.7776,
100+
"p_draw": 0.154,
101+
"p_away": 0.0683,
102+
"home_flag": "fr",
103+
"away_flag": "se"
79104
},
80105
{
81106
"match_id": "2026-06-30|Ivory Coast|Norway",
@@ -89,7 +114,12 @@
89114
"skew_pred": 0.4021,
90115
"win_payoff": 1.49,
91116
"lose_payoff": -1.0,
92-
"verdict": "pos_strong"
117+
"verdict": "pos_strong",
118+
"p_home": 0.3176,
119+
"p_draw": 0.2809,
120+
"p_away": 0.4014,
121+
"home_flag": "ci",
122+
"away_flag": "no"
93123
},
94124
{
95125
"match_id": "2026-06-30|Mexico|Ecuador",
@@ -103,7 +133,12 @@
103133
"skew_pred": -0.0017,
104134
"win_payoff": 1.0,
105135
"lose_payoff": -1.0,
106-
"verdict": "flat"
136+
"verdict": "flat",
137+
"p_home": 0.5004,
138+
"p_draw": 0.267,
139+
"p_away": 0.2326,
140+
"home_flag": "mx",
141+
"away_flag": "ec"
107142
},
108143
{
109144
"match_id": "2026-07-01|Belgium|Senegal",
@@ -117,7 +152,12 @@
117152
"skew_pred": -0.205,
118153
"win_payoff": 0.81,
119154
"lose_payoff": -1.0,
120-
"verdict": "neg"
155+
"verdict": "neg",
156+
"p_home": 0.551,
157+
"p_draw": 0.2535,
158+
"p_away": 0.1955,
159+
"home_flag": "be",
160+
"away_flag": "sn"
121161
},
122162
{
123163
"match_id": "2026-07-01|England|DR Congo",
@@ -131,7 +171,12 @@
131171
"skew_pred": -1.3593,
132172
"win_payoff": 0.28,
133173
"lose_payoff": -1.0,
134-
"verdict": "neg_strong"
174+
"verdict": "neg_strong",
175+
"p_home": 0.7811,
176+
"p_draw": 0.1521,
177+
"p_away": 0.0669,
178+
"home_flag": "gb-eng",
179+
"away_flag": "cd"
135180
},
136181
{
137182
"match_id": "2026-07-01|United States|Bosnia and Herzegovina",
@@ -145,7 +190,12 @@
145190
"skew_pred": -1.1038,
146191
"win_payoff": 0.35,
147192
"lose_payoff": -1.0,
148-
"verdict": "neg_strong"
193+
"verdict": "neg_strong",
194+
"p_home": 0.7416,
195+
"p_draw": 0.1738,
196+
"p_away": 0.0846,
197+
"home_flag": "us",
198+
"away_flag": "ba"
149199
},
150200
{
151201
"match_id": "2026-07-02|Portugal|Croatia",
@@ -159,7 +209,12 @@
159209
"skew_pred": -0.1529,
160210
"win_payoff": 0.86,
161211
"lose_payoff": -1.0,
162-
"verdict": "neg"
212+
"verdict": "neg",
213+
"p_home": 0.5381,
214+
"p_draw": 0.2573,
215+
"p_away": 0.2046,
216+
"home_flag": "pt",
217+
"away_flag": "hr"
163218
},
164219
{
165220
"match_id": "2026-07-02|Spain|Austria",
@@ -173,7 +228,12 @@
173228
"skew_pred": -0.9623,
174229
"win_payoff": 0.4,
175230
"lose_payoff": -1.0,
176-
"verdict": "neg_strong"
231+
"verdict": "neg_strong",
232+
"p_home": 0.7168,
233+
"p_draw": 0.1866,
234+
"p_away": 0.0966,
235+
"home_flag": "es",
236+
"away_flag": "at"
177237
},
178238
{
179239
"match_id": "2026-07-02|Switzerland|Algeria",
@@ -187,7 +247,12 @@
187247
"skew_pred": 0.0777,
188248
"win_payoff": 1.08,
189249
"lose_payoff": -1.0,
190-
"verdict": "flat"
250+
"verdict": "flat",
251+
"p_home": 0.4806,
252+
"p_draw": 0.2712,
253+
"p_away": 0.2482,
254+
"home_flag": "ch",
255+
"away_flag": "dz"
191256
},
192257
{
193258
"match_id": "2026-07-03|Argentina|Cape Verde",
@@ -201,7 +266,12 @@
201266
"skew_pred": -2.8731,
202267
"win_payoff": 0.1,
203268
"lose_payoff": -1.0,
204-
"verdict": "neg_strong"
269+
"verdict": "neg_strong",
270+
"p_home": 0.9104,
271+
"p_draw": 0.0691,
272+
"p_away": 0.0205,
273+
"home_flag": "ar",
274+
"away_flag": "cv"
205275
},
206276
{
207277
"match_id": "2026-07-03|Australia|Egypt",
@@ -215,7 +285,12 @@
215285
"skew_pred": 0.0168,
216286
"win_payoff": 1.02,
217287
"lose_payoff": -1.0,
218-
"verdict": "flat"
288+
"verdict": "flat",
289+
"p_home": 0.4958,
290+
"p_draw": 0.268,
291+
"p_away": 0.2362,
292+
"home_flag": "au",
293+
"away_flag": "eg"
219294
},
220295
{
221296
"match_id": "2026-07-03|Colombia|Ghana",
@@ -229,7 +304,12 @@
229304
"skew_pred": -1.8977,
230305
"win_payoff": 0.18,
231306
"lose_payoff": -1.0,
232-
"verdict": "neg_strong"
307+
"verdict": "neg_strong",
308+
"p_home": 0.8442,
309+
"p_draw": 0.1139,
310+
"p_away": 0.042,
311+
"home_flag": "co",
312+
"away_flag": "gh"
233313
}
234314
],
235315
"backtest2026": {
@@ -244,5 +324,103 @@
244324
"n_pending": 15,
245325
"n_resolved": 0
246326
},
327+
"recent_games": [
328+
{
329+
"home": "South Africa",
330+
"away": "Canada",
331+
"home_flag": "za",
332+
"away_flag": "ca",
333+
"fh": 0,
334+
"fa": 1,
335+
"fav_team": "Canada",
336+
"fav_won": true,
337+
"p_fav": 0.543,
338+
"skew_pred": -0.1728
339+
},
340+
{
341+
"home": "Croatia",
342+
"away": "Ghana",
343+
"home_flag": "hr",
344+
"away_flag": "gh",
345+
"fh": 2,
346+
"fa": 1,
347+
"fav_team": "Croatia",
348+
"fav_won": true,
349+
"p_fav": 0.7479,
350+
"skew_pred": -1.1419
351+
},
352+
{
353+
"home": "Panama",
354+
"away": "England",
355+
"home_flag": "pa",
356+
"away_flag": "gb-eng",
357+
"fh": 0,
358+
"fa": 2,
359+
"fav_team": "England",
360+
"fav_won": true,
361+
"p_fav": 0.6622,
362+
"skew_pred": -0.686
363+
},
364+
{
365+
"home": "DR Congo",
366+
"away": "Uzbekistan",
367+
"home_flag": "cd",
368+
"away_flag": "uz",
369+
"fh": 3,
370+
"fa": 1,
371+
"fav_team": "Uzbekistan",
372+
"fav_won": false,
373+
"p_fav": 0.3762,
374+
"skew_pred": 0.511
375+
},
376+
{
377+
"home": "Colombia",
378+
"away": "Portugal",
379+
"home_flag": "co",
380+
"away_flag": "pt",
381+
"fh": 0,
382+
"fa": 0,
383+
"fav_team": "Colombia",
384+
"fav_won": false,
385+
"p_fav": 0.44,
386+
"skew_pred": 0.2418
387+
},
388+
{
389+
"home": "Jordan",
390+
"away": "Argentina",
391+
"home_flag": "jo",
392+
"away_flag": "ar",
393+
"fh": 1,
394+
"fa": 3,
395+
"fav_team": "Argentina",
396+
"fav_won": true,
397+
"p_fav": 0.8417,
398+
"skew_pred": -1.8727
399+
},
400+
{
401+
"home": "Algeria",
402+
"away": "Austria",
403+
"home_flag": "dz",
404+
"away_flag": "at",
405+
"fh": 3,
406+
"fa": 3,
407+
"fav_team": "Algeria",
408+
"fav_won": false,
409+
"p_fav": 0.4109,
410+
"skew_pred": 0.362
411+
},
412+
{
413+
"home": "Senegal",
414+
"away": "Iraq",
415+
"home_flag": "sn",
416+
"away_flag": "iq",
417+
"fh": 5,
418+
"fa": 0,
419+
"fav_team": "Senegal",
420+
"fav_won": true,
421+
"p_fav": 0.642,
422+
"skew_pred": -0.5923
423+
}
424+
],
247425
"recent_resolved": []
248426
}

0 commit comments

Comments
 (0)