Session 41: P0 audit fixes — MLB stat_types, broken routes, tier mismatch, self-hosted fonts (1940 tests)

- Backend: whitelist MLB stat_types in analyze.js + scan.js gates (mirrors
  python validation.py); fixes MLB scans 400ing.
- Routes: /settings -> /profile, /report -> /blog redirect pages.
- Profile: read tier from useAuth().tier (nav's source) to kill the
  Free-vs-DESK mismatch.
- Fonts: self-host Inter/JetBrains Mono/IBM Plex Mono via next/font, drop the
  503ing fonts.googleapis.com <link>; rewire literal font-family refs to vars.
- Kept /settings/security (real MFA page) intact — NOT clobbered to a redirect.
- +33 tests (1907 -> 1940), 149 suites; web build clean (exit 0).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kev
2026-06-17 21:55:40 -04:00
parent e453c24d2c
commit 32069863dc
17 changed files with 318 additions and 41 deletions
+28
View File
@@ -293,6 +293,34 @@ The 7-session design conversion (3339) is done and parity-verified against §
it falls through to live adapters on cache miss and flaked at Jest's 5s default
under full-suite load (same family as the S32 pipeline test).
## P0 Audit Fixes (Session 41 — non-obvious)
- **THREE stat_type whitelists must stay in sync.** A prop's `stat_type` is
gated in `src/routes/analyze.js` (`/prop` + `/batch`), `src/routes/scan.js`
(parlay legs), AND `src/services/python/utils/validation.py`. Adding a sport's
stats to one without the others silently 400s. The S41 MLB bug was exactly
this: Python had the MLB set; both Node gates didn't. `mlbGrader.js` is DEAD
CODE (required nowhere) — the live MLB grade path is the generic engine1
feature pipeline, which keys off the Python validator's exact stat names
(`rbi`/`runs`/`innings_pitched`, NOT `rbis`/`runs_scored`/`outs_recorded`).
- **`tests/integration/analyze.test.js` sits exactly at the 10-req/min IP rate
limit** (`createRateLimit max:10`, no reset hook). Adding any HTTP test there
429s the later cases. Put new analyze-route HTTP tests in a SEPARATE file
(jest isolates module state per file → fresh limiter): see
`tests/integration/analyzeMlbStats.test.js`.
- **Fonts are self-hosted via `next/font/google`** (layout.tsx): Inter→
`--font-sans`, JetBrains_Mono→`--font-mono`, IBM_Plex_Mono→`--font-ibm`, all
set on `<html className>`. globals.css `:root` maps `--sans`/`--mono`/
`--ibm-mono` onto them. CRITICAL: next/font OBFUSCATES family names, so literal
`'JetBrains Mono'`/`'IBM Plex Mono'` in CSS or inline `fontFamily` no longer
resolve — always reference the variable. The old `fonts.googleapis.com` CDN
`<link>` is GONE (it 503'd in prod). ShareCard canvas still uses literal names
(canvas can't read CSS vars) — knowingly left.
- **Redirect routes** use server-component `redirect()` from `next/navigation`
(`/settings`→`/profile`, `/report`→`/blog`). `/settings/security` is a REAL
MFA enrollment page — do NOT clobber it into a redirect.
- **Profile tier** reads from `useAuth().tier` (the nav's source), not the
`/api/user/profile` fetch, so the two can't disagree.
## Active Skills
- vyndr-voice (all user-facing output)
- prop-analysis (grading methodology)