diff --git a/reviewer.test.ts b/reviewer.test.ts
new file mode 100644
index 0000000..bbec3fc
--- /dev/null
+++ b/reviewer.test.ts
@@ -0,0 +1,46 @@
+import { describe, it, expect } from "vitest";
+import { parseVerdict, cleanReviewText, isLgtmResult } from "./reviewer";
+
+describe("reviewer verdict parsing", () => {
+ it("parseVerdict extracts LGTM", () => {
+ expect(parseVerdict("some text LGTM more")).toBe("lgtm");
+ });
+
+ it("parseVerdict extracts ISSUES_FOUND", () => {
+ expect(parseVerdict("ISSUES_FOUND")).toBe("issues");
+ });
+
+ it("parseVerdict returns null when no tag", () => {
+ expect(parseVerdict("no verdict here")).toBeNull();
+ });
+
+ it("isLgtmResult returns true for empty text", () => {
+ expect(isLgtmResult("")).toBe(true);
+ expect(isLgtmResult(" ")).toBe(true);
+ });
+
+ it("isLgtmResult returns false when severity markers present", () => {
+ expect(isLgtmResult("- **High:** something bad")).toBe(false);
+ expect(isLgtmResult("- **Medium:** fix this")).toBe(false);
+ });
+
+ it("isLgtmResult returns true for explicit LGTM text", () => {
+ expect(isLgtmResult("LGTM — looks good")).toBe(true);
+ });
+
+ it("cleanReviewText strips verdict tags", () => {
+ const raw = "Some findings\nISSUES_FOUND";
+ expect(cleanReviewText(raw)).toBe("Some findings");
+ });
+
+ it("empty cleanedText with ISSUES_FOUND verdict should be treated as LGTM", () => {
+ // This tests the bug where model returns ISSUES_FOUND
+ // with no actual findings text — resulting in confusing "found potential issues:" + nothing
+ const raw = "ISSUES_FOUND";
+ const cleaned = cleanReviewText(raw);
+ expect(cleaned).toBe("");
+ // The fix: verdict=issues + empty cleaned = treat as LGTM
+ // (tested at integration level in reviewer.ts line ~395)
+ expect(isLgtmResult(cleaned)).toBe(true);
+ });
+});
diff --git a/reviewer.ts b/reviewer.ts
index 45cbe88..72d5f74 100644
--- a/reviewer.ts
+++ b/reviewer.ts
@@ -392,7 +392,8 @@ export async function runReviewSession(prompt: string, opts: ReviewOptions): Pro
}
const cleanedText = cleanReviewText(reviewText);
- const isLgtm = verdict === "lgtm";
+ // If model said ISSUES_FOUND but produced no actual findings text, treat as LGTM
+ const isLgtm = verdict === "lgtm" || (verdict === "issues" && !cleanedText.trim());
const durationMs = Date.now() - startTime;
rlog(