From 9968db65db76ab5a0cdc959a1d1c128b3c49ffb1 Mon Sep 17 00:00:00 2001 From: Tak Hoffman <781889+Takhoffman@users.noreply.github.com> Date: Mon, 18 May 2026 17:10:35 -0500 Subject: [PATCH] fix(github): preserve clawsweeper proof labels (#83781) --- scripts/github/barnacle-auto-response.mjs | 36 +++++++++- test/scripts/barnacle-auto-response.test.ts | 80 +++++++++++++++++++++ 2 files changed, 114 insertions(+), 2 deletions(-) diff --git a/scripts/github/barnacle-auto-response.mjs b/scripts/github/barnacle-auto-response.mjs index 10e2bf4faf6..d36fdf249ec 100644 --- a/scripts/github/barnacle-auto-response.mjs +++ b/scripts/github/barnacle-auto-response.mjs @@ -794,13 +794,36 @@ async function addMissingLabels(github, context, core, issueNumber, labels, labe core.info(`Added candidate labels to #${issueNumber}: ${missingLabels.join(", ")}`); } -function shouldRemoveProofSufficientLabel(context, proofEvaluation, hasExactHeadClawSweeperProof) { +function isClawSweeperOwnedLabel(label) { + return label === "clawsweeper" || label.startsWith("clawsweeper:"); +} + +function isActiveClawSweeperWork(pullRequest, labelSet) { + const authorLogin = pullRequest.user?.login ?? ""; + const headRef = pullRequest.head?.ref ?? ""; + return ( + /clawsweeper/i.test(authorLogin) || + headRef.startsWith("clawsweeper/") || + [...labelSet].some(isClawSweeperOwnedLabel) + ); +} + +function shouldRemoveProofSufficientLabel( + context, + pullRequest, + labelSet, + proofEvaluation, + hasExactHeadClawSweeperProof, +) { if (hasExactHeadClawSweeperProof) { return false; } if (proofEvaluation.status === "override") { return false; } + if (isActiveClawSweeperWork(pullRequest, labelSet)) { + return false; + } if (!["edited", "synchronize"].includes(context.payload.action)) { return false; } @@ -836,7 +859,13 @@ async function applyPullRequestCandidateLabels(github, context, core, pullReques ); if ( labelSet.has(PROOF_SUFFICIENT_LABEL) && - shouldRemoveProofSufficientLabel(context, proofEvaluation, hasExactHeadClawSweeperProof) + shouldRemoveProofSufficientLabel( + context, + pullRequest, + labelSet, + proofEvaluation, + hasExactHeadClawSweeperProof, + ) ) { staleProofLabels.push(PROOF_SUFFICIENT_LABEL); } @@ -927,6 +956,9 @@ async function removeLabels(github, context, issueNumber, labels, labelSet) { if (!labelSet.has(label)) { continue; } + if (isClawSweeperOwnedLabel(label)) { + continue; + } try { await github.rest.issues.removeLabel({ owner: context.repo.owner, diff --git a/test/scripts/barnacle-auto-response.test.ts b/test/scripts/barnacle-auto-response.test.ts index 51a8f377d71..8d1976ebbba 100644 --- a/test/scripts/barnacle-auto-response.test.ts +++ b/test/scripts/barnacle-auto-response.test.ts @@ -889,6 +889,86 @@ describe("barnacle-auto-response", () => { expect(calls.removeLabel).toEqual([expectedRemoveLabel(123, PROOF_SUFFICIENT_LABEL)]); }); + it("preserves stale sufficient proof while ClawSweeper automerge owns the PR", async () => { + const { calls, github } = barnacleGithub([file("src/gateway/server.ts")]); + + await runBarnacleAutoResponse({ + github, + context: barnacleContext( + { + head: { + ref: "fix/memory-search-event-loop-yield-81172", + sha: "0ede3d716805e7d2ced8df37c6666af510dc9e19", + }, + body: realBehaviorProofBody( + "![after](https://github.com/user-attachments/assets/gateway-ready)", + ), + }, + [PROOF_SUPPLIED_LABEL, PROOF_SUFFICIENT_LABEL, "clawsweeper:automerge"], + { action: "synchronize" }, + ), + core: { + info: () => undefined, + }, + }); + + expect(calls.removeLabel).toEqual([]); + }); + + it("preserves stale sufficient proof on ClawSweeper branch updates", async () => { + const { calls, github } = barnacleGithub([file("src/gateway/server.ts")]); + + await runBarnacleAutoResponse({ + github, + context: barnacleContext( + { + head: { + ref: "clawsweeper/repair-pr-83758", + sha: "0ede3d716805e7d2ced8df37c6666af510dc9e19", + }, + body: realBehaviorProofBody( + "![after](https://github.com/user-attachments/assets/gateway-ready)", + ), + }, + [PROOF_SUPPLIED_LABEL, PROOF_SUFFICIENT_LABEL], + { action: "synchronize" }, + ), + core: { + info: () => undefined, + }, + }); + + expect(calls.removeLabel).toEqual([]); + }); + + it("preserves stale sufficient proof on ClawSweeper-authored PR updates", async () => { + const { calls, github } = barnacleGithub([file("src/gateway/server.ts")]); + + await runBarnacleAutoResponse({ + github, + context: barnacleContext( + { + body: realBehaviorProofBody( + "![after](https://github.com/user-attachments/assets/gateway-ready)", + ), + user: { + login: "clawsweeper[bot]", + type: "Bot", + }, + }, + [PROOF_SUPPLIED_LABEL, PROOF_SUFFICIENT_LABEL], + { action: "synchronize" }, + ), + core: { + info: () => undefined, + }, + }); + + expect(calls.removeLabel).not.toContainEqual( + expect.objectContaining({ name: PROOF_SUFFICIENT_LABEL }), + ); + }); + it("preserves ClawSweeper's sufficient proof label on ordinary label events", async () => { const { calls, github } = barnacleGithub([file("src/gateway/server.ts")]);