diff --git a/src/signals/engine.ts b/src/signals/engine.ts index 04466444ec..c5b6e6b7b3 100644 --- a/src/signals/engine.ts +++ b/src/signals/engine.ts @@ -3844,7 +3844,7 @@ function queuePressureComponent(queueHealth: QueueHealth): { score: number; max: const cachedOpenPullRequests = Math.max(0, signals.cachedOpenPullRequests ?? signals.ageBuckets.under7Days + signals.ageBuckets.days7To30 + signals.ageBuckets.over30Days); const likelyReviewablePullRequests = Math.max(0, Math.min(openPullRequests, signals.likelyReviewablePullRequests)); const sampledLikelyReviewable = signals.likelyReviewablePullRequestsSource === "sampled_cache" || (signals.likelyReviewablePullRequestsSource === undefined && cachedOpenPullRequests < openPullRequests); - const score = queuePressureScore(openPullRequests); + const score = queuePressureScore(queueHealth, openPullRequests); const likelyEvidence = openPullRequests === 0 ? "0 likely reviewable" @@ -3867,13 +3867,25 @@ function queuePressureComponent(queueHealth: QueueHealth): { score: number; max: }; } -function queuePressureScore(openPullRequests: number): number { +function queuePressureScore(queueHealth: QueueHealth, openPullRequests: number): number { + if (openPullRequests === 0) return 10; + return Math.min(queuePressureOpenPullRequestScore(openPullRequests), queuePressureLevelScore(queueHealth.level)); +} + +function queuePressureOpenPullRequestScore(openPullRequests: number): number { if (openPullRequests <= 4) return 10; if (openPullRequests <= 8) return 8; if (openPullRequests <= 13) return 5; return 3; } +function queuePressureLevelScore(level: QueueHealth["level"]): number { + if (level === "low") return 10; + if (level === "medium") return 8; + if (level === "high") return 5; + return 3; +} + function hasClearNoIssueRationale(pr: PullRequestRecord): boolean { return /\b(no issue\s*(?:because|:)|no linked issue\s*(?:because|:)|no ticket\s*(?:because|:)|maintenance|docs? only|typo|chore|cleanup)\b/i.test([pr.title, pr.body ?? ""].join(" ")); } diff --git a/test/unit/signals-coverage.test.ts b/test/unit/signals-coverage.test.ts index d6748e26ff..cbd329cf70 100644 --- a/test/unit/signals-coverage.test.ts +++ b/test/unit/signals-coverage.test.ts @@ -1176,6 +1176,30 @@ describe("signal coverage edge cases", () => { action: "No action.", }); + const staleQueuePullRequests = [44, 45, 46, 47].map((number) => + pr(directRepo.fullName, number, `Stale unlinked queue item ${number}`, { + updatedAt: "2020-01-01T00:00:00.000Z", + }), + ); + const criticalBurdenQueue = buildQueueHealth( + directRepo, + [], + staleQueuePullRequests, + buildCollisionReport(directRepo.fullName, [], staleQueuePullRequests), + ); + expect(criticalBurdenQueue).toMatchObject({ level: "critical", burdenScore: 100 }); + + const criticalBurdenScore = buildPublicReadinessScore({ + pr: currentPr, + preflight: { ...preflight, status: "ready", reviewBurden: "low", findings: [] }, + queueHealth: criticalBurdenQueue, + }); + expect(scoreComponent(criticalBurdenScore, "queue_pressure")).toMatchObject({ + score: 3, + evidence: "4 open PR(s), 0 likely reviewable, 4 stale, 4 unlinked.", + action: "Expect slower review.", + }); + const sampledQueue = buildQueueHealth( directRepo, [],