diff --git a/src/scoring/model.ts b/src/scoring/model.ts index bb49a6e50f..86f028c6ac 100644 --- a/src/scoring/model.ts +++ b/src/scoring/model.ts @@ -8,10 +8,14 @@ import { errorMessage, nowIso } from "../utils/json"; export const DEFAULT_SCORING_CONSTANTS: Record = { OSS_EMISSION_SHARE: 0.9, - ISSUE_TREASURY_EMISSION_SHARE: 0.1, + // Upstream name is ISSUES_TREASURY_EMISSION_SHARE (plural). The prior singular spelling never matched + // upstream, freezing this at the local default and showing up as a false "unmodeled" drift warning (#806). + ISSUES_TREASURY_EMISSION_SHARE: 0.1, PR_LOOKBACK_DAYS: 30, MERGED_PR_BASE_SCORE: 25, - MAX_CONTRIBUTION_BONUS: 25, + // Upstream MAX_CONTRIBUTION_BONUS is 5. This local value is only the fetch-failure fallback; keeping it at + // 25 silently 5x-inflated the contribution bonus whenever the upstream fetch failed (#807). + MAX_CONTRIBUTION_BONUS: 5, CONTRIBUTION_SCORE_FOR_FULL_BONUS: 1500, TEST_FILE_CONTRIBUTION_WEIGHT: 0.05, MIN_VALID_MERGED_PRS: 3, diff --git a/src/scoring/preview.ts b/src/scoring/preview.ts index 697a55b2cf..d358cedb4b 100644 --- a/src/scoring/preview.ts +++ b/src/scoring/preview.ts @@ -954,11 +954,11 @@ function saturationContributionBonus(totalTokenScore: number, constants: Record< // Shared contribution-bonus ramp used by both scoring models so the saturation // and density bonuses cannot drift: clamp(totalTokenScore / FULL_BONUS, 0, 1) -// scaled by MAX_CONTRIBUTION_BONUS (default 25). +// scaled by MAX_CONTRIBUTION_BONUS (upstream default 5; see model.ts #807). function contributionBonusRamp(totalTokenScore: number, constants: Record): number { return ( clamp(totalTokenScore / constant(constants, "CONTRIBUTION_SCORE_FOR_FULL_BONUS", 1500), 0, 1) * - constant(constants, "MAX_CONTRIBUTION_BONUS", 25) + constant(constants, "MAX_CONTRIBUTION_BONUS", 5) ); } diff --git a/test/unit/scoring.test.ts b/test/unit/scoring.test.ts index 89b4192bf6..fc05c09756 100644 --- a/test/unit/scoring.test.ts +++ b/test/unit/scoring.test.ts @@ -84,6 +84,20 @@ MAX_CODE_DENSITY_MULTIPLIER = 1.15 expect(detectActiveModel(parsed)).toBe("pending_saturation_model"); }); + it("uses upstream's exact constant names and fallback values (#806, #807)", () => { + // #807: the fetch-failure fallback for MAX_CONTRIBUTION_BONUS must equal upstream's value (5), never the + // old 25 that silently 5x-inflated the contribution bonus whenever the upstream fetch failed. + expect(DEFAULT_SCORING_CONSTANTS.MAX_CONTRIBUTION_BONUS).toBe(5); + // #806: the treasury share must use upstream's plural spelling (ISSUES_…) so it actually syncs instead of + // freezing at the local default and showing up as a false "unmodeled" drift warning. + expect(DEFAULT_SCORING_CONSTANTS).toHaveProperty("ISSUES_TREASURY_EMISSION_SHARE"); + expect(DEFAULT_SCORING_CONSTANTS).not.toHaveProperty("ISSUE_TREASURY_EMISSION_SHARE"); + // When upstream sends the plural name it is recognized, not reported as unmodeled drift. + expect( + findUnmodeledUpstreamConstants("ISSUES_TREASURY_EMISSION_SHARE = 0.1\nMAX_CONTRIBUTION_BONUS = 5\n"), + ).not.toContain("ISSUES_TREASURY_EMISSION_SHARE"); + }); + it("detects the active model from fetched constants before default fallback constants", async () => { const env = createTestEnv({ GITHUB_PUBLIC_TOKEN: "token" }); vi.stubGlobal("fetch", async (input: RequestInfo | URL) => { @@ -98,7 +112,9 @@ MAX_CODE_DENSITY_MULTIPLIER = 1.15 const refreshed = await refreshScoringModelSnapshot(env); expect(refreshed.activeModel).toBe("current_density_model"); - expect(refreshed.constants.MAX_CONTRIBUTION_BONUS).toBe(25); + // Upstream did not send MAX_CONTRIBUTION_BONUS, so it falls back to the local default — which must match + // upstream's value of 5, not the old inflated 25 (#807). + expect(refreshed.constants.MAX_CONTRIBUTION_BONUS).toBe(5); expect(refreshed.constants.SRC_TOK_SATURATION_SCALE).toBe(58); expect(refreshed.warnings).not.toEqual(expect.arrayContaining([expect.stringContaining("density-era indicators")])); });