'use strict'; /** * Ranking instrument — challenger vs incumbent (2026-08-01). * * These lock the reason the challenger exists: measured on n=200 settled MLB * rows, corr(p_win, outcome) = +0.26 while corr(edge, outcome) = -0.010 under * the incumbent ruler and -0.022 under the consensus ruler. A quantity that * does not predict must not rank, gate or decide. */ const { rankGrades, rankByForecast, rankingDelta, gradeKey, takeablePWin, } = require('../../src/utils/gradeRanking'); const g = (player, grade, p_win, odds = -110, extra = {}) => ({ player, stat_type: 'hits', line: 1.5, direction: 'over', grade, p_win, book_odds: odds, ...extra, }); describe('rankByForecast — the challenger', () => { it('contains NO edge term: edge cannot move the order at all', () => { const a = [g('A', 'B', 0.62, -110, { edge: -99 }), g('B', 'B', 0.55, -110, { edge: +99 })]; const b = [g('A', 'B', 0.62, -110, { edge: +99 }), g('B', 'B', 0.55, -110, { edge: -99 })]; expect(rankByForecast(a).map((x) => x.player)).toEqual(['A', 'B']); expect(rankByForecast(b).map((x) => x.player)).toEqual(['A', 'B']); }); it('leads with p_win, not the grade letter', () => { // The letter measured r ~ 0.005 and is INVERTED; p_win measures +0.26. // A high-p_win C must outrank a low-p_win A. const out = rankByForecast([g('lowPwinA', 'A', 0.51), g('highPwinC', 'C', 0.74)]); expect(out[0].player).toBe('highPwinC'); }); it('keeps the takeable gate — raw p_win would crown chalk', () => { const chalk = g('chalk', 'A', 0.93, -300); // untakeable price const real = g('real', 'B', 0.61, -115); expect(takeablePWin(chalk)).toBeNull(); expect(rankByForecast([chalk, real])[0].player).toBe('real'); }); it('sorts a missing p_win LAST, never first (Number(null) === 0 guard)', () => { const out = rankByForecast([g('none', 'A', null), g('has', 'C', 0.58)]); expect(out.map((x) => x.player)).toEqual(['has', 'none']); }); it('is stable for genuinely tied rows', () => { const rows = [g('first', 'B', 0.6), g('second', 'B', 0.6)]; expect(rankByForecast(rows).map((x) => x.player)).toEqual(['first', 'second']); }); it('drops ungraded rows, like the incumbent', () => { expect(rankByForecast([g('x', null, 0.9), g('y', 'B', 0.5)]).map((r) => r.player)).toEqual(['y']); }); }); describe('rankGrades — the incumbent is UNTOUCHED (live ordering byte-identical)', () => { it('still leads with the grade letter and still consults edge', () => { const out = rankGrades([g('lowPwinA', 'A', 0.51), g('highPwinC', 'C', 0.74)]); expect(out[0].player).toBe('lowPwinA'); // grade-first, unchanged }); it('edge still breaks a true tie in the incumbent', () => { const out = rankGrades([ g('lowEdge', 'B', 0.6, -110, { edge: 1 }), g('highEdge', 'B', 0.6, -110, { edge: 9 }), ]); expect(out[0].player).toBe('highEdge'); }); }); describe('rankingDelta — the challenger-first measurement', () => { it('reports how far the board moves and whether the top read changes', () => { const rows = [g('A', 'A', 0.52), g('B', 'C', 0.77), g('C', 'B', 0.64)]; const d = rankingDelta(rows, 3); expect(d.n).toBe(3); expect(d.incumbent_top).toBe(gradeKey(rows[0])); // A-grade leads incumbent expect(d.challenger_top).toBe(gradeKey(rows[1])); // highest p_win leads challenger expect(d.top_changed).toBe(true); expect(d.moved).toBeGreaterThan(0); }); it('reports zero movement when both instruments agree', () => { const rows = [g('A', 'A', 0.80), g('B', 'B', 0.60), g('C', 'C', 0.40)]; const d = rankingDelta(rows, 3); expect(d.moved).toBe(0); expect(d.top_changed).toBe(false); expect(d.top_n_overlap_pct).toBe(100); }); it('changes nothing about the inputs (pure)', () => { const rows = [g('A', 'A', 0.52), g('B', 'C', 0.77)]; const snapshot = JSON.stringify(rows); rankingDelta(rows); expect(JSON.stringify(rows)).toBe(snapshot); }); });