code review

Why diff-only code review misses the bugs that hurt

The dangerous part of a change is rarely the lines that changed. It's the code that depends on them. Here's why reviewing the diff alone falls short, and what whole-codebase review does differently.

Drafted with AI assistance and reviewed by the CodeReviewer team. How we use AI

Open any pull request and you see a diff: red lines out, green lines in. It’s a clear, tidy view of what the author did. It’s also a trap, because a diff shows you what changed, not what the change affects.

Think about the last bug that reached production on your team. Odds are it wasn’t a typo in the edited lines. Those get caught, by the compiler or the tests or the reviewer. The expensive bugs tend to sit one hop away from the edit.

Four bugs a diff can’t show you

1. The caller that relied on the old behavior. Someone changes formatAmount() to return a string instead of a number. The diff is clean and correct. But three screens called it and did arithmetic on the result. None of those files is in the pull request, so none of them is in the review.

2. The second code path. Your app counts money in cents everywhere, except in the new export feature, which divides by 100 and works in decimals. On its own the new code looks fine. Next to the other fourteen money paths it’s clearly wrong, and totals will drift by a cent on three-way splits. The reviewer would need to know those other paths exist.

3. The check that wasn’t copied. Every existing endpoint in the billing module checks that the caller belongs to the workspace they’re querying. The new export endpoint doesn’t. The diff contains nothing wrong, just something missing. Missing things are nearly impossible to spot in a diff, because nothing marks the absence.

4. The test that should have changed. Behavior changed and the tests didn’t, yet the tests still pass, because they never covered the path that changed. A green check mark hides the gap.

Why human reviewers can’t just “look harder”

None of this is a skill problem. An experienced reviewer who knows the codebase well will often catch all four. The trouble is time and memory.

To catch the caller bug, the reviewer has to remember or search for every call site. To catch the second-path bug, they need to know how money is handled across the whole app. To catch the missing check, they need to hold the module’s conventions in their head and notice that one is absent. To catch the test gap, they need to map the behavior change onto the coverage.

That’s hours of work for a thorough review of one pull request, and the people who could do it are usually the busiest on the team. So reviews get narrower as teams get busier. The diff becomes the whole review.

What whole-codebase review does differently

CodeReviewer starts where a thorough human reviewer would, if they had all day. It builds your repository as it will look after the merge, then follows the change outward:

  • Callers and callees. Every place the changed code is used, and everything it uses.
  • Sibling patterns. Other code that does the same job, such as other money paths, other endpoints and other forms, so any inconsistency stands out.
  • Conventions. The checks and helpers your codebase uses consistently. Code that skips them gets flagged, with the existing examples as evidence.
  • Tests. Whether the behavior that changed is covered, and by what.

Because it has that context, a finding can cite its evidence. It doesn’t say “consider using integer arithmetic for currency”. It says “this divides by 100, but billing/invoice.ts, money/format.ts and twelve other files count in cents, so totals will drift on thirds.” A reviewer can check that in seconds and accept or reject it.

Fewer comments, more signal

The usual complaint about automated review is noise: dozens of style nitpicks and a real bug buried among them. Whole-codebase context helps here too. When the reviewer can see that your codebase always does something a certain way, it doesn’t need to raise generic best-practice comments. It raises the ones where your own code disagrees with itself.

Each finding also carries a severity (critical, major, minor or nit) and a category (bug, security, performance, structure, tests, docs, style or scope), so a team can triage quickly and skim the rest. If your team keeps dismissing a type of finding, that pattern shows up in Insights, and you can teach the reviewer your preference in a small config file in the repository.

The human reviewer’s job gets better

None of this replaces your reviewers. It changes what they spend their time on. When the first pass has already traced callers, checked conventions and flagged the missing test, the human review can focus on the questions only a person on your team can answer: Is this the right design? Is this what the customer asked for? Will we regret this in six months?

That’s the review your senior engineers want to give. The diff alone never gave them time for it.

Give every PR the review it deserves.

Start your 15-day free trial. We onboard a few teams every week.