Stop reporting "no matching diff" for code the model was never shown#81
Conversation
Description-drift compared a whole-PR description against a partial diff, so it reported claims as unsupported whenever their code was simply absent from the prompt. On mk7luke/agent-tui#1 all six PR-level findings named files that were in the PR the whole time. The findings read as confident rather than hedged because the reasoning was sound — only the evidence was truncated. No prompt tuning could fix that. Three independent ways the diff arrived incomplete: 1. Incremental trim. reviewer.ts mutated context.files down to files changed since the last review, and drift consumed the same object 400 lines later. Correct for line-level review; wrong for prose describing every commit. Extracted partitionFilesForReview() so the full set survives the trim. 2. Unpaginated fetch. pulls.listFiles used per_page:100 with no pagination, so PRs over 100 files silently lost the rest. Those files reached neither ignoredFiles nor cappedFiles, so nothing downstream could report the loss. Now paginated, bounded at GitHub's own 3000-file listFiles ceiling. 3. Size budget. Drift now carries its own budget — context.diffBudget is computed after the trim, so reusing it would have sent an unbounded prompt that throws and gets swallowed by the existing catch. buildChatPrompt was ignoring diffBudget entirely, which would have made that budget a no-op. Drift is also told which PR files it cannot see (ignored, capped, budget- dropped) and instructed not to report them, and CHAT_SYSTEM no longer claims full PR context it may not have. Both matter beyond the incremental case: the same false positive could fire on a full review of a large PR. Tests mutation-verified — reverting each fix fails them. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
📝 WalkthroughWalkthroughFixed false-positive description-drift findings caused by incomplete diffs by paginating file fetches, preserving the full file set for whole-PR reasoning, and telling the model which files it cannot see. Changes
Sequence Diagram(s)sequenceDiagram
participant Reviewer
participant Partition as partitionFilesForReview
participant Drift as detectDescriptionDrift
participant AI
Reviewer->>Partition: files, mode, priorFileShas
Partition-->>Reviewer: allFiles, filesToReview, skipped
Note over Reviewer: context.files trimmed for line-level review
Reviewer->>Reviewer: applyDiffBudget on allFiles
Reviewer->>Drift: full files, driftBudget, unavailableFiles
Drift->>AI: chat prompt plus scope note
AI-->>Drift: drift findings JSON
Drift-->>Reviewer: DriftFinding list
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~30 minutes Suggested Labels
Risk AssessmentScore: 5/100 — 🟢 Low
Test Coverage Signal🟢 140 prod / 243 test lines added.
Linked Issues
🚥 Pre-merge checks | ✅ 5 | ❌ 0✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in your ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Generate docstrings (beta)
🧹 Simplify (beta)
🪄 Autofix unresolved comments (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
This PR addresses the root cause of the noisy description-drift false positives in the right places: prompt scope, PR file retrieval, and reviewer orchestration. The changes are coherent and well covered by regression tests, and I did not find any correctness or contract regressions in the modified paths. The new tests also directly guard the previously broken behaviors, including incremental trimming and unpaginated listFiles fetches.
ℹ️ Review info
⚙️ Run configuration
Configuration used: .diffsentry.yaml
Review profile: ASSERTIVE
Run ID: 9b03e59c-aae8-4965-bbae-8757407db764
📥 Commits
Reviewing files at bd3aebe (base SHA unavailable).
📒 Files selected for processing (6)
src/ai/prompt.tssrc/drift.tssrc/github.tssrc/reviewer.tstests/unit/drift-scope.test.tstests/unit/pr-files-pagination.test.ts
ℹ️ The primary review model was unavailable; this review was generated by the configured backup provider.
📌 Status — last updated
|
| Risk score | 5/100 (Low) ▁ |
| Unresolved threads | 0 |
| Failing checks | 0 |
| Pending checks | 1 |
| Files reviewed | 6 |
| Updated | 2026-07-19 03:28Z |
Live-updated by DiffSentry on every push. Use @diffsentry ship for a verdict, @diffsentry timeline for full history.
|
@diffsentry release-notes |
📣 Release Notes✨ What's new
🛠 Improvements
🐛 Fixes
Marketing-speak version of this PR. Re-run with |
The bug
Description-drift compares the PR description against the diff. It was being handed a partial diff while asked to reason about a description covering the whole PR, so any claim whose supporting code wasn't in the prompt got reported as unsupported.
On mk7luke/agent-tui#1, all six PR-level findings named files that were in the PR the entire time —
.cargo/config.toml,build.rs,bin/protoc,hooks.rs,external_auth.rs,Cargo.toml.The reason they read as confident Major findings rather than hedged ones is that the model's reasoning was correct. Given the diff it saw, the change really wasn't there. The
confidence: highguidance already in the prompt couldn't help, because the diff plainly lacked the code. This was never fixable by prompt tuning.Three ways the diff arrived incomplete
1. The incremental trim (
src/reviewer.ts)context.fileswas mutated down to files changed since the last review, and drift consumed that same object 400 lines later. Right for line-level review — re-flagging untouched files is pointless, and the inline findings on #1 were correct. Wrong for prose describing ten commits.Extracted
partitionFilesForReview(), which returnsallFilesalongsidefilesToReview. Worsened with every push, since more files fall intofilesSkippedSimilar.2. Unpaginated fetch (
src/github.ts)pulls.listFilesusedper_page: 100with no pagination. PRs over 100 files silently lost the remainder — and the dropped files reached neitherignoredFilesnorcappedFiles, so nothing downstream could even report they were missed. Now paginated, bounded at GitHub's own 3000-filelistFilesceiling so a runaway PR costs a known number of calls.3. The size budget (
src/ai/prompt.ts)Drift now computes its own budget.
context.diffBudgetis calculated after the trim, so restoring the full file set while reusing it would have sent an unbounded prompt — which throws, and the existingcatchswallows drift silently. That would have traded loud false positives for quiet disappearance.buildChatPromptwas ignoringdiffBudgetentirely, so without fixing that the new budget would have been a no-op. Other chat callers set no budget and are unaffected.Beyond the reported case
Drift is now told which PR files it cannot see (config-ignored, past the cap, budget-dropped) and instructed not to report them.
CHAT_SYSTEMno longer claims "full context of the PR" it may not have.This matters independently: the same false positive could fire on a full review of a large PR. Fixing only the incremental trim would have left that alive.
Verification
tscclean; 378 tests passing across 26 files; lint unchanged from baseline (12 warnings, 0 errors — all pre-existing).allFilesto the trimmed set, dropping the scope note, and restoring the single-page fetch each fail them.Not addressed
getRelatedPRs(src/github.ts:~1320) also callslistFilesunpaginated atper_page: 50. Left alone — it's a best-effort overlap heuristic, not review input, so an incomplete list degrades a suggestion rather than producing a false finding. Worth a follow-up.🤖 Generated with Claude Code
Summary
Fixed false-positive description-drift findings caused by incomplete diffs by paginating file fetches, preserving the full file set for whole-PR reasoning, and telling the model which files it cannot see.
Changes
src/ai/prompt.tssrc/drift.tssrc/github.tssrc/reviewer.tstests/unit/drift-scope.test.tstests/unit/pr-files-pagination.test.ts