'use strict'; /** * B2 — stop persisting refusals nothing reads. * * `missed_window` is a fact about our cron cadence, not the market: the same * prop generates a fresh refusal every ~20 minutes for the rest of the night, * per book, per side. 4.2M rows, ~465k/day, read by nothing since B1. * * The cut must be NARROW — priced captures and `one_sided_price` are read, and * the capture-rate alarm must keep seeing every refusal even though we no longer * store them. */ const cap = require('../../src/services/closingCapture'); const capture = (calls) => ({ getClient: () => ({ from() { return { insert: async (chunk) => { calls.push(...chunk); return { error: null }; } }; }, }), }); const priced = (p = {}) => ({ sport: 'mlb', player_key: 'a', stat: 'hits', side: 'over', game_date: '2026-08-12', book: 'draftkings', line: 0.5, over_odds: -120, under_odds: 100, missed_reason: null, ...p, }); const refusal = (reason, p = {}) => ({ sport: 'mlb', player_key: 'a', stat: 'hits', side: 'over', game_date: '2026-08-12', book: 'draftkings', line: null, over_odds: null, under_odds: null, missed_reason: reason, ...p, }); describe('what persists and what does not', () => { it('a PRICED capture persists', async () => { const calls = []; const out = await cap.persist([priced()], capture(calls)); expect(out.written).toBe(1); expect(calls).toHaveLength(1); expect(out.skipped_unread).toBe(0); }); it('a ONE_SIDED_PRICE refusal persists — it is a real liquidity signal', async () => { const calls = []; const out = await cap.persist([refusal('one_sided_price')], capture(calls)); expect(out.written).toBe(1); expect(calls[0].missed_reason).toBe('one_sided_price'); }); it('a MISSED_WINDOW refusal is NOT persisted', async () => { const calls = []; const out = await cap.persist([refusal('missed_window')], capture(calls)); expect(out.written).toBe(0); expect(out.skipped_unread).toBe(1); expect(calls).toHaveLength(0); }); it('a mixed pass writes exactly the readable rows', async () => { const calls = []; const rows = [ priced(), priced({ player_key: 'b' }), refusal('one_sided_price', { player_key: 'c' }), refusal('missed_window', { player_key: 'd' }), refusal('missed_window', { player_key: 'e' }), ]; const out = await cap.persist(rows, capture(calls)); expect(out.attempted).toBe(5); expect(out.written).toBe(3); expect(out.skipped_unread).toBe(2); expect(calls.map((r) => r.player_key).sort()).toEqual(['a', 'b', 'c']); }); it('OTHER refusals still persist — each names a pipeline fault worth seeing', async () => { for (const reason of ['unbound_game_time', 'doubleheader_ambiguous', 'fetch_failed']) { const calls = []; const out = await cap.persist([refusal(reason)], capture(calls)); expect(out.written).toBe(1); } }); it('a missed_window row that somehow CARRIES a price is kept — do not over-cut', async () => { const calls = []; const out = await cap.persist([refusal('missed_window', { over_odds: -110, under_odds: -110 })], capture(calls)); expect(out.written).toBe(1); }); it('the flag restores the old behaviour', async () => { const calls = []; const out = await cap.persist([refusal('missed_window')], { ...capture(calls), persistMissedWindow: true }); expect(out.written).toBe(1); }); it('a pass that is ALL unread refusals never opens a client', async () => { let opened = false; const out = await cap.persist([refusal('missed_window'), refusal('missed_window')], { getClient: () => { opened = true; return null; }, }); expect(opened).toBe(false); expect(out.skipped_unread).toBe(2); expect(out.written).toBe(0); }); }); describe('THE OPS SIGNAL SURVIVES — the alarm never read the stored rows', () => { it('captureRateAlarm is pure: it takes counts, not a database', () => { const late = cap.captureRateAlarm({ eligible: 100, captured: 10 }); expect(late.alarm).toBe(true); expect(late.reason).toMatch(/unrecoverable/); const fine = cap.captureRateAlarm({ eligible: 100, captured: 90 }); expect(fine.alarm).toBe(false); }); it('still fires on a late pass whose refusals are now dropped', async () => { // 100 props, 10 priced, 90 post-first-pitch: nothing but the 10 persists, // and the alarm must still see 10/100. const rows = [ ...Array.from({ length: 10 }, (_, i) => priced({ player_key: `p${i}` })), ...Array.from({ length: 90 }, (_, i) => refusal('missed_window', { player_key: `m${i}` })), ]; const calls = []; const out = await cap.persist(rows, capture(calls)); expect(out.written).toBe(10); expect(out.skipped_unread).toBe(90); // The caller computes the alarm from the FULL array, not from what persisted. const captured = rows.filter((r) => !r.missed_reason).length; const al = cap.captureRateAlarm({ eligible: rows.length, captured }); expect(al.alarm).toBe(true); expect(al.rate).toBeCloseTo(0.10, 5); }); it('the caller still passes the FULL array to the alarm', () => { const src = require('fs').readFileSync( require('path').join(__dirname, '..', '..', 'src/services/intradayRefreshService.js'), 'utf8'); expect(src).toMatch(/captureRateAlarm\(\{ eligible: rows\.length, captured \}\)/); expect(src).toMatch(/const captured = rows\.filter\(\(r\) => !r\.missed_reason\)\.length/); }); }); describe('buildCaptureRows is UNCHANGED — the alarm depends on it', () => { it('still emits missed_window rows in memory', () => { const started = { player: 'A', stat_type: 'hits', game_time: '2026-08-12T00:00:00Z', book: 'dk' }; const rows = cap.buildCaptureRows('mlb', [started], { now: new Date('2026-08-12T02:00:00Z') }); expect(rows).toHaveLength(2); // both sides expect(rows.every((r) => r.missed_reason === 'missed_window')).toBe(true); }); it('isUnreadRefusal identifies exactly those rows', () => { expect(cap.isUnreadRefusal(refusal('missed_window'))).toBe(true); expect(cap.isUnreadRefusal(refusal('one_sided_price'))).toBe(false); expect(cap.isUnreadRefusal(priced())).toBe(false); expect(cap.isUnreadRefusal(null)).toBe(false); }); });