diff --git a/apps/loopover-ui/src/components/site/app-panels/activation-preview.tsx b/apps/loopover-ui/src/components/site/app-panels/activation-preview.tsx index 4e196d8173..cad5d91a17 100644 --- a/apps/loopover-ui/src/components/site/app-panels/activation-preview.tsx +++ b/apps/loopover-ui/src/components/site/app-panels/activation-preview.tsx @@ -37,7 +37,6 @@ type ActivationPreviewResponse = { type ActivationResponse = { repoFullName: string; reviewCheckMode: string; - checkRunMode: string; linkedIssueGateMode: string; duplicatePrGateMode: string; qualityGateMode: string; diff --git a/apps/loopover-ui/src/components/site/app-panels/gate-ramp-control.test.tsx b/apps/loopover-ui/src/components/site/app-panels/gate-ramp-control.test.tsx index b1842c2939..5b55aa5d0d 100644 --- a/apps/loopover-ui/src/components/site/app-panels/gate-ramp-control.test.tsx +++ b/apps/loopover-ui/src/components/site/app-panels/gate-ramp-control.test.tsx @@ -21,12 +21,6 @@ import { GateRampControl } from "@/components/site/app-panels/gate-ramp-control" const REVIEWABILITY = [{ pr: "acme/widgets#1" }]; const ADVISORY_SETTINGS = { - commentMode: "detected_contributors_only" as const, - publicAudienceMode: "oss_maintainer" as const, - publicSignalLevel: "standard" as const, - publicSurface: "comment_and_label" as const, - checkRunMode: "enabled" as const, - checkRunDetailLevel: "standard" as const, reviewCheckMode: "required" as const, gatePack: "gittensor" as const, linkedIssueGateMode: "advisory" as const, @@ -42,7 +36,6 @@ const ADVISORY_SETTINGS = { autoLabelEnabled: true, gittensorLabel: "gittensor", createMissingLabel: true, - includeMaintainerAuthors: false, requireLinkedIssue: false, badgeEnabled: false, publicQualityMetrics: false, @@ -108,7 +101,7 @@ describe("GateRampControl (#2218)", () => { expect(body.linkedIssueGateMode).toBe("block"); expect(body.duplicatePrGateMode).toBe("block"); expect(body.qualityGateMode).toBe("block"); - expect(body.commentMode).toBe("detected_contributors_only"); + expect(body.gittensorLabel).toBe("gittensor"); }); it("closes confirm without saving when cancel is clicked", async () => { diff --git a/apps/loopover-ui/src/components/site/app-panels/maintainer-settings.tsx b/apps/loopover-ui/src/components/site/app-panels/maintainer-settings.tsx index 483aae6bd2..26d6470445 100644 --- a/apps/loopover-ui/src/components/site/app-panels/maintainer-settings.tsx +++ b/apps/loopover-ui/src/components/site/app-panels/maintainer-settings.tsx @@ -142,65 +142,10 @@ const SLOP_FIELDS: FieldDef[] = [ }, ]; +// commentMode/publicSurface/publicSignalLevel/publicAudienceMode/checkRunMode/checkRunDetailLevel/ +// includeMaintainerAuthors moved off the dashboard entirely (Batch A, loopover#6442) -- configure them via +// this repo's own .loopover.yml settings.* block instead. const SURFACE_FIELDS: FieldDef[] = [ - { - key: "commentMode", - label: "Comment mode", - kind: "select", - options: [ - ["off", "off"], - ["detected_contributors_only", "detected contributors only"], - ["all_prs", "all PRs"], - ], - }, - { - key: "publicSurface", - label: "Public surface", - kind: "select", - options: [ - ["off", "off"], - ["comment_and_label", "comment + label"], - ["comment_only", "comment only"], - ["label_only", "label only"], - ], - }, - { - key: "publicSignalLevel", - label: "Public signal level", - kind: "select", - options: [ - ["minimal", "minimal"], - ["standard", "standard"], - ], - }, - { - key: "publicAudienceMode", - label: "Audience", - kind: "select", - options: [ - ["oss_maintainer", "OSS maintainer"], - ["gittensor_only", "gittensor only"], - ], - }, - { - key: "checkRunMode", - label: "Context check run", - kind: "select", - options: [ - ["off", "off"], - ["enabled", "enabled"], - ], - }, - { - key: "checkRunDetailLevel", - label: "Check detail", - kind: "select", - options: [ - ["minimal", "minimal"], - ["standard", "standard"], - ], - }, - { key: "includeMaintainerAuthors", label: "Include maintainer-authored PRs", kind: "toggle" }, { key: "requireLinkedIssue", label: "Require a linked issue", kind: "toggle" }, { key: "badgeEnabled", label: "Repo badge", kind: "toggle" }, { key: "publicQualityMetrics", label: "Public quality page", kind: "toggle" }, diff --git a/apps/loopover-ui/src/lib/maintainer-settings-editable.test.ts b/apps/loopover-ui/src/lib/maintainer-settings-editable.test.ts index a49841984f..5de88f2867 100644 --- a/apps/loopover-ui/src/lib/maintainer-settings-editable.test.ts +++ b/apps/loopover-ui/src/lib/maintainer-settings-editable.test.ts @@ -7,12 +7,6 @@ import { } from "@/lib/maintainer-settings-editable"; const SETTINGS: MaintainerSettingsEditable = { - commentMode: "detected_contributors_only", - publicAudienceMode: "oss_maintainer", - publicSignalLevel: "standard", - publicSurface: "comment_and_label", - checkRunMode: "enabled", - checkRunDetailLevel: "standard", reviewCheckMode: "required", gatePack: "gittensor", linkedIssueGateMode: "advisory", @@ -28,7 +22,6 @@ const SETTINGS: MaintainerSettingsEditable = { autoLabelEnabled: true, gittensorLabel: "gittensor", createMissingLabel: true, - includeMaintainerAuthors: false, requireLinkedIssue: false, badgeEnabled: false, publicQualityMetrics: false, @@ -44,7 +37,7 @@ describe("maintainer-settings-editable (#2218)", () => { const payload = buildMaintainerSettingsSavePayload(SETTINGS); expect(Object.keys(payload).sort()).toEqual([...MAINTAINER_SETTINGS_EDITABLE_KEYS].sort()); expect(payload.linkedIssueGateMode).toBe("advisory"); - expect(payload.commentMode).toBe("detected_contributors_only"); + expect(payload.gittensorLabel).toBe("gittensor"); }); it("buildMaintainerSettingsSavePayload merges a partial patch over the base settings", () => { @@ -56,7 +49,7 @@ describe("maintainer-settings-editable (#2218)", () => { expect(payload.duplicatePrGateMode).toBe("block"); // Untouched fields pass through unchanged. expect(payload.qualityGateMode).toBe("advisory"); - expect(payload.commentMode).toBe("detected_contributors_only"); + expect(payload.gittensorLabel).toBe("gittensor"); }); it("an empty patch object is a no-op (same as omitting it)", () => { diff --git a/apps/loopover-ui/src/lib/maintainer-settings-editable.ts b/apps/loopover-ui/src/lib/maintainer-settings-editable.ts index 51779e5a4e..6e790ee26b 100644 --- a/apps/loopover-ui/src/lib/maintainer-settings-editable.ts +++ b/apps/loopover-ui/src/lib/maintainer-settings-editable.ts @@ -18,12 +18,6 @@ export type AgentActionClass = export type AutoMergeMethod = "merge" | "squash" | "rebase"; export type MaintainerSettingsEditable = { - commentMode: "off" | "detected_contributors_only" | "all_prs"; - publicAudienceMode: "oss_maintainer" | "gittensor_only"; - publicSignalLevel: "minimal" | "standard"; - publicSurface: "off" | "comment_and_label" | "comment_only" | "label_only"; - checkRunMode: "off" | "enabled"; - checkRunDetailLevel: "minimal" | "standard"; // #4618/#5373: a prior gateCheckMode field was a deprecated computed read-back, since removed entirely -- // reviewCheckMode is the real, writable authority for whether the review-agent check-run publishes. reviewCheckMode: "required" | "visible" | "disabled"; @@ -41,7 +35,6 @@ export type MaintainerSettingsEditable = { autoLabelEnabled: boolean; gittensorLabel: string; createMissingLabel: boolean; - includeMaintainerAuthors: boolean; requireLinkedIssue: boolean; badgeEnabled: boolean; publicQualityMetrics: boolean; @@ -54,12 +47,6 @@ export type MaintainerSettingsEditable = { // The maintainer-editable subset, sent verbatim to PUT /settings (which merges onto current settings). export const MAINTAINER_SETTINGS_EDITABLE_KEYS: Array = [ - "commentMode", - "publicAudienceMode", - "publicSignalLevel", - "publicSurface", - "checkRunMode", - "checkRunDetailLevel", "reviewCheckMode", "gatePack", "linkedIssueGateMode", @@ -75,7 +62,6 @@ export const MAINTAINER_SETTINGS_EDITABLE_KEYS: Array, dataQuality); } +// Batch A (loopover#6442): these 9 fields moved off the DB entirely -- rawSettings (getRepositorySettings) +// always returns the same hardcoded default for them now, so a "DB vs yml" comparison built on rawSettings +// alone would be comparing a constant against yml, never reflecting a repo's real .loopover.yml-driven +// behavior. Overlays the true EFFECTIVE value for just these 9 fields onto an otherwise-raw-DB settings +// object, preserving the #2912 DB-vs-yml comparison intent for every other (still DB-backed) field. +const CONFIG_AS_CODE_ONLY_FIELDS = [ + "commentMode", + "publicAudienceMode", + "publicSignalLevel", + "checkRunMode", + "checkRunDetailLevel", + "regateSweepOrderMode", + "publicSurface", + "includeMaintainerAuthors", + "backfillEnabled", +] as const satisfies ReadonlyArray; +function applyConfigAsCodeOnlyFields(rawSettings: RepositorySettings, resolvedSettings: RepositorySettings): RepositorySettings { + const settings = { ...rawSettings }; + for (const field of CONFIG_AS_CODE_ONLY_FIELDS) (settings[field] as unknown) = resolvedSettings[field]; + return settings; +} + export async function buildRegistrationReadinessResponse(env: Env, fullName: string) { /* v8 ignore start -- Registration readiness route-level shaping over covered signal helpers. */ // Intentionally the raw DB `settings` alongside the raw (cache-only, never live-fetched) `focusManifest`, @@ -5071,12 +5069,17 @@ export async function buildRegistrationReadinessResponse(env: Env, fullName: str // relationship between the two config layers (e.g. "your yml sets X but the currently active settings say // Y"), which requires seeing them unmerged (#2912). See buildRegistrationReadiness's use of `focusManifest` // for the yml-compiled policy section, separate from `settings` for the currently-active-behavior section. - const [intelligence, settings, upstreamReports, focusManifest] = await Promise.all([ + const [intelligence, rawSettings, upstreamReports, focusManifest] = await Promise.all([ buildRepoIntelligenceResponse(env, fullName), getRepositorySettings(env, fullName), listUpstreamDriftReports(env, 20), loadRepoFocusManifest(env, fullName, { fetcher: async () => null }), ]); + // Batch A (loopover#6442): the 9 config-as-code-only fields no longer have an independent DB value to + // compare against yml (#2912's rationale doesn't apply to them anymore -- `rawSettings` would always show + // the same hardcoded default), so overlay the real EFFECTIVE value for those specific fields onto the raw + // DB settings used for everything else. + const settings = applyConfigAsCodeOnlyFields(rawSettings, resolveEffectiveSettings(rawSettings, focusManifest)); const repo = intelligence.repo; const installation = await loadInstallationHealthSummary(env, repo); const report = buildRegistrationReadiness({ @@ -5128,8 +5131,13 @@ export async function buildGittensorConfigRecommendationResponse(env: Env, fullN // to ADD to .loopover.yml based on the repo's currently-active (dashboard/API-configured) behavior — using // the yml-merged view here would be comparing the recommendation against itself once a yml override exists // (#2912). - const intelligence = await buildRepoIntelligenceResponse(env, fullName); - const settings = await getRepositorySettings(env, fullName); + const [intelligence, rawSettings, resolvedSettings] = await Promise.all([ + buildRepoIntelligenceResponse(env, fullName), + getRepositorySettings(env, fullName), + resolveRepositorySettings(env, fullName), + ]); + // Batch A (loopover#6442): see buildRegistrationReadinessResponse's identical comment above. + const settings = applyConfigAsCodeOnlyFields(rawSettings, resolvedSettings); const repo = intelligence.repo; const recommendation = buildGittensorConfigRecommendation({ repoFullName: fullName, diff --git a/src/db/repositories.ts b/src/db/repositories.ts index 73970508a0..44e746024f 100644 --- a/src/db/repositories.ts +++ b/src/db/repositories.ts @@ -656,12 +656,15 @@ export async function getRepositorySettings(env: Env, fullName: string): Promise } return { repoFullName: row.repoFullName, - commentMode: parseCommentMode(row.commentMode), - publicAudienceMode: parsePublicAudienceMode(row.publicAudienceMode), - publicSignalLevel: row.publicSignalLevel === "minimal" ? "minimal" : "standard", - checkRunMode: parseCheckRunMode(row.checkRunMode), - checkRunDetailLevel: parseCheckRunDetailLevel(row.checkRunDetailLevel), - regateSweepOrderMode: parseRegateSweepOrderMode(row.regateSweepOrderMode), + // Config-as-code only (Batch A, loopover#6442): no DB column backs these 9 fields anymore -- the + // built-in default here is unconditional (not row-dependent), matching the !row branch above. + // resolveEffectiveSettings still overlays a repo's .loopover.yml settings.* value over this default. + commentMode: "detected_contributors_only", + publicAudienceMode: "oss_maintainer", + publicSignalLevel: "standard", + checkRunMode: "off", + checkRunDetailLevel: "minimal", + regateSweepOrderMode: "staleness", reviewCheckMode: parseReviewCheckMode(row.reviewCheckMode), autoProjectMilestoneMatch: parseProjectMilestoneMatchMode(row.projectMilestoneMatchMode), autoProjectMilestoneMatchBackend: parseProjectMilestoneMatchBackend(row.autoProjectMilestoneMatchBackend), @@ -693,10 +696,11 @@ export async function getRepositorySettings(env: Env, fullName: string): Promise gittensorLabel: row.gittensorLabel, blacklistLabel: row.blacklistLabel, createMissingLabel: row.createMissingLabel, - publicSurface: parsePublicSurface(row.publicSurface), - includeMaintainerAuthors: row.includeMaintainerAuthors, + // Config-as-code only (Batch A, loopover#6442): see the comment on the reviewCheckMode block above. + publicSurface: "comment_and_label", + includeMaintainerAuthors: false, requireLinkedIssue: row.requireLinkedIssue, - backfillEnabled: row.backfillEnabled, + backfillEnabled: true, badgeEnabled: row.badgeEnabled, publicQualityMetrics: row.publicQualityMetrics, agentPaused: row.agentPaused, @@ -773,12 +777,16 @@ export async function upsertRepositorySettings(env: Env, settings: Partial(value, null)).policy; } diff --git a/src/db/schema.ts b/src/db/schema.ts index f3aed66ea7..9b354abd20 100644 --- a/src/db/schema.ts +++ b/src/db/schema.ts @@ -45,14 +45,6 @@ export const repositories = sqliteTable("repositories", { export const repositorySettings = sqliteTable("repository_settings", { repoFullName: text("repo_full_name").primaryKey(), - commentMode: text("comment_mode").notNull().default("detected_contributors_only"), - publicAudienceMode: text("public_audience_mode").notNull().default("oss_maintainer"), - publicSignalLevel: text("public_signal_level").notNull().default("standard"), - checkRunMode: text("check_run_mode").notNull().default("off"), - checkRunDetailLevel: text("check_run_detail_level").notNull().default("minimal"), - // Scheduled re-gate sweep candidate ordering (#3815). staleness | oldest-first. Default staleness — see - // RepositorySettings["regateSweepOrderMode"] for the full convergence-guarantee rationale. - regateSweepOrderMode: text("regate_sweep_order_mode").notNull().default("staleness"), reviewCheckMode: text("review_check_mode").notNull().default("disabled"), projectMilestoneMatchMode: text("project_milestone_match_mode").notNull().default("off"), autoProjectMilestoneMatchBackend: text("auto_project_milestone_match_backend").notNull().default("github"), @@ -110,10 +102,7 @@ export const repositorySettings = sqliteTable("repository_settings", { // Linked-issue label propagation (#priority-linked-issue-gate): the only mechanism that can select the // configured priority label -- never inferred from title/files/AI/PR-labels. Default disabled, no mappings. linkedIssueLabelPropagationJson: text("linked_issue_label_propagation_json").notNull().default("{}"), - publicSurface: text("public_surface").notNull().default("comment_and_label"), - includeMaintainerAuthors: integer("include_maintainer_authors", { mode: "boolean" }).notNull().default(false), requireLinkedIssue: integer("require_linked_issue", { mode: "boolean" }).notNull().default(false), - backfillEnabled: integer("backfill_enabled", { mode: "boolean" }).notNull().default(true), badgeEnabled: integer("badge_enabled", { mode: "boolean" }).notNull().default(false), publicQualityMetrics: integer("public_quality_metrics", { mode: "boolean" }).notNull().default(false), commandAuthorizationJson: text("command_authorization_json").notNull().default("{}"), diff --git a/src/services/maintainer-activation.ts b/src/services/maintainer-activation.ts index bfc064bfca..fb2b5a6a79 100644 --- a/src/services/maintainer-activation.ts +++ b/src/services/maintainer-activation.ts @@ -115,11 +115,14 @@ function buildSummary(evaluated: number, withFindings: number, currentlyActive: */ export function recommendedAdvisoryActivationSettings(): Pick< RepositorySettings, - "reviewCheckMode" | "checkRunMode" | "linkedIssueGateMode" | "duplicatePrGateMode" | "qualityGateMode" + "reviewCheckMode" | "linkedIssueGateMode" | "duplicatePrGateMode" | "qualityGateMode" > { + // checkRunMode moved off the DB entirely (Batch A, loopover#6442) -- writing it via upsertRepositorySettings + // is now a silent no-op, so it's dropped from this one-click patch rather than pretending to activate it. + // Turning check-run mode on now requires a repo's own .loopover.yml settings.checkRunMode -- there is no + // config-as-code write mechanism this one-click action can use to set that on the maintainer's behalf. return { reviewCheckMode: "required", - checkRunMode: "enabled", linkedIssueGateMode: "advisory", duplicatePrGateMode: "advisory", qualityGateMode: "advisory", diff --git a/test/integration/api.test.ts b/test/integration/api.test.ts index d7020df770..ff173263aa 100644 --- a/test/integration/api.test.ts +++ b/test/integration/api.test.ts @@ -411,18 +411,6 @@ describe("api routes", () => { await expect(response.json()).resolves.toMatchObject({ repoFullName: "acme/badged", badgeEnabled: true }); }); - it("REGRESSION (#2907): defaults checkRunDetailLevel to minimal, matching the DB column's own default, when omitted", async () => { - const app = createApp(); - const env = createTestEnv(); - const response = await app.request( - "/v1/internal/repos/acme/detail-level-default/settings", - { method: "POST", headers: { authorization: `Bearer ${env.INTERNAL_JOB_TOKEN}`, "content-type": "application/json" }, body: JSON.stringify({ checkRunMode: "enabled" }) }, - env, - ); - expect(response.status).toBe(200); - await expect(response.json()).resolves.toMatchObject({ checkRunMode: "enabled", checkRunDetailLevel: "minimal" }); - }); - it("downgrades qualityGateMode: block to advisory through the internal settings write endpoint too (#2267)", async () => { // Readiness/quality can never hard-block a PR — the internal full-settings write path (used by tooling, // not just the maintainer dashboard) gets the identical downgrade so it can't persist "block" either. @@ -2171,6 +2159,10 @@ describe("api routes", () => { // .loopover.yml succeeds via GitHub's repo-rename redirect and returns the CURRENT (broader) autonomy // grant, which would upgrade requiredPermissions beyond what this test asserts. vi.stubGlobal("fetch", async () => new Response("Not Found", { status: 404 })); + // commentMode/publicSurface/checkRunMode moved off the DB entirely (Batch A, loopover#6442) -- the + // hardcoded defaults (commentMode: detected_contributors_only, publicSurface: comment_and_label, + // checkRunMode: off) already satisfy usesCommentMode/usesLabelMode's conditions below, so no manifest + // override is needed for this first assertion block. await upsertRepositorySettings(env, { repoFullName: "JSONbored/gittensory", autoLabelEnabled: true, @@ -4621,7 +4613,7 @@ describe("api routes", () => { expect(queuedBurden.status).toBe(202); const queuedSignals = await app.request("/v1/internal/jobs/generate-signal-snapshots", { method: "POST", headers: internalHeaders, body: JSON.stringify({ repoFullName: "owner/repo" }) }, env); expect(queuedSignals.status).toBe(202); - expect((await app.request("/v1/internal/repos/owner/repo/settings", { method: "POST", headers: internalHeaders, body: JSON.stringify({ commentMode: "bad" }) }, env)).status).toBe(400); + expect((await app.request("/v1/internal/repos/owner/repo/settings", { method: "POST", headers: internalHeaders, body: JSON.stringify({ reviewCheckMode: "bad" }) }, env)).status).toBe(400); }); it("settings-preview never mutates GitHub state", async () => { @@ -6066,12 +6058,13 @@ describe("api routes", () => { await upsertRepositorySettings(env, { repoFullName: "entrius/allways-ui", - publicSurface: "off", requireLinkedIssue: true, autoLabelEnabled: false, createMissingLabel: false, gittensorLabel: "gittensor-miner", }); + // publicSurface moved off the DB entirely (Batch A, loopover#6442) -- set via manifest injection instead. + await upsertRepoFocusManifest(env, "entrius/allways-ui", { settings: { publicSurface: "off" } }); const directReadiness = await app.request("/v1/repos/entrius/allways-ui/registration-readiness", { headers: apiHeaders(env) }, env); expect(directReadiness.status).toBe(200); await expect(directReadiness.json()).resolves.toMatchObject({ @@ -6086,6 +6079,7 @@ describe("api routes", () => { maintainerNotes: [ "Private reviewability note with wallet, hotkey, raw trust, and farming details.", ], + settings: { publicSurface: "off" }, }); const policyReadiness = await app.request("/v1/repos/entrius/allways-ui/registration-readiness", { headers: apiHeaders(env) }, env); expect(policyReadiness.status).toBe(200); @@ -6457,7 +6451,7 @@ describe("api routes", () => { expect(signalsOne.status).toBe(202); const invalidSettings = await app.request( "/v1/internal/repos/owner/repo/settings", - { method: "POST", headers: { authorization: `Bearer ${env.INTERNAL_JOB_TOKEN}` }, body: JSON.stringify({ commentMode: "loud" }) }, + { method: "POST", headers: { authorization: `Bearer ${env.INTERNAL_JOB_TOKEN}` }, body: JSON.stringify({ reviewCheckMode: "loud" }) }, env, ); expect(invalidSettings.status).toBe(400); @@ -6539,7 +6533,7 @@ describe("api routes", () => { "/v1/internal/repos/entrius/allways-ui/settings", { method: "POST", - body: JSON.stringify({ commentMode: "detected_contributors_only", publicSignalLevel: "minimal" }), + body: JSON.stringify({ gatePack: "oss-anti-slop" }), }, env, ); @@ -6551,8 +6545,6 @@ describe("api routes", () => { method: "POST", headers: { authorization: `Bearer ${env.INTERNAL_JOB_TOKEN}` }, body: JSON.stringify({ - commentMode: "detected_contributors_only", - publicSignalLevel: "minimal", gatePack: "oss-anti-slop", commandAuthorization: { default: ["maintainer"], commands: { preflight: ["pr_author"], "queue-summary": ["maintainer", "collaborator"] } }, }), @@ -6561,15 +6553,13 @@ describe("api routes", () => { ); expect(updated.status).toBe(200); await expect(updated.json()).resolves.toMatchObject({ - commentMode: "detected_contributors_only", - publicSignalLevel: "minimal", gatePack: "oss-anti-slop", commandAuthorization: { default: ["maintainer"], commands: expect.objectContaining({ preflight: ["pr_author"] }) }, }); const settings = await app.request("/v1/repos/entrius/allways-ui/settings", { headers: apiHeaders(env) }, env); expect(settings.status).toBe(200); - await expect(settings.json()).resolves.toMatchObject({ commentMode: "detected_contributors_only", gatePack: "oss-anti-slop", commandAuthorization: { commands: expect.objectContaining({ preflight: ["pr_author"] }) } }); + await expect(settings.json()).resolves.toMatchObject({ gatePack: "oss-anti-slop", commandAuthorization: { commands: expect.objectContaining({ preflight: ["pr_author"] }) } }); const preview = await app.request( "/v1/repos/entrius/allways-ui/settings-preview", diff --git a/test/integration/routes-errors.test.ts b/test/integration/routes-errors.test.ts index 16ea9cf49f..c98d3e8942 100644 --- a/test/integration/routes-errors.test.ts +++ b/test/integration/routes-errors.test.ts @@ -1095,7 +1095,7 @@ describe("api route guards and error branches", () => { await app.request("/v1/internal/repos/JSONbored/gittensory/settings", { method: "POST", headers: internalHeaders(env), - body: JSON.stringify({ commentMode: "bad" }), + body: JSON.stringify({ reviewCheckMode: "bad" }), }, env) ).status, ).toBe(400); @@ -1184,16 +1184,15 @@ describe("api route guards and error branches", () => { method: "POST", headers: internalHeaders(env), body: JSON.stringify({ - commentMode: "all_prs", - publicSignalLevel: "minimal", - checkRunDetailLevel: "standard", - backfillEnabled: false, + gatePack: "oss-anti-slop", + createMissingLabel: false, + badgeEnabled: true, }), }, env, ); expect(updated.status).toBe(200); - await expect(updated.json()).resolves.toMatchObject({ commentMode: "all_prs", checkRunDetailLevel: "standard", backfillEnabled: false }); + await expect(updated.json()).resolves.toMatchObject({ gatePack: "oss-anti-slop", createMissingLabel: false, badgeEnabled: true }); }); it("exposes and clears self-tune overrides for operators, rejecting unauthorized callers (#6168)", async () => { diff --git a/test/unit/backfill.test.ts b/test/unit/backfill.test.ts index fe93950860..ef398a38a4 100644 --- a/test/unit/backfill.test.ts +++ b/test/unit/backfill.test.ts @@ -30,6 +30,7 @@ import { upsertRepositoryFromGitHub, upsertRepositorySettings, } from "../../src/db/repositories"; +import { upsertRepoFocusManifest } from "../../src/signals/focus-manifest-loader"; import { backfillOpenPullRequestDetails, backfillRegisteredRepositories, @@ -62,7 +63,6 @@ import { } from "../../src/github/client"; import { normalizeRegistryPayload } from "../../src/registry/normalize"; import { persistRegistrySnapshot } from "../../src/registry/sync"; -import { upsertRepoFocusManifest } from "../../src/signals/focus-manifest-loader"; import { renderMetrics, resetMetrics } from "../../src/selfhost/metrics"; import { createTestEnv } from "../helpers/d1"; @@ -1010,6 +1010,7 @@ describe("GitHub backfill", () => { await upsertRepositorySettings(env, { repoFullName: "JSONbored/gittensory", }); + // checkRunMode moved off the DB entirely (Batch A, loopover#6442) -- set via manifest injection instead. await upsertRepoFocusManifest(env, "JSONbored/gittensory", { settings: { checkRunMode: "enabled" } }); vi.stubGlobal("fetch", async (input: RequestInfo | URL) => { const url = input.toString(); @@ -1180,13 +1181,10 @@ describe("GitHub backfill", () => { repoFullName: "JSONbored/gittensory", autoLabelEnabled: false, }); - await upsertRepoFocusManifest(env, "JSONbored/gittensory", { - settings: { commentMode: "off", publicSurface: "off", checkRunMode: "off" }, - }); - // Without this, the manifest resolver's live (unmocked) GitHub fetch for "JSONbored/gittensory"'s - // .loopover.yml actually succeeds -- GitHub's repo-rename redirect resolves it to this same repo's - // CURRENT .loopover.yml, which now grants full agent autonomy -- silently upgrading the required - // permissions this test asserts are absent. Force the fetch to a deterministic 404 instead. + // commentMode/publicSurface/checkRunMode moved off the DB entirely (Batch A, loopover#6442) -- set via + // manifest injection instead. The pre-cached row means the loader never calls fetch for this repo, but + // stub it defensively anyway so this test never depends on live network either way. + await upsertRepoFocusManifest(env, "JSONbored/gittensory", { settings: { commentMode: "off", publicSurface: "off", checkRunMode: "off" } }); vi.stubGlobal("fetch", async () => new Response("Not Found", { status: 404 })); const repair = await buildInstallationRepairDiagnostics(env, { @@ -1425,6 +1423,8 @@ describe("GitHub backfill", () => { await upsertRepositorySettings(env, { repoFullName: "JSONbored/gittensory", }); + // commentMode/publicSignalLevel/checkRunMode/checkRunDetailLevel/backfillEnabled moved off the DB + // entirely (Batch A, loopover#6442) -- set via manifest injection instead. await upsertRepoFocusManifest(env, "JSONbored/gittensory", { settings: { commentMode: "off", publicSignalLevel: "standard", checkRunMode: "enabled", checkRunDetailLevel: "standard", backfillEnabled: false }, }); diff --git a/test/unit/maintainer-activation.test.ts b/test/unit/maintainer-activation.test.ts index 4fd847741c..baca1ca834 100644 --- a/test/unit/maintainer-activation.test.ts +++ b/test/unit/maintainer-activation.test.ts @@ -239,7 +239,6 @@ describe("recommendedAdvisoryActivationSettings", () => { it("enables the gate + deterministic rules in advisory (non-blocking) mode", () => { expect(recommendedAdvisoryActivationSettings()).toEqual({ reviewCheckMode: "required", - checkRunMode: "enabled", linkedIssueGateMode: "advisory", duplicatePrGateMode: "advisory", qualityGateMode: "advisory", diff --git a/test/unit/repo-identity-rename.test.ts b/test/unit/repo-identity-rename.test.ts index 33f533785b..72e8e6e8b2 100644 --- a/test/unit/repo-identity-rename.test.ts +++ b/test/unit/repo-identity-rename.test.ts @@ -97,21 +97,21 @@ describe("renameRepositoryIdentity", () => { // these assert on the raw row directly to distinguish "no row" / "renamed row" / "folded row". it("renames the settings row's repo_full_name", async () => { const env = createTestEnv(); - await upsertRepositorySettings(env, { repoFullName: OLD, commentMode: "off" }); + await upsertRepositorySettings(env, { repoFullName: OLD, gittensorLabel: "marker-old" }); await renameRepositoryIdentity(env, OLD, NEW); const oldRow = await env.DB.prepare("select count(*) as n from repository_settings where repo_full_name = ?").bind(OLD).first<{ n: number }>(); expect(oldRow?.n).toBe(0); const settings = await getRepositorySettings(env, NEW); - expect(settings.commentMode).toBe("off"); + expect(settings.gittensorLabel).toBe("marker-old"); }); it("REGRESSION (#repo-rename-migration): folds away a stray new-name settings row, keeping the pre-existing configured settings", async () => { const env = createTestEnv(); - await upsertRepositorySettings(env, { repoFullName: OLD, commentMode: "detected_contributors_only" }); - await upsertRepositorySettings(env, { repoFullName: NEW, commentMode: "off" }); // stray, should be discarded + await upsertRepositorySettings(env, { repoFullName: OLD, gittensorLabel: "marker-configured" }); + await upsertRepositorySettings(env, { repoFullName: NEW, gittensorLabel: "marker-stray" }); // stray, should be discarded await renameRepositoryIdentity(env, OLD, NEW); const settings = await getRepositorySettings(env, NEW); - expect(settings.commentMode).toBe("detected_contributors_only"); + expect(settings.gittensorLabel).toBe("marker-configured"); const newRowCount = await env.DB.prepare("select count(*) as n from repository_settings where repo_full_name = ?").bind(NEW).first<{ n: number }>(); expect(newRowCount?.n).toBe(1); // exactly one surviving row, not two });