11import {
2- countOpenIssues,
3- countOpenPullRequests,
42 listOpenItemsForAuthorAcrossInstall,
53 type OpenItemAcrossInstallRow,
64 getAgentCommandAnswer,
75 getInstallation,
8- getLatestRepoGithubTotalsSnapshot,
96 getFreshOfficialMinerDetection,
107 getPullRequest,
118 getPullRequestDetailSyncState,
@@ -27,8 +24,6 @@ import {
2724 listIssues,
2825 listIssueSignalSample,
2926 listLatestSignalSnapshotsByTarget,
30- listSignalSnapshots,
31- listRepoGithubTotalsSnapshotHistory,
3227 listOtherOpenPullRequests,
3328 listOtherOpenPullRequestsForAuthor,
3429 listOpenIssues,
@@ -37,7 +32,6 @@ import {
3732 listPullRequestFiles,
3833 listRecentMergedPullRequests,
3934 updatePullRequestSlopAssessment,
40- listRepoLabels,
4135 listRepoPullRequestFilePaths,
4236 listRepoSyncStates,
4337 listRepoSyncSegments,
@@ -87,8 +81,6 @@ import {
8781 recordAiUsageEvent,
8882 persistSignalSnapshot,
8983 recordWebhookEvent,
90- replaceCollisionEdges,
91- upsertRepoQueueTrendSnapshot,
9284 upsertAgentCommandAnswer,
9385 upsertCheckSummary,
9486 upsertOfficialMinerDetection,
@@ -328,14 +320,6 @@ import { processSubmitDraft } from "../services/draft";
328320import { loadIssueQualityReportMap } from "../services/issue-quality";
329321import { generateWeeklyValueReport } from "../services/weekly-value-report";
330322import { generateAndSendReviewRecap } from "../services/review-recap";
331- import {
332- REPO_OUTCOME_PATTERNS_SIGNAL,
333- computeRepoOutcomePatterns,
334- } from "../services/repo-outcome-patterns";
335- import {
336- buildQueueTrendReport,
337- QUEUE_TREND_HISTORY_DAYS,
338- } from "../services/queue-trends";
339323import {
340324 fileUpstreamDriftIssues,
341325 refreshUpstreamDrift,
@@ -346,21 +330,14 @@ import {
346330} from "../signals/data-quality";
347331import {
348332 buildBurdenForecast,
349- buildCollisionEdges,
350333 buildCollisionReport,
351334 isPullRequestInDuplicateCluster,
352- buildConfigQuality,
353335 buildContributorFit,
354336 buildContributorOutcomeHistory,
355337 buildContributorProfile,
356338 buildContributorScoringProfile,
357339 buildContributorStrategy,
358340 buildDuplicateWinnerRelatedWorkView,
359- buildContributorIntakeHealth,
360- buildIssueQualityReport,
361- buildLabelAudit,
362- buildMaintainerCutReadiness,
363- buildMaintainerLaneReport,
364341 buildPreflightResult,
365342 buildPublicPrIntelligenceComment,
366343 buildPublicPrPanelSignalRows,
@@ -393,6 +370,14 @@ import {
393370// unchanged -- those tests are deeply interspersed with unrelated ones in that file family, not in a cleanly
394371// extractable describe block, so relocating them is deliberately deferred rather than forced into this PR.
395372export { claimPrActuationLock, releasePrActuationLock } from "./transient-locks";
373+ // #4013 step 2: same shim shape for generateSignalSnapshots -- imported here for processJob's own internal
374+ // call below, and re-exported so src/api/routes.ts and test/unit/queue-trends.test.ts's existing
375+ // `import { generateSignalSnapshots } from "../../src/queue/processors"` keeps working unchanged.
376+ // loadOpenQueueCounts moved there too (it has no other callers besides generateSignalSnapshots and this
377+ // file's own buildBurdenForecasts) rather than staying here and importing back, which would have made the
378+ // two files circularly dependent.
379+ import { generateSignalSnapshots, loadOpenQueueCounts } from "./signal-snapshot";
380+ export { generateSignalSnapshots } from "./signal-snapshot";
396381import { isVisualPath } from "../review/visual/paths";
397382import { buildCapture, fetchShotContentBlock, hasSuccessfulBotCapture, resolveVisualRoutes, type CaptureRoute } from "../review/visual/capture";
398383import {
@@ -5354,203 +5339,6 @@ async function buildBurdenForecasts(
53545339 }
53555340}
53565341
5357- export async function generateSignalSnapshots(
5358- env: Env,
5359- repoFullName?: string,
5360- ): Promise<void> {
5361- const repositories = (await listRepositories(env)).filter(
5362- (repo) =>
5363- repo.isRegistered && (!repoFullName || repo.fullName === repoFullName),
5364- );
5365- for (const repo of repositories) {
5366- const trendSince = new Date(
5367- Date.now() - QUEUE_TREND_HISTORY_DAYS * 24 * 60 * 60 * 1000,
5368- ).toISOString();
5369- const [
5370- issues,
5371- pullRequests,
5372- recentMergedPullRequests,
5373- labels,
5374- queueCounts,
5375- bounties,
5376- totalsHistory,
5377- queueHealthHistory,
5378- ] = await Promise.all([
5379- listIssueSignalSample(env, repo.fullName),
5380- listOpenPullRequests(env, repo.fullName),
5381- listRecentMergedPullRequests(env, repo.fullName),
5382- listRepoLabels(env, repo.fullName),
5383- loadOpenQueueCounts(env, repo.fullName),
5384- listBountiesByRepo(env, repo.fullName),
5385- listRepoGithubTotalsSnapshotHistory(env, repo.fullName, {
5386- sinceIso: trendSince,
5387- limit: 120,
5388- }),
5389- listSignalSnapshots(env, "queue-health", repo.fullName),
5390- ]);
5391- const collisions = buildCollisionReport(
5392- repo.fullName,
5393- issues,
5394- pullRequests,
5395- recentMergedPullRequests,
5396- );
5397- const queueHealth = buildQueueHealth(
5398- repo,
5399- issues,
5400- pullRequests,
5401- collisions,
5402- queueCounts,
5403- );
5404- const configQuality = buildConfigQuality(
5405- repo,
5406- issues,
5407- pullRequests,
5408- repo.fullName,
5409- );
5410- const labelAudit = buildLabelAudit(
5411- repo,
5412- labels,
5413- issues,
5414- pullRequests,
5415- repo.fullName,
5416- );
5417- const maintainerLane = buildMaintainerLaneReport(
5418- repo,
5419- issues,
5420- pullRequests,
5421- repo.fullName,
5422- collisions,
5423- queueCounts,
5424- );
5425- const maintainerCutReadiness = buildMaintainerCutReadiness(
5426- repo,
5427- issues,
5428- pullRequests,
5429- repo.fullName,
5430- queueCounts,
5431- collisions,
5432- );
5433- const contributorIntakeHealth = buildContributorIntakeHealth(
5434- repo,
5435- issues,
5436- pullRequests,
5437- repo.fullName,
5438- collisions,
5439- queueCounts,
5440- );
5441- const issueQuality = buildIssueQualityReport(
5442- repo,
5443- issues,
5444- pullRequests,
5445- repo.fullName,
5446- bounties,
5447- collisions,
5448- recentMergedPullRequests,
5449- );
5450- await replaceCollisionEdges(
5451- env,
5452- repo.fullName,
5453- buildCollisionEdges(collisions),
5454- );
5455- const generatedAt = new Date().toISOString();
5456- await persistSignalSnapshot(env, {
5457- id: crypto.randomUUID(),
5458- signalType: "queue-health",
5459- targetKey: repo.fullName,
5460- repoFullName: repo.fullName,
5461- payload: queueHealth as unknown as Record<string, never>,
5462- generatedAt,
5463- });
5464- await upsertRepoQueueTrendSnapshot(env, {
5465- repoFullName: repo.fullName,
5466- payload: buildQueueTrendReport({
5467- repoFullName: repo.fullName,
5468- totalsSnapshots: totalsHistory,
5469- queueHealthSnapshots: queueHealthHistory,
5470- currentQueueHealth: queueHealth,
5471- generatedAt,
5472- }) as unknown as Record<string, never>,
5473- generatedAt,
5474- });
5475- await persistSignalSnapshot(env, {
5476- id: crypto.randomUUID(),
5477- signalType: "config-quality",
5478- targetKey: repo.fullName,
5479- repoFullName: repo.fullName,
5480- payload: configQuality as unknown as Record<string, never>,
5481- generatedAt,
5482- });
5483- await persistSignalSnapshot(env, {
5484- id: crypto.randomUUID(),
5485- signalType: "label-audit",
5486- targetKey: repo.fullName,
5487- repoFullName: repo.fullName,
5488- payload: labelAudit as unknown as Record<string, never>,
5489- generatedAt,
5490- });
5491- await persistSignalSnapshot(env, {
5492- id: crypto.randomUUID(),
5493- signalType: "maintainer-lane",
5494- targetKey: repo.fullName,
5495- repoFullName: repo.fullName,
5496- payload: maintainerLane as unknown as Record<string, never>,
5497- generatedAt,
5498- });
5499- await persistSignalSnapshot(env, {
5500- id: crypto.randomUUID(),
5501- signalType: "maintainer-cut-readiness",
5502- targetKey: repo.fullName,
5503- repoFullName: repo.fullName,
5504- payload: maintainerCutReadiness as unknown as Record<string, never>,
5505- generatedAt,
5506- });
5507- await persistSignalSnapshot(env, {
5508- id: crypto.randomUUID(),
5509- signalType: "contributor-intake-health",
5510- targetKey: repo.fullName,
5511- repoFullName: repo.fullName,
5512- payload: contributorIntakeHealth as unknown as Record<string, never>,
5513- generatedAt,
5514- });
5515- await persistSignalSnapshot(env, {
5516- id: crypto.randomUUID(),
5517- signalType: "issue-quality",
5518- targetKey: repo.fullName,
5519- repoFullName: repo.fullName,
5520- payload: issueQuality as unknown as Record<string, never>,
5521- generatedAt,
5522- });
5523- const repoOutcomePatterns = await computeRepoOutcomePatterns(
5524- env,
5525- repo.fullName,
5526- repo,
5527- );
5528- await persistSignalSnapshot(env, {
5529- id: crypto.randomUUID(),
5530- signalType: REPO_OUTCOME_PATTERNS_SIGNAL,
5531- targetKey: repo.fullName,
5532- repoFullName: repo.fullName,
5533- payload: repoOutcomePatterns as unknown as Record<string, never>,
5534- generatedAt,
5535- });
5536- }
5537- }
5538-
5539- async function loadOpenQueueCounts(
5540- env: Env,
5541- repoFullName: string,
5542- ): Promise<{ openIssues: number; openPullRequests: number }> {
5543- const [totals, openIssues, openPullRequests] = await Promise.all([
5544- getLatestRepoGithubTotalsSnapshot(env, repoFullName),
5545- countOpenIssues(env, repoFullName),
5546- countOpenPullRequests(env, repoFullName),
5547- ]);
5548- return {
5549- openIssues: totals?.openIssuesTotal ?? openIssues,
5550- openPullRequests: totals?.openPullRequestsTotal ?? openPullRequests,
5551- };
5552- }
5553-
55545342/**
55555343 * True when one row from listOpenItemsForAuthorAcrossInstall is CONFIRMED still open on GitHub right now
55565344 * (#2562 gate-review follow-up): the stored DB cache can lag GitHub for a repo OTHER than the one this
0 commit comments