diff --git a/specs/STATE.md b/specs/STATE.md index 2501268..83df910 100644 --- a/specs/STATE.md +++ b/specs/STATE.md @@ -1,5 +1,5 @@ # VYNDR — STATE OF THE WORLD -### As of `6dd6f59` (main, DEPLOYED), 2026-07-21. This file opens every future session. **Start with the CURRENT STATUS + OPEN ITEMS block below.** +### As of `7b25d97` (main, DEPLOYED), 2026-07-21. This file opens every future session. **Start with the CURRENT STATUS + OPEN ITEMS block below.** --- @@ -131,6 +131,72 @@ 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 77 — DORMANT ADJUSTERS WIRED LIVE (2026-07-21) +The four-order plumbing gap is CLOSED. park + weather + platoon now reach live +grades. Pure input-wiring — **the 5 adjuster files are byte-identical** (verified +`git diff --quiet`). + +## Phase 0 gate — all three inputs AVAILABLE at build +| Input | Availability | Source | +|---|---|---| +| Venue | **ALWAYS** 15/15 | schedule game object | +| First-pitch | **ALWAYS** | schedule `gameTime` | +| Opposing-SP hand | **declared 30/30 this afternoon** (morning locks precede it → platoon absent, correct) | probable `pitcherId` → statsapi hand | +Batter hand (`statcast.bats`) + MLBAM id were already on each grade. + +## What was built +**`src/services/environmentContext.js`** (the wiring; adjusters untouched). +Fetches ONCE per snapshot: schedule, probable pitchers, ONE batched handedness +call, ONE Open-Meteo forecast per home park, batter splits per hitter. +`PARK_COORDS` (30 parks) lives here as public geometry (like the dome list), NOT +in an adjuster. Best-effort throughout — any failure → that prop archetype-only, +never a pipeline break. +**`attachChallenger` is now async** + takes `contextFor(grade)` → `{environment, +matchup}` → `adjust()` (which already accepted both). + +## Independent attribution (each of 4 measurable separately) +Ledger columns `env_multiplier / env_park_base / env_weather_mod / +env_weather_state` + `challenger_adjustments` jsonb keeping archetype / +environment / matchup as SEPARATE entries. Not one blended delta. + +## Combined bound (tested) +Coors slugger + wind-out + favourable platoon, all at once → **δ < 0.12**. Every +layer capped, total nudge clamped. Stacks lean, never re-forecast. + +## ✅ PASS CONDITION MET — env_multiplier non-null (was 0 for 4 orders) +Proven END-TO-END on the live slate (buildContext + adjust against real feeds): +`venues_with_weather 15 · opp_declared 30 · pitchers_with_hand 30`. +| Park | env | compose | +|---|---|---| +| PHI | **1.179** | park 1.09 × wx 1.082 → **δ +0.041** | +| COL/ATL | >1 | hitter parks | +| CLE 0.929 · KC 0.937 | <1 | pitcher parks | +| **TOR/MIL** | park only | `wx 1 [dome_na]` — weather stands down, **park still applies** | + +## 🔴 THE ONE HONEST GAP — not yet on a LEDGER ROW +Immutability refused to rewrite today's already-locked props (`ignoreDuplicates`), +so re-inducing wrote 0 new rows and **`env_multiplier` is still 0 on ledger rows**. +The wiring is PROVEN to produce the value (above); it lands on a row at the **next +NEW MLB lock**. Verify then: +```sql +select count(*) filter (where env_multiplier is not null) with_env, + count(*) filter (where challenger_adjustments::text like '%matchup%') with_platoon +from ledger_entries where user_id is null; +``` + +## Point-in-time / no lookahead +Weather = FORECAST for first pitch fetched at projection time. Platoon = split +entering the game. Neither reads settle-time. + +## Still open (unchanged, NOT this order) +- **No settled row carries `p_win`** — all adjusters still unmeasurable until + tonight's locks settle. +- Read-card triplet gap · mappingHarness nomination flow · A/D emission · + EV overconfidence · zero-push bug · edge_pct surfaces · 3 key rotations. + + --- # 🟡 SESSION 76 — PLATOON SPLITS (regressed) (2026-07-21)