STATE: game_date root fixed, 64 voids reverted, grading blast radius flagged

This commit is contained in:
Kev
2026-07-20 03:27:42 -04:00
parent 1bcdd8b305
commit 8e17de4010
+45
View File
@@ -133,6 +133,51 @@ exist locally; harmless, the data restores completely.
---
## 🟢 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) ||
dateET(gradedTs)` always fell through to the **GRADE clock**. A 01:00/03:00
UTC snapshot is 21:00/23:00 ET the PREVIOUS day → tonight's props filed under
yesterday → settlement correctly found no game → Order 1's void logic
destroyed 64 real results.
- **FIX — `src/services/gameBinder.js`:** binds each prop to a scheduled game by
TEAMS across the ET window (grade date, +1, 1) and attaches the GAME'S own
time/date/id, in `snapshotService` **before** grading and the ledger write, so
ledger + retention + settlement all inherit one correct date.
**PROVEN against the live schedule at the failing hour:** a `2026-07-20T03:00Z`
grade (ET date 07-19, what the old code used) bound Steven Kwan to
**game_date 2026-07-20**, `mlb:2026-07-20:401816188`.
- **HARD CONTRACT:** unbindable → **nothing**. The grade-clock fallback is gone;
ledgerService SKIPS and counts such rows. Verified live: a prop with an
invented matchup returned `unresolved`, never a guessed date.
- **Doubleheaders** are flagged `ambiguous`, never attributed. Real case already
in data: `mlb:2026-07-11:MilwaukeeBrewers@PittsburghPirates(Game1)`.
- **Retention had the same bug** (rows dated by the snapshot clock) — fixed to
the bound game's ET date.
- **64 wrong voids REVERTED** (60 mlb + 4 wnba), scoped exactly to
`settlement_version=2 AND outcome='void' AND settlement_source='player_dnp'`.
- **LIVE PROOF of the safety fix:** the next induced settle pass returned
**`voided: 0, pending: 64`**. The old code voided all 64; the deployed code
refuses to claim DNP on an unconfirmed absence.
### 🔴 STOP-AND-REPORT — the date bug also reaches GRADING (not just settlement)
`computeFeatures.lookupTodayGame` calls the ESPN scoreboard with **no date
param** — it takes whatever ESPN calls "today". A prop graded at 23:00 ET can
therefore bind its `home_away` / `opponentAbbr` features to the WRONG game
(yesterday's finished one), which feeds `opp_rank_stat` and the home/away factor.
**Not fixed — flagged per the order's stop rule.** Blast radius:
- **Grading: AFFECTED** (feature correctness at late-ET slots — 01:00/03:00 UTC).
- **Settlement: FIXED** (this order).
- **Retention: FIXED** (this order).
- **Display/slate: NOT affected** — the board renders from the date-pinned
schedule and joins grades by player+stat, never by ledger `game_date`.
### 🔶 STILL OPEN — the reverted 64 cannot settle yet
Their `game_date` is still the OLD wrong value (Jul 17/18); the binder only
corrects rows written from now on. They will retry and age to `unrecoverable`
until their dates are corrected. **Correcting them is the first act of the heal
order** — healing against wrong dates would simply re-fail.
## 🟢 RETENTION CLOCK TICKS ON ITS OWN (2026-07-20 06:05 UTC)
Induced the REAL cron entrypoint rather than waiting for 14:00 UTC.
- **Cron capture needed NO wiring — verified in code.** `snapshotScheduler`'s