/** * BUILD 1 CORRECTED — itemized grades are PAID (live AND settled). * The property that matters: the one-day-behind exploit must be DEAD. */ const g = require('../../src/utils/snapshotGating'); const settled = { player: 'Settled Sam', stat_type: 'points', line: 12.5, book_odds: -110, fair_odds: -104, season_avg: 14, grade: 'A', confidence: 75, reasoning: { summary: 'real why' }, kill_conditions_triggered: [{ code: 'X', reason: 'r' }], projection: 15, edge_pct: 20, outcome: { result: 'hit', actual: 14 } }; const live = { player: 'Live Larry', stat_type: 'assists', line: 5.5, book_odds: -120, fair_odds: -112, season_avg: 6, archetype: { primary: { name: 'CONDUCTOR' } }, grade: 'A', confidence: 75, confidence_basis: 'grade_band', reasoning: { summary: 'secret why' }, kill_conditions_triggered: [{ code: 'Y', reason: 'secret' }], projection: 7.1, edge_pct: 29, matchup_grade: 'B', form: 'hot', alt_lines: [{}], kelly: { units: 1 } }; const J = ['grade', 'confidence', 'confidence_basis', 'reasoning', 'kill_conditions_triggered', 'projection', 'edge_pct', 'matchup_grade', 'form', 'alt_lines', 'kelly']; describe('THE EXPLOIT IS DEAD — settled itemized grades are PAID too', () => { const out = g.gateItemizedGrades([settled, live], 'free'); test('a SETTLED grade is locked for free — no one-day-delayed feed', () => { for (const f of J) expect(out[0][f]).toBeUndefined(); expect(out[0].locked).toBe(true); }); test('a LIVE grade is locked for free', () => { for (const f of J) expect(out[1][f]).toBeUndefined(); expect(out[1].locked).toBe(true); }); test('NEITHER serialized row carries a trace of judgment', () => { const json = JSON.stringify(out); expect(json).not.toMatch(/real why|secret why|grade_band|hot/); }); test('free-side DATA survives on both, so the board still reads as real', () => { expect(out[0].player).toBe('Settled Sam'); expect(out[1].fair_odds).toBe(-112); // the fair leg is never the paywall expect(out[1].season_avg).toBe(6); expect(out[1].archetype).toBeTruthy(); expect(out[0].outcome).toEqual({ result: 'hit', actual: 14 }); // the RESULT is a fact, not judgment }); }); describe('the free SAMPLE is a taste, not the archive', () => { const pool = Array.from({ length: 40 }, (_, i) => ({ player: `P${i}`, grade: 'B', outcome: { result: 'hit' } })); test('capped at 3 no matter how large the settled pool', () => { expect(g.FREE_SAMPLE_CAP).toBe(3); expect(g.freeSample(pool, '2026-07-31')).toHaveLength(3); expect(g.freeSample(pool, '2026-07-31').length).toBeLessThan(pool.length); }); test('rotates by day but is STABLE within a day', () => { const a = g.freeSample(pool, '2026-07-30').map((x) => x.player); const b = g.freeSample(pool, '2026-07-31').map((x) => x.player); expect(a).toEqual(g.freeSample(pool, '2026-07-30').map((x) => x.player)); // stable expect(a).not.toEqual(b); // rotates }); test('only RESOLVED calls can be sampled — never a live read', () => { expect(g.freeSample([live, settled], 'd')).toEqual([settled]); expect(g.freeSample([live], 'd')).toEqual([]); }); }); describe('entitled tiers get everything, untouched', () => { test('analyst and desk get the array by reference — live AND archive', () => { const rows = [settled, live]; expect(g.gateItemizedGrades(rows, 'analyst')).toBe(rows); expect(g.gateItemizedGrades(rows, 'desk')).toBe(rows); expect(g.entitledToItemizedGrades('free')).toBe(false); expect(g.entitledToItemizedGrades(undefined)).toBe(false); }); }); describe('the tease shows shape, never which prop', () => { test('aggregate count + tiers, and no gated row carries a grade', () => { const s = g.liveLockedSummary([settled, live, { grade: 'B' }]); expect(s.count).toBe(2); // settled excluded from LIVE count expect(s.tiers).toEqual({ A: 1, B: 1 }); for (const row of g.gateItemizedGrades([live, { grade: 'B' }], 'free')) { expect(row.grade).toBeUndefined(); } }); });