STATE: Session 72 — Tier-1 live, Tier-2 harness forward-accrual (no historical OOS)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj
This commit is contained in:
Kev
2026-07-21 00:30:46 -04:00
parent 927e867a23
commit beac1816d2
+72 -1
View File
@@ -1,5 +1,5 @@
# VYNDR — STATE OF THE WORLD
### As of `f2da9dd` (main, DEPLOYED), 2026-07-21. This file opens every future session. **Start with the CURRENT STATUS + OPEN ITEMS block below.**
### As of `927e867` (main, DEPLOYED), 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 72 — TIER-1 MAPPINGS LIVE + TIER-2 HARNESS (2026-07-21)
## 🔴 PHASE 0 GATE — NO HISTORICAL OOS IS POSSIBLE (and why)
`statcast_aggregates` is **overwritten nightly by design** (Layer 1 = full
re-pull upsert) → season-TO-DATE only, **no point-in-time history**. Classifying
a player for a Jul-15 game with today's aggregate feeds in Jul 1521 →
**look-ahead leakage**, making any "out-of-sample" verdict worthless.
**→ The harness reads the archetype vector RETAINED at grade time (S70
instrument) and runs FORWARD-ACCRUAL.** Reported, not worked around.
*(If point-in-time archetypes are ever wanted, Layer 1 must retain a dated
snapshot per refresh — a real schema change, not a query.)*
## Canonical names — asserted, not assumed
Every mapping references the axis keys the classifier **emits**; a test walks
both maps against `BATTER_AXES`/`PITCHER_AXES`. **A non-existent key would look
wired and never fire** — that's the failure this guards.
## TIER 1 — LIVE (tautological, directional, MLB-only)
| Axis (canonical) | Labels | Stat | Dir |
|---|---|---|---|
| `strikeout` | PUNCHOUT / WHIFF | strikeouts | ↑ |
| `ground_ball` | SINKER / SEAM | home_runs_allowed | ↓ |
| `fly_ball` | FLY BALL / ELEVATOR | home_runs_allowed | ↑ |
| `control` | SURGEON ARM / PINPOINT | walks_allowed | ↓ |
| `power` | SLUGGER / BOMBER | total_bases, home_runs | ↑ |
| `contact` | TECHNICIAN / SURGEON | hits ↑, strikeouts ↓ | |
| `patience` | GRINDER / SNIPER | walks | ↑ |
Average player untouched; UNDER mirrors OVER exactly.
**SPEED (BURNER→SB) is HONESTLY ABSENT** — SB never reached the aggregate store,
so Layer 2 shelved the axis. `BATTER_MAP.stolen_bases = {}`, not invented.
## TIER-2 HARNESS — `src/services/mappingHarness.js`
Three hurdles a plausible-but-worthless mapping fails:
1. **MARGINAL, not correlation** — scores the archetype against the
**projection's RESIDUAL** (`outcome p_win`). If the projection already
knows it → `REJECT (redundant)`. **This is the double-counting catch.**
2. **OOS split by DATE, never random** — rows from one game share pitcher/park/
lineup; a random split leaks.
3. **Direction validated from held-out data; a contradicted sign is REJECTED,
never silently flipped** (flipping = fitting noise).
Floors: `MIN_ROWS 200 · MIN_HELD_OUT 60 · MIN_EFFECT 0.02` → else `INSUFFICIENT`.
**Lifecycle encoded: `nominated → live → claimed`.** A survivor RUNS LIVE and is
measured; **only the quantified public claim waits.** Nothing sits dark.
## Real candidate, end-to-end
`GROUND-BALL → hits_allowed`**INSUFFICIENT — 0 / 200 settled rows**, because
no settled row carries `p_win` yet (S70 instrument starts at the next new lock).
Correct and expected verdict.
## Gotcha worth keeping
My first synthetic fixture **aliased the carrier selector against the outcome
draw** and manufactured a 0.038 effect where zero was injected. The harness
rejected it correctly — but via the SIGN reason, not redundancy, which is how I
found the fixture bug. Draw now uses a coprime modulus. *Lesson: when a harness
gives the right verdict for the wrong reason, check the fixture.*
## Still blocking everything downstream
**No settled row carries `p_win`/`p_win_challenger` yet.** Tier-1 adjusts real
projections now, but neither it nor any Tier-2 candidate can be evaluated until
volume accrues. Verify:
```sql
select count(p_win) champion, count(p_win_challenger) challenger,
count(*) filter (where challenger_delta <> 0) moved
from ledger_entries where user_id is null;
```
---
# 🟡 SESSION 71 — LAYER 3 STEP 2: CHALLENGER PROJECTION (2026-07-21)