From 5e8d3199f4137fbeece0548f4cd7828e22f754e0 Mon Sep 17 00:00:00 2001
From: JSONbored <49853598+JSONbored@users.noreply.github.com>
Date: Sat, 27 Jun 2026 12:04:32 -0700
Subject: [PATCH] fix(review): skip re-publishing a PR surface already current
at its head (#1615)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The scheduled re-gate sweep re-reviewed + re-published every open PR's public
surface every ~2-min cycle regardless of change (~4292 pr_public_surface_published
in 2h for ~64 PRs). The sticky comment was PATCHed unconditionally and no per-PR
marker recorded the head the surface was last published at.
Add pull_requests.last_published_surface_sha (migration 0080), stamped head_sha-
keyed after a successful publish and omitted from the GitHub-sync SET clause like
the sibling approved_head_sha marker. In reReviewStoredPullRequest, after the
live-head resync, skip the re-review + re-publish when the marker equals the live
head. A never-published PR (NULL marker) or a changed head (push/rebase/force-push)
falls through and re-reviews at the new head; the head_sha-keyed AI cache also
misses on a rebase, so rebases are never skipped (pinned by a regression test).
Also skip the comment PATCH when the body is byte-identical.
Folds in the proof-of-power-stats count-up flake fix (force prefers-reduced-motion
so the value settles synchronously instead of racing a 3s findByText on the rAF
tween — it flaked the ui job repeatedly).
---
.../site/proof-of-power-stats.test.tsx | 16 +++-
.../0080_pr_last_published_surface_sha.sql | 7 ++
src/db/repositories.ts | 15 +++
src/db/schema.ts | 6 ++
src/github/comments.ts | 5 +
src/queue/processors.ts | 18 ++++
src/types.ts | 4 +
test/unit/db-parsers.test.ts | 20 ++++
test/unit/github-comments.test.ts | 40 ++++++++
test/unit/queue.test.ts | 96 +++++++++++++++++++
10 files changed, 225 insertions(+), 2 deletions(-)
create mode 100644 migrations/0080_pr_last_published_surface_sha.sql
diff --git a/apps/gittensory-ui/src/components/site/proof-of-power-stats.test.tsx b/apps/gittensory-ui/src/components/site/proof-of-power-stats.test.tsx
index e1b81a9bdb..00f93671bf 100644
--- a/apps/gittensory-ui/src/components/site/proof-of-power-stats.test.tsx
+++ b/apps/gittensory-ui/src/components/site/proof-of-power-stats.test.tsx
@@ -1,12 +1,14 @@
import { render, screen, waitFor } from "@testing-library/react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
-import { describe, expect, it, vi } from "vitest";
+import { afterEach, describe, expect, it, vi } from "vitest";
import type { ReactNode } from "react";
const { apiFetch } = vi.hoisted(() => ({ apiFetch: vi.fn() }));
vi.mock("@/lib/api/request", () => ({ apiFetch: (...args: unknown[]) => apiFetch(...args) }));
vi.mock("@/lib/api/origin", () => ({ getApiOrigin: () => "https://api.test" }));
+afterEach(() => vi.unstubAllGlobals());
+
import { ProofOfPowerStats } from "@/components/site/proof-of-power-stats";
import {
formatStatsAgo,
@@ -121,8 +123,18 @@ describe("ProofOfPowerStats", () => {
});
it("settles the count-up on the real reviewed total (not stuck at 0 when rAF never fires)", async () => {
+ // Deterministic (#flake): force prefers-reduced-motion so useCountUp lands the final value synchronously on
+ // mount, instead of running the requestAnimationFrame tween. jsdom has no matchMedia, so the unfixed test took
+ // the animated path and raced the 3s findByText timeout under CI load. This still pins the intent — the count
+ // settles on the real reviewed total, never stuck at 0 — without depending on animation-frame timing.
+ vi.stubGlobal("matchMedia", () => ({
+ matches: true,
+ media: "(prefers-reduced-motion: reduce)",
+ addEventListener: () => {},
+ removeEventListener: () => {},
+ }));
apiFetch.mockResolvedValue({ ok: true, status: 200, durationMs: 1, data: PAYLOAD });
renderWithClient();
- expect(await screen.findByText("2,708", undefined, { timeout: 3000 })).toBeTruthy();
+ expect(await screen.findByText("2,708")).toBeTruthy();
});
});
diff --git a/migrations/0080_pr_last_published_surface_sha.sql b/migrations/0080_pr_last_published_surface_sha.sql
new file mode 100644
index 0000000000..c800a57069
--- /dev/null
+++ b/migrations/0080_pr_last_published_surface_sha.sql
@@ -0,0 +1,7 @@
+-- Over-publish dedup (#4): the head SHA at which a PR's public surface (comment/label/check-run) was LAST
+-- published. The scheduled re-gate sweep skips re-reviewing + re-publishing a PR while
+-- last_published_surface_sha === head_sha (the surface is already current). Keyed to the head SHA so a push /
+-- rebase / force-push (new head) no longer matches → the next sweep re-reviews + re-publishes the new code.
+-- NULL = never published. gittensory-computed (publish-written); like approved_head_sha / merge_blocked_sha it is
+-- omitted from the GitHub-sync SET clause so a later sync cannot clobber it.
+ALTER TABLE pull_requests ADD COLUMN last_published_surface_sha TEXT;
diff --git a/src/db/repositories.ts b/src/db/repositories.ts
index 4bcc77b060..41482147af 100644
--- a/src/db/repositories.ts
+++ b/src/db/repositories.ts
@@ -2627,6 +2627,20 @@ export async function markPullRequestApproved(env: Env, fullName: string, number
.where(and(eq(pullRequests.repoFullName, fullName), eq(pullRequests.number, number), eq(pullRequests.headSha, headSha)));
}
+/** Over-publish dedup (#4): record the head SHA at which the PR's public surface was just published. The scheduled
+ * re-gate sweep skips re-reviewing while last_published_surface_sha == headSha. Scoped to headSha so a later commit
+ * (push/rebase/force-push — the live head no longer matches) re-publishes the new code without any manual reset.
+ * The eq(headSha) in the WHERE is load-bearing: if the live head advanced between review and this write, the UPDATE
+ * no-ops (never stamps a stale head) → the next sweep correctly re-reviews. Mirrors markPullRequestApproved. */
+export async function markPullRequestSurfacePublished(env: Env, fullName: string, number: number, headSha: string | null | undefined): Promise {
+ if (!headSha) return; // no head to key the marker on → nothing to stamp (the caller's advisory had no head SHA)
+ const db = getDb(env.DB);
+ await db
+ .update(pullRequests)
+ .set({ lastPublishedSurfaceSha: headSha, updatedAt: nowIso() })
+ .where(and(eq(pullRequests.repoFullName, fullName), eq(pullRequests.number, number), eq(pullRequests.headSha, headSha)));
+}
+
/** Sweep convergence: stamp the timestamp the scheduled re-gate sweep just recomputed this PR. A plain D1 UPDATE
* — NOT routed through the agent-action-executor chokepoint (#1258) — so it advances even when GitHub writes are
* suppressed (dry-run / paused). selectRegateCandidates orders the sweep by last_regated_at, so a just-regated PR
@@ -4161,6 +4175,7 @@ function toPullRequestRecordFromRow(row: typeof pullRequests.$inferSelect): Pull
approvedHeadSha: row.approvedHeadSha,
// Read straight from the row, NEVER the GitHub payload — this is a gittensory-internal sweep marker.
lastRegatedAt: row.lastRegatedAt,
+ lastPublishedSurfaceSha: row.lastPublishedSurfaceSha,
};
}
diff --git a/src/db/schema.ts b/src/db/schema.ts
index 5c60600d8d..396992ab51 100644
--- a/src/db/schema.ts
+++ b/src/db/schema.ts
@@ -304,6 +304,12 @@ export const pullRequests = sqliteTable(
// review WRITE that would bump updated_at is suppressed (dry-run / paused). gittensory-computed (sweep-written),
// omitted from the GitHub-sync SET clause so a later sync cannot clobber it. (Mirrors approved_head_sha.)
lastRegatedAt: text("last_regated_at"),
+ // Over-publish dedup: the head SHA at which the public surface (comment/label/check-run) was LAST published.
+ // The sweep skips re-reviewing + re-publishing a PR while last_published_surface_sha === headSha (already
+ // current). Keyed to head SHA → a push/rebase/force-push (new head) clears the match and the next sweep
+ // re-reviews + re-publishes. gittensory-computed (publish-written), omitted from the GitHub-sync SET clause so
+ // a later sync cannot clobber it. (Mirrors approved_head_sha.)
+ lastPublishedSurfaceSha: text("last_published_surface_sha"),
createdAt: text("created_at").notNull().$defaultFn(() => nowIso()),
updatedAt: text("updated_at").notNull().$defaultFn(() => nowIso()),
},
diff --git a/src/github/comments.ts b/src/github/comments.ts
index 368caabc8d..f31a2d7bb2 100644
--- a/src/github/comments.ts
+++ b/src/github/comments.ts
@@ -72,6 +72,11 @@ async function createOrUpdateIssueCommentWithMarker(
if (batch.length < 100) break;
}
if (existing) {
+ // Idempotency (#4): skip the PATCH when the rendered body is byte-identical to what's already posted. The
+ // re-gate sweep re-renders the same surface every cycle for an unchanged PR; without this, every cycle PATCHes
+ // GitHub (a write + rate-limit cost) for no visible change. Defense-in-depth alongside the head_sha publish
+ // marker — also collapses a duplicate webhook delivery for the same commit.
+ if (existing.body === body) return { id: existing.id, ...(existing.html_url !== undefined ? { html_url: existing.html_url } : {}) };
const response = await octokit.request("PATCH /repos/{owner}/{repo}/issues/comments/{comment_id}", {
owner,
repo,
diff --git a/src/queue/processors.ts b/src/queue/processors.ts
index 0edd9a835c..022f413516 100644
--- a/src/queue/processors.ts
+++ b/src/queue/processors.ts
@@ -41,6 +41,7 @@ import {
getCachedAiReview,
putCachedAiReview,
markPullRequestsRegated,
+ markPullRequestSurfacePublished,
getLatestRegatedAt,
claimRegateFanoutSlot,
recordAgentCommandFeedback,
@@ -1508,6 +1509,16 @@ async function reReviewStoredPullRequest(
/* v8 ignore next -- the row was just upserted above, so the re-read always returns it; `?? pr` is belt-and-suspenders fail-open. */
pr = (await getPullRequest(env, repoFullName, prNumber)) ?? pr;
}
+ // Over-publish dedup (#4): the resync above made pr.headSha the LIVE head. If the public surface was already
+ // published at this exact head, the verdict + comment are already current — skip the re-review + re-publish so the
+ // sweep stops re-publishing every open PR every ~2-min cycle. A never-published PR (NULL marker) or a drifted head
+ // (push/rebase/force-push → marker !== live head) falls THROUGH and re-reviews at the new head; the AI cache is
+ // head_sha-keyed too, so a rebase misses it and gets a fresh review. (Webhook synchronize/opened paths review
+ // directly and always re-stamp — this guard only gates the scheduled sweep.)
+ if (pr.lastPublishedSurfaceSha && pr.lastPublishedSurfaceSha === pr.headSha) {
+ console.log(JSON.stringify({ level: "info", event: "rereview_skipped_surface_current", deliveryId, repository: repoFullName, pullNumber: prNumber, headSha: pr.headSha }));
+ return;
+ }
// Operator review flow: rebase-if-behind → wait for ALL CI to finish → only THEN review. Defers (returns) when
// a rebase fired a synchronize, or CI is still running — the synchronize / CI-completion webhook re-triggers
// once the head is current and CI has settled (the sweep backstops a missed event). REST-budget dedup
@@ -5328,6 +5339,13 @@ async function maybePublishPrPublicSurface(
failedOutputs,
},
});
+ // Over-publish dedup (#4): stamp the head SHA we just published at, so the scheduled sweep skips re-reviewing +
+ // re-publishing this PR until its head changes (see the guard in reReviewStoredPullRequest). Reached only when at
+ // least one surface output actually published (the zero-output early-return above covers the suppressed/dry-run
+ // case). The helper no-ops on a null head, and its WHERE pins head_sha so a head that advanced mid-pass won't stamp.
+ await markPullRequestSurfacePublished(env, repoFullName, pr.number, advisory.headSha).catch((error) => {
+ console.error(JSON.stringify({ level: "warn", event: "surface_published_mark_failed", repoFullName, pullNumber: pr.number, error: errorMessage(error) }));
+ });
return gateEvaluation;
}
diff --git a/src/types.ts b/src/types.ts
index fd7e2379d6..eea8fab367 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -453,6 +453,10 @@ export type PullRequestRecord = {
* review write that would bump updatedAt is suppressed (dry-run / paused). Sweep-written; read straight from
* the row (never the GitHub payload). */
lastRegatedAt?: string | null | undefined;
+ /** Over-publish dedup: the head SHA at which the public surface was last published. The re-gate sweep skips
+ * re-reviewing + re-publishing while lastPublishedSurfaceSha === headSha; a new commit (push/rebase/force-push)
+ * clears the match so the surface re-publishes the new code. Publish-written; read straight from the row. */
+ lastPublishedSurfaceSha?: string | null | undefined;
};
export type IssueRecord = {
diff --git a/test/unit/db-parsers.test.ts b/test/unit/db-parsers.test.ts
index 300b326ec0..e55ceb8c96 100644
--- a/test/unit/db-parsers.test.ts
+++ b/test/unit/db-parsers.test.ts
@@ -12,6 +12,7 @@ import {
listRepoSyncStates,
markPullRequestRegated,
markPullRequestsRegated,
+ markPullRequestSurfacePublished,
recordAuditEvent,
recordWebhookEvent,
upsertOfficialMinerDetection,
@@ -101,6 +102,25 @@ describe("database row parser hardening", () => {
expect(after?.title).toBe("Stale PR"); // INVARIANT: a plain D1 UPDATE — it touches only the marker, not PR content
});
+ it("markPullRequestSurfacePublished stamps last_published_surface_sha only at the matching live head (#4 over-publish dedup)", async () => {
+ const env = createTestEnv();
+ await upsertPullRequestFromGitHub(env, "owner/repo", { number: 9, title: "PR", state: "open", user: { login: "alice" }, head: { sha: "headA" }, labels: [] });
+
+ const before = (await listPullRequests(env, "owner/repo")).find((p) => p.number === 9);
+ expect(before?.lastPublishedSurfaceSha ?? null).toBeNull(); // never published → marker absent
+
+ await markPullRequestSurfacePublished(env, "owner/repo", 9, null); // null head → no-op (the !headSha guard)
+ expect((await listPullRequests(env, "owner/repo")).find((p) => p.number === 9)?.lastPublishedSurfaceSha ?? null).toBeNull();
+
+ await markPullRequestSurfacePublished(env, "owner/repo", 9, "oldHead"); // stale head → WHERE head_sha mismatch → no-op
+ expect((await listPullRequests(env, "owner/repo")).find((p) => p.number === 9)?.lastPublishedSurfaceSha ?? null).toBeNull();
+
+ await markPullRequestSurfacePublished(env, "owner/repo", 9, "headA"); // matches the live head → stamps
+ const after = (await listPullRequests(env, "owner/repo")).find((p) => p.number === 9);
+ expect(after?.lastPublishedSurfaceSha).toBe("headA");
+ expect(after?.title).toBe("PR"); // INVARIANT: touches only the marker, not PR content
+ });
+
it("markPullRequestsRegated batch-stamps every candidate at dispatch and no-ops on an empty list (#audit-sweep-dispatch-stamp)", async () => {
const env = createTestEnv();
for (const number of [5, 6, 7]) {
diff --git a/test/unit/github-comments.test.ts b/test/unit/github-comments.test.ts
index 7a855ed6b4..483e2b7760 100644
--- a/test/unit/github-comments.test.ts
+++ b/test/unit/github-comments.test.ts
@@ -229,6 +229,46 @@ describe("GitHub PR intelligence comments", () => {
expect(calls.some((call) => call.startsWith("POST ") && call.includes("/issues/12/comments"))).toBe(true);
});
+ it("skips the PATCH when the existing sticky comment body is byte-identical (#4 idempotency), keeping html_url", async () => {
+ const privateKey = await generatePrivateKeyPem();
+ const body = `${PR_INTELLIGENCE_COMMENT_MARKER}\nidentical body`;
+ const calls: string[] = [];
+ vi.stubGlobal("fetch", async (input: RequestInfo | URL, init?: RequestInit) => {
+ const url = input.toString();
+ calls.push(`${init?.method ?? "GET"} ${url}`);
+ if (url.includes("/access_tokens")) return Response.json({ token: "installation-token" });
+ if (url.includes("/issues/12/comments") && (init?.method ?? "GET") === "GET") {
+ return Response.json([{ id: 101, body, html_url: "https://github.com/comment/101", user: { login: "gittensory[bot]", type: "Bot" } }]);
+ }
+ return new Response("not found", { status: 404 });
+ });
+
+ const result = await createOrUpdatePrIntelligenceComment(createTestEnv({ GITHUB_APP_PRIVATE_KEY: privateKey }), 123, "JSONbored/gittensory", 12, body);
+
+ expect(result).toEqual({ id: 101, html_url: "https://github.com/comment/101" }); // html_url-present branch of the early return
+ expect(calls.some((call) => call.startsWith("PATCH "))).toBe(false); // identical body → NO GitHub write
+ });
+
+ it("skips the PATCH on an identical body even when the existing comment has no html_url (#4 idempotency)", async () => {
+ const privateKey = await generatePrivateKeyPem();
+ const body = `${PR_INTELLIGENCE_COMMENT_MARKER}\nidentical body`;
+ const calls: string[] = [];
+ vi.stubGlobal("fetch", async (input: RequestInfo | URL, init?: RequestInit) => {
+ const url = input.toString();
+ calls.push(`${init?.method ?? "GET"} ${url}`);
+ if (url.includes("/access_tokens")) return Response.json({ token: "installation-token" });
+ if (url.includes("/issues/12/comments") && (init?.method ?? "GET") === "GET") {
+ return Response.json([{ id: 202, body, user: { login: "gittensory[bot]", type: "Bot" } }]); // no html_url field
+ }
+ return new Response("not found", { status: 404 });
+ });
+
+ const result = await createOrUpdatePrIntelligenceComment(createTestEnv({ GITHUB_APP_PRIVATE_KEY: privateKey }), 123, "JSONbored/gittensory", 12, body);
+
+ expect(result).toEqual({ id: 202 }); // html_url-absent branch → no html_url key on the early return
+ expect(calls.some((call) => call.startsWith("PATCH "))).toBe(false);
+ });
+
it("rejects invalid repository names before calling GitHub", async () => {
await expect(createOrUpdatePrIntelligenceComment(createTestEnv(), 123, "invalid", 12, "body")).rejects.toThrow(/Invalid repository full name/);
});
diff --git a/test/unit/queue.test.ts b/test/unit/queue.test.ts
index 104e576e93..74123a9a72 100644
--- a/test/unit/queue.test.ts
+++ b/test/unit/queue.test.ts
@@ -864,6 +864,102 @@ describe("queue processors", () => {
resyncUpsertSpy.mockRestore();
});
+ it("#4 over-publish dedup: the sweep SKIPS re-review when the surface was already published at the current head", async () => {
+ const env = createTestEnv({ GITHUB_APP_PRIVATE_KEY: await generatePrivateKeyPem() });
+ await upsertInstallation(env, { action: "created", installation: { id: 9001, 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" } }, 9001);
+ await upsertRepositorySettings(env, { repoFullName: "owner/agent-repo", autonomy: { merge: "auto" }, aiReviewMode: "off", gatePack: "oss-anti-slop", gateCheckMode: "enabled", checkRunMode: "off", commentMode: "off", publicSurface: "off" });
+ await upsertPullRequestFromGitHub(env, "owner/agent-repo", { number: 7, title: "Current PR", state: "open", user: { login: "contributor" }, head: { sha: "a7" }, labels: [], body: "Closes #1" });
+ await repositoriesModule.markPullRequestSurfacePublished(env, "owner/agent-repo", 7, "a7"); // already published at the live head
+ let checkRunsFetched = false;
+ vi.stubGlobal("fetch", async (input: RequestInfo | URL) => {
+ const url = input.toString();
+ if (url.includes("/access_tokens")) return Response.json({ token: "installation-token" });
+ if (url.endsWith("/pulls/7")) return Response.json({ number: 7, title: "Current PR", state: "open", user: { login: "contributor" }, head: { sha: "a7" }, labels: [], body: "Closes #1" }); // live head matches → no drift
+ if (url.includes("/check-runs")) { checkRunsFetched = true; return Response.json({ total_count: 0, check_runs: [] }); }
+ if (url.includes("/status")) return Response.json({ state: "success", statuses: [] });
+ return Response.json({});
+ });
+ vi.setSystemTime(new Date("2026-05-28T02:00:00.000Z"));
+
+ await processJob(env, { type: "agent-regate-pr", deliveryId: "skip-current", repoFullName: "owner/agent-repo", prNumber: 7, installationId: 9001 });
+
+ // The dedup guard returned BEFORE prReadyForReview → no CI check-runs were fetched (the re-review never ran).
+ expect(checkRunsFetched).toBe(false);
+ });
+
+ it("#4 over-publish dedup: a rebased PR (marker != live head) is NOT skipped — it resyncs + re-reviews at the new head, and the marker survives the resync", async () => {
+ const env = createTestEnv({ GITHUB_APP_PRIVATE_KEY: await generatePrivateKeyPem() });
+ await upsertInstallation(env, { action: "created", installation: { id: 9001, 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" } }, 9001);
+ await upsertRepositorySettings(env, { repoFullName: "owner/agent-repo", autonomy: { merge: "auto" }, aiReviewMode: "off", gatePack: "oss-anti-slop", gateCheckMode: "enabled", checkRunMode: "off", commentMode: "off", publicSurface: "off" });
+ await upsertPullRequestFromGitHub(env, "owner/agent-repo", { number: 7, title: "Rebased PR", state: "open", user: { login: "contributor" }, head: { sha: "a7" }, labels: [], body: "Closes #1" });
+ await repositoriesModule.markPullRequestSurfacePublished(env, "owner/agent-repo", 7, "a7"); // published at the OLD head a7
+ let checkRunsFetchedAtNewHead = false;
+ vi.stubGlobal("fetch", async (input: RequestInfo | URL) => {
+ const url = input.toString();
+ if (url.includes("/access_tokens")) return Response.json({ token: "installation-token" });
+ if (url.endsWith("/pulls/7")) return Response.json({ number: 7, title: "Rebased PR", state: "open", user: { login: "contributor" }, head: { sha: "b8" }, labels: [], body: "Closes #1" }); // LIVE head drifted to b8 (rebase/force-push)
+ if (url.includes("/pulls/7/files")) return Response.json([{ filename: "src/a.ts", status: "modified", additions: 1, deletions: 0, changes: 1, patch: "@@\n+export const ok = true;" }]);
+ if (url.includes("/commits/b8/check-runs")) { checkRunsFetchedAtNewHead = true; return Response.json({ total_count: 0, check_runs: [] }); }
+ if (url.includes("/commits/b8/status")) return Response.json({ state: "success", statuses: [] });
+ if (url.includes("/issues/1")) return Response.json({ number: 1, title: "Issue", state: "open", labels: [], user: { login: "reporter" } });
+ if (url.includes("/branches/")) return Response.json({ protected: false, protection: { required_status_checks: { contexts: [] } } });
+ return Response.json({});
+ });
+ vi.setSystemTime(new Date("2026-05-28T02:00:00.000Z"));
+
+ await processJob(env, { type: "agent-regate-pr", deliveryId: "rebase-rereview", repoFullName: "owner/agent-repo", prNumber: 7, installationId: 9001 });
+
+ // The old-head marker (a7) != the live rebased head (b8) → the guard fell THROUGH → the PR was resynced to b8 and
+ // re-reviewed at the new head (check-runs fetched at b8). The marker is NOT in the GitHub-sync SET clause, so the
+ // resync upsert preserved it (still a7) until a fresh publish advances it — proving rebases are never skipped.
+ expect(checkRunsFetchedAtNewHead).toBe(true);
+ const stored = await getPullRequest(env, "owner/agent-repo", 7);
+ expect(stored?.headSha).toBe("b8");
+ expect(stored?.lastPublishedSurfaceSha).toBe("a7"); // marker survived the resync (omitted from the sync SET clause)
+ });
+
+ it("#4 over-publish dedup: a failing surface-published stamp is swallowed (fail-open) — the publish still completes", async () => {
+ const env = createTestEnv({ GITHUB_APP_PRIVATE_KEY: await generatePrivateKeyPem() });
+ await upsertRepositoryFromGitHub(env, { name: "gittensory", full_name: "JSONbored/gittensory", private: false, owner: { login: "JSONbored" } }, 123);
+ await upsertRepositorySettings(env, { repoFullName: "JSONbored/gittensory", commentMode: "all_prs", publicSurface: "comment_only", autoLabelEnabled: false, checkRunMode: "off", gateCheckMode: "enabled", aiReviewMode: "off", gatePack: "oss-anti-slop" });
+ const stampSpy = vi.spyOn(repositoriesModule, "markPullRequestSurfacePublished").mockRejectedValueOnce(new Error("D1 stamp failed"));
+ let commentPosted = false;
+ vi.stubGlobal("fetch", async (input: RequestInfo | URL, init?: RequestInit) => {
+ const url = input.toString();
+ const method = init?.method ?? "GET";
+ if (url.includes("/access_tokens")) return Response.json({ token: "installation-token" });
+ if (url.includes("/pulls/7/files")) return Response.json([{ filename: "src/a.ts", status: "modified", additions: 1, deletions: 0, changes: 1, patch: "@@\n+export const ok = true;" }]);
+ if (url.endsWith("/pulls/7")) return Response.json({ number: 7, title: "Clean PR", state: "open", user: { login: "contributor" }, head: { sha: "a7" }, labels: [], body: "Closes #1" });
+ if (url.includes("/commits/a7/check-runs")) return Response.json({ total_count: 0, check_runs: [] });
+ if (url.includes("/commits/a7/status")) return Response.json({ state: "success", statuses: [] });
+ if (url.includes("/issues/1")) return Response.json({ number: 1, title: "Issue", state: "open", labels: [], user: { login: "reporter" } });
+ if (url.includes("/issues/7/comments") && method === "GET") return Response.json([]);
+ if (url.includes("/issues/7/comments") && method === "POST") { commentPosted = true; return Response.json({ id: 1 }, { status: 201 }); }
+ if (url.includes("/branches/")) return Response.json({ protected: false, protection: { required_status_checks: { contexts: [] } } });
+ return Response.json({});
+ });
+
+ await expect(
+ processJob(env, {
+ type: "github-webhook",
+ deliveryId: "stamp-failopen",
+ eventName: "pull_request",
+ payload: {
+ action: "opened",
+ installation: { id: 123, account: { login: "JSONbored", id: 1, type: "User" } },
+ repository: { name: "gittensory", full_name: "JSONbored/gittensory", private: false, owner: { login: "JSONbored" } },
+ pull_request: { number: 7, title: "Clean PR", state: "open", user: { login: "contributor" }, head: { sha: "a7" }, labels: [], body: "Closes #1" },
+ },
+ }),
+ ).resolves.toBeUndefined();
+
+ expect(commentPosted).toBe(true); // the surface published despite the marker write throwing
+ expect(stampSpy).toHaveBeenCalled();
+ stampSpy.mockRestore();
+ });
+
it("#1: the block-mode re-gate sweep replays cached AI findings before gate evaluation", async () => {
let aiCalls = 0;
const env = createTestEnv({