From 014c97c3fb87044eeedc2cf422430eb9ede91d72 Mon Sep 17 00:00:00 2001 From: Thiago Gonzaga Date: Mon, 10 Aug 2026 23:41:26 +0000 Subject: [PATCH] fix(review): drop ceiling-skipped files from the walkthrough rows (#515) --- .../thrillhousebot/review/VerdictBuilder.java | 7 ++++- .../review/VerdictBuilderTest.java | 26 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/main/java/dev/thiagogonzaga/thrillhousebot/review/VerdictBuilder.java b/src/main/java/dev/thiagogonzaga/thrillhousebot/review/VerdictBuilder.java index 30e2d65f..4e3a412d 100644 --- a/src/main/java/dev/thiagogonzaga/thrillhousebot/review/VerdictBuilder.java +++ b/src/main/java/dev/thiagogonzaga/thrillhousebot/review/VerdictBuilder.java @@ -23,6 +23,7 @@ import jakarta.inject.Inject; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -146,7 +147,11 @@ ReviewResult build( var diffStats = DiffStats.fromFiles(overviewFiles, omitted, truncation) .withAuthoritativeTotals(ctx.prTotals()); - var omittedNames = Set.copyOf(truncation.omittedFileNames()); + // Rows are dropped for every never-reviewed class — planned/runtime omissions AND ceiling + // skips (the detail keeps them separate only so the disclosure names the ceiling) — while + // clipped and response-cut files keep theirs: those were partially reviewed. + var omittedNames = new HashSet<>(truncation.omittedFileNames()); + omittedNames.addAll(truncation.spendCeilingSkippedFileNames()); var changedFiles = toChangedFiles( overviewFiles.stream() diff --git a/src/test/java/dev/thiagogonzaga/thrillhousebot/review/VerdictBuilderTest.java b/src/test/java/dev/thiagogonzaga/thrillhousebot/review/VerdictBuilderTest.java index 52d57295..cb373dc6 100644 --- a/src/test/java/dev/thiagogonzaga/thrillhousebot/review/VerdictBuilderTest.java +++ b/src/test/java/dev/thiagogonzaga/thrillhousebot/review/VerdictBuilderTest.java @@ -389,6 +389,32 @@ void budgetOmittedFilesAreDroppedFromTheWalkthroughRows() { assertTrue(rowsCaptor.getValue().isEmpty(), rowsCaptor.getValue().toString()); } + @Test + void ceilingSkippedFilesAreDroppedFromTheWalkthroughRowsLikeOtherNotReviewedFiles() { + // #515 — a file skipped at the token spend ceiling was never reviewed at all: the banner says + // so and the model-facing overview lists it as not reviewed, so its walkthrough row must be + // dropped like every other not-reviewed class — only partially reviewed files (clipped, + // response-cut) keep their rows. + var ctx = + contextWithLineCapOmissions( + 0, + List.of( + new FileDiff("reviewed.java", "modified", 1, 0, 1, ""), + new FileDiff("skipped.java", "modified", 1, 0, 1, ""))); + var plan = new DiffBudgetPlanner.BudgetPlan(List.of(), List.of(), List.of(), true); + plan.recordSpendCeilingSkippedFiles(List.of("skipped.java")); + var rowsCaptor = ArgumentCaptor.forClass(List.class); + + builder.build(ctx, CLEAN_RESPONSE, CI_CLEAR, plan); + + verify(summaryGenerator) + .generate(anyInt(), anyInt(), anyInt(), rowsCaptor.capture(), any(), any()); + assertEquals( + List.of(new PrSummaryGenerator.ChangedFile("reviewed.java", "modified")), + rowsCaptor.getValue(), + "a ceiling-skipped (never reviewed) file must not keep its walkthrough row"); + } + /** * #471 — the walkthrough filter is the third site that asks an immutable name set whether it * holds a {@code FileDiff.filename()} that Jackson never validated. {@code contains(null)} throws