fix(review): guard /add-docs cross-batch merge with isPostable - #479
Open
devops-thiago wants to merge 1 commit into
Open
fix(review): guard /add-docs cross-batch merge with isPostable#479devops-thiago wants to merge 1 commit into
devops-thiago wants to merge 1 commit into
Conversation
The cross-batch merge in DocGenerationService.generateEachBatch keyed the
dedupe set on doc.file().strip() + ":" + doc.line() before any postability
check. DocSuggestion.file is nullable, so a model reply that omits "file" on
one entry threw NullPointerException at .strip(). The call site sits outside
planOrReportFailure's try, so the throw landed in handle()'s outer
catch (RuntimeException) which only logs: the maintainer who ran /add-docs got
no comment at all, and every valid entry in the same reply was silently lost.
Mirror PrImprovementService: gate the dedupe key with doc.isPostable(). This
also stops a non-postable entry from consuming file:line and blocking a later
batch's valid suggestion for the same declaration, and keeps malformed entries
out of the merged list so the summary no longer reports COULD_NOT_PLACE ("This
usually happens after a force-push") for a reply that was simply malformed.
Two parameterized cases in DocGenerationServiceTest pinned the defect: a
non-postable entry previously reached the merged list and was reported as
COULD_NOT_PLACE. They now assert NOTHING_TO_DOCUMENT, the correct verdict for a
reply with no usable documentation.
Refs audit a3-P1
Contributor
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
🤖 ThrillhouseBot PR SummaryWhat this PR doesAdds a postability check before constructing a dedupe key in the cross-batch merge of DocGenerationService, fixing a NullPointerException when a doc entry omits the file field, and preventing non-postable entries from blocking later valid suggestions for the same declaration line. Control-Flow Diagram🔀 Show diagramflowchart TD
A["For each doc in response.docs()"] --> B{"doc.isPostable()?"}
B -- "false" --> C["Skip (no key consumed, not merged)"]
B -- "true" --> D{"seen.add(file.strip() + ':' + line)?"}
D -- "true" --> E["Add to merged list"]
D -- "false" --> F["Duplicate, skip"]
Changes Overview
Changed Files
Risk Assessment
No new issues found in this PR, but the review cannot be approved until CI is confirmed green.
|
| Check | Type | Status | Detail |
|---|---|---|---|
| test | check-run | ⏳ Pending | - |
| changes | check-run | ⏳ Pending | - |
| format | check-run | ⏳ Pending | - |
| trivy | check-run | ⏳ Pending | - |
| actionlint | check-run | ⏳ Pending | - |
| frontend | check-run | ⏳ Pending | - |
| dependency-review | check-run | ⏳ Pending | - |
Automated review by ThrillhouseBot. Reply with /review to re-run.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



What type of PR is this?
Description
The cross-batch merge loop in
DocGenerationService.generateEachBatchbuilt its dedupe key asdoc.file().strip() + ":" + doc.line()before any postability check.DocGenerationResponse.DocSuggestion.fileis nullable —isPostable()exists precisely becausefile,line,suggestion_oldandsuggestion_newmay be null/absent. A model reply that omits"file"on one entry therefore threwNullPointerExceptionat the.strip().That call site is in
handle(), outsideplanOrReportFailure's try, so the throw landed inhandle()'s outercatch (RuntimeException)which only logs. The maintainer who ran/add-docsgot no comment at all (not evenGENERATION_FAILED), and every valid entry in the same reply was silently lost. The sibling/improveguards the identical line withimprovement.isPostable() && seen.add(dedupeKey(improvement));/add-docslost that guard when it was migrated onto the shared generator seam in #469.The fix mirrors
PrImprovementService— gate the dedupe key withdoc.isPostable():This fixes three defects at once:
fileno longer throws.file:line, so it can no longer block a later batch's valid suggestion for the same declaration line.merged, so the summary no longer reportsCOULD_NOT_PLACE("This usually happens after a force-push") for a reply that was simply malformed; it correctly reportsNOTHING_TO_DOCUMENT.Change is confined to
DocGenerationService.javaand its test.Related Issues
Refs audit a3-P1 (validated HIGH regression introduced by #469). N/A for a tracked issue number.
How Has This Been Tested?
Red/green, per finding, on the current base before and after the one-line fix.
Test 1 —
postsTheValidDocWhenAnEarlierEntryInTheSameBatchOmitsItsFileA batch reply with two doc entries: the first omits
"file"(parsed as null), the second is valid. Asserts the valid suggestion is still posted and a real comment is produced.Red (before fix) — the NPE is thrown in the merge loop and swallowed by
handle()'s outer catch, so nothing is posted. Captured verbatim from the run:and the test then fails on the missing post:
Green (after fix) — the null-
fileentry is dropped, the valid one is posted (/add-docs posted 1 suggestion(s) and 0 note(s)). Passes.Test 2 —
aNonPostableEntryDoesNotConsumeTheDedupeKeyForALaterBatchsValidOneBatch 1 returns a non-postable doc for
src/Foo.java:1(blanksuggestion_new); batch 2 returns a postable doc for the samesrc/Foo.java:1. Asserts the postable one is still posted and the summary is notCOULD_NOT_PLACE.Red (before fix) — the non-postable entry consumed the
file:linekey and suppressed the later valid suggestion; nothing was posted:Green (after fix) —
isPostable()gates the key, the non-postable entry is skipped, the valid suggestion posts. Passes.Existing test that pinned the defect
Two cases of the parameterized
doesNotPostSuggestionThatCannotAnchorCleanly(suggestion_new is blank,suggestion_old is omitted) previously assertedCOULD_NOT_PLACE— the exact misleading verdict this fix removes. They now assertNOTHING_TO_DOCUMENT, the correct verdict for a reply carrying no usable documentation. The postable-but-unanchorable cases still assertCOULD_NOT_PLACE.Gates
./mvnw -B spotless:apply— BUILD SUCCESS./mvnw -B clean compile spotbugs:check spotless:check—BugInstance size is 0, BUILD SUCCESS./mvnw -B clean test— Tests run: 2344, Failures: 0, Errors: 0, Skipped: 0, BUILD SUCCESSUnit tests
Integration tests
Manual testing
Checklist
Additional Notes
Scope is limited to the
/add-docsgenerator and its test; no unrelated files were touched or reformatted. One existing test was changed (not disabled) to assert the corrected summary verdict — explained above.