From 8ff59614c1463c4ebe9a92e4680eaf7f49187f49 Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Mon, 2 Nov 2026 13:22:40 -0700 Subject: [PATCH] fix: label a run that reviewed nothing "No review", without claiming why MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The label said "No review — every pass failed", but the same flag also marks CI runs that failed or stopped before any pass ran, so the reason was often wrong. The summary under it already says what happened. --- src/__tests__/render.test.ts | 14 ++++++++++++++ src/core/render.ts | 4 ++-- src/core/schema.ts | 4 ++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/__tests__/render.test.ts b/src/__tests__/render.test.ts index bb95eeb..b36721f 100644 --- a/src/__tests__/render.test.ts +++ b/src/__tests__/render.test.ts @@ -45,6 +45,20 @@ test("setup note renders only when there is ref advice, and never as a finding", expect(body).toContain("No findings."); }); +test("a run that reviewed nothing renders No review, without claiming why", () => { + const body = renderMarkdown({ ...base, couldNotComplete: true }, "tag"); + expect(body).toContain("**Decision:** No review\n"); + const aggregate = renderAggregateMarkdown( + [ + { scope: "app", review: { ...base, couldNotComplete: true } }, + { scope: "docs", review: base }, + ], + "tag", + [], + ); + expect(aggregate).toContain("| app | No review | 0 |"); +}); + test("coverage note only renders when incomplete is non-empty (no more wolf-crying)", () => { expect(renderMarkdown(base, "tag")).not.toContain("Coverage note"); expect(renderMarkdown({ ...base, incomplete: ["a pass timed out"] }, "tag")).toContain( diff --git a/src/core/render.ts b/src/core/render.ts index 282a6b5..c7eb85c 100644 --- a/src/core/render.ts +++ b/src/core/render.ts @@ -314,7 +314,7 @@ function renderReviewBody( const lines: string[] = [commentMarker(tag), "## 🤖 AI code review", ""]; lines.push( - `**Decision:** ${review.couldNotComplete ? "No review — every pass failed" : decisionLabel(review.decision)}`, + `**Decision:** ${review.couldNotComplete ? "No review" : decisionLabel(review.decision)}`, "", modelText(review.summary), "", @@ -1002,7 +1002,7 @@ export function renderAggregateMarkdown( ]; for (const { result, kept } of perScope) { lines.push( - `| ${stripStateMarkers(result.scope)} | ${result.review.couldNotComplete ? "No review — every pass failed" : decisionLabel(result.review.decision)} | ${kept.length} |`, + `| ${stripStateMarkers(result.scope)} | ${result.review.couldNotComplete ? "No review" : decisionLabel(result.review.decision)} | ${kept.length} |`, ); } lines.push(""); diff --git a/src/core/schema.ts b/src/core/schema.ts index f4c5057..fd05fcc 100644 --- a/src/core/schema.ts +++ b/src/core/schema.ts @@ -361,8 +361,8 @@ export const CoordinatorOutputSchema = CoordinatorModelOutputSchema.extend({ */ incomplete: z.array(z.string()).default([]), /** - * True when EVERY pass failed — nothing was actually reviewed. Set by the - * engine, never the model. Reporters must not render an approving decision + * True when nothing was actually reviewed: every pass failed, or the CI run + * failed or stopped before any pass. Set by the engine, never the model. Reporters must not render an approving decision * label for such a run (the decision enum has no "no review" member, and * widening it would ripple through dismiss state and exit codes — this flag * overrides the presentation instead).