Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 56 additions & 7 deletions apps/gittensory-ui/public/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -4338,6 +4338,12 @@
},
"issueCredibility": {
"type": "number"
},
"nonCodeLineCap": {
"type": "number"
},
"nonCodeLinesObserved": {
"type": "number"
}
},
"required": [
Expand All @@ -4352,7 +4358,8 @@
"openIssueCount",
"mergedPrFloor",
"validSolvedIssuesFloor",
"issueCredibilityFloor"
"issueCredibilityFloor",
"nonCodeLineCap"
]
},
"effectiveEstimatedScore": {
Expand Down Expand Up @@ -4640,6 +4647,12 @@
},
"issueCredibility": {
"type": "number"
},
"nonCodeLineCap": {
"type": "number"
},
"nonCodeLinesObserved": {
"type": "number"
}
},
"required": [
Expand All @@ -4654,7 +4667,8 @@
"openIssueCount",
"mergedPrFloor",
"validSolvedIssuesFloor",
"issueCredibilityFloor"
"issueCredibilityFloor",
"nonCodeLineCap"
]
},
"effectiveEstimatedScore": {
Expand Down Expand Up @@ -4942,6 +4956,12 @@
},
"issueCredibility": {
"type": "number"
},
"nonCodeLineCap": {
"type": "number"
},
"nonCodeLinesObserved": {
"type": "number"
}
},
"required": [
Expand All @@ -4956,7 +4976,8 @@
"openIssueCount",
"mergedPrFloor",
"validSolvedIssuesFloor",
"issueCredibilityFloor"
"issueCredibilityFloor",
"nonCodeLineCap"
]
},
"effectiveEstimatedScore": {
Expand Down Expand Up @@ -5244,6 +5265,12 @@
},
"issueCredibility": {
"type": "number"
},
"nonCodeLineCap": {
"type": "number"
},
"nonCodeLinesObserved": {
"type": "number"
}
},
"required": [
Expand All @@ -5258,7 +5285,8 @@
"openIssueCount",
"mergedPrFloor",
"validSolvedIssuesFloor",
"issueCredibilityFloor"
"issueCredibilityFloor",
"nonCodeLineCap"
]
},
"effectiveEstimatedScore": {
Expand Down Expand Up @@ -5546,6 +5574,12 @@
},
"issueCredibility": {
"type": "number"
},
"nonCodeLineCap": {
"type": "number"
},
"nonCodeLinesObserved": {
"type": "number"
}
},
"required": [
Expand All @@ -5560,7 +5594,8 @@
"openIssueCount",
"mergedPrFloor",
"validSolvedIssuesFloor",
"issueCredibilityFloor"
"issueCredibilityFloor",
"nonCodeLineCap"
]
},
"effectiveEstimatedScore": {
Expand Down Expand Up @@ -6504,6 +6539,12 @@
},
"issueCredibility": {
"type": "number"
},
"nonCodeLineCap": {
"type": "number"
},
"nonCodeLinesObserved": {
"type": "number"
}
},
"required": [
Expand All @@ -6518,7 +6559,8 @@
"openIssueCount",
"mergedPrFloor",
"validSolvedIssuesFloor",
"issueCredibilityFloor"
"issueCredibilityFloor",
"nonCodeLineCap"
]
},
"branchEligibility": {
Expand Down Expand Up @@ -6805,6 +6847,12 @@
},
"issueCredibility": {
"type": "number"
},
"nonCodeLineCap": {
"type": "number"
},
"nonCodeLinesObserved": {
"type": "number"
}
},
"required": [
Expand All @@ -6819,7 +6867,8 @@
"openIssueCount",
"mergedPrFloor",
"validSolvedIssuesFloor",
"issueCredibilityFloor"
"issueCredibilityFloor",
"nonCodeLineCap"
]
},
"effectiveEstimatedScore": {
Expand Down
2 changes: 2 additions & 0 deletions src/openapi/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1290,6 +1290,8 @@ const ScoreGatesSchema = z.object({
validSolvedIssues: z.number().optional(),
issueCredibilityFloor: z.number(),
issueCredibility: z.number().optional(),
nonCodeLineCap: z.number(),
nonCodeLinesObserved: z.number().optional(),
});

const BranchEligibilitySchema = z.object({
Expand Down
7 changes: 7 additions & 0 deletions src/scoring/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ export type ScorePreviewResult = {
issueCredibilityFloor: number;
/** Observed issue-discovery credibility when supplied; absent when unknown. */
issueCredibility?: number | undefined;
/** Upstream non-code line scoring cap (MAX_LINES_SCORED_FOR_NON_CODE_EXT); non-code token score beyond this
* many changed non-code lines is not scored. */
nonCodeLineCap: number;
/** Observed raw non-code line count before the cap; absent when no non-code line count was supplied. */
nonCodeLinesObserved?: number | undefined;
};
branchEligibility: BranchEligibilityResult;
effectiveEstimatedScore: number;
Expand Down Expand Up @@ -474,6 +479,8 @@ function computeScoreCore(
...(validSolvedIssuesObserved !== undefined ? { validSolvedIssues: validSolvedIssuesObserved } : {}),
issueCredibilityFloor,
...(issueCredibilityObserved !== undefined ? { issueCredibility: issueCredibilityObserved } : {}),
nonCodeLineCap: constant(constants, "MAX_LINES_SCORED_FOR_NON_CODE_EXT"),
...(input.nonCodeLines !== undefined ? { nonCodeLinesObserved: nonNegative(input.nonCodeLines) } : {}),
},
};
}
Expand Down
31 changes: 31 additions & 0 deletions src/services/score-breakdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,36 @@ function contributionBonusBreakdown(preview: ScorePreviewResult): ScoreMultiplie
};
}

// Sibling of the history-floor breakdowns for the upstream non-code line cap (MAX_LINES_SCORED_FOR_NON_CODE_EXT):
// non-code token score beyond the cap's worth of changed non-code lines is not scored, so a docs/config-heavy PR
// can silently lose non-code contribution. Surfaced here so a miner sees the cap the same way the gate breakdowns
// already surface the open-PR / open-issue / merged-history floors. The cap is a token-score reducer (not a stacked
// multiplier), so it reads neutral unless the observed non-code line count actually exceeds the cap.
function nonCodeCapBreakdown(preview: ScorePreviewResult): ScoreMultiplierBreakdown {
const { nonCodeLineCap, nonCodeLinesObserved } = preview.gates;
if (nonCodeLinesObserved === undefined) {
return {
component: "nonCodeLineCap",
band: "neutral",
summary: `No scored non-code line count is observed for this preview (upstream scores at most ${nonCodeLineCap} non-code lines).`,
lever: "No action needed; the non-code line cap only affects previews that add scored non-code lines.",
leverageScore: 0,
};
}
const capped = nonCodeLinesObserved > nonCodeLineCap;
return {
component: "nonCodeLineCap",
band: capped ? "reduced" : "neutral",
summary: capped
? `Non-code lines (${nonCodeLinesObserved}) exceed the upstream scored cap (${nonCodeLineCap}); non-code token contribution beyond the cap is not scored.`
: `Non-code lines (${nonCodeLinesObserved}) are within the upstream scored cap (${nonCodeLineCap}).`,
lever: capped
? "Non-code changes beyond the cap add no score; move substantive logic into source files or split the non-code bulk out of this PR."
: "Non-code contribution is within the scored cap; no action needed on this lever.",
leverageScore: capped ? 30 : 5,
};
}

function roundBand(value: number): string {
return value.toFixed(2).replace(/\.?0+$/, "");
}
Expand Down Expand Up @@ -319,6 +349,7 @@ export function explainScoreBreakdown(preview: ScorePreviewResult): ScoreBreakdo
openIssueBreakdown(preview),
mergedHistoryBreakdown(preview),
timeDecayBreakdown(preview),
nonCodeCapBreakdown(preview),
].map((entry) => ({
...entry,
summary: sanitizePublicComment(entry.summary),
Expand Down
28 changes: 28 additions & 0 deletions test/unit/score-breakdown.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ describe("explainScoreBreakdown", () => {
"openIssueMultiplier",
"mergedHistoryMultiplier",
"timeDecayMultiplier",
"nonCodeLineCap",
]),
);
for (const component of breakdown.components) {
Expand Down Expand Up @@ -122,6 +123,33 @@ describe("explainScoreBreakdown", () => {
expect(JSON.stringify(blocked)).not.toMatch(FORBIDDEN);
});

it("explains the non-code line cap as neutral (unobserved / within cap) and reduced (over cap)", () => {
const base = {
repoFullName: repo.fullName,
contributorLogin: "miner",
sourceTokenScore: 40,
totalTokenScore: 60,
sourceLines: 80,
openPrCount: 1,
credibility: 0.9,
linkedIssueMode: "none" as const,
};
// No non-code line count supplied -> the cap is not counted for this preview -> neutral, zero leverage.
const unobserved = explainScoreBreakdown(buildScorePreview({ repo, snapshot, input: base }));
expect(unobserved.components.find((entry) => entry.component === "nonCodeLineCap")).toMatchObject({ band: "neutral", leverageScore: 0 });

// Observed within the upstream cap (MAX_LINES_SCORED_FOR_NON_CODE_EXT = 300) -> neutral.
const within = explainScoreBreakdown(buildScorePreview({ repo, snapshot, input: { ...base, nonCodeLines: 10 } }));
expect(within.components.find((entry) => entry.component === "nonCodeLineCap")).toMatchObject({ band: "neutral", leverageScore: 5 });

// Observed over the cap -> reduced, with an actionable move-to-source lever.
const over = explainScoreBreakdown(buildScorePreview({ repo, snapshot, input: { ...base, nonCodeLines: 5000 } }));
const cap = over.components.find((entry) => entry.component === "nonCodeLineCap")!;
expect(cap).toMatchObject({ band: "reduced", leverageScore: 30 });
expect(cap.summary).toMatch(/exceed/i);
expect(JSON.stringify(over)).not.toMatch(FORBIDDEN);
});

it("explains an over-threshold open-issue count as a blocked open-issue spam gate", () => {
const preview = buildScorePreview({
repo,
Expand Down
Loading