diff --git a/src/scoring/preview.ts b/src/scoring/preview.ts index 19e0d418fd..6ef7de7540 100644 --- a/src/scoring/preview.ts +++ b/src/scoring/preview.ts @@ -301,12 +301,11 @@ function computeScoreCore( const issueDiscoverySlice = repoSlice * issueDiscoveryShare; const sourceTokenScore = nonNegative(input.sourceTokenScore); // TEST_FILE_CONTRIBUTION_WEIGHT (#808): upstream weights test-file tokens at 0.05× relative to source tokens. - // Applied only when totalTokenScore is not explicitly provided — an explicit caller total is honoured as-is. const testFileWeight = constant(constants, "TEST_FILE_CONTRIBUTION_WEIGHT", 0.05); const cappedNonCodeTokenScore = applyNonCodeLineCap(input, constants); - const totalTokenScore = nonNegative( - input.totalTokenScore ?? sourceTokenScore + testFileWeight * nonNegative(input.testTokenScore) + cappedNonCodeTokenScore, - ); + const derivedTotalTokenScore = sourceTokenScore + testFileWeight * nonNegative(input.testTokenScore) + cappedNonCodeTokenScore; + const totalTokenScore = + input.totalTokenScore === undefined ? nonNegative(derivedTotalTokenScore) : applyNonCodeCapToTotal(input.totalTokenScore, input, cappedNonCodeTokenScore); const sourceLines = Math.max(1, nonNegative(input.sourceLines ?? sourceTokenScore)); const fixedBaseScore = input.fixedBaseScore ?? config?.fixedBaseScore ?? undefined; const rawDensity = sourceTokenScore / sourceLines; @@ -978,6 +977,17 @@ function applyNonCodeLineCap(input: Pick, + cappedNonCodeTokenScore: number, +): number { + const total = nonNegative(totalTokenScore); + const nonCodeTokenScore = nonNegative(input.nonCodeTokenScore); + if (nonCodeTokenScore <= 0 || cappedNonCodeTokenScore >= nonCodeTokenScore) return total; + return Math.max(0, total - (nonCodeTokenScore - cappedNonCodeTokenScore)); +} + function constant(constants: Record, key: string, fallback: number): number { const value = constants[key]; return typeof value === "number" && Number.isFinite(value) ? value : fallback; diff --git a/test/unit/scoring.test.ts b/test/unit/scoring.test.ts index 139972c2e8..8302f37ecc 100644 --- a/test/unit/scoring.test.ts +++ b/test/unit/scoring.test.ts @@ -286,6 +286,25 @@ NOVELTY_BONUS_SCALAR = 3 }).scoreEstimate.contributionBonus, 5, ); + + const explicitTotalWithNonCode = buildScorePreview({ + repo, + snapshot: { + ...snapshot, + constants: { ...snapshot.constants, MAX_LINES_SCORED_FOR_NON_CODE_EXT: 300, CONTRIBUTION_SCORE_FOR_FULL_BONUS: 1500, MAX_CONTRIBUTION_BONUS: 25 }, + }, + input: { + repoFullName: repo.fullName, + sourceTokenScore: 100, + totalTokenScore: 700, + nonCodeTokenScore: 600, + nonCodeLines: 600, + sourceLines: 100, + openPrCount: 0, + credibility: 1, + }, + }); + expect(explicitTotalWithNonCode.scoreEstimate.contributionBonus).toBeCloseTo(cappedNonCode.scoreEstimate.contributionBonus, 5); }); it("detects the active model from fetched constants before default fallback constants", async () => {