Skip to content
Closed
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
40 changes: 40 additions & 0 deletions src/services/score-breakdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,45 @@ function mergedHistoryBreakdown(preview: ScorePreviewResult): ScoreMultiplierBre
};
}

// Sibling of mergedHistoryBreakdown for the issue-discovery validity floor (upstream MIN_VALID_SOLVED_ISSUES +
// MIN_ISSUE_CREDIBILITY): a contributor whose observed valid solved-issue count or issue credibility is below
// the upstream floors has the entire issue-discovery preview zeroed. Explained here so a miner in the
// issue-discovery lane sees the same actionable breakdown the merged-PR history floor already provides.
function issueDiscoveryHistoryBreakdown(preview: ScorePreviewResult): ScoreMultiplierBreakdown {
const { issueDiscoveryHistoryMultiplier } = preview.scoreEstimate;
const {
validSolvedIssuesFloor,
issueCredibilityFloor,
validSolvedIssues,
issueCredibility,
} = preview.gates;
// Either evidence dimension unobserved => the floor is not enforced for this preview => neutral (mirrors
// preview.ts:410 issueDiscoveryHistoryKnown).
if (validSolvedIssues === undefined || issueCredibility === undefined) {
return {
component: "issueDiscoveryHistoryMultiplier",
band: "neutral",
summary: `Issue-discovery validity floor is not enforced for this preview (no solved-issue evidence observed; upstream floors are ${validSolvedIssuesFloor} valid solved / ${issueCredibilityFloor.toFixed(2)} credibility).`,
lever: "No action needed for this preview; the upstream issue-discovery floors apply once solved-issue evidence is observed.",
leverageScore: 0,
};
}
const meetsFloor =
validSolvedIssues >= validSolvedIssuesFloor && issueCredibility >= issueCredibilityFloor;
const band = bandForMultiplier(issueDiscoveryHistoryMultiplier);
return {
component: "issueDiscoveryHistoryMultiplier",
band,
summary: meetsFloor
? `Solved-issue evidence (${validSolvedIssues} valid solved, ${issueCredibility.toFixed(2)} credibility) meets the upstream floors (${validSolvedIssuesFloor} / ${issueCredibilityFloor.toFixed(2)}).`
: `Solved-issue evidence (${validSolvedIssues} valid solved, ${issueCredibility.toFixed(2)} credibility) is below the upstream floors (${validSolvedIssuesFloor} valid solved, ${issueCredibilityFloor.toFixed(2)} credibility), so this issue-discovery preview is zeroed.`,
lever: meetsFloor
? "Keep resolving valid open issues with solved-by-PR evidence to maintain issue-discovery eligibility."
: "Land more solved-by-PR-validated issues and grow issue credibility to clear the upstream floors before relying on this preview.",
leverageScore: meetsFloor ? 5 : 100,
};
}

function credibilityBreakdown(preview: ScorePreviewResult): ScoreMultiplierBreakdown {
const { credibilityMultiplier } = preview.scoreEstimate;
const { credibilityObserved, credibilityFloor } = preview.gates;
Expand Down Expand Up @@ -272,6 +311,7 @@ export function explainScoreBreakdown(preview: ScorePreviewResult): ScoreBreakdo
openPrBreakdown(preview),
openIssueBreakdown(preview),
mergedHistoryBreakdown(preview),
issueDiscoveryHistoryBreakdown(preview),
].map((entry) => ({
...entry,
summary: sanitizePublicComment(entry.summary),
Expand Down
25 changes: 25 additions & 0 deletions test/unit/score-breakdown.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
import { buildScorePreview } from "../../src/scoring/preview";
import { explainScoreBreakdown } from "../../src/services/score-breakdown";
import type { RepositoryRecord, ScoringModelSnapshotRecord } from "../../src/types";
import type { LinkedIssueMultiplierContext } from "../../src/scoring/preview";

const FORBIDDEN = /\b(wallet|hotkey|coldkey|mnemonic|farming|payout|raw[-_\s]?trust)\b/i;

Expand Down Expand Up @@ -120,6 +121,30 @@ describe("explainScoreBreakdown", () => {
expect(JSON.stringify(blocked)).not.toMatch(FORBIDDEN);
});

it("explains the issue-discovery validity floor as neutral (unobserved), full (meets floors), and blocked (below floors)", () => {
const standardContext: LinkedIssueMultiplierContext = { status: "raw", source: "github_cache", issueNumbers: [12] };

// Unobserved evidence -> floors not enforced -> neutral.
const unobserved = explainScoreBreakdown(
buildScorePreview({ repo, snapshot, input: { repoFullName: repo.fullName, contributorLogin: "miner", sourceTokenScore: 40, totalTokenScore: 60, sourceLines: 80, openPrCount: 1, credibility: 0.9, linkedIssueMode: "standard", linkedIssueContext: standardContext } }),
);
expect(unobserved.components.find((entry) => entry.component === "issueDiscoveryHistoryMultiplier")).toMatchObject({ band: "neutral" });

// Observed + both floors met -> full.
const meets = explainScoreBreakdown(
buildScorePreview({ repo, snapshot, input: { repoFullName: repo.fullName, contributorLogin: "miner", sourceTokenScore: 40, totalTokenScore: 60, sourceLines: 80, openPrCount: 1, credibility: 0.9, linkedIssueMode: "standard", linkedIssueContext: standardContext, validSolvedIssues: 5, issueCredibility: 0.95 } }),
);
expect(meets.components.find((entry) => entry.component === "issueDiscoveryHistoryMultiplier")).toMatchObject({ band: "full" });

// Observed + below floors -> blocked, and the issue-discovery lever surfaces as highest-leverage.
const blocked = explainScoreBreakdown(
buildScorePreview({ repo, snapshot, input: { repoFullName: repo.fullName, contributorLogin: "miner", sourceTokenScore: 40, totalTokenScore: 60, sourceLines: 80, openPrCount: 1, credibility: 0.9, linkedIssueMode: "standard", linkedIssueContext: standardContext, validSolvedIssues: 1, issueCredibility: 0.5 } }),
);
expect(blocked.components.find((entry) => entry.component === "issueDiscoveryHistoryMultiplier")).toMatchObject({ band: "blocked", leverageScore: 100 });
expect(blocked.highestLeverageLever.lever).toMatch(/issue/i);
expect(JSON.stringify(blocked)).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