diff --git a/packages/loopover-engine/src/phase7-calibration-loop.ts b/packages/loopover-engine/src/phase7-calibration-loop.ts index 3309e9b83d..20ea6d896e 100644 --- a/packages/loopover-engine/src/phase7-calibration-loop.ts +++ b/packages/loopover-engine/src/phase7-calibration-loop.ts @@ -177,7 +177,14 @@ function normalizeCompositeWeights(config: Phase7CalibrationConfig): { historica }; const total = raw.historicalReplay + raw.prOutcome; if (total <= 0) { - return { historicalReplay: DEFAULT_CONFIG.historicalReplayWeight, prOutcome: DEFAULT_CONFIG.prOutcomeWeight }; + // #8644: PRESERVE an explicit all-zero weighting instead of silently substituting the defaults. This + // branch is reachable ONLY when both weights were explicitly 0 -- `finiteNonNegative` floors any invalid + // input to a positive default, which cannot sum to 0 -- so a 0 total is a deliberate "disable composite + // weighting" signal from the operator, not a degraded input. Returning {0,0} leaves weightTotal 0 + // downstream, which the combinedAccuracy guard already renders as a null composite (the same state reached + // when no source contributes), matching the "preserve explicit zero" principle the sibling calibration + // composers follow -- rather than overriding the operator's intent back to a 50/50 default. + return { historicalReplay: 0, prOutcome: 0 }; } return { historicalReplay: raw.historicalReplay / total, diff --git a/packages/loopover-engine/test/phase7-calibration-loop.test.ts b/packages/loopover-engine/test/phase7-calibration-loop.test.ts index 1751e8a90d..951e59d3d1 100644 --- a/packages/loopover-engine/test/phase7-calibration-loop.test.ts +++ b/packages/loopover-engine/test/phase7-calibration-loop.test.ts @@ -493,3 +493,21 @@ test("REGRESSION (#3014): combined metric stays anchored to the documented 62% b assert.equal(result.combinedAccuracy, 0.62); assert.equal(result.deltaFromBaseline, 0); }); + +test("normalizeCompositeWeights preserves an explicit all-zero weighting rather than silently defaulting (#8644)", () => { + const config = enabledConfig({ historicalReplayWeight: 0, prOutcomeWeight: 0 }); + assert.equal(config.historicalReplayWeight, 0); + assert.equal(config.prOutcomeWeight, 0); + + const result = computePhase7CalibrationLoop({ + config, + prOutcome: sufficientPrOutcome(0.75), + historicalReplay: healthyReplay(0.82), + now: NOW, + }); + + // Preserved, not reverted to the 50/50 default; {0,0} yields no composite (null), matching the + // "preserve explicit zero" principle rather than overriding the operator's intent. + assert.deepEqual(result.weights, { historicalReplay: 0, prOutcome: 0 }); + assert.equal(result.combinedAccuracy, null); +}); diff --git a/test/unit/phase7-calibration-loop-weights.test.ts b/test/unit/phase7-calibration-loop-weights.test.ts new file mode 100644 index 0000000000..c9abd74cd8 --- /dev/null +++ b/test/unit/phase7-calibration-loop-weights.test.ts @@ -0,0 +1,33 @@ +import { describe, expect, it } from "vitest"; + +import { computePhase7CalibrationLoop, resolvePhase7CalibrationConfig } from "../../packages/loopover-engine/src/index"; + +// #8644: root-vitest mirror so `normalizeCompositeWeights`'s explicit-all-zero branch in +// phase7-calibration-loop.ts is Codecov-measured. The package-native node:test suite +// (packages/loopover-engine/test/) runs under the engine workspace, not this root run that Codecov grades -- +// same reasoning as #8438's signal-tracking root mirror. Imports the engine SOURCE (src/index) so coverage +// attributes to the .ts rather than the built dist. +describe("phase7 composite weights — explicit all-zero is preserved (#8644)", () => { + it("preserves both weights as 0 instead of silently reverting to the 50/50 default", () => { + const config = resolvePhase7CalibrationConfig({ + miner: { calibration: { phase7LoopEnabled: true, historicalReplayWeight: 0, prOutcomeWeight: 0 } }, + }); + // Precondition: an explicit 0 is stored as 0, not defaulted — otherwise the branch under test is unreachable. + expect(config.historicalReplayWeight).toBe(0); + expect(config.prOutcomeWeight).toBe(0); + + const result = computePhase7CalibrationLoop({ config }); + expect(result.weights).toEqual({ historicalReplay: 0, prOutcome: 0 }); + // {0,0} leaves no composite weighting, so combinedAccuracy is null — the same state reached when no + // source contributes, not a silently-defaulted weighted average. + expect(result.combinedAccuracy).toBeNull(); + }); + + it("still normalizes a normal positive config to sum 1 (the unchanged happy path, both branches covered)", () => { + const config = resolvePhase7CalibrationConfig({ + miner: { calibration: { phase7LoopEnabled: true, historicalReplayWeight: 3, prOutcomeWeight: 1 } }, + }); + const result = computePhase7CalibrationLoop({ config }); + expect(result.weights).toEqual({ historicalReplay: 0.75, prOutcome: 0.25 }); + }); +});