DEV Community

Cover image for Merge-Ready Isn't Production-Ready
Violetta Solovyova
Violetta Solovyova

Posted on Edited on Originally published at violetsoloveva.substack.com

Merge-Ready Isn't Production-Ready

A pull request lands with 40 changed files. An AI agent produced it in ten minutes, the description is clear, the tests are green, the code is neatly formatted, and the summary ends with "Everything works as expected." It always does. Which of those 40 files should get a careful human read?

That's the new review problem. AI lets developers build features, refactor and change large codebases faster than ever. More code reaches review, and reading all of it with the same attention doesn't scale. Skimming everything isn't the answer, and neither is adding more reviewers to every PR. We need to be deliberate about what deserves human attention.

Code review is ultimately about making a judgment: does this change solve the right problem, what could it break, and do we have enough confidence to ship it?

I answer those questions with three ideas: risk, evidence, and context. The five practices below put them to work: the first two are about risk, the next two about evidence, and the last one about context.

1. Let risk determine review depth

The number of changed lines is a poor measure of how carefully a change should be reviewed. A one-line edit to a shared API client can affect the entire application. A much larger change to an isolated component might have very limited impact. AI makes this gap wider, because a generated diff can be large, tidy and convincing whether it touches a button or the auth layer.

I start with the change's blast radius: how much of the application could be affected if it fails? I group changes into three levels.

Low blast radius: isolated code

A standalone UI component, a presentational component without shared state, a small styling adjustment, or a self-contained feature. I still check the implementation for obvious mistakes, but I can rely more on automated checks, tests and visual verification.

Medium blast radius: feature-level code

Feature-specific hooks, form validation and submission, API integration within a single feature, or state scoped to a page. These deserve a closer look at data flow, edge cases and regressions within the feature.

High blast radius: shared or core code

Global state, authentication and authorization, shared API clients, common hooks and utilities, routing, permissions, application-wide configuration, and core business logic. These call for a deeper review of dependencies, side effects, compatibility, security and production impact. I also expect stronger tests and, where useful, a second reviewer, human or AI.

Blast radius is where I start, but it isn't the whole picture. It tells me how widely a failure could spread. It doesn't tell me how likely the failure is, or how bad it would be. A shared formatting utility has a wide blast radius, but if it breaks, the cost is small. A small change to payment authorization touches one flow, and a failure there is serious.

So I look at two things together: how far a failure spreads, and how severe it is when it happens.

Imagine two PRs reviewed on the same day. One adds a 300-line settings page, new components and all. The other changes one line in the shared API client, so that a failed request now returns an empty list instead of throwing. The settings page can only break the settings page. The one-liner changes how every screen in the app handles errors, and now a failed request looks like "no data". The small diff deserves most of the review time.

Review the potential impact, not the size of the diff. The more serious the consequences, the more scrutiny the change deserves.

Blast radius versus severity of failure: four quadrants showing how much review each kind of change needs

2. Think about failure and recovery before approving

Reviewing a change means thinking beyond the happy path. Before approving, I want to answer three questions:

  1. What existing behavior must remain unchanged?
  2. What is the worst plausible outcome if this change fails?
  3. How quickly and safely can we recover?

Those questions help reveal cases that are easy to miss when looking only at whether the new code appears to work. What happens if an API returns unexpected data? What if a request fails halfway through? Could the change corrupt data, break compatibility, or weaken an authorization check?

The answers should influence both the depth of the review and the way the change is delivered. A risky change that's difficult to reverse deserves extra caution. Where possible, make it easier to recover through feature flags, gradual rollouts, backward-compatible changes, and small, focused pull requests.

Smaller changes aren't automatically safer, but they are usually easier to understand, test, discuss, and revert. A focused PR also makes it easier for reviewers to notice what matters instead of spending their attention reconstructing a large collection of unrelated changes.

A 2,000-line PR gets one of two reviews: a thorough one that takes a week, or "LGTM" in four minutes. Guess which one is more common.

A good review considers not only whether a change works, but also how it can fail and how we will recover.

3. Verify the outcome, not just the implementation

A convincing explanation isn't proof that a change works. A code review should look for evidence that the implementation behaves as expected.

The evidence depends on the type of change. For a frontend update, it might be screenshots, recordings, or a walkthrough of the affected flows. For business logic, it might be meaningful tests and their results. For an API integration, it might include verification of error handling, unexpected responses, and edge cases.

It's equally important to check the requirements. Code can be well structured, pass its tests, and still solve the wrong problem. Does the change meet the original acceptance criteria? Are the expected user flows covered? Have important scenarios been overlooked? Is the implementation more complicated than the problem requires?

This matters especially when AI agents write code. An agent can produce a plausible implementation and report that tests passed, while misunderstanding the requirement or testing only the behavior it implemented. I want to know what was actually run, what passed, and what remains unverified.

Say an agent reports "implemented the filter and all tests pass". Looking closer, the tests only cover the cases the agent wrote the code for, and the requirement says the filter must persist after a page refresh. A short recording of the flow, or a single test that reloads the page, would have shown the gap. The code was fine. It just didn't do the thing that was asked.

Don't take the implementation's correctness on trust. Check that it solves the right problem, and look for evidence that it behaves as expected.

4. Automate the noise, but protect readability

Human review time is too valuable to spend on issues that tools can detect consistently. TypeScript, ESLint, formatters, and static analysis can catch many problems before a PR reaches a reviewer. AI can also help with repetitive cleanup and straightforward refactoring.

That should leave more room for the things that need engineering judgment: correctness, architecture, security, business rules, and regressions.

This doesn't mean that every readability issue is merely a style preference. Formatting choices and personal naming preferences rarely deserve long discussions. The formatter will settle the trailing-comma debate for free, and it never gets tired. But misleading names, confusing control flow, unnecessary abstractions, and code that's hard to maintain are legitimate concerns.

A useful distinction is whether the comment expresses a personal preference or points to a real cost for the next person who has to understand or change the code.

The same principle applies to feedback. "This could be better" isn't a review comment. It's a mood. A good comment explains the problem and makes clear whether it blocks approval or is simply a suggestion.

Automate what can be checked mechanically. Use human attention for issues that require judgment, and make that feedback specific and actionable.

5. Review the change in context

Code review isn't only about understanding what changed. It's also about understanding why it changed.

Before diving into the diff, I want to understand the task, the requirements, and the problem the change is intended to solve. The PR description, linked issue, and relevant commit history can provide context that isn't visible in the implementation itself.

A piece of code might look unnecessarily complicated until you understand the constraint behind it. Every strange-looking line has a story, and it's usually a bug report. A refactoring that seems harmless might undo a decision made to prevent a regression. Without that history, it's easy to suggest a change that reintroduces an old problem.

This is one reason to keep PRs focused and Git history understandable. Clear descriptions, meaningful commits, and links to related tasks make it easier to follow how a feature evolved and to investigate problems later.

AI can help search files, trace dependencies, and summarize unfamiliar parts of a codebase. But it still needs useful context, and developers need enough understanding to judge whether its conclusions make sense. Knowing the codebase and its history makes both human and AI-assisted reviews more effective.

Don't review a diff in isolation. Understand the requirement, the surrounding code, and the decisions that led to the change.

Final thoughts

Better code review doesn't come from reading every line more carefully. It comes from deciding where careful human attention makes the biggest difference. For me that comes down to three ideas.

Risk tells you where to look. Blast radius shows how far a failure could spread. The severity of the consequences and the ease of recovery show how much it would hurt. Spend your review time there, and make risky changes easy to roll back.

Evidence tells you whether it works. Tests, screenshots, logs and walkthroughs, checked against the real requirements, count for more than a confident explanation. That's especially true when the explanation comes from an AI agent. Let tools handle the mechanical checks so your attention goes to judgment calls.

Context tells you whether it's the right change. The task, the surrounding code and the history behind it are what let you, and any AI reviewer you use, tell a real problem from a harmless-looking one.

AI makes code arrive faster. These three habits let review keep up without turning into skimming.

A change can pass its tests and be ready to merge without being ready for production. AI can help make code merge-ready. Good engineering judgment is what makes it production-ready.

Top comments (1)

Collapse
 
onelifevibe profile image
OneLifeVibe •

This framing helped me a lot, especially separating blast radius from severity. A small diff in shared auth code deserves far more attention than a large settings page, and I liked the three questions about what must stay unchanged, the worst plausible outcome, and how quickly we can recover. The point about verifying the outcome rather than trusting a confident summary also rings true with AI generated PRs, where the tests can pass while the original requirement is still missed.