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
6 changes: 5 additions & 1 deletion src/queue/processors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4715,9 +4715,13 @@ export async function buildBurdenForecasts(
env: Env,
repoFullName?: string,
): Promise<void> {
// Burden forecasting is generic repo-health forecasting, unrelated to subnet economics -- it should
// cover every repo this instance operates on (isInstalled), not just gittensor-subnet-registered ones
// (isRegistered), so a self-host operator's installed-but-unregistered repos aren't left with zero
// coverage (#5022, part of the isRegistered->isInstalled untangling epic #5016).
const repositories = (await listRepositories(env)).filter(
(repo) =>
repo.isRegistered && (!repoFullName || repo.fullName === repoFullName),
repo.isInstalled && (!repoFullName || repo.fullName === repoFullName),
);
for (const repo of repositories) {
const [issues, pullRequests, recentMergedPullRequests, queueCounts] =
Expand Down
24 changes: 23 additions & 1 deletion test/unit/queue.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ import {
listReviewSuppressions,
setGlobalAgentFrozen,
} from "../../src/db/repositories";
import { agentMaintenanceHeadMatchesGate, changedPathsForGuardrail, claimAiReviewLock, claimPrActuationLock, contributorEvidenceBatchSize, enrichOpenPullRequestsWithChangedFiles, processJob, reconcileLiveDuplicateSiblings, releaseAiReviewLock, releasePrActuationLock, reviewDurationMsSince, SWEEP_FANOUT_RESOLUTION_CONCURRENCY } from "../../src/queue/processors";
import { agentMaintenanceHeadMatchesGate, buildBurdenForecasts, changedPathsForGuardrail, claimAiReviewLock, claimPrActuationLock, contributorEvidenceBatchSize, enrichOpenPullRequestsWithChangedFiles, processJob, reconcileLiveDuplicateSiblings, releaseAiReviewLock, releasePrActuationLock, reviewDurationMsSince, SWEEP_FANOUT_RESOLUTION_CONCURRENCY } from "../../src/queue/processors";
import type { PullRequestRecord } from "../../src/types";
import { aiReviewCacheInputFingerprint } from "../../src/review/ai-review-cache-input";
import { fingerprint as reviewMemoryFingerprint } from "../../src/review/review-memory-match";
Expand Down Expand Up @@ -398,6 +398,9 @@ describe("queue processors", () => {
await processJob(env, { type: "refresh-contributor-activity", requestedBy: "test", login: "oktofeesh1", repoFullName: "JSONbored/gittensory" });
await processJob(env, { type: "build-contributor-evidence", requestedBy: "test" });
await processJob(env, { type: "build-contributor-decision-packs", requestedBy: "test" });
// buildBurdenForecasts fans out on isInstalled, not isRegistered (#5022) -- mark the repo installed
// (refresh-registry above only sets isRegistered) so this generic repo-health forecast still runs.
await upsertRepositoryFromGitHub(env, { name: "gittensory", full_name: "JSONbored/gittensory", private: true, owner: { login: "JSONbored" } }, 555);
await processJob(env, { type: "build-burden-forecasts", requestedBy: "test", repoFullName: "JSONbored/gittensory" });
await processJob(env, { type: "refresh-contributor-activity", requestedBy: "test", login: "oktofeesh1" });
await processJob(env, {
Expand Down Expand Up @@ -458,6 +461,25 @@ describe("queue processors", () => {
);
});

it("fans out burden forecasts by isInstalled, not isRegistered (#5022 regression)", async () => {
const env = createTestEnv();
vi.spyOn(repositoriesModule, "listRepositories").mockResolvedValue([
// Installed but not gittensor-subnet-registered: burden forecasting is generic repo-health
// tracking unrelated to subnet economics, so this repo MUST still be covered.
{ fullName: "acme/installed-not-registered", owner: "acme", name: "installed-not-registered", isInstalled: true, isRegistered: false, isPrivate: false },
// Subnet-registered but not installed on this instance: this repo must NOT be covered -- it is
// not one this instance operates on.
{ fullName: "acme/registered-not-installed", owner: "acme", name: "registered-not-installed", isInstalled: false, isRegistered: true, isPrivate: false },
]);

await buildBurdenForecasts(env);

await expect(getBurdenForecast(env, "acme/installed-not-registered")).resolves.toMatchObject({
repoFullName: "acme/installed-not-registered",
});
await expect(getBurdenForecast(env, "acme/registered-not-installed")).resolves.toBeNull();
});

it("runs queued agent jobs through the queue processor", async () => {
const queued: unknown[] = [];
const env = createTestEnv({
Expand Down