Session 48: Name normalization at every layer + usage field (2156 tests)
Trace-first: the normalizer functions were correct (S47) but raw names still
flowed through paths that skipped them. Fixed each leaking path.
- 2a (source chokepoint): snapshotService.runSnapshot normalizes each grade's
player to the de-dotted display AND dedupes to one grade per nameKey|stat
(highest confidence) before writing grades:{sport} + snapshot:latest. Every
consumer (GameCard, Explore, leaders, profile) now gets clean merged names.
- 2b: buildPlayerStripsFromProps dedupes a player's props by stat (graded >
awaiting) → one row per stat (kills "Ks 5.5 AND Ks 3.5" variant dupes).
- 2c: scan tonightsPlayers grid groups by nameKey, displays normalized name.
- 3: profile VYNDR INTELLIGENCE "+0%"/"—" was buildIntel's defaults (separate
from the grade card's buildIntelFields, which already works). resolvePlayerStats
now attaches real usage (AB/G) + rest (B2B/Xd); buildIntel renders them; REST
default is now "—".
Backend 2149 -> 2156 tests (+7), 181 suites. Web build clean (exit 0).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -493,6 +493,25 @@ snapshot, locked to the line, and read from cache.
|
||||
moderate). If you re-tune archetype thresholds, remember season totals are
|
||||
partial mid-season — don't use full-season cutoffs.
|
||||
|
||||
## Normalization Chokepoints (Session 48 — non-obvious)
|
||||
- **The snapshot is the normalization SOURCE.** `snapshotService.runSnapshot`
|
||||
normalizes every grade's player to `normalizeName().display` AND dedupes to one
|
||||
grade per `nameKey|stat_type` (highest confidence) before writing
|
||||
`grades:{sport}` + `snapshot:{sport}:latest`. So GameCard overlay, Explore,
|
||||
leaders, and profile activeProps ALL inherit clean, merged names — don't add
|
||||
per-consumer normalization, fix it here.
|
||||
- **Three paths that needed it (all fixed):** snapshot grades (above);
|
||||
`buildPlayerStripsFromProps` dedupes a player's props by stat (graded > awaiting);
|
||||
scan `tonightsPlayers` groups by `nameKey`. If a NEW surface lists players,
|
||||
group by `nameKey` + display `normalizeName().display`.
|
||||
- **TWO intel renderers — don't confuse them:** the GRADE CARD (scan) uses
|
||||
`analyzeViaEngine1.buildIntelFields(features)`; the PLAYER PROFILE uses
|
||||
`playerIntelService.buildIntel(stats)`. The "+0%"/"—" bug was the PROFILE's
|
||||
defaults — fixed by `resolvePlayerStats` attaching real `usage` (AB/G) + `rest`
|
||||
and `buildIntel` reading them. The grade card already worked (the full feature
|
||||
merge carries ab_per_game/rest_days; `FEATURE_NAMES` is meta bookkeeping only,
|
||||
NOT a whitelist that filters the vector).
|
||||
|
||||
## Active Skills
|
||||
- vyndr-voice (all user-facing output)
|
||||
- prop-analysis (grading methodology)
|
||||
|
||||
Reference in New Issue
Block a user