Updated August 2026.
I originally wrote this article in 2025. Since then, coding assistants have changed quickly. We went from autocomplete and chat-based helpers to agents that can explore a repository, implement features, write tests, run them, fix failures and review pull requests.
That changed the way I think about code review.
AI makes code very cheap to produce. That's useful, but it also means we can now generate implementation faster than we can properly understand it.
For me, that changes the job of the reviewer.
I care less than I used to about whether a piece of code was written by a developer, Copilot, Claude or another agent. What matters much more is whether the change makes sense in the context of the system and whether the team understands what it is about to own.
Good-looking code is easy to trust
One thing coding agents are very good at is producing code that looks convincing. The naming is usually reasonable, formatting is clean, types are there, and tests may already exist.
That makes it surprisingly easy to review too quickly.
Imagine an agent generates this:
export async function getUser(id: string) {
try {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw new Error("Failed to load user");
}
return response.json();
} catch (error) {
console.error(error);
throw error;
}
}
There is nothing obviously terrible about this. It probably works.
Now imagine the rest of the application already does this:
import { apiClient } from "@/lib/api";
import { logger } from "@/lib/logger";
const user = await apiClient.get(`/users/${id}`);
The generated version has just introduced another HTTP pattern, another error-handling strategy and direct use of console.error. It may also bypass authentication, retries, tracing or other behavior already implemented in apiClient.
The code isn't necessarily wrong in isolation. It's wrong for the codebase.
That is one of the things I pay much more attention to today.
I usually read the requirement before the diff
When a pull request arrives, the natural reflex is to open the changed files immediately.
I try not to do that anymore, especially when a lot of the implementation was generated with an agent. I first want to understand what the change was supposed to achieve.
Coding agents are very good at following instructions. The problem is that instructions are often incomplete.
Suppose the requirement says:
Only employees should be able to register.
An agent could easily generate a sophisticated email-validation utility that supports international domains, quoted addresses and a long list of RFC edge cases.
That might be technically correct, but it completely misses the point.
If the actual rule is simply that employees use a company address, this may be enough:
const isEmployeeEmail = (email: string) =>
email.endsWith("@company.com");
So before I spend time discussing abstractions or implementation details, I want to know whether the solution actually matches the requirement.
Did we miss an important business rule? Did we solve a problem that wasn't really there? Did the implementation make assumptions that were never part of the request?
These questions are not specific to AI. They were useful before Copilot existed. AI just makes it much easier to generate a lot of polished code around the wrong assumption.
Repository context matters more than local correctness
Agents are getting much better at exploring existing projects. They can search the repository, inspect nearby files and reuse utilities that already exist.
That helps a lot, but a repository does not always contain the full story.
Some decisions only make sense if you know the history of the product.
Maybe an application deliberately avoids global state because the team spent months removing it.
Maybe an API client has unusual retry logic because one external service is unreliable.
Maybe an abstraction looks awkward because several teams depend on it.
Maybe a field that looks obsolete is still needed by an older mobile client.
An agent may see the code without knowing any of that.
This is where an experienced reviewer can still bring context that doesn't exist in the task description or even in the repository itself.
When I review a change, I pay attention to whether it introduces a second way of solving a problem that the project already knows how to solve. I also look for new dependencies, duplicated utilities or abstractions that don't really match the surrounding code.
AI did not invent architectural inconsistency. It simply made it easier to create more of it, faster.
Passing tests don't always mean what they used to
This is one of the areas where my review habits have changed the most.
A few years ago, a pull request with good test coverage gave me a fairly strong signal that the author had thought through the behavior.
Today, the implementation and the tests may both have been generated by the same agent from the same prompt.
That means they can share the same misunderstanding.
Imagine the requirement is:
A user cannot cancel an order after shipment.
The implementation is:
function canCancel(status: OrderStatus) {
return status !== "delivered";
}
And the generated tests are:
expect(canCancel("pending")).toBe(true);
expect(canCancel("delivered")).toBe(false);
Everything is green.
The problem is that "shipped" was the important state.
The tests prove that the implementation behaves as expected by the implementation. They don't prove that the implementation matches the business rule.
So I still care about test coverage, but I spend more time checking where the test cases came from. For important business logic, I want at least some cases to be derived from acceptance criteria, domain rules or known edge cases rather than from the code itself.
Security is still where I slow down
Security-sensitive code has always deserved more scrutiny, and AI doesn't really change that.
What changes is how convincing an incomplete implementation can look.
Take this endpoint:
app.get("/users/:id", async (req, res) => {
const user = await db.user.findUnique({
where: { id: req.params.id },
});
res.json(user);
});
It is simple, readable and probably works.
But the important question may not be whether the user exists. It may be whether the current user is actually allowed to access that record.
That requirement can disappear very easily if the original task was only:
Add an endpoint to retrieve a user.
I deliberately spend more time around authentication, authorization, permissions, database queries, user input, file access, payments and personal data.
Static analysis, security scanners and AI reviewers are useful here. I want them in the pipeline because they catch things humans miss.
But they cannot infer every business permission rule. Sometimes the missing constraint only becomes obvious when you understand how the product is supposed to behave.
I stopped caring about how much code AI wrote
In the first version of this article, I thought the amount of AI-generated code could be a useful signal for deciding how deeply to review a pull request.
I don't think that anymore.
An agent can refactor hundreds of repetitive lines without changing much risk.
A ten-line change to authorization, payments, IAM permissions or a database migration can be far more important.
So I don't really ask how much of the pull request came from AI. I look at what the change can affect.
A small styling change deserves a small review. A new permission model deserves much more attention, regardless of whether it took a developer two hours to write or an agent thirty seconds to generate.
That feels like a much more useful way to think about it.
Let automation deal with the boring parts
By 2026, AI is not only generating code. It is reviewing it too.
I think that's a good thing.
I would rather have tooling catch formatting problems, obvious type errors, lint violations, known vulnerabilities, dead code and simple mistakes before another developer even opens the pull request.
Linters are good at linting.
Type checkers are good at type checking.
Static analysis tools are good at finding patterns humans easily overlook.
AI reviewers can also be useful for a first pass.
That leaves the human reviewer more time for the questions that are harder to automate: whether the change makes sense, whether it fits the architecture, what happens when it fails and whether the team will still be comfortable maintaining it later.
That's a better use of review time than arguing about something ESLint could have fixed automatically.
"Why?" is still one of the best review comments
One thing I have noticed since using coding agents more often is that I ask very simple questions in reviews.
Why do we need this abstraction?
Do we already solve this somewhere else?
What happens if this call fails?
Why are we introducing this dependency?
Does this actually match the requirement?
Could this be simpler?
None of those are specifically AI-related questions. They are just normal engineering questions.
That's also why I'm less convinced today that "AI code review" needs to be treated as an entirely separate discipline.
Most of the problems are familiar.
Developers were already over-engineering before Copilot. We already introduced unnecessary dependencies, missed edge cases and misunderstood requirements.
The main difference is that agents can now produce these mistakes at a much higher speed and often wrap them in code that looks perfectly reasonable.
The developer still owns the result
There is one thing I haven't changed my mind about.
If I submit code generated by an agent, I still consider it my code.
I should be able to explain what the change does, why this approach was chosen, what assumptions it makes and where the important risks are.
If I can't explain why a piece of code exists, I probably shouldn't be asking someone else to approve it.
That doesn't mean memorizing every generated line or pretending the agent wasn't involved. It just means that using AI does not remove responsibility from the developer who submits the change.
For me, that's one of the most important habits to keep as these tools become more capable.
How I actually review these changes
I don't follow a strict framework.
Most of the time I start by checking whether the pull request solves the right problem. Then I look at how well the implementation fits the existing codebase and where the real risk is.
After that, I spend more time on things like permissions, failure modes, edge cases and whether the tests reflect the requirement rather than simply confirming the implementation.
How deep I go depends entirely on the change.
A CSS adjustment doesn't need the same level of attention as an authorization rule. A mechanical refactor isn't the same as changing how data is persisted. A new dependency may deserve more discussion than fifty lines of ordinary application code.
That sounds obvious, but I find it more useful than trying to invent a special review process based on how much AI was involved.
What changed for me
AI hasn't made me distrust every generated line.
If anything, I spend less time obsessing over individual lines than I did before. I'm more interested in the decisions behind them.
Implementation is getting cheaper. Generating another version is cheap. Writing basic tests is cheap. Refactoring is cheap.
Understanding the domain is not.
Knowing which edge case actually matters is not.
Making a good architectural trade-off is not.
And taking responsibility for what goes into production certainly isn't.
The biggest change in code review, at least for me, is that AI makes implementation faster without making understanding faster.
A good review is therefore less about proving that the code works in isolation and more about making sure the team understands the change it is about to own.
I suspect that will matter even more as coding agents continue to improve.
Your Turn
I'm curious how this has changed for other teams.
When you review AI-assisted code today, what do you find yourself checking more carefully than you did a few years ago?
Business logic? Architecture? Security? Tests? Something else?
I'd be interested to hear how your own review habits have changed.
Further Reading
A few resources that are still useful regardless of whether the code was written by a developer or generated with an agent:
- Google Engineering Practices — Google's code review guidelines
- GitHub Pull Request Documentation — Pull request and review workflows
- OWASP Code Review Guide — Security-focused code review
- ESLint — JavaScript and TypeScript linting
- SonarQube — Static analysis and maintainability
- Snyk — Dependency and application security analysis
Top comments (0)