⚠️ Definition of Done: this issue must be completed in full, in a single PR. Do not split this
work across multiple PRs, and do not defer any Deliverable below to a follow-up issue. A PR that
satisfies only some of the Deliverables, stubs a required test, or leaves a checkbox
partially-done does NOT resolve this issue and will be closed.
Context
src/scoring/model.ts's fail-closed guard (lines 78-87) correctly freezes the last-good snapshot when the upstream constants.py fetch returns HTTP 200 but the body is non-source garbage (recognizedCount < MIN_RECOGNIZED_SCORING_CONSTANTS) -- but only when a valid lastGood snapshot exists. If it doesn't (first run, or last-good was itself a fallback), execution falls through, and the drift-sync guard at line 137 is only if (constantsResult.ok) -- not a usable-content check -- so syncUnmodeledScoringConstantDrift still runs findUnmodeledUpstreamConstants against the garbage body and can open a spurious high/medium-severity upstream_drift_reports row.
Requirements
Change line 137's guard to check content usability (e.g. if (constantsUsable), mirroring whatever variable/check the fail-closed guard at line 78-87 uses to determine "usable" vs "garbage-but-200"), so a garbage-body fetch never feeds syncUnmodeledScoringConstantDrift.
Deliverables
All of the above Deliverables are required in the same PR unless the deliverable text itself states otherwise.
Test Coverage Requirements
src/** -- 99%+ patch coverage, branch-counted, on the corrected guard.
Expected Outcome
A garbage-but-200 upstream constants.py fetch with no prior good snapshot no longer opens a spurious high/medium-severity drift report.
Links & Resources
src/scoring/model.ts:78-87,137-142
Context
src/scoring/model.ts's fail-closed guard (lines 78-87) correctly freezes the last-good snapshot when the upstreamconstants.pyfetch returns HTTP 200 but the body is non-source garbage (recognizedCount < MIN_RECOGNIZED_SCORING_CONSTANTS) -- but only when a validlastGoodsnapshot exists. If it doesn't (first run, or last-good was itself afallback), execution falls through, and the drift-sync guard at line 137 is onlyif (constantsResult.ok)-- not a usable-content check -- sosyncUnmodeledScoringConstantDriftstill runsfindUnmodeledUpstreamConstantsagainst the garbage body and can open a spurious high/medium-severityupstream_drift_reportsrow.Requirements
Change line 137's guard to check content usability (e.g.
if (constantsUsable), mirroring whatever variable/check the fail-closed guard at line 78-87 uses to determine "usable" vs "garbage-but-200"), so a garbage-body fetch never feedssyncUnmodeledScoringConstantDrift.Deliverables
syncUnmodeledScoringConstantDriftlastGoodsnapshot) does not produce a spuriousupstream_drift_reportsrowAll of the above Deliverables are required in the same PR unless the deliverable text itself states otherwise.
Test Coverage Requirements
src/**-- 99%+ patch coverage, branch-counted, on the corrected guard.Expected Outcome
A garbage-but-200 upstream
constants.pyfetch with no prior good snapshot no longer opens a spurious high/medium-severity drift report.Links & Resources
src/scoring/model.ts:78-87,137-142