22cf51c4b0
Runtime probes say the fleet is on a8de676, one process generation. But
"isotonic" was a label, not a claim: probabilityContractService refits per
snapshot against `game_date < todayEt()`, so the mapping changes as outcomes
settle, and nothing on a row could say WHICH mapping produced its number.
The artifact now has an identity:
estimator_type / estimator_version / certification_version / model_version
fit_as_of the exact lt(game_date) bound 2026-09-02
training_cutoff last date INSIDE the fit 2026-08-21
fit_n / knot_count 6,084 / 28
knot_digest d9d571d728ba76de
served_curve the COMPLETE served function over [0.50,0.80)
served_curve_digest
The served curve is not a sample. p_win is quantised to three decimals at the
source, so a step table at 0.001 granularity is the mapping itself for every
input that can occur — six steps, ~200 bytes. Storing it makes a Read
reconstructable WITHOUT re-deriving a training set that may since have been
re-settled, and a claim you can only verify when the inputs happen not to have
moved is not a reconstructable claim.
Proven, not asserted: the production construction path run twice gives an
identical digest, and an INDEPENDENT reconstruction — re-walk 9,361 settled
ledger rows at the declared bound, refit from scratch — reproduces
d9d571d728ba76de exactly, 28 knots for 28.
A teeth injection found a real defect behind a coverage hole. `resolve` checked
the CONTRACT's model era and never the ARTIFACT's, so a mapping fitted for a
different era could be recorded beside a served number with every test green.
Both the era and the estimator type are now checked, and a mismatch serves
nothing rather than serving quietly.
OBSERVED AND NOT CHANGED: calibrationService splits 65/35 to certify its own
bands, a step this contract does not consume because support comes from the
frozen artifact. So the served map is fitted through 2026-08-21 while 3,277
more recent settled rows sit unused, and that lag grows with history. Changing
it would change the fitted function, which this tranche froze.
Shadow still defaults OFF. CALIBRATION_DEPLOYED still []. served_probability is
referenced by nothing outside the contract layer — asserted by a tooth.
Suite 401/401, 5,593 passed, 4 skipped. Teeth 23/23 (prior) + 7/7 (new).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CQJeAG8vcDoL5zkiaJyVb8
138 lines
7.5 KiB
JavaScript
138 lines
7.5 KiB
JavaScript
#!/usr/bin/env node
|
|
'use strict';
|
|
/**
|
|
* teeth-certified-probability — the NEW ground in this tranche.
|
|
*
|
|
* Teeth 6-15 and 19-23 of the order are already landed independently by
|
|
* scripts/teeth-probability-contract.js (23/23) and are not re-asserted here;
|
|
* this runner covers runtime observability, artifact identity, point-in-time
|
|
* evidence, shadow harmlessness, and the activation ordering.
|
|
*
|
|
* Teeth 17, 18 and 24 target a LIVE SERVING path that does not exist yet.
|
|
* They are recorded UNREACHABLE rather than asserted weakly.
|
|
*/
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const crypto = require('crypto');
|
|
const { execSync } = require('child_process');
|
|
|
|
const ROOT = path.join(__dirname, '..');
|
|
const sha = (f) => crypto.createHash('sha256').update(fs.readFileSync(f)).digest('hex');
|
|
const codeOf = (s) => s.replace(/\/\*[\s\S]*?\*\//g, '').replace(/^\s*\/\/.*$/gm, '');
|
|
const results = [];
|
|
|
|
function runSuite(file) {
|
|
try { execSync(`npx jest ${file} --silent --testTimeout=45000`, { cwd: ROOT, stdio: 'pipe', timeout: 300000 });
|
|
return true; } catch { return false; }
|
|
}
|
|
function injectionTooth(id, name, file, find, replace, suite) {
|
|
const full = path.join(ROOT, file);
|
|
const before = fs.readFileSync(full, 'utf8');
|
|
const beforeSha = sha(full);
|
|
let landed = false, detail = '';
|
|
try {
|
|
if (!before.includes(find)) {
|
|
results.push({ id, name, landed: false, detail: `ANCHOR NOT FOUND in ${file} — the injection would have silently no-opped` });
|
|
return;
|
|
}
|
|
fs.writeFileSync(full, before.replace(find, replace));
|
|
if (fs.readFileSync(full, 'utf8') === before) throw new Error('injection produced no change');
|
|
landed = runSuite(suite) === false;
|
|
detail = landed ? `defect installed -> ${suite} FAILED as required`
|
|
: `defect installed and ${suite} STILL PASSED — coverage hole`;
|
|
} catch (e) { detail = 'threw: ' + e.message; }
|
|
finally {
|
|
fs.writeFileSync(full, before);
|
|
const ok = sha(full) === beforeSha;
|
|
detail += ok ? ' | restored byte-identical' : ' | RESTORE MISMATCH';
|
|
if (!ok) landed = false;
|
|
}
|
|
results.push({ id, name, landed, detail });
|
|
}
|
|
function logicTooth(id, name, fn) {
|
|
let landed = false, detail = '';
|
|
try { const r = fn(); landed = r.caught === true; detail = r.detail || ''; }
|
|
catch (e) { detail = 'threw: ' + e.message; }
|
|
results.push({ id, name, landed, detail });
|
|
}
|
|
|
|
// ── 1 — runtime SHA observability actually exists and is used ─────────────
|
|
logicTooth(1, 'runtime SHA verification waits for a snapshot despite working runtime status', () => {
|
|
const src = codeOf(fs.readFileSync(path.join(ROOT, 'src/routes/internal.js'), 'utf8'));
|
|
const block = src.slice(src.indexOf("router.get('/snapshot/status'"), src.indexOf("router.get('/snapshot/status'") + 4000);
|
|
const hasSha = /runtime:\s*\{[\s\S]*?code_sha:\s*codeSha\(\)/.test(block);
|
|
const hasStart = /started_at:\s*PROCESS_STARTED_AT/.test(block);
|
|
// and it must resolve from the SAME provenance source, not git HEAD
|
|
const ret = codeOf(fs.readFileSync(path.join(ROOT, 'src/services/retentionService.js'), 'utf8'));
|
|
const sameResolver = /function codeSha\(\)\s*\{\s*return process\.env\.SOURCE_COMMIT/.test(ret);
|
|
return { caught: hasSha && hasStart && sameResolver,
|
|
detail: `status exposes runtime.code_sha=${hasSha} started_at=${hasStart}; same resolver as provenance=${sameResolver}` };
|
|
});
|
|
|
|
// ── 2 — the estimator must carry a reconstructable identity ──────────────
|
|
injectionTooth(2, 'runtime estimator lacks a reconstructable artifact identity',
|
|
'src/services/model/probabilityContractService.js',
|
|
` knot_digest: digest(fitted.map),`,
|
|
` knot_digest: 'static-placeholder',`,
|
|
'tests/unit/probabilityContract.test.js');
|
|
|
|
// ── 3 — the artifact must be tied to the certified model era ─────────────
|
|
injectionTooth(3, 'runtime artifact differs from the certified artifact',
|
|
'src/services/model/probabilityContractService.js',
|
|
` model_version: contract.model_version,`,
|
|
` model_version: 'engine1@some-other-era',`,
|
|
'tests/unit/probabilityContractShadow.test.js');
|
|
|
|
// ── 4 — point-in-time evidence ───────────────────────────────────────────
|
|
injectionTooth(4, 'dynamic refit uses future settlement evidence for an earlier Read',
|
|
'src/services/model/calibrationService.js',
|
|
` .lt('game_date', cutoff), // STRICTLY before — the whole point`,
|
|
` .lte('game_date', cutoff),`,
|
|
'tests/unit/probabilityContract.test.js');
|
|
|
|
// ── 5 — the shadow may not move served product ───────────────────────────
|
|
injectionTooth(5, 'shadow changes current user-facing output',
|
|
'src/services/retentionService.js',
|
|
` return {
|
|
...r,
|
|
probability_contract: {`,
|
|
` return {
|
|
...r,
|
|
p_win: res.served_probability != null ? res.served_probability : r.p_win,
|
|
probability_contract: {`,
|
|
'tests/unit/probabilityContractShadow.test.js');
|
|
|
|
// ── 16 — activation ordering ─────────────────────────────────────────────
|
|
logicTooth(16, 'live serving activates before the shadow has passed', () => {
|
|
const snap = codeOf(fs.readFileSync(path.join(ROOT, 'src/services/snapshotService.js'), 'utf8'));
|
|
const deployedEmpty = /CALIBRATION_DEPLOYED\s*=\s*Object\.freeze\(\[\s*\]\)/.test(snap);
|
|
// no live consumer may read served_probability yet
|
|
const srcFiles = execSync(`grep -rl "served_probability" ${ROOT}/src ${ROOT}/web/src 2>/dev/null || true`)
|
|
.toString().trim().split('\n').filter(Boolean).map((f) => f.replace(ROOT + '/', ''));
|
|
const allowed = ['src/services/model/probabilityContract.js',
|
|
'src/services/model/probabilityContractService.js', 'src/services/retentionService.js'];
|
|
const leaked = srcFiles.filter((f) => !allowed.includes(f));
|
|
return { caught: deployedEmpty && leaked.length === 0,
|
|
detail: `CALIBRATION_DEPLOYED empty=${deployedEmpty}; served_probability referenced outside the contract layer: ${leaked.join(', ') || 'none'}` };
|
|
});
|
|
|
|
// ── the shadow flag itself ───────────────────────────────────────────────
|
|
logicTooth(25, 'shadow flag parses loosely or defaults ON', () => {
|
|
const snap = fs.readFileSync(path.join(ROOT, 'src/services/snapshotService.js'), 'utf8');
|
|
const strict = snap.includes("String(process.env.PROBABILITY_CONTRACT_SHADOW || '') === '1'");
|
|
const scoped = snap.includes("&& sp === 'mlb'");
|
|
const statScoped = snap.includes("{ sport: 'mlb', stat: 'hits' }");
|
|
return { caught: strict && scoped && statScoped,
|
|
detail: `strict '1' compare=${strict}; sport-scoped=${scoped}; stat-scoped=${statScoped}` };
|
|
});
|
|
|
|
const unreachable = [
|
|
{ id: 17, name: 'UI displays raw exact confidence for UNCERTIFIED', why: 'no live-serving UI path exists; nothing consumes served_probability yet' },
|
|
{ id: 18, name: 'live EV/Kelly/VALUE consumers bypass served_probability', why: 'live consumers are unchanged by design in this tranche — tooth 16 asserts none exist' },
|
|
{ id: 24, name: 'rollback rewrites historical probability contracts', why: 'nothing is activated, so there is no activation to roll back' },
|
|
];
|
|
|
|
const landed = results.filter((r) => r.landed).length;
|
|
console.log(JSON.stringify({ teeth_landed: `${landed}/${results.length}`, results, unreachable }, null, 2));
|
|
process.exit(landed === results.length ? 0 : 1);
|