How to review a pull request you did not ask for

Open any active repository and look at the pull request list. A growing share of what is there was not requested by anyone.
Dependency version updates from an update bot. Security patches from a scanning tool. Lint and formatting corrections. Refactors an agent decided were an improvement while working on something related. Suggested fixes from static analysis. They arrive daily, they are usually small, the build usually passes, and they get approved in a few seconds each.
The review habits everybody learned were built for a different situation, and they fail on these in a specific way that is worth naming.
The missing half of a review
When you review a human's change, half of the information is already in front of you. The diff carries what was done. What is missing, reliably, is why: which approaches were tried and abandoned, what the author knew about the calling code, what they checked before deciding a case could not happen.
So reviewers ask. Why this approach. Did you consider the other thing. What happens when this is null. The question is a request for information that exists, in somebody's memory, and can be retrieved.
On an unrequested pull request there is nothing to retrieve. The agent has no retained reasoning. Ask it anyway and you will get a fluent, confident, well-structured answer, reconstructed from the diff in front of it. That answer may be correct. It carries no evidence either way, and it is more dangerous than silence, because it satisfies the reviewer's instinct that a reason was given.
This is the adjustment: the review has to be based on evidence inside the change rather than on the author's intent.
Three questions that work without an author
What did this change that I cannot see?
The diff shows only part of the change. This is most obvious on a dependency update, where the visible edit is one line in a lock file and the actual change is every difference between two versions of somebody else's code.
For a version update, the document to read is the upstream changelog between the two versions, not the diff. You are looking for behavioural changes, deprecations, default value changes, and anything in the "breaking" section that the semantic version number did not warn you about, which happens more often than the convention promises.
For a generated refactor, the invisible part is whether behaviour changed at a boundary. Refactors are defined as behaviour-preserving and generated ones sometimes are not, particularly around null handling, ordering, and error paths that no test covers.
What does this change assume about real data?
Generated changes constantly encode assumptions about data. This value is never null. This field is unused. This collection is small enough to load at once. This loop runs a handful of times.
Each is a claim about your production system, and your production system is not in the pull request. The reviewer's job on these is to notice the claim and then go and check it against something real: a query, a log, a metric. Intuition is a poor check here, because guesses about what the data looks like are wrong in exactly the way that causes incidents.
This is the same failure described in why data changes are riskier than code changes, and it shows up wherever generated code meets data nobody measured.
What happens if this is wrong at 3am?
Two properties matter, and diff size is neither of them: how much breaks if the change is wrong, and whether it can be reversed.
A change that is small and reversible deserves a fast approval, because being wrong costs a rollback. A change that is small and irreversible does not, regardless of how tidy it looks. Dropping a column, altering a permission default, changing a retry policy, modifying something that runs in a scheduled job: all of these can be eleven lines and none of them is cheaply undone.
The reason this question matters most is that approval speed in practice follows diff size, and diff size is nearly unrelated to consequence. That link is what you have to stop.
The queue problem
Behind the individual reviews is a volume problem that changes behaviour whether or not anyone decides it should.
A repository generating fifteen automated pull requests a week, each needing a genuine ten minutes of investigation, has created two and a half hours of weekly work that nobody was assigned and nobody scheduled. What happens next is predictable. The queue grows, somebody feels bad about it, and a habit forms of approving anything that looks routine. At that point the review step exists only in the process diagram, which is worse than not having it, because it is being counted as a control.
Three things help.
Set a policy per category rather than deciding per pull request. Patch updates to development-only dependencies with a suite that would catch a regression: automatic merging is reasonable. Anything touching authentication, payments, or data handling: always a human, always the changelog. Major versions: always a human. Write this down so it is a decision made once rather than fifteen times a week under time pressure.
Batch and schedule. Review these in one session on a fixed day rather than one by one as they arrive. Reviewing low-urgency changes as they arrive is how the fast-approval habit forms.
Name owners. Dependencies, security patches, and generated refactors each get a specific person. Unowned automated changes are reviewed by whoever has a spare moment, which in practice means no review.
What a passing build proves
Every one of these arrives with a passing build, and the temptation is to treat that as the answer.
A passing build is evidence about exactly the cases the test suite covers, and nothing else. On a dependency update it proves your tests still pass against the new version, which says nothing about the upstream behaviour your tests never test. On a refactor it proves the covered paths still work, and refactors go wrong on uncovered paths.
The useful habit, and it takes an afternoon once rather than effort per review, is knowing what your suite actually protects. Break something a check is supposed to catch, on purpose, and confirm the build fails. A check that cannot fail has been contributing false confidence to every review it appeared in. We made the longer argument in how many tests does AI-generated code need.
Where the actual risk sits
The dangerous unrequested pull request is never the large one. A 600-line generated refactor gets attention automatically, because its size triggers the instinct to slow down.
The one that gets merged is small, green, plausible, and appears among fourteen others exactly like it. It bumps a library that handles session tokens across a minor version where the default expiry changed. It removes a null check that a linter called redundant and that was covering a case the linter could not see. It adjusts a retry count in a job that only runs on the first of the month.
None of those are found by reading more carefully. They are found by asking what changed outside the diff, what the change assumes about real data, and what being wrong costs, on every change, including the boring ones. Especially the boring ones, since almost every change in this category is boring.
Sources
- Veracode spring 2026 GenAI code security testing: across more than 150 large language models, syntax correctness exceeded 95 percent while the security pass rate stayed near 55 percent and was roughly flat over two years.
- METR, early-2025 study of experienced open-source developers: 16 developers took 19 percent longer across 246 tasks when using AI tools, while afterwards believing they had been 20 percent faster.


