diff --git a/specs/STATE.md b/specs/STATE.md index c2fdc2b..f15ddae 100644 --- a/specs/STATE.md +++ b/specs/STATE.md @@ -1,5 +1,5 @@ # VYNDR β€” STATE OF THE WORLD -### As of `3ac91c3` (main, DEPLOYED), 2026-07-21. This file opens every future session. **Start with the CURRENT STATUS + OPEN ITEMS block below.** +### As of `f33091d` (main, DEPLOYED + fingerprinted live), 2026-07-21. This file opens every future session. **Start with the CURRENT STATUS + OPEN ITEMS block below.** --- @@ -131,6 +131,77 @@ exist locally; harmless, the data restores completely. `specs/snapshot-retention.md` (Phase 2 report + schema) Β· `specs/audit-data/grade-collapse.md` Β· `specs/audit-data/gate-simulation.md`. +--- + +# 🟒 SESSION 74 β€” PARK BASE (public, pluggable) + GAME-LEVEL CAPTURE (2026-07-21) + +## Phase 0 β€” the grain is cheaper than expected +Settle sees a player's game-log line (date + teams), **never venue or totals**. +But **ONE statsapi schedule call per game DATE** returns every game that day with +venue + linescore + scoringPlays. **Not per game, not per prop.** Verified: 15 +games, 1 call. + +## Public base β€” the ingestion was ALREADY DONE +`src/data/parkFactors.js` (static FanGraphs, S15) **is** the public base. +`src/services/parkBase.js` converts its 100-index to the composable multiplier +(COL 128 β†’ **1.28**) instead of ingesting a second copy. + +**πŸ”΄ THE COMMODITY LINE IS IN CODE, not just a comment.** Every resolution +carries `provenance`: +- public β†’ `proprietary: false`, *"Commodity: a public number. Not a VYNDR + derivation."* +- derived β†’ `proprietary: true` β€” **reserved**, and only earned once it beats + the public base on the instrument. +**Never market "proprietary park factors" about the public base.** + +**Honest-absent where even PUBLIC is thin** (`UNSTABLE_PUBLIC`: ATH/OAK/SAC/LV β€” +relocated club, temporary venue). Extend that set whenever a park opens or a +club moves; a missing entry means a confident factor for a stadium with no data. + +## SOURCE-PLUGGABLE β€” the architectural point +`resolveParkBase()` is the ONLY accessor; public and derived return **identical +shapes**, so callers never branch on source. Self-derived swaps into the same +slot with nothing downstream rewritten. **A derived source with no factor +returns `absent` β€” it does NOT silently fall back to public** (that would turn a +commodity number into a proprietary claim). + +## Game-level capture β€” LIVE +`game_context` (migration 035), **game grain, deduped on `game_id`, never copied +onto prop rows**. Named-purpose fields ONLY: venue β†’ park factors Β· runs β†’ run +environment Β· HR totals β†’ HR factors. Nothing else stored. +- **Finals only** (an in-progress total is not a result). +- **No scoring plays β†’ HR is `null`, not 0.** +- HR from scoringPlays is COMPLETE β€” every HR scores β‰₯ the batter. +- Runs nightly beside the settle pass (yesterday's date). + +**Live fingerprint:** `POST /api/internal/gamectx/2026-07-20` β†’ **15 games, 15 +venues, 15 with HR totals, 0 duplicates.** + +## πŸ“… ACCRUAL TARGET β€” "later" is a number +**150 home games/venue** (β‰ˆ81/season) β†’ **~1.9 seasons** before a self-derived +factor can be NOMINATED against the public base. +Live now: **15 games Β· 15 venues Β· 0 ready.** Track: +`GET /api/internal/gamectx/accrual`. + +## Induced (live) +COL HR **+0.061** hitter Β· **+0.061** pitcher HR-allowed (same park, sign lives +in the STAT) Β· mirrored on under Β· SF negative Β· **TB weather_na=true with its +factor STILL applying** Β· ATH **absent** Β· strikeouts untouched. + +## ⚠️ STILL OPEN (unchanged from S73) +**Park does not yet reach live props** β€” `snapshotService` still doesn't attach a +venue per prop and pass `environment` into `attachChallenger`. `parkBase` + +`parkMultiplier` + the challenger's `environment` slot are all ready; the +propβ†’venue lookup is the missing link. +**And still blocking ALL measurement: no settled row carries `p_win`.** + +## Next +1. Attach venue β†’ prop β†’ `environment` (closes the park loop). +2. **Weather** β€” multiplies `park_base`; domes already `weather_na`; add + weather-actuals to `game_context` for later self-derived modulation. +3. Self-derived park factors at ~1.9 seasons of accrual. + + --- # 🟑 SESSION 73 β€” PARK FACTORS (derived, composable) (2026-07-21)