Best Practices

Async code review vs real-time PR checks: they are not the same job

7 min read
Abstract visualization of async vs real-time review timing

There is a conversation that keeps surfacing in engineering team retrospectives. Someone asks why they still need human reviewers when they have automated PR checks. Or someone asks the reverse: why they need a PR check tool when they already have code reviewers. Both questions come from the same misunderstanding: async human review and real-time automated checks are the same job performed by different actors.

They are not. They have different inputs, different latency profiles, different failure modes, and they catch fundamentally different categories of issues. Conflating them causes teams to either underuse automation (expecting humans to catch what machines should catch) or underuse human judgment (expecting machines to catch what only humans can catch).

What async human review actually does well

A human reviewer brings context that no static analysis tool has access to: knowledge of the product roadmap, understanding of the business logic this code implements, awareness of related work in other branches, and judgment about whether the design choice is appropriate for the problem at hand.

Async review is a judgment conversation. The reviewer is asking: does this approach make sense given what I know about where we are going? Is this abstraction pulling its weight? Is the naming consistent with how we think about this domain? Will this be maintainable in a year when the person reading it does not have the context the author had?

None of these are questions a static analyzer can answer. They require understanding the intent behind the code, not just its structure. They also require context about what the rest of the codebase looks like and where it is heading, which a PR-level tool only partially has.

Async review also enables negotiation. A reviewer who disagrees with a design choice can leave a comment, the author can respond, and they can arrive at a shared understanding of a tradeoff. This is a conversation with multiple turns, not a pass/fail signal. That conversational nature is valuable and not replaceable.

What real-time PR checks do well

Automated checks run at PR open time, before any human has looked at the diff. Their value is in the speed and consistency of that pass. They do not have context fatigue, they do not skip sections because they are in a hurry, and they apply the same rule set to every PR regardless of who submitted it or what time of day it is.

The class of issues they catch is deterministic: patterns that are always wrong (a raw SQL string in a method that already has a parameterized query builder), patterns that are almost always wrong (catching and swallowing exceptions without logging), and rule violations that require no judgment to identify (a public API endpoint missing authentication middleware in a project where all other endpoints have it).

The other thing real-time checks do is reduce the cognitive load on human reviewers. When a human opens a diff that has already had a consistency pass, they are not also scanning for the mechanical issues. They can direct their attention at the things that require judgment. This is not a minor benefit; reviewer attention is the bottleneck in most code review workflows, and reducing what human reviewers have to check directly increases review depth on what matters.

The two failure modes when they are conflated

When teams expect automated checks to catch everything a human reviewer would catch, they see one failure mode: important design-level issues and logic bugs that require understanding intent go undetected until production. The automated tool gave a green status, so the PR went through with minimal human scrutiny. The tool's limitations were not visible until something broke.

When teams expect human reviewers to catch everything an automated check would catch, they see the opposite failure mode: reviewers spending time on issues that should have been resolved before they looked at the diff. A reviewer leaves a comment about a missing null check. The author fixes it. The reviewer re-reviews. All of that time is spent on an issue that could have been resolved in a CI gate before the first review request was sent. The human reviewer's time is consumed by mechanical checking, leaving less capacity for genuine design review.

We have seen both patterns. The second one is probably more common in teams that care about code quality, because those teams tend to have thorough human reviewers who catch the mechanical issues too. The cost is hidden in reviewer time, not in production incidents. But it is still a real cost.

The sequencing that actually works

The model that makes both effective is to treat them as sequential stages with different roles. Automated checks run first, before human review begins. They handle the consistency pass: does this code violate any patterns that are always wrong? Are there findings from static analysis or security scanning that need to be addressed? Is the PR structurally ready for a human to review (tests passing, linting clean, obvious mechanical issues resolved)?

Human review starts after that gate is passed. The reviewer is not picking up where the automated check left off on the same task. They are doing a different task: evaluating whether the code does the right thing, is designed well, and fits the codebase's direction. The automated check result is input to the human review, not a partial substitute for it.

When PRCheck leaves a finding on a PR, the intent is not to replace the reviewer's attention to that area. The intent is to make sure the reviewer's attention is directed at the issues the reviewer can actually evaluate, not at issues that can be verified mechanically.

Why this distinction matters for false positives

Treating automated checks and human review as the same job also distorts how teams handle false positives from automated tools. If the tool is expected to catch everything, then a false positive that suppresses a finding creates anxiety: what else is being missed? The tool's credibility is its completeness, and completeness is not achievable.

If the tool is correctly understood as a consistency pass for a specific class of deterministic issues, false positives are managed differently. A false positive on a specific rule means that rule needs tuning for the codebase. It does not imply the rest of the tool's findings are also false. And a false negative (a rule that fails to fire on a real issue) does not mean the human reviewer failed; it means the issue was in the category that human review is for.

This framing also makes it easier to configure rules well. Rules should be written to cover only the category of issues where automation produces reliable signal. Rules that require context the tool does not have will produce false positives, which over time trains engineers to ignore findings. A tighter rule set with higher precision is more valuable than a broader rule set with lower precision, even if the tighter set has more false negatives.

What each layer should own

The practical split: automated checks own pattern-level correctness, security-obvious issues, API contract violations detectable by static analysis, and style enforcement. Human review owns design quality, business logic correctness, naming and abstraction clarity, and whether the change fits the product direction.

There is overlap at the edges. A human reviewer might notice a security issue the tool missed. An automated check might flag a design-level concern that looks mechanically wrong but is actually intentional. Those overlaps are fine. The issue is not when one layer catches something the other layer was expected to own. The issue is when a layer is expected to do the other layer's entire job.

Catch issues before code ships

PRCheck reviews every pull request the moment it opens. Start in two minutes.