STATE: grading date binding fixed + blast radius quantified

This commit is contained in:
Kev
2026-07-20 03:52:34 -04:00
parent 6415751f2e
commit b76e35f575
+60
View File
@@ -133,6 +133,66 @@ exist locally; harmless, the data restores completely.
---
## 🟢 GRADING DATE BINDING FIXED — wrong-opponent bug closed (2026-07-20 07:50 UTC)
`computeFeatures.lookupTodayGame`**`lookupGameOnDate`**: it now sends
`?dates=YYYYMMDD` from the prop's BOUND game instead of taking ESPN's dateless
"today". Grading, settlement, retention and the ledger finally reference the
SAME game. **This was a MODEL-OUTPUT bug**: `opponentAbbr` feeds `opp_rank_stat`
(a ±1.0 factor) and `isHome` feeds `home_away` (+0.5).
**PROVEN against live ESPN, same instant:**
```
dateless "today" CLE→PIT NYY→LAD LAD→NYY (Jul 19 card)
bound to 2026-07-20 CLE→MIN NYY→PIT LAD→PHI (the real games)
bound to 2026-07-19 CLE→PIT NYY→LAD LAD→NYY (reproduces OLD exactly)
```
**Every opponent was wrong.** Measured at 07:5x UTC = **03:5x ET** — ESPN's
dateless scoreboard was STILL serving the previous day's card, so **the affected
window is wider than the 01:00/03:00 slots**.
- **Honest degradation:** no bound date → NO fallback lookup. Records
`no_bound_game_date`, leaves `opponentAbbr`/`isHome`/`gameId` null, and engine1
omits those factors rather than scoring a wrong matchup. Tests lock both ways.
- **Same class, also fixed:** Tank01 augmentation keyed its cache on TODAY's UTC
date; now uses the bound game date.
- **Audited:** no other dateless/"today" lookups remain in the feature path
(weather is current-conditions by venue; park/pace are static).
- Live cycles at 07:50/07:51 UTC wrote retention rows with `game_date 2026-07-20`
and `home_away` on 38/50 — games binding. MLB `opp_rank_stat` stays 0 for the
separate, known reason (ESPN's MLB team endpoint carries no defensive metric).
### 🔴 BLAST RADIUS (report-only — gates the heal)
**`ledger_entries` — grades by UTC hour (at-risk = late slots):**
| UTC hour | grades | settled results | risk |
|---|---|---|---|
| 00 | 32 | 29 | 🔴 at risk |
| 01 | 68 | 67 | 🔴 at risk |
| 03 | 152 | 103 | 🔴 at risk |
| 06 | 51 | 0 | 🔴 at risk (ESPN still on prior card at 02 ET) |
| 13/14/19/22 | 390 | 379 | ✅ same-ET-day, correct |
**At-risk: 303 grades (199 already settled with real results).** ~44 % of the
public record was graded in the affected window.
**`model_snapshots`:** 350 rows total — **50 carry `opp_rank_stat`** (the 03:02
UTC WNBA cycle) and are the poisoned moat rows; 190 carry `home_away`. Rows
captured 07:50+ are clean (post-fix).
**Recoverable vs quarantine (PLAN ONLY, nothing written):**
- **RECOVERABLE:** the correct opponent for a past date is still fetchable from
the date-pinned ESPN scoreboard, so a grade can be RE-DERIVED — but only where
the feature vector is reproducible. `model_snapshots` rows store the full
feature vector, so those are re-computable; **ledger rows do not** and would
need a full re-grade against historical inputs.
- **QUARANTINE:** any at-risk ledger grade that cannot be re-derived should be
marked computed-against-wrong-opponent and EXCLUDED from harness/validation —
never silently trusted. It stays in the public record as a real settled bet
(the result happened) but must not train or validate anything.
- **Scope note for the heal:** at-risk is defined by grading HOUR, not by proven
wrongness. Proving per-row wrongness requires re-deriving each row's opponent —
that IS the heal work.
## 🟢 game_date ROOT FIXED + 64 WRONG VOIDS REVERTED (2026-07-20 07:30 UTC)
- **ROOT (not DNP, as first diagnosed):** PropLine emits **no `commence_time`**
(grep-verified), so `ledgerService`'s `dateET(prop.game_time) ||