Session 50: Complete Parlay Lab (2215 tests)
Correlation-aware combined parlay grading — the Desk-tier differentiator.
- Correlation model (parlayService.js, added to S28 funcs): correlationScore
(game-aware 0.7/0.4/0.2/0.0), combinedGrade (avg penalized by avgCorr*0.5),
estimatedPayout (fair-odds product * (1-avgCorr) discount), correlationWarning,
gradeParlay.
- POST /api/parlay/grade (public, 2-6 legs) -> {combined,correlation,payout,legs}.
Fixed the Next proxy (was forwarding to /api/scan/parlay).
- ParlayContext: legs gained team/game/archetype; tier-aware maxLegs; auto-grades
the slip (debounced) when legs>=2 -> live combined/correlation/payout; hasLeg/
legKey/atCap.
- "+" button on every graded prop: StatStrip onAddLeg/isLegActive, wired by
vyndr/GameCard via useParlay (builds leg w/ team + game). GradeResultCard feeds
the same context from the scan page.
- ParlayPanel (replaces legacy ParlayTray): bottom slide-up w/ legs, combined
grade, correlation warning, est payout, CLEAR ALL + floating leg-count badge.
Tier-gated: free 2 legs (payout blurred -> Desk upsell), Analyst 4, Desk 6.
Backend 2185 -> 2215 tests (+30), 187 suites. Web build clean (exit 0).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -533,6 +533,29 @@ snapshot, locked to the line, and read from cache.
|
||||
- **Name micro-fix:** `playerName.js` `collapseInitials` merges "J C" → "JC"
|
||||
(display + key) so space-separated initials dedupe.
|
||||
|
||||
## Parlay Lab (Session 50 — non-obvious)
|
||||
- **Correlation model** lives in `src/services/parlayService.js` (ADDED to the
|
||||
S28 categorical matrix — both coexist). `correlationScore(l1,l2)` is numeric +
|
||||
GAME-aware (0.7 same-player/game, 0.4 same-team/game, 0.2 same-game, 0.0 diff-
|
||||
game). `combinedGrade` penalizes the leg-grade avg by `avgCorrelation*0.5`;
|
||||
`estimatedPayout` = Πfair-odds × (1−avgCorr) discount. `gradeParlay` is the
|
||||
bundle the route returns. Leg shape: `{ player, team, game, stat, grade }`.
|
||||
- **POST /api/parlay/grade** (`src/routes/parlay.js`) — public, 2–6 legs, returns
|
||||
`{ combined, correlation, payout, legs }`. The Next proxy was pointed at the
|
||||
WRONG upstream (`/api/scan/parlay`); it now forwards to `/api/parlay/grade`.
|
||||
- **ParlayContext auto-grades** the slip (debounced 250ms) via that endpoint
|
||||
whenever legs change (≥2). `combined`/`correlation`/`payout` are live on the
|
||||
context — don't call the endpoint from components, read the context.
|
||||
- **Leg cap is tier-aware via the context.** `maxLegs` defaults 6; `ParlayPanel`
|
||||
sets it from `useAuth().tier` (free 2 / analyst 4 / desk 6). `addLeg` reads a
|
||||
ref so it stays a stable callback. The "+" buttons no-op at the cap.
|
||||
- **"+" wiring:** `StatStrip` takes `onAddLeg`/`isLegActive`; `vyndr/GameCard`
|
||||
provides them via `useParlay` (it owns the game id + team). `legKey` =
|
||||
`player|stat|line|direction` is the dedupe key (exported from the context).
|
||||
- **ParlayPanel** (mounted in layout, REPLACED `ParlayTray` which called a
|
||||
then-missing `/grade` endpoint). Floating badge bottom-right when closed; free
|
||||
tier blurs the payout with a `window.__goPaywall` upsell.
|
||||
|
||||
## Active Skills
|
||||
- vyndr-voice (all user-facing output)
|
||||
- prop-analysis (grading methodology)
|
||||
|
||||
Reference in New Issue
Block a user