S11 (a1): live tracking — the read locked, the game watched

MLB statsapi + WNBA ESPN live boxscores -> per-player current values
(live:{sport}:{date} TTL 90s, /api/live/:sport + Next proxy). Pure
propState math (HIT / ON PACE / NEEDS N / HOLDS / LINE PASSED — never
red in-progress), attachLiveProgress strip join on nameKey+statType,
proximity-to-hit slate float, StatStrip LiveTracker in the ROW-GRAMMAR
outcome slot (spec amended + lock test updated). Grades never change
in-game — tracking, labeled as such. 2698 -> 2757 tests, web build 0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kev
2026-07-12 00:45:29 -04:00
parent 14dc9cf270
commit b5d3fd14bb
18 changed files with 1666 additions and 18 deletions
+34 -1
View File
@@ -1,7 +1,40 @@
# VYNDR — Build State
## Last Updated
2026-07-11
2026-07-12
## Session S11 (a1 board, 2026-07-12) — Live Tracking: the read locked, the game watched ✅
Spec: `specs/LIVE-TRACKING.md` (+ ROW-GRAMMAR §2/§3 S11 amendment).
2698 → **2757 tests** (229 suites), web build exit 0.
- **`liveTrackingService`** — MLB statsapi (`schedule?hydrate=linescore`
identifies Live games + inning in ONE call → boxscore per live game) + WNBA
ESPN (scoreboard 'in' → summary boxscore). Pure parsers built on REAL feed
shapes captured while PHI@DET was live (bottom 8th, 2026-07-11). LOCAL
`LIVE_BOX_FIELD` map (batting/pitching split + IP thirds — deliberately
decoupled from outcomeService.MLB_LOG_FIELD, same rule as settlement).
A player with empty box stats is ABSENT, never 0.
- **POLLING RULE** — `live:{sport}:{date}` TTL 90s, written cache-aside by
public `GET /api/live/:sport` (60/min, mounted in app.js + Next proxy
`app/api/live/[sport]`). Quota: 1 schedule + N-live-games boxscore calls
per 90s across ALL users; zero boxscore calls when nothing is live.
- **`lib/liveProgress.js`** (pure, CommonJS) — `propState` (over: HIT ✓ /
ON PACE / NEEDS N beats-the-push; under: HOLDS-IF — never hit until final,
LINE PASSED amber when exceeded; never red in-progress), `buildLiveIndex`,
`attachLiveProgress` (graded+unsettled+non-dead props only, joined on
nameKey + the new canonical `statType` strip field, state vs the LOCKED
line), `gameLiveProximity` + `sortLiveFirst`.
- **LIVE SLATE MODE** — Slate polls `/api/live/{sport}` every 60s ONLY while
live mlb/wnba games are on screen; live games with tracked props float to
the top by proximity-to-hit. `StatStrip.LiveTracker` renders
`3/1.5 TB · ▼8th` + game-progress bar + state chip in the ROW-GRAMMAR
OUTCOME slot (proto-outcome; actions suppressed while live); GameCard shows
"TRACKING — READ LOCKED PRE-GAME" once per live card. GRADES NEVER CHANGE
IN-GAME.
- **Acceptance (real feed)**: `Bryce Harper 3/1.5 TB · ▼8th → HIT ✓`,
`Cristopher Sánchez 1/2.5 ER · ▼8th → HOLDS` — full pipeline on the live
capture. Verify tonight: `curl -s https://vyndr.app/api/live/mlb | head -c 400`
(or `node -e "require('./src/services/liveTrackingService').getLiveTracking('mlb').then(o=>console.log(JSON.stringify(o).slice(0,400)))"`
on the box during a live window).
## Session S6 (a1 board, 2026-07-11) — Display: the full picture under the grammar ✅
Spec/law: `specs/ROW-GRAMMAR.md` (locked by `tests/unit/rowGrammar.test.js`).