The seam never ran: an undeclared variable, and a bare catch that hid it
LIVE was switched on in production and nothing happened, because
`snapshotGating.stripModelPrice` contained
try { rows = require(...).applyToRows(rows); } catch { }
`rows` is not declared in that function — the parameter is `grades`. Under
'use strict' that is a ReferenceError on every call, and the empty catch
swallowed it. For an entire release the seam was dead, the status surface
reported LIVE ON, and every row was served raw.
Two failures, and the second is the one that mattered: a silent catch turned a
hard crash into nothing at all. It now names the failure in the log and degrades
to uncalibrated rows explicitly.
The entitled branch also returned `grades` — the original array — so even a
working seam would have had its output discarded for exactly the tier meant to
receive it. Both fixed; `grades` is threaded through.
MY TESTS COULD NOT SEE IT. They called `applyToRows` directly and grepped the
source for the require line. Neither exercises the boundary, and a source grep
is not proof a line runs: the dead wiring contained that exact require. The new
tests call `stripModelPrice` and assert on its RETURN VALUE, entitled and
unentitled, plus a throwing-seam case that requires the warning.
Verified on real production rows through the real entitled path:
0.706 -> 0.625 CERTIFIED, EV recomputed 8.7 -> -3.7, grade B unchanged
0.858 -> unavailable UNCERTIFIED, its value:true WITHDRAWN, grade B+ unchanged
rbi -> untouched
free tier -> model fields still stripped
Found only because the live acceptance measured real rows instead of trusting a
green suite.
Suite 407/407, 5,697 passed. Teeth 48/48 + 10/10 + 23/23.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CQJeAG8vcDoL5zkiaJyVb8
This commit is contained in:
@@ -112,7 +112,11 @@ describe('one seam', () => {
|
||||
it('serving routes reach it through stripModelPrice, not by duplicating logic', () => {
|
||||
const fs = require('fs'); const path = require('path');
|
||||
const gsrc = fs.readFileSync(path.join(__dirname, '../../src/utils/snapshotGating.js'), 'utf8');
|
||||
expect(gsrc).toContain("require('../services/model/servedProbability').applyToRows(rows)");
|
||||
// NOTE: a source grep is NOT proof the seam runs — the first wiring
|
||||
// contained this exact require and did nothing. The behavioural proof is in
|
||||
// "THE SEAM MUST FIRE THROUGH THE REAL BOUNDARY" below; this only checks
|
||||
// that consumers do not duplicate the logic.
|
||||
expect(gsrc).toContain("servedProbability').applyToRows(grades)");
|
||||
// no consumer may hold calibration logic of its own
|
||||
for (const f of ['src/routes/snapshot.js', 'src/routes/heroProp.js', 'src/services/topGradedService.js']) {
|
||||
const src = fs.readFileSync(path.join(__dirname, '../../', f), 'utf8')
|
||||
@@ -123,3 +127,81 @@ describe('one seam', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('THE SEAM MUST FIRE THROUGH THE REAL BOUNDARY', () => {
|
||||
/**
|
||||
* The first wiring assigned to an undeclared `rows` instead of `grades`,
|
||||
* threw a ReferenceError under strict mode, and a bare catch swallowed it.
|
||||
* Live reported ON while every row was served raw, for a whole release.
|
||||
*
|
||||
* The old tests could not see it: they called `applyToRows` directly and
|
||||
* grepped the source for the require line. Neither exercises the boundary.
|
||||
* These call `stripModelPrice` and assert on its RETURN VALUE.
|
||||
*/
|
||||
const OLD = process.env.PROBABILITY_CONTRACT_LIVE;
|
||||
beforeAll(() => { process.env.PROBABILITY_CONTRACT_LIVE = '1'; });
|
||||
afterAll(() => {
|
||||
if (OLD === undefined) delete process.env.PROBABILITY_CONTRACT_LIVE;
|
||||
else process.env.PROBABILITY_CONTRACT_LIVE = OLD;
|
||||
});
|
||||
|
||||
const batch = () => ([
|
||||
row({ p_win: 0.706, confidence: 71, ev_pct: 8.7, value: false, book_odds: -185, fair_odds: -160, grade: 'B' }),
|
||||
row({ p_win: 0.858, confidence: 86, ev_pct: 51.8, value: true, book_odds: -130, fair_odds: -110, grade: 'B+', side: 'under' }),
|
||||
row({ stat_type: 'rbi', p_win: 0.65, confidence: 65, ev_pct: 12, value: true, grade: 'C+' }),
|
||||
]);
|
||||
|
||||
it('an ENTITLED caller receives the CALIBRATED rows, not the originals', () => {
|
||||
const src = batch();
|
||||
const out = gating.stripModelPrice(src, 'desk');
|
||||
const expected = registry.applyCurve(A, 0.706);
|
||||
expect(out[0].p_win).toBe(Math.round(expected * 1000) / 1000);
|
||||
expect(out[0].p_win).not.toBe(0.706); // the seam actually ran
|
||||
expect(out[0].probability_state).toBe(pc.STATE.CERTIFIED_CALIBRATED);
|
||||
expect(out[0].raw_model_probability).toBe(0.706);
|
||||
});
|
||||
|
||||
it('EV is recomputed from the served probability at the boundary', () => {
|
||||
const out = gating.stripModelPrice(batch(), 'desk');
|
||||
const { evPct } = require('../../src/utils/devig');
|
||||
expect(out[0].ev_pct).toBe(evPct(out[0].p_win, -185));
|
||||
expect(out[0].ev_pct).not.toBe(8.7); // the raw-derived value
|
||||
});
|
||||
|
||||
it('an UNCERTIFIED row loses its number and its TRUE value badge', () => {
|
||||
const out = gating.stripModelPrice(batch(), 'desk');
|
||||
expect(out[1].p_win).toBeNull();
|
||||
expect(out[1].confidence).toBeNull();
|
||||
expect(out[1].ev_pct).toBeNull();
|
||||
expect(out[1].value).toBeNull(); // was true
|
||||
expect(out[1].grade).toBe('B+'); // grade survives
|
||||
expect(out[1].raw_model_probability).toBe(0.858);
|
||||
});
|
||||
|
||||
it('a non-hits row is untouched at the boundary', () => {
|
||||
const out = gating.stripModelPrice(batch(), 'desk');
|
||||
expect(out[2].p_win).toBe(0.65);
|
||||
expect(out[2].probability_state).toBeUndefined();
|
||||
});
|
||||
|
||||
it('an UNENTITLED caller still gets the model fields stripped', () => {
|
||||
const out = gating.stripModelPrice(batch(), 'free');
|
||||
for (const r of out) {
|
||||
expect(r.p_win).toBeUndefined();
|
||||
expect(r.ev_pct).toBeUndefined();
|
||||
expect(r.value).toBeUndefined();
|
||||
}
|
||||
});
|
||||
|
||||
it('a throwing seam degrades to uncalibrated rows and SAYS SO', () => {
|
||||
const warn = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
const mod = require('../../src/services/model/servedProbability');
|
||||
const real = mod.applyToRows;
|
||||
mod.applyToRows = () => { throw new Error('boom'); };
|
||||
try {
|
||||
const out = gating.stripModelPrice(batch(), 'desk');
|
||||
expect(out[0].p_win).toBe(0.706); // unchanged, not lost
|
||||
expect(warn).toHaveBeenCalled(); // and not silent
|
||||
} finally { mod.applyToRows = real; warn.mockRestore(); }
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user