'use strict'; /** * CONTROLLED_FORCED provenance. * * `runSnapshot` defaults an absent trigger to SCHEDULED, so the internal * one-shot route recorded operator-invoked runs as though the cron had fired * them. That is a lie about provenance, and it was there by omission. * * The pipeline path is unchanged: the route already called the same production * runSnapshot with the same default dependencies. Only the label is corrected, * and the trace store now retains that label. */ const fs = require('fs'); const path = require('path'); const acq = require('../../src/services/ops/acquisitionTrace'); const ROOT = path.resolve(__dirname, '..', '..'); describe('THE TRIGGER IS TRUTHFUL', () => { test('CONTROLLED_FORCED exists and is distinct from SCHEDULED', () => { expect(acq.TRIGGER.CONTROLLED_FORCED).toBe('CONTROLLED_FORCED'); expect(acq.TRIGGER.CONTROLLED_FORCED).not.toBe(acq.TRIGGER.SCHEDULED); }); test('the internal one-shot route labels its runs CONTROLLED_FORCED', () => { const src = fs.readFileSync(path.join(ROOT, 'src/routes/internal.js'), 'utf8'); const i = src.indexOf("runSnapshot(req.params.sport"); const block = src.slice(i - 500, i + 300); expect(block).toMatch(/trigger: acqT\.TRIGGER\.CONTROLLED_FORCED/); expect(block).toMatch(/processStartedAt: PROCESS_STARTED_AT/); }); test('the /snapshot/all route labels its runs CONTROLLED_FORCED too', () => { const src = fs.readFileSync(path.join(ROOT, 'src/routes/internal.js'), 'utf8'); const i = src.indexOf('runAllSnapshots({'); expect(i).toBeGreaterThan(-1); const block = src.slice(i - 200, i + 220); expect(block).toMatch(/trigger: acqT\.TRIGGER\.CONTROLLED_FORCED/); }); test('NEITHER internal route can label itself SCHEDULED', () => { // Both routes appear in one file, so a single-occurrence edit can silently // fix one and leave the other lying. const src = fs.readFileSync(path.join(ROOT, 'src/routes/internal.js'), 'utf8'); expect(src).not.toMatch(/trigger: acqT\.TRIGGER\.SCHEDULED/); expect((src.match(/trigger: acqT\.TRIGGER\.CONTROLLED_FORCED/g) || [])).toHaveLength(2); }); test('it does NOT pass a scheduled hour — there is no slot for a forced run', () => { const src = fs.readFileSync(path.join(ROOT, 'src/routes/internal.js'), 'utf8'); const i = src.indexOf("runSnapshot(req.params.sport"); expect(src.slice(i - 500, i + 300)).not.toMatch(/scheduledHourUtc/); }); test('the scheduler still labels its own runs SCHEDULED', () => { const src = fs.readFileSync(path.join(ROOT, 'src/snapshotScheduler.js'), 'utf8'); expect(src).toMatch(/trigger: acq\.TRIGGER\.SCHEDULED/); expect(src).not.toMatch(/CONTROLLED_FORCED/); }); }); describe('RETENTION OF TRACES BY TRIGGER', () => { const store = () => { const seen = []; return { seen, client: { lpush: async (k, v) => seen.push([k, JSON.parse(v).trigger]), ltrim: async () => {}, expire: async () => {} } }; }; test('a CONTROLLED_FORCED trace IS retained, tagged as itself', async () => { const s = store(); const t = acq.finish(acq.begin({ sport: 'mlb', trigger: acq.TRIGGER.CONTROLLED_FORCED }), { final: acq.FINAL.NONZERO }); const out = await acq.persist(t, { getRedisClient: () => s.client }); expect(out.stored).toBe(true); expect(s.seen[0]).toEqual(['ops:acquisition:mlb', 'CONTROLLED_FORCED']); }); test('its pre-grading trace is retained too', async () => { const s = store(); const t = acq.finishPregrade(acq.beginPregrade({ attemptId: 'a', sport: 'mlb', trigger: acq.TRIGGER.CONTROLLED_FORCED }), {}); expect((await acq.persistPregrade(t, { getRedisClient: () => s.client })).stored).toBe(true); expect(s.seen[0][0]).toBe('ops:pregrade:mlb'); }); test('INTRADAY is STILL refused — it would displace scheduled evidence', async () => { const s = store(); const t = acq.finish(acq.begin({ sport: 'mlb', trigger: acq.TRIGGER.INTRADAY }), { final: acq.FINAL.NONZERO }); const out = await acq.persist(t, { getRedisClient: () => s.client }); expect(out.stored).toBe(false); expect(out.reason).toBe('not_retained_trigger'); expect(s.seen).toHaveLength(0); }); test('MANUAL_API is refused as well — only the two named triggers are kept', () => { expect(acq.RETAINED_TRIGGERS).toEqual([acq.TRIGGER.SCHEDULED, acq.TRIGGER.CONTROLLED_FORCED]); expect(acq.RETAINED_TRIGGERS).not.toContain(acq.TRIGGER.MANUAL); }); }); describe('THE PIPELINE PATH IS UNCHANGED', () => { const src = fs.readFileSync(path.join(ROOT, 'src/routes/internal.js'), 'utf8'); test('the route still calls the SAME production runSnapshot', () => { expect(src).toMatch(/const snapshot = require\('\.\.\/services\/snapshotService'\)/); expect(src).toMatch(/snapshot\.runSnapshot\(req\.params\.sport, \{/); }); test('it injects NO dependency override — production defaults throughout', () => { const i = src.indexOf('runSnapshot(req.params.sport'); const call = src.slice(i, src.indexOf('});', i) + 3); for (const dep of ['getOdds', 'gradeAndCacheSlate', 'retention', 'ledger', 'cacheSet', 'cacheGet', 'gameBinder', 'eventIdentity', 'mlbAdapter', 'notify']) { expect(call).not.toContain(dep); } // Only the bisect limit and the two diagnostic fields. expect(call).toMatch(/trigger:/); expect(call).toMatch(/processStartedAt:/); }); test('lineage is untouched by the trigger label', () => { const rs = fs.readFileSync(path.join(ROOT, 'src/services/retentionService.js'), 'utf8'); expect(rs).not.toMatch(/CONTROLLED_FORCED/); }); });