Session 32: Grades pipeline + NFL/NHL wiring + rate limiting + audit cleanup (1718 tests)
- gradeSlateService writes grades:{sport} cache (closes content pipeline →
dataLevel full); fire-and-forget from oddsService.recordDownstream, gated
by shouldGradeSlate (off in test, GRADE_SLATE_ON_FETCH override)
- NFL/NHL wired: oddsService SPORT_KEYS/SPORT_MARKETS (correct the-odds-api
keys americanfootball_nfl/icehockey_nhl), proplineAdapter MARKETS, NHL
MARKET_MAP keys to avoid silent-zero
- rate limiting mounted on 8 public cached routers (odds/parlay 30/min,
rest 60/min)
- jsonlLogger writes to temp under test (no more dirtied tracked artifact);
5MB pipeline test given 20s timeout
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+86
-2
@@ -1,10 +1,94 @@
|
||||
# VYNDR — Build State
|
||||
|
||||
## Last Updated
|
||||
2026-06-14
|
||||
2026-06-15
|
||||
|
||||
## Current Phase
|
||||
AUDIT v31.0 — Full code audit + security review + cleanup (Session 31)
|
||||
SHIP BUILD v32.0 — Close audit gaps: grades pipeline + NFL/NHL wiring +
|
||||
rate limiting + test-artifact cleanup (Session 32)
|
||||
|
||||
## Session 32 (2026-06-15) — SHIPPED
|
||||
|
||||
Surgical close of the four functional gaps Session 31's audit documented.
|
||||
No new feature scope (design session runs in parallel). Backend
|
||||
1695 → **1718 tests** (+23), 140 suites, zero regressions. Web build clean.
|
||||
Tracked `data/` tree stays clean after a full test run (artifact fixed).
|
||||
|
||||
### PHASE 1 — Grades cache writer (closes the content pipeline)
|
||||
- Traced: `analyzeViaEngine1` (computeFeatures → engine1 → toLegacyShape)
|
||||
produces the legacy grade shape; `contentTemplateService` reads
|
||||
`grades:{sport}:{utc}` then `grades:{sport}`, accepting an array or
|
||||
`{grades:[...]}`. The legacy shape already matches `normalizeGrade` — no
|
||||
remap needed. Session 31 confirmed NO writer existed.
|
||||
- `gradeSlateService.gradeAndCacheSlate(sport, props, opts)` — dedupes to
|
||||
unique player+stat+line (cap 25, concurrency 5), grades BOTH sides
|
||||
(engine1 is direction-aware) keeping the higher-confidence verdict, sorts
|
||||
by confidence desc, writes `grades:{sport}` = `{grades, updated_at,
|
||||
source}` TTL 2h. Injectable grader/cacheSet/now → fully unit-tested.
|
||||
- Wired fire-and-forget into `oddsService.recordDownstream` (fires on a
|
||||
fresh odds fetch only, never blocks the odds response). Gated by
|
||||
`shouldGradeSlate()`: default ON, OFF under `NODE_ENV==='test'` (its
|
||||
feature-compute fan-out otherwise pollutes the odds integration tests'
|
||||
axios call-count assertions via floating promises), `GRADE_SLATE_ON_FETCH`
|
||||
override (`0` = operator kill-switch). 12 tests. Self-eval 9/10.
|
||||
|
||||
### PHASE 2 — NFL + NHL sport-key wiring
|
||||
- **Corrected the spec's sport keys.** Spec said `football_nfl`/`hockey_nhl`
|
||||
for `oddsService.SPORT_KEYS`, but that file maps to the-odds-api, whose
|
||||
keys are `americanfootball_nfl` / `icehockey_nhl` (verified against the
|
||||
the-odds-api sports list). The spec's values would have silently 404'd —
|
||||
the exact silent-failure class this session fights. (`football_nfl`/
|
||||
`hockey_nhl` ARE correct for PropLine in `proplineAdapter`, unchanged.)
|
||||
- Added nfl/nhl to `SPORT_KEYS` + `SPORT_MARKETS` (NFL_MARKETS/NHL_MARKETS).
|
||||
Filled `proplineAdapter.MARKETS.nfl/nhl`. Added NHL keys
|
||||
(`player_shots_on_goal`, `goalie_saves`) to `MARKET_MAP` so NHL props
|
||||
don't normalize to zero in-season (same fix family as Session 31's NFL
|
||||
MARKET_MAP gap). 10 tests, incl. end-to-end MARKET_MAP normalization +
|
||||
off-season empty handling. Self-eval 9/10.
|
||||
|
||||
### PHASE 3 — Rate limiting on public routes
|
||||
- Mounted the existing `middleware/rateLimit` (`createRateLimit`, in-memory
|
||||
per-IP, independent bucket per call site) via `router.use` on every public
|
||||
cached router: odds + parlay = 30/min; schedule/gamelines/streaks/hotlist/
|
||||
content/lines/books = 60/min. `/api/analyze` keeps its own 10/min.
|
||||
- 3 route-level tests (429 after limit, tighter odds limit, independent
|
||||
per-router buckets) complementing the existing middleware-level tests.
|
||||
Self-eval 9/10.
|
||||
|
||||
### PHASE 4 — Test artifact + cleanup
|
||||
- `jsonlLogger` ROOT now resolves to `os.tmpdir()/vyndr-training-test` under
|
||||
`NODE_ENV==='test'` (override `TRAINING_DATA_DIR`), so tests no longer
|
||||
append to the tracked `data/training/resolutions-YYYY-MM.jsonl`. Reverted
|
||||
the dirtied artifact; verified the tree stays clean after a full run.
|
||||
- Gave the 5MB-payload pipeline regression test a 20s timeout — it's
|
||||
CPU-bound and flaked on Jest's 5s default under the heavier full-suite
|
||||
load from the +23 new tests (Jest's own error message recommends this).
|
||||
|
||||
### Files created
|
||||
- `src/services/gradeSlateService.js`
|
||||
- `tests/unit/gradeSlateService.test.js`,
|
||||
`tests/unit/nflNhlWiring.test.js`,
|
||||
`tests/integration/publicRouteRateLimit.test.js`
|
||||
|
||||
### Files modified
|
||||
- `src/services/oddsService.js` (SPORT_KEYS/SPORT_MARKETS nfl+nhl,
|
||||
recordDownstream grades trigger + shouldGradeSlate gate)
|
||||
- `src/utils/oddsNormalizer.js` (NHL MARKET_MAP keys)
|
||||
- `src/services/adapters/proplineAdapter.js` (MARKETS.nfl/nhl)
|
||||
- `src/services/training/jsonlLogger.js` (test-env temp path)
|
||||
- 8 public route files (rate-limit mount): odds, parlay, schedule,
|
||||
gameLines, streaks, hotlist, content, lineMovement, bookComparison
|
||||
- `tests/integration/pipeline.test.js` (5MB test timeout)
|
||||
- `CLAUDE.md`
|
||||
|
||||
### Deliberately deferred (per spec — await design session)
|
||||
- CLV tracking + prop resolution (need PropLine Hobby-tier endpoint access
|
||||
confirmed). Design implementation. Player watchlists + push.
|
||||
- The grades auto-grade trigger is ON by default but its per-prop
|
||||
feature-compute cost is unmeasured in prod; `GRADE_SLATE_ON_FETCH=0` is
|
||||
the kill-switch. Worth profiling once real PropLine slates flow.
|
||||
|
||||
---
|
||||
|
||||
## Session 31 (2026-06-14) — SHIPPED (audit)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user