<?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>Forem: Ryan DesJardins</title>
    <description>The latest articles on Forem by Ryan DesJardins (@radpdx).</description>
    <link>https://forem.com/radpdx</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3864265%2Fe75b318c-3d2c-40b4-bed1-e1324b48c264.jpg</url>
      <title>Forem: Ryan DesJardins</title>
      <link>https://forem.com/radpdx</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/radpdx"/>
    <language>en</language>
    <item>
      <title>Blame-aware code review — why your AI reviewer should only flag what you changed</title>
      <dc:creator>Ryan DesJardins</dc:creator>
      <pubDate>Sat, 11 Apr 2026 19:24:58 +0000</pubDate>
      <link>https://forem.com/radpdx/blame-aware-code-review-why-your-ai-reviewer-should-only-flag-what-you-changed-54he</link>
      <guid>https://forem.com/radpdx/blame-aware-code-review-why-your-ai-reviewer-should-only-flag-what-you-changed-54he</guid>
      <description>&lt;p&gt;Here's a problem that sounds minor but adds up fast: you open a pull request, run an AI code reviewer, and get 40 findings. Twelve of them are in files you touched. The other 28 are in code that was there before you arrived.&lt;/p&gt;

&lt;p&gt;Now you have a decision to make about 28 issues that aren't your fault,&lt;br&gt;
weren't introduced by your change, and probably can't be fixed in this PR&lt;br&gt;
without scope creep. You either ignore them (and train yourself to ignore&lt;br&gt;
the reviewer), fix them (and bloat the PR), or spend time triaging which are real and which aren't.&lt;/p&gt;

&lt;p&gt;This is the blame-aware scoping problem. Here's why it matters more for&lt;br&gt;
AI-assisted development versus traditional development — and how to think about solving it.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why this is worse with AI-generated code
&lt;/h2&gt;

&lt;p&gt;In traditional development, a code reviewer skimming a 200-line diff can&lt;br&gt;
mentally filter pre-existing issues. "That function was already there, not&lt;br&gt;
my problem right now." The human reviewer applies an implicit blame context.&lt;/p&gt;

&lt;p&gt;AI reviewers don't do this by default. They scan whatever they're given and report everything. If you ask an AI to "review this file," it reviews the whole file — including the 300 lines your change didn't touch.&lt;/p&gt;

&lt;p&gt;AI-assisted development makes this worse in a second way: you're often&lt;br&gt;
making changes to existing files. You add a function, refactor a hook, fix&lt;br&gt;
a bug in a route handler. The AI that helped you write the change didn't&lt;br&gt;
introduce the issues in the surrounding code, but a naive reviewer will flag them anyway.&lt;/p&gt;

&lt;p&gt;The result: reviewer fatigue, noisy reports, and a tendency to stop taking findings seriously.&lt;/p&gt;


&lt;h2&gt;
  
  
  What blame-aware scoping actually means
&lt;/h2&gt;

&lt;p&gt;The concept comes from &lt;code&gt;git blame&lt;/code&gt; — the ability to attribute every line of code to the commit that last modified it.&lt;/p&gt;

&lt;p&gt;Blame-aware code review means:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scope to the diff&lt;/strong&gt; — only look at lines that changed in this PR or commit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apply blame context&lt;/strong&gt; — for each changed line, know who introduced it and when&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extend to dependency chains&lt;/strong&gt; — if you changed a function, flag issues in
functions it calls that your change might affect, but not unrelated code&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Step 3 is the nuanced part. Purely diff-scoped review misses cases where&lt;br&gt;
your change interacts with pre-existing problems. If you call an existing&lt;br&gt;
function that has a security issue, and your new code passes untrusted data to it, that's your problem, even though you didn't write the vulnerable function.&lt;/p&gt;

&lt;p&gt;A good blame-aware reviewer distinguishes between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Issues in lines you wrote (always flag)&lt;/li&gt;
&lt;li&gt;Issues in lines your change depends on (flag with context)&lt;/li&gt;
&lt;li&gt;Issues in lines your change didn't touch and doesn't interact with (skip)&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  The incremental review case
&lt;/h2&gt;

&lt;p&gt;There's a related problem: reviewing work that spans multiple commits.&lt;/p&gt;

&lt;p&gt;Say you've been working on a feature for three days across eight commits.&lt;br&gt;
You want a review of the whole feature before merging — but not a review of the entire codebase.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git diff main...HEAD&lt;/code&gt; gives you the cumulative diff. A blame-aware reviewer&lt;br&gt;
can scope to that diff and treat it as a coherent unit, flagging issues&lt;br&gt;
introduced anywhere in the feature branch without surfacing pre-existing&lt;br&gt;
issues from main.&lt;/p&gt;

&lt;p&gt;This is the &lt;code&gt;--since&lt;/code&gt; flag pattern: review everything since a specific commit or branch point, not the entire repo, and not just the last commit.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why this matters specifically for AI slop detection
&lt;/h2&gt;

&lt;p&gt;AI code review has a specific job that general code review doesn't: catching the patterns that AI code generators introduce. Hallucinated imports, fake error handling, missing auth checks, hardcoded ARIA states.&lt;/p&gt;

&lt;p&gt;These patterns are meaningfully more likely to appear in recently written&lt;br&gt;
code than in code that's been in production for six months. A diff-scoped reviewer that focuses on new code will find AI slop at a much higher&lt;br&gt;
signal-to-noise ratio than a full-repo scan.&lt;/p&gt;

&lt;p&gt;If you're doing full-repo scans looking for AI slop, you're spending most&lt;br&gt;
of your time on code that wasn't AI-generated in the first place.&lt;/p&gt;


&lt;h2&gt;
  
  
  Practical implementation
&lt;/h2&gt;

&lt;p&gt;Whether you're building this into an automated reviewer or doing manual review, the workflow looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Get the diff you actually want to review&lt;/span&gt;
git diff HEAD~1          &lt;span class="c"&gt;# last commit only&lt;/span&gt;
git diff main...HEAD     &lt;span class="c"&gt;# entire feature branch&lt;/span&gt;
git diff abc123..HEAD    &lt;span class="c"&gt;# since a specific commit&lt;/span&gt;

&lt;span class="c"&gt;# For each changed file, get blame context&lt;/span&gt;
git blame &lt;span class="nt"&gt;-L&lt;/span&gt; &amp;lt;start&amp;gt;,&amp;lt;end&amp;gt; &amp;lt;file&amp;gt;  &lt;span class="c"&gt;# blame specific line range&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key discipline: &lt;strong&gt;start with the diff, not the file.&lt;/strong&gt; If your reviewer takes a file as input, it will review the whole file. If it takes a diff as input, it's forced to scope correctly.&lt;/p&gt;

&lt;p&gt;For automated review, you want the reviewer to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Parse the diff to get changed line ranges per file&lt;/li&gt;
&lt;li&gt;Review only those ranges (plus direct dependencies)&lt;/li&gt;
&lt;li&gt;Explicitly ignore unchanged lines in changed files&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Step 3 is where most implementations fall short. Changed files still contain a lot of unchanged code, and reviewers who scan the full file content will surface issues from the unchanged portions.&lt;/p&gt;




&lt;h2&gt;
  
  
  The severity calibration problem
&lt;/h2&gt;

&lt;p&gt;Even with correct blame scoping, there's a secondary issue: severity&lt;br&gt;
calibration changes based on context.&lt;/p&gt;

&lt;p&gt;A hardcoded credential in a utility function that was last touched two years ago is a serious issue, regardless of blame — but it's not your PR's&lt;br&gt;
responsibility to fix right now. A hardcoded credential in a line you just&lt;br&gt;
wrote is a blocker.&lt;/p&gt;

&lt;p&gt;Good blame-aware review separates findings into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Your responsibility&lt;/strong&gt; — in lines you wrote or that you directly depend on&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inherited issues&lt;/strong&gt; — pre-existing, should be tracked but not blocking your PR&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incidental findings&lt;/strong&gt; — unrelated, out of scope entirely&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Surfacing all three without distinguishing them trains reviewers to ignore&lt;br&gt;
everything.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I built around this
&lt;/h2&gt;

&lt;p&gt;I implemented blame-aware scoping in a Claude Code plugin&lt;br&gt;
(&lt;a href="https://github.com/radesjardins/RAD-Claude-Skills" rel="noopener noreferrer"&gt;rad-code-review&lt;/a&gt;) after getting frustrated with full-repo reviews that were too noisy to act on.&lt;/p&gt;

&lt;p&gt;The default mode is diff-scoped with dependency chain detection. You can&lt;br&gt;
override to full-scan when you actually want that (&lt;code&gt;--full-scan&lt;/code&gt;), run&lt;br&gt;
incremental reviews with &lt;code&gt;--since &amp;lt;commit&amp;gt;&lt;/code&gt;, and set strictness level for&lt;br&gt;
pre-release audits.&lt;/p&gt;

&lt;p&gt;The signal-to-noise improvement from scoping correctly is significant. A&lt;br&gt;
full-repo scan of a mature codebase produces dozens of findings. The same&lt;br&gt;
reviewer scoped to a three-file diff produces three or four — all of which&lt;br&gt;
are things you actually introduced and can actually fix right now.&lt;/p&gt;




&lt;p&gt;The underlying principle: a reviewer who produces too much noise gets&lt;br&gt;
ignored. Blame-aware scoping isn't a nice-to-have — it's what separates a&lt;br&gt;
reviewer you use from one you turn off.&lt;/p&gt;

</description>
      <category>codereview</category>
      <category>ai</category>
      <category>claude</category>
      <category>developer</category>
    </item>
    <item>
      <title>14 patterns AI code generators get wrong — and how to catch them</title>
      <dc:creator>Ryan DesJardins</dc:creator>
      <pubDate>Mon, 06 Apr 2026 19:34:27 +0000</pubDate>
      <link>https://forem.com/radpdx/14-patterns-ai-code-generators-get-wrong-and-how-to-catch-them-45l9</link>
      <guid>https://forem.com/radpdx/14-patterns-ai-code-generators-get-wrong-and-how-to-catch-them-45l9</guid>
      <description>&lt;p&gt;AI coding tools ship code fast. That's the point. But fast means they also&lt;br&gt;
introduce a specific class of bugs that are easy to miss in review — not&lt;br&gt;
because they're hidden, but because they &lt;em&gt;look&lt;/em&gt; correct at a glance.&lt;/p&gt;

&lt;p&gt;After building an automated reviewer specifically for AI-generated code, I've cataloged 14 recurring patterns. Here's what they look like and how to spot them.  Although an automated review agent can be helpful, manually spotting these 14 things can also benefit your work when using coding agents.&lt;/p&gt;


&lt;h2&gt;
  
  
  The core problem
&lt;/h2&gt;

&lt;p&gt;AI code generators optimize for producing code that looks complete and&lt;br&gt;
compiles. They're not optimizing for runtime correctness, security, or the&lt;br&gt;
subtle behavioral contracts your codebase depends on. The patterns below&lt;br&gt;
all share the same root: plausible-looking code that silently fails, skips&lt;br&gt;
important work, or creates vulnerabilities that generic linters don't catch.&lt;/p&gt;


&lt;h2&gt;
  
  
  1. Fake error handling
&lt;/h2&gt;

&lt;p&gt;The most common one. The try/catch exists, the error variable is named, and absolutely nothing useful happens with it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Looks handled. Isn't.&lt;/span&gt;
&lt;span class="k"&gt;try&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;processPayment&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Payment failed:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&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;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// ← the real problem&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tell: the catch block logs but doesn't change the outcome. The function returns success regardless. This pattern is everywhere in AI-generated code because the model is completing a "handle errors" pattern without reasoning about what handling should actually do.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Hallucinated imports
&lt;/h2&gt;

&lt;p&gt;AI models confidently import packages that don't exist, functions that were renamed, or methods from the wrong module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sanitizeHtml&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express-validator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// doesn't exist there&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;parseJWT&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jsonwebtoken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// it's jwt.verify(), not parseJWT&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createLogger&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@company/utils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// your internal package, maybe&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These fail at runtime, not compile time (unless you have strict module checking). They're easy to miss in review because the import looks reasonable.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Placeholder stubs that look complete
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;sendNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// TODO: integrate with notification service&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Notification queued for &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&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="nx"&gt;message&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;queued&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;The function signature is real. It returns a typed response. It logs&lt;br&gt;
something. It will pass a basic smoke test. The actual work is never done.&lt;br&gt;
AI generators do this when they're implementing something they don't have&lt;br&gt;
enough context to complete — they produce scaffolding that looks finished.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Silent async failures
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// somewhere in initialization&lt;/span&gt;
&lt;span class="nf"&gt;loadUserPreferences&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// no await, no .catch()&lt;/span&gt;

&lt;span class="c1"&gt;// result: preferences silently fail to load, app continues with defaults,&lt;/span&gt;
&lt;span class="c1"&gt;// user wonders why their settings aren't saving&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unhandled promise rejections are a top-tier AI slop pattern. The model adds the function call, forgets the await, and the error disappears into the void.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. An optimistic state that never rolls back
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Update UI immediately&lt;/span&gt;
&lt;span class="nf"&gt;setCartItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newItem&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// Then try the server&lt;/span&gt;
&lt;span class="k"&gt;try&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;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addToCart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newItem&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ← nothing here&lt;/span&gt;
  &lt;span class="c1"&gt;// cart shows item that wasn't actually saved&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AI models learn to write optimistic updates from examples that include&lt;br&gt;
rollback logic — but they frequently omit the rollback when generating new&lt;br&gt;
code.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Missing auth checks in route handlers
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;PUT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&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="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&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;body&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;request&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="c1"&gt;// ← where is the auth check?&lt;/span&gt;
  &lt;span class="c1"&gt;// ← where is the ownership check?&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="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;posts&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="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;posts&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;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="k"&gt;return&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="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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 is IDOR (Insecure Direct Object Reference) — any authenticated user can update any post. AI models write the happy path correctly but skip the&lt;br&gt;
authorization layer because it requires knowledge of your specific auth&lt;br&gt;
system that isn't in the immediate context.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Hardcoded ARIA states
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This button controls a dropdown&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;aria-expanded&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="na"&gt;aria-controls&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"menu"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  Options
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ARIA attribute is there. The accessibility auditor won't flag it as&lt;br&gt;
missing. But &lt;code&gt;aria-expanded&lt;/code&gt; is hardcoded to &lt;code&gt;false&lt;/code&gt; and never updates when the menu opens. Screen reader users get incorrect state information on every interaction.&lt;/p&gt;

&lt;p&gt;AI models add ARIA attributes to pass static analysis without connecting&lt;br&gt;
them to the component state.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Array index as React key
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ListItem&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;  &lt;span class="c1"&gt;// ← classic&lt;/span&gt;
&lt;span class="p"&gt;))}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everyone knows this one, and AI still generates it constantly. It causes&lt;br&gt;
subtle reconciliation bugs when items are reordered or deleted. The fix&lt;br&gt;
(&lt;code&gt;key={item.id}&lt;/code&gt;) requires knowing your data shape, which the model doesn't always have.&lt;/p&gt;




&lt;h2&gt;
  
  
  9. TypeScript escape hatches
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// trusts external data unconditionally&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.target&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// assumes&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// the double cast — worse&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Type assertions instead of type guards. The code compiles, and TypeScript&lt;br&gt;
stops complaining, but the runtime behavior is undefined if the assumption&lt;br&gt;
is wrong. AI models reach for &lt;code&gt;as&lt;/code&gt; when the type system resists them, rather than fixing the underlying issue.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. useEffect with no cleanup
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&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;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;eventEmitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handleEvent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// ← no return () =&amp;gt; subscription.unsubscribe()&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;Memory leaks and stale closure bugs. The model writes the setup, skips the&lt;br&gt;
teardown. Shows up in event listeners, subscriptions, timers, and WebSocket connections.&lt;/p&gt;




&lt;h2&gt;
  
  
  11. N+1 query patterns
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&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="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;usersTable&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// for each user, a separate query — scales as O(n)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usersWithPosts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&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="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
    &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;postsTable&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;postsTable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&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;id&lt;/span&gt;&lt;span class="p"&gt;))&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 works correctly in development with a handful of records. In production with thousands of users it's a significant performance problem. AI generates the naive version because it's the direct translation of the requirement.&lt;/p&gt;




&lt;h2&gt;
  
  
  12. Unbounded list rendering
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserList&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;span class="nl"&gt;users&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="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="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserItem&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&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 pagination, no virtualization, no limit. Renders fine with test data.&lt;br&gt;
Blocks the main thread with 10,000 records. AI models generate the complete render because truncating the list requires product decisions they don't have context for.&lt;/p&gt;




&lt;h2&gt;
  
  
  13. Missing loading and error states
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Dashboard&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="p"&gt;[&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;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&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="nf"&gt;fetchDashboardData&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DashboardContent&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// null crash on first render&lt;/span&gt;
  &lt;span class="c1"&gt;// no loading state, no error state, no empty state&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The happy path is complete. The other three states (loading, error, empty)&lt;br&gt;
are absent. This pattern comes up because the model implements what was&lt;br&gt;
asked for without considering the temporal states of the component.&lt;/p&gt;




&lt;h2&gt;
  
  
  14. Over-broad catch with specific handling
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&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;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paymentIntents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;card_declined&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="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Your card was declined&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="c1"&gt;// ← every other error silently returns undefined&lt;/span&gt;
  &lt;span class="c1"&gt;// network errors, auth errors, rate limits — all disappear&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Handles one specific case, drops everything else. The model generates the&lt;br&gt;
case it was asked to handle and stops.&lt;/p&gt;




&lt;h2&gt;
  
  
  The pattern behind the patterns
&lt;/h2&gt;

&lt;p&gt;All 14 of these share the same root cause: &lt;strong&gt;AI models generate code that&lt;br&gt;
satisfies the immediate requirement without reasoning about failure modes,&lt;br&gt;
state transitions, or the implicit contracts of the surrounding system.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The fix isn't to stop using AI code generation — it's to review specifically for these patterns rather than doing a general read-through. They're consistent enough that you can check for them systematically.&lt;/p&gt;

&lt;p&gt;I automated this check in a Claude Code plugin&lt;br&gt;
(&lt;a href="https://github.com/radesjardins/RAD-Claude-Skills" rel="noopener noreferrer"&gt;rad-code-review&lt;/a&gt;) that specifically looks for these patterns in diffs before you commit. But even without automation, knowing the list makes manual review significantly faster.&lt;/p&gt;




&lt;p&gt;Any patterns I missed? Drop them in the comments — I'm still actively&lt;br&gt;
updating the detection logic.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>beginners</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
