Files
vyndr/tests/unit/topGradedSelector.test.js
T
builtbykev 72a14dc4cd Build /api/props/top-graded server selector: rank with p_win, serve without it
New READ endpoint. No grade, ledger row, lock_line, or scoring write. Push
scoring untouched.

REVIEW ZERO CORRECTED THE PREMISE: the handler NEVER EXISTED in any commit
(searched git rev-list --all for a /top-graded definition in src/ — zero hits).
Not "removed" — the three axios callers (cheatsheetGenerator, gradeOfTheDay,
widget) and the Next proxy were written against a phantom endpoint, so those
three content generators have silently received [] for their entire life.
Contract recovered from the four consumers, not guessed: {props:[...]},
?sport=UPPERCASE (absent = all sports, which gradeOfTheDay relies on) + ?limit,
rows carrying player/stat/line/direction/sport/grade/confidence? plus the
player_name/stat_type aliases and game_id.

POPULATED-PATH RISK FOUND: the board's populated branch had never run in prod,
and dashboard/page.tsx:463 calls g.stat.replace(/_/g,' ') UNGUARDED (g.player
also feeds the row key, /scan URL and heading; sport must be UPPERCASE for
SportPill). toRow requires non-empty string player+stat and a finite line,
uppercases sport, and DROPS unrenderable rows — a shorter board beats a broken
one.

THE LEAK BOUNDARY (why this is server-side): the browser cannot rank on p_win
for all tiers because stripModelPrice deliberately withholds it from unentitled
tiers. Order of operations is
  read cache -> RANK with p_win (every tier) -> map rows incl. model fields
    -> stripModelPrice(rows, tier) -> serialize
so a free caller receives the paid RANKING without the paid VALUES. Tier comes
from resolveTierFromRequest, which FAILS CLOSED to 'free'. Cache-Control is
private under a bearer token, public otherwise (the /api/snapshot precedent).

ONE SHARED DEFINITION, no drift: new src/utils/gradeRanking.js
(takeablePWin/descNullsLast/rankGrades). heroPropService now imports
takeablePWin instead of its inline copy (behaviour unchanged — it was that
logic verbatim); the selector imports rankGrades; web/src/lib/slateAdapter
keeps its mirror (the browser cannot import src/, S25) and a test cross-checks
the two on identical fixtures (playerName.js precedent). Board is grade-first
("top GRADES"), hero is p_win-first ("top read") — they differ BY DESIGN and
agree within the leading tier.

HONEST LIMIT: the Next proxy (cachedBackendJson) sends no Authorization header
and caches under a shared key, so via the dashboard every viewer gets the
free-tier payload — correct order, no paid values. That is the SAFE behaviour;
forwarding auth into a shared cache is exactly how a paid payload leaks to
anonymous viewers. Per-tier delivery through the proxy needs a tier-keyed cache
and is not done here.

Verified on real prod snapshot data (anonymous path): MLB 8 props, WNBA 10,
0 paid-field leaks, render-contract safe on every row, sport uppercase.

Floor: 311 suites / 3882 tests green (18 new — leak test uses POPULATED p_win,
not today's nulls: entitled gets p_win and it drove the order, unentitled gets
a byte-identical order with all five MODEL_FIELDS absent and no trace in
JSON.stringify, while book/fair market facts survive). Web build exit 0.
Dashboard visual is auth-gated -> tagged for the Chrome audit, not faked.

Held: edge_pct rescale/retirement (Order B); board columns/contract unchanged;
tier-keyed proxy caching.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
2026-07-29 22:05:30 -04:00

222 lines
11 KiB
JavaScript

/**
* /api/props/top-graded server selector (specs/top-graded-selector.md).
*
* THE TEST THAT MATTERS is the LEAK BOUNDARY: rank WITH p_win server-side, serve
* WITHOUT it to unentitled tiers. Proven on POPULATED p_win (fixtures below carry
* real values) — not on today's stripped nulls, which would prove nothing.
*/
const request = require('supertest');
const svc = require('../../src/services/topGradedService');
const { rankGrades, takeablePWin } = require('../../src/utils/gradeRanking');
const webAdapter = require('../../web/src/lib/slateAdapter');
const { MODEL_FIELDS } = require('../../src/utils/snapshotGating');
// POPULATED p_win + takeable prices. `chalk` is untakeable (-300) with the HIGHEST
// p_win, so it must NOT top the board.
const GRADES = [
{ player: 'chalk', stat_type: 'hits', line: 0.5, direction: 'over', grade: 'B', confidence: 57, p_win: 0.95, book_odds: -300, ev_pct: 9, model_odds: -1900, value: true, takeable: false, fair_odds: -280 },
{ player: 'mid', stat_type: 'points', line: 8.5, direction: 'over', grade: 'B', confidence: 57, p_win: 0.61, book_odds: -120, ev_pct: 3, model_odds: -156, value: true, takeable: true, fair_odds: -115 },
{ player: 'best', stat_type: 'points', line: 6.5, direction: 'over', grade: 'B', confidence: 57, p_win: 0.78, book_odds: -110, ev_pct: 5, model_odds: -354, value: true, takeable: true, fair_odds: -108 },
{ player: 'nosignal', stat_type: 'assists',line: 3.5, direction: 'over', grade: 'B', confidence: 57 },
{ player: 'topgrade', stat_type: 'rebounds',line: 4.5, direction: 'under', grade: 'A', confidence: 75, p_win: 0.52, book_odds: -105, fair_odds: -102 },
];
const cacheGet = (key) => Promise.resolve(
key === 'snapshot:wnba:latest' ? { grades: GRADES, updated_at: 'T' } : null,
);
const names = (props) => props.map((p) => p.player);
describe('topGradedService — rank order', () => {
test('grade tier dominates; takeable p_win orders within a tier; nulls LAST', async () => {
const { props } = await svc.getTopGraded({ sport: 'WNBA', tier: 'desk', cacheGet });
// A first (grade), then B rows by takeable p_win desc, missing signal last.
expect(names(props)).toEqual(['topgrade', 'best', 'mid', 'chalk', 'nosignal']);
});
test('UNTAKEABLE chalk does not top the board despite the highest p_win', async () => {
const { props } = await svc.getTopGraded({ sport: 'WNBA', tier: 'desk', cacheGet });
const b = props.filter((p) => p.grade === 'B').map((p) => p.player);
expect(b[0]).toBe('best'); // 0.78 takeable
expect(b.indexOf('chalk')).toBeGreaterThan(b.indexOf('mid')); // 0.95 but -300
});
test('a missing-signal row is PRESENT, just last', async () => {
const { props } = await svc.getTopGraded({ sport: 'WNBA', tier: 'desk', cacheGet });
expect(names(props)).toContain('nosignal');
expect(names(props)[props.length - 1]).toBe('nosignal');
});
});
describe('topGradedService — THE LEAK BOUNDARY (populated p_win)', () => {
test('entitled tier: p_win PRESENT and it drove the ranking', async () => {
const { props } = await svc.getTopGraded({ sport: 'WNBA', tier: 'desk', cacheGet });
const best = props.find((p) => p.player === 'best');
expect(best.p_win).toBe(0.78);
expect(best.ev_pct).toBe(5);
expect(best.model_odds).toBe(-354);
});
test('UNENTITLED tier: identical ORDER, paid signal ABSENT', async () => {
const entitled = await svc.getTopGraded({ sport: 'WNBA', tier: 'desk', cacheGet });
const free = await svc.getTopGraded({ sport: 'WNBA', tier: 'free', cacheGet });
// the ORDER is byte-identical — the free caller gets the paid RANKING
expect(names(free.props)).toEqual(names(entitled.props));
// ...and none of the paid VALUES
for (const row of free.props) {
for (const f of MODEL_FIELDS) {
expect(Object.prototype.hasOwnProperty.call(row, f)).toBe(false);
}
}
// serialized form carries no trace either
const json = JSON.stringify(free.props);
expect(json).not.toMatch(/p_win|ev_pct|model_odds/);
// market facts SURVIVE — the fair leg is never the paywall
expect(free.props.find((p) => p.player === 'best').fair_odds).toBe(-108);
expect(free.props.find((p) => p.player === 'best').book_odds).toBe(-110);
});
test('anonymous (no tier given) defaults to the LEAST entitled — fails closed', async () => {
const { props } = await svc.getTopGraded({ sport: 'WNBA', cacheGet });
for (const row of props) {
for (const f of MODEL_FIELDS) expect(row[f]).toBeUndefined();
}
});
});
describe('topGradedService — contract + honest empty', () => {
test('emits the populated-render contract (unguarded g.stat.replace must not crash)', async () => {
const { props } = await svc.getTopGraded({ sport: 'WNBA', tier: 'free', cacheGet });
for (const p of props) {
expect(typeof p.player).toBe('string');
expect(p.player.length).toBeGreaterThan(0);
expect(typeof p.stat).toBe('string');
expect(() => p.stat.replace(/_/g, ' ')).not.toThrow();
expect(p.sport).toBe('WNBA'); // UPPERCASE for SportPill
expect(['over', 'under']).toContain(p.direction);
expect(Number.isFinite(p.line)).toBe(true);
expect(p.grade).toBeTruthy();
expect(p.player_name).toBe(p.player); // the other callers' alias
expect(p.stat_type).toBe(p.stat);
}
});
test('drops unrenderable rows rather than crashing the board', async () => {
const bad = (key) => Promise.resolve(key === 'snapshot:mlb:latest' ? { grades: [
{ player: null, stat_type: 'hits', line: 0.5, grade: 'A' },
{ player: 'ok', stat_type: null, line: 0.5, grade: 'A' },
{ player: 'ok2', stat_type: 'hits', line: null, grade: 'A' },
{ player: 'good', stat_type: 'hits', line: 0.5, grade: 'A' },
] } : null);
const { props } = await svc.getTopGraded({ sport: 'MLB', tier: 'free', cacheGet: bad });
expect(names(props)).toEqual(['good']);
});
test('thin/empty slate → props: [] (never a 404, never filler)', async () => {
const empty = () => Promise.resolve(null);
const out = await svc.getTopGraded({ sport: 'MLB', tier: 'free', cacheGet: empty });
expect(out.props).toEqual([]);
});
test('refusals (insufficient_data) never reach the board', async () => {
const g = (key) => Promise.resolve(key === 'snapshot:mlb:latest' ? { grades: [
{ player: 'refused', stat_type: 'hits', line: 0.5, grade: 'C', insufficient_data: true },
{ player: 'real', stat_type: 'hits', line: 0.5, grade: 'C' },
] } : null);
const { props } = await svc.getTopGraded({ sport: 'MLB', tier: 'free', cacheGet: g });
expect(names(props)).toEqual(['real']);
});
test('limit is honored and capped; no sport = all sports merged', async () => {
const one = await svc.getTopGraded({ sport: 'WNBA', tier: 'free', limit: 2, cacheGet });
expect(one.props).toHaveLength(2);
const all = await svc.getTopGraded({ tier: 'free', cacheGet }); // gradeOfTheDay's call
expect(all.props.length).toBeGreaterThan(0);
expect(all.sport).toBeNull();
});
});
describe('ONE shared ranking definition — hero / server / client cannot drift', () => {
test('server rankGrades and the web mirror agree on identical fixtures', () => {
const fixture = GRADES.map((g) => ({ ...g, player: g.player, edge: g.p_win ? null : 1 }));
const server = rankGrades(fixture, 10).map((g) => g.player);
const client = webAdapter.selectTopGrades(fixture, 10).map((g) => g.player);
expect(server).toEqual(client);
});
test('the hero uses the SAME takeable-gated primitive (no inline copy)', () => {
const src = require('fs').readFileSync(
require('path').join(__dirname, '../../src/services/heroPropService.js'), 'utf8',
);
expect(src).toMatch(/require\('\.\.\/utils\/gradeRanking'\)/);
expect(src).toMatch(/takeablePWin\(g\)/);
// the former inline duplicate is gone
expect(src).not.toMatch(/const num = \(v\) =>/);
});
test('takeablePWin gates chalk and honors the locked-odds fallback', () => {
expect(takeablePWin({ p_win: 0.9, book_odds: -300 })).toBeNull();
expect(takeablePWin({ p_win: 0.9, book_odds: -120 })).toBe(0.9);
expect(takeablePWin({ p_win: 0.9, gradedAt: { odds: -115 } })).toBe(0.9);
expect(takeablePWin({ p_win: null, book_odds: -110 })).toBeNull();
expect(takeablePWin({ p_win: 0.9 })).toBeNull(); // no price → cannot gate
});
test('board (grade-first) and hero (p_win-first) may differ, but agree WITHIN a tier', async () => {
const { props } = await svc.getTopGraded({ sport: 'WNBA', tier: 'desk', cacheGet });
expect(props[0].player).toBe('topgrade'); // grade A leads the board
// the hero's rule = max takeable p_win regardless of tier → 'best'
const heroPick = GRADES.filter((g) => takeablePWin(g) != null)
.sort((a, b) => takeablePWin(b) - takeablePWin(a))[0];
expect(heroPick.player).toBe('best');
expect(props[0].player).not.toBe(heroPick.player); // INTENDED difference
// ...and within the leading tier they agree
const tier = props.filter((p) => p.grade === 'A');
expect(tier[0].player).toBe('topgrade');
});
});
describe('GET /api/props/top-graded — route', () => {
let app;
beforeAll(() => { app = require('../../src/app'); });
afterEach(() => { require('../../src/routes/props').__deps = undefined; });
test('200 with ranked props; anonymous caller gets NO paid fields + public cache', async () => {
require('../../src/routes/props').__internals.setDeps({
resolveTier: async () => 'free',
getTopGraded: (o) => svc.getTopGraded({ ...o, cacheGet }),
});
const res = await request(app).get('/api/props/top-graded?sport=WNBA');
expect(res.status).toBe(200);
expect(names(res.body.props)).toEqual(['topgrade', 'best', 'mid', 'chalk', 'nosignal']);
expect(res.headers['cache-control']).toMatch(/public/);
for (const row of res.body.props) {
for (const f of MODEL_FIELDS) expect(row[f]).toBeUndefined();
}
});
test('an entitled bearer caller gets p_win AND a private cache directive', async () => {
require('../../src/routes/props').__internals.setDeps({
resolveTier: async () => 'desk',
getTopGraded: (o) => svc.getTopGraded({ ...o, cacheGet }),
});
const res = await request(app)
.get('/api/props/top-graded?sport=WNBA')
.set('Authorization', 'Bearer x');
expect(res.status).toBe(200);
expect(res.body.props.find((p) => p.player === 'best').p_win).toBe(0.78);
expect(res.headers['cache-control']).toMatch(/private/);
});
test('a thrown selector still returns 200 + empty props, never a 404', async () => {
require('../../src/routes/props').__internals.setDeps({
resolveTier: async () => 'free',
getTopGraded: () => { throw new Error('boom'); },
});
const res = await request(app).get('/api/props/top-graded?sport=MLB');
expect(res.status).toBe(200);
expect(res.body.props).toEqual([]);
});
});