From 987e547860e3cabaa954b1fa0292e9d528c23f28 Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Sun, 12 Jul 2026 13:05:18 -0700 Subject: [PATCH] chore(activation): replace gateCheckMode with reviewCheckMode on the maintainer-activation surface (#5373) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes currentGateMode (MaintainerActivationPreview) and the gateCheckMode passthrough on the POST /activation response, replacing both with a reviewCheckMode-based equivalent instead of dropping the information outright -- reviewCheckMode is strictly more informative (required/visible/disabled vs. the old off/enabled) and was already the real value driving the recommendedAction/currentlyActive decision; gateCheckMode was purely a display echo that never affected any logic in buildMaintainerActivationPreview. Updates the UI (activation-preview.tsx's "gate {…}" status pill and its local response type) to match, and rewrites the #2852 legacy-yml mismatch regression test: gateCheckMode/reviewCheckMode can no longer diverge on this surface since the display field IS reviewCheckMode now, so the test keeps its real invariant (recommendedAction follows reviewCheckMode only) without the now-meaningless gateCheckMode echo. --- .../app-panels/activation-preview.test.tsx | 4 ++-- .../site/app-panels/activation-preview.tsx | 4 ++-- src/api/routes.ts | 1 - src/services/maintainer-activation.ts | 10 +++++----- .../integration/maintainer-activation.test.ts | 12 +++++------ test/unit/maintainer-activation.test.ts | 20 +++++++++---------- 6 files changed, 25 insertions(+), 26 deletions(-) diff --git a/apps/gittensory-ui/src/components/site/app-panels/activation-preview.test.tsx b/apps/gittensory-ui/src/components/site/app-panels/activation-preview.test.tsx index 113d8bbe99..59c8643a2a 100644 --- a/apps/gittensory-ui/src/components/site/app-panels/activation-preview.test.tsx +++ b/apps/gittensory-ui/src/components/site/app-panels/activation-preview.test.tsx @@ -13,7 +13,7 @@ const REVIEWABILITY = [{ pr: "acme/widgets#1" }]; const BASE_PREVIEW = { repoFullName: "acme/widgets", generatedAt: "2026-07-05T00:00:00.000Z", - currentGateMode: "off" as const, + currentReviewCheckMode: "disabled" as const, aiReviewConfigured: false, evaluatedCount: 3, withFindingsCount: 2, @@ -106,7 +106,7 @@ describe("ActivationPreview", () => { // Reload after activation reports the gate is now on — the button should disappear. apiFetch.mockResolvedValueOnce({ ok: true, - data: { ...BASE_PREVIEW, currentGateMode: "enabled", recommendedAction: null }, + data: { ...BASE_PREVIEW, currentReviewCheckMode: "required", recommendedAction: null }, }); fireEvent.click(activateButton); diff --git a/apps/gittensory-ui/src/components/site/app-panels/activation-preview.tsx b/apps/gittensory-ui/src/components/site/app-panels/activation-preview.tsx index fa6165f873..5bf3051af6 100644 --- a/apps/gittensory-ui/src/components/site/app-panels/activation-preview.tsx +++ b/apps/gittensory-ui/src/components/site/app-panels/activation-preview.tsx @@ -22,7 +22,7 @@ type ActivationSample = { type ActivationPreviewResponse = { repoFullName: string; generatedAt: string; - currentGateMode: "off" | "enabled"; + currentReviewCheckMode: "required" | "visible" | "disabled"; aiReviewConfigured: boolean; evaluatedCount: number; withFindingsCount: number; @@ -140,7 +140,7 @@ export function ActivationPreview({ reviewability }: { reviewability: Array<{ pr {preview ? ( - gate {preview.currentGateMode} + gate {preview.currentReviewCheckMode} ) : null} diff --git a/src/api/routes.ts b/src/api/routes.ts index 6b299af0cb..e06f88a040 100644 --- a/src/api/routes.ts +++ b/src/api/routes.ts @@ -2551,7 +2551,6 @@ export function createApp() { const updated = await upsertRepositorySettings(c.env, { ...current, ...recommendedAdvisoryActivationSettings() }); return c.json({ repoFullName: fullName, - gateCheckMode: updated.gateCheckMode, reviewCheckMode: updated.reviewCheckMode, checkRunMode: updated.checkRunMode, linkedIssueGateMode: updated.linkedIssueGateMode, diff --git a/src/services/maintainer-activation.ts b/src/services/maintainer-activation.ts index 71a80978a7..15b0bb6f1a 100644 --- a/src/services/maintainer-activation.ts +++ b/src/services/maintainer-activation.ts @@ -18,10 +18,10 @@ export type MaintainerActivationSample = { export type MaintainerActivationPreview = { repoFullName: string; generatedAt: string; - // What's on today, so the UI can show the current state next to the one-click ramp. - /** @deprecated (#4618, tracked for removal in #5373) sourced from the computed read-back - * `RepositorySettings["gateCheckMode"]` -- kept only for API/dashboard back-compat display. */ - currentGateMode: RepositorySettings["gateCheckMode"]; + // What's on today, so the UI can show the current state next to the one-click ramp. Sourced from + // reviewCheckMode (#2852), the real publish authority -- not the deprecated gateCheckMode read-back + // (#5373), which never carried more information than reviewCheckMode already does. + currentReviewCheckMode: RepositorySettings["reviewCheckMode"]; aiReviewConfigured: boolean; evaluatedCount: number; withFindingsCount: number; @@ -91,7 +91,7 @@ export function buildMaintainerActivationPreview(args: { return { repoFullName: args.repoFullName, generatedAt: args.generatedAt, - currentGateMode: args.settings.gateCheckMode, + currentReviewCheckMode: args.settings.reviewCheckMode, aiReviewConfigured: args.settings.aiReviewMode !== "off", evaluatedCount: samples.length, withFindingsCount, diff --git a/test/integration/maintainer-activation.test.ts b/test/integration/maintainer-activation.test.ts index 1dc42c9f40..069de13a2e 100644 --- a/test/integration/maintainer-activation.test.ts +++ b/test/integration/maintainer-activation.test.ts @@ -41,21 +41,21 @@ describe("maintainer activation routes", () => { const preview = await app.request(PATH_PREVIEW, { headers }, env); expect(preview.status).toBe(200); - const previewBody = (await preview.json()) as { repoFullName: string; recommendedAction: string | null; currentGateMode: string; evaluatedCount: number }; - expect(previewBody).toMatchObject({ repoFullName: FULL_NAME, recommendedAction: "enable_advisory", currentGateMode: "off", evaluatedCount: 0 }); + const previewBody = (await preview.json()) as { repoFullName: string; recommendedAction: string | null; currentReviewCheckMode: string; evaluatedCount: number }; + expect(previewBody).toMatchObject({ repoFullName: FULL_NAME, recommendedAction: "enable_advisory", currentReviewCheckMode: "disabled", evaluatedCount: 0 }); const activate = await app.request(PATH_ACTIVATE, { method: "POST", headers, body: "{}" }, env); expect(activate.status).toBe(200); expect(await activate.json()).toMatchObject({ repoFullName: FULL_NAME, - gateCheckMode: "enabled", + reviewCheckMode: "required", linkedIssueGateMode: "advisory", duplicatePrGateMode: "advisory", qualityGateMode: "advisory", }); // The flip persisted, and the preview now reports nothing left to enable. - expect((await getRepositorySettings(env, FULL_NAME)).gateCheckMode).toBe("enabled"); + expect((await getRepositorySettings(env, FULL_NAME)).reviewCheckMode).toBe("required"); const afterPreview = await app.request(PATH_PREVIEW, { headers }, env); expect((await afterPreview.json() as { recommendedAction: string | null }).recommendedAction).toBeNull(); }); @@ -86,7 +86,7 @@ describe("maintainer activation routes", () => { const activate = await app.request(PATH_ACTIVATE, { method: "POST", headers, body: "{}" }, env); expect(activate.status).toBe(403); expect(await activate.json()).toMatchObject({ error: "insufficient_repo_permission" }); - expect((await getRepositorySettings(env, FULL_NAME)).gateCheckMode).toBe("off"); + expect((await getRepositorySettings(env, FULL_NAME)).reviewCheckMode).toBe("disabled"); }); it("allows a session with GitHub write permission to activate advisory checks", async () => { @@ -98,7 +98,7 @@ describe("maintainer activation routes", () => { const { token } = await createSessionForGitHubUser(env, { login: "owner", id: 201 }); const response = await app.request(PATH_ACTIVATE, { method: "POST", headers: { cookie: `gittensory_session=${token}`, "content-type": "application/json" }, body: "{}" }, env); expect(response.status).toBe(200); - expect(await response.json()).toMatchObject({ repoFullName: FULL_NAME, gateCheckMode: "enabled" }); + expect(await response.json()).toMatchObject({ repoFullName: FULL_NAME, reviewCheckMode: "required" }); }); it("forbids read-only repo collaborators from writing agent settings", async () => { diff --git a/test/unit/maintainer-activation.test.ts b/test/unit/maintainer-activation.test.ts index 0100dca0f9..b202bde85e 100644 --- a/test/unit/maintainer-activation.test.ts +++ b/test/unit/maintainer-activation.test.ts @@ -85,7 +85,7 @@ describe("buildMaintainerActivationPreview", () => { expect(preview.withFindingsCount).toBe(1); expect(preview.recommendedAction).toBe("enable_advisory"); expect(preview.aiReviewConfigured).toBe(false); - expect(preview.currentGateMode).toBe("off"); + expect(preview.currentReviewCheckMode).toBe("disabled"); expect(preview.findingCodeCounts).toContainEqual({ code: "missing_linked_issue", count: 1 }); const flagged = preview.samples.find((sample) => sample.number === 1)!; @@ -116,29 +116,29 @@ describe("buildMaintainerActivationPreview", () => { const preview = buildMaintainerActivationPreview({ repoFullName: repo.fullName, repo, - settings: settings({ gateCheckMode: "enabled", reviewCheckMode: "required", aiReviewMode: "advisory" }), + settings: settings({ reviewCheckMode: "required", aiReviewMode: "advisory" }), pullRequests: [pr(1, { linkedIssues: [] })], generatedAt: "2026-06-14T00:00:00.000Z", }); expect(preview.recommendedAction).toBeNull(); expect(preview.aiReviewConfigured).toBe(true); - expect(preview.currentGateMode).toBe("enabled"); + expect(preview.currentReviewCheckMode).toBe("required"); expect(preview.summary).toContain("already enabled"); }); - it("still recommends activation when gateCheckMode is enabled but reviewCheckMode is disabled (#2852 legacy-yml mismatch)", () => { - // Reachable via .gittensory.yml's independent settings.gateCheckMode/settings.reviewCheckMode keys (or any - // caller that sets one without the other) -- currentGateMode echoes the legacy field for display, but - // recommendedAction/currentlyActive must follow reviewCheckMode, the actual check-run publish authority, - // not the legacy field, since the check genuinely is not publishing in this state. + it("recommendedAction/currentlyActive follow only reviewCheckMode (#2852), regardless of any other settings (#5373)", () => { + // reviewCheckMode is the sole publish authority; the legacy gateCheckMode echo this test used to guard + // against (a maintainer-activation display that could diverge from the real activation decision) was + // removed in #5373 -- currentReviewCheckMode IS reviewCheckMode now, so there is no separate field left + // to drift. Kept as a plain reviewCheckMode invariant check. const preview = buildMaintainerActivationPreview({ repoFullName: repo.fullName, repo, - settings: settings({ gateCheckMode: "enabled", reviewCheckMode: "disabled" }), + settings: settings({ reviewCheckMode: "disabled" }), pullRequests: [pr(1, { linkedIssues: [] })], generatedAt: "2026-06-14T00:00:00.000Z", }); - expect(preview.currentGateMode).toBe("enabled"); + expect(preview.currentReviewCheckMode).toBe("disabled"); expect(preview.recommendedAction).toBe("enable_advisory"); expect(preview.summary).not.toContain("already enabled"); });