Files
backnotprop__plannotator/apps/droid-plugin/lib/run-plannotator.test.js
Souptik Chakraborty 26681abb8c fix(amp,droid): surface Approve-with-Notes feedback instead of dropping it (#1146)
The Approve with Notes flow (#1092) emits decision:"approved" with a
feedback field, but both adapters collapsed every approved decision to a
bare "Approved." -- the reviewer's notes were silently lost.

Amp had two drop sites: formatAnnotationFeedback returned null for
anything not "annotated", and handleAnnotateResult early-returned on
approved before formatting was ever reached. Droid's
emitAnnotateDecision printed only "Approved."

Both adapters now emit the shared approved-with-notes prompt (mirroring
DEFAULT_ANNOTATE_APPROVED_WITH_NOTES_PROMPT in
packages/shared/prompts.ts); note-less approvals keep the old behavior.
The amp config override key approvedWithNotes matches the shared prompt
config shape.

Fixes #1137
2026-07-29 22:59:46 -07:00

75 lines
2.7 KiB
JavaScript

const { afterEach, beforeEach, describe, expect, test } = require("bun:test");
const { emitAnnotateDecision } = require("./run-plannotator");
// #1137: approved decisions carrying Approve-with-Notes feedback (#1092) were
// collapsed to a bare "Approved." and the reviewer's notes were silently
// dropped. These tests pin the full decision -> stdout contract.
describe("emitAnnotateDecision", () => {
let written;
let originalWrite;
beforeEach(() => {
written = [];
originalWrite = process.stdout.write;
process.stdout.write = (chunk) => {
written.push(String(chunk));
return true;
};
});
afterEach(() => {
process.stdout.write = originalWrite;
});
const output = () => written.join("");
test("plain approval still prints Approved.", () => {
emitAnnotateDecision('{"decision":"approved"}', "Markdown Annotations");
expect(output()).toBe("Approved.\n");
});
test("approved-with-notes surfaces the feedback instead of dropping it", () => {
emitAnnotateDecision(
JSON.stringify({
decision: "approved",
feedback: "Ship it, but rename the flag before GA.",
}),
"Markdown Annotations",
);
expect(output()).toBe(
"# Approved with Notes\n\nThe artifact is approved. The notes below are non-blocking guidance, not a request for another revision.\n\nShip it, but rename the flag before GA.\n\nDo not revise or reopen the artifact solely because of these notes unless the user explicitly requests it. Carry the notes into subsequent work where applicable.\n",
);
});
test("approved with blank feedback prints Approved.", () => {
emitAnnotateDecision('{"decision":"approved","feedback":" "}', "Markdown Annotations");
expect(output()).toBe("Approved.\n");
});
test("dismissed decision closes the session", () => {
emitAnnotateDecision('{"decision":"dismissed"}', "Markdown Annotations");
expect(output()).toBe("Annotation session closed.\n");
});
test("annotated decision wraps feedback under the heading", () => {
emitAnnotateDecision(
'{"decision":"annotated","feedback":"Comment: tighten this section."}',
"Markdown Annotations",
);
expect(output()).toBe(
"# Markdown Annotations\n\nComment: tighten this section.\n\nPlease address the annotation feedback above.\n",
);
});
test("empty output closes the session", () => {
emitAnnotateDecision("", "Markdown Annotations");
expect(output()).toBe("Annotation session closed.\n");
});
test("non-JSON output falls back to raw passthrough", () => {
emitAnnotateDecision("plain text feedback", "Markdown Annotations");
expect(output()).toBe("plain text feedback\n");
});
});