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
9 changes: 8 additions & 1 deletion src/queue/processors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1332,7 +1332,14 @@ async function refreshOpenPullRequestsForScheduledSweep(
requestedBy: "schedule" | "api" | "test",
): Promise<void> {
if (requestedBy !== "schedule") return;
if (!repo || !sweepOpenPullRequestSyncCredentialAvailable(env, repo)) return;
// No installation -> no per-PR regate fan-out will ever happen for this repo (the candidate-selection
// gate below only dispatches agent-regate-pr jobs for installed repos), so refreshing its open-PR list
// here only spends the shared GITHUB_PUBLIC_TOKEN budget on data nothing in THIS sweep will use. A
// registry-only repo (registry/sync.ts, isRegistered) still gets its own data kept fresh by the
// dedicated backfill-registered-repos/refresh-registry jobs, so skipping here is pure waste removal,
// not a functionality gap (#audit-rate-headroom, #sweep-uninstalled-budget-waste).
if (!repo?.installationId) return;
if (!sweepOpenPullRequestSyncCredentialAvailable(env, repo)) return;
const segment = await getRepoSyncSegment(
env,
repo.fullName,
Expand Down
48 changes: 48 additions & 0 deletions test/unit/queue.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6737,6 +6737,54 @@ describe("queue processors", () => {
warn.mockRestore();
});

it("REGRESSION (#sweep-uninstalled-budget-waste): a scheduled sweep never refreshes open PRs (via the shared GITHUB_PUBLIC_TOKEN) for a registered-but-uninstalled repo, since no per-PR fan-out will ever follow", async () => {
const sent: import("../../src/types").JobMessage[] = [];
const env = createTestEnv({
GITHUB_PUBLIC_TOKEN: "public-token",
JOBS: {
async send(m: import("../../src/types").JobMessage) {
sent.push(m);
},
} as unknown as Queue,
});
// Registered (e.g. via the subnet registry sync) but NOT installed — no installationId.
await upsertRepositoryFromGitHub(env, { name: "no-install", full_name: "owner/no-install", private: false, owner: { login: "owner" } });
await upsertRepositorySettings(env, { repoFullName: "owner/no-install", autonomy: { merge: "auto" } });
const segmentSpy = vi.spyOn(repositoriesModule, "getRepoSyncSegment");
const backfillSpy = vi.spyOn(backfillModule, "backfillRepositorySegment");
vi.setSystemTime(new Date("2026-05-28T02:00:00.000Z"));

await processJob(env, { type: "agent-regate-sweep", requestedBy: "schedule", repoFullName: "owner/no-install" });

expect(segmentSpy).not.toHaveBeenCalled();
expect(backfillSpy).not.toHaveBeenCalled();
expect(sent.filter((job) => job.type === "agent-regate-pr")).toEqual([]);
segmentSpy.mockRestore();
backfillSpy.mockRestore();
});

it("scheduled sweeps DO still refresh open PRs for an installed repo even when GITHUB_PUBLIC_TOKEN is also configured (installation presence gates the skip, not credential kind)", async () => {
const sent: import("../../src/types").JobMessage[] = [];
const env = createTestEnv({
GITHUB_PUBLIC_TOKEN: "public-token",
JOBS: {
async send(m: import("../../src/types").JobMessage) {
sent.push(m);
},
} as unknown as Queue,
});
await upsertInstallation(env, { action: "created", installation: { id: 9405, account: { login: "owner", id: 1, type: "Organization" }, target_type: "Organization", repository_selection: "selected", permissions: {}, events: [] } });
await upsertRepositoryFromGitHub(env, { name: "agent-repo", full_name: "owner/agent-repo", private: false, owner: { login: "owner" } }, 9405);
await upsertRepositorySettings(env, { repoFullName: "owner/agent-repo", autonomy: { merge: "auto" }, gateCheckMode: "off", checkRunMode: "off", commentMode: "off", publicSurface: "off" });
const backfillSpy = vi.spyOn(backfillModule, "backfillRepositorySegment").mockResolvedValueOnce(undefined as never);
vi.setSystemTime(new Date("2026-05-28T02:00:00.000Z"));

await processJob(env, { type: "agent-regate-sweep", requestedBy: "schedule", repoFullName: "owner/agent-repo" });

expect(backfillSpy).toHaveBeenCalledWith(env, expect.objectContaining({ segment: "open_pull_requests", mode: "light", force: true }));
backfillSpy.mockRestore();
});

it("scheduled sweeps refresh incomplete open-PR sync segments", async () => {
const sent: import("../../src/types").JobMessage[] = [];
const env = createTestEnv({
Expand Down