Engineering Diaries · AI
§
AICode ReviewSoftware Engineering

AI Code Review Is Making Your Codebase Harder to Maintain

Everyone is merging faster, the PR backlog is clean, and the dashboards look very good. So why does opening a module from eight months ago feel like reading someone else's fever dream?

01 · Where It Began

That Green Checkmark Felt So Good

About six months back, our team adopted an AI-assisted code review tool. The pitch was genuinely compelling. Automated first-pass review on every PR, catching style violations, null-pointer issues, unhandled promise rejections, sketchy logic, all before any human engineer even opened the diff. Review cycles got shorter. Junior folks were getting instant feedback. That embarrassing backlog of unreviewed PRs, which had been sitting there since God knows when, vanished in about a week.

The numbers looked very nice. Mean time to merge dropped by 34%. On-call was quieter. People felt more confident pushing changes. We celebrated, recommended the tool to two other internal teams, and wrote one of those smug internal blog posts about productivity gains. You know the type.

Then eight weeks later, a senior engineer from a different team, someone who had nothing to do with our rollout, was reviewing a legacy module for a migration project. She flagged something that made the whole room go quiet. The codebase, she said, had become coherent at the line level and incoherent at the system level. Individual functions were well-commented, variable names were clear, error handling was consistent. But the architectural logic tying all those clean functions together had become nearly impossible to follow. Abstractions had multiplied. Module boundaries had blurred. The same concept was being represented four different ways across four different files, and every single one of those files had passed AI review without any issues flagged.

The AI had been optimising for correctness all along. Nobody, it turned out, had been optimising for comprehensibility.

"The AI polished every sentence in a document that was increasingly about the wrong thing. Individually correct, collectively incoherent."

02 · The Mechanism

What AI Code Review Is Actually Doing Under the Hood

To understand why this happens, you need to be honest about what these tools are doing. In order of how reliably they do it, current AI code review tools are quite good at the following:

  1. Syntactic correctness and style conformance. Matching against known patterns, linting rules, and style guides. Think of it as a very context-aware, very patient linter. It does this well, no doubt about it.
  2. Common bug pattern recognition. Off-by-one errors, race conditions in well-understood concurrent patterns, SQL injection risks, XSS vectors, unvalidated inputs. Pattern matching against a massive corpus of known vulnerabilities.
  3. Local logic coherence. Does the code inside this particular function do what the function name says? Does the conditional logic handle the cases it claims to? Works well within a single function or class boundary.
  4. Documentation and naming feedback. Whether variable names are expressive, whether docstrings actually reflect what the implementation is doing.

These are real, useful capabilities that save real time. The problem is not that the AI does them badly. The problem is what does not get checked, and nobody seems to be talking much about that part.

What AI Review Misses, Consistently

AI code review tools operate on diffs and, at best, on the surrounding file context. They cannot, and largely will not given how they are deployed, reason about the following:

The Blind Spots

Architectural intent. Whether this new abstraction is consistent with module design decisions made six months ago in a now-archived architecture decision record. The AI has no access to that record and no model of the intended system structure whatsoever.

Cross-service ownership. Whether this change to a shared utility is appropriate given that three other teams depend on it in ways not visible anywhere in this PR's diff.

Accumulated design drift. Whether this PR, perfectly reasonable in isolation, is the fifth one in a row that has added yet another parameter to an already overloaded function signature. That pattern is only visible to someone watching the codebase week over week.

Team conventions living in people's heads, not in code. Why the original author made an unintuitive choice three releases ago that the new code is now quietly undoing, for reasons that were perfectly sensible at the time.

03 · Human Behaviour

How That Little Checkmark Changes the Way People Review

Here is where it gets a bit uncomfortable, because the harm is not purely technical. It is behavioural. And it is subtle enough that most teams will not notice it happening until the damage is already done.

When an AI tool marks a PR as having no issues found, something shifts in the human review that follows. This has been documented in other domains, aviation autopilot reliance, radiology CAD systems, and it is showing up in software development now as well. The human reviewer anchors on the AI's verdict. The mental frame shifts from "let me evaluate this change" to "let me confirm the AI did not miss something obvious." Those are meaningfully different tasks, and only one of them is actually code review.

Automation Bias, Briefly Automation bias is the tendency of humans to over-rely on automated systems even when those systems are demonstrably fallible in the current context. In code review, it shows up as shorter human reviews on AI-approved PRs, a higher merge rate without discussion on AI-approved PRs, and a reduced likelihood of asking architectural questions when the surface code looks clean.

It gets worse with seniority gradients. Junior engineers, already inclined to defer to review feedback, now have two authority signals at once: the AI's approval and the senior engineer's response to it. If the AI approves and the senior engineer does a quick scan and hits merge, the junior internalises that as the correct pattern. They learn from what gets approved, not from what gets discussed. And increasingly, what gets approved is whatever the AI found acceptable.

The Review That Simply Does Not Happen

There is a second-order effect that is harder to measure but equally damaging: the review that never happens at all. When AI tools give automated first-pass feedback the moment a PR is created, the author typically addresses those AI comments before even requesting human review. By the time a human looks at it, the PR has already been through one round of revision. It looks cleaner. More finished.

The human reviewer, seeing a tidy, AI-polished diff, spends less time with it. The architectural question they might have asked on a rougher draft, something like "why are we adding another abstraction layer here when we already have one doing most of this?", just does not surface. The code looks done. The question never gets asked. The abstraction proliferates quietly, and nobody is the wiser until six months later when someone actually has to maintain the thing.

"The AI cleaned the code just enough that no one looked closely enough to notice what was actually being built underneath."

04 · A Real Pattern

The Abstraction Spiral: What It Looks Like in Practice

Let me make this concrete with a pattern we observed directly in our own codebase. Details have been changed, but the structure and the trajectory are real.

Before AI Review Adoption

The team had a straightforward UserNotificationService with two methods: sendEmail and sendSMS. Both took a user ID, a template key, and a payload. Simple, legible, understood by every engineer on the team without needing any explanation.

Original Implementation · Notification Service
class UserNotificationService {
  async sendEmail(userId: string, template: string, payload: Record<string, unknown>) {
    const user = await this.userRepo.findById(userId);
    const rendered = this.templateEngine.render(template, payload);
    return this.mailer.send({ to: user.email, body: rendered });
  }

  async sendSMS(userId: string, template: string, payload: Record<string, unknown>) {
    const user = await this.userRepo.findById(userId);
    const rendered = this.templateEngine.render(template, payload);
    return this.smsGateway.send({ to: user.phone, body: rendered });
  }
}

After Six Months of AI-Reviewed PRs

The same concept, sending a notification to a user, now involved a NotificationDispatcherFactory, an INotificationChannel interface, a ChannelRouter, a TemplateResolutionStrategy enum, and a separate UserPreferenceResolver. Each class was well-named. Each had accurate docstrings. Each had passed AI review without any issues flagged. None of the PRs that introduced them had been marked as problematic, because individually each change looked like a reasonable refactoring or extension.

The AI had caught a missing null check here, suggested a more descriptive parameter name there, flagged an unhandled promise rejection in one PR. It approved the architectural trajectory at every step, because it could see each step but not the staircase.

Why Nobody Noticed Until It Was Too Late

Any single one of those abstractions might have been a defensible call in isolation. The AI had no way to evaluate the accumulated weight of the pattern across multiple PRs over multiple weeks. It could see each diff. It could not see the trend. And since the human reviewers were anchoring on the AI's approval, neither could they. Not until a new engineer tried to trace a notification send from the API endpoint all the way to the email provider and needed 45 minutes to understand a flow that had previously been five function calls.

We actually counted. Five function calls had become twenty-three, spread across nine files, in six months of clean and approved PRs.

05 · Knowledge Loss

The Slow Disappearance of Why Things Are the Way They Are

Code review was never only about catching bugs. Its other job, arguably the more important one, is knowledge transfer. Making sure that more than one engineer understands why code was written a particular way, and that the reasoning behind design decisions lives somewhere beyond a single person's head.

AI code review short-circuits this process in a way that is completely invisible until it is far too late to fix cheaply.

The Conversation That Gets Skipped

When a human reviewer pushes back on a design decision, the author has to actually articulate their reasoning. This is genuinely useful, not just for the reviewer but for the author themselves. It forces a check on whether the reasoning holds up when said out loud. And it produces a record, a comment thread, that any future engineer can read to understand how and why a decision was made.

When the AI approves and the human reviewer skims and merges, that conversation never happens. The reasoning evaporates. The decision is made, but nobody writes down why. Six months later, when someone asks "why is the UserPreferenceResolver a separate class rather than a method on the NotificationService?", there is simply no answer anywhere. The decision was made across four PRs, each approved quickly, none of which contains a single sentence of reasoning.

What New Engineers Are Learning From Your Review History

New engineers learn a codebase through its review history. They read old PRs. They look at what got flagged, what got discussed, what the senior engineers pushed back on. This gives them a calibrated sense of the team's actual values, which architectural principles were genuinely enforced (as opposed to the ones rotting in an outdated wiki), and what kinds of decisions are supposed to warrant careful thought.

A codebase with twelve months of AI-assisted reviews produces a history that is heavily weighted toward style and syntax comments. The architectural debates are missing. A new engineer reads through it and concludes, incorrectly, that this team does not think deeply about those things. They pattern-match on what they see being discussed and model their own contributions accordingly. The culture of careful design review dies without anyone ever deciding to kill it.

34%
Faster Merge
Times Observed
61%
Fewer Review
Comments Per PR
3x
Growth in
Module Count
82%
Drop in
Architectural Discussions
06 · Three Real Failures

Things That Actually Went Wrong on Our Watch

These are not hypotheticals. These are sanitised versions of real incidents from a twelve-month window across three of our teams after aggressive AI code review adoption. I am sharing the specifics because vague warnings are not very useful, frankly.

The Dependency Inversion That Helped Nobody

An AI review tool flagged a class as violating the dependency inversion principle because it directly instantiated a concrete implementation rather than depending on an interface. Fair enough observation in general. The author, correctly following the suggestion, introduced an interface and injected the dependency. Clean, correct, approved.

What the AI could not know: this class was an internal implementation detail of a module that was explicitly designed never to be substituted or extended. The interface added zero actual flexibility, increased test setup complexity for every unit test touching that module, and left future engineers wondering why an interface existed with exactly one implementation and no conceivable second one. The decision that made direct instantiation appropriate here was documented in an ADR that predated the AI tool by eight months. Nobody referenced it in the PR. Nobody even knew to look for it.

The Naming Convention the AI Invented Out of Thin Air

Our AI review tool kept suggesting that service classes follow a naming convention using the Manager suffix: UserManager, OrderManager, SessionManager. It noted, confidently, that this was consistent with the existing pattern in the codebase. It was partially right, but in a very misleading way: there were two legacy classes with that suffix, written by an engineer who had left the team long ago. The team had consciously moved to a Service suffix convention eighteen months prior.

Over the next four months, three engineers followed the AI's suggestion without questioning it. The codebase now has two incompatible naming conventions sitting side by side, with the older pattern actively growing again because an AI incorrectly weighted a minority historical pattern as the team's current convention. Fixing this will require touching dozens of files and is nobody's priority right now, so it will just stay messy.

The Security Review That Got Quietly Skipped

This is the incident that made me want to write this article. A PR introduced a change to authentication middleware. The AI tool reviewed it and flagged three things: a missing return type annotation, an inconsistent error message format, and a variable that could be const rather than let. The author fixed all three. The AI re-reviewed and approved. The human reviewer, seeing the clean second diff with the AI's green light, merged after roughly two minutes of skimming.

The change had introduced a timing side-channel in the token comparison logic. The kind of vulnerability that requires understanding the threat model, not just the code in front of you. The AI had no model of the threat context. The human reviewer, anchored on the AI's surface approval, did not engage at that depth. The vulnerability was caught six weeks later in an internal security audit, not in production. That was lucky, not a process.

"The AI reviewed the code. Nobody reviewed the decision. Those are not the same thing, and treating them as equivalent is where the real danger sits."

07 · Where AI Fits

Where AI Review Actually Belongs in Your Pipeline

The problem is not that these AI code review tools exist at all. They add real value in specific, bounded roles. The problem is where teams are inserting them and what authority they are treating the output as having.

Current State · How Most Teams Are Using AI Review
PR Created
AI Review ✓
Human Skims
Merge
Better State · AI as a Scoped Pre-Filter Only
PR Created
AI Flags Surface Issues
Author Self-Fixes
Human Review (Architecture)
Merge

The key reframe: AI review belongs before human review, not instead of it. Its job is to clear the low-level noise so that human reviewers can spend their attention on things only humans can evaluate. When AI approval becomes a merge gate, when "the AI approved it" reduces the depth of human engagement, the tool is actively working against long-term maintainability.

What Human Review Must Be Protecting

Human reviewers, with the low-level noise already handled by the AI, should be explicitly focused on a different set of questions. Questions the AI literally cannot answer:

  1. Does this change fit the intended module boundaries? Not whether the code is correct, but whether it is in the right place within the system's intended architecture. These are genuinely different questions.
  2. Is this the third time we are solving a similar problem differently? Only a human tracking the codebase over time will notice this pattern. The AI sees the diff; the reviewer should be seeing the trend.
  3. Does the author actually understand why they made this decision? Asking "why did you choose this approach over the existing X?" in a review comment is not nitpicking. It is knowledge transfer. It is the review doing its real job.
  4. What does this change make harder downstream? AI tools are optimised to find what is wrong with the change as written. Nobody is asking what options the change closes off, what assumptions it quietly bakes in, what future work it makes painful.
  5. Is there a threat model being implicitly shifted here? For any change touching auth, data access, or external interfaces, a human must evaluate whether the change is consistent with the intended security posture, regardless of what the AI found.
08 · What We Changed

What Actually Helped: No-Nonsense Interventions

We spent about three months after identifying this problem trying different things. Some worked well. Some created new problems of their own. Here is an honest account of what had real impact.

Remove AI Approval From the Merge Gate

The single most effective change: removing AI approval as a required status check for merge. The AI tool still runs and posts its findings as comments. But engineers can no longer use "the AI approved it" as a reason to skip depth. The AI's output becomes reference material, not authorisation to merge.

This sounds trivially simple. The resistance to it was surprisingly strong. Engineers had genuinely internalised the AI approval as a time-saving mechanism and were reluctant to let it go. Getting the change through required an actual team-level conversation about what review is fundamentally for, which itself turned out to be a valuable discussion to have.

Require Architecture Notes on Certain PRs

For any change introducing a new abstraction, a new module, or a new dependency, we now require a short architecture note in the PR description. Not a formal document, just three to five sentences explaining the design decision and why it fits the existing system model. The AI cannot write this. The author must. The reviewer must engage with it before approving.

The side effect we did not anticipate: authors who are forced to articulate the architectural rationale upfront make noticeably better decisions. The act of writing "I am introducing this interface because..." forces a real check on whether the interface is actually warranted. Several PRs got simplified before they were even submitted, just because the author could not write a convincing architecture note for the original design.

Hard Checklists for High-Risk Areas

We identified three areas of the codebase where AI review is explicitly marked as insufficient in our contribution guidelines: authentication flows, data access patterns, and external API contracts. PRs touching these areas have a mandatory human review checklist that must be completed and signed off before merge, covering threat model alignment, contract versioning, and backward compatibility. The AI still reviews these PRs, but its output is clearly framed as the surface check, not the complete check.

The Thing We Did Not Expect

Making the AI's limitations explicit, formally in the contribution guidelines, actually improved how engineers interacted with the tool itself. People started providing more context in PR descriptions because they understood the AI was working with limited information. Better-described PRs produced better AI feedback, which in turn helped human reviewers more. Articulating the limitation made the tool more useful in practice. Funny how that works out.

Quarterly Codebase Walks

Once per quarter, a rotating pair of senior engineers does a deliberate walk through a section of the codebase. Not reviewing a PR, not fixing a bug, just reading the code as it currently stands and asking honestly: does this still make sense? Are these abstractions earning their keep? Have conventions drifted without anyone noticing? This practice existed before the AI tooling. After adopting AI review, we nearly dropped it as unnecessary overhead. Reinstating it has been, without exaggeration, the most important long-term health intervention we have made.

09 · Fair Assessment

Being Straight About the Trade-offs

None of what I have written above is an argument for removing AI code review tools entirely. The productivity gains are real. The bug-catching within its domain is legitimate. Junior engineers benefit from immediate, patient feedback that senior engineers often simply do not have time to give. These are not small things, and I do not want to dismiss them.

Where AI Review Genuinely Earns Its Keep

Style and convention enforcement is a real burden lifted from human reviewers, freeing them for higher-order concerns. When this is the AI's job, and clearly only this job, it delivers well.

Onboarding acceleration is genuine. New engineers get faster feedback on surface-level mistakes, the load on senior engineers for low-stakes corrections drops, and junior contributors can move faster on the things the AI can evaluate accurately.

Common vulnerability pattern detection is valuable within the AI's known pattern set. A security-focused human reviewer is still better, but the AI catches the obvious patterns consistently at scale, and that matters.

Where It Needs Active Management From You

Codebases with long architectural history need explicit guardrails to prevent the AI from reinforcing outdated patterns or approving changes that violate design decisions it simply cannot access.

Teams with high junior-to-senior ratios need to be particularly careful. Junior engineers anchor on AI approval more strongly than senior engineers. The knowledge transfer function of review is most critical for these engineers and also most likely to get short-circuited by the AI's presence in the workflow.

Security-adjacent code must always have mandatory human review with an explicit threat model check. This should be codified in your contribution guidelines, not left to individual reviewer judgment on any given day.

Where It Is Actively Creating Risk

When AI approval becomes a merge gate, whether formally in your CI pipeline or informally in team culture, the automation bias effect kicks in and human review depth degrades. This is the primary failure mode and it is entirely avoidable through deliberate configuration and team norm-setting.

When used without a human architectural review layer for changes that introduce new abstractions or cross module boundaries, the abstraction spiral is nearly inevitable over a six-to-twelve-month horizon. We saw this ourselves and measured it.

10 · Closing Thoughts

The Review You Automate Away Is Usually the One That Mattered

Here is the core tension with AI code review: the things it is best at checking are not the things that most determine whether a codebase stays maintainable over time. Style, correctness, known vulnerability patterns, these matter, but they are largely recoverable if you get them wrong. Architectural incoherence, accumulated abstraction debt, eroded institutional knowledge, these are not. They compound quietly and become very expensive to reverse at exactly the moment when the team is under the most pressure to ship.

Tooling that automates the recoverable checks is genuinely useful, when it frees human attention for the things that are not recoverable. Tooling deployed in a way that reduces human attention for the non-recoverable things, even if nobody intended this, is doing real and slow harm to the systems it claims to be improving.

The engineers on your team who remember why UserNotificationService was built the way it was, who notice when the same abstraction is being invented for the third time, who ask "why here?" when a PR looks technically fine but architecturally off, these people are your actual review system. The AI is a useful pre-filter for the grunt work. It is not a substitute for this, and treating its approval as meaningful authorisation for a merge is the mistake I have been trying to describe throughout this whole piece.

Use the AI to protect your reviewers' time and attention. Then spend that time and attention on the questions only reviewers can answer. The codebase you will be maintaining two years from now is being shaped by those conversations, or by the absence of them, right now.

· · ·
What We Actually Recommend

Do Use AI review as a pre-filter, not a merge gate. Require human review to engage explicitly with architecture, design intent, and threat model rather than just surface style.

Do Mandate short architectural rationale notes in PR descriptions for any change introducing a new abstraction or crossing a module boundary.

Do Run periodic codebase walk sessions. Explicit time spent reading the existing code, not reviewing new code, is not overhead. It is maintenance.

Don't Let AI approval substitute for human engagement on security-adjacent code. Codify mandatory human checklists for auth, data access, and external API contracts and actually enforce them.

Don't Assume that because every individual PR was approved, the accumulated trajectory of those PRs is healthy. Someone on your team needs to be watching the trend, not just each individual diff.

The statistics cited in Section 05 are drawn from internal measurements across three engineering teams over a twelve-month observation period. Figures are approximate and represent team-level aggregates, not industry benchmarks. Your experience will vary depending on team composition, codebase age, and how your AI review tooling is configured and deployed.