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
78 changes: 71 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"
},
"validIssueTokenFloor": {
"type": "number"
},
"validIssueTokenGatePassed": {
"type": "boolean"
}
},
"required": [
Expand All @@ -4352,7 +4358,9 @@
"openIssueCount",
"mergedPrFloor",
"validSolvedIssuesFloor",
"issueCredibilityFloor"
"issueCredibilityFloor",
"validIssueTokenFloor",
"validIssueTokenGatePassed"
]
},
"effectiveEstimatedScore": {
Expand All @@ -4376,6 +4384,7 @@
"open_issue_threshold",
"merged_pr_history_floor",
"issue_discovery_validity_floor",
"valid_issue_token_floor",
"credibility_floor",
"review_penalty",
"metadata_only",
Expand Down Expand Up @@ -4640,6 +4649,12 @@
},
"issueCredibility": {
"type": "number"
},
"validIssueTokenFloor": {
"type": "number"
},
"validIssueTokenGatePassed": {
"type": "boolean"
}
},
"required": [
Expand All @@ -4654,7 +4669,9 @@
"openIssueCount",
"mergedPrFloor",
"validSolvedIssuesFloor",
"issueCredibilityFloor"
"issueCredibilityFloor",
"validIssueTokenFloor",
"validIssueTokenGatePassed"
]
},
"effectiveEstimatedScore": {
Expand All @@ -4678,6 +4695,7 @@
"open_issue_threshold",
"merged_pr_history_floor",
"issue_discovery_validity_floor",
"valid_issue_token_floor",
"credibility_floor",
"review_penalty",
"metadata_only",
Expand Down Expand Up @@ -4942,6 +4960,12 @@
},
"issueCredibility": {
"type": "number"
},
"validIssueTokenFloor": {
"type": "number"
},
"validIssueTokenGatePassed": {
"type": "boolean"
}
},
"required": [
Expand All @@ -4956,7 +4980,9 @@
"openIssueCount",
"mergedPrFloor",
"validSolvedIssuesFloor",
"issueCredibilityFloor"
"issueCredibilityFloor",
"validIssueTokenFloor",
"validIssueTokenGatePassed"
]
},
"effectiveEstimatedScore": {
Expand All @@ -4980,6 +5006,7 @@
"open_issue_threshold",
"merged_pr_history_floor",
"issue_discovery_validity_floor",
"valid_issue_token_floor",
"credibility_floor",
"review_penalty",
"metadata_only",
Expand Down Expand Up @@ -5244,6 +5271,12 @@
},
"issueCredibility": {
"type": "number"
},
"validIssueTokenFloor": {
"type": "number"
},
"validIssueTokenGatePassed": {
"type": "boolean"
}
},
"required": [
Expand All @@ -5258,7 +5291,9 @@
"openIssueCount",
"mergedPrFloor",
"validSolvedIssuesFloor",
"issueCredibilityFloor"
"issueCredibilityFloor",
"validIssueTokenFloor",
"validIssueTokenGatePassed"
]
},
"effectiveEstimatedScore": {
Expand All @@ -5282,6 +5317,7 @@
"open_issue_threshold",
"merged_pr_history_floor",
"issue_discovery_validity_floor",
"valid_issue_token_floor",
"credibility_floor",
"review_penalty",
"metadata_only",
Expand Down Expand Up @@ -5546,6 +5582,12 @@
},
"issueCredibility": {
"type": "number"
},
"validIssueTokenFloor": {
"type": "number"
},
"validIssueTokenGatePassed": {
"type": "boolean"
}
},
"required": [
Expand All @@ -5560,7 +5602,9 @@
"openIssueCount",
"mergedPrFloor",
"validSolvedIssuesFloor",
"issueCredibilityFloor"
"issueCredibilityFloor",
"validIssueTokenFloor",
"validIssueTokenGatePassed"
]
},
"effectiveEstimatedScore": {
Expand All @@ -5584,6 +5628,7 @@
"open_issue_threshold",
"merged_pr_history_floor",
"issue_discovery_validity_floor",
"valid_issue_token_floor",
"credibility_floor",
"review_penalty",
"metadata_only",
Expand Down Expand Up @@ -5757,6 +5802,7 @@
"open_issue_threshold",
"merged_pr_history_floor",
"issue_discovery_validity_floor",
"valid_issue_token_floor",
"credibility_floor",
"review_penalty",
"metadata_only",
Expand Down Expand Up @@ -6504,6 +6550,12 @@
},
"issueCredibility": {
"type": "number"
},
"validIssueTokenFloor": {
"type": "number"
},
"validIssueTokenGatePassed": {
"type": "boolean"
}
},
"required": [
Expand All @@ -6518,7 +6570,9 @@
"openIssueCount",
"mergedPrFloor",
"validSolvedIssuesFloor",
"issueCredibilityFloor"
"issueCredibilityFloor",
"validIssueTokenFloor",
"validIssueTokenGatePassed"
]
},
"branchEligibility": {
Expand Down Expand Up @@ -6599,6 +6653,7 @@
"open_issue_threshold",
"merged_pr_history_floor",
"issue_discovery_validity_floor",
"valid_issue_token_floor",
"credibility_floor",
"review_penalty",
"metadata_only",
Expand Down Expand Up @@ -6805,6 +6860,12 @@
},
"issueCredibility": {
"type": "number"
},
"validIssueTokenFloor": {
"type": "number"
},
"validIssueTokenGatePassed": {
"type": "boolean"
}
},
"required": [
Expand All @@ -6819,7 +6880,9 @@
"openIssueCount",
"mergedPrFloor",
"validSolvedIssuesFloor",
"issueCredibilityFloor"
"issueCredibilityFloor",
"validIssueTokenFloor",
"validIssueTokenGatePassed"
]
},
"effectiveEstimatedScore": {
Expand All @@ -6843,6 +6906,7 @@
"open_issue_threshold",
"merged_pr_history_floor",
"issue_discovery_validity_floor",
"valid_issue_token_floor",
"credibility_floor",
"review_penalty",
"metadata_only",
Expand Down
3 changes: 3 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(),
validIssueTokenFloor: z.number(),
validIssueTokenGatePassed: z.boolean(),
});

const BranchEligibilitySchema = z.object({
Expand All @@ -1312,6 +1314,7 @@ const ScoreGateBlockerSchema = z.object({
"open_issue_threshold",
"merged_pr_history_floor",
"issue_discovery_validity_floor",
"valid_issue_token_floor",
"credibility_floor",
"review_penalty",
"metadata_only",
Expand Down
1 change: 1 addition & 0 deletions src/scenarios/scenario-summary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ const PUBLIC_BLOCKER_TEXT: Partial<Record<ScoreGateBlocker["code"], string>> = {
open_issue_threshold: "Too many open issues exist; closing excess issues would help.",
merged_pr_history_floor: "Merged PR history on this repo is below the upstream eligibility floor.",
issue_discovery_validity_floor: "Valid solved-issue history or issue credibility is below the upstream issue-discovery floor.",
valid_issue_token_floor: "The planned source change may be too small to count as a valid issue-discovery solve upstream.",
credibility_floor: "Contributor credibility evidence is below the expected floor.",
review_penalty: "Review churn history may reduce the contribution quality signal.",
metadata_only: "Only metadata signals are available; detailed analysis requires full context.",
Expand Down
20 changes: 20 additions & 0 deletions src/scoring/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ export type ScoreGateBlocker = {
| "open_issue_threshold"
| "merged_pr_history_floor"
| "issue_discovery_validity_floor"
| "valid_issue_token_floor"
| "credibility_floor"
| "review_penalty"
| "metadata_only"
Expand Down Expand Up @@ -209,6 +210,9 @@ export type ScorePreviewResult = {
issueCredibilityFloor: number;
/** Observed issue-discovery credibility when supplied; absent when unknown. */
issueCredibility?: number | undefined;
validIssueTokenFloor: number;
/** True when the planned PR's source tokens meet MIN_TOKEN_SCORE_FOR_VALID_ISSUE (#808). */
validIssueTokenGatePassed: boolean;
};
branchEligibility: BranchEligibilityResult;
effectiveEstimatedScore: number;
Expand Down Expand Up @@ -248,6 +252,9 @@ export function buildScorePreview(args: {
...(current.scoreEstimate.issueDiscoveryHistoryMultiplier === 0
? ["Build valid solved-issue history and issue credibility before relying on issue-discovery scoring on this repo."]
: []),
...(current.gates.validIssueTokenGatePassed === false
? ["Increase meaningful source change size so this linked-issue solve would count toward valid issue-discovery history upstream."]
: []),
...(current.scoreEstimate.credibilityMultiplier < 1 ? ["Build or wait for contributor credibility evidence before relying on this preview."] : []),
...(current.scoreEstimate.reviewPenaltyMultiplier < 1 ? ["Reduce review churn with tighter tests and clearer evidence."] : []),
...(current.scoreEstimate.labelMultiplier <= 1 && Object.keys(args.repo?.registryConfig?.labelMultipliers ?? {}).length > 0
Expand Down Expand Up @@ -414,6 +421,8 @@ function computeScoreCore(
: validSolvedIssuesObserved >= validSolvedIssuesFloor && issueCredibilityObserved >= issueCredibilityFloor
? 1
: 0;
const validIssueTokenFloor = constant(constants, "MIN_TOKEN_SCORE_FOR_VALID_ISSUE");
const validIssueTokenGatePassed = !issueDiscoveryRelevant || sourceTokenScore >= validIssueTokenFloor;
// Upstream time-decay (#703): mirrors upstream's `scored.time_decay_multiplier` applied to a PR's score.
// Opt-in + env-gated (default off). A fresh PR (prAgeHours below the grace period) yields 1.0, so a normal
// new-PR preview is unchanged even when enabled — only an aged-PR projection decays.
Expand Down Expand Up @@ -474,6 +483,8 @@ function computeScoreCore(
...(validSolvedIssuesObserved !== undefined ? { validSolvedIssues: validSolvedIssuesObserved } : {}),
issueCredibilityFloor,
...(issueCredibilityObserved !== undefined ? { issueCredibility: issueCredibilityObserved } : {}),
validIssueTokenFloor,
validIssueTokenGatePassed,
},
};
}
Expand Down Expand Up @@ -738,6 +749,15 @@ function blockedByFor(input: ScorePreviewInput, repo: RepositoryRecord | null, c
},
]
: []),
...(!core.gates.validIssueTokenGatePassed
? [
{
code: "valid_issue_token_floor" as const,
severity: "context" as const,
detail: `Source token score ${roundScore(nonNegative(input.sourceTokenScore))} is below the upstream valid-issue floor ${core.gates.validIssueTokenFloor}; this solve may not count toward valid issue-discovery history.`,
},
]
: []),
...(core.gates.credibilityObserved < core.gates.credibilityFloor
? [
{
Expand Down
61 changes: 61 additions & 0 deletions src/services/score-breakdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,64 @@ function openIssueBreakdown(preview: ScorePreviewResult): ScoreMultiplierBreakdo
};
}

function mergedHistoryBreakdown(preview: ScorePreviewResult): ScoreMultiplierBreakdown {
const { mergedHistoryMultiplier } = preview.scoreEstimate;
const { mergedPrFloor, mergedPullRequests } = preview.gates;
const band = bandForMultiplier(mergedHistoryMultiplier);
return {
component: "mergedHistoryMultiplier",
band,
summary:
mergedHistoryMultiplier >= 1
? mergedPullRequests !== undefined
? `Merged PR history (${mergedPullRequests}) meets the upstream floor (${mergedPrFloor}).`
: "Merged PR history is unknown; the upstream merged-history floor is not blocking this preview."
: `Merged PR history (${mergedPullRequests ?? 0}) is below the upstream floor (${mergedPrFloor}).`,
lever:
mergedHistoryMultiplier >= 1
? "Continue building clean merged PR history on this repo."
: "Land more merged PRs on this repo before relying on full-strength previews.",
leverageScore: mergedHistoryMultiplier >= 1 ? 12 : 90,
};
}

function issueDiscoveryHistoryBreakdown(preview: ScorePreviewResult): ScoreMultiplierBreakdown {
const { issueDiscoveryHistoryMultiplier } = preview.scoreEstimate;
const { validSolvedIssues, validSolvedIssuesFloor, issueCredibility, issueCredibilityFloor } = preview.gates;
const band = bandForMultiplier(issueDiscoveryHistoryMultiplier);
return {
component: "issueDiscoveryHistoryMultiplier",
band,
summary:
issueDiscoveryHistoryMultiplier >= 1
? validSolvedIssues !== undefined && issueCredibility !== undefined
? `Issue-discovery history (${validSolvedIssues} valid solved, credibility ${roundBand(issueCredibility)}) meets upstream floors.`
: "Issue-discovery history is unknown; validity floors are not blocking this preview."
: `Issue-discovery history (${validSolvedIssues ?? 0} valid solved, credibility ${roundBand(issueCredibility ?? 0)}) is below upstream floors (${validSolvedIssuesFloor} valid solved, ${issueCredibilityFloor} credibility).`,
lever:
issueDiscoveryHistoryMultiplier >= 1
? "Keep building valid solved-issue history with strong issue credibility."
: "Close more valid solved issues and improve issue credibility before relying on issue-discovery scoring.",
leverageScore: issueDiscoveryHistoryMultiplier >= 1 ? 15 : 88,
};
}

function validIssueTokenBreakdown(preview: ScorePreviewResult): ScoreMultiplierBreakdown {
const { validIssueTokenGatePassed, validIssueTokenFloor } = preview.gates;
const band: ScoreMultiplierBand = validIssueTokenGatePassed ? "full" : "reduced";
return {
component: "validIssueTokenGate",
band,
summary: validIssueTokenGatePassed
? `Source change size meets the upstream valid-issue token floor (${validIssueTokenFloor}).`
: `Source change size is below the upstream valid-issue token floor (${validIssueTokenFloor}), so this linked solve may not count toward valid issue-discovery history.`,
lever: validIssueTokenGatePassed
? "Keep the linked solve clearly scoped with substantive source changes."
: "Increase meaningful source changes so the linked issue solve can count as valid issue-discovery history upstream.",
leverageScore: validIssueTokenGatePassed ? 10 : 55,
};
}

function credibilityBreakdown(preview: ScorePreviewResult): ScoreMultiplierBreakdown {
const { credibilityMultiplier } = preview.scoreEstimate;
const { credibilityObserved, credibilityFloor } = preview.gates;
Expand Down Expand Up @@ -235,10 +293,13 @@ export function explainScoreBreakdown(preview: ScorePreviewResult): ScoreBreakdo
contributionBonusBreakdown(preview),
labelMultiplierBreakdown(preview),
issueMultiplierBreakdown(preview),
validIssueTokenBreakdown(preview),
credibilityBreakdown(preview),
reviewPenaltyBreakdown(preview),
openPrBreakdown(preview),
openIssueBreakdown(preview),
mergedHistoryBreakdown(preview),
issueDiscoveryHistoryBreakdown(preview),
].map((entry) => ({
...entry,
summary: sanitizePublicComment(entry.summary),
Expand Down
Loading
Loading