'use strict'; /** * PATH COVERAGE — acquisition success to the first real onGraded callback. * * Every branch in that corridor must explain itself. Twice now this programme * has read an absence as a conclusion: first "MLB exited at acquisition" (from * a missing retention record), then "all props rejected at admission" (from an * empty collector). Both were wrong. So the rule here is that a MISSING trace * is an OBSERVABILITY_GAP, never a pipeline verdict. */ const fs = require('fs'); const path = require('path'); const acq = require('../../src/services/ops/acquisitionTrace'); const snap = require('../../src/services/snapshotService'); const { __internals } = require('../../src/services/gradeSlateService'); const { MODEL_BOOKS } = require('../../src/config/bookRoles'); const ROOT = path.resolve(__dirname, '..', '..'); const BOOK = [...MODEL_BOOKS][0]; jest.setTimeout(20000); const P = (n, over = {}) => Array.from({ length: n }, (_, i) => ({ player: `P${i}`, stat_type: 'hits', line: 0.5 + i, sport: 'mlb', book: BOOK, home_team: 'Reds', away_team: 'Cardinals', game_date: '2026-08-28', ...over, })); const identityOk = (counts = {}) => ({ buildPlayerTeamIndex: async () => ({ index: {}, stats: { players: 12, teams: 2, failed: 0 } }), evidenceIsDateValid: () => true, attachEventIdentity: () => ({ total: 4, canonical: 4, unresolved: 0, unsupported: 0, impossible: 0, reasons: {}, ...counts }), }); /** Runs the REAL runSnapshot corridor; grading is stubbed unless asked for. */ async function corridor(over = {}) { const pg = []; const a = []; await snap.runSnapshot('mlb', { getOdds: async () => ({ sport: 'mlb', props: P(4), provider: 'propline', source: 'cache' }), gradeAndCacheSlate: async () => ({ written: false, count: 0 }), gameBinder: { attachGameTimes: async () => ({ bound: 4, unresolved: 0, alreadyHad: 0 }) }, mlbAdapter: { getScheduleWithPitchers: async () => [{ gamePk: 1 }, { gamePk: 2 }] }, eventIdentity: identityOk(), notify: async () => {}, sleep: async () => {}, retryDelayMs: 0, now: () => '2026-08-28T14:00:00.000Z', scheduledHourUtc: 14, processStartedAt: 'proc-1', retention: null, ledger: { recordPipelineGrades: async () => {}, captureClosing: async () => {}, gameDateFor: () => '2026-08-28' }, captureBookPrices: async () => ({}), buildEspnIndex: async () => ({}), refreshTeamStats: async () => ({ captured: 0 }), cacheGet: async () => null, cacheSet: async () => {}, persistAcquisitionTrace: async (t) => a.push(t), persistPregradeTrace: async (t) => pg.push(t), ...over, }); return { pg: pg[0], acq: a[0] }; } describe('UPSTREAM MLB STAGES', () => { test('SCHEDULE FETCH ERROR names the schedule stage, not identity', async () => { const { pg } = await corridor({ mlbAdapter: { getScheduleWithPitchers: async () => { throw new Error('statsapi 503'); } } }); expect(pg.schedule.threw).toBe(true); expect(pg.schedule.error).toMatch(/statsapi 503/); expect(pg.outcome).toBe(acq.PREGRADE_OUTCOME.SCHEDULE_STAGE_ERROR); expect(pg.outcome).not.toBe(acq.PREGRADE_OUTCOME.EVENT_IDENTITY_STAGE_ERROR); }); test('SCHEDULE SUCCESS records dates requested and game count', async () => { const { pg } = await corridor(); expect(pg.schedule.completed).toBe(true); expect(pg.schedule.dates_requested).toBe(1); expect(pg.schedule.games).toBe(2); }); test('ROSTER INDEX ERROR is visible — its catch used to swallow silently', async () => { const { pg } = await corridor({ eventIdentity: { ...identityOk(), buildPlayerTeamIndex: async () => { throw new Error('roster 500'); } }, }); expect(pg.roster.threw).toBe(true); expect(pg.roster.error).toMatch(/roster 500/); expect(pg.outcome).toBe(acq.PREGRADE_OUTCOME.ROSTER_STAGE_ERROR); }); test('ROSTER SUCCESS records the indexed counts', async () => { const { pg } = await corridor(); expect(pg.roster.completed).toBe(true); expect(pg.roster.players).toBe(12); expect(pg.roster.teams).toBe(2); expect(pg.roster.evidence_date_valid).toBe(true); }); test('BINDING ERROR names the binding stage', async () => { const { pg } = await corridor({ gameBinder: { attachGameTimes: async () => { throw new Error('binder boom'); } } }); expect(pg.binding.threw).toBe(true); expect(pg.outcome).toBe(acq.PREGRADE_OUTCOME.BINDING_STAGE_ERROR); }); test('BINDING SUCCESS records bound / unresolved / already-had', async () => { const { pg } = await corridor({ gameBinder: { attachGameTimes: async () => ({ bound: 3, unresolved: 1, alreadyHad: 0 }) } }); expect(pg.binding).toMatchObject({ completed: true, bound: 3, unresolved: 1, already_had: 0 }); }); test('EVENT IDENTITY ERROR is recorded and the existing fallback is preserved', async () => { const { pg } = await corridor({ eventIdentity: { ...identityOk(), attachEventIdentity: () => { throw new Error('identity boom'); } }, }); expect(pg.identity.threw).toBe(true); expect(pg.outcome).toBe(acq.PREGRADE_OUTCOME.EVENT_IDENTITY_STAGE_ERROR); // The existing catch keeps the slate alive — props stay on legacy identity. const src = fs.readFileSync(path.join(ROOT, 'src/services/snapshotService.js'), 'utf8'); expect(src).toMatch(/Identity is additive: a failure leaves props on legacy identity/); }); test('IDENTITY ALL UNRESOLVED reports truthful status counts', async () => { const { pg } = await corridor({ eventIdentity: identityOk({ total: 4, canonical: 0, unresolved: 4, impossible: 0, reasons: { no_team_match: 4 } }), gradeAndCacheSlate: async (sp, props, o) => { o.pregrade.admission({ started: true, completed: true, threw: false, input_count: 4, admitted_count: 0, rejected_count: 4, rejection_reason_counts: { EVENT_UNRESOLVED: 4 } }); return { written: false, count: 0 }; }, }); expect(pg.identity).toMatchObject({ completed: true, total: 4, canonical: 0, unresolved: 4 }); expect(pg.identity.reasons.no_team_match).toBe(4); // Names the CAUSE, not just the symptom. expect(pg.outcome).toBe(acq.PREGRADE_OUTCOME.IDENTITY_ALL_UNRESOLVED); }); }); describe('DEDUPE IS A FILTER — exact drop accounting off its own branches', () => { const d = (rows, limit = 100) => { const st = {}; const out = __internals.dedupeProps(rows, limit, st); return { out, st }; }; test('behaviour is byte-identical with and without the stats object', () => { const rows = [...P(3), ...P(2, { book: 'nope' })]; expect(__internals.dedupeProps(rows, 100).length).toBe(d(rows).out.length); }); test('ALL dropped by MODEL BOOK', () => { const { out, st } = d(P(5, { book: 'not_a_model_book' })); expect(out).toHaveLength(0); expect(st.dropped_non_model_book).toBe(5); expect(st.dropped_invalid_fields || 0).toBe(0); }); test('ALL dropped by MISSING REQUIRED FIELDS', () => { const { out, st } = d(P(4).map((p) => ({ ...p, player: null }))); expect(out).toHaveLength(0); expect(st.dropped_invalid_fields).toBe(4); expect(st.dropped_non_model_book || 0).toBe(0); }); test('only TRUE duplicates counted as duplicates', () => { const one = P(1); const { out, st } = d([...one, ...one, ...one]); expect(out).toHaveLength(1); expect(st.duplicate_identity_removed).toBe(2); expect(st.dropped_non_model_book || 0).toBe(0); }); test('counts reconcile to the input exactly', () => { const rows = [...P(2), ...P(2), ...P(1, { book: 'x' }), { player: null }]; const { out, st } = d(rows); const accounted = out.length + (st.dropped_invalid_fields || 0) + (st.dropped_non_model_book || 0) + (st.duplicate_identity_removed || 0) + (st.not_examined || 0); expect(accounted).toBe(rows.length); expect(st.input_count).toBe(rows.length); }); test('MODEL-book eligibility is countable for the cohort', () => { const { st } = d([...P(3), ...P(2, { book: 'nope' })]); expect(st.model_book_eligible).toBe(3); expect(st.dropped_non_model_book).toBe(2); }); test('the cap records not_examined rather than pretending it saw everything', () => { const { out, st } = d(P(10), 4); expect(out).toHaveLength(4); expect(st.capped).toBe(true); expect(st.not_examined).toBe(6); }); }); describe('THE GRADING BOUNDARY', () => { const realGrade = () => require('../../src/services/gradeSlateService').gradeAndCacheSlate; test('candidates > 0 but loop NOT entered is distinct from loop entered', () => { const t = acq.beginPregrade({ attemptId: 'a', sport: 'mlb', propsCount: 4 }); acq.pregradeRecorder(t).gradeLoop({ candidate_count: 4, reached: true }); expect(acq.finishPregrade(t, {}).outcome).toBe(acq.PREGRADE_OUTCOME.READY_FOR_GRADING); expect(t.grade_loop.first_gradebestside_started).toBeUndefined(); }); test('FIRST gradeBestSide START is proven through the REAL loop', async () => { const t = acq.beginPregrade({ attemptId: 'a', sport: 'mlb', propsCount: 3 }); await realGrade()('mlb', P(3), { pregrade: acq.pregradeRecorder(t), cacheSet: async () => {}, grade: async () => null, }); expect(t.grade_loop.entered).toBe(true); expect(t.grade_loop.first_gradebestside_started).toBe(true); expect(acq.finishPregrade(t, {}).outcome).toBe(acq.PREGRADE_OUTCOME.GRADE_LOOP_STARTED); }); test('FIRST onGraded is proven separately from gradeBestSide starting', async () => { const t = acq.beginPregrade({ attemptId: 'a', sport: 'mlb', propsCount: 3 }); const rec = acq.pregradeRecorder(t); await realGrade()('mlb', P(3), { pregrade: rec, cacheSet: async () => {}, grade: async () => null, onGraded: () => { rec.firstOnGraded(); }, }); expect(t.grade_loop.first_gradebestside_started).toBe(true); expect(t.grade_loop.first_ongraded_observed).toBe(true); expect(acq.finishPregrade(t, {}).outcome).toBe(acq.PREGRADE_OUTCOME.FIRST_GRADE_CALLBACK_OBSERVED); }); test('gradeBestSide starting WITHOUT onGraded is its own state', async () => { const t = acq.beginPregrade({ attemptId: 'a', sport: 'mlb', propsCount: 3 }); await realGrade()('mlb', P(3), { pregrade: acq.pregradeRecorder(t), cacheSet: async () => {}, grade: async () => null, }); expect(t.grade_loop.first_gradebestside_started).toBe(true); expect(t.grade_loop.first_ongraded_observed).toBeUndefined(); expect(acq.finishPregrade(t, {}).outcome).not.toBe(acq.PREGRADE_OUTCOME.FIRST_GRADE_CALLBACK_OBSERVED); }); test('runSnapshot wraps onGraded ONLY when a collector exists', () => { const src = fs.readFileSync(path.join(ROOT, 'src/services/snapshotService.js'), 'utf8'); expect(src).toMatch(/onGraded: collector \? \(\(base, sides\) => \{ pgRec\.firstOnGraded\(\); return collector\.onGraded\(base, sides\); \}\) : undefined/); expect(src).toMatch(/ongraded_hook_attached: !!collector/); }); test('no model output is recorded — control-flow facts only', () => { const t = acq.beginPregrade({ attemptId: 'a', sport: 'mlb' }); const rec = acq.pregradeRecorder(t); rec.gradeStarted(); rec.firstOnGraded(); const blob = JSON.stringify(t); for (const forbidden of ['p_win', 'grade', 'confidence', 'projection', 'edge', 'side']) { expect(blob).not.toMatch(new RegExp(`"${forbidden}"`)); } }); }); describe('TRACE COMPLETENESS INVARIANT', () => { const acqOk = { snapshot_attempt_id: 'acq_1', final: acq.FINAL.NONZERO, outcome: acq.OUTCOME.CONTINUED }; test('acquisition CONTINUED + NO downstream trace = OBSERVABILITY_GAP, not failure', () => { const r = acq.reconcilePregrade(acqOk, null); expect(r.applicable).toBe(true); expect(r.complete).toBe(false); expect(r.outcome).toBe(acq.PREGRADE_OUTCOME.OBSERVABILITY_GAP); }); test('a mismatched attempt id is also a gap, never a verdict', () => { const r = acq.reconcilePregrade(acqOk, { snapshot_attempt_id: 'other', outcome: acq.PREGRADE_OUTCOME.ALL_REJECTED }); expect(r.outcome).toBe(acq.PREGRADE_OUTCOME.OBSERVABILITY_GAP); expect(r.reason).toBe('attempt_id_mismatch'); }); test('an undecided downstream state is a gap, not a conclusion', () => { for (const o of [undefined, acq.PREGRADE_OUTCOME.INCOMPLETE, acq.PREGRADE_OUTCOME.OTHER_PREGRADING_ERROR]) { const r = acq.reconcilePregrade(acqOk, { snapshot_attempt_id: 'acq_1', outcome: o }); expect(r.outcome).toBe(acq.PREGRADE_OUTCOME.OBSERVABILITY_GAP); } }); test('a decided downstream state reconciles complete', () => { const r = acq.reconcilePregrade(acqOk, { snapshot_attempt_id: 'acq_1', outcome: acq.PREGRADE_OUTCOME.ALL_REJECTED }); expect(r.complete).toBe(true); expect(r.outcome).toBe(acq.PREGRADE_OUTCOME.ALL_REJECTED); }); test('a stubbed/short-circuited grader that records nothing IS a gap', async () => { // Proves the invariant fires rather than inventing a verdict from silence. const { pg, acq: a } = await corridor(); expect(acq.reconcilePregrade(a, pg).outcome).toBe(acq.PREGRADE_OUTCOME.OBSERVABILITY_GAP); }); test('it does not apply when acquisition did not continue', () => { const r = acq.reconcilePregrade({ snapshot_attempt_id: 'a', final: acq.FINAL.THREW, outcome: acq.OUTCOME.EARLY_RETURN_ODDS_ERROR }, null); expect(r.applicable).toBe(false); }); test('a real corridor run produces a decided state and the SAME attempt id', async () => { // The REAL grader, so admission/dedupe/grade-loop actually record. With a // stubbed grader nothing records and the reconciliation correctly reports a // gap — which is the invariant working, not a decided state. const { pg, acq: a } = await corridor({ gradeAndCacheSlate: require('../../src/services/gradeSlateService').gradeAndCacheSlate, grade: async () => null, }); expect(pg.snapshot_attempt_id).toBe(a.snapshot_attempt_id); const r = acq.reconcilePregrade(a, pg); expect(r.complete).toBe(true); expect(r.outcome).not.toBe(acq.PREGRADE_OUTCOME.OBSERVABILITY_GAP); }); }); describe('THE NO-OP RECORDER MUST IMPLEMENT EVERY METHOD', () => { // A missing method throws inside the grade loop, and the enclosing catch // turns that into {written:false,count:0} — a silently empty slate for every // caller that passes no recorder. This shipped once; it must not again. test('NO_PREGRADE covers the full recorder surface', async () => { const real = acq.pregradeRecorder(acq.beginPregrade({ attemptId: 'a', sport: 'mlb' })); const src = fs.readFileSync(path.join(ROOT, 'src/services/gradeSlateService.js'), 'utf8'); const i = src.indexOf('const NO_PREGRADE'); const block = src.slice(i, src.indexOf('\n});', i) + 4); for (const m of Object.keys(real)) { expect(block).toContain(`${m}(`); } }); test('grading works with NO recorder passed at all', async () => { const res = await require('../../src/services/gradeSlateService') .gradeAndCacheSlate('mlb', P(2), { cacheSet: async () => {}, grade: async () => null }); // Refusals produce no grades, but it must NOT fail with a recorder error. expect(res.error).toBeUndefined(); }); }); describe('ZERO NEW EXTERNAL CALLS', () => { test('the observer adds no provider or schedule call', () => { const snapSrc = fs.readFileSync(path.join(ROOT, 'src/services/snapshotService.js'), 'utf8'); // getScheduleWithPitchers is called exactly where the product already called it. expect((snapSrc.match(/getScheduleWithPitchers\(/g) || []).length).toBe(2); expect((snapSrc.match(/buildPlayerTeamIndex\(/g) || []).length).toBe(1); const traceSrc = fs.readFileSync(path.join(ROOT, 'src/services/ops/acquisitionTrace.js'), 'utf8'); const code = traceSrc.replace(/\/\*[\s\S]*?\*\//g, '').replace(/(^|[^:])\/\/.*$/gm, '$1') .replace(/s\.replace\([\s\S]*?\);/g, ''); for (const f of ['fetch(', 'axios', 'getSchedule', 'getProps', 'getOdds', 'oddsService']) { expect(code).not.toContain(f); } }); test('a trace-store failure never changes the product outcome', async () => { const { pg } = await corridor({ persistPregradeTrace: async () => { throw new Error('redis down'); } }); expect(pg).toBeUndefined(); // nothing stored… // …and the run still completed: no throw escaped runSnapshot. }); });