One evaluator for the shadow, so the probe cannot report a mode the pipeline is not in

"Is the shadow effective?" was only answerable by waiting for a snapshot to
write a row. That leaves a blind spot with real cost: a variable SET IN COOLIFY
BUT NOT YET APPLIED to the running process is indistinguishable from an unset
one, and the runtime probe already proves the distinction matters — code_sha
22cf51c with started_at 01:45:44Z means anything set after that is not in this
process's environment.

probabilityContract.shadowState() is now the single evaluator. snapshotService
calls it and the protected status probe calls it, and a test asserts NEITHER
reads process.env directly — the same rule that keeps lineage_write_mode honest.
Reading the env in two places is how a status page and a gate come to disagree.

Strict by construction: only the exact string '1' enables it. 'true', 'yes',
'on', '01', ' 1 ' and '' are all OFF, because a loose parse turns a typo into an
activation. `configuration_source` separates an unset variable from one
explicitly set to '0', and `live_serving` is reported as its own switch so the
shadow can never be read as implying serving.

No behaviour changes. The shadow still defaults OFF, CALIBRATION_DEPLOYED is
still [], and served fields are untouched.

Frontend byte-identical to the last green build (git reports zero changes under
web/), so the build from 22cf51c stands.

Suite 401/401, 5,597 passed, 4 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CQJeAG8vcDoL5zkiaJyVb8
This commit is contained in:
Kev
2026-09-02 22:53:21 -04:00
parent 22cf51c4b0
commit 556d186ff1
6 changed files with 240 additions and 4 deletions
+3 -1
View File
@@ -119,7 +119,9 @@ logicTooth(16, 'live serving activates before the shadow has passed', () => {
// ── 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 pcSrc = fs.readFileSync(path.join(ROOT, 'src/services/model/probabilityContract.js'), 'utf8');
const strict = pcSrc.includes("String(raw || '') === '1'")
&& snap.includes("probabilityContract').shadowState().shadow === 'ON'");
const scoped = snap.includes("&& sp === 'mlb'");
const statScoped = snap.includes("{ sport: 'mlb', stat: 'hits' }");
return { caught: strict && scoped && statScoped,