




















@@ -5,6 +5,10 @@ import {
55managedLabelSpecs,
66runBarnacleAutoResponse,
77} from "../../scripts/github/barnacle-auto-response.mjs";
8+import {
9+PROOF_SUFFICIENT_LABEL,
10+PROOF_SUPPLIED_LABEL,
11+} from "../../scripts/github/real-behavior-proof-policy.mjs";
812913const blankTemplateBody = [
1014"## Summary",
@@ -227,6 +231,8 @@ describe("barnacle-auto-response", () => {
227231expect(managedLabelSpecs["r: false-positive"].description).toContain("false positive");
228232expect(managedLabelSpecs["r: third-party-extension"].description).toContain("ClawHub");
229233expect(managedLabelSpecs["r: too-many-prs"].description).toContain("twenty active PRs");
234+expect(managedLabelSpecs[PROOF_SUPPLIED_LABEL].color).toBe("C2E0C6");
235+expect(managedLabelSpecs[PROOF_SUFFICIENT_LABEL].color).toBe("0E8A16");
230236231237for (const label of Object.values(candidateLabels)) {
232238expect(managedLabelSpecs[label]).toBeDefined();
@@ -283,7 +289,7 @@ describe("barnacle-auto-response", () => {
283289expect(labels).not.toContain(candidateLabels.needsRealBehaviorProof);
284290});
285291286-it("does not label external PRs that include real behavior proof", () => {
292+it("labels external PRs that include real behavior proof as supplied", () => {
287293const labels = classifyPullRequestCandidateLabels(
288294pr(
289295"Fix gateway startup",
@@ -292,6 +298,23 @@ describe("barnacle-auto-response", () => {
292298[file("src/gateway/server.ts")],
293299);
294300301+expect(labels).toContain(PROOF_SUPPLIED_LABEL);
302+expect(labels).not.toContain(candidateLabels.needsRealBehaviorProof);
303+expect(labels).not.toContain(candidateLabels.mockOnlyProof);
304+});
305+306+it("labels CRLF-formatted external PRs with screenshot proof as supplied", () => {
307+const labels = classifyPullRequestCandidateLabels(
308+pr(
309+"Fix gateway startup",
310+realBehaviorProofBody(
311+"",
312+).replace(/\n/g, "\r\n"),
313+),
314+[file("src/gateway/server.ts")],
315+);
316+317+expect(labels).toContain(PROOF_SUPPLIED_LABEL);
295318expect(labels).not.toContain(candidateLabels.needsRealBehaviorProof);
296319expect(labels).not.toContain(candidateLabels.mockOnlyProof);
297320});
@@ -662,18 +685,115 @@ describe("barnacle-auto-response", () => {
662685663686await runBarnacleAutoResponse({
664687 github,
665-context: barnacleContext({}, [candidateLabels.needsRealBehaviorProof, "proof: override"]),
688+context: barnacleContext({}, [
689+candidateLabels.needsRealBehaviorProof,
690+candidateLabels.mockOnlyProof,
691+PROOF_SUPPLIED_LABEL,
692+PROOF_SUFFICIENT_LABEL,
693+"proof: override",
694+]),
666695core: {
667696info: () => undefined,
668697},
669698});
670699671-expect(calls.removeLabel).toContainEqual(
672-expect.objectContaining({ name: candidateLabels.needsRealBehaviorProof }),
700+expect(calls.removeLabel.map((call) => call.name)).toEqual(
701+expect.arrayContaining([
702+candidateLabels.needsRealBehaviorProof,
703+candidateLabels.mockOnlyProof,
704+PROOF_SUPPLIED_LABEL,
705+PROOF_SUFFICIENT_LABEL,
706+]),
673707);
674708expect(calls.update).toEqual([]);
675709});
676710711+it("removes stale negative proof labels and adds supplied when proof is present", async () => {
712+const { calls, github } = barnacleGithub([file("src/gateway/server.ts")]);
713+714+await runBarnacleAutoResponse({
715+ github,
716+context: barnacleContext(
717+{
718+body: realBehaviorProofBody(
719+"",
720+),
721+},
722+[candidateLabels.needsRealBehaviorProof, candidateLabels.mockOnlyProof],
723+),
724+core: {
725+info: () => undefined,
726+},
727+});
728+729+expect(calls.removeLabel.map((call) => call.name)).toEqual(
730+expect.arrayContaining([
731+candidateLabels.needsRealBehaviorProof,
732+candidateLabels.mockOnlyProof,
733+]),
734+);
735+expect(calls.addLabels).toContainEqual(
736+expect.objectContaining({
737+labels: expect.arrayContaining([PROOF_SUPPLIED_LABEL]),
738+}),
739+);
740+});
741+742+it.each(["edited", "synchronize"])(
743+"removes stale sufficient proof label after PR %s events",
744+async (action) => {
745+const { calls, github } = barnacleGithub([file("src/gateway/server.ts")]);
746+747+await runBarnacleAutoResponse({
748+ github,
749+context: barnacleContext(
750+{
751+body: realBehaviorProofBody(
752+"",
753+),
754+},
755+[PROOF_SUPPLIED_LABEL, PROOF_SUFFICIENT_LABEL],
756+{ action },
757+),
758+core: {
759+info: () => undefined,
760+},
761+});
762+763+expect(calls.removeLabel).toContainEqual(
764+expect.objectContaining({ name: PROOF_SUFFICIENT_LABEL }),
765+);
766+},
767+);
768+769+it("preserves ClawSweeper's sufficient proof label on ordinary label events", async () => {
770+const { calls, github } = barnacleGithub([file("src/gateway/server.ts")]);
771+772+await runBarnacleAutoResponse({
773+ github,
774+context: barnacleContext(
775+{
776+body: realBehaviorProofBody(
777+"",
778+),
779+},
780+[PROOF_SUPPLIED_LABEL, PROOF_SUFFICIENT_LABEL],
781+{
782+action: "labeled",
783+label: { name: PROOF_SUFFICIENT_LABEL },
784+sender: { login: "openclaw-clawsweeper[bot]", type: "Bot" },
785+},
786+),
787+core: {
788+info: () => undefined,
789+},
790+});
791+792+expect(calls.removeLabel).not.toContainEqual(
793+expect.objectContaining({ name: PROOF_SUFFICIENT_LABEL }),
794+);
795+});
796+677797it("actions manually applied candidate labels", async () => {
678798const { calls, github } = barnacleGithub([file("extensions/example/openclaw.plugin.json")]);
679799此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。