fix(issue-triage): trust only the workflow's own dispatch marker and keep a clear rerun off flagged issues

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
ryan 2026-09-19 00:51:55 +00:00
parent a5d7f6a262
commit 2d3ae5a780
4 changed files with 20 additions and 5 deletions

View file

@ -72,6 +72,13 @@ describe("dispatchTarget", () => {
expect(dispatchTarget(ready(), [unrelated], [])).toEqual({ kind: "dispatch" });
});
test("only the workflow's own marker counts, a commenter pasting it cannot opt the issue out", () => {
const forged: Comment = { ...marker, user: { type: "User", login: "someone" } };
expect(dispatchTarget(ready(), [forged], [])).toEqual({ kind: "dispatch" });
const otherBot: Comment = { ...marker, user: { type: "Bot", login: "some-other-app[bot]" } };
expect(dispatchTarget(ready(), [otherBot], [])).toEqual({ kind: "dispatch" });
});
test("an open pull request that references the issue blocks, a merged one or a plain issue does not", () => {
expect(reasonOf(dispatchTarget(ready(), [], [crossRef(41950, "open")]))).toBe("open pull request #41950 already references it");
expect(reasonOf(dispatchTarget(ready(), [], [crossRef(41950, "open"), crossRef(41960, "open")]))).toBe(

View file

@ -31,6 +31,7 @@ export type DispatchVerdict =
export const BUG_LABEL = labelName("kind", "bug");
export const RUNNING_LABEL = labelName("repro", "running");
export const DISPATCH_MARKER = "<!-- litellm:repro-dispatched -->";
export const DISPATCH_AUTHOR = "github-actions[bot]";
export const DISPATCH_COMMENT = [
DISPATCH_MARKER,
"Devin is going to try to reproduce this. A PR or a Linear ticket follows if it does. Add repro:skip to opt out",
@ -70,7 +71,7 @@ export function dispatchTarget(
if (blocking.length > 0) {
return skip(`carries ${blocking.join(", ")}`);
}
if (comments.some((comment) => comment.body.includes(DISPATCH_MARKER))) {
if (comments.some((comment) => comment.user.login === DISPATCH_AUTHOR && comment.body.includes(DISPATCH_MARKER))) {
return skip("was already dispatched once");
}
const pulls = openPullsReferencing(timeline);

View file

@ -195,6 +195,13 @@ describe("flagIssue", () => {
const { api, writes } = fakeApi(undefined, [existing]);
expect(await flagIssue(api, config, verdict())).toEqual({ kind: "skip", reason: "already carries a duplicate notice" });
expect(writes).toEqual([]);
const rerun = fakeApi(undefined, [existing]);
expect(await flagIssue(rerun.api, config, verdict({ duplicate_of: null }))).toEqual({
kind: "skip",
reason: "already carries a duplicate notice",
});
expect(rerun.writes).toEqual([]);
});
test("a failed comment leaves no marker, so the rerun finishes the job", async () => {

View file

@ -103,16 +103,16 @@ export function noticeBody(issue: Issue, prior: Issue, evidence: string): string
export async function flagIssue(api: GitHubApi, config: FlagConfig, verdict: Verdict): Promise<FlagVerdict> {
const target = flagTarget(verdict, config.issueNumber);
const issuePath = `/repos/${config.repo}/issues/${config.issueNumber}`;
const comments = await listAll<Comment>(api, `${issuePath}/comments`);
if (comments.some((comment) => comment.body.includes(NOTICE_MARKER_PREFIX))) {
return skip("already carries a duplicate notice");
}
if (target.kind === "clear") {
if (!config.dryRun) {
await api.request("POST", `${issuePath}/labels`, { labels: [CLEAR_LABEL] });
}
return target;
}
const comments = await listAll<Comment>(api, `${issuePath}/comments`);
if (comments.some((comment) => comment.body.includes(NOTICE_MARKER_PREFIX))) {
return skip("already carries a duplicate notice");
}
const prior = await api.request<Issue>("GET", `/repos/${config.repo}/issues/${target.original}`);
if (prior.pull_request !== undefined) {
return skip(`#${target.original} is a pull request`);