Engineering Notes01 December 20258 min read

Reviewing AI-Generated Code in 2026: What Linters Catch and What Still Needs a Human

Static analysis catches syntax errors and known vulnerability patterns well. It does not catch a business logic mistake that only shows up at runtime.

VishalFounder & Engineering Lead
FIGURE 1.0
EDITORIAL REFERENCE
Colorful source code on a monitor being inspected during a human code review
CONTEXT:Colorful source code on a monitor being inspected during a human code review
REFERENCE:Markus Spiske
ON THIS PAGE (6 SECTIONS)
EXECUTIVE BRIEFING · KEY TAKEAWAYS
  • ✓Automated linters and static analysis are genuinely good at syntax errors, unused code, and known vulnerability signatures — let them do that job.
  • ✓Business logic, timezone handling, and side-effect ordering are where AI-generated code most often looks correct but is not, and where a human review has to focus.
  • ✓A model reviewing its own output is not an independent check; the review authority has to sit with a person who understands the system's actual constraints.

AI coding assistants have gotten good enough that the code they produce is usually syntactically clean, follows the project's existing patterns, and passes a casual read. That is exactly what makes review harder, not easier: the failure mode has shifted from "obviously broken" to "looks completely reasonable and is wrong in a way you only notice if you already understand the domain." The useful response to that is not more skepticism of AI code in general — it is being precise about which categories of mistake a machine can catch reliably, and which ones still require a person who knows why the system is built the way it is.

What automated checks are actually good at

Static analysis, linters, and type checkers are genuinely reliable at a specific set of problems: syntax errors, unused variables and imports, obviously mistyped API calls, known vulnerable dependency versions, and pattern-matched security anti-patterns like string-concatenated SQL. These tools do not get tired, do not skim, and check every line the same way every time, which is precisely what makes them well suited to this category and poorly suited to anything that requires understanding what the code is supposed to do. We run these as a hard gate — nothing merges if they fail — because that frees human review time to focus on the things automation genuinely cannot catch.

What still requires a human, with a real example

The category of bug that consistently gets past automated tooling is business logic that is syntactically fine but semantically wrong for a specific edge case the model was not tracking. Timezone handling is a recurring example, because it is exactly the kind of problem that looks solved with a simple offset calculation and is not. A hardcoded UTC offset works for exactly one day of the year in a region that observes daylight saving, and for regions that don't observe it, it looks correct in every manual test you are likely to run — until a date crosses a boundary the test cases didn't cover.

CODE AUDIT DIFF COMPARE
// AI DRAFT (REJECTED VULNERABILITY)FAIL
1// Converting an incoming UTC timestamp to a local display hour
2- // Looks reasonable, passes every test written against a single fixed date
3- const date = new Date(incomingTimestamp);
4- const localHour = date.getUTCHours() + 5.5; // Asia/Kolkata is UTC+5:30
5- return { hour: Math.floor(localHour) };
6 
// VASIVA AUDITED (MERGED TO PRODUCTION)VERIFIED
1// Converting an incoming UTC timestamp to a local display hour
2 
3+ // Explicit IANA zone, handles DST regions correctly, and half-hour offsets
4+ // without manual arithmetic
5+ const dt = DateTime.fromISO(incomingTimestamp, { zone: 'Asia/Kolkata' });
6+ if (!dt.isValid) throw new Error('Invalid ISO timestamp');
7+ return { hour: dt.hour };

Nothing about the first version is a syntax error, and a linter has no way to flag it — it is valid, readable JavaScript that produces a plausible-looking number. The problem only shows up when you know that half-hour offsets and daylight saving are common enough that hardcoding an offset is never actually safe, and that a library like Luxon or a native `Intl` API exists specifically to avoid this class of mistake. That is domain knowledge, not a pattern a static tool matches against.

A model checking its own output is not an independent review. If the same system that wrote the timezone bug is also asked to grade the timezone code, it has no more reason to catch its own blind spot the second time than the first.

Other categories that consistently need a human

Timezone handling is one example of a broader pattern: the mistakes that survive to review are almost always about implicit assumptions the model had no way to know were wrong, rather than mistakes in syntax or obvious logic. Currency rounding is another — code that rounds to the nearest cent looks fine in every test until it hits a value where the business actually expects rounding up, or down, or to the nearest five, and none of that expectation is visible from the code itself unless someone who knows the business rule is reading it. An API call with a side effect — sending an email, charging a card, writing an audit log entry — placed before a validation step instead of after is another recurring shape: it is invisible in a single successful test run and only matters the day the validation actually fails and the side effect has already happened. Idempotency is a fourth: a retryable operation missing an idempotency key looks completely correct on the happy path, and only double-processes something the day a network retry actually fires against an operation that already succeeded.

None of these announce themselves with a stack trace or a failing test, which is exactly why they are the hard category. They require someone who already knows what the system is supposed to guarantee — that a charge only happens once, that a rounding rule matches a specific accounting convention, that a validation genuinely runs before an irreversible action — and is checking the code against that guarantee rather than against "does this run without throwing."

What an actual review pass looks like for us

In practice, reviewing AI-generated code at Vasiva is not a single undifferentiated read-through. Automated checks — lint, type checking, the test suite, dependency scanning — run first and have to pass before a human looks at anything; there is no point spending a person's attention on a typo a linter would have caught in half a second. The human pass that follows is deliberately asking a different question than "does this look right": for anything touching dates or money, we ask what happens at a boundary — a year change, a daylight saving transition, a value that rounds exactly on the line. For anything with an external side effect, we trace the order of operations explicitly rather than trusting that it reads top to bottom correctly. For anything retryable, we ask what happens if this exact request arrives twice. Framing the review around specific questions like these, instead of a general "look for bugs" pass, is what actually catches the categories that matter, because it forces the reviewer to check the code against the system's real constraints instead of skimming for things that look obviously wrong.

The review questions that catch real bugs are specific to the domain, not generic. "What happens at a boundary" and "what happens if this runs twice" catch more than "does this look correct" ever will.

Why we don't ask a model to grade its own output

It is tempting to close the loop entirely and have a second AI pass review the first one's output, and there is a real place for that as an additional automated filter — a second model can sometimes catch an inconsistency the first missed. But it is not a substitute for human review, because both passes share the same blind spots for the same underlying reason: a model's judgment about what is "obviously fine" is shaped by patterns in code it has seen before, and a hardcoded timezone offset is an extremely common pattern in code it has seen before. Asking a second model instance to review the first is asking the same kind of judgment to catch its own kind of mistake. It is a useful extra filter, not an independent one, and the distinction matters when you are deciding what your actual review gate is.

The practical version of this for a team adopting AI-assisted development is to write down, explicitly, which categories of change get a domain-specific human question applied and which are safe to pass through automated checks alone. Date and time handling, money, anything with an external side effect, anything retried automatically by infrastructure — those get a person asking the specific question that category needs. Formatting, dependency bumps, and straightforward refactors that automated tests already cover well do not need the same scrutiny every time. Making that distinction explicit, rather than applying uniform suspicion to every AI-generated line or uniform trust to all of it, is what makes review sustainable as the volume of AI-generated code goes up.

This is the same principle that runs through everything else we do with AI tooling: it drafts, it accelerates, and it is genuinely useful at that — but a named engineer is the one who decides what merges, and deterministic tools do the checking that does not require judgment. If you are integrating AI-assisted development into your own team and want to think through where that review boundary should actually sit for your systems, that is squarely AI Integration work we do.

ACADEMIC & INDUSTRY CITATIONS

References & Prior Art

REF 01Engineering Standard

Software Engineering at Google: Lessons Learned from Programming Over Time

Titus Winters, Tom Manshreck, Hyrum Wright • O’Reilly Media (2020)

Source
REF 02Security Research

Asleep at the Keyboard? Assessing the Security of GitHub Copilot’s Code Contributions

Hammond Pearce, Benjamin Tan, Baleegh Ahmad, et al. • IEEE Symposium on Security and Privacy (S&P) (2022)

Source
VERIFIED CONTRIBUTOR

Vishal

Founder & Engineering Lead

Vishal founded Vasiva in 2026 with an engineering-first rule: AI drafts, engineers decide. He writes on static analysis, runtime verification, and code review.

CURATED ARCHIVE

Continue Reading

Contextually relevant engineering logs and production architecture notes.

SYSTEM ADVISORY

Have an AI workflow or complex system worth exploring?

Work directly with the senior engineers who designed and shipped these systems. Zero vendor lock-in, deterministic architectures, and first-party audit integrity.

Primary Domain:ai integration
Evaluate the opportunity