STATE: Session 69 — multi-axis archetypes live, FLEX fabrication deleted

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-20 22:40:26 -04:00
parent 7ac6aa73e3
commit 063e9fb3f7
2 changed files with 67 additions and 2 deletions
+66 -1
View File
@@ -1,5 +1,5 @@
# VYNDR — STATE OF THE WORLD
### As of `a499598` (main, DEPLOYED + fingerprinted live), 2026-07-21. This file opens every future session. **Start with the CURRENT STATUS + OPEN ITEMS block below.**
### As of `7ac6aa7` (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,71 @@ 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 69 — LAYER 2: MULTI-AXIS ARCHETYPES (2026-07-21)
Spec: **`docs/ARCHETYPE-AXES.md`** (every name accounted for). Layer 3 NOT built.
**Archetype still does not feed grades** — display + snapshot + future Layer 3.
## Tier-A joins — all three landed, each ONE free call
| Join | Before | After | Source |
|---|---|---|---|
| Handedness | batters **0%** | **1,354/1,354** | statsapi `/sports/1/players` (bats+throws+position) |
| True role | IP proxy (drifts) | **750/750** | statsapi stats `playerPool=ALL` (751 rows; default returns only ~57) |
| **Velo** | **53%** | **99%** (721/729) | wide `pitch-arsenals` matched BY PITCH TYPE |
**Role split (real usage):** starter 219 · reliever 365 · setup 126 · closer 40.
The velo fix is what makes CANNON/HOWITZER buildable instead of shelved.
## 🔬 AXIS INDEPENDENCE — MEASURED (467 batters / 531 pitchers)
**|r| ≥ 0.70 ⇒ one trait ⇒ COLLAPSED** (never show one trait as two archetypes):
`batter k%~whiff% +0.89` · `hard-hit%~exit velo +0.88` · `chase%~swing% +0.87` ·
`chase%~bb% 0.72` · `pitcher k%~whiff% +0.76` · `gb%~fb% 0.73`.
**The finding that mattered:** `pitcher velo ~ k% = +0.14`, `~whiff% = +0.07`,
`~gb% = +0.07`. **Velocity is NOT a proxy for missing bats** — a hard thrower
who misses no bats is a real distinct type, so it earns its own axis.
`pitcher k% ~ gb% = 0.10` → PUNCHOUT ⊥ SINKER, which IS the multi-axis thesis.
## Cut-lines
Real **p75 (distinctive) / p90 (elite)**, **per role where tails differ** even
when medians agree — reliever GB% p90 **54.1** vs starter **48.9**, both median
42.5. Floors PA≥50 / IP≥10.
## 🔴 THE FLEX FALLBACK IS DELETED (`archetypeService.js`)
`classify()` returned FLEX (mlb) / SHIELD (wnba) / CONNECTOR (nba) **at weight
1.0** when nothing scored — "could not classify" rendered as a confident
classification **with descriptive education copy**. 8 of 18 MLB players carried
it, and FLEX could never be *earned* (its only input, `utility`, had zero
writers). Every sport now does what MMA already did: **unclassified = absent.**
**Live fingerprint:** Alan Roden → `primary: null, blend: []`.
## Induced on real players
| Player | Blend |
|---|---|
| Skubal | STARTER · L · **WHIFF + SEAM + PINPOINT** (all elite) |
| Judge | **BOMBER + GRINDER + WHIFF RISK** (elite power, patient, whiffs) |
| Kwan | **SURGEON + SNIPER + SLASH**, power **absent** (0.4 barrel ≠ "low power") |
| **Josh Bell** (was DRIVER) | **empty** — "No standout profile" |
| **Alan Roden** (was FLEX @1.0, 21 PA) | **all axes absent** — "Not enough PA yet" |
| velo-less SP | keeps 3 axes; velocity+slot absent |
**`absent` (no data) is distinct from a null vector entry (measured, ordinary).**
## Gotchas
- `classify(sport, null)` **threw** — an explicit null does NOT trigger a default
parameter and every scorer dereferences its arg. Guarded in `classify`.
- Three tests asserted the fallback; updated to assert absence. One over-broad
edit briefly broke a test where a player has REAL stats and legitimately
classifies (Riley → BOMBER) — removing the FALLBACK is not removing
classification.
- `TeamHub.tsx` `|| 'zzz'` is a SORT key, not a display default — sorts
unclassified last. Correct; leave it.
## Layer 3 (HELD) reads the FULL vector
`classifyPlayer()` stores every axis; only the top ≤3 surface. Projection +
adjusters (park, weather, umpire, platoon) are the next arc, not built here.
---
# 🟢 SESSION 68 — LAYER 1: STATCAST MECHANISM DATA (2026-07-21)