'use strict'; /** * Which settled rows a forward re-audit may use. * * The refusal these encode: no measurement on rows produced by the retired * ten-game forecaster, and no reconstruction standing in for what was served. */ const el = require('../../src/services/model/reAuditEligibility'); const row = (version, date) => ({ model_version: version, game_date: date }); const OLD = 'engine1@2026-07-20'; describe('eligibility is mechanical, not a promise', () => { it('accepts only rows carrying the repaired champion marker', () => { expect(el.isEligible(row(el.REPAIRED_CHAMPION_VERSION, '2026-08-08'))).toBe(true); expect(el.isEligible(row(OLD, '2026-08-08'))).toBe(false); expect(el.isEligible(row(null, '2026-08-08'))).toBe(false); expect(el.isEligible(null)).toBe(false); }); it('an all-old table blocks every measurement and says why', () => { const a = el.assess(Array.from({ length: 500 }, (_, i) => row(OLD, `2026-07-${(i % 28) + 1}`))); expect(a.eligible_rows).toBe(0); expect(a.blocked_reason).toMatch(/nothing may be measured/); for (const v of Object.values(a.ready)) expect(v.ready).toBe(false); }); it('a MIXED table counts only the repaired rows — the invisible trap', () => { // Once both generations sit in the same table, a naive count would happily // fit a map on a blend of two different forecasters. const mixed = [ ...Array.from({ length: 300 }, (_, i) => row(OLD, `2026-07-${(i % 20) + 1}`)), ...Array.from({ length: 30 }, (_, i) => row(el.REPAIRED_CHAMPION_VERSION, `2026-08-${(i % 3) + 8}`)), ]; const a = el.assess(mixed); expect(a.total_rows).toBe(330); expect(a.eligible_rows).toBe(30); expect(a.eligible_dates).toBe(3); }); }); describe('thresholds are per-measurement and pre-stated', () => { it('unblocks each measurement independently at its own date bar', () => { const dates = 10; const rows = Array.from({ length: 400 }, (_, i) => row(el.REPAIRED_CHAMPION_VERSION, `2026-08-${(i % dates) + 8}`)); const a = el.assess(rows); expect(a.eligible_dates).toBe(dates); expect(a.ready.calibration_refit.ready).toBe(true); expect(a.ready.hits_factor_lift.ready).toBe(true); // The heavier measurements still wait. expect(a.ready.prior_verdict_reaudit.ready).toBe(false); expect(a.ready.rbi_lineup_slot_gate.ready).toBe(false); }); it('counts DATES, not rows — the binding scarcity all session', () => { const many = Array.from({ length: 5000 }, () => row(el.REPAIRED_CHAMPION_VERSION, '2026-08-08')); expect(el.assess(many).ready.calibration_refit.ready).toBe(false); }); it('the thresholds are frozen so they cannot drift', () => { expect(Object.isFrozen(el.ACCRUAL)).toBe(true); }); });