Skip to content

fix(review): give the verifier the PR description it judges description gaps against - #724

Merged
devops-thiago merged 1 commit into
mainfrom
fix/711-verifier-description-context
Aug 15, 2026
Merged

fix(review): give the verifier the PR description it judges description gaps against#724
devops-thiago merged 1 commit into
mainfrom
fix/711-verifier-description-context

Conversation

@devops-thiago

Copy link
Copy Markdown
Owner

What type of PR is this?

  • 🐛 Bug fix

Description

The finding verifier receives findings, diff, projectStack and previousFindings. It has never
received the PR title and description.

That makes one whole class of candidate unverifiable by construction: a finding that weighs the
author's stated intent against the code has half its claim in a description the verifier cannot see.
And the verifier's own prompt tells it to reject a claim whose material is not provided — so whether
such a finding survives depends on whether the model happens to notice the absence.

It noticed roughly half the time. One dogfood round, one build, five PRs each planting the same
description-versus-code mismatch:

PR claim verifier
go retry/backoff described but not implemented kept
kotlin zero-cost rows described but never emitted kept
zig ignored pools described as staged, dropped instead kept
rust 409 described as carrying the earliest free slot, returns a fixed string rejected
react search described as matching submitter name, filters title only rejected

Both rejections cite the same ground — "depends on a PR description not in the provided material"
and the code fact was equally checkable in all five. The three that survived rested on the
description exactly as much as the two that did not. That is sampling, not judgement, and it lands in
both directions: correct findings deleted on one side, and a 3/5 dimension score that measures the
coin flip rather than the capability on the other.

The fix supplies the material rather than asking the model to remember an exception. The PR
context now reaches the verifier, escaped and fenced as untrusted data exactly as the review prompt
receives it, with the section stating that such a candidate is checkable there and must not be
rejected for missing material. The rejection ground becomes inapplicable instead of remaining
applicable-but-discouraged.

The existing entry points keep their shape and send no context, which leaves the section out of the
prompt entirely rather than sending an empty heading. Both production call sites already held the
value — PromptInputs.prContext() — so nothing new is fetched or spent beyond the prompt text.

Scope — what this does not fix

This closes the structural half of #711 (instance 2). Instance 1 — a CRITICAL SQL-injection false
positive correctly rejected in one round and published in the next, on unchanged code — is variance
on material that was present, so supplying more material cannot address it. The verifier also
shares the concise model with the summary and reply lanes, so a per-call temperature or seed is not
available without splitting that lane. I'd keep #711 open for that half rather than close it here.

Related Issues

Part of #711. Related to #475, which is the general form of "the verifier never sees the context that
produced the finding"; this is the one slice of it with measured evidence of non-determinism.

How Has This Been Tested?

  • Unit tests

Red proof, with the prompt section removed:

AiServicePromptRenderingTest.verifyPromptIncludesDiffAndAllContext
  the PR title and description must reach the verifier prompt ==> expected: <true> but was: <false>

Three seams are pinned separately, because a pass-through can be wired to the wrong value and still
compile: the prompt renders the context, the service forwards it to the model call (and forwards ""
when a caller has none), and the pipeline passes the batch's own prContext rather than the diff.

  • ./mvnw -B clean compile spotbugs:check spotless:checkBugInstance size is 0
  • ./mvnw -B clean testTests run: 3267, Failures: 0, Errors: 0, Skipped: 0
  • Coverage (jacoco ∩ diff): 0 uncovered lines, 0 uncovered branches

Checklist

  • My code follows the project's coding standards
  • I have performed a self-review of my own code

…on gaps against

The verifier received findings, the diff, the project stack and the previous
findings — never the PR title and description. A candidate weighing the stated
intent against the code has half its claim in that description, so it was
unverifiable by construction, and the verifier's own prompt instructs it to
reject a claim whose material is not provided.

Across one dogfood round five PRs planted the same description-versus-code
mismatch on one build. Two were rejected on exactly that ground — 'depends on a
PR description not in the provided material' — and three were kept. The code fact
was equally checkable in all five, so the split is sampling rather than
judgement, and it lands in both directions: correct findings deleted on one side,
a 3/5 score that measures the coin flip rather than the capability on the other.

The description now reaches the call, escaped and fenced as untrusted data the
same way the review prompt receives it, with the section instructing that such a
candidate is checkable here and must not be rejected for missing material.
Supplying the material makes the rejection ground inapplicable instead of asking
the model to remember not to apply it.

The existing entry points keep their shape and send no context, which leaves the
section out of the prompt rather than sending an empty heading; both production
call sites already held the value.

Scope: this closes the structural half of #711. The CRITICAL false positive in
instance 1 is variance on material that WAS present, and the verifier shares the
concise model with the summary and reply lanes, so a per-call sampling knob is
not available without splitting that lane.
@github-actions

Copy link
Copy Markdown
Contributor

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@thrillhousebot

Copy link
Copy Markdown
Contributor

🤖 ThrillhouseBot PR Summary

What this PR does

This PR fixes the finding verifier never seeing the PR title and description, so findings that weigh the author's stated intent against the code are no longer rejected for missing material. The PR context is escaped and fenced as untrusted data in the verifier prompt when a caller has it, empty callers send an empty string to suppress the section, and the production pipeline passes the batch's own prContext. All call sites, mocks, and prompt-rendering tests are updated to the new five-argument verify contract.

Description vs. Implementation

No mismatch found between the PR description and the change.

Control-Flow Diagram

🔀 Show diagram
flowchart TD
  A["ReviewPipeline / ReviewOrchestrator"] --> B["FindingVerificationService.verify(...)"]
  B --> C{"caller has prContext?"}
  C -- "yes" --> D["FindingVerifier.verify(findings, prContext, diff, stack, prevFindings)"]
  C -- "no (null)" --> E["prContext = empty string"]
  E --> D
  D --> F["FindingVerifierPrompts renders PR Title & Description section"]
  F --> G["PR title/description fenced as untrusted data"]
  G --> H["LLM verifier can check description vs code"]
  F --> I["No prContext: section omitted from prompt"]
  I --> J["Findings judged against diff only"]
Loading

Changes Overview

  • Files changed: 9
  • Lines added: +151
  • Lines removed: -53

Changed Files

File Change Summary
src/main/java/dev/thiagogonzaga/thrillhousebot/review/FindingPipeline.java Modified Passes batchInputs.prContext() and promptInputs.prContext() into the verification service calls.
src/main/java/dev/thiagogonzaga/thrillhousebot/review/ai/FindingVerificationService.java Modified Adds a verify overload accepting prContext and forwards it to the verifier, defaulting null to empty string.
src/main/java/dev/thiagogonzaga/thrillhousebot/review/ai/FindingVerifier.java Modified Adds prContext parameter to the FindingVerifier interface's verify method.
src/main/java/dev/thiagogonzaga/thrillhousebot/review/ai/FindingVerifierPrompts.java Modified Adds conditional PR Title and Description section with untrusted-data fencing to the verifier prompt.
src/test/java/dev/thiagogonzaga/thrillhousebot/review/FindingPipelineTest.java Modified Updates verify stubs to seven arguments and asserts the batch's own prContext reaches the verifier twice per multi-call review.
src/test/java/dev/thiagogonzaga/thrillhousebot/review/ReviewOrchestratorTest.java Modified Updates the findingVerificationService stub to the seven-argument verify signature.
src/test/java/dev/thiagogonzaga/thrillhousebot/review/ai/AiServicePromptRenderingTest.java Modified Adds PRCONTEXT_SENTINEL to the verifier prompt rendering assertion.
src/test/java/dev/thiagogonzaga/thrillhousebot/review/ai/ConciseModelTruncationTest.java Modified Updates the findingVerifier.verify call to include the empty prContext argument.
src/test/java/dev/thiagogonzaga/thrillhousebot/review/ai/FindingVerificationServiceTest.java Modified Updates all verify stubs to five arguments and adds tests for PR-description passthrough and empty-context behavior.

Risk Assessment

Risk Count
🔴 Critical 0
🟠 High 0
🟡 Medium 0
🔵 Low 0

No new issues found in this PR, but the review cannot be approved until required CI is confirmed green.

⚠️ Required CI Checks Status

Some required checks are still pending or have failed:

Check Type Status Detail
dependency-review check-run ⏳ Pending -
test check-run ⏳ Pending -
trivy check-run ⏳ Pending -
format check-run ⏳ Pending -
frontend check-run ⏳ Pending -

Automated review by ThrillhouseBot. Reply with /review to re-run.

@thrillhousebot thrillhousebot Bot added bug Something isn't working java Pull requests that update java code testing Test coverage and test quality labels Aug 15, 2026
@sonarqubecloud

Copy link
Copy Markdown

@codecov

codecov Bot commented Aug 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@devops-thiago
devops-thiago merged commit 1480a20 into main Aug 15, 2026
17 checks passed
@devops-thiago
devops-thiago deleted the fix/711-verifier-description-context branch August 15, 2026 22:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working java Pull requests that update java code testing Test coverage and test quality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant