/** * /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([]); }); });