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>
This commit is contained in:
@@ -86,7 +86,44 @@ function mapScanToGradeResult(input = {}) {
|
||||
altLadder: includeAlt && Array.isArray(input.alt_lines)
|
||||
? input.alt_lines.map((a) => ({ line: a.line, grade: a.grade }))
|
||||
: [],
|
||||
// Session 42 — Player Intelligence additions. All OPTIONAL + self-hiding:
|
||||
// they only render once the engine supplies them (Session 43 data pipeline).
|
||||
...buildIntelFields(input),
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = { mapScanToGradeResult, statLabel, computeEdge, isPhosphorConfirmed, toSignals };
|
||||
/**
|
||||
* Build the optional archetype / stat-context / vyndr-intelligence fields for
|
||||
* the grade card from whatever the engine provided. Returns {} when nothing is
|
||||
* present so the card sections stay hidden (no empty boxes).
|
||||
*/
|
||||
function buildIntelFields(input) {
|
||||
const out = {};
|
||||
if (Array.isArray(input.archetype_blend) && input.archetype_blend.length) {
|
||||
out.archetypeBlend = input.archetype_blend;
|
||||
} else if (input.archetype) {
|
||||
out.archetypeBlend = [{ archetype: String(input.archetype), weight: 1 }];
|
||||
}
|
||||
if (input.prop_dna && (input.prop_dna.reliable || input.prop_dna.volatile)) {
|
||||
out.propDNA = {
|
||||
reliable: input.prop_dna.reliable || [],
|
||||
volatile: input.prop_dna.volatile || [],
|
||||
};
|
||||
}
|
||||
const sc = {};
|
||||
if (input.season_avg != null) sc.season = String(input.season_avg);
|
||||
if (input.last10_avg != null) sc.last10 = String(input.last10_avg);
|
||||
if (input.vs_opp_avg != null) sc.vsOpp = String(input.vs_opp_avg);
|
||||
if (Object.keys(sc).length) out.statContext = sc;
|
||||
|
||||
const vi = {};
|
||||
if (input.form != null) vi.form = input.form;
|
||||
if (input.usage != null) vi.usage = String(input.usage);
|
||||
if (input.matchup_grade != null) vi.matchup = String(input.matchup_grade);
|
||||
if (input.rest != null) vi.rest = String(input.rest);
|
||||
if (Object.keys(vi).length) out.vyndrIntel = vi;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
module.exports = { mapScanToGradeResult, statLabel, computeEdge, isPhosphorConfirmed, toSignals, buildIntelFields };
|
||||
|
||||
Reference in New Issue
Block a user