Session 54: Audit cleanup — name edges + polish (2255 tests)
P1 name edge cases (BOTH playerName.js copies, kept identical): - normalizeName strips hyphens (display+key): "Jung-hoo Lee" === "Jung Hoo Lee". - nameKey strips single-letter MIDDLE tokens: "Josh H Smith" === "Josh Smith" (keeps first+last; real middle names + collapsed initials untouched). - richie -> richard added to NICKNAMES. P2 polish: - Team Hub names normalized at the source (teamService.getTeamHub) so "J.C. Escarra" renders as "JC Escarra" like the dashboard. - snapshotService dedup keeps the highest-confidence GRADE but the richest DISPLAY (accented "José" over "Jose") so prop rows match the pitcher line. - correlationWarning names the game: "2 legs from the same game (NYY @ BOS)". Backend 2246 -> 2255 tests (+9), 194 suites. Web build clean (exit 0). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -213,15 +213,30 @@ async function runSnapshot(sport, opts = {}) {
|
||||
// merged names. PropLine sends "Matt"/"Matthew", "A.J."/"AJ", "(STL)" tags as
|
||||
// separate players; collapse to ONE grade per normalized player + stat (keep
|
||||
// the highest-confidence; rawGraded is already confidence-desc).
|
||||
// Session 54 — also keep the RICHEST display per player (prefer the accented
|
||||
// variant: "José" over "Jose", then the longer string) so the prop rows match
|
||||
// the accented pitcher line. The GRADE picked is still the highest-confidence.
|
||||
const hasAccent = (s) => [...String(s)].some((c) => c.charCodeAt(0) > 127);
|
||||
const richerDisplay = (a, b) => {
|
||||
if (!b) return a;
|
||||
if (hasAccent(a) !== hasAccent(b)) return hasAccent(a) ? a : b;
|
||||
return a.length >= b.length ? a : b;
|
||||
};
|
||||
const dedup = new Map();
|
||||
const bestDisplay = new Map();
|
||||
for (const g of rawGraded) {
|
||||
const disp = normalizeName(g.player || g.player_name).display || g.player || g.player_name || '';
|
||||
const k = `${nameKey(disp)}|${String(g.stat_type || g.stat || '').toLowerCase()}`;
|
||||
const pk = nameKey(disp);
|
||||
bestDisplay.set(pk, richerDisplay(disp, bestDisplay.get(pk)));
|
||||
const k = `${pk}|${String(g.stat_type || g.stat || '').toLowerCase()}`;
|
||||
const cur = { ...g, player: disp, player_name: disp };
|
||||
const prev = dedup.get(k);
|
||||
if (!prev || (Number(g.confidence) || 0) > (Number(prev.confidence) || 0)) dedup.set(k, cur);
|
||||
}
|
||||
const graded = [...dedup.values()];
|
||||
const graded = [...dedup.values()].map((g) => {
|
||||
const disp = bestDisplay.get(nameKey(g.player)) || g.player;
|
||||
return { ...g, player: disp, player_name: disp };
|
||||
});
|
||||
|
||||
// Archetype per unique player (pure math once we have stats). Best-effort —
|
||||
// a missing stat line → no badge (not a fallback archetype).
|
||||
|
||||
Reference in New Issue
Block a user