From a978ecadef3cb3bad0b8728ba8fe036ecf649632 Mon Sep 17 00:00:00 2001 From: Nicky Leach Date: Fri, 23 Oct 2026 17:38:50 -0700 Subject: [PATCH] Honor negated attachment requests in task completion (#17399) --- .../native-deliverable-feedback.test.ts | 10 ++++++++++ .../native-runtime/native-deliverable-feedback.ts | 7 ++++++- .../native-runtime/native-runner-file-handoff.test.ts | 11 ++++++++--- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/server/src/services/native-runtime/native-deliverable-feedback.test.ts b/server/src/services/native-runtime/native-deliverable-feedback.test.ts index eb6831d6530..a033834de93 100644 --- a/server/src/services/native-runtime/native-deliverable-feedback.test.ts +++ b/server/src/services/native-runtime/native-deliverable-feedback.test.ts @@ -6,6 +6,9 @@ describe("explicit file output requirements", () => { "Prepare a requested file", "Make a Markdown file named checklist.md with three items.", "Export the results as a CSV.", + "Do not modify repository files, but create an attachment.", + "Do not create attachments; export the results as CSV.", + "Do not create attachments and instead export a CSV.", "Give me a downloadable report.", "Please create out/answer.pdf and attach it.", "Do not use external services. Create a file with the results.", @@ -37,6 +40,13 @@ describe("explicit file output requirements", () => { "Read the file and explain what it does.", "Review the PDF and answer in the chat.", "Do not create a file; answer inline.", + "Run hostname, id, and pwd on your assigned computer. Report their output in a short completion comment, followed by CONTROL_PLANE_CHECK_OK. Do not modify repository files or create attachments. Mark the task done when finished.", + "Do not modify repository files or create attachments.", + "Do not edit files and do not create attachments.", + "Do not create files; instead, don't create attachments either.", + "Do not create files and attach them.", + "Don’t edit files or create attachments.", + "Never edit files nor create attachments.", "Don't attach a file. Reply with three bullets.", "Fix a crash in parser.ts.", "Read the file and write a short explanation inline.", diff --git a/server/src/services/native-runtime/native-deliverable-feedback.ts b/server/src/services/native-runtime/native-deliverable-feedback.ts index 9ad88b25449..3970c173227 100644 --- a/server/src/services/native-runtime/native-deliverable-feedback.ts +++ b/server/src/services/native-runtime/native-deliverable-feedback.ts @@ -87,7 +87,12 @@ export function explicitlyRequestsFileOutput(objective: string): boolean { const creates = [...clause.matchAll(/\b(?:create|make|write|save|export|attach|send|generate|produce|prepare|provide|give|return|build)\b/giu)]; return creates.flatMap((create, createIndex) => { const before = clause.slice(0, create.index); - if (/\b(?:do not|don't|never|no need to)\s*$/iu.test(before)) return []; + if (/\b(?:do not|don['’]t|never|no need to)\s*$/iu.test(before)) return []; + const negation = /\b(?:do not|don['’]t|never|no need to)\b/iu.exec(before); + if (negation) { + const rest = before.slice(negation.index + negation[0].length); + if (!/\binstead\b/iu.test(rest) && /^(?:\s*|[\s\S]*\b(?:and|or|nor)\s*)$/iu.test(rest)) return []; + } // Bind each object to its own verb. A denied write or "create no files" // cannot suppress a separate requested report in this same clause. const output = clause.slice(create.index + create[0].length, creates[createIndex + 1]?.index); diff --git a/server/src/services/native-runtime/native-runner-file-handoff.test.ts b/server/src/services/native-runtime/native-runner-file-handoff.test.ts index 9bf2720b67d..0abae30539f 100644 --- a/server/src/services/native-runtime/native-runner-file-handoff.test.ts +++ b/server/src/services/native-runtime/native-runner-file-handoff.test.ts @@ -325,9 +325,14 @@ describe("native runner file handoff", () => { await db.update(issueWorkProducts).set({ status: "failed" }).where(eq(issueWorkProducts.id, product.id)); await expect(nativeCompletionFeedback(db, runId, doneReport([`work_product:${product.id}`]))) .rejects.toThrow("requested file has no accessible delivery evidence"); - await db.update(heartbeatRuns).set({ contextSnapshot: { issueId, executionContinuation: { objective: "Do not create a file. Explain the result inline." } } }).where(eq(heartbeatRuns.id, runId)); - await expect(nativeCompletionFeedback(db, runId, doneReport([]))) - .resolves.toContain("Completion report accepted"); + for (const objective of [ + "Do not create a file. Explain the result inline.", + "Run hostname, id, and pwd. Report the output in a completion comment. Do not modify repository files or create attachments.", + ]) { + await db.update(heartbeatRuns).set({ contextSnapshot: { issueId, executionContinuation: { objective } } }).where(eq(heartbeatRuns.id, runId)); + await expect(nativeCompletionFeedback(db, runId, doneReport([]))) + .resolves.toContain("Completion report accepted"); + } } finally { await db.delete(issueWorkProducts).where(eq(issueWorkProducts.id, product.id)); await db.update(heartbeatRuns).set({ contextSnapshot: { issueId } }).where(eq(heartbeatRuns.id, runId));