AI can write code in seconds.
It can generate a function, build an API endpoint, write a SQL query, create tests, refactor a component, or even scaffold an entire feature.
That speed is impressive.
But there is a dangerous moment that comes after the code is generated:
The moment you decide whether it is safe to merge.
AI-generated code can look completely reasonable while still containing subtle bugs, unnecessary dependencies, security problems, incorrect assumptions, or logic that nobody on the team fully understands.
That is why I have stopped treating AI-generated code as something that is "ready" just because it works.
I treat it like a pull request from a very fast developer who does not have complete knowledge of the application.
Before merging, I check these 10 things.
- Do I Actually Understand What the Code Is Doing?
This is my first check, and probably the most important one.
If I cannot explain the generated code, I do not merge it.
It does not matter whether:
The tests pass
The application runs
The code looks clean
The AI explained it confidently
The feature works in my local environment
If I do not understand the logic, I am accepting a maintenance problem.
For example, imagine AI generates this:
const result = items
.filter(item => item.active)
.reduce((acc, item) => {
acc[item.category] = (acc[item.category] || 0) + item.value;
return acc;
}, {});
The code is short.
It looks clean.
But before merging it, I still want to know:
What happens when category is missing?
Can value be null?
Is value always a number?
Should inactive items really be excluded?
Is this aggregation actually what the business logic requires?
The code being syntactically correct does not mean the code is logically correct.
If I cannot explain it, I do not approve it.
- Does It Actually Solve the Problem?
AI is very good at solving the problem described in a prompt.
The problem is that the prompt may not describe the real problem.
This happens frequently when developers give AI a simplified request such as:
"Add authentication to this endpoint."
The generated solution might technically add authentication.
But what does authentication mean in this application?
Does the endpoint also need authorization?
Are there different user roles?
Should admins have access to different resources?
Does the endpoint expose sensitive information?
Does the application already have an authentication middleware?
AI can optimize for the request you gave it.
It does not automatically understand the larger product requirements.
Before merging, I ask:
Does this code solve the actual problem, or just the problem described in the prompt?
That distinction matters.
- What Changed Outside the Feature?
One of the easiest ways for AI-generated code to create trouble is by changing more than you requested.
You ask for one feature.
The AI modifies:
Several files
Configuration
Dependencies
Error handling
Database logic
Existing components
Formatting
Tests
Suddenly, a 20-line feature becomes a 400-line pull request.
That is a warning sign.
I always inspect the diff.
git diff
Or, if working through GitHub, I review every changed file in the pull request.
I want to answer a simple question:
Why did every changed line need to change?
If the answer is unclear, I reduce the scope.
Smaller changes are easier to review, test, debug, and revert.
This is especially important with AI coding agents because they may have access to a much larger repository context than the specific file you initially asked them to modify.
- Are There Any Security Problems?
This is where I become much more skeptical.
AI-generated code can introduce security issues even when the code appears functional.
I specifically look for:
Hardcoded secrets
Weak authentication
Missing authorization checks
SQL injection
Command injection
Unsafe file handling
Improper input validation
Sensitive data exposure
Insecure API calls
Unsafe deserialization
Excessive permissions
For example, if AI generates database code like this:
const query = SELECT * FROM users WHERE email = '${email}';
It may look simple.
But directly inserting user input into a SQL query can create a serious injection vulnerability.
A safer implementation would use parameterized queries:
const query = "SELECT * FROM users WHERE email = ?";
const result = await db.query(query, [email]);
The exact implementation depends on the database library, but the principle remains the same.
Security cannot be delegated to the code generator.
OWASP's current guidance for secure coding with AI emphasizes human ownership and review of AI-generated changes, including security and maintainability considerations.
NIST also recommends that AI-generated software content be monitored and validated by humans rather than blindly trusted.
So my rule is simple:
If AI generated it, I still own the security of it.
- Did AI Introduce a Dependency I Don't Need?
This one is surprisingly easy to miss.
You ask AI:
"How can I convert this date into this format?"
Instead of using an existing utility in the project, AI might suggest installing a new package.
Now you have another dependency.
Another package means:
More maintenance
More updates
More potential vulnerabilities
More bundle size
More licensing considerations
More supply chain risk
Before accepting a new dependency, I ask:
Do we actually need it?
Then:
Are we already solving this problem somewhere else?
And finally:
Is this dependency trusted and maintained?
I would rather write five understandable lines using functionality already available in the project than introduce a package for something trivial.
AI has no reason to care about keeping your dependency tree small unless you explicitly tell it to.
You need to care.
- Are the Tests Actually Testing the Right Thing?
One of the most dangerous assumptions is:
"The AI wrote tests, so the code must be safe."
No.
Tests can be wrong too.
AI can generate tests that verify the implementation rather than the intended behavior.
Imagine the requirement is:
Users should not be able to access another user's profile.
An AI-generated test might verify that a request returns 403.
That sounds good.
But does it test:
Different user IDs?
Admin users?
Missing authentication?
Expired sessions?
Manipulated request parameters?
Direct API access?
A test suite can have high coverage while still missing important behavior.
I therefore ask:
What could go wrong that these tests are not checking?
Then I add tests for those cases.
At minimum, I look for:
Happy path
Does the expected scenario work?
Invalid input
What happens when users provide bad data?
Empty input
What happens when something is missing?
Boundary conditions
What happens at the limits?
Failure scenarios
What happens when a dependency fails?
Authorization
Can someone access something they should not?
Good testing is not about producing a large number of tests.
It is about testing meaningful behavior.
- What Happens With Edge Cases?
AI tends to produce solutions for the obvious scenario.
Real applications rarely live in obvious scenarios.
Suppose you ask AI to create pagination.
The normal case might be:
?page=2&limit=20
But what happens with:
?page=0
Or:
?page=-5
Or:
?limit=1000000
Or:
?page=abc
Or no parameters at all?
Edge cases are where production bugs often hide.
For every AI-generated feature, I ask:
What happens when the input is empty?
What happens when it is invalid?
What happens when it is unexpectedly large?
What happens when the dependency fails?
What happens when two things happen at the same time?
You do not need to predict every possible failure.
But you should deliberately look for the assumptions the generated code is making.
- Is the Code More Complicated Than It Needs to Be?
AI has a tendency to overengineer.
Ask it to solve a small problem and you may receive:
A new abstraction
Multiple helper functions
A configuration layer
Several interfaces
A new utility class
Extra error handling
A design pattern you did not ask for
Sometimes those things are justified.
Often they are not.
Consider this simple requirement:
Convert a string to lowercase.
You probably do not need a new utility architecture.
const normalized = input.toLowerCase();
The best code is not the code with the most architecture.
It is the code that solves the problem clearly while fitting the existing system.
Before merging AI-generated code, I ask:
Can this be simpler without losing correctness?
If yes, simplify it.
- Does It Match the Existing Codebase?
AI can generate technically valid code that does not belong in your project.
Imagine your codebase consistently uses:
async function getUser() {}
But the AI introduces a completely different pattern:
class UserRepository {
async fetchUser() {}
}
There is nothing inherently wrong with the second approach.
But if your entire application follows the first pattern, introducing a new architecture for one feature creates inconsistency.
I check:
Naming conventions
Folder structure
Error handling
Logging
Testing patterns
API conventions
Database access patterns
Type definitions
Existing abstractions
Good code does not exist in isolation.
It exists inside a codebase.
The question is not simply:
"Is this code good?"
It is:
"Is this code good for this codebase?"
- Can I Defend This Code in a Code Review?
This is my final test.
Imagine another developer asks:
"Why did you implement it this way?"
Can you answer?
If the response is:
"Because AI generated it."
That is not an answer.
AI does not own the pull request.
You do.
NIST's secure development guidance emphasizes code review and analysis, while OWASP explicitly recommends human ownership and approval for AI-generated changes.
A developer should be able to explain:
What changed
Why it changed
What assumptions were made
How it was tested
What risks exist
Why the chosen approach is appropriate
If you cannot explain those things, you probably should not merge the code yet.
My AI Code Review Checklist
Before merging AI-generated code, I run through this checklist:
[ ] I understand the generated code
[ ] It solves the actual requirement
[ ] I reviewed the complete diff
[ ] No unnecessary files were changed
[ ] No security vulnerabilities were introduced
[ ] No unnecessary dependencies were added
[ ] Tests verify actual behavior
[ ] Edge cases have been considered
[ ] The implementation is not unnecessarily complex
[ ] It follows the existing codebase patterns
[ ] I can explain and defend the implementation
That last point is important.
If you cannot defend the code, do not merge it.
AI Should Make Code Review More Important, Not Less
There is a common assumption that AI-generated code reduces the need for developers.
https://goodoff.co/
I think it changes the developer's responsibilities instead.
When writing everything manually, you spend a lot of time producing code.
When AI generates much of that code, the bottleneck can move somewhere else.
You now need to spend more time asking:
Is this correct?
Is this secure?
Is this maintainable?
Does this belong here?
What did we miss?
That means code review becomes even more important.
AI can increase the speed at which code enters your repository.
That makes human judgment more valuable, not less.
The Real Skill Is Not Getting AI to Write More Code
It is tempting to measure AI productivity by lines of code.
That is the wrong metric.
A developer who generates 1,000 lines of code and spends two days debugging it has not necessarily been more productive than someone who wrote 200 lines correctly.
The better question is:
Did AI help me produce reliable software faster?
That requires more than generation.
It requires understanding, testing, reviewing, and judgment.
The best developers using AI will not necessarily be the ones who generate the most code.
They will be the ones who know which generated code deserves to survive the review process.
Final Thoughts
AI coding tools are incredibly useful.
They can help developers explore unfamiliar APIs, generate boilerplate, write tests, explain code, refactor repetitive logic, and move from an idea to a working prototype much faster.
But generated code is still generated code.
It needs to earn its place in the codebase.
Before merging, I want to know ten things:
Do I understand it?
Does it solve the real problem?
Did it change anything unnecessary?
Is it secure?
Did it introduce unnecessary dependencies?
Do the tests actually prove the behavior?
What happens in edge cases?
Can the code be simpler?
Does it fit the existing codebase?
Can I defend the decision in a code review?
If the answer to all ten is yes, I am much more comfortable merging it.
The goal is not to distrust AI.
The goal is to trust it appropriately.
AI can generate the code.
The developer is still responsible for deciding whether that code belongs in production.
Top comments (0)