<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Codzee.io</title>
    <description>The latest articles on DEV Community by Codzee.io (@codzee_io).</description>
    <link>https://dev.to/codzee_io</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4072305%2F64f26605-4d54-48b4-9777-a1c76eb52c93.png</url>
      <title>DEV Community: Codzee.io</title>
      <link>https://dev.to/codzee_io</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/codzee_io"/>
    <language>en</language>
    <item>
      <title>what if Dismissed an AI Code Review Comment. Then I Checked the Next PR.</title>
      <dc:creator>Codzee.io</dc:creator>
      <pubDate>Mon, 21 Sep 2026 13:30:50 +0000</pubDate>
      <link>https://dev.to/codzee_io/what-if-dismissed-an-ai-code-review-comment-then-i-checked-the-next-pr-20j0</link>
      <guid>https://dev.to/codzee_io/what-if-dismissed-an-ai-code-review-comment-then-i-checked-the-next-pr-20j0</guid>
      <description>&lt;p&gt;I dismissed an AI code review comment.&lt;/p&gt;

&lt;p&gt;Nothing unusual there.&lt;/p&gt;

&lt;p&gt;What was interesting was what happened in the next pull request.&lt;/p&gt;

&lt;p&gt;A few &lt;a href="https://codzee.io/" rel="noopener noreferrer"&gt;PRs&lt;/a&gt; later, a similar pattern appeared in the code. I expected the same review comment.&lt;/p&gt;

&lt;p&gt;It wasn't there.&lt;/p&gt;

&lt;p&gt;That small behavior points to a bigger question for AI-assisted code review:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What should an AI reviewer do when an engineer disagrees with it?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the answer is simply “nothing,” the reviewer stays stateless.&lt;/p&gt;

&lt;p&gt;If the answer is “learn from the decision,” review behavior can become more aligned with the repository over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The annoying part of automated review
&lt;/h2&gt;

&lt;p&gt;AI code review can catch things that are easy to miss.&lt;/p&gt;

&lt;p&gt;But there is another failure mode: &lt;strong&gt;repetition&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A reviewer finds something that looks questionable according to a general coding guideline.&lt;/p&gt;

&lt;p&gt;The developer knows the pattern is intentional.&lt;/p&gt;

&lt;p&gt;The comment gets dismissed.&lt;/p&gt;

&lt;p&gt;Then another PR comes along.&lt;/p&gt;

&lt;p&gt;The same pattern appears.&lt;/p&gt;

&lt;p&gt;The reviewer raises the same concern.&lt;/p&gt;

&lt;p&gt;The developer dismisses it again.&lt;/p&gt;

&lt;p&gt;And again.&lt;/p&gt;

&lt;p&gt;At some point, the problem isn't that the reviewer cannot find issues.&lt;/p&gt;

&lt;p&gt;The problem is that it hasn't learned which issues &lt;strong&gt;this repository doesn't need to discuss repeatedly&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That is where dismissal-learning becomes interesting.&lt;/p&gt;

&lt;h2&gt;
  
  
  PR #1: The first review
&lt;/h2&gt;

&lt;p&gt;Imagine a repository where a particular implementation pattern is intentional.&lt;/p&gt;

&lt;p&gt;An AI reviewer sees it and leaves a comment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI reviewer:

Consider changing X to Y for better consistency.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The comment is reasonable in isolation.&lt;/p&gt;

&lt;p&gt;But the repository has a reason for using X.&lt;/p&gt;

&lt;p&gt;So the engineer dismisses the comment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Dismissed.

This pattern is intentional in this repository.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Normally, that interaction is over.&lt;/p&gt;

&lt;p&gt;The comment disappears from the PR.&lt;/p&gt;

&lt;p&gt;But the dismissal contains useful information.&lt;/p&gt;

&lt;h2&gt;
  
  
  A dismissal is engineering feedback
&lt;/h2&gt;

&lt;p&gt;A dismissal doesn't necessarily mean:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“The reviewer is useless.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It can mean:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This recommendation doesn't apply to this codebase.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's an important distinction.&lt;/p&gt;

&lt;p&gt;Repositories have local conventions that aren't always obvious from the code itself.&lt;/p&gt;

&lt;p&gt;Some exist because of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;compatibility requirements&lt;/li&gt;
&lt;li&gt;architectural decisions&lt;/li&gt;
&lt;li&gt;performance constraints&lt;/li&gt;
&lt;li&gt;legacy integrations&lt;/li&gt;
&lt;li&gt;operational considerations&lt;/li&gt;
&lt;li&gt;team conventions&lt;/li&gt;
&lt;li&gt;deliberate trade-offs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A generic reviewer doesn't automatically know all of these.&lt;/p&gt;

&lt;p&gt;The developer does.&lt;/p&gt;

&lt;p&gt;So when a developer dismisses a review comment, that decision can be treated as feedback about the repository.&lt;/p&gt;

&lt;p&gt;The interesting part is what happens next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turning the dismissal into repository memory
&lt;/h2&gt;

&lt;p&gt;Instead of storing only the conversation, the system can extract the underlying pattern from the interaction.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Review comment
      ↓
Developer dismissal
      ↓
Underlying pattern identified
      ↓
Repository memory
      ↓
Future reviews use that context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Repository memory:

"This pattern is accepted/preferred in this repository."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important word here is &lt;strong&gt;repository&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This isn't a global rule saying that the pattern is always correct.&lt;/p&gt;

&lt;p&gt;It is context associated with this particular codebase.&lt;/p&gt;

&lt;p&gt;That's important because engineering decisions are rarely universal.&lt;/p&gt;

&lt;p&gt;A pattern that is discouraged in one repository may be completely intentional in another.&lt;/p&gt;

&lt;h2&gt;
  
  
  PR #2: The same situation appears again
&lt;/h2&gt;

&lt;p&gt;Now a different pull request arrives.&lt;/p&gt;

&lt;p&gt;The code contains a similar pattern.&lt;/p&gt;

&lt;p&gt;Without repository memory, the reviewer might produce:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI reviewer:

Consider changing X to Y for better consistency.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which leads to another dismissal.&lt;/p&gt;

&lt;p&gt;With the previous feedback available as repository context, the reviewer can recognize that this type of comment has already been rejected for this repository.&lt;/p&gt;

&lt;p&gt;So the result is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI reviewer:

[No comment]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the part I find interesting.&lt;/p&gt;

&lt;p&gt;The system didn't need another configuration file.&lt;/p&gt;

&lt;p&gt;The developer didn't need to write a permanent rule manually.&lt;/p&gt;

&lt;p&gt;A previous engineering decision influenced a future review.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before vs. after
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Without dismissal-learning&lt;/th&gt;
&lt;th&gt;With repository memory&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;First PR&lt;/td&gt;
&lt;td&gt;Review comment appears&lt;/td&gt;
&lt;td&gt;Review comment appears&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Developer response&lt;/td&gt;
&lt;td&gt;Dismisses comment&lt;/td&gt;
&lt;td&gt;Dismisses comment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Feedback retained&lt;/td&gt;
&lt;td&gt;Little or no context&lt;/td&gt;
&lt;td&gt;Pattern becomes repository context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Similar later PR&lt;/td&gt;
&lt;td&gt;Same comment may return&lt;/td&gt;
&lt;td&gt;Reviewer can stay quiet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Developer experience&lt;/td&gt;
&lt;td&gt;Repeated explanation&lt;/td&gt;
&lt;td&gt;Less repeated feedback&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This doesn't mean every similar comment should disappear.&lt;/p&gt;

&lt;p&gt;Context still matters.&lt;/p&gt;

&lt;p&gt;But it creates the possibility of a reviewer that becomes better aligned with the repository's actual engineering decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  This isn't “remembering a conversation”
&lt;/h2&gt;

&lt;p&gt;This distinction is worth making.&lt;/p&gt;

&lt;p&gt;When people hear “AI memory,” they often think about conversational memory:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Remember what I told you yesterday.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's not the interesting part here.&lt;/p&gt;

&lt;p&gt;The useful unit is the &lt;strong&gt;engineering decision&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The system needs to understand something closer to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pattern:
    X is used in this repository.

Developer decision:
    This usage is intentional.

Review implication:
    Don't repeatedly flag this pattern in the same context.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's repository memory.&lt;/p&gt;

&lt;p&gt;It turns feedback from an individual review interaction into context that can influence future reviews.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this feedback loop matters
&lt;/h2&gt;

&lt;p&gt;Code review isn't just about detecting problems.&lt;/p&gt;

&lt;p&gt;It's also about communicating what a team considers important.&lt;/p&gt;

&lt;p&gt;Human reviewers naturally build this context over time.&lt;/p&gt;

&lt;p&gt;After reviewing hundreds of pull requests, an experienced engineer knows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which patterns are normal&lt;/li&gt;
&lt;li&gt;which warnings are usually noise&lt;/li&gt;
&lt;li&gt;which conventions are intentional&lt;/li&gt;
&lt;li&gt;which architectural decisions shouldn't be revisited every PR&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An AI reviewer that doesn't retain any of that context has to rediscover the same information repeatedly.&lt;/p&gt;

&lt;p&gt;That creates review fatigue.&lt;/p&gt;

&lt;p&gt;A feedback loop changes the model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Find something
     ↓
Developer responds
     ↓
Learn from the response
     ↓
Apply the context later
     ↓
Produce more relevant feedback
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal isn't fewer comments for the sake of fewer comments.&lt;/p&gt;

&lt;p&gt;It's &lt;strong&gt;higher-signal comments&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  There are caveats
&lt;/h2&gt;

&lt;p&gt;Dismissal-learning shouldn't turn every dismissal into a permanent rule.&lt;/p&gt;

&lt;p&gt;A developer can dismiss something because the comment is wrong.&lt;/p&gt;

&lt;p&gt;They can also dismiss it because the context is different in that particular file or PR.&lt;/p&gt;

&lt;p&gt;The architecture may change later.&lt;/p&gt;

&lt;p&gt;A pattern that was acceptable six months ago might become a technical debt issue today.&lt;/p&gt;

&lt;p&gt;So repository memory needs scope and context.&lt;/p&gt;

&lt;p&gt;The right behavior isn't:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This was dismissed once, never mention it again.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's closer to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Previous engineering feedback says this pattern is acceptable here. Consider that context before raising the same observation again.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's a much more useful mental model.&lt;/p&gt;

&lt;h2&gt;
  
  
  The interesting shift
&lt;/h2&gt;

&lt;p&gt;AI code review is often discussed in terms of how much it can detect.&lt;/p&gt;

&lt;p&gt;I think another question deserves equal attention:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How well can it learn what not to say?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A reviewer that finds everything but repeatedly generates low-value comments can still create friction.&lt;/p&gt;

&lt;p&gt;A reviewer that incorporates developer feedback can gradually become more aligned with the repository.&lt;/p&gt;

&lt;p&gt;That's what makes this behavior interesting.&lt;/p&gt;

&lt;p&gt;One comment gets dismissed.&lt;/p&gt;

&lt;p&gt;The underlying pattern becomes repository memory.&lt;/p&gt;

&lt;p&gt;A similar situation appears later.&lt;/p&gt;

&lt;p&gt;The reviewer stays quiet.&lt;/p&gt;

&lt;p&gt;Not because the reviewer has learned everything.&lt;/p&gt;

&lt;p&gt;Not because repeated comments magically disappear.&lt;/p&gt;

&lt;p&gt;But because a real engineering decision from the repository has become part of the context for the next review.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That's what “gets quieter” actually means.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want to see this behavior rather than read about it, the most useful test is simple: try it on a repository with an established review convention and watch what happens across two similar PRs.&lt;/p&gt;

&lt;p&gt;See the mechanism in action on your own repository.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Review AI-Generated Code Without Losing Your Mind</title>
      <dc:creator>Codzee.io</dc:creator>
      <pubDate>Thu, 17 Sep 2026 12:53:01 +0000</pubDate>
      <link>https://dev.to/codzee_io/how-to-review-ai-generated-code-without-losing-your-mind-5ah8</link>
      <guid>https://dev.to/codzee_io/how-to-review-ai-generated-code-without-losing-your-mind-5ah8</guid>
      <description>&lt;p&gt;&lt;a href="https://www.codzee.io/" rel="noopener noreferrer"&gt;AI &lt;/a&gt;can generate a working implementation in seconds.&lt;/p&gt;

&lt;p&gt;That doesn't mean the implementation is correct.&lt;/p&gt;

&lt;p&gt;For developers, this creates a slightly different code-review problem. You're no longer reviewing only code written from scratch by someone who understands the surrounding system. You're often reviewing code generated from a prompt, existing examples, partial context, or a combination of all three.&lt;/p&gt;

&lt;p&gt;The result can compile, pass tests, and look perfectly reasonable while still being wrong.&lt;/p&gt;

&lt;p&gt;The answer isn't to distrust every line of AI-generated code. It's to review it differently.&lt;/p&gt;

&lt;p&gt;This article presents a practical approach for reviewing AI-generated changes without spending an hour reading every line with equal attention.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Why AI-Generated Code Is Different
&lt;/h2&gt;

&lt;p&gt;AI-generated code has one particularly important characteristic:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It can be locally convincing while being globally incorrect.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider a simple API endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/users/{user_id}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_db&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User not found&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, this looks fine.&lt;/p&gt;

&lt;p&gt;But several questions immediately matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is the endpoint authenticated?&lt;/li&gt;
&lt;li&gt;Can any authenticated user retrieve another user's data?&lt;/li&gt;
&lt;li&gt;Is &lt;code&gt;User&lt;/code&gt; safely serializable?&lt;/li&gt;
&lt;li&gt;Does returning the ORM object expose fields that shouldn't leave the API?&lt;/li&gt;
&lt;li&gt;Is there an authorization requirement that isn't represented in this function?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code itself doesn't contain enough information to answer those questions.&lt;/p&gt;

&lt;p&gt;That's common with AI-generated code.&lt;/p&gt;

&lt;p&gt;The model optimizes for producing a plausible implementation from the available context. It doesn't automatically understand your organization's security model, undocumented business rules, production traffic patterns, or architectural constraints.&lt;/p&gt;

&lt;p&gt;So code review needs to evaluate two things:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does this code do?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;and&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What assumptions does this code make?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The second question is often where the important bugs are.&lt;/p&gt;




&lt;h1&gt;
  
  
  2. What Should Reviewers Check First?
&lt;/h1&gt;

&lt;p&gt;Don't start by reading every line.&lt;/p&gt;

&lt;p&gt;Start with the change itself.&lt;/p&gt;

&lt;p&gt;Before looking at implementation details, answer:&lt;/p&gt;

&lt;h3&gt;
  
  
  What problem is this PR solving?
&lt;/h3&gt;

&lt;p&gt;If the PR description says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Add caching to improve API performance."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;you should immediately ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What endpoint?&lt;/li&gt;
&lt;li&gt;What data is cached?&lt;/li&gt;
&lt;li&gt;How long?&lt;/li&gt;
&lt;li&gt;What invalidates it?&lt;/li&gt;
&lt;li&gt;Is stale data acceptable?&lt;/li&gt;
&lt;li&gt;Is the cache shared between users?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then look at the diff.&lt;/p&gt;

&lt;p&gt;A useful first pass is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Understand the intended behavior.&lt;/li&gt;
&lt;li&gt;Identify the files changed.&lt;/li&gt;
&lt;li&gt;Look for changes to security boundaries.&lt;/li&gt;
&lt;li&gt;Look for database and external-service interactions.&lt;/li&gt;
&lt;li&gt;Look for new state or caching.&lt;/li&gt;
&lt;li&gt;Check error-handling paths.&lt;/li&gt;
&lt;li&gt;Only then inspect implementation details.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This prevents a common review failure: spending ten minutes debating naming while missing a broken authorization check.&lt;/p&gt;




&lt;h1&gt;
  
  
  3. Logic and Edge Cases
&lt;/h1&gt;

&lt;p&gt;AI-generated code frequently handles the happy path well.&lt;/p&gt;

&lt;p&gt;The interesting bugs tend to live elsewhere.&lt;/p&gt;

&lt;p&gt;Suppose an AI-generated function processes payments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculateRefund&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requestedAmount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestedAmount&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;requestedAmount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks harmless.&lt;/p&gt;

&lt;p&gt;But what happens with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;calculateRefund&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function returns &lt;code&gt;-100&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What about floating-point currency?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What about an already-refunded order?&lt;/p&gt;

&lt;p&gt;What about concurrent refund requests?&lt;/p&gt;

&lt;p&gt;What about an order whose total has changed after partial refunds?&lt;/p&gt;

&lt;p&gt;The important question isn't:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Does this function work?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Under what conditions does this function stop working?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For AI-generated code, explicitly test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Empty input&lt;/li&gt;
&lt;li&gt;Null/undefined values&lt;/li&gt;
&lt;li&gt;Zero values&lt;/li&gt;
&lt;li&gt;Negative values&lt;/li&gt;
&lt;li&gt;Very large values&lt;/li&gt;
&lt;li&gt;Duplicate requests&lt;/li&gt;
&lt;li&gt;Concurrent requests&lt;/li&gt;
&lt;li&gt;Missing records&lt;/li&gt;
&lt;li&gt;Deleted records&lt;/li&gt;
&lt;li&gt;Partial failures&lt;/li&gt;
&lt;li&gt;Timeouts&lt;/li&gt;
&lt;li&gt;Retries&lt;/li&gt;
&lt;li&gt;Invalid state transitions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Consider this common pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;create_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That looks reasonable until two requests arrive simultaneously.&lt;/p&gt;

&lt;p&gt;Both requests can observe that the user doesn't exist.&lt;/p&gt;

&lt;p&gt;Both attempt to create it.&lt;/p&gt;

&lt;p&gt;Now you've discovered a race condition.&lt;/p&gt;

&lt;p&gt;The database should usually enforce the invariant as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;users_email_unique&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the application needs to handle the constraint violation appropriately.&lt;/p&gt;

&lt;p&gt;Don't assume the generated code has considered concurrency simply because the sequential logic looks correct.&lt;/p&gt;




&lt;h1&gt;
  
  
  4. Security
&lt;/h1&gt;

&lt;p&gt;Security deserves an earlier pass than ordinary correctness.&lt;/p&gt;

&lt;p&gt;AI-generated code can accidentally introduce vulnerabilities because security depends heavily on context.&lt;/p&gt;

&lt;h3&gt;
  
  
  SQL injection
&lt;/h3&gt;

&lt;p&gt;Bad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM users WHERE email = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;
&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM users WHERE email = :email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But parameterized queries aren't the end of the review.&lt;/p&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is authorization enforced?&lt;/li&gt;
&lt;li&gt;Is sensitive information logged?&lt;/li&gt;
&lt;li&gt;Are secrets exposed?&lt;/li&gt;
&lt;li&gt;Is user-controlled input trusted?&lt;/li&gt;
&lt;li&gt;Are uploaded files validated?&lt;/li&gt;
&lt;li&gt;Are redirects controlled?&lt;/li&gt;
&lt;li&gt;Are permissions checked server-side?&lt;/li&gt;
&lt;li&gt;Are internal errors exposed to clients?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/admin/users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Authentication exists.&lt;/p&gt;

&lt;p&gt;Authorization might not.&lt;/p&gt;

&lt;p&gt;A reviewer should ask whether &lt;code&gt;req.user&lt;/code&gt; actually has permission to access the endpoint.&lt;/p&gt;

&lt;h3&gt;
  
  
  Logging is another common problem
&lt;/h3&gt;

&lt;p&gt;An AI-generated debugging statement might look innocent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Payment request: %s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the request contains card information, authentication tokens, addresses, or other sensitive fields, you've just created a data-exposure problem.&lt;/p&gt;

&lt;p&gt;Review security based on &lt;strong&gt;data flow&lt;/strong&gt;, not just individual functions.&lt;/p&gt;




&lt;h1&gt;
  
  
  5. Tests
&lt;/h1&gt;

&lt;p&gt;Passing tests don't prove that generated code is correct.&lt;/p&gt;

&lt;p&gt;They prove that the tested scenarios currently behave as expected.&lt;/p&gt;

&lt;p&gt;AI-generated tests can have another problem: they may simply encode the implementation rather than validate the requirement.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_discount&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_discount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful, but incomplete.&lt;/p&gt;

&lt;p&gt;What about:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;calculate_discount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;calculate_discount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;calculate_discount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;calculate_discount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;110&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;calculate_discount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More importantly, ask whether the tests represent actual business requirements.&lt;/p&gt;

&lt;p&gt;A strong review checks:&lt;/p&gt;

&lt;h3&gt;
  
  
  Coverage of behavior
&lt;/h3&gt;

&lt;p&gt;Not just line coverage.&lt;/p&gt;

&lt;p&gt;You want coverage of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Happy paths&lt;/li&gt;
&lt;li&gt;Failure paths&lt;/li&gt;
&lt;li&gt;Boundary conditions&lt;/li&gt;
&lt;li&gt;Authorization&lt;/li&gt;
&lt;li&gt;State transitions&lt;/li&gt;
&lt;li&gt;Retries&lt;/li&gt;
&lt;li&gt;Timeouts&lt;/li&gt;
&lt;li&gt;Concurrency where relevant&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Test independence
&lt;/h3&gt;

&lt;p&gt;Watch for tests that depend on execution order or shared mutable state.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mock realism
&lt;/h3&gt;

&lt;p&gt;AI-generated tests often mock everything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;mock_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fake_user&lt;/span&gt;
&lt;span class="n"&gt;mock_api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;return_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ok&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The test may pass while the real integration is broken.&lt;/p&gt;

&lt;p&gt;Mocks should isolate behavior intentionally, not hide the behavior you're supposed to verify.&lt;/p&gt;




&lt;h1&gt;
  
  
  6. Architecture
&lt;/h1&gt;

&lt;p&gt;This is where human review becomes particularly important.&lt;/p&gt;

&lt;p&gt;AI is very good at producing an implementation that fits the immediate request.&lt;/p&gt;

&lt;p&gt;It isn't necessarily good at knowing whether that implementation belongs in your architecture.&lt;/p&gt;

&lt;p&gt;Imagine a service that adds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;externalApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All inside one HTTP controller.&lt;/p&gt;

&lt;p&gt;Each operation may work.&lt;/p&gt;

&lt;p&gt;The architectural problem is that one request handler now owns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;persistence&lt;/li&gt;
&lt;li&gt;external integration&lt;/li&gt;
&lt;li&gt;caching&lt;/li&gt;
&lt;li&gt;notifications&lt;/li&gt;
&lt;li&gt;business logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The PR might technically work while making the system harder to evolve.&lt;/p&gt;

&lt;p&gt;Ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does this belong in this layer?&lt;/li&gt;
&lt;li&gt;Are responsibilities separated?&lt;/li&gt;
&lt;li&gt;Is existing architecture being bypassed?&lt;/li&gt;
&lt;li&gt;Does this introduce a new abstraction unnecessarily?&lt;/li&gt;
&lt;li&gt;Does this duplicate existing functionality?&lt;/li&gt;
&lt;li&gt;Does this create a new dependency?&lt;/li&gt;
&lt;li&gt;Does the data flow still match the system's boundaries?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI-generated code often creates new helpers or abstractions when an existing one already exists.&lt;/p&gt;

&lt;p&gt;Search the repository before approving new infrastructure.&lt;/p&gt;

&lt;p&gt;The best implementation may already be somewhere in the codebase.&lt;/p&gt;




&lt;h1&gt;
  
  
  7. Maintainability
&lt;/h1&gt;

&lt;p&gt;Readable code isn't necessarily maintainable code.&lt;/p&gt;

&lt;p&gt;Look for unnecessary complexity.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shouldProcess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;disabled&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deletedAt&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deletedAt&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;write&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code works, but the condition is difficult to reason about.&lt;/p&gt;

&lt;p&gt;Could the domain logic be clearer?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;canWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;disabled&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deletedAt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;write&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During review, consider the next developer.&lt;/p&gt;

&lt;p&gt;Will they understand why this code exists?&lt;/p&gt;

&lt;p&gt;Can they modify it safely?&lt;/p&gt;

&lt;p&gt;Does it introduce duplicated logic?&lt;/p&gt;

&lt;p&gt;Does the naming describe the domain?&lt;/p&gt;

&lt;p&gt;Is there enough context around non-obvious decisions?&lt;/p&gt;

&lt;p&gt;AI can produce syntactically clean code very quickly. That doesn't automatically make the codebase easier to maintain.&lt;/p&gt;




&lt;h1&gt;
  
  
  8. Common AI-Review Mistakes
&lt;/h1&gt;

&lt;p&gt;There are several ways reviewers can make AI-generated PRs harder to review.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake 1: Reviewing every line equally
&lt;/h3&gt;

&lt;p&gt;Not every line has the same risk.&lt;/p&gt;

&lt;p&gt;Focus attention on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Security boundaries&lt;/li&gt;
&lt;li&gt;Database mutations&lt;/li&gt;
&lt;li&gt;Authentication/authorization&lt;/li&gt;
&lt;li&gt;Concurrency&lt;/li&gt;
&lt;li&gt;External APIs&lt;/li&gt;
&lt;li&gt;State changes&lt;/li&gt;
&lt;li&gt;Error handling&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Mistake 2: Trusting green tests
&lt;/h3&gt;

&lt;p&gt;Tests are evidence.&lt;/p&gt;

&lt;p&gt;They're not proof.&lt;/p&gt;

&lt;p&gt;Ask what isn't tested.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake 3: Focusing on style before behavior
&lt;/h3&gt;

&lt;p&gt;Don't spend ten comments discussing variable naming while missing incorrect business logic.&lt;/p&gt;

&lt;p&gt;Automate formatting and linting wherever possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake 4: Assuming generated code understands your system
&lt;/h3&gt;

&lt;p&gt;It doesn't have your entire organizational context.&lt;/p&gt;

&lt;p&gt;Review assumptions explicitly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake 5: Ignoring PR size
&lt;/h3&gt;

&lt;p&gt;A 1,500-line AI-generated PR is difficult to review regardless of how clean the code looks.&lt;/p&gt;

&lt;p&gt;Breaking changes into smaller PRs makes correctness easier to establish.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake 6: Asking AI to review AI without verification
&lt;/h3&gt;

&lt;p&gt;An AI reviewer can be useful for finding patterns humans might miss.&lt;/p&gt;

&lt;p&gt;But its findings still require validation.&lt;/p&gt;

&lt;p&gt;Don't replace human judgment with another generated judgment.&lt;/p&gt;




&lt;h1&gt;
  
  
  9. A Practical AI-Code Review Checklist
&lt;/h1&gt;

&lt;p&gt;Before approving an AI-assisted PR, run through this checklist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Do I understand what problem this PR solves?&lt;/li&gt;
&lt;li&gt;[ ] Is the scope clear?&lt;/li&gt;
&lt;li&gt;[ ] Is the PR reasonably sized?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Logic
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Does the implementation match the requirement?&lt;/li&gt;
&lt;li&gt;[ ] What assumptions does the code make?&lt;/li&gt;
&lt;li&gt;[ ] What happens with empty, invalid, or extreme input?&lt;/li&gt;
&lt;li&gt;[ ] Are race conditions possible?&lt;/li&gt;
&lt;li&gt;[ ] Are retries and duplicate requests safe?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Is authentication correct?&lt;/li&gt;
&lt;li&gt;[ ] Is authorization enforced?&lt;/li&gt;
&lt;li&gt;[ ] Is user input handled safely?&lt;/li&gt;
&lt;li&gt;[ ] Are secrets protected?&lt;/li&gt;
&lt;li&gt;[ ] Could sensitive information reach logs?&lt;/li&gt;
&lt;li&gt;[ ] Are errors exposing internal information?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Data
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Are database queries safe?&lt;/li&gt;
&lt;li&gt;[ ] Are transactions required?&lt;/li&gt;
&lt;li&gt;[ ] Are constraints enforced at the database level?&lt;/li&gt;
&lt;li&gt;[ ] Could concurrent requests corrupt state?&lt;/li&gt;
&lt;li&gt;[ ] Is caching introducing stale or cross-user data?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tests
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Are important behaviors tested?&lt;/li&gt;
&lt;li&gt;[ ] Are edge cases covered?&lt;/li&gt;
&lt;li&gt;[ ] Are failure paths tested?&lt;/li&gt;
&lt;li&gt;[ ] Are tests testing requirements rather than implementation details?&lt;/li&gt;
&lt;li&gt;[ ] Are mocks hiding important integration behavior?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Does the change fit existing patterns?&lt;/li&gt;
&lt;li&gt;[ ] Is there already code that solves this problem?&lt;/li&gt;
&lt;li&gt;[ ] Are responsibilities in the right layer?&lt;/li&gt;
&lt;li&gt;[ ] Does the change introduce unnecessary dependencies?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Maintainability
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Is the code understandable?&lt;/li&gt;
&lt;li&gt;[ ] Is complexity justified?&lt;/li&gt;
&lt;li&gt;[ ] Are names meaningful?&lt;/li&gt;
&lt;li&gt;[ ] Is duplication introduced?&lt;/li&gt;
&lt;li&gt;[ ] Will another developer understand the reasoning six months from now?&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  The Goal Isn't to Review More. It's to Review Better.
&lt;/h1&gt;

&lt;p&gt;AI changes the economics of writing code.&lt;/p&gt;

&lt;p&gt;When producing another function, test, refactor, or API endpoint becomes dramatically cheaper, teams can generate changes faster than humans can carefully inspect them.&lt;/p&gt;

&lt;p&gt;That creates a new bottleneck:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;engineering attention.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The answer isn't to manually inspect every generated line forever.&lt;/p&gt;

&lt;p&gt;It's to make review more deliberate.&lt;/p&gt;

&lt;p&gt;Start with the highest-risk behavior.&lt;/p&gt;

&lt;p&gt;Question assumptions.&lt;/p&gt;

&lt;p&gt;Test boundaries.&lt;/p&gt;

&lt;p&gt;Trace data.&lt;/p&gt;

&lt;p&gt;Inspect security boundaries.&lt;/p&gt;

&lt;p&gt;Understand architectural consequences.&lt;/p&gt;

&lt;p&gt;And keep changes small enough that another engineer can actually understand them.&lt;/p&gt;

&lt;p&gt;AI can make code generation cheap.&lt;/p&gt;

&lt;p&gt;Human attention is still expensive.&lt;/p&gt;

&lt;p&gt;Code review should spend that attention where it has the highest chance of preventing something from reaching production.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>code</category>
      <category>developers</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>A Label Isn't a Code Review</title>
      <dc:creator>Codzee.io</dc:creator>
      <pubDate>Tue, 15 Sep 2026 10:53:47 +0000</pubDate>
      <link>https://dev.to/codzee_io/a-label-isnt-a-code-review-2lpg</link>
      <guid>https://dev.to/codzee_io/a-label-isnt-a-code-review-2lpg</guid>
      <description>&lt;p&gt;Consider two comments on the same piece of code.&lt;/p&gt;

&lt;p&gt;The first:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Consider refactoring this function for readability.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The second:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This returns &lt;code&gt;null&lt;/code&gt; when no active subscription exists, but the caller immediately dereferences &lt;code&gt;.plan&lt;/code&gt;. That turns a valid ‘no subscription’ state into an exception. Handle the empty case before accessing &lt;code&gt;plan&lt;/code&gt;.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The first comment might be correct.&lt;/p&gt;

&lt;p&gt;The function might genuinely be difficult to read.&lt;/p&gt;

&lt;p&gt;But it leaves an important question unanswered:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the &lt;a href="https://codzee.io/" rel="noopener noreferrer"&gt;engineer supposed&lt;/a&gt; to do with that information?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The second comment contains considerably more information. It identifies a behavior, connects it to another part of the system, describes the failure mode, and suggests a direction.&lt;/p&gt;

&lt;p&gt;That seems straightforward.&lt;/p&gt;

&lt;p&gt;But it raises a more interesting question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What information does a code review comment actually need to contain to be useful?&lt;/strong&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Code review isn't just defect detection
&lt;/h1&gt;

&lt;p&gt;It is tempting to think about code review as a simple pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;code
  ↓
reviewer
  ↓
problem detected
  ↓
comment
  ↓
code changed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But modern code review is doing several things simultaneously.&lt;/p&gt;

&lt;p&gt;It can catch defects.&lt;/p&gt;

&lt;p&gt;It can question design decisions.&lt;/p&gt;

&lt;p&gt;It can communicate project conventions.&lt;/p&gt;

&lt;p&gt;It can transfer knowledge between engineers.&lt;/p&gt;

&lt;p&gt;It can document decisions.&lt;/p&gt;

&lt;p&gt;It can expose assumptions that aren't visible in the code itself.&lt;/p&gt;

&lt;p&gt;Research on modern code review has found that reviewers and authors value activities beyond defect detection, including knowledge sharing and increasing awareness of the codebase.&lt;/p&gt;

&lt;p&gt;A Microsoft Research study of peer review also found that review is a form of knowledge exchange in which design rationale can be surfaced during the discussion.&lt;/p&gt;

&lt;p&gt;So a review comment isn't merely a defect marker.&lt;/p&gt;

&lt;p&gt;It is a small communication channel between two people who may have very different amounts of context.&lt;/p&gt;

&lt;p&gt;That changes what “good” means.&lt;/p&gt;




&lt;h1&gt;
  
  
  Flagging isn't explaining
&lt;/h1&gt;

&lt;p&gt;Consider:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Potential race condition.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There may indeed be a race condition.&lt;/p&gt;

&lt;p&gt;But the comment assumes the author will reconstruct the reviewer's reasoning.&lt;/p&gt;

&lt;p&gt;Where is the race?&lt;/p&gt;

&lt;p&gt;Under what interleaving?&lt;/p&gt;

&lt;p&gt;Does it produce incorrect data?&lt;/p&gt;

&lt;p&gt;Duplicate work?&lt;/p&gt;

&lt;p&gt;A crash?&lt;/p&gt;

&lt;p&gt;Is it harmless?&lt;/p&gt;

&lt;p&gt;Now compare:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Two requests can both observe that the key is absent before either calls &lt;code&gt;set()&lt;/code&gt;. That means &lt;code&gt;fetchValue()&lt;/code&gt; can execute twice and the second result can overwrite the first. If &lt;code&gt;fetchValue()&lt;/code&gt; has side effects, the current check-then-set sequence isn't sufficient; use an atomic get-or-create operation.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The second comment isn't merely more verbose.&lt;/p&gt;

&lt;p&gt;It exposes the reasoning.&lt;/p&gt;

&lt;p&gt;That distinction matters.&lt;/p&gt;

&lt;p&gt;A label such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[bug]
[performance]
[security]
[style]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What category did the reviewer assign this observation?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It doesn't necessarily answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why should I change the code?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A label is metadata.&lt;/p&gt;

&lt;p&gt;An explanation contains a model of the problem.&lt;/p&gt;




&lt;h1&gt;
  
  
  What information should a review comment contain?
&lt;/h1&gt;

&lt;p&gt;I don't think there is a universal template.&lt;/p&gt;

&lt;p&gt;But useful comments often contain some combination of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WHAT
What behavior or property is concerning?

WHY
Why does it matter?

CONTEXT
What assumption, constraint, or system behavior makes it important?

CONSEQUENCE
What can happen if it remains unchanged?

NEXT
What should the author investigate or change?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A comment doesn't need all five.&lt;/p&gt;

&lt;p&gt;For an obvious typo:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“&lt;code&gt;recieve&lt;/code&gt; → &lt;code&gt;receive&lt;/code&gt;.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;is probably sufficient.&lt;/p&gt;

&lt;p&gt;For a concurrency bug:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Two requests can both pass this check…”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;may need considerably more context.&lt;/p&gt;

&lt;p&gt;The amount of explanation should depend on the amount of ambiguity.&lt;/p&gt;




&lt;h1&gt;
  
  
  Correctness is not the same as usefulness
&lt;/h1&gt;

&lt;p&gt;This is an important distinction.&lt;/p&gt;

&lt;p&gt;Suppose a reviewer writes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This function is too complex.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And suppose the function really is too complex.&lt;/p&gt;

&lt;p&gt;The statement can be &lt;strong&gt;correct&lt;/strong&gt; while the review remains &lt;strong&gt;unhelpful&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The author still has to determine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which complexity?&lt;/li&gt;
&lt;li&gt;Why is it a problem?&lt;/li&gt;
&lt;li&gt;What boundary should change?&lt;/li&gt;
&lt;li&gt;Is the reviewer concerned about readability?&lt;/li&gt;
&lt;li&gt;Testing?&lt;/li&gt;
&lt;li&gt;Runtime behavior?&lt;/li&gt;
&lt;li&gt;Future modification?&lt;/li&gt;
&lt;li&gt;Something else?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compare:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This function now validates input, persists the record, and publishes an event. These operations have different failure semantics, so changing the event behavior now requires modifying persistence logic. Consider separating event publication from the persistence operation.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The second comment doesn't necessarily prescribe the correct refactoring.&lt;/p&gt;

&lt;p&gt;It does something more fundamental:&lt;/p&gt;

&lt;p&gt;It makes the reviewer's concern inspectable.&lt;/p&gt;

&lt;p&gt;The author can agree.&lt;/p&gt;

&lt;p&gt;The author can disagree.&lt;/p&gt;

&lt;p&gt;The author can explain why the coupling is intentional.&lt;/p&gt;

&lt;p&gt;That is a healthy property of a review comment.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why “why” matters
&lt;/h1&gt;

&lt;p&gt;Code frequently contains decisions that are not obvious from the code itself.&lt;/p&gt;

&lt;p&gt;Imagine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsDeleted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ErrNotFound&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A reviewer might ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Why return not found instead of forbidden?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That question could be perfectly reasonable.&lt;/p&gt;

&lt;p&gt;But suppose the actual reason is security-sensitive API behavior:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“The public endpoint intentionally returns &lt;code&gt;404&lt;/code&gt; for deleted users so callers can't distinguish between an existing deleted account and an account that never existed. This is consistent with the behavior of the other account lookup endpoints.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now the comment isn't just about an error code.&lt;/p&gt;

&lt;p&gt;It transfers context.&lt;/p&gt;

&lt;p&gt;This is why established review guidelines emphasize explaining why rather than simply describing what the code does. GitLab's review guidance explicitly recommends explaining rationale and making comments actionable.&lt;/p&gt;

&lt;p&gt;Google's code-review guidance similarly asks whether comments are clear and useful and distinguishes substantive concerns from optional style feedback.&lt;/p&gt;

&lt;p&gt;The “why” matters because code often cannot contain the entire reasoning behind itself.&lt;/p&gt;




&lt;h1&gt;
  
  
  But there is a danger in over-explaining
&lt;/h1&gt;

&lt;p&gt;Here is the obvious counterargument:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Could this framework cause reviewers to over-explain everything?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Absolutely.&lt;/p&gt;

&lt;p&gt;Imagine receiving this review comment:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This variable is named &lt;code&gt;i&lt;/code&gt;, which could potentially reduce semantic clarity because variable names are an important part of communicating intent. Consider using &lt;code&gt;index&lt;/code&gt; instead, since…”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nobody needs a paragraph for that.&lt;/p&gt;

&lt;p&gt;The problem is not lack of context.&lt;/p&gt;

&lt;p&gt;The problem is that the context is already obvious.&lt;/p&gt;

&lt;p&gt;A useful principle is therefore not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“More explanation is better.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“Enough explanation to remove meaningful ambiguity.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For a typo, that's almost nothing.&lt;/p&gt;

&lt;p&gt;For a distributed-system failure mode, it might be several sentences.&lt;/p&gt;

&lt;p&gt;Comment length should follow uncertainty.&lt;/p&gt;




&lt;h1&gt;
  
  
  Signal versus noise
&lt;/h1&gt;

&lt;p&gt;This becomes especially important when review comments are cheap to generate.&lt;/p&gt;

&lt;p&gt;A human reviewer has a natural constraint: attention.&lt;/p&gt;

&lt;p&gt;An automated reviewer can potentially produce many observations.&lt;/p&gt;

&lt;p&gt;That creates a dangerous feedback loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;more detection
     ↓
more comments
     ↓
more things to inspect
     ↓
less attention per comment
     ↓
more review fatigue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem isn't hypothetical in the broader code-review literature.&lt;/p&gt;

&lt;p&gt;Researchers have studied reviewer participation, usefulness of comments, review size, reviewer experience, and other factors that affect modern code-review effectiveness.&lt;/p&gt;

&lt;p&gt;For example, Bosu, Greiler, and Bird analyzed approximately 1.5 million review comments from five Microsoft projects to investigate characteristics associated with useful review feedback. Their work found relationships between usefulness and factors including reviewer experience and change characteristics.&lt;/p&gt;

&lt;p&gt;The implication isn't that automated review is bad.&lt;/p&gt;

&lt;p&gt;It's that &lt;strong&gt;review bandwidth is finite&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If a system produces ten additional comments, the relevant question isn't whether all ten are technically defensible.&lt;/p&gt;

&lt;p&gt;It's whether the engineer's attention was spent better because they received them.&lt;/p&gt;




&lt;h1&gt;
  
  
  The preference problem
&lt;/h1&gt;

&lt;p&gt;There is another source of noise that has nothing to do with AI.&lt;/p&gt;

&lt;p&gt;Human reviewers do it constantly.&lt;/p&gt;

&lt;p&gt;Consider:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“I'd use a map here.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That might be a good suggestion.&lt;/p&gt;

&lt;p&gt;But why?&lt;/p&gt;

&lt;p&gt;Maybe the map makes lookup complexity clearer.&lt;/p&gt;

&lt;p&gt;Maybe it avoids repeated scans.&lt;/p&gt;

&lt;p&gt;Maybe it is simply the reviewer's preferred style.&lt;/p&gt;

&lt;p&gt;Those are different claims.&lt;/p&gt;

&lt;p&gt;Compare:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“I'd use a map here.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;with:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“We're doing a linear scan for every lookup, so the cost grows with the number of entries. Since this collection is accessed repeatedly, an indexed structure would avoid repeated scans.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now the author can evaluate the reasoning.&lt;/p&gt;

&lt;p&gt;This distinction between &lt;strong&gt;preference and engineering necessity&lt;/strong&gt; is important.&lt;/p&gt;

&lt;p&gt;Google's review guidance essentially argues that when multiple approaches are consistent with sound engineering principles, reviewers should accept the author's choice rather than treating their own preferred implementation as mandatory.&lt;/p&gt;

&lt;p&gt;A review culture that treats every preference as a defect creates noise even when every reviewer is acting in good faith.&lt;/p&gt;




&lt;h1&gt;
  
  
  Five examples
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Nullability
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Weak
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;“Handle null.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Stronger
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;“&lt;code&gt;getSubscription()&lt;/code&gt; returns &lt;code&gt;null&lt;/code&gt; when the user has no subscription, but this caller immediately reads &lt;code&gt;.plan&lt;/code&gt;. That turns a valid empty state into a runtime exception. Handle the empty case before dereferencing the result.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The second comment exposes the contract and failure mode.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Database queries
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Weak
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;“N+1.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Stronger
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;“&lt;code&gt;getCustomer()&lt;/code&gt; runs a database query inside this loop. With 500 orders, this can result in hundreds of additional queries. Load the required customers before the loop and reuse them here.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The label tells an experienced engineer what to investigate.&lt;/p&gt;

&lt;p&gt;The explanation tells them why this particular code has the problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Error semantics
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Weak
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;“Don't swallow the error.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Stronger
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;“Returning &lt;code&gt;nil&lt;/code&gt; here makes a failed request indistinguishable from a valid empty response. The caller treats &lt;code&gt;nil&lt;/code&gt; as success, so a network failure could be interpreted as ‘no data.’ Preserve the error so the caller can decide whether to retry or surface it.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The concern isn't merely “errors are important.”&lt;/p&gt;

&lt;p&gt;It's that information is being destroyed.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Authorization
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Weak
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;“Security issue.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Stronger
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;“Authentication establishes that the user has a valid session, but it doesn't establish that they can modify this document. Since the document isn't checked against the user's project, this path could allow cross-project modification. Verify authorization before the update.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The reviewer is identifying the missing security boundary.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Maintainability
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Weak
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;“This should be refactored.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Stronger
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;“This method now handles validation, persistence, retries, and notification. Those operations have different failure modes and are already changing independently. Separating the retry/notification path would keep future notification changes from touching persistence logic.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The second comment explains why the proposed structural change matters.&lt;/p&gt;




&lt;h1&gt;
  
  
  What if the reviewer doesn't know the author's intent?
&lt;/h1&gt;

&lt;p&gt;This is where the framework gets uncomfortable.&lt;/p&gt;

&lt;p&gt;Suppose a reviewer sees:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They might write:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This is wrong. A 404 should be an error.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But perhaps the API deliberately uses &lt;code&gt;404&lt;/code&gt; to represent “no matching resources.”&lt;/p&gt;

&lt;p&gt;The reviewer has made an assumption about intent.&lt;/p&gt;

&lt;p&gt;A more useful comment might be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Is &lt;code&gt;404&lt;/code&gt; expected to mean ‘no matching resources’ for this endpoint? If it represents a missing resource instead, returning an empty list here would hide an API error.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's a question rather than a declaration.&lt;/p&gt;

&lt;p&gt;And sometimes that is the better review comment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good review doesn't require the reviewer to pretend they know things they don't know.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Uncertainty should be communicated as uncertainty.&lt;/p&gt;

&lt;p&gt;There is a major difference between:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This is wrong.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“I may be missing context, but if X is possible, doesn't this create Y?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The second invites the author to supply missing information.&lt;/p&gt;




&lt;h1&gt;
  
  
  Review comments are conversations, not verdicts
&lt;/h1&gt;

&lt;p&gt;This is easy to forget when reviews are represented as annotations attached to lines.&lt;/p&gt;

&lt;p&gt;The interface makes a comment look like a judgment.&lt;/p&gt;

&lt;p&gt;But a review is usually a conversation.&lt;/p&gt;

&lt;p&gt;The reviewer proposes an interpretation.&lt;/p&gt;

&lt;p&gt;The author provides context.&lt;/p&gt;

&lt;p&gt;The two converge on a decision.&lt;/p&gt;

&lt;p&gt;That means a useful review comment doesn't necessarily need to prove that the reviewer is right.&lt;/p&gt;

&lt;p&gt;It needs to make the disagreement productive.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“I think this could race if two workers execute this block concurrently. Is there a lock around this operation elsewhere that I'm missing?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That might be a better comment than a confidently incorrect:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This has a race condition. Fix it.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The first comment contains uncertainty.&lt;/p&gt;

&lt;p&gt;The second hides it.&lt;/p&gt;




&lt;h1&gt;
  
  
  What about AI-generated review comments?
&lt;/h1&gt;

&lt;p&gt;AI makes this problem more interesting.&lt;/p&gt;

&lt;p&gt;An automated system can examine code at a scale that humans can't.&lt;/p&gt;

&lt;p&gt;It can notice patterns.&lt;/p&gt;

&lt;p&gt;It can compare implementations.&lt;/p&gt;

&lt;p&gt;It can identify suspicious data flows.&lt;/p&gt;

&lt;p&gt;It can explain some classes of issues.&lt;/p&gt;

&lt;p&gt;But there is a fundamental limitation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The code is not the entire system.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Intent may live in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;product requirements,&lt;/li&gt;
&lt;li&gt;architecture documents,&lt;/li&gt;
&lt;li&gt;incident history,&lt;/li&gt;
&lt;li&gt;database constraints,&lt;/li&gt;
&lt;li&gt;undocumented operational assumptions,&lt;/li&gt;
&lt;li&gt;conversations between engineers,&lt;/li&gt;
&lt;li&gt;downstream consumers,&lt;/li&gt;
&lt;li&gt;or simply someone's knowledge of why the system works the way it does.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An AI looking only at a pull request may not have access to that context.&lt;/p&gt;

&lt;p&gt;So consider an automated comment:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This validation is redundant.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Maybe it is.&lt;/p&gt;

&lt;p&gt;Or maybe the validation exists because an external system violates the contract once every few thousand requests.&lt;/p&gt;

&lt;p&gt;Without broader context, the model may correctly understand the local code and incorrectly understand the system.&lt;/p&gt;

&lt;p&gt;That's an important distinction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Local correctness is not necessarily system correctness.&lt;/strong&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Can AI generate specific comments without understanding the whole system?
&lt;/h1&gt;

&lt;p&gt;Sometimes.&lt;/p&gt;

&lt;p&gt;For straightforward cases, specificity may not require deep system-level intent.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This value is checked for &lt;code&gt;None&lt;/code&gt; here, but dereferenced unconditionally three lines later.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The evidence is local.&lt;/p&gt;

&lt;p&gt;The model doesn't need to understand the entire architecture.&lt;/p&gt;

&lt;p&gt;But consider:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This retry count is too low.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That might require knowing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;upstream service behavior,&lt;/li&gt;
&lt;li&gt;timeout characteristics,&lt;/li&gt;
&lt;li&gt;SLA requirements,&lt;/li&gt;
&lt;li&gt;idempotency guarantees,&lt;/li&gt;
&lt;li&gt;traffic patterns,&lt;/li&gt;
&lt;li&gt;and production failure modes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The more a comment depends on external intent, the less safe it is to infer that intent from code alone.&lt;/p&gt;

&lt;p&gt;This suggests a useful boundary for automated review:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The system should distinguish observations supported directly by code from conclusions that depend on missing context.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That could mean expressing uncertainty.&lt;/p&gt;

&lt;p&gt;It could mean asking a question.&lt;/p&gt;

&lt;p&gt;It could mean requesting additional repository context.&lt;/p&gt;

&lt;p&gt;It could mean not commenting at all.&lt;/p&gt;

&lt;p&gt;Silence is sometimes better than a plausible but unsupported explanation.&lt;/p&gt;




&lt;h1&gt;
  
  
  Explanation isn't evidence
&lt;/h1&gt;

&lt;p&gt;There's another subtle failure mode.&lt;/p&gt;

&lt;p&gt;A detailed comment can sound authoritative simply because it is detailed.&lt;/p&gt;

&lt;p&gt;Consider an AI-generated comment:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This implementation creates a race condition because the cache is not synchronized across worker threads, which could cause stale reads and inconsistent state…”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It sounds convincing.&lt;/p&gt;

&lt;p&gt;But does the system actually know that the workers share the same cache?&lt;/p&gt;

&lt;p&gt;Does it know the operation is concurrent?&lt;/p&gt;

&lt;p&gt;Does it know stale reads matter?&lt;/p&gt;

&lt;p&gt;A long explanation can create &lt;strong&gt;false confidence&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So review quality cannot simply become:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“More detailed comments are better.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The real requirement is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The explanation should be proportional to the evidence.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A concise, well-supported observation can be more trustworthy than a sophisticated explanation built on assumptions.&lt;/p&gt;




&lt;h1&gt;
  
  
  The unit of review isn't always the line
&lt;/h1&gt;

&lt;p&gt;Another limitation of line-level comments is that many engineering problems aren't located on one line.&lt;/p&gt;

&lt;p&gt;Consider an authorization bug.&lt;/p&gt;

&lt;p&gt;The problem might be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;controller
    ↓
service
    ↓
repository
    ↓
database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The individual lines can all look reasonable.&lt;/p&gt;

&lt;p&gt;The vulnerability emerges from how the components interact.&lt;/p&gt;

&lt;p&gt;Likewise with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;distributed systems,&lt;/li&gt;
&lt;li&gt;caching,&lt;/li&gt;
&lt;li&gt;transactions,&lt;/li&gt;
&lt;li&gt;retries,&lt;/li&gt;
&lt;li&gt;consistency,&lt;/li&gt;
&lt;li&gt;API contracts,&lt;/li&gt;
&lt;li&gt;concurrency,&lt;/li&gt;
&lt;li&gt;lifecycle management.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes the most useful review comment needs to refer to a &lt;strong&gt;relationship&lt;/strong&gt;, not a line.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“The transaction ends before the event is published, so a successful response can be returned even if event publication fails. Is that intentional? If the event is part of the operation's contract, the transaction/outbox boundary probably needs to move.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's difficult to express as a simple label.&lt;/p&gt;

&lt;p&gt;It requires a model of the interaction between components.&lt;/p&gt;




&lt;h1&gt;
  
  
  So what makes a review comment good?
&lt;/h1&gt;

&lt;p&gt;I don't think the answer is “make every comment more detailed.”&lt;/p&gt;

&lt;p&gt;Nor is it “always explain the why.”&lt;/p&gt;

&lt;p&gt;There are cases where the why is obvious.&lt;/p&gt;

&lt;p&gt;Nor is it “never use labels.”&lt;/p&gt;

&lt;p&gt;Labels are useful.&lt;/p&gt;

&lt;p&gt;The more interesting answer is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A good review comment contains the minimum information necessary for another engineer to correctly evaluate the concern.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sometimes that's:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Typo: &lt;code&gt;recieve&lt;/code&gt; → &lt;code&gt;receive&lt;/code&gt;.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sometimes it's:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This returns &lt;code&gt;null&lt;/code&gt; when X happens, but Y dereferences it immediately, turning a valid state into an exception.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sometimes it's a question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Is this 404 intentional? If not, are we hiding an API failure by returning an empty list?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sometimes the right review is no comment at all.&lt;/p&gt;

&lt;p&gt;That last case matters.&lt;/p&gt;

&lt;p&gt;A reviewer should not be rewarded simply for finding something to say.&lt;/p&gt;




&lt;h1&gt;
  
  
  A small framework: WHAT → WHY → NEXT
&lt;/h1&gt;

&lt;p&gt;If I had to give reviewers a practical heuristic, it would be:&lt;/p&gt;

&lt;h3&gt;
  
  
  WHAT?
&lt;/h3&gt;

&lt;p&gt;What exactly are you observing?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This can return &lt;code&gt;null&lt;/code&gt;.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  WHY?
&lt;/h3&gt;

&lt;p&gt;Why does that matter?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“The caller dereferences it immediately.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  NEXT?
&lt;/h3&gt;

&lt;p&gt;What should the author investigate or change?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Handle the empty case before accessing the property.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Together:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This can return &lt;code&gt;null&lt;/code&gt;, but the caller immediately dereferences it, which can turn a valid empty state into a runtime exception. Handle the empty case before accessing the property.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But the framework should be treated as a diagnostic tool, not a writing template.&lt;/p&gt;

&lt;p&gt;If the issue is obvious, don't force an explanation.&lt;/p&gt;

&lt;p&gt;If the reviewer is uncertain, don't manufacture certainty.&lt;/p&gt;

&lt;p&gt;If the concern depends on system context the reviewer doesn't have, ask.&lt;/p&gt;

&lt;p&gt;If the implementation is simply a matter of preference, say so.&lt;/p&gt;




&lt;h1&gt;
  
  
  The deeper problem
&lt;/h1&gt;

&lt;p&gt;There is a tendency to think of software engineering communication as secondary to the “real” engineering work.&lt;/p&gt;

&lt;p&gt;The code is the artifact.&lt;/p&gt;

&lt;p&gt;The review comment is just discussion around it.&lt;/p&gt;

&lt;p&gt;I'm not convinced that's true.&lt;/p&gt;

&lt;p&gt;A codebase contains decisions.&lt;/p&gt;

&lt;p&gt;Reviews contain the reasoning behind some of those decisions.&lt;/p&gt;

&lt;p&gt;When that reasoning is missing, future engineers have to reconstruct it.&lt;/p&gt;

&lt;p&gt;When it is vague, authors have to interpret it.&lt;/p&gt;

&lt;p&gt;When it is excessively noisy, people stop paying attention.&lt;/p&gt;

&lt;p&gt;And when it is confidently wrong, the review system can actively make engineering decisions worse.&lt;/p&gt;

&lt;p&gt;That applies equally to human and automated reviewers.&lt;/p&gt;

&lt;p&gt;The hard problem isn't merely detecting something suspicious.&lt;/p&gt;

&lt;p&gt;It's knowing &lt;strong&gt;what information another engineer needs to evaluate the observation&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  Open questions
&lt;/h1&gt;

&lt;p&gt;I don't think we've solved this.&lt;/p&gt;

&lt;p&gt;A few questions seem particularly interesting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much context is enough?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Can review systems estimate when a comment needs one sentence versus five?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can usefulness be measured without reducing it to “did the author change the code”?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A correct review may result in no change because the author provides missing context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How should automated reviewers represent uncertainty?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Should a system say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This is a bug.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;or:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“If X is possible, this may produce Y. Is X guaranteed not to happen?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;How much repository context should an AI reviewer consume before making a claim?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;More context can improve reasoning, but it can also increase cost and introduce irrelevant information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can automated systems distinguish preference from correctness reliably?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Or will they reproduce the same subjective review behavior humans already struggle with?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens to review quality when the cost of generating comments approaches zero?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If comments become effectively free, attention becomes the scarce resource.&lt;/p&gt;

&lt;p&gt;And perhaps the most basic question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Should the objective of code review be to find more problems, or to help engineers make better decisions?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those are related goals.&lt;/p&gt;

&lt;p&gt;They aren't necessarily the same.&lt;/p&gt;

&lt;p&gt;A label tells us that someone thinks there is a problem.&lt;/p&gt;

&lt;p&gt;A useful review comment gives us enough reasoning to decide whether they are right.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That's why a label isn't a code review.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>code</category>
      <category>coding</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Why AI Code Review Needs to Learn From Developers</title>
      <dc:creator>Codzee.io</dc:creator>
      <pubDate>Tue, 08 Sep 2026 11:30:32 +0000</pubDate>
      <link>https://dev.to/codzee_io/why-ai-code-review-needs-to-learn-from-developers-bad</link>
      <guid>https://dev.to/codzee_io/why-ai-code-review-needs-to-learn-from-developers-bad</guid>
      <description>&lt;p&gt;After 15+ years of building software, &lt;a href="https://codzee.io/" rel="noopener noreferrer"&gt;reviewing pull requests&lt;/a&gt;, debugging production systems, and working with engineering teams, I've become increasingly convinced that we're asking the wrong question about AI code review.&lt;/p&gt;

&lt;p&gt;The obvious question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How accurately can AI detect problems in code?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's an important question.&lt;/p&gt;

&lt;p&gt;But there's another question that becomes more important once a team uses the system for months:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How well does the system understand what this particular team considers worth reviewing?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those are very different problems.&lt;/p&gt;

&lt;p&gt;A reviewer can be technically accurate and still be frustrating to use.&lt;/p&gt;

&lt;p&gt;It can identify real complexity, real duplication, real security risks, and real maintainability concerns—and still lose the trust of the engineers receiving its comments.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because software engineering isn't just a collection of rules.&lt;/p&gt;

&lt;p&gt;It's context, conventions, trade-offs, history, architecture, and judgment.&lt;/p&gt;

&lt;p&gt;And much of that knowledge isn't written anywhere.&lt;/p&gt;

&lt;p&gt;It's learned through interaction.&lt;/p&gt;

&lt;p&gt;That is why I believe the next generation of AI code review needs to learn from developers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Static Analysis Was Never the Whole Story
&lt;/h2&gt;

&lt;p&gt;We've had static analysis for decades.&lt;/p&gt;

&lt;p&gt;Linters are incredibly useful.&lt;/p&gt;

&lt;p&gt;They catch formatting problems, suspicious constructs, unused variables, dangerous patterns, complexity issues, and countless other classes of problems.&lt;/p&gt;

&lt;p&gt;Static analysis is deterministic and predictable.&lt;/p&gt;

&lt;p&gt;That's exactly why engineers like it.&lt;/p&gt;

&lt;p&gt;You can define a rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if condition X is true
    report finding Y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then configure how that finding behaves.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Warning&lt;/li&gt;
&lt;li&gt;Error&lt;/li&gt;
&lt;li&gt;Info&lt;/li&gt;
&lt;li&gt;Ignore&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can add thresholds.&lt;/p&gt;

&lt;p&gt;You can exclude directories.&lt;/p&gt;

&lt;p&gt;You can configure allowlists and denylists.&lt;/p&gt;

&lt;p&gt;You can override rules for specific repositories.&lt;/p&gt;

&lt;p&gt;This works remarkably well for problems that can be expressed clearly.&lt;/p&gt;

&lt;p&gt;But there's a fundamental limitation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The configuration describes what we think matters. It doesn't necessarily describe what the team actually considers useful.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Those aren't always the same thing.&lt;/p&gt;




&lt;h1&gt;
  
  
  Configuration Has a Ceiling
&lt;/h1&gt;

&lt;p&gt;Consider a team working on a large backend system.&lt;/p&gt;

&lt;p&gt;They configure a complexity threshold:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;complexity &amp;gt; 10 → warning
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seems reasonable.&lt;/p&gt;

&lt;p&gt;Then the system starts flagging a particular class of functions.&lt;/p&gt;

&lt;p&gt;The team repeatedly dismisses them.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Maybe those functions are generated around a complex business domain.&lt;/p&gt;

&lt;p&gt;Maybe they're deliberately structured that way because splitting them would make the code harder to understand.&lt;/p&gt;

&lt;p&gt;Maybe the threshold is appropriate for most of the repository but not this subsystem.&lt;/p&gt;

&lt;p&gt;Maybe the team has accepted the complexity because the alternative introduces a worse architectural trade-off.&lt;/p&gt;

&lt;p&gt;You can solve this with another configuration rule.&lt;/p&gt;

&lt;p&gt;Add an exception.&lt;/p&gt;

&lt;p&gt;Then another exception.&lt;/p&gt;

&lt;p&gt;Then another.&lt;/p&gt;

&lt;p&gt;Eventually, your configuration starts looking like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flag X
unless repository Y
unless directory Z
unless pattern A
unless service B
unless annotation C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At some point, we're essentially trying to encode years of engineering judgment into a configuration file.&lt;/p&gt;

&lt;p&gt;That's not necessarily the best abstraction.&lt;/p&gt;




&lt;h1&gt;
  
  
  Engineering Teams Are Dynamic Systems
&lt;/h1&gt;

&lt;p&gt;The bigger problem is that repositories don't stay still.&lt;/p&gt;

&lt;p&gt;Neither do teams.&lt;/p&gt;

&lt;p&gt;An organization might move from a monolith to services.&lt;/p&gt;

&lt;p&gt;A team might adopt a new framework.&lt;/p&gt;

&lt;p&gt;A legacy subsystem might become effectively frozen.&lt;/p&gt;

&lt;p&gt;A new architectural standard might be introduced.&lt;/p&gt;

&lt;p&gt;Performance requirements might change.&lt;/p&gt;

&lt;p&gt;Security requirements might become stricter.&lt;/p&gt;

&lt;p&gt;The team might deliberately relax a particular style rule because it's slowing development without providing meaningful value.&lt;/p&gt;

&lt;p&gt;Configuration tends to represent a snapshot.&lt;/p&gt;

&lt;p&gt;Engineering practice is a moving target.&lt;/p&gt;

&lt;p&gt;That's why I think AI code review needs something beyond configuration.&lt;/p&gt;

&lt;p&gt;It needs a &lt;strong&gt;feedback loop&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Most Interesting Signal Might Be a Dismissal
&lt;/h1&gt;

&lt;p&gt;Here's a simple example.&lt;/p&gt;

&lt;p&gt;Suppose an AI review system repeatedly reports:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This function is too complex.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The developer dismisses the comment.&lt;/p&gt;

&lt;p&gt;The same pattern appears in another pull request.&lt;/p&gt;

&lt;p&gt;The developer dismisses it again.&lt;/p&gt;

&lt;p&gt;Then again.&lt;/p&gt;

&lt;p&gt;What should happen?&lt;/p&gt;

&lt;p&gt;A conventional system records three dismissed findings.&lt;/p&gt;

&lt;p&gt;End of story.&lt;/p&gt;

&lt;p&gt;But I think we're throwing away valuable information.&lt;/p&gt;

&lt;p&gt;Repeated dismissal could mean several things.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The rule is too broad
&lt;/h3&gt;

&lt;p&gt;Perhaps the complexity threshold isn't appropriate for this codebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The system lacks context
&lt;/h3&gt;

&lt;p&gt;The function may look complex locally but be perfectly reasonable given the surrounding architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The team has an intentional exception
&lt;/h3&gt;

&lt;p&gt;The engineers may understand the trade-off and have consciously decided to accept it.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. The feedback is technically correct but practically irrelevant
&lt;/h3&gt;

&lt;p&gt;Something can be objectively improvable without being worth interrupting a developer about.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. The team may actually be wrong
&lt;/h3&gt;

&lt;p&gt;This possibility is important too.&lt;/p&gt;

&lt;p&gt;Learning from developers shouldn't mean blindly accepting every dismissal.&lt;/p&gt;

&lt;p&gt;Sometimes an engineer dismisses a legitimate security issue.&lt;/p&gt;

&lt;p&gt;Sometimes a team has normalized technical debt.&lt;/p&gt;

&lt;p&gt;Sometimes people ignore warnings because fixing them is inconvenient.&lt;/p&gt;

&lt;p&gt;So the answer isn't:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Developer dismissed it, therefore never report it again."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The better question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"What does this interaction tell us, and how confident should we be when adapting?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's a much more interesting engineering problem.&lt;/p&gt;




&lt;h1&gt;
  
  
  A Review Comment Is an Interaction
&lt;/h1&gt;

&lt;p&gt;We usually model code review as something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Code → Analysis → Finding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But real code review is closer to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Code
  ↓
Analysis
  ↓
Finding
  ↓
Developer judgment
  ↓
Accept / dismiss / modify / ignore
  ↓
Future behavior
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That final step is where a lot of today's systems stop paying attention.&lt;/p&gt;

&lt;p&gt;But it may be the most valuable part.&lt;/p&gt;

&lt;p&gt;Every interaction provides information.&lt;/p&gt;

&lt;p&gt;A developer accepts a finding.&lt;/p&gt;

&lt;p&gt;That's a signal.&lt;/p&gt;

&lt;p&gt;A developer dismisses it.&lt;/p&gt;

&lt;p&gt;That's a signal.&lt;/p&gt;

&lt;p&gt;A developer repeatedly modifies recommendations in the same way.&lt;/p&gt;

&lt;p&gt;That's a signal.&lt;/p&gt;

&lt;p&gt;An entire team consistently ignores a category of feedback.&lt;/p&gt;

&lt;p&gt;That's a much stronger signal.&lt;/p&gt;

&lt;p&gt;The challenge is turning those signals into useful adaptation without creating unpredictable behavior.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Repository Shouldn't Be Treated as an Isolated Installation
&lt;/h1&gt;

&lt;p&gt;One thing that bothers me about the current mental model is the idea that every repository starts from zero.&lt;/p&gt;

&lt;p&gt;Install the tool.&lt;/p&gt;

&lt;p&gt;Configure it.&lt;/p&gt;

&lt;p&gt;Run it.&lt;/p&gt;

&lt;p&gt;Done.&lt;/p&gt;

&lt;p&gt;But an established codebase already contains enormous amounts of engineering knowledge.&lt;/p&gt;

&lt;p&gt;You can find it in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Existing implementation patterns&lt;/li&gt;
&lt;li&gt;Pull request discussions&lt;/li&gt;
&lt;li&gt;Architectural decisions&lt;/li&gt;
&lt;li&gt;Test strategies&lt;/li&gt;
&lt;li&gt;Naming conventions&lt;/li&gt;
&lt;li&gt;Error-handling approaches&lt;/li&gt;
&lt;li&gt;Accepted technical debt&lt;/li&gt;
&lt;li&gt;Framework-specific patterns&lt;/li&gt;
&lt;li&gt;Exceptions to general standards&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some of this can be explicitly documented.&lt;/p&gt;

&lt;p&gt;Much of it isn't.&lt;/p&gt;

&lt;p&gt;An AI system operating inside that repository should have the opportunity to understand those patterns.&lt;/p&gt;

&lt;p&gt;Not simply analyze the current pull request in isolation.&lt;/p&gt;




&lt;h1&gt;
  
  
  False Positives Are More Expensive Than They Look
&lt;/h1&gt;

&lt;p&gt;False positives aren't just an accuracy problem.&lt;/p&gt;

&lt;p&gt;They're a trust problem.&lt;/p&gt;

&lt;p&gt;Imagine a developer receives ten review comments.&lt;/p&gt;

&lt;p&gt;Two are genuinely useful.&lt;/p&gt;

&lt;p&gt;Eight aren't.&lt;/p&gt;

&lt;p&gt;After a while, the developer stops carefully evaluating each comment.&lt;/p&gt;

&lt;p&gt;They start scanning.&lt;/p&gt;

&lt;p&gt;Eventually they start dismissing automatically.&lt;/p&gt;

&lt;p&gt;That's when the system has failed even if its underlying detection model is technically sophisticated.&lt;/p&gt;

&lt;p&gt;The cost isn't just the time spent reading irrelevant comments.&lt;/p&gt;

&lt;p&gt;The larger cost is &lt;strong&gt;signal degradation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Once developers stop believing that a comment is likely to matter, even good findings become harder to trust.&lt;/p&gt;

&lt;p&gt;This is why reducing noise isn't merely a UX improvement.&lt;/p&gt;

&lt;p&gt;It is part of the intelligence of the system.&lt;/p&gt;




&lt;h1&gt;
  
  
  But Adaptation Needs Guardrails
&lt;/h1&gt;

&lt;p&gt;There's an obvious danger here.&lt;/p&gt;

&lt;p&gt;If we allow AI systems to learn from developer behavior without constraints, they could learn the wrong lessons.&lt;/p&gt;

&lt;p&gt;Imagine a team consistently dismisses security warnings because fixing them is inconvenient.&lt;/p&gt;

&lt;p&gt;Should the system become quieter?&lt;/p&gt;

&lt;p&gt;Probably not.&lt;/p&gt;

&lt;p&gt;Some categories should have stronger guarantees.&lt;/p&gt;

&lt;p&gt;Some findings should remain visible regardless of preference.&lt;/p&gt;

&lt;p&gt;Some adaptations should require explicit confirmation.&lt;/p&gt;

&lt;p&gt;Some changes should be explainable.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This finding has been repeatedly dismissed for this repository. Should future findings of this type be deprioritized?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's very different from silently changing behavior.&lt;/p&gt;

&lt;p&gt;The goal shouldn't be autonomous customization at any cost.&lt;/p&gt;

&lt;p&gt;The goal should be &lt;strong&gt;safe adaptation&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  What Would an Adaptive Review System Look Like?
&lt;/h1&gt;

&lt;p&gt;I don't think this requires some magical autonomous agent.&lt;/p&gt;

&lt;p&gt;The underlying architecture could be relatively straightforward.&lt;/p&gt;

&lt;p&gt;Imagine maintaining a feedback model for findings.&lt;/p&gt;

&lt;p&gt;Something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Finding
├── category
├── location
├── repository context
├── confidence
├── severity
├── historical interactions
└── developer/team feedback
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then review decisions become part of the system's future reasoning.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Finding A
→ accepted 27 times
→ rarely dismissed
→ high relevance

Finding B
→ dismissed 18 times
→ accepted 1 time
→ low relevance in this repository

Finding C
→ dismissed frequently by one team
→ accepted frequently by another
→ highly context dependent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the system isn't simply asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Is this technically a problem?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It can also ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"How relevant has this type of finding historically been in this environment?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is a fundamentally different signal.&lt;/p&gt;

&lt;p&gt;And it can become increasingly repository-specific without requiring engineers to manually encode every preference.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Goal Isn't Fewer Findings
&lt;/h1&gt;

&lt;p&gt;This distinction matters.&lt;/p&gt;

&lt;p&gt;Adaptive code review shouldn't simply become a system that says less.&lt;/p&gt;

&lt;p&gt;The objective is &lt;strong&gt;higher-value output&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;There will be situations where the correct behavior is to become more aggressive.&lt;/p&gt;

&lt;p&gt;Suppose a team repeatedly accepts findings related to a particular security pattern.&lt;/p&gt;

&lt;p&gt;The system now has evidence that this category matters.&lt;/p&gt;

&lt;p&gt;That should increase confidence that similar findings are worth surfacing.&lt;/p&gt;

&lt;p&gt;Adaptation should work in both directions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Developer behavior
       ↓
Observed preference
       ↓
Updated relevance
       ↓
Future review behavior
       ↓
More developer feedback
       ↓
Updated preference
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a feedback loop.&lt;/p&gt;

&lt;p&gt;And feedback loops are how systems become better aligned with their environment.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Metric We Should Care About
&lt;/h1&gt;

&lt;p&gt;This leads to a question I think the industry should spend more time discussing.&lt;/p&gt;

&lt;p&gt;We measure code-review systems by things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detection accuracy&lt;/li&gt;
&lt;li&gt;Precision&lt;/li&gt;
&lt;li&gt;Recall&lt;/li&gt;
&lt;li&gt;False-positive rate&lt;/li&gt;
&lt;li&gt;Number of findings&lt;/li&gt;
&lt;li&gt;Vulnerability coverage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These metrics are useful.&lt;/p&gt;

&lt;p&gt;But they're incomplete.&lt;/p&gt;

&lt;p&gt;I'd also want to know:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What percentage of findings does a team consider useful?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And perhaps more importantly:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does that percentage improve over time?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine two systems.&lt;/p&gt;

&lt;p&gt;System A finds 100 issues in the first month and continues finding roughly 100 every month.&lt;/p&gt;

&lt;p&gt;System B finds 70 issues initially, learns from developer interactions, and eventually surfaces 30 highly relevant findings.&lt;/p&gt;

&lt;p&gt;Which one is better?&lt;/p&gt;

&lt;p&gt;The answer depends on what those findings contain.&lt;/p&gt;

&lt;p&gt;But for an engineering team, I would strongly prefer the system that earns the right to speak less—and gets better at knowing when to speak.&lt;/p&gt;




&lt;h1&gt;
  
  
  This Is Bigger Than AI Code Review
&lt;/h1&gt;

&lt;p&gt;There's a broader principle here.&lt;/p&gt;

&lt;p&gt;Good developer tools don't merely perform tasks.&lt;/p&gt;

&lt;p&gt;They fit into human workflows.&lt;/p&gt;

&lt;p&gt;Git became useful because developers could build mental models around it.&lt;/p&gt;

&lt;p&gt;IDEs became useful because developers shaped them around their workflows.&lt;/p&gt;

&lt;p&gt;Linters became useful because teams could define what mattered.&lt;/p&gt;

&lt;p&gt;The next generation of AI tools has another opportunity:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They can learn from the workflow itself.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's different from traditional configuration.&lt;/p&gt;

&lt;p&gt;Configuration says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Here is what we told the system."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Behavioral feedback says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Here is what the team actually does."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The combination could be much more powerful.&lt;/p&gt;




&lt;h1&gt;
  
  
  Signal Isn't a Feature. It's a Relationship.
&lt;/h1&gt;

&lt;p&gt;After 15+ years in software engineering, I don't think developer trust comes from a feature checklist.&lt;/p&gt;

&lt;p&gt;It comes from repeated evidence.&lt;/p&gt;

&lt;p&gt;You make a judgment.&lt;/p&gt;

&lt;p&gt;The system observes it.&lt;/p&gt;

&lt;p&gt;It adapts.&lt;/p&gt;

&lt;p&gt;You make another judgment.&lt;/p&gt;

&lt;p&gt;It adapts again.&lt;/p&gt;

&lt;p&gt;Over time, the system becomes less generic and more aligned with the environment in which it operates.&lt;/p&gt;

&lt;p&gt;That's what makes the idea of adaptive AI code review compelling to me.&lt;/p&gt;

&lt;p&gt;The next generation won't compete only on who can detect the most bugs.&lt;/p&gt;

&lt;p&gt;They'll compete on who can understand &lt;strong&gt;which bugs, patterns, and risks are actually worth surfacing to a particular engineering team.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because detection gets you into the workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Relevance keeps you there.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And relevance comes from understanding context.&lt;/p&gt;

&lt;p&gt;That is why I believe:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Signal isn't a feature. It's a relationship.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The best AI code-review systems will be the ones that earn that relationship carefully—through feedback, context, transparency, and repeated interaction.&lt;/p&gt;

&lt;p&gt;Not during installation.&lt;/p&gt;

&lt;p&gt;Over time.&lt;/p&gt;

&lt;p&gt;And ultimately, the real measure of an AI reviewer won't be how much it can say.&lt;/p&gt;

&lt;p&gt;It will be how quickly—and how safely—it earns the team's trust.&lt;br&gt;
:::&lt;/p&gt;

</description>
      <category>ai</category>
      <category>developers</category>
      <category>software</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>How can AI code review tools be evaluated reliably for real-world pull requests?</title>
      <dc:creator>Codzee.io</dc:creator>
      <pubDate>Tue, 01 Sep 2026 14:40:12 +0000</pubDate>
      <link>https://dev.to/codzee_io/how-can-ai-code-review-tools-be-evaluated-reliably-for-real-world-pull-requests-1pl3</link>
      <guid>https://dev.to/codzee_io/how-can-ai-code-review-tools-be-evaluated-reliably-for-real-world-pull-requests-1pl3</guid>
      <description>&lt;p&gt;I am evaluating &lt;a href="https://www.codzee.io/" rel="noopener noreferrer"&gt;AI-assisted code review systems&lt;/a&gt; and have found that published benchmarks use substantially different methodologies. Some replay historical bugs, some evaluate complete pull requests, some inject synthetic defects into real code, and others use human or LLM-based judgments of review comments.&lt;/p&gt;

&lt;p&gt;I am trying to design a fair evaluation for systems that review real-world pull requests.&lt;/p&gt;

&lt;p&gt;The main issues I am running into are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dataset construction:&lt;/strong&gt; Should the test set consist primarily of historical production bugs, clean pull requests, synthetic defects, or a combination?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ground truth:&lt;/strong&gt; How should a benchmark define the complete set of valid findings when the original human review may have missed defects?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Precision and recall:&lt;/strong&gt; Should findings be matched individually, or should a PR count as correct if the system identifies at least one valid issue?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;False positives:&lt;/strong&gt; How should speculative, stylistic, duplicate, or technically correct but non-actionable comments affect the score?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Severity:&lt;/strong&gt; Should critical security or correctness defects receive more weight than low-severity maintainability issues?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human review:&lt;/strong&gt; What level of expert annotation or adjudication is necessary to establish reliable ground truth?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository context:&lt;/strong&gt; Should systems receive the full repository, issue description, tests, commit history, and search capabilities, or should all systems be restricted to the diff?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Languages and projects:&lt;/strong&gt; How should results be normalized across programming languages, repositories, domains, and different patch sizes?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reproducibility:&lt;/strong&gt; What artifacts and experimental details should be published so another team can independently reproduce the evaluation?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a system that produces 20 comments and correctly identifies 10 defects is quite different from one that produces 5 comments and correctly identifies 4, even if their aggregate scores happen to be similar. Likewise, a benchmark based only on human review comments may penalize a system for finding a legitimate defect that the original reviewers missed.&lt;/p&gt;

&lt;p&gt;I am looking for a methodology that measures &lt;strong&gt;useful defect detection on real pull requests&lt;/strong&gt;, rather than simply similarity to historical review comments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What benchmark design and scoring procedure would provide the most statistically and methodologically defensible comparison of AI code review systems, including dataset construction, ground-truth validation, finding-level precision/recall, severity weighting, repository context, human adjudication, and reproducibility?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>codequality</category>
      <category>softwareengineering</category>
      <category>testing</category>
    </item>
    <item>
      <title>Your CODEOWNERS File Might Be Correct And Still Send Your PR to the Wrong Person</title>
      <dc:creator>Codzee.io</dc:creator>
      <pubDate>Mon, 31 Aug 2026 11:15:03 +0000</pubDate>
      <link>https://dev.to/codzee_io/your-codeowners-file-might-be-correct-and-still-send-your-pr-to-the-wrong-person-i8j</link>
      <guid>https://dev.to/codzee_io/your-codeowners-file-might-be-correct-and-still-send-your-pr-to-the-wrong-person-i8j</guid>
      <description>&lt;p&gt;You open a &lt;a href="https://www.codzee.io/" rel="noopener noreferrer"&gt;PR&lt;/a&gt;. GitHub looks at the changed paths, checks them against &lt;code&gt;CODEOWNERS&lt;/code&gt;, and auto-assigns a reviewer. This happens so often you probably don't think about it anymore. It's infrastructure — it just works.&lt;/p&gt;

&lt;p&gt;Except sometimes it doesn't, and it fails in a way that never throws an error.&lt;/p&gt;

&lt;p&gt;Here's a realistic example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight codeowners"&gt;&lt;code&gt;&lt;span class="c1"&gt;# CODEOWNERS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;/payments/&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nf"&gt;@engineer-a&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Engineer A hasn't touched &lt;code&gt;payments/&lt;/code&gt; in eight months — they moved to a different team in Q1. Engineer B has made the last 18 commits in that directory and has reviewed most of the recent PRs that touched it. Engineer B isn't in the file.&lt;/p&gt;

&lt;p&gt;Your PR touches &lt;code&gt;payments/refunds.go&lt;/code&gt;. It gets routed to Engineer A.&lt;/p&gt;

&lt;p&gt;Nothing is misconfigured. The glob pattern matches. The username resolves to a real, active employee. GitHub does exactly what it's supposed to do. The routing logic is just missing context it was never designed to have.&lt;/p&gt;

&lt;p&gt;This is the gap this article is about: &lt;strong&gt;CODEOWNERS tells you who owns a file. It doesn't tell you who should review a specific change.&lt;/strong&gt; Those turn out to be different questions, and the difference gets bigger as your team and codebase grow.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. What CODEOWNERS Gets Right
&lt;/h2&gt;

&lt;p&gt;Before picking it apart, it's worth being clear that CODEOWNERS solves a real problem well, and nothing below is an argument for ripping it out.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Explicit ownership.&lt;/strong&gt; Anyone can look at one file and see who's accountable for a given path. No tribal knowledge required.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Required reviews.&lt;/strong&gt; You can enforce that certain paths always get eyes from the right team before merge — critical for things like auth, billing, or infra-as-code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clear accountability.&lt;/strong&gt; When something in &lt;code&gt;/payments/&lt;/code&gt; breaks, there's no ambiguity about who's supposed to be paying attention to that code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simple, predictable behavior.&lt;/strong&gt; It's a text file with glob patterns. No ML model, no black box, no surprises. You can &lt;code&gt;git blame&lt;/code&gt; it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a small team, or for stable, slow-moving parts of a codebase, this is close to sufficient. The problem shows up specifically as team size and code churn increase — which is exactly when the cost of getting routing wrong also goes up.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Where Static Routing Breaks
&lt;/h2&gt;

&lt;p&gt;CODEOWNERS answers one question — &lt;em&gt;who owns this path&lt;/em&gt; — and organizations often treat that as a proxy for a different question: &lt;em&gt;who should review this change&lt;/em&gt;. Here's where those diverge:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;Static CODEOWNERS&lt;/th&gt;
&lt;th&gt;Dynamic routing&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;File ownership&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recent contribution&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Current expertise&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Review history&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reviewer load&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Expertise decay&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Walking through the "No" column:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Recent contribution&lt;/strong&gt; — CODEOWNERS has no time dimension. An entry from two years ago carries the same weight as one from yesterday.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Current expertise&lt;/strong&gt; — "Limited" because ownership is often a reasonable proxy for expertise &lt;em&gt;at the moment the file was written&lt;/em&gt;, but it's frozen after that. It doesn't update when someone's knowledge of an area grows or fades.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review history&lt;/strong&gt; — the file doesn't know who's actually been reviewing changes in an area, only who's nominally responsible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reviewer load&lt;/strong&gt; — &lt;a href="https://www.codzee.io/will" rel="noopener noreferrer"&gt;https://www.codzee.io/will&lt;/a&gt; happily assign a fifth simultaneous PR to someone already buried in review requests. It has no concept of "currently busy."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expertise decay&lt;/strong&gt; — there's no mechanism for an owner's relevance to degrade over time as they stop working in an area, and no mechanism for someone else's relevance to rise as they start.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this is a criticism of CODEOWNERS as a tool — it's just outside its scope. It's a static ownership file, not a reviewer-relevance model. The mistake is using it as if it were the second thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Model Expertise as Something That Changes
&lt;/h2&gt;

&lt;p&gt;The core idea: &lt;strong&gt;expertise isn't binary, and it isn't permanent.&lt;/strong&gt; "Alice owns payments" is a snapshot. What you actually want to know is closer to "how relevant is Alice's expertise, right now, to this specific diff."&lt;/p&gt;

&lt;p&gt;Useful inputs for that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Last contribution date&lt;/strong&gt; — when did this person last touch this area?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Number of recent relevant changes&lt;/strong&gt; — not lifetime commits, recent ones. Someone with 3 commits last month is a stronger current signal than someone with 200 commits two years ago.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Similarity to the current PR&lt;/strong&gt; — has this person touched the same files, the same functions, the same data model recently?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review activity&lt;/strong&gt; — have they been reviewing PRs in this area, even if they haven't authored changes there?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Historical ownership&lt;/strong&gt; — were they ever formally responsible for this, even if the file has since changed?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can express this as a rough conceptual model — not a formula anyone should treat as an industry standard, just a way to make the tradeoff explicit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;reviewer_relevance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ownership_weight&lt;/span&gt;
                    &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;expertise_weight&lt;/span&gt;
                    &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;recency_weight&lt;/span&gt;
                    &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;load_penalty&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The actual weights are going to be organization-specific, and honestly team-specific within an org. A security-critical path might want ownership weighted heavily no matter what. A fast-moving product surface might want recency and review history to dominate. The point of writing it this way isn't to hand you a formula — it's to make explicit that "who reviews this" is a function of multiple decaying/growing signals, not a single static lookup.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Work Through a Sample PR
&lt;/h2&gt;

&lt;p&gt;Say you've got a repo with three top-level domains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/payments/
/identity/
/notifications/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A PR comes in touching &lt;code&gt;payments/refunds.go&lt;/code&gt;. &lt;code&gt;CODEOWNERS&lt;/code&gt; says &lt;code&gt;payments/&lt;/code&gt; belongs to Engineer A. Here's how three candidate reviewers actually stack up:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Reviewer&lt;/th&gt;
&lt;th&gt;Ownership&lt;/th&gt;
&lt;th&gt;Recent work&lt;/th&gt;
&lt;th&gt;Similar reviews&lt;/th&gt;
&lt;th&gt;Current load&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Engineer A&lt;/strong&gt; is the listed owner, but hasn't done recent work in this directory, and is already carrying a heavy review load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Engineer B&lt;/strong&gt; isn't in CODEOWNERS at all, but has been actively working in this area recently and has reviewed similar changes — they've probably seen the exact class of bug this PR could introduce.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Engineer C&lt;/strong&gt; has moderate ownership and moderate recent activity, low similarity to this specific change, but has bandwidth right now.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A purely static system routes to A every time, because A is the only name it knows how to check against. But on the actual signals that predict a useful review — recent, hands-on context and demonstrated familiarity with similar changes — B is the stronger candidate, and C is a reasonable fallback if B is unavailable.&lt;/p&gt;

&lt;p&gt;This doesn't mean A should be removed from the review entirely — for something in a sensitive path, keeping the formal owner in the loop for accountability might still make sense. It means A shouldn't be the &lt;em&gt;only&lt;/em&gt; signal the system checks.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. A Practical Routing Framework
&lt;/h2&gt;

&lt;p&gt;Distilling this into something you could actually reason about (or build) for your own repo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Ownership&lt;/strong&gt; — who's formally accountable, per CODEOWNERS or equivalent?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recency&lt;/strong&gt; — who's touched this code lately?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expertise&lt;/strong&gt; — who has a track record of relevant, substantive contributions here?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review history&lt;/strong&gt; — who's reviewed similar changes before, and reviewed them well (not just approved fast)?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load&lt;/strong&gt; — who has the bandwidth to actually do this review in a reasonable timeframe?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of these should unilaterally win. Ownership keeps governance intact — you don't want a recency model quietly routing security-sensitive changes away from the team accountable for them. Load is a modifier, not a primary filter — someone who's slightly busy but the clear best fit is often still the right call over someone who's fully free but has no context. The five signals are meant to be combined, with the weighting depending on what kind of change you're looking at (a one-line config tweak needs way less of this than a cross-cutting refactor).&lt;/p&gt;

&lt;h2&gt;
  
  
  6. The Routing-Decay Loop
&lt;/h2&gt;

&lt;p&gt;Here's the pattern that causes CODEOWNERS files to quietly go stale, laid out as a loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;People change teams / roles
        ↓
Code changes (new services, refactors, deprecations)
        ↓
Expertise shifts (some people gain context, others lose it)
        ↓
Ownership file stays the same (nobody's job to update it proactively)
        ↓
Routing quality declines
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing in that loop is anomalous — it's just normal organizational and codebase churn. The failure isn't that people move around or that code changes. The failure is that CODEOWNERS has no way to hear about any of it. It's a file, not a feed.&lt;/p&gt;

&lt;p&gt;The fix isn't "update the file more often" — that's a losing battle against how fast real orgs change. It's closer to: &lt;strong&gt;continuously derive dynamic signals from data you already have&lt;/strong&gt; (commit history, PR review history, recent activity) and layer them on top of the static file, rather than trying to keep the static file itself perfectly current. Contribution and review data refresh automatically as people work — no one has to remember to edit a YAML-adjacent file when Bob becomes the de facto payments expert. The signal is already sitting in your git history and PR review logs; it's just not being used for routing.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. What Teams Can Measure Today
&lt;/h2&gt;

&lt;p&gt;You don't need new tooling to start getting visibility into how well your current routing is actually working. Most of this is derivable from data already in GitHub:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reviewer reassignment rate&lt;/strong&gt; — how often does the auto-assigned reviewer get swapped out before the PR merges? High rate = your default routing isn't matching reality.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time to first &lt;em&gt;meaningful&lt;/em&gt; review&lt;/strong&gt; — not first comment, first substantive review. If the assigned reviewer routinely takes days to engage, they may be overloaded or not the right fit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review load concentration&lt;/strong&gt; — what percentage of review volume in a given area lands on one person? If it's consistently one name, you likely have a bottleneck, whether or not that person is technically the best expert.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PRs routed to inactive contributors&lt;/strong&gt; — a rough version of this is: for each CODEOWNERS entry, check &lt;code&gt;git log --since="6 months ago" -- &amp;lt;path&amp;gt;&lt;/code&gt; and see if the listed owner shows up. If not, that entry is a candidate for drift.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review handoffs&lt;/strong&gt; — PRs where the review gets passed from one person to another before merge are a decent proxy for "the first routing decision missed."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recent contribution coverage&lt;/strong&gt; — what share of merged PRs in an area were reviewed by someone who'd actually committed to that area in the last N weeks?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these require a new system to start tracking. A few are a &lt;code&gt;git log&lt;/code&gt; or a GitHub API query away. The value isn't in any single metric — it's in noticing, over a few months, whether your routing is drifting in a direction nobody's paying attention to.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Practical Takeaway
&lt;/h2&gt;

&lt;p&gt;None of this is an argument for dropping CODEOWNERS. It's still the right mechanism for encoding accountability — who's on the hook for a given part of the codebase, and which teams need guaranteed visibility into changes that touch their area.&lt;/p&gt;

&lt;p&gt;What it's not sufficient for, on its own, is figuring out who should actually review a given PR today.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep CODEOWNERS for accountability. Add dynamic signals for relevance.&lt;/strong&gt; Ownership answers "who's responsible." Recency, expertise, review history, and load together answer "who's actually the right person to look at this, right now." A routing setup that only asks the first question will keep sending PRs to people who used to be the right answer. A routing setup that ignores the first question entirely gives up the governance guarantees CODEOWNERS exists to provide. You want both.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;How are you handling reviewer routing today&lt;/strong&gt; — static CODEOWNERS, team rotation, tribal knowledge ("just tag whoever's around"), or something more dynamic? Curious what's actually working at different team sizes — drop your setup in the comments.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>git</category>
      <category>github</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Our AI code reviewer problem wasn't that it was wrong. It was that it wouldn't shut up</title>
      <dc:creator>Codzee.io</dc:creator>
      <pubDate>Thu, 27 Aug 2026 13:16:37 +0000</pubDate>
      <link>https://dev.to/codzee_io/our-ai-code-reviewer-problem-wasnt-that-it-was-wrong-it-was-that-it-wouldnt-shut-up-5b5</link>
      <guid>https://dev.to/codzee_io/our-ai-code-reviewer-problem-wasnt-that-it-was-wrong-it-was-that-it-wouldnt-shut-up-5b5</guid>
      <description>&lt;p&gt;I've been thinking about a problem with AI code review that I don't see discussed enough: a reviewer can be technically correct and still make the whole review experience worse.&lt;/p&gt;

&lt;p&gt;Here's the PR that made this click for me. Small change, maybe 200 lines, nothing exotic. New validation path, a couple helper functions. The kind of thing that used to get a comment or two and an approve.&lt;/p&gt;

&lt;p&gt;The AI reviewer came back with something like a dozen comments. A naming suggestion. A "this null check might be redundant" note. A theoretical race condition that would only show up under conditions the code was never going to hit in prod. A "you could extract this into a function" suggestion on a function that was already about ten lines long.&lt;/p&gt;

&lt;p&gt;And here's the annoying part  most of these weren't &lt;em&gt;&lt;a href="https://www.codzee.io/" rel="noopener noreferrer"&gt;wrong&lt;/a&gt;&lt;/em&gt;. The variable name genuinely could've been clearer. The null check probably was redundant. Individually, I could defend almost every comment on that list.&lt;/p&gt;

&lt;p&gt;But there was one comment in there about an actual edge case in the validation logic that genuinely mattered. And it was sitting in the middle of eleven other comments that didn't. The dev opening the PR skimmed most of it, dismissed a few without really reading them, and nearly skipped the important one too — because by comment seven or eight, he'd already stopped expecting any of it to be worth his time.&lt;/p&gt;

&lt;p&gt;Nobody wanted "more thorough." They wanted to know what actually mattered.&lt;/p&gt;

&lt;p&gt;That's the distinction I think gets missed constantly: &lt;strong&gt;"is this technically an issue" and "is this worth interrupting someone for" are completely different questions&lt;/strong&gt;, and most tooling in this space only ever answers the first one.&lt;/p&gt;

&lt;p&gt;The assumption baked into a lot of AI review tools is basically: if finding more issues is good, finding even more must be better. But review was never just an issue-detection problem, it's a signal-to-noise problem, and honestly kind of a trust problem too. Once a reviewer starts treating a PR like a checklist to maximize, it stops mattering how accurate any individual comment is — the aggregate experience is what people remember, and the aggregate experience was "annoying."&lt;/p&gt;

&lt;p&gt;That frustration eventually became one of the reasons I started working on Codzee. Not going to turn this into a pitch — the short version is the goal isn't "find everything," it's figuring out what actually deserves a developer's attention. Still early, still figuring a lot of it out.&lt;/p&gt;

&lt;p&gt;Genuinely curious how other people think about this though:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How many AI review comments do you actually want to see on a normal PR? Is there a number where it tips from "helpful" to "annoying" for you?&lt;/li&gt;
&lt;li&gt;Do you find yourself tuning out AI-generated comments after a tool has burned you with noise a few times?&lt;/li&gt;
&lt;li&gt;Where's your personal line between a useful warning and something that's just noise dressed up as a finding?&lt;/li&gt;
&lt;li&gt;Would you rather a reviewer miss a low-confidence issue entirely, or flag it anyway and let you decide?&lt;/li&gt;
&lt;li&gt;What actually makes you trust an automated reviewer, versus just tolerate it?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not trying to manufacture a debate here, I'm actually unsure about some of these myself — like the miss-vs-flag question, I go back and forth on what the right default even is. Curious what this sub thinks.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>codequality</category>
      <category>coding</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>AI code review: Are more comments actually</title>
      <dc:creator>Codzee.io</dc:creator>
      <pubDate>Tue, 25 Aug 2026 12:23:34 +0000</pubDate>
      <link>https://dev.to/codzee_io/ai-code-review-are-more-comments-actually-3e2d</link>
      <guid>https://dev.to/codzee_io/ai-code-review-are-more-comments-actually-3e2d</guid>
      <description>&lt;p&gt;we’ve been thinking about something that seems easy to overlook with AI-assisted code review.&lt;/p&gt;

&lt;p&gt;Imagine a PR gets &lt;strong&gt;24 AI-generated comments&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That sounds thorough—but how many of those comments would you actually want a developer to spend time on?&lt;/p&gt;

&lt;p&gt;There’s a big difference between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“This could cause a production bug.”&lt;/li&gt;
&lt;li&gt;“This might create a security issue.”&lt;/li&gt;
&lt;li&gt;“This code could be more readable.”&lt;/li&gt;
&lt;li&gt;“You could rename this variable.”&lt;/li&gt;
&lt;li&gt;“Consider refactoring this small section.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these may technically be valid observations, but they don't have the same value.&lt;/p&gt;

&lt;p&gt;For developers, the real challenge isn't just &lt;strong&gt;finding issues&lt;/strong&gt; anymore.&lt;/p&gt;

&lt;p&gt;It's &lt;strong&gt;prioritizing them&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Too many low-value comments can create review fatigue, hide important findings, and slow down the person who actually needs to make the decision.&lt;/p&gt;

&lt;p&gt;I'm curious how other developers handle this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When using AI for code review, what do you prefer?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;AI should report everything and let developers filter it.&lt;/li&gt;
&lt;li&gt;AI should only report high-confidence, high-impact issues.&lt;/li&gt;
&lt;li&gt;AI should report everything but rank comments by severity.&lt;/li&gt;
&lt;li&gt;Something else?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We've been exploring this problem at Codzee and believe that AI code review should optimize for &lt;strong&gt;signal, not comment count&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Would love to hear how this works in your team and what you've found useful—or annoying—about AI code review.&lt;br&gt;
&lt;a href="http://www.codzee.io" rel="noopener noreferrer"&gt;www.codzee.io&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How I'd Benchmark an AI Code Reviewer Before Putting It on 100 Engineers' PRs</title>
      <dc:creator>Codzee.io</dc:creator>
      <pubDate>Mon, 24 Aug 2026 12:55:11 +0000</pubDate>
      <link>https://dev.to/codzee_io/how-id-benchmark-an-ai-code-reviewer-before-putting-it-on-100-engineers-prs-1i19</link>
      <guid>https://dev.to/codzee_io/how-id-benchmark-an-ai-code-reviewer-before-putting-it-on-100-engineers-prs-1i19</guid>
      <description>&lt;p&gt;&lt;a href="https://www.codzee.io/" rel="noopener noreferrer"&gt;AI code-review tools&lt;/a&gt; are easy to demo.&lt;/p&gt;

&lt;p&gt;Give one a pull request, wait a few seconds, and it produces a handful of comments that look surprisingly useful. Maybe it catches a missing authorization check. Maybe it spots a race condition. Maybe it complains about a test that doesn't cover an edge case.&lt;/p&gt;

&lt;p&gt;That's a good demo.&lt;/p&gt;

&lt;p&gt;It is not a benchmark.&lt;/p&gt;

&lt;p&gt;If you're considering putting an AI reviewer on the pull requests of 100 engineers, the question isn't &lt;em&gt;"How good does this look?"&lt;/em&gt; It's:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How often does this tool find problems that matter in our code, how often does it waste developers' time, and does it improve the review process enough to justify the cost?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I'd answer that question with an evaluation built around your own repositories, languages, review practices, and historical bugs.&lt;/p&gt;

&lt;p&gt;Here's how.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Build a representative PR dataset
&lt;/h2&gt;

&lt;p&gt;Start with a dataset of &lt;a href="https://www.codzee.io/" rel="noopener noreferrer"&gt;pull requests&lt;/a&gt; that looks like your actual engineering workload.&lt;/p&gt;

&lt;p&gt;Don't build it entirely from toy examples. A benchmark containing 50 artificially constructed security bugs will tell you something about the model, but not necessarily much about what happens when it encounters your production code.&lt;/p&gt;

&lt;p&gt;I'd aim for a few categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Historical production bug fixes&lt;/li&gt;
&lt;li&gt;PRs that introduced bugs but were later fixed&lt;/li&gt;
&lt;li&gt;Normal feature PRs with no known bugs&lt;/li&gt;
&lt;li&gt;Refactoring PRs&lt;/li&gt;
&lt;li&gt;Dependency updates&lt;/li&gt;
&lt;li&gt;Performance-related changes&lt;/li&gt;
&lt;li&gt;Security-sensitive changes&lt;/li&gt;
&lt;li&gt;Database/schema changes&lt;/li&gt;
&lt;li&gt;API changes&lt;/li&gt;
&lt;li&gt;Test-only changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important part is preserving the context available during a real review: the PR diff, repository state, relevant files, tests, configuration, and whatever other context your normal review process exposes.&lt;/p&gt;

&lt;p&gt;You should also keep a hidden ground-truth record for each PR.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PR-1842
Repository: payments-api
Language: Go
Known issue: authorization bypass
Severity: Critical
Introduced in: PR
Fixed by: PR-1911
Expected finding: Yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For clean PRs, record that too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PR-2017
Repository: customer-service
Language: Kotlin
Known issue: None
Expected finding: No
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives you both positive and negative examples.&lt;/p&gt;

&lt;p&gt;The negative examples are essential. An AI reviewer that finds something suspicious in every PR can look impressive until developers have to deal with the resulting noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Include known real-world bugs
&lt;/h2&gt;

&lt;p&gt;Historical bugs are some of the most valuable test cases you have.&lt;/p&gt;

&lt;p&gt;Look through incident reports, postmortems, security fixes, bug tickets, and reverted changes. Find bugs that were actually introduced into your codebase.&lt;/p&gt;

&lt;p&gt;Then construct benchmark cases that reproduce the review situation.&lt;/p&gt;

&lt;p&gt;For example, suppose six months ago a PR introduced:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_admin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;export_all_accounts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;when the intended condition was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_admin&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;can_export_accounts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;export_all_accounts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The benchmark should test whether the reviewer catches the authorization problem from the PR context—not whether it can identify a deliberately planted &lt;code&gt;TODO: SECURITY BUG&lt;/code&gt; comment.&lt;/p&gt;

&lt;p&gt;This distinction matters.&lt;/p&gt;

&lt;p&gt;A useful benchmark measures performance on problems engineers genuinely encounter.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Include different bug severities
&lt;/h2&gt;

&lt;p&gt;Not every finding has the same value.&lt;/p&gt;

&lt;p&gt;A reviewer that catches one critical security issue but misses 20 minor problems may still be extremely valuable. Conversely, a tool that produces hundreds of "potential issue" comments while missing serious defects can become a productivity problem.&lt;/p&gt;

&lt;p&gt;Classify your known issues.&lt;/p&gt;

&lt;p&gt;One simple taxonomy is:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Critical&lt;/td&gt;
&lt;td&gt;Data loss, privilege escalation, severe security vulnerability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Production outage, major correctness issue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Significant edge case or reliability problem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Minor correctness issue, maintainability problem&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You can adapt these categories to your existing incident or vulnerability classification.&lt;/p&gt;

&lt;p&gt;Then measure recall separately by severity.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Critical: 4/5 found
High:     11/18 found
Medium:   17/31 found
Low:      9/22 found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That tells you much more than a single "82% accuracy" number.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Test multiple repositories and languages
&lt;/h2&gt;

&lt;p&gt;If your organization has six repositories and four languages, don't benchmark the tool on one favorite service written in the language it handles best.&lt;/p&gt;

&lt;p&gt;Split the dataset across representative environments.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;payments-api       Go
web-frontend       TypeScript
mobile-backend     Kotlin
data-platform      Python
infrastructure     Terraform
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't necessarily need equal numbers of PRs in every repository. You do need enough samples to identify obvious differences.&lt;/p&gt;

&lt;p&gt;The question isn't only "Does the tool work?"&lt;/p&gt;

&lt;p&gt;It's:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Does it work consistently enough across the environments where we're planning to deploy it?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A reviewer that performs brilliantly on TypeScript but poorly on Terraform may still be useful. You just need to know that before making it mandatory across the organization.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Give every reviewer the same context
&lt;/h2&gt;

&lt;p&gt;Benchmark fairness is surprisingly easy to get wrong.&lt;/p&gt;

&lt;p&gt;If you're comparing two AI reviewers, make the input as equivalent as possible.&lt;/p&gt;

&lt;p&gt;Give each one the same:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PR diff&lt;/li&gt;
&lt;li&gt;Base revision&lt;/li&gt;
&lt;li&gt;Repository contents&lt;/li&gt;
&lt;li&gt;Relevant configuration&lt;/li&gt;
&lt;li&gt;Tests&lt;/li&gt;
&lt;li&gt;Documentation&lt;/li&gt;
&lt;li&gt;Existing review context&lt;/li&gt;
&lt;li&gt;Tool permissions, where applicable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't manually explain a tricky bug to one system because "it needed a little help."&lt;/p&gt;

&lt;p&gt;Likewise, don't give one tool access to information that the other cannot see unless that difference is part of the product you're evaluating.&lt;/p&gt;

&lt;p&gt;Context also needs to be documented.&lt;/p&gt;

&lt;p&gt;For each benchmark run, record exactly what the reviewer was allowed to inspect.&lt;/p&gt;

&lt;p&gt;Otherwise, six months later, you'll have two benchmark results that look comparable but weren't generated under comparable conditions.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Measure bugs correctly identified
&lt;/h2&gt;

&lt;p&gt;The first metric I'd track is &lt;strong&gt;bug recall&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At its simplest:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bug recall = known bugs correctly identified / known bugs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Suppose your dataset contains 100 known bugs and the tool identifies 72 of them.&lt;/p&gt;

&lt;p&gt;That's 72% recall.&lt;/p&gt;

&lt;p&gt;But there's a catch: what counts as "identified"?&lt;/p&gt;

&lt;p&gt;A comment saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This code might have an issue."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;isn't necessarily equivalent to correctly identifying the actual defect.&lt;/p&gt;

&lt;p&gt;Define acceptance criteria before running the benchmark.&lt;/p&gt;

&lt;p&gt;For example, a finding might count as correct only if it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Points to the relevant code.&lt;/li&gt;
&lt;li&gt;Describes the actual failure mode.&lt;/li&gt;
&lt;li&gt;Explains why the change causes the problem.&lt;/li&gt;
&lt;li&gt;Provides enough information for an engineer to validate it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This prevents optimistic scoring.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Measure false positives
&lt;/h2&gt;

&lt;p&gt;Now run the other half of the experiment.&lt;/p&gt;

&lt;p&gt;Give the reviewer PRs with no known bugs and see what it reports.&lt;/p&gt;

&lt;p&gt;A useful metric is &lt;strong&gt;false-positive rate&lt;/strong&gt;, but I also like tracking the simpler number:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;False findings per PR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If a tool produces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Known bugs found:      72
False findings:       180
PRs reviewed:          100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then its 72% recall doesn't look nearly as exciting.&lt;/p&gt;

&lt;p&gt;You can also calculate precision:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Precision = correct findings / all findings&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the reviewer produces 100 findings and only 40 are genuinely actionable, precision is 40%.&lt;/p&gt;

&lt;p&gt;For developers, this metric can matter enormously.&lt;/p&gt;

&lt;p&gt;A reviewer that catches everything but complains about everything isn't necessarily useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Measure duplicate and noisy findings
&lt;/h2&gt;

&lt;p&gt;False positives aren't the only source of noise.&lt;/p&gt;

&lt;p&gt;AI reviewers can report the same underlying problem multiple times.&lt;/p&gt;

&lt;p&gt;For example, one missing validation might produce:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Input isn't validated."&lt;/li&gt;
&lt;li&gt;"Potential invalid state."&lt;/li&gt;
&lt;li&gt;"Unexpected value may reach database."&lt;/li&gt;
&lt;li&gt;"Consider adding defensive checks."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Four comments, one issue.&lt;/p&gt;

&lt;p&gt;I'd explicitly measure &lt;strong&gt;unique actionable findings&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can group findings that describe the same underlying defect and count them once.&lt;/p&gt;

&lt;p&gt;Also track findings that are technically true but don't deserve review attention.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This function could be refactored to reduce complexity."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That may be reasonable advice, but if your benchmark is evaluating bug detection, it shouldn't count as a valuable bug finding.&lt;/p&gt;

&lt;p&gt;A useful classification is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Correct + actionable
Correct + low value
Duplicate
False positive
Not a bug
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the output much easier to analyze.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Measure severity accuracy
&lt;/h2&gt;

&lt;p&gt;Finding the bug isn't enough.&lt;/p&gt;

&lt;p&gt;The reviewer should also understand its impact.&lt;/p&gt;

&lt;p&gt;Suppose your ground truth says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Authorization bypass → Critical
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the AI says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Potential code quality issue → Low
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Technically, it noticed something. Operationally, it failed an important part of the review.&lt;/p&gt;

&lt;p&gt;Compare predicted severity with your ground truth:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                  Actual
Predicted       Critical  High  Medium  Low
Critical            7      2      0      0
High                3     14      4      1
Medium              0      5     19      7
Low                 0      1      8     11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't need sophisticated statistics to start. Even a confusion matrix like this will show whether the tool systematically underestimates serious defects.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Measure whether developers actually accept findings
&lt;/h2&gt;

&lt;p&gt;Eventually, the benchmark has to leave the spreadsheet.&lt;/p&gt;

&lt;p&gt;Ask engineers to review the AI findings without knowing which tool produced them.&lt;/p&gt;

&lt;p&gt;For every finding, capture something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Valid issue?       Yes / No
Actionable?        Yes / No
Would fix it?      Yes / No
Would mention it?  Yes / No
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're running a live pilot, you can also measure what happens to findings in actual PRs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accepted&lt;/li&gt;
&lt;li&gt;Fixed&lt;/li&gt;
&lt;li&gt;Dismissed&lt;/li&gt;
&lt;li&gt;Ignored&lt;/li&gt;
&lt;li&gt;Marked duplicate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is arguably one of the strongest signals you can get.&lt;/p&gt;

&lt;p&gt;A finding with 95% technical accuracy but a 10% acceptance rate may not be particularly useful.&lt;/p&gt;

&lt;p&gt;A finding that engineers consistently validate and act on is much more valuable.&lt;/p&gt;

&lt;h2&gt;
  
  
  11. Measure review latency
&lt;/h2&gt;

&lt;p&gt;Don't forget the economics of the workflow.&lt;/p&gt;

&lt;p&gt;Measure how long it takes from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PR opened
    ↓
AI review starts
    ↓
AI findings available
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then compare that with the existing review process.&lt;/p&gt;

&lt;p&gt;Latency matters because an AI reviewer that takes 45 minutes to analyze every PR may be technically impressive but operationally awkward.&lt;/p&gt;

&lt;p&gt;You should also test different PR sizes.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Small:   &amp;lt;200 changed lines
Medium:  200–1,000
Large:   &amp;gt;1,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A tool might be excellent on small PRs and degrade badly on large ones.&lt;/p&gt;

&lt;p&gt;That's something you want to discover in a benchmark, not after deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  12. Measure developer time saved
&lt;/h2&gt;

&lt;p&gt;This is where the benchmark becomes a business case.&lt;/p&gt;

&lt;p&gt;Estimate the human effort associated with the findings.&lt;/p&gt;

&lt;p&gt;For example, during a pilot you might measure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PRs reviewed:                  200
Valid AI findings:              86
Findings accepted by authors:   61
Estimated review effort saved:  24 hours
Additional triage time:          7 hours
Net time saved:                 17 hours
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Be conservative.&lt;/p&gt;

&lt;p&gt;If an AI comment catches something a human reviewer would definitely have found anyway, don't automatically count the entire human review as "saved."&lt;/p&gt;

&lt;p&gt;Instead, ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"How much work did this finding actually remove from the engineering process?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can estimate time through short developer surveys, sampled review sessions, or controlled experiments.&lt;/p&gt;

&lt;p&gt;The goal isn't to manufacture a perfect number. It's to get a defensible estimate.&lt;/p&gt;

&lt;h2&gt;
  
  
  13. Repeat the evaluation over time
&lt;/h2&gt;

&lt;p&gt;One benchmark run isn't enough.&lt;/p&gt;

&lt;p&gt;AI systems change. Your repositories change. Prompting changes. Models change. Vendors ship new detection logic.&lt;/p&gt;

&lt;p&gt;Run the benchmark periodically.&lt;/p&gt;

&lt;p&gt;I'd keep a fixed &lt;strong&gt;golden dataset&lt;/strong&gt; containing a representative sample of your most important historical cases, then add new cases over time.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Baseline
├── 100 historical bugs
├── 100 clean PRs
└── 50 security-sensitive PRs

Quarter 2
├── +25 new production bugs
└── +25 new clean PRs

Quarter 3
├── +20 new production bugs
└── +20 new clean PRs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can track whether performance is actually improving.&lt;/p&gt;

&lt;p&gt;You can also detect regressions.&lt;/p&gt;

&lt;p&gt;If version 4.2 of your AI reviewer goes from 78% to 84% recall but doubles false findings, that's not simply "better."&lt;/p&gt;

&lt;p&gt;It's a trade-off.&lt;/p&gt;

&lt;h2&gt;
  
  
  A simple scoring framework
&lt;/h2&gt;

&lt;p&gt;You don't need a complicated machine-learning benchmark.&lt;/p&gt;

&lt;p&gt;Here's a framework I'd start with:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Weight&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bug recall&lt;/td&gt;
&lt;td&gt;30%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Precision / false positives&lt;/td&gt;
&lt;td&gt;20%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Severity accuracy&lt;/td&gt;
&lt;td&gt;10%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Developer acceptance&lt;/td&gt;
&lt;td&gt;15%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Duplicate/noise rate&lt;/td&gt;
&lt;td&gt;10%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Review latency&lt;/td&gt;
&lt;td&gt;5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Developer time saved&lt;/td&gt;
&lt;td&gt;10%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Score each category from 0–100, then calculate the weighted total.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Recall                  82 × 0.30 = 24.6
Precision               76 × 0.20 = 15.2
Severity accuracy       80 × 0.10 =  8.0
Developer acceptance    71 × 0.15 = 10.7
Noise                   85 × 0.10 =  8.5
Latency                 90 × 0.05 =  4.5
Time saved              68 × 0.10 =  6.8

Total                               78.3 / 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact weights are less important than agreeing on them &lt;strong&gt;before&lt;/strong&gt; you see the results.&lt;/p&gt;

&lt;p&gt;And I'd add one more rule: define minimum thresholds for critical metrics.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Overall score       ≥ 75
Critical bug recall ≥ 90%
Precision            ≥ 60%
P95 review latency   ≤ 10 minutes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That prevents a tool from compensating for catastrophic performance in one area with excellent performance in another.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about vendor benchmarks?
&lt;/h2&gt;

&lt;p&gt;Vendor benchmarks are useful.&lt;/p&gt;

&lt;p&gt;They can tell you how a tool performs against standardized datasets, and they're worth looking at when you're building your shortlist.&lt;/p&gt;

&lt;p&gt;But they answer a different question.&lt;/p&gt;

&lt;p&gt;A vendor benchmark asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"How well does our system perform on this benchmark?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Your benchmark asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"How well does this system work for our engineers, in our codebases, under our review process?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's the number I'd use when deciding whether to put the tool on 100 engineers' PRs.&lt;/p&gt;

&lt;p&gt;For example, if you're evaluating a tool such as Codzee, treat its published benchmark results as one input into your research—not as the final deployment decision.&lt;/p&gt;

&lt;p&gt;The same methodology should apply to every vendor.&lt;/p&gt;

&lt;h2&gt;
  
  
  The benchmark I'd actually run
&lt;/h2&gt;

&lt;p&gt;If I were setting this up for an engineering organization tomorrow, I'd make the process roughly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Select 300–500 representative PRs
              ↓
2. Label known bugs and expected severity
              ↓
3. Include clean PRs as negative examples
              ↓
4. Run each AI reviewer with equivalent context
              ↓
5. Normalize and deduplicate findings
              ↓
6. Blind-score correctness and severity
              ↓
7. Run a developer acceptance study
              ↓
8. Measure latency and engineering effort
              ↓
9. Calculate weighted score
              ↓
10. Repeat periodically
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most importantly, keep the benchmark independent from the vendor.&lt;/p&gt;

&lt;p&gt;You choose the PRs.&lt;/p&gt;

&lt;p&gt;You define what constitutes a correct finding.&lt;/p&gt;

&lt;p&gt;You decide how severity is classified.&lt;/p&gt;

&lt;p&gt;You determine which findings are useful.&lt;/p&gt;

&lt;p&gt;And you keep the dataset private enough that it can't simply become another benchmark for vendors to optimize against.&lt;/p&gt;

&lt;p&gt;That's how you turn an AI code-review demo into an engineering evaluation.&lt;/p&gt;

&lt;p&gt;The goal isn't to find the AI reviewer with the highest benchmark score.&lt;/p&gt;

&lt;p&gt;It's to find the one that makes &lt;strong&gt;your&lt;/strong&gt; code-review process better without creating a new category of developer noise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What would you add to this benchmark?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>I Put an AI Reviewer on Every PR. Here's What Happened After the 100th Review.</title>
      <dc:creator>Codzee.io</dc:creator>
      <pubDate>Thu, 20 Aug 2026 12:03:16 +0000</pubDate>
      <link>https://dev.to/codzee_io/i-put-an-ai-reviewer-on-every-pr-heres-what-happened-after-the-100th-review-393p</link>
      <guid>https://dev.to/codzee_io/i-put-an-ai-reviewer-on-every-pr-heres-what-happened-after-the-100th-review-393p</guid>
      <description>&lt;p&gt;At first, adding an &lt;a href="http://www.codzee.io/" rel="noopener noreferrer"&gt;AI code reviewer&lt;/a&gt; to every pull request feels like cheating.&lt;/p&gt;

&lt;p&gt;Every PR gets another pair of eyes.&lt;/p&gt;

&lt;p&gt;Every diff gets analyzed.&lt;/p&gt;

&lt;p&gt;Potential bugs are pointed out before a human reviewer even opens the PR.&lt;/p&gt;

&lt;p&gt;The first few reviews are impressive.&lt;/p&gt;

&lt;p&gt;Then something strange happens.&lt;/p&gt;

&lt;p&gt;You stop reading every comment.&lt;/p&gt;

&lt;p&gt;Not because the reviewer is always wrong.&lt;/p&gt;

&lt;p&gt;Because you learn that most comments aren't worth stopping for.&lt;/p&gt;

&lt;p&gt;That's the part of AI code review I think we don't talk about enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  The reviewer's first job isn't finding bugs
&lt;/h2&gt;

&lt;p&gt;It's earning the developer's attention.&lt;/p&gt;

&lt;p&gt;Imagine this PR:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI review

✓ Possible null handling issue
✓ Consider extracting this function
✓ This variable could be renamed
✓ Potential race condition
✓ Missing test case
✓ This comment could be clearer
✓ Consider using...
✓ Consider using...
✓ Consider using...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem isn't that every comment is bad.&lt;/p&gt;

&lt;p&gt;Some might be useful.&lt;/p&gt;

&lt;p&gt;The problem is that the developer now has to perform another review:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“Which of these comments should I care about?”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's review fatigue.&lt;/p&gt;

&lt;p&gt;And it can happen surprisingly quickly.&lt;/p&gt;




&lt;h1&gt;
  
  
  There are four kinds of &lt;a href="http://www.codzee.io/" rel="noopener noreferrer"&gt;AI review noise&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;I've found it useful to think about review noise in four categories.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Wrong
&lt;/h2&gt;

&lt;p&gt;The reviewer identifies something that isn't actually a problem.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This condition can never be true.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Except it can.&lt;/p&gt;

&lt;p&gt;The reviewer simply misunderstood how the value reaches the function.&lt;/p&gt;

&lt;p&gt;This is the easiest type of noise to recognize.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Technically correct
&lt;/h2&gt;

&lt;p&gt;This one is more dangerous.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This function is 45 lines long.
Consider splitting it into smaller functions.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fine.&lt;/p&gt;

&lt;p&gt;Maybe that's a good idea.&lt;/p&gt;

&lt;p&gt;But if the PR is fixing a production incident and the function is intentionally kept together for transactional behavior, this isn't the problem the reviewer should be talking about.&lt;/p&gt;

&lt;p&gt;The comment isn't wrong.&lt;/p&gt;

&lt;p&gt;It just isn't useful right now.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Missing context
&lt;/h2&gt;

&lt;p&gt;This happens constantly.&lt;/p&gt;

&lt;p&gt;The reviewer sees:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (!user) {
    return;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Potentially unsafe null handling.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But the API intentionally permits anonymous users.&lt;/p&gt;

&lt;p&gt;The reviewer doesn't understand the business rule.&lt;/p&gt;

&lt;p&gt;The developer does.&lt;/p&gt;

&lt;p&gt;Now the developer has to explain the business rule to the AI reviewer.&lt;/p&gt;

&lt;p&gt;That's backwards.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Repetition
&lt;/h2&gt;

&lt;p&gt;This is the fastest way to turn useful tooling into background noise.&lt;/p&gt;

&lt;p&gt;The same type of comment appears over and over.&lt;/p&gt;

&lt;p&gt;Eventually developers recognize the pattern.&lt;/p&gt;

&lt;p&gt;They stop reading.&lt;/p&gt;

&lt;p&gt;And once they stop reading, the good comments get ignored too.&lt;/p&gt;




&lt;h1&gt;
  
  
  The worst metric for AI code review
&lt;/h1&gt;

&lt;p&gt;I don't care how many comments an AI reviewer generates.&lt;/p&gt;

&lt;p&gt;Seriously.&lt;/p&gt;

&lt;p&gt;Imagine two systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  System A
&lt;/h3&gt;

&lt;p&gt;100 comments.&lt;/p&gt;

&lt;p&gt;8 accepted.&lt;/p&gt;

&lt;h3&gt;
  
  
  System B
&lt;/h3&gt;

&lt;p&gt;15 comments.&lt;/p&gt;

&lt;p&gt;9 accepted.&lt;/p&gt;

&lt;p&gt;Which one would you rather have?&lt;/p&gt;

&lt;p&gt;Obviously B.&lt;/p&gt;

&lt;p&gt;But comment volume is seductive because it's easy to put on a dashboard.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PRs reviewed: 2,381

Issues detected: 14,921
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That sounds impressive.&lt;/p&gt;

&lt;p&gt;It doesn't tell you whether developers found those issues useful.&lt;/p&gt;

&lt;p&gt;I'd rather see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Findings: 1,200

Accepted: 780
Dismissed: 310
Duplicates: 70
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we're measuring something interesting.&lt;/p&gt;




&lt;h1&gt;
  
  
  Try a review-noise audit
&lt;/h1&gt;

&lt;p&gt;If your team already uses AI code review, here's a simple experiment.&lt;/p&gt;

&lt;p&gt;Take the last 100 AI-generated review comments.&lt;/p&gt;

&lt;p&gt;Put each one into one of these buckets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A — Fixed
B — Discussed / investigated
C — Dismissed
D — Duplicate
E — Not actionable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then calculate the percentages.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Fixed:              31%
Investigated:       18%
Dismissed:           27%
Duplicate:           12%
Not actionable:      12%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you have a much more useful picture of your reviewer.&lt;/p&gt;

&lt;p&gt;The interesting number isn't “31% fixed.”&lt;/p&gt;

&lt;p&gt;It's everything else.&lt;/p&gt;

&lt;p&gt;Because every dismissed or low-value comment still consumed some amount of developer attention.&lt;/p&gt;




&lt;h1&gt;
  
  
  Then look at severity
&lt;/h1&gt;

&lt;p&gt;This is another place where AI reviewers can lose trust.&lt;/p&gt;

&lt;p&gt;Suppose a normal PR gets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;5 critical issues
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You investigate them.&lt;/p&gt;

&lt;p&gt;Three are style suggestions.&lt;/p&gt;

&lt;p&gt;One is a minor maintainability concern.&lt;/p&gt;

&lt;p&gt;One is actually important.&lt;/p&gt;

&lt;p&gt;After a few PRs like that, what does “critical” mean to you?&lt;/p&gt;

&lt;p&gt;Probably not much.&lt;/p&gt;

&lt;p&gt;Severity needs a contract.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;h3&gt;
  
  
  Critical
&lt;/h3&gt;

&lt;p&gt;Could realistically cause:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;security compromise&lt;/li&gt;
&lt;li&gt;data loss&lt;/li&gt;
&lt;li&gt;major outage&lt;/li&gt;
&lt;li&gt;broken core functionality&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  High
&lt;/h3&gt;

&lt;p&gt;Meaningful production risk.&lt;/p&gt;

&lt;h3&gt;
  
  
  Medium
&lt;/h3&gt;

&lt;p&gt;Worth fixing but not urgent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Low
&lt;/h3&gt;

&lt;p&gt;Minor concern.&lt;/p&gt;

&lt;p&gt;And then there's another category:&lt;/p&gt;

&lt;h3&gt;
  
  
  Don't comment
&lt;/h3&gt;

&lt;p&gt;If the reviewer isn't confident enough, it should stay quiet.&lt;/p&gt;




&lt;h1&gt;
  
  
  The uncomfortable lesson
&lt;/h1&gt;

&lt;p&gt;Developers don't need an AI reviewer that notices everything.&lt;/p&gt;

&lt;p&gt;They need one that knows what &lt;strong&gt;not&lt;/strong&gt; to mention.&lt;/p&gt;

&lt;p&gt;That's a very different optimization target.&lt;/p&gt;

&lt;p&gt;A human reviewer naturally filters.&lt;/p&gt;

&lt;p&gt;They might see 20 questionable things and comment on 2.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because they understand that every comment costs the author something.&lt;/p&gt;

&lt;p&gt;Time.&lt;/p&gt;

&lt;p&gt;Attention.&lt;/p&gt;

&lt;p&gt;Discussion.&lt;/p&gt;

&lt;p&gt;Potential context switching.&lt;/p&gt;

&lt;p&gt;AI systems don't naturally feel that cost.&lt;/p&gt;

&lt;p&gt;They need to be designed around it.&lt;/p&gt;




&lt;h1&gt;
  
  
  AI writing code makes this more important
&lt;/h1&gt;

&lt;p&gt;There's another reason this problem is getting bigger.&lt;/p&gt;

&lt;p&gt;AI coding agents can produce much larger changes much faster.&lt;/p&gt;

&lt;p&gt;A developer might ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Add OAuth login.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent might modify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;auth/
middleware/
routes/
database/
frontend/
tests/
configuration/
documentation/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now someone has to understand that entire change.&lt;/p&gt;

&lt;p&gt;The bottleneck has moved.&lt;/p&gt;

&lt;p&gt;We used to ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“How can we write code faster?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now we increasingly need to ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“How can we verify more code without increasing cognitive load at the same rate?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is a much harder engineering problem.&lt;/p&gt;




&lt;h1&gt;
  
  
  So what should an AI reviewer actually do?
&lt;/h1&gt;

&lt;p&gt;My ideal reviewer has five rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 1: Don't repeat deterministic tools
&lt;/h2&gt;

&lt;p&gt;If ESLint already catches it, don't produce another paragraph explaining it.&lt;/p&gt;

&lt;p&gt;If the compiler catches it, don't create an AI warning.&lt;/p&gt;

&lt;p&gt;AI should focus on things that require reasoning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 2: Understand the surrounding code
&lt;/h2&gt;

&lt;p&gt;A diff without context is often not enough.&lt;/p&gt;

&lt;p&gt;The reviewer should understand relevant:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;functions&lt;/li&gt;
&lt;li&gt;tests&lt;/li&gt;
&lt;li&gt;interfaces&lt;/li&gt;
&lt;li&gt;configuration&lt;/li&gt;
&lt;li&gt;repository conventions&lt;/li&gt;
&lt;li&gt;PR intent&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Rule 3: Prioritize risk
&lt;/h2&gt;

&lt;p&gt;A potential authentication vulnerability should not appear underneath 12 variable-naming suggestions.&lt;/p&gt;

&lt;p&gt;Rank findings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 4: Explain why the finding matters
&lt;/h2&gt;

&lt;p&gt;Don't say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This could cause a problem.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Say what could happen.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This query now executes once per customer because it sits inside the loop. At 10,000 customers, this turns the operation into an N+1 query pattern.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's actionable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 5: Be willing to say nothing
&lt;/h2&gt;

&lt;p&gt;This may be the most important rule.&lt;/p&gt;

&lt;p&gt;A review that returns:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“No high-confidence issues found.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;can be a successful review.&lt;/p&gt;

&lt;p&gt;Silence is better than noise.&lt;/p&gt;




&lt;h1&gt;
  
  
  Where Codzee fits
&lt;/h1&gt;

&lt;p&gt;This is the problem space where &lt;a href="http://www.codzee.io/" rel="noopener noreferrer"&gt;Codzee&lt;/a&gt; is interesting.&lt;/p&gt;

&lt;p&gt;The useful question isn't:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Can we put AI on every pull request?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's relatively easy now.&lt;/p&gt;

&lt;p&gt;The harder question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Can we put AI on every pull request without making developers hate the review process?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That requires better prioritization, useful context, and a focus on actionable findings rather than maximizing comment volume.&lt;/p&gt;

&lt;p&gt;That's the direction AI-assisted code review needs to move.&lt;/p&gt;




&lt;h1&gt;
  
  
  A simple mental model
&lt;/h1&gt;

&lt;p&gt;Think about AI review like a security guard.&lt;/p&gt;

&lt;p&gt;A bad security guard stops everyone.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;“Bag check.”

“Bag check.”

“Bag check.”

“Bag check.”

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eventually everyone stops paying attention.&lt;/p&gt;

&lt;p&gt;A good security guard doesn't stop everyone.&lt;/p&gt;

&lt;p&gt;They identify the situations that actually deserve attention.&lt;/p&gt;

&lt;p&gt;AI code review should work the same way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't maximize interruptions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Maximize useful interruptions.&lt;/strong&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  The real success metric
&lt;/h1&gt;

&lt;p&gt;After a few months of using an AI reviewer, ask your team one question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“When this reviewer leaves a comment, do you usually read it?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If everyone says yes, you've probably built trust.&lt;/p&gt;

&lt;p&gt;If people say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“I usually just dismiss them.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You have a problem.&lt;/p&gt;

&lt;p&gt;And it's not necessarily model accuracy.&lt;/p&gt;

&lt;p&gt;It's relevance.&lt;/p&gt;

&lt;p&gt;The reviewer has become background noise.&lt;/p&gt;

&lt;p&gt;That's what I mean by &lt;strong&gt;earned irrelevance&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The AI didn't necessarily fail because it couldn't find bugs.&lt;/p&gt;

&lt;p&gt;It failed because developers stopped believing that its comments were worth their attention.&lt;/p&gt;

&lt;p&gt;And in code review, attention is the resource that matters most.&lt;/p&gt;




&lt;h2&gt;
  
  
  What about your team?
&lt;/h2&gt;

&lt;p&gt;If you're already using an AI code reviewer, try the 100-comment audit.&lt;/p&gt;

&lt;p&gt;Take your last 100 comments.&lt;/p&gt;

&lt;p&gt;Classify them.&lt;/p&gt;

&lt;p&gt;Then see how many were actually useful.&lt;/p&gt;

&lt;p&gt;I'd be genuinely interested in what teams are finding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Are AI reviewers reducing your review workload, or have they just created another thing you have to review?&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: This article discusses Codzee as an example of AI-assisted code-review tooling. The broader argument is about the design of AI review workflows, not a claim that any single tool solves the problem.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The AI Code Review Checklist I Actually Use Before Merging a PR</title>
      <dc:creator>Codzee.io</dc:creator>
      <pubDate>Wed, 19 Aug 2026 12:48:48 +0000</pubDate>
      <link>https://dev.to/codzee_io/the-ai-code-review-checklist-i-actually-use-before-merging-a-pr-1l9i</link>
      <guid>https://dev.to/codzee_io/the-ai-code-review-checklist-i-actually-use-before-merging-a-pr-1l9i</guid>
      <description>&lt;p&gt;I've been using &lt;a href="//www.codzee.io"&gt;AI &lt;/a&gt;coding tools heavily for a while now, and the thing that changed my workflow the most wasn't the code generation itself, it was building a review habit that actually catches the failure modes specific to generated code. AI output tends to look more finished than it is. The variable names are good, the structure is clean, the comments are confident. That polish is exactly what makes it easy to under-review.&lt;/p&gt;

&lt;p&gt;This is the checklist I actually run through, not the one I aspire to run through. Eight categories, each with a quick explanation of why it matters and a small example of the kind of thing that slips past a fast skim.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Correctness: does it do what was asked, not just something plausible
&lt;/h2&gt;

&lt;p&gt;AI models are very good at producing code that satisfies the letter of a prompt while missing the actual intent. If you ask for "a function that returns the most recent order for a user," you need to check what "most recent" means in the data. Sorted by creation date? Updated date? What if there are two orders with the same timestamp?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_most_recent_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works until two orders share a timestamp, and then the result is whichever one Python's sort happens to place last, which is not "most recent" in any meaningful sense. It's arbitrary. Nobody asked for arbitrary.&lt;/p&gt;

&lt;p&gt;Why it matters: correctness bugs from AI output are rarely syntax errors, they're semantic gaps between what was asked and what got built. You have to read the code against the requirement, not just against itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Edge cases: the inputs nobody put in the prompt
&lt;/h2&gt;

&lt;p&gt;If your prompt didn't mention empty lists, null values, negative numbers, or duplicate entries, the model probably didn't think about them either. It optimizes for the happy path described in the request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculateAverage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pass an empty array and you get &lt;code&gt;NaN&lt;/code&gt; silently propagating into whatever calls this next. No error, no crash, just a quietly wrong number working its way downstream.&lt;/p&gt;

&lt;p&gt;Why it matters: edge cases are where AI-generated code fails most often, because the model is pattern-matching against the common case in its training data, not reasoning about your specific data guarantees.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Security: don't assume the model thought about it unless you told it to
&lt;/h2&gt;

&lt;p&gt;If you didn't explicitly ask for input sanitization, parameterized queries, or auth checks, don't assume they're there. They often aren't, because the prompt didn't ask for them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM users WHERE email = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;
&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is straightforward SQL injection, and it's also one of the most common patterns I see generated when someone asks for "a function that looks up a user by email" without mentioning security at all.&lt;/p&gt;

&lt;p&gt;Why it matters: generated code defaults to the simplest version of a solution, and the simplest version is very often the insecure version. Treat every generated data access or input-handling function as unreviewed for security until you've explicitly checked it.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Performance: check the complexity, not just the output
&lt;/h2&gt;

&lt;p&gt;Generated code frequently reaches for the most obvious algorithm rather than the most efficient one, especially for anything involving lookups or nested iteration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_duplicates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;duplicates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;duplicates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;duplicates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;duplicates&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is O(n²) for a problem that's a few lines away from O(n) with a set or a counter. It'll pass every test on a small list and quietly become a bottleneck the moment someone runs it against production-sized data.&lt;/p&gt;

&lt;p&gt;Why it matters: small inputs during testing hide complexity problems that only show up at scale, and AI output doesn't come with a complexity analysis attached. You have to do that part yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Maintainability: will the next person understand this without you
&lt;/h2&gt;

&lt;p&gt;Generated code is often correct in isolation but disconnected from the conventions of the rest of your codebase. Different error handling style, different naming pattern, a slightly different way of structuring similar logic that already exists three files over.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# existing pattern in the codebase
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserNotFoundError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="c1"&gt;# what got generated for a new function
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;  &lt;span class="c1"&gt;# inconsistent with the rest of the codebase's error pattern
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why it matters: consistency is a maintainability feature. Code that solves the problem correctly but ignores established patterns adds friction for every future reader, even if it never causes a bug.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Tests: check what's actually being asserted, not just that tests exist
&lt;/h2&gt;

&lt;p&gt;Generated tests can create a false sense of safety. It's common to get tests that run without error but don't assert anything meaningful.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_process_payment&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;process_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This test passes whether the payment succeeded, failed silently, or returned an empty error object. It confirms the function returned something, not that it did the right thing.&lt;/p&gt;

&lt;p&gt;Why it matters: a test suite with weak assertions is worse than no test suite in some ways, because it creates confidence that isn't backed by actual verification. Read the assertions, not just the test count.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Dependencies: verify the package actually exists and does what's claimed
&lt;/h2&gt;

&lt;p&gt;Models occasionally reference packages, methods, or APIs that don't exist, or that existed in an older version and have since changed. This is less common than it used to be but still worth a direct check, especially for less mainstream libraries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;iteritems&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# removed in pandas 2.0, replaced by df.items()
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Code like this can look completely reasonable to someone who hasn't kept up with a specific library's recent changes, and it'll fail immediately in CI or, worse, only in a slightly older pinned environment.&lt;/p&gt;

&lt;p&gt;Why it matters: a broken import or a deprecated method is an easy fix once caught, but it's an annoying one to debug blind if it ships and fails somewhere downstream instead of at review time.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Production behavior: what happens when a dependency it relies on goes down
&lt;/h2&gt;

&lt;p&gt;This is the category that's easiest to skip because it doesn't show up in normal testing at all. Does the code handle timeouts? Partial failures? What does logging look like when something goes wrong at 3am and someone's trying to debug it without you in the room?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_notification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NOTIFICATION_API_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No timeout, no retry, no handling of a non-200 response, and no logging if it fails. When the notification service has a bad five minutes, this function will hang or throw an unhandled exception with zero context about what actually happened.&lt;/p&gt;

&lt;p&gt;Why it matters: this is the category of bug that doesn't show up until it's already in production, because local development rarely simulates a flaky dependency. It's worth explicitly asking "what does this look like when the thing it depends on is unavailable" for anything that talks to an external service.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern across all eight
&lt;/h2&gt;

&lt;p&gt;Every one of these examples looks fine at a glance. That's not a coincidence, it's the actual challenge with reviewing generated code. The syntax is clean, the naming is sensible, the code reads as intentional. The gaps aren't in how the code looks, they're in what it doesn't account for, and you only catch that by asking specific questions of it rather than scanning for things that look wrong.&lt;/p&gt;

&lt;p&gt;Save this, print it, stick it next to your monitor, whatever works. The categories don't change much project to project, only the specifics do.&lt;/p&gt;

&lt;p&gt;What would you add to this list? Curious what's bitten people that isn't covered here.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>coding</category>
      <category>productivity</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Before You Merge AI-Generated Code, Ask These 12 Questions</title>
      <dc:creator>Codzee.io</dc:creator>
      <pubDate>Fri, 14 Aug 2026 12:21:07 +0000</pubDate>
      <link>https://dev.to/codzee_io/before-you-merge-ai-generated-code-ask-these-12-questions-14p3</link>
      <guid>https://dev.to/codzee_io/before-you-merge-ai-generated-code-ask-these-12-questions-14p3</guid>
      <description>&lt;p&gt;I've merged plenty of AI-generated code that was genuinely fine. I've also caught myself almost merging code that looked fine and wasn't, because it read like something a competent person wrote and my brain filled in the rest.&lt;/p&gt;

&lt;p&gt;Over the last year I've settled into a rough set of questions I run through before approving anything I didn't write line by line myself, generated or not. Here they are, in the order I actually ask them.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. What problem is this code actually solving?
&lt;/h2&gt;

&lt;p&gt;It's easy to review whether code works and skip whether it solves the right thing. AI tends to answer the literal prompt, not the intent behind it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_active_users&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM users WHERE active = true&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If "active" was supposed to mean "logged in within 30 days" and not a boolean flag that's rarely updated, this passes every test and still solves the wrong problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reviewer tip:&lt;/strong&gt; Read the original ticket or request before reading the diff. Check the code against the intent, not just the literal ask.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Do I actually understand the implementation?
&lt;/h2&gt;

&lt;p&gt;Not "does it look reasonable," actually understand it, line by line, well enough to explain it to someone else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reviewer tip:&lt;/strong&gt; Try to explain the function out loud in one sentence per major step. If you get stuck anywhere, that's the part you haven't actually reviewed yet, just skimmed.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. What assumptions is it making?
&lt;/h2&gt;

&lt;p&gt;Every implementation bakes in assumptions about the shape of the data, the order things happen in, or what "normal" looks like.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getLatestOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This assumes &lt;code&gt;orders&lt;/code&gt; is sorted chronologically and never empty. Neither assumption is stated anywhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reviewer tip:&lt;/strong&gt; Ask "what does this assume about its inputs that isn't checked anywhere?" Write the answer down, literally, in the PR comment if it matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. What happens with bad input?
&lt;/h2&gt;

&lt;p&gt;Bad input isn't an edge case, it's a certainty over a long enough timeline.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parse_age&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pass it &lt;code&gt;"25"&lt;/code&gt; and it works. Pass it &lt;code&gt;"twenty-five"&lt;/code&gt;, &lt;code&gt;None&lt;/code&gt;, or &lt;code&gt;-5&lt;/code&gt; and you get a crash or a nonsensical value with no complaint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reviewer tip:&lt;/strong&gt; Pick three inputs that would never appear in a demo but could plausibly appear in production: empty, wrong type, absurdly large. Trace through what actually happens.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. What happens when an external service fails?
&lt;/h2&gt;

&lt;p&gt;Generated code frequently assumes the network, database, or third-party API always responds successfully.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getExchangeRate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://api.example.com/rates/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No timeout, no handling for a non-200 response, no fallback. If that API is slow or down, this fails in whatever way &lt;code&gt;fetch&lt;/code&gt; and &lt;code&gt;.json()&lt;/code&gt; happen to fail, which may not be a clear error at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reviewer tip:&lt;/strong&gt; For every external call, ask "what does the caller see if this times out or returns an error status?" If the answer is "an unhandled exception," that's worth a comment.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Are permissions actually enforced, not just checked?
&lt;/h2&gt;

&lt;p&gt;There's a difference between "there's an auth check" and "it's the right auth check."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unauthorized&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This confirms someone is logged in. It never confirms they own or have access to &lt;em&gt;this&lt;/em&gt; document.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reviewer tip:&lt;/strong&gt; For any endpoint touching a specific resource, ask "does this check the resource belongs to the requester, or just that the requester is logged in?"&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Is sensitive data exposed anywhere?
&lt;/h2&gt;

&lt;p&gt;Look at what actually goes into logs, error responses, and API payloads, not just what the happy path returns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fine in local development. In production this can leak file paths, query fragments, or internal structure to whoever triggers the error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reviewer tip:&lt;/strong&gt; Grep the diff for &lt;code&gt;console.log&lt;/code&gt;, &lt;code&gt;print&lt;/code&gt;, and catch blocks. Check what they actually expose.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Is this more complex than the problem needs?
&lt;/h2&gt;

&lt;p&gt;Generated code sometimes over-engineers a simple problem with extra configuration, unnecessary abstraction layers, or generic solutions to specific problems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reviewer tip:&lt;/strong&gt; Ask "could this be half the length and still be correct?" If yes, that's worth pushing back on, complexity has an ongoing cost even when it's not technically wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Are the tests actually meaningful?
&lt;/h2&gt;

&lt;p&gt;Generated tests often confirm the code does what it does, not that it does what it should.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_apply_discount&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;apply_discount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This confirms the arithmetic. It says nothing about a discount over 100%, a negative price, or invalid input.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reviewer tip:&lt;/strong&gt; For each test, ask "what wrong implementation would still pass this?" If you can think of one easily, the test isn't pinning down enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Does it fit existing conventions?
&lt;/h2&gt;

&lt;p&gt;Locally correct code can still be a long-term problem if it introduces a new pattern the codebase doesn't already use, a different error-handling style, a new HTTP client, a different logging approach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reviewer tip:&lt;/strong&gt; Before approving, check one comparable file elsewhere in the codebase. If the patterns don't match, ask whether that's intentional.&lt;/p&gt;

&lt;h2&gt;
  
  
  11. What happens under unusual load or concurrency?
&lt;/h2&gt;

&lt;p&gt;Code that's correct for one request at a time can break under concurrent access, especially anything involving shared state or caching.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fine single-threaded. Under concurrent requests this can lose increments, since read-then-write isn't atomic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reviewer tip:&lt;/strong&gt; For anything touching shared state, ask "what happens if this runs twice at the exact same moment?"&lt;/p&gt;

&lt;h2&gt;
  
  
  12. Will the next developer understand this without me?
&lt;/h2&gt;

&lt;p&gt;The final check. If someone opens this file in eight months with zero memory of this PR, can they figure out what it does and why from the code and comments alone?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reviewer tip:&lt;/strong&gt; Read the diff as a stranger would, not as someone who already knows what it's supposed to do. If it doesn't hold up, add a comment now while the reasoning is still fresh.&lt;/p&gt;

&lt;h2&gt;
  
  
  Copy-paste checklist for your PR template
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## AI-Generated Code Review Checklist&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; [ ] Solves the actual requirement, not just a literal reading of it
&lt;span class="p"&gt;-&lt;/span&gt; [ ] I understand every part of this well enough to explain it
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Assumptions are identified and actually hold true
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Handles empty, invalid, and unexpected input
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Handles external service failures and timeouts
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Permissions checked against the specific resource, not just login state
&lt;span class="p"&gt;-&lt;/span&gt; [ ] No sensitive data leaked via logs, errors, or responses
&lt;span class="p"&gt;-&lt;/span&gt; [ ] No unnecessary complexity for the problem size
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Tests check behavior, not just current output
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Matches existing codebase conventions
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Considered behavior under concurrent access or load
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Understandable to a developer with no context on this PR
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;None of this is exotic review practice. It's the same discipline good engineers apply to any code they didn't personally trace through, generated or not. The only thing that's changed is how often that situation comes up, and how easy it is to skip these questions when the first draft already looks like someone competent wrote it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
    </item>
  </channel>
</rss>
