'use strict'; /** * probabilityContractService — LOAD THE FROZEN ARTIFACT. DO NOT FIT. * * This used to call the fitter on every snapshot, so the active mapping changed * silently as outcomes settled: a user's number could move with no version, no * review and no rollback, and a past Read could not be reconstructed because the * curve that produced it no longer existed anywhere. * * The refit PROCEDURE is certified separately and offline * (`scripts/certify-current-era-procedure.js`), and produces ONE committed * artifact (`scripts/build-current-era-artifact.js`). At runtime there is no * fitter, no ledger read, and nothing to drift: `artifactRegistry` loads the * promoted JSON and the served value comes from its frozen curve. * * A consequence worth stating: new settled outcomes are FORWARD EVALUATION * evidence. They may inform a future candidate. They cannot alter this curve. */ const pc = require('./probabilityContract'); const registry = require('./artifactRegistry'); /** * @returns {null|{contract, artifact, resolve}} null when nothing is promoted * for this sport/stat, or the promoted artifact fails to load. Null means * NOTHING is served — never a fallback curve, which would be a mapping nobody * certified. */ async function build(_sb, { sport = 'mlb', stat = 'hits', usage = 'shadow' } = {}) { const contract = pc.contractFor(sport, stat); if (!contract) return null; const artifact = registry.load(sport, stat); if (!artifact) return null; return { contract, artifact, fit_n: artifact.fit_n, fitted_through: artifact.training_cutoff, cutoff: artifact.fit_as_of, /** The frozen curve. Two calls return the same value, forever. */ estimate: (p) => registry.applyCurve(artifact, p), /** * THE ROW'S IDENTITY DECIDES — never the identity this resolver was built * with. Stamping `{sport, stat}` here applied the mlb-hits curve to every * row in the batch: measured on cohort 0353c551, 513 PUBLISHED non-hits * rows (total_bases, runs, rbi, walks, outs, strikeouts, hits_allowed, * earned_runs) came back CERTIFIED_CALIBRATED with a served probability * from the hits artifact. A read that names no stat resolves to no * contract, which is UNSUPPORTED — the correct answer, not a fallback. */ resolve(read) { return pc.resolve(read, { estimate: (p) => registry.applyCurve(artifact, p), artifact, usage }); }, }; } module.exports = { build };