4d1803f6d72480c3d41d97569d10564d7c5089a9
4 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7ac6aa73e3 |
Layer 2: multi-axis archetype classifier; the FLEX fallback is gone
A player is a blend across independent axes, not one label. Skubal is a STARTER and a strikeout arm and a ground-ball arm and a control arm — four true things at once, and single-label classification threw three of them away. AXIS INDEPENDENCE WAS MEASURED, NOT ASSUMED. Correlations over the live store (467 batters, 531 pitchers); anything |r| >= 0.70 is one underlying trait and was collapsed so we 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 — all collapsed. The survivors are genuinely orthogonal, and one result is worth stating: pitcher velocity correlates +0.14 with K%, +0.07 with whiff% and +0.07 with GB%. Velocity is NOT a proxy for missing bats — a hard thrower who misses no bats is a real distinct type, so CANNON earns its own axis rather than being folded into STRIKEOUT. Pitcher K% ~ GB% is -0.10, so PUNCHOUT and SINKER are independent, which is exactly the multi-axis thesis. Cut-lines are the measured p75 (distinctive) and p90 (elite), per role where the tails differ even when the medians agree: reliever GB% p90 is 54.1 against a starter's 48.9, both with a median of 42.5. THE FALLBACK IS DELETED. classify() used to return FLEX (mlb) / SHIELD (wnba) / CONNECTOR (nba) at weight 1.0 when nothing scored — "could not classify" rendered as a fully-confident classification of a real archetype, with descriptive education copy attached. 8 of 18 MLB players carried it, and FLEX could never be earned because its only scoring input had zero writers. Every sport now does what MMA already did: unclassified is absent. Induced on real players. Skubal: STARTER, throws L, WHIFF + SEAM + PINPOINT, all elite. Judge: BOMBER + GRINDER + WHIFF RISK — elite power, patient, strikes out, three true things. Kwan: SURGEON + SNIPER + SLASH with NO power claimed (0.4 barrel% is absent, not "low power"). Josh Bell, who used to classify as DRIVER: empty blend, "No standout profile — league-average across every measured axis." Alan Roden, who was FLEX at weight 1.0 on 21 PA: every axis absent, "Not enough plate appearances yet — no profile claimed." Per-axis honest-absence holds: a velo-less pitcher keeps every other axis, and NO DATA is distinguishable from LEAGUE-AVERAGE rather than collapsing into one shrug. The full vector is stored for Layer 3; only the top three distinctive traits surface. Three existing tests asserted the fallback and were updated to assert absence. One of them surfaced a real robustness gap: classify(sport, null) threw, because an explicit null does not trigger a default parameter and every scorer dereferences its argument. Guarded. Every baseball name is accounted for in docs/ARCHETYPE-AXES.md — built, alias, tier, or shelved with its unlock condition. Zero orphans; cross-sport names left for their sport. Tests 3601 passed / 293 suites. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj |
||
|
|
f5156dd16d |
Un-claim CLV on the public profile; un-fabricate player-page FORM
Two Truth-Law fixes found by auditing the product logged-out. FIX 1 — /u/[handle] claimed a "CLV-verified record" with "closing-line value included" while ZERO closing-line value renders there. Verified live: GET /api/profiles/vyndr returns beat_close_pct null (gated behind CLV_CAPTURE_RELIABLE, unset while C4 is open). Eight instances found — two of them (the OG + portrait "CLV-VERIFIED RECORD · 30D" eyebrows) only by the post-removal residual sweep; two more printed the claim in exactly the no-record branch. Copy now describes what the page shows. The gated CLV-VERIFIED badge and the BEAT CLOSE figure are removed from the public profile, OG card and portrait card. DISPLAY ONLY: beat_close_pct, clvCaptureReliable() and the whole CLV data path are untouched, and the earned directional badge stays Analyst+Desk. The claim returns when CLV genuinely renders here. Also fixes the doubled "· VYNDR · VYNDR" title (layout's '%s · VYNDR' template already supplies the suffix); verified on composed output by serving the build and reading the real HTML, not on source. FIX 2 — the player page's FORM was `70 + 4 × (count of tonight's graded props)`. Nothing on the HTTP path ever sets stats.form, so that fallback WAS the live number: Josh Bell's "74" is 70 + 4×1 prop, confirmed against his live payload. MATCHUP was gradeFromForm(that number), with a hardcoded 'B' on the no-archetype branch — both fabricated letters with no opponent input on the path. Systemic: buildIntel is the unconditional path for every player and sport. FORM and MATCHUP now render "—" (kind 'plain', so no bar width or colour is computed off a null). gradeFromForm is deleted and the prop count is no longer passed into buildIntel. computeFormScore's hardcoded 75 now returns undefined. Induced across MLB/NBA/WNBA: all render cleanly, and real values (USAGE 3.6 AB/G, REST B2B) still render. Neither form value feeds the grade — engine1 reads raw l5_avg/l20_avg against the line and never a form key; buildIntelFields decorates the already-graded object. Grade inputs are byte-identical. Held (needs a per-sport headline-stat design call): a real player-level form metric + label disambiguation. Tests 3491 passed / 289 suites, web build exit 0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj |
||
|
|
c8fc9f577e |
Session 46: Grade card intel + name normalization + pitchers (2122 tests)
Three focused P1 fixes on the Session-45 snapshot model.
- Grade card intel ROOT CAUSE: gameLogService is NBA/WNBA-only (offline Python),
so MLB props never got l5_avg/l20_avg and buildIntelFields returned {}. Wired
MLB game logs into featureCache.gameLogFeatures via mlbStatsAdapter.getPlayerStats
(pure mlbGameLogFeatures + MLB stat_type->field map). buildIntelFields gained
playerStats/projection fallbacks for partial intel.
- Player name normalization: src/utils/playerName.js (+ web/src/lib copy):
normalizeName -> {display,key}. Strips periods, de-dots suffix, accent-folds
the key. Applied in snapshotService grouping, slateAdapter grade index +
player-strip merge (variants collapse, longest name shown), and
playerIntelService. "A.J. Ewing"/"AJ Ewing" + "Jazz Chisholm"/"Jr." now merge.
- MLB starting pitchers: new GET /api/schedule/:sport/pitchers (probablePitchers
service wrapping mlbStatsAdapter.getScheduleWithPitchers + best-effort ERA).
Slate fetches it, builds a team->pitcher map (full name + mascot match),
attaches pitchers to MLB GameCardData. + Next proxy.
Backend 2100 -> 2122 tests (+22), 176 suites. Web build clean (exit 0).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
8bc79f3c38 |
Session 42: Player Intelligence System — archetypes, stat strips, player profile, enhanced cards (2011 tests)
Built from the Claude Design "VYNDR Player Intelligence" bundle (10 sections). - Archetypes: src/services/archetypeService.js — 41 archetypes (15 NBA / 5 WNBA-unique / 15 MLB / 6 soccer), classify -> primary+secondary+blend. Frontend visual map web/src/lib/archetypes.js (colors verified == backend). ArchetypeBadge (full/ghost/tint + glyphs) + ArchetypeBlend (DNA bar). - StatStrip (compact/expanded): player name once, horizontal mono stats, inline GradeBadge props, onPlayerClick -> profile. - Stats API: extended src/routes/stats.js with /player/:name, /leaders, /game/:id (rate-limited). Aggregation in playerIntelService.js (sanitizes name param; grades cache; graceful on cold cache). Next proxies added. - Player Profile /player/[name]: all 9 design sections, graceful empty states. - Enhanced GameCard (MLB pitchers + player-grouped StatStrips) + GradeResultCard (archetype strip + stat context + VYNDR intelligence, optional/self-hiding via gradeAdapter.buildIntelFields). Player-name links wired everywhere. - Settings page replaces the S41 redirect (account/subscription/notifications/ display/responsible-play/danger-zone with DELETE-gated delete). LINKS to the real /settings/security MFA page — does not replace it. + BookChip. - Bonus: Stats Explorer /explore (real /api/stats/leaders leaderboard); added Explore + Settings to Nav MORE. Deferred (need data pipelines, Session 43): Team Hub, Offseason Intel, Slate redesign, Stats Explorer sub-panels. Backend 1940 -> 2011 tests (+71), 157 suites. Web build clean (exit 0). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |