Skip to content

Commit 811e818

Browse files
docs: scrub dangling references to removed paid-API tooling
Fix doc/comment/message references left after the SportMonks removal so the public repo has zero broken or mangled file paths: - relevance.py / OPPONENT_ADJUSTMENT.md / experiments_log.json: drop deleted file paths (LOO harness + corpus loader live in git history), keep the writeup - group_scenarios.py + DAILY.md: point at the pre-fetched data/standings/ snapshots - DATA_STRATEGY / NEW_QUESTION_TYPES / PARSIMONY: genericize provider name + paths - untrack the orphaned paid-API enrichment runbook (kept locally, gitignored) No code paths change; 186 tests pass, validators 104/48/52 green.
1 parent ad2d320 commit 811e818

10 files changed

Lines changed: 24 additions & 83 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,6 @@ predictions/baselines/**/_fire_map.json
3131

3232
# raw screenshot dump (curated subset lives in docs/results/)
3333
docs/results-screnshots/
34+
35+
# Orphaned paid-API enrichment runbook (kept locally, not part of the public repo)
36+
workflows/DATA_ENRICHMENT.md

bot/data/relevance.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@
2323
Opponent strength is a *corpus-internal* rating (mean goal difference per team), so it covers every
2424
team in the history corpus without an external Elo table and is internally consistent.
2525
26-
This module is pure/estimation-only; the LOO validation harness lives in
27-
``scripts/relevance_backtest.py`` and the eventual wiring point is ``StatsJsonProvider``.
26+
This module is pure/estimation-only; the leave-one-out validation harness and corpus
27+
loader were removed from the public repo (kept in git history), and the eventual wiring
28+
point is ``StatsJsonProvider``.
2829
"""
2930

3031
from __future__ import annotations
@@ -120,7 +121,7 @@ def team_strengths(matches: list[Match], stat: str = "goals") -> dict[str, float
120121
121122
A simple, leakage-stable team attribute used only as the *opponent-similarity variable* (which
122123
past opponents resemble the current one). ``stat`` selects the differential: "goals" (history,
123-
where goal-difference is available) or "shots_on_target" (the stats-api corpus has no goals, so
124+
where goal-difference is available) or "shots_on_target" (this corpus has no goals, so
124125
SoT-differential is the available dominance proxy). Z-scoring puts sigma on a ~unit scale.
125126
"""
126127
diff: dict[str, list[float]] = defaultdict(list)

research/DATA_STRATEGY.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -446,17 +446,17 @@ WC/Euro 2024 support with `--season` flag]
446446

447447
🟡 [INFERRED from general knowledge and product page structure; not directly verified]
448448

449-
#### 4.2.2 the stats API Football API
449+
#### 4.2.2 A paid football-stats API
450450

451451
| Property | Detail |
452452
|---|---|
453-
| **URL** | `stats-api.com/football-api/` |
453+
| **URL** | (paid provider) |
454454
| **What it provides** | "Statistics from professional football clubs, media agencies, and gaming companies... goals, average minute teams/players need to score, average goals per minute per team, trends" |
455455
| **Free tier** | 14-day trial or limited free plan |
456456
| **Reachability** | Landing page accessible |
457457
| **Useful for** | Broader league coverage; international stats including WC qualifiers |
458458

459-
🔵 [stats-api.com/football-api — confirmed accessible; feature list directly verified]
459+
🔵 [paid provider — confirmed accessible; feature list directly verified]
460460

461461
#### 4.2.3 Opta / StatsPerform
462462

research/NEW_QUESTION_TYPES.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ model RBP +1020.8 unchanged, 187 tests pass — the handlers fire ONLY on the no
1919
`player A > player B SoT` and single-player SoT props are only as sharp as our player rates. The
2020
`BaseRateProvider` returns a GENERIC default (sot90≈0.60) for players without specific data, so e.g.
2121
Yamal and Messi both get λ≈0.47 → P(Yamal>Messi)≈coin-minus-ties≈0.28. **To price these sharply we
22-
need per-player SoT/90 rates** (fetch via `scripts/fetch_stats-api_player_sot.py` into `data/`), else
22+
need per-player SoT/90 rates** (fetch per-player SoT/90 rates into `data/`), else
2323
apply a manual volume tilt at pricing time (Yamal is a higher-volume shooter than Messi's deep role).
2424

2525
## "Odds can mislead" (apply at pricing)
@@ -41,7 +41,7 @@ the model where it has a real data basis and the market is thin.
4141
H2H and brace (Poisson tail). 2026-07-18.*
4242

4343
## Update — player-SoT data fetched & wired (2026-07-18)
44-
Ran `scripts/fetch_stats-api_player_sot.py --write``data/players/stats-api_sot.json` (157 players,
44+
Fetched per-player SoT/90`data/players/player_sot_rates.json` (157 players,
4545
leak-free, WC-2026 season excluded). This is **auto-wired** via `bot/data/teamstats.py` (blends
4646
`sot_per90` into each player rate). Finalists now carry REAL rates: **Messi 1.66, Mbappé 2.03, Kane
4747
1.88, Oyarzabal 2.42, Olmo 1.51, Álvarez 0.96** (vs the 0.60 generic default). Backtest-gated:

research/OPPONENT_ADJUSTMENT.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ OTHER matches — weighting each past match by how relevant it is to *this* matc
1717
- `w_blowout` down-weight ≥5-goal blowouts.
1818
- `k` pseudo-matches of shrinkage toward the league prior μ0.
1919

20-
Code: `bot/data/relevance.py` (estimator) · `scripts/relevance_backtest.py` (leave-one-out harness).
20+
Code: `bot/data/relevance.py` (estimator). The leave-one-out harness and corpus loader were
21+
removed from the public repo (kept in git history).
2122

2223
## Validation (history LOO, 526 team-matches, 2,104 territorial outcomes)
2324

@@ -32,9 +33,8 @@ Scored with **Brier** (binary markets) + **RPS** (3-way match outcome; Constanti
3233

3334
## Cross-validation on the WC2026 teams' OWN data (7,088 territorial outcomes)
3435

35-
Built a per-match corpus for all 48 WC2026 teams from **cached** stats-api internationals
36-
(`data/stats-api/between/*.json`, 2024-25 qualifiers/friendlies) — `bot/data/match_corpus.py`.
37-
Coverage: **all 48 teams**, median 21 matches/team (min 9, max 35). The method generalises:
36+
Built a per-match corpus for all 48 WC2026 teams from **cached** internationals
37+
(2024-25 qualifiers/friendlies). Coverage: **all 48 teams**, median 21 matches/team (min 9, max 35). The method generalises:
3838

3939
| Config | terr Brier (WC corpus) |
4040
|---|---|

research/PARSIMONY_AND_DATASETS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ highest-ROI signals make it significantly better (less overfitting)?
2323
|---|---|---|---|
2424
| 1 | **Sharp market odds** | ★★★★★ (dominates liquid markets) | anchored (_ODDS_WEIGHT=4) |
2525
| 2 | **Elo / SPI / pi-ratings** | ★★★★☆ | have (elo + margin-elo) |
26-
| 3 | **xG / shot quality** | ★★★☆☆ (counts; can add noise on sparse intl) | have (stats-api xG) |
26+
| 3 | **xG / shot quality** | ★★★☆☆ (counts; can add noise on sparse intl) | have (paid-API xG) |
2727
| 4 | **Shots-on-target / territorial** | ★★★☆☆ (dir-acc 0.80) | have |
2828
| 5 | **Corners** | ★★★☆☆ (0.79) | have |
2929
|| Offsides totals (ref/base-rate) | ★★☆☆☆ | have |

results/experiments_log.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@
344344
{
345345
"name": "exp/relevance-weighted-rates (E0-E5)",
346346
"date": "2026-06-26",
347-
"change": "per-fixture opponent-aligned rate estimator: opp-strength Gaussian kernel + Gamma-Poisson shrinkage + (optional) time-decay/competition/blowout weights. Validated via scripts/relevance_backtest.py LOO on data/history (526 team-matches, 2104 territorial outcomes).",
347+
"change": "per-fixture opponent-aligned rate estimator: opp-strength Gaussian kernel + Gamma-Poisson shrinkage + (optional) time-decay/competition/blowout weights. Validated via leave-one-out on data/history (526 team-matches, 2104 territorial outcomes).",
348348
"metric": "territorial_Brier + 3-way RPS (history LOO, NOT the WC2026 gate yet)",
349349
"results": {
350350
"flat_baseline": {
@@ -364,7 +364,7 @@
364364
"findings": "k (shrinkage) is the dominant lever: k=0 is WORSE than flat (+0.0074), k=5 best (-0.0120). Opp-strength kernel helps modestly on territorial and more on RPS (sigma~0.8-1.2). For COUNT stats time-decay HURTS (xi=0 best) and blowout-downweight HURTS (blowout games carry real territorial signal) - opposite of the goals/results literature. Competition weighting ~no-op on the all-major-tournament history corpus (kept as the live friendly/qualifier hook).",
365365
"verdict": "VALIDATED on history LOO; NOT yet deployed - needs per-match data for WC2026 teams to wire into StatsJsonProvider, then the WC2026 gate.",
366366
"cross_validation_wc_corpus": {
367-
"corpus": "bot/data/match_corpus.py (cached stats-api internationals, all 48 WC teams, median 21 matches/team, 7088 territorial outcomes)",
367+
"corpus": "cached internationals corpus (all 48 WC teams, all 48 WC teams, median 21 matches/team, 7088 territorial outcomes)",
368368
"flat_terr_brier": 0.2025,
369369
"best_terr_brier": 0.19,
370370
"best_config": "sigma=1.0,k=0",
@@ -434,8 +434,8 @@
434434
"verdict": "PASS-NEUTRAL (handlers fire only on novel types; 0 regression on 621-question backtest; 187 tests pass). Forward-test on final/3rd-place to calibrate."
435435
},
436436
{
437-
"name": "data/stats-api-player-sot-refresh",
438-
"change": "Fetched leak-free per-player SoT/90 for 157 players via fetch_stats-api_player_sot.py --write (WC-2026 season excluded). Auto-wired through bot/data/teamstats.py (blends stats-api sot_per90 into player rates). Finalists now carry real rates (Messi 1.66, Mbappe 2.03, Kane 1.88, Oyarzabal 2.42, Alvarez 0.96) vs the 0.60 generic default.",
437+
"name": "player-sot-rate-refresh",
438+
"change": "Fetched leak-free per-player SoT/90 for 157 players from a paid stats API (WC-2026 season excluded), later removed from the public repo. Blended sot_per90 into player rates via bot/data/teamstats.py. Finalists carried real rates (Messi 1.66, Mbappe 2.03, Kane 1.88, Oyarzabal 2.42, Alvarez 0.96) vs the 0.60 generic default.",
439439
"category": "player_prop / SoT data",
440440
"rbp_before": 1020.84,
441441
"rbp_after": 1039.08,

scripts/group_scenarios.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
def _latest_snapshot() -> Path:
3030
files = sorted(glob.glob(str(REPO / "data" / "standings" / "*.json")))
3131
if not files:
32-
raise SystemExit("no standings snapshot; run scripts/fetch_standings.py first")
32+
raise SystemExit("no standings snapshot found in data/standings/")
3333
# prefer a -live file for today if present
3434
return Path(files[-1])
3535

workflows/DAILY.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ When the user reports a settled result, log it: write `results/games/<NNN>.json`
5757
3. It will **not** submit unless you tell it to.
5858

5959
## Group standings & motivation (Matchday 3+)
60-
From MD3, group games kick off in pairs. Pull the table and qualification scenarios:
60+
From MD3, group games kick off in pairs. Pull the qualification scenarios from the
61+
pre-fetched standings snapshots in `data/standings/`:
6162
```bash
62-
python scripts/fetch_standings.py # data/standings/<date>.json (add --live mid-matchday)
6363
python scripts/group_scenarios.py # per-team clinched / must_win / eliminated / alive
6464
```
6565
**Use it as a DECISION-SUPPORT aid, NOT a model tilt.** Empirical test (526-match history) found the

workflows/DATA_ENRICHMENT.md

Lines changed: 0 additions & 63 deletions
This file was deleted.

0 commit comments

Comments
 (0)