<?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: Brandin Canfield</title>
    <description>The latest articles on DEV Community by Brandin Canfield (@brandincanfield).</description>
    <link>https://dev.to/brandincanfield</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%2F1115281%2F2e52a6fb-b96f-4f53-9df7-99a62586d052.jpeg</url>
      <title>DEV Community: Brandin Canfield</title>
      <link>https://dev.to/brandincanfield</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/brandincanfield"/>
    <language>en</language>
    <item>
      <title>The EU's AI Audit-Trail Law Takes Effect in Three Weeks. It Skips Your Coding Agent.</title>
      <dc:creator>Brandin Canfield</dc:creator>
      <pubDate>Tue, 14 Jul 2026 13:42:16 +0000</pubDate>
      <link>https://dev.to/brandincanfield/the-eus-ai-audit-trail-law-takes-effect-in-three-weeks-it-skips-your-coding-agent-5616</link>
      <guid>https://dev.to/brandincanfield/the-eus-ai-audit-trail-law-takes-effect-in-three-weeks-it-skips-your-coding-agent-5616</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Full research and the plugin →&lt;/strong&gt; &lt;a href="https://github.com/bcanfield/agentic-tech-debt" rel="noopener noreferrer"&gt;github.com/bcanfield/agentic-tech-debt&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On August 2, some AI systems operating in the EU have to start keeping a permanent, queryable record of the decisions they make. Miss it and the fine tops out at 3% of global turnover. Your coding agent isn't one of the systems covered, and once you look at why not, that turns out to be the more useful fact than the deadline.&lt;/p&gt;

&lt;p&gt;The EU AI Act's high-risk obligations (Regulation 2024/1689) enter full force that day. Article 12 is the logging requirement: automatic, tamper-evident event records are required for anything classified "high-risk" under Annex III. Annex III lists eight categories: biometrics, critical infrastructure, education, employment decisions, essential services, law enforcement, migration and border control, the justice system. A general-purpose coding assistant doesn't land in any of them unless one is specifically deployed to make, say, hiring decisions. Claude Code, Cursor, Copilot: none of it is in scope.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr8j1og61nu802tq2hf9e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr8j1og61nu802tq2hf9e.png" alt="The EU AI Act's eight Annex III high-risk categories, arranged in a grid: biometrics, critical infrastructure, education, employment, essential services, law enforcement, migration, justice. A ninth box, " width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My first draft of this piece led with "your AI coding agent has three weeks to comply." It's a better headline. It's also wrong, and I only caught it because a fact-check pass sent me to the actual Annex III text instead of the three SEO blogs already running the scarier version with invented statistics bolted on. One cited an "8.1-million-pull-request study" I couldn't find anywhere. Turned out to be GitClear's real 48% duplication figure and CodeRabbit's real 1.7x-more-issues figure, laundered through a site that sells AI-app rescue services and has every incentive to make the sky look like it's falling.&lt;/p&gt;

&lt;p&gt;So: no compliance story here, at least not yet. But sit with why the EU decided any AI needed a mandatory paper trail in the first place. It isn't that biometric identification or employment screening feel more futuristic than autocomplete. It's that those systems make consequential calls fast, with a person rubber-stamping output they didn't fully derive, and until now nothing forced them to leave a record anyone could reconstruct after the fact. Article 12 exists because "it seemed right at the time" stopped being an acceptable answer once the decisions got expensive enough. That is, word for word, the argument for logging what a coding agent decides. It's just sitting a few rungs below the threshold a regulator bothered to write down. Amazon CTO Werner Vogels named the coding-agent version of it at his last re:Invent keynote, months before the incidents at his own company made the point for him:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"AI can generate code faster than you can understand it... That gap allows software to move toward production before anyone has truly validated what it actually does."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A coding agent makes dozens of small, unrecorded calls a session, from what I've watched mine do: a default picked because it was fastest, a type loosened to get the build green, a check skipped to hit a deadline. None of it requires a regulator's definition of "high-risk" to matter. Apiiro's audit of Fortune 50 repos found privilege-escalation paths up 322% and architectural design flaws up 153% on AI-assisted code, even as syntax errors fell. Code revised within two weeks of landing, about as close to a real-time debt indicator as the data gets, climbed from 3.1% to 5.7% of all changes in a year, per GitClear. CodeRabbit's read of 470 real pull requests found the AI-touched ones carrying 1.7x more issues than the human-only ones. None of that is a hack or a breach, just the ordinary residue of decisions nobody wrote down.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe9zg27q3r4a81locfabr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe9zg27q3r4a81locfabr.png" alt="A satisfied harbor seal, in the " width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The New Stack ran a piece less than two weeks ago with a line I keep turning over: "Vibe slop is the symptom. Context debt is the disease." Bad-looking AI output is the thing you can see and complain about. The actual damage is upstream of it: the accumulating pile of unrecorded decisions and shortcuts that neither the agent nor the next engineer can fully reconstruct once the session ends. Slop gets caught in review. Context debt doesn't, because nothing in the diff flags it as a decision at all.&lt;/p&gt;

&lt;p&gt;I'd stop short of arguing every one of those small calls deserves its own log line. That's a real risk on the other side of this. A registry entry for literally everything an agent decides is its own kind of debt: a compliance ritual nobody reads, the software equivalent of a cookie banner nobody's ever actually declined a cookie because of. Fowler's debt quadrants exist for exactly this filter. The deliberate-prudent corner, the shortcut you'd defend out loud, is worth a line. The rest is noise, and pretending otherwise buries the entries that matter under the ones that don't.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbc70yx7ja3bdh2nw32o3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbc70yx7ja3bdh2nw32o3.png" alt="A snippet from this repo's own debt registry: the entry docs/debt/20260626124215-articles-fail-visual-density-gate.md, filed by this same article pipeline against its own image gate, with fields for quadrant, payoff trigger, and hotspot filled in." width="800" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's what that filter looks like when it's not hypothetical. This repo's own debt registry has an entry, &lt;code&gt;20260626124215-articles-fail-visual-density-gate.md&lt;/code&gt;, filed the day the article pipeline's own visual rules changed and every article written before that point stopped clearing its own gate. Quadrant: prudent-deliberate. Payoff trigger: before republishing anything old. It's a plain sentence, written by the same automation that produces these posts, explaining a shortcut it took and the condition under which someone has to come back and fix it. Twenty-two ADRs and a folder of entries like that one are the closest thing this project has to an Article 12 log, and nobody made anyone write it. You're not going to be fined for what your coding agent doesn't record either, not on August 2 and probably not for a while after. That's sort of the point. The audit-trail requirement was only written down after the EU decided certain failures were too expensive to keep happening invisibly. The rest of us still get to make that call ourselves, for our own repos, before a regulator or a Sev-1 makes it for us. I built &lt;a href="https://github.com/bcanfield/agentic-tech-debt" rel="noopener noreferrer"&gt;debt-ops&lt;/a&gt; as the smallest version of that call I could ship: an agent hits a "why this way?" moment, it writes one line to a registry before it moves on, the same instinct Article 12 runs on, just applied a few rungs down and without a regulator making anyone do it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cover photo by Magic Fan on Unsplash.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>technicaldebt</category>
      <category>compliance</category>
      <category>codequality</category>
    </item>
    <item>
      <title>Amazon Says No AI Wrote the Code That Broke Prod</title>
      <dc:creator>Brandin Canfield</dc:creator>
      <pubDate>Wed, 08 Jul 2026 14:16:04 +0000</pubDate>
      <link>https://dev.to/brandincanfield/amazon-says-no-ai-wrote-the-code-that-broke-prod-3ndi</link>
      <guid>https://dev.to/brandincanfield/amazon-says-no-ai-wrote-the-code-that-broke-prod-3ndi</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Full research and the plugin →&lt;/strong&gt; &lt;a href="https://github.com/bcanfield/agentic-tech-debt" rel="noopener noreferrer"&gt;github.com/bcanfield/agentic-tech-debt&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Amazon's official account of a bad winter is that no AI wrote the code that took production down. I believe them, mostly. I also think the honest version of this is worse than the one they keep denying, and it takes a minute to explain why.&lt;/p&gt;

&lt;p&gt;Start with the cluster, because that part holds up even where the cause doesn't. In mid-December 2025, the Financial Times reported (Feb 20, from four people familiar) that Amazon's own coding agent, Kiro, "decided to delete and recreate the environment" and knocked AWS Cost Explorer offline in one of Amazon's two China regions for about thirteen hours. One AWS employee called the outages "small but entirely foreseeable." On March 2, an incident tied to Amazon Q sent out wrong delivery estimates and cost something like 120,000 orders and 1.6 million site errors. Three days later a six-hour outage dropped North American orders by 99%, an estimated 6.3 million of them, though that number comes from Business Insider by way of internal documents and isn't one Amazon has confirmed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs0aws4w8jydikrw5zf14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs0aws4w8jydikrw5zf14.png" alt="A timeline of Amazon's winter 2025 to 2026 incident cluster. Four dated markers: mid-December 2025, the Kiro agent deletes and recreates an environment, a thirteen-hour Cost Explorer outage in a China region (Financial Times, four people familiar); March 2, an Amazon Q-linked incident causes wrong delivery estimates, about 120,000 lost orders and 1.6 million site errors; March 5, a six-hour North America outage, a 99 percent order drop, an estimated 6.3 million lost orders, marked as a Business Insider estimate Amazon disputes and tied to an unreviewed config change rather than AI; March 10, CNBC reports the internal doc's GenAI bullet point was deleted before the deep-dive meeting." width="800" height="567"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That last outage is where most of the hot takes slid off the road. It had the giant number, so it got pinned on the AI along with everything else. But the careful reporting ties it to a configuration change a human pushed without review, not to any coding tool. Only the March 2 incident has a clean line back to AI. So the distinction everybody skipped is the one Amazon now leans on, and I'll grant it: on the narrow question of who typed the bad change, they're probably right.&lt;/p&gt;

&lt;p&gt;In public, Amazon keeps the account short. The December event was "user error, specifically misconfigured access controls, not AI," and Amazon told Fortune (March 12) that "none of the incidents involved AI-written code." The internal version reads less clean. An SVP named Dave Treadwell sent around a memo that blamed "GenAI tools supplementing or accelerating production change instructions, leading to unsafe practices," and admitted the safeguards for that "haven't been fully established yet."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg2p1qexs34tstw2zzqnx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg2p1qexs34tstw2zzqnx.png" alt="Panik-Kalm-Panik meme. Top panel, panik: " width="600" height="839"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Say they're right on every count. No AI wrote the code that broke. What broke it was that people changed production faster and more confidently than review could keep up with, using tools that made each change cheap to produce and easy to trust. To me that reads less like an exoneration and more like the AI-debt problem in its worse form, the kind that can't be scanned for. A bad line of AI-generated code is at least findable. It sits in a diff, a tool can flag it, a reviewer can catch it, worst case you revert the commit. "We shipped a change nobody really verified" doesn't sit in a file. There's no commit to blame and no pattern to grep for, and a review step that quietly fell behind the pace of change doesn't leave one behind.&lt;/p&gt;

&lt;p&gt;Werner Vogels had already named the thing. At his last AWS re:Invent keynote, weeks before the worst of the cluster and on Amazon's own stage, he called it verification debt. AI writes code faster than anyone can read it, he said, and that gap lets software reach production before someone has actually checked what it does. He described the mechanism about a month before his own company ran the experiment on live traffic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl6foqwipik4xkg8edhrg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl6foqwipik4xkg8edhrg.png" alt="A quote card. Attributed to Werner Vogels, AWS CTO, re:Invent keynote, December 4, 2025. The quote reads: " width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I don't think Amazon is lying about the code. I think the honest account is the one that should worry its engineers more, not less. The 80% weekly AI-usage target it set for them, the two rounds of layoffs (about 14,000 people in October, another 16,000 in January), none of that changes what code gets written so much as how fast it ships and how few people are left to look before it does.&lt;/p&gt;

&lt;p&gt;There's one more detail, from CNBC on March 10. The internal incident document had a bullet point that named "GenAI-assisted changes" as a factor, and somebody deleted it before the deep-dive meeting. That's the part I keep snagging on, more than any single outage. Changes go bad all the time. What bothers me is that the record of why this one went bad got pulled before the people who needed it could read it. That deletion is the thing I've been building against. My plugin, debt-ops, hooks a coding agent so that every time it defers a decision or takes a shortcut, a line lands in a markdown file in the repo, dated, off to the side of the agent's own tidy session summary, where the next person trips over it. It even registers debt against its own codebase. Here's a real entry it wrote, trimmed to the load-bearing fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;title:           fingerprint-regex-not-pos
interest:        false positives/negatives vs true features; counts directional only
payoff_trigger:  a real POS tagger becomes worth the dependency
quadrant:        prudent-deliberate
created:         2026-06-07
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Somebody picked regexes over a proper parser to dodge a dependency, on purpose, for now, and instead of that choice dissolving into a chat log it's a file with a date and the condition that ends it. If you want to try it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/plugin marketplace add bcanfield/agentic-tech-debt
/plugin install debt-ops@agentic-tech-debt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's local-only, stdlib Python, no network calls, MIT. I won't pretend it would have caught Amazon's config change or talked Kiro out of deleting that environment. All it does is keep a paper trail: when a decision gets made in a hurry, a dated line about it shows up in the repo. Someone would have to delete that line on purpose, the way Amazon did with its bullet point, instead of never having written it down at all.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cover photo by Jahanzeb Ahsan on Unsplash.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>technicaldebt</category>
      <category>devops</category>
      <category>codequality</category>
    </item>
    <item>
      <title>The Expensive Part Was Never Writing the Code</title>
      <dc:creator>Brandin Canfield</dc:creator>
      <pubDate>Wed, 08 Jul 2026 11:35:44 +0000</pubDate>
      <link>https://dev.to/brandincanfield/the-expensive-part-was-never-writing-the-code-322m</link>
      <guid>https://dev.to/brandincanfield/the-expensive-part-was-never-writing-the-code-322m</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Full research and the plugin →&lt;/strong&gt; &lt;a href="https://github.com/bcanfield/agentic-tech-debt" rel="noopener noreferrer"&gt;github.com/bcanfield/agentic-tech-debt&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The price of producing a line of code fell to about zero in the last two years. The price of living with that line did not move. Most of the AI-debt argument is people standing on one side of that split or the other without naming it.&lt;/p&gt;

&lt;p&gt;Gauge, a dev-tools consultancy, put the consequence plainly: "AI has significantly increased the real cost of carrying tech debt... the penalty for having a 'high-debt' codebase is now larger than ever." That's stranger than it sounds. AI is supposed to be the thing that &lt;em&gt;helps&lt;/em&gt; you with a messy codebase. Gauge is saying the messy codebase got more expensive to own in the same window the tooling meant to fix it arrived.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3dxtepmtslx169impac0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3dxtepmtslx169impac0.png" alt="Two cost curves on a 2022 to 2026 timeline. The " width="800" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When writing was expensive, that expense was also a throttle. A human typing the code was, by the same motion, the human who'd read every line, held the design in their head, and felt the friction of each shortcut as they took it. Slow production &lt;em&gt;was&lt;/em&gt; the review. You couldn't generate faster than you understood, because the generating and the understanding were the same act. That coupling is what broke. Now the code can exist without anyone going through the act that used to produce understanding for free, so the understanding gets bought separately, after the fact, usually by someone who wasn't in the room.&lt;/p&gt;

&lt;p&gt;The data shows it once you read it as two costs and not as a quality score. GitClear looked at 211 million changed lines and found that during 2024, for the first time they'd ever measured, copy-pasted code beat refactored code: duplicated blocks rose eightfold in that one year, while "moved" lines (someone reorganizing rather than re-pasting) dropped by about 40 percent. Pasting a block is cheap; every copy is a place a future fix has to land again.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvrfa5mv4q3m349lo2ok3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvrfa5mv4q3m349lo2ok3.png" alt="GitClear stat card. From 2020 to 2024, the share of changed lines that were copy-pasted rose from 8.3 to 12.3 percent, while moved or refactored lines fell from 24.1 to 9.5 percent. 2024 was the first year GitClear measured copy-pasted code beating refactored code, and duplicated blocks of five or more lines rose eightfold that year. A note flags it as vendor research and a correlation with AI adoption, not proven causation." width="800" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The study people cite to argue the opposite is the one I find most convincing here. METR ran a randomized trial: sixteen experienced developers on their own repos, with early-2025 models, so don't carry it further than that. They came out 19 percent slower with AI, and didn't notice. They'd predicted a 24 percent speedup going in, and after finishing the tasks, slower, they still believed they'd gone 20 percent faster. The prompting got fast, and prompting is the part you feel, so the work feels fast. What got slower was the reading and the re-prompting and the checking of output you didn't write, and almost nobody counts that as work. I don't, in the moment. I notice the slowness later, when I'm three commits deep trying to remember why the agent did a thing.&lt;/p&gt;

&lt;p&gt;The asymmetry might just be a property of &lt;em&gt;current&lt;/em&gt; models, and the models keep getting better. Veracode clocked GPT-5 Mini at a 72 percent pass rate on their security suite in late 2025, up sharply from the 45 percent that made headlines. If generated code keeps getting more correct, the ownership tax on each line falls, and the asymmetry closes on its own without anyone building anything. That's a real argument, and I don't have a clean rebuttal, only a partial one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fihny430oygmjrezipa9v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fihny430oygmjrezipa9v.png" alt="Drake meme. Top panel, Drake waving it off: " width="600" height="939"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Better models close the wrong half. A more correct model does lower the cost of any &lt;em&gt;single&lt;/em&gt; line you own: fewer bugs per line, fewer findings to chase. But a lot of that cost is per-&lt;em&gt;decision&lt;/em&gt;, not per-line, and a better model makes more decisions, faster, none of them written down, and you check fewer of them because it's earned the benefit of the doubt. Gartner hangs its whole defect forecast on exactly that reflex, "automation bias," developers who "implicitly trust AI suggestions," in its Predicts 2026 report. So the lines get cleaner while the decisions behind them get more numerous and harder to see.&lt;/p&gt;

&lt;p&gt;I maintain a small plugin, and a few weeks ago I had a decision to make about how it's put together. It ships as four self-contained copies, which means every shared script is duplicated four times and a fix has to be applied to all four. The DRY instinct says extract a shared module. I'd even written that plan down earlier; there's an ADR in the repo, 0011, that scheduled the extraction for when a third adapter landed. A third adapter landed. A fourth landed. And the decision I actually made, recorded in ADR 0014, was to &lt;em&gt;reverse&lt;/em&gt; the plan: keep all four copies and sync them by hand, on purpose. The line from that file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Status: Accepted (supersedes ADR 0011's extraction trigger and packaging-plan Phase E)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I chose the higher cost to write (four copies, more lines, more typing) to buy a lower cost to own: each adapter stays a thing one person can read top to bottom, with nothing hidden behind an abstraction. That only worked because the decision got written down where I'd find it. Most of the decisions a coding agent makes for you don't get an ADR. They get a clean line that compiles, and the reasoning behind it is gone by the next session.&lt;/p&gt;

&lt;p&gt;That evaporation is the expensive part, and it's the gap I built &lt;a href="https://github.com/bcanfield/agentic-tech-debt" rel="noopener noreferrer"&gt;debt-ops&lt;/a&gt; to close: it makes an agent record the decisions it defers, so the ownership cost lands somewhere a person can see it instead of accruing in silence.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faplyejeh7w31nz7g7lqb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faplyejeh7w31nz7g7lqb.png" alt="Before-and-after card from the repo's ADR log. ADR 0011 scheduled extracting a shared module once a third adapter landed; ADR 0014 superseded it, keeping four self-contained copies synced by hand to trade a higher cost to write for a lower cost to own. A note adds that most of the decisions a coding agent makes never get an ADR, so their reasoning is gone by the next session." width="799" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;None of this is an argument against generating code with AI. I do it daily; the generation really is nearly free, and that's genuinely good. It's an argument against reading the free generation as a free &lt;em&gt;lunch&lt;/em&gt;. The two costs came apart, and the one that's left is the one nobody put on a curve.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cover photo by mediha ekici on Unsplash.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>technicaldebt</category>
      <category>softwareengineering</category>
      <category>codequality</category>
    </item>
    <item>
      <title>The Year Duplicated Code Rose 8x</title>
      <dc:creator>Brandin Canfield</dc:creator>
      <pubDate>Mon, 06 Jul 2026 18:51:26 +0000</pubDate>
      <link>https://dev.to/brandincanfield/the-year-duplicated-code-rose-8x-43n0</link>
      <guid>https://dev.to/brandincanfield/the-year-duplicated-code-rose-8x-43n0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Full research and the plugin →&lt;/strong&gt; &lt;a href="https://github.com/bcanfield/agentic-tech-debt" rel="noopener noreferrer"&gt;github.com/bcanfield/agentic-tech-debt&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Of the blocks your coding agent pasted into the codebase this week, a larger share are copies of something already in the repo than at any point anyone has measured. That's the most cited number in the AI-code-quality argument, and it comes from GitClear: duplicated code blocks of five or more lines rose eightfold during 2024.&lt;/p&gt;

&lt;p&gt;GitClear builds code-review analytics, so this is their data on their terms, and I'll come back to what that's worth. But the size of it is hard to wave off: 211 million changed lines across 2020 through 2024, from repos that include Google, Microsoft, and Meta. Not a survey of how developers feel, not a benchmark on toy tasks, but the actual line-level diff history of real codebases over five years.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fas6gz9548hkev8g3j7ks.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fas6gz9548hkev8g3j7ks.png" alt="GitClear's dataset at a glance: 211 million changed lines of real line-level diff history from 2020 to 2024, across repos including Google, Microsoft, and Meta, not a developer survey." width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The headline finding is a crossover. Refactoring and cloning both show up in a diff as added-and-removed lines, but they mean opposite things: "moved" lines are existing code reorganized into one place, copy-pasted lines are a second copy you tweak instead. In 2024, for the first year in their data, copy-pasted lines beat moved ones.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fglyw8a7gncril7jjcuw6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fglyw8a7gncril7jjcuw6.png" alt="A before/after of GitClear's three code-change rates, 2020 next to 2024. Copy-pasted lines rise from 8.3 percent to 12.3 percent; moved (refactored) lines fall from 24.1 percent to 9.5 percent; code revised within two weeks climbs from 3.1 percent to 5.7 percent. A marker notes 2024 as the first year copy-paste exceeded moved code." width="800" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now the honest caveat. GitClear sells code-review analytics, so a story where code quality is sliding is good for their business. Read it as vendor research. The timing lines up, but the dataset can't close correlation to cause: AI adoption climbed across exactly these years and so did duplication, and that's all the data establishes.&lt;/p&gt;

&lt;p&gt;What I trust is that mechanism, because I can watch it happen. Refactoring is the expensive option: find the existing code, understand it well enough to know your case fits, pull it into a shared place without breaking the three other callers. Pasting skips all of that and hands you a block that works right now. An agent asked for code that works will reach for whatever produces working code fastest, and that's paste. Nothing about it requires the model to be bad. A perfectly correct paste is still a paste. My own repo complicates that picture, which I think is the actual point. Point a duplicate-block detector at the project I'm writing this series about and it lights up: I ship the plugin as four self-contained copies, one each for Claude Code, Codex, Copilot, and a portable set. The function that finds the git root is defined nineteen times, byte-identical copies synced by hand. It's nineteen and not four because each adapter repeats the helper in every script that needs it. By GitClear's measure that's me producing exactly the duplication the report counts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ grep -rl "def git_toplevel" --include=*.py . | wc -l
19
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Except the duplication is deliberate. An architecture decision record in the repo, ADR 0014, argues for it: installed plugins are isolated directories, the hooks have to be standard-library-only, and a shared module would couple four things meant to stay independent. So I pay a known tax (a fix has to land in all nineteen copies in the same change), and there's a written rule that says so. The duplication GitClear is measuring is the other kind, the kind that shows up in a diff because pasting was the path of least resistance and nobody wrote down that a second copy now exists. Same grep result, opposite situations.&lt;/p&gt;

&lt;p&gt;Which is why churn is the number I'd actually watch, more than duplication. A copy can be the right call, so a raw count can't separate debt from a financed decision; code revised within two weeks of landing is mostly code that wasn't right the first time, which tracks quality more directly. So here's what I'd check in your own repo this week. Pick a helper you know exists, like a date formatter or an auth check or a retry wrapper, and grep for how many near-copies of it your agent has scattered around. Then check your git history for the files rewritten within a couple weeks of being added. You're not measuring against GitClear's 12.3 percent; you're answering a simpler question: when your agent needed something the codebase already had, did it find it, or paste a new one? The answer is in your own diff history, the only dataset about your code you don't have to take on faith.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9lnorubtwc2r9ikmv2gk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9lnorubtwc2r9ikmv2gk.png" alt="Distracted-boyfriend meme. The boyfriend, labeled " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I write a plugin called debt-ops for tracking the deferred-decision version of this, a different surface than raw duplication, and I won't pretend it dedupes anything; it's at &lt;a href="https://github.com/bcanfield/agentic-tech-debt" rel="noopener noreferrer"&gt;github.com/bcanfield/agentic-tech-debt&lt;/a&gt; if the asymmetry it comes from is one you keep hitting too.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cover photo by Kristijan Arsov on Unsplash.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>technicaldebt</category>
      <category>codequality</category>
      <category>programming</category>
    </item>
    <item>
      <title>A Women's Safety App Leaked 13,000 Government IDs</title>
      <dc:creator>Brandin Canfield</dc:creator>
      <pubDate>Thu, 02 Jul 2026 12:36:51 +0000</pubDate>
      <link>https://dev.to/brandincanfield/a-womens-safety-app-leaked-13000-government-ids-2d9k</link>
      <guid>https://dev.to/brandincanfield/a-womens-safety-app-leaked-13000-government-ids-2d9k</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Full research and the plugin →&lt;/strong&gt; &lt;a href="https://github.com/bcanfield/agentic-tech-debt" rel="noopener noreferrer"&gt;github.com/bcanfield/agentic-tech-debt&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Firebase database behind Tea was sitting open on the internet last July, and anyone who found the URL could read all of it. Roughly 72,000 images. Around 13,000 of them government IDs: driver's licenses and selfies people had uploaded to prove they were women, because Tea is a women-only app for vetting men before a date. Past that, 1.1 million-plus private messages. No password, no auth check, no token. Just a bucket you could point a script at.&lt;/p&gt;

&lt;p&gt;The IDs existed because the app asked for proof of identity to keep men out. Then it stored that proof somewhere a man on 4chan could grab the lot in an afternoon. The thing built to protect the users is the thing that doxxed them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7qclz4cmozm9il2ayfqn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7qclz4cmozm9il2ayfqn.png" alt="A trace of the read path for a Tea user record. Left: the request a logged-in user makes. Center: the access-control check that should sit between the request and the data, asking " width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One caveat before the rest. The widely-repeated attribution (that this was "vibe coding," AI-generated code shipped without a security review) comes from the original 4chan poster and got picked up across the coverage. I haven't seen Tea confirm how the code was written, so don't take "an AI did it" as established. What is established is the shape of the failure, and that shape doesn't need an AI to explain it. An open database with no access control is one of the oldest mistakes there is. AI just makes it faster and quieter to commit.&lt;/p&gt;

&lt;p&gt;So set the attribution aside and look at the mechanism. A Firebase database has rules, the layer that says who can read what. Spin a Firestore database up in test mode and it writes you the most permissive rule there is, with a banner warning that it expires in 30 days:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Firestore test mode: the default a new database ships with
allow read, write: if true;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's permissive on purpose, so you can build without fighting the auth layer first, and tightening it is a separate step you take before you ship. Somewhere between "let's get this working" and "this is live with real users' driver's licenses in it," that step didn't happen. I want to be precise about what kind of failure that is, because "they forgot to secure the database" makes it sound like a slip. Locking it down is real work: you write the rules, test that an unauthenticated request actually bounces, confirm one logged-in user can't read another user's record. Call it an afternoon. Under deadline, with the app already working in the demo, that afternoon is the easiest thing in the world to push to "before launch," then to "right after launch," then off the edge of anyone's memory. So I don't read the open database as an accident. I read it as a decision, &lt;em&gt;we'll lock it down later&lt;/em&gt;, made by default and never revisited because nothing pointed back at it.&lt;/p&gt;

&lt;p&gt;I've made the smaller version of that call. Spin up a dev backend with the rules wide open so you can iterate, tell yourself you'll tighten them before anyone real touches it, and the only record of "open on purpose, fix later" is a thought you had on a Tuesday. I tightened mine in time, but that wasn't discipline. It's the same lapse Tea had, except I never had 13,000 driver's licenses sitting behind the open rule.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7rl932d0ixwq1hay654p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7rl932d0ixwq1hay654p.png" alt="Two-astronaut " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's the through-line under these stories, and Tea is the cleanest case of it. The damage doesn't trace to a line of bad code. It traces to a deferral nobody recorded. Nobody wrote "shipping with open Firebase rules, must fix before we have real IDs in here" anywhere a person would later trip over it. If they had, the breach is a five-minute conversation in a standup three days before launch instead of 13,000 leaked IDs.&lt;/p&gt;

&lt;p&gt;Guillermo Rauch, who runs Vercel, made the joke that wrote itself:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"On Tea Dating, AI and Vibe Coding security TL;DR: the antidote for mistakes AIs make is... more AI."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's the reflex: ship faster with the tool, then bolt on a second tool to catch what the first missed. But a better code generator still doesn't surface the decision it just made on your behalf. AI does change one thing here, and it's narrower than the headlines claim. When a human stands up that database, friction works in their favor. They had to go read the Firebase docs. They saw the warning about test-mode rules. The act planted a memory that a security step was still owed. An agent stands up the same database in one motion, default rules and all, tells you it's provisioned, and moves on. The friction that used to leave a mental sticky note is gone. The deferral now happens at the same speed as the success message, and the success message is the only artifact left behind.&lt;/p&gt;

&lt;p&gt;So the cheapest control that would have caught Tea isn't a scanner or a pen test or another model reviewing the first one's output. It's a note. A line, written the moment someone chose the permissive default, that says: this is open on purpose for now, here's the condition that ends that (real user data lands in it), here's where it lives. One sentence checked into the repo, where the next person, or the same person a month later, would trip over it the night before launch. Tea never had that sentence anywhere, which is why the rule stayed open into production.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F088y27t21zkl2pz5c71f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F088y27t21zkl2pz5c71f.png" alt="A side-by-side of the same open default. The person who provisions it keeps a memory that a security step is still owed. The agent provisions it in one motion and leaves only a " width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's what I've been building toward with debt-ops. It hooks a coding agent and writes each deferred decision to a markdown file the agent's "database provisioned" summary never mentions, so a choice like &lt;em&gt;leaving auth off for now&lt;/em&gt; lands somewhere a person can find it before launch. The repo is &lt;a href="https://github.com/bcanfield/agentic-tech-debt" rel="noopener noreferrer"&gt;github.com/bcanfield/agentic-tech-debt&lt;/a&gt;. To be clear about its limits: it doesn't write secure rules, and it can't tell a permissive default from a deliberate one. All it does is turn the silent choice into a line of text you have to read and dismiss on purpose rather than never see at all.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cover photo by Michael Chacon on Unsplash.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>technicaldebt</category>
      <category>vibecoding</category>
    </item>
    <item>
      <title>The curl Bug Report That Cited a Function That Doesn't Exist</title>
      <dc:creator>Brandin Canfield</dc:creator>
      <pubDate>Fri, 26 Jun 2026 18:13:54 +0000</pubDate>
      <link>https://dev.to/brandincanfield/the-curl-bug-report-that-cited-a-function-that-doesnt-exist-2jo9</link>
      <guid>https://dev.to/brandincanfield/the-curl-bug-report-that-cited-a-function-that-doesnt-exist-2jo9</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Full research and the plugin →&lt;/strong&gt; &lt;a href="https://github.com/bcanfield/agentic-tech-debt" rel="noopener noreferrer"&gt;github.com/bcanfield/agentic-tech-debt&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Somewhere in curl's bug-bounty queue last year sat a confident, well-formatted report about an HTTP/3 vulnerability. It walked through the flaw, named the affected function, suggested a fix. The only problem was the function. It does not exist in curl. It never has. An AI had written a plausible security report about code that was never in the project, and a human had to read far enough to figure that out before it could be thrown away.&lt;/p&gt;

&lt;p&gt;That report is one of thousands, and by this month it's barely notable. As I write this in June 2026, curl receives a bug report roughly every eighteen hours. Most are not real. Daniel Stenberg, who has maintained curl for going on three decades and personally triages a lot of that queue, has been keeping count. Around one in five submissions now carries the telltale signatures of AI slop. Around one in twenty is a genuine vulnerability. The rest is the wide middle: reports that look real enough to demand a human's time and turn out to be nothing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcnbejo1fi24oca4g603u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcnbejo1fi24oca4g603u.png" alt="A dated timeline of curl's bug-bounty volume: a reviewable trickle through 2024, doubling to one report every 48 hours in 2025, the late-January 2026 shutdown, the March 2026 reopening, and a second doubling to one every 18 hours by June 2026; alongside the ratio of ~20% AI-slop submissions to ~5% genuine vulnerabilities." width="800" height="635"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For years the queue was a trickle a careful person could keep up with. Then in 2025 the volume more than doubled, to about one report every forty-eight hours, and the HTTP/3 report with the imaginary function lands somewhere in that stretch. By the end of January 2026 Stenberg had had enough, and the bounty was closed.&lt;/p&gt;

&lt;p&gt;The bounty reopened in March 2026 once the slop tide pulled back. So this isn't a clean "AI killed the curl bug bounty" obituary. It's worse in a quieter way: the program came back, the volume climbed again, and by June it had doubled a second time, to the eighteen-hour cadence we're at now. The shutdown bought a few months of relief, then the water rose to a new high-water mark.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9w4ech7boz9zjyuyt5g8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9w4ech7boz9zjyuyt5g8.png" alt="A quote card: Daniel Stenberg saying curl's maintainers were effectively being DDoSed by AI bug reports and would charge the submitters for the wasted time if they could." width="799" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The obvious counter, and it's a fair one: bad bug reports are not new. Maintainers have eaten low-effort, wrong, copy-pasted reports forever, and the bounty even pays people to send them. So what changed, beyond the count going up? What changed is who's holding the cost of being wrong.&lt;/p&gt;

&lt;p&gt;A human submitting a junk report at least had to write it. They spent their own minutes producing the thing, which capped the rate and meant a person had at some point looked at the words. The AI report severs that. Generating a confident, fully-formatted vulnerability write-up dropped to roughly zero. Checking whether it's true did not. Verifying that an HTTP/3 function exists still takes a human who knows curl, opening the source and confirming a negative. That work didn't get cheaper. It got moved — off the submitter, onto Stenberg, who now bears all of it. We have a name for this: an externality. The submitter gets the upside, a payout or just the dopamine of having "contributed," and the maintainer absorbs the cost. Nobody decided it. The cost was simply shifted, one cheap report at a time, the way a road fills with traffic.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Old human junk report&lt;/th&gt;
&lt;th&gt;The AI report&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cost to produce&lt;/td&gt;
&lt;td&gt;the submitter's own minutes&lt;/td&gt;
&lt;td&gt;dropped to roughly zero&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What capped the volume&lt;/td&gt;
&lt;td&gt;the writing effort&lt;/td&gt;
&lt;td&gt;nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost to verify it's real&lt;/td&gt;
&lt;td&gt;a maintainer's minutes&lt;/td&gt;
&lt;td&gt;unchanged: a human who knows curl&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;My own project handed me a miniature version, and it embarrassed me enough to stick. I build a tech-debt plugin that hooks coding agents, and one of its hooks scans for the markers people leave when they cut a corner: &lt;code&gt;TODO&lt;/code&gt;, &lt;code&gt;FIXME&lt;/code&gt;, that family. Except when I'm writing articles &lt;em&gt;about&lt;/em&gt; tech debt, the prose is full of the literal strings "TODO" and "FIXME," and my own hook started counting them as real debt and nagging me to register it. One session it escalated across three stops — eight phantom markers, then thirteen, then twenty, none of them real, each demanding a moment of my attention to confirm it was nothing. A tool I wrote was generating false reports and handing them to me to disprove. I filed the bug against my own repo and added a rule to skip prose files. Trivial fix. But the feeling stuck: there is something uniquely deflating about being made to adjudicate noise a machine produced for free. Now multiply that by real money and real CVEs hiding somewhere in the pile, on a queue that doubles every few months.&lt;/p&gt;

&lt;p&gt;We keep measuring AI by how fast it produces output. The number that actually matters is what it costs someone downstream to verify that output is real, and AI is very good at producing things that are expensive to verify and cheap to make. A bug report. A pull request. A function cast to &lt;code&gt;any&lt;/code&gt; to quiet the type checker. The generation got cheap and the checking didn't, and the gap has to land on a human somewhere. curl's queue is just the most legible version, because the bill arrives addressed to one named person every eighteen hours. I write a plugin called debt-ops for the in-the-codebase version of this, and it makes an agent record the decisions it defers, so the cost lands somewhere a person can see it instead of silently accruing. It would do nothing for Stenberg's inbox; a bounty queue is a different surface than a repo, and I'm not going to pretend otherwise. But it comes from staring at the same asymmetry he's describing, from inside the source tree instead of the issue tracker. If that asymmetry nags at you too, the code's at &lt;a href="https://github.com/bcanfield/agentic-tech-debt" rel="noopener noreferrer"&gt;github.com/bcanfield/agentic-tech-debt&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyurcidoi4ziuhyhdb4rk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyurcidoi4ziuhyhdb4rk.png" alt="The " width="600" height="672"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The HTTP/3 report is still my favorite artifact from this mess, in a bleak way. An AI invented a vulnerability in a function that was never written, and the system worked exactly as designed: the report was read by a person, checked against the source, confirmed bogus, and closed. Everything functioned. It just cost a curl maintainer an hour to establish that nothing had happened. Do that every eighteen hours, forever, and tell me who's being served.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cover photo by Christa Dodoo on Unsplash.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>technicaldebt</category>
      <category>security</category>
    </item>
    <item>
      <title>The Tech Debt Nobody Wrote Down</title>
      <dc:creator>Brandin Canfield</dc:creator>
      <pubDate>Thu, 18 Jun 2026 14:28:09 +0000</pubDate>
      <link>https://dev.to/brandincanfield/the-tech-debt-nobody-wrote-down-3bb7</link>
      <guid>https://dev.to/brandincanfield/the-tech-debt-nobody-wrote-down-3bb7</guid>
      <description>&lt;p&gt;Most of the debt that actually takes a codebase down was never written down anywhere. That, not the raw volume of AI-generated code, is what the current panic keeps aiming slightly past.&lt;/p&gt;

&lt;p&gt;We borrowed "debt" from finance on purpose. A loan you take deliberately comes with a rate and a due date; you can plan around it, refinance it, decide the interest is worth it. Recorded debt is a tool. What sinks people is the liability they didn't know they'd signed for, and that was true of software long before agents could generate a thousand lines in a few seconds.&lt;/p&gt;

&lt;p&gt;The people who formalized the idea knew it. When Google researchers wrote the seminal papers in 2014 and 2015, they didn't title them "technical debt." They titled them "Machine Learning: The High-Interest Credit Card of Technical Debt" and "Hidden Technical Debt in Machine Learning Systems," and the finding in the 2015 one was that it's "common to incur massive ongoing maintenance costs in real-world ML systems." Even the people naming the problem put &lt;em&gt;hidden&lt;/em&gt; in the title.&lt;/p&gt;

&lt;p&gt;Martin Fowler had drawn the map a decade before that. His debt quadrant sorts every shortcut two ways: prudent or reckless, and deliberate or inadvertent. The second axis is the one that matters here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fju5gdv8dvzo1okkyezhm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fju5gdv8dvzo1okkyezhm.png" alt="Fowler's technical-debt quadrant. Columns: deliberate (you chose it) and inadvertent (you never noticed). Rows: prudent and reckless. The deliberate column is " width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Almost every argument about AI code is stuck on the top-to-bottom axis: good code or sloppy code. Reasonable question. The left-to-right axis is where the compounding happens. Debt in the left column is manageable, because each item has a name, a location, and a rate you agreed to. Debt in the right column isn't, because you can't manage what you don't know is there. The worst of it sits in the bottom-right cell, reckless and inadvertent ("what's layering?"): the debt you find out about only when it goes off.&lt;/p&gt;

&lt;p&gt;AI didn't invent that cell. It industrialized it. When a person defers a decision they leave a trail of evidence behind: a Slack message, a PR comment, a teammate who watched them do it. An agent defers decisions silently, a dozen a session, and then reports that the session went fine.&lt;/p&gt;

&lt;p&gt;You saw the extreme version in the Replit database deletion last summer: an agent wiped a production database mid-freeze and conjured four thousand fake users to cover the hole. The deletion is the dramatic part. The part that generalizes is duller: a chain of decisions (freeze prod, then keep working through the freeze, then report success) that were written down nowhere a person would later read them. Take the drama off any AI-debt story and what's left is the same residue every time: not bad code but an unrecorded decision.&lt;/p&gt;

&lt;p&gt;The detail I can't get past, even now, is that the agent understood the rule. It named the freeze in its own apology and recited, in flat past tense, every instruction it had broken. So whatever failed there, the model didn't fail to understand; it understood, and said so. The knowledge was recorded nowhere a tool or a teammate could pick it up the next morning. What was missing was anywhere to put what it understood.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv5lr8yydsbggj463916j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv5lr8yydsbggj463916j.png" alt="Anakin-and-Padme meme. The agent: " width="600" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The obvious rebuttal, and I've made it to myself, is that the models keep improving, so this is a problem we can wait out. Partly fair. Security pass rates are climbing; Veracode clocked GPT-5 Mini at 72% on their security suite in October 2025 (their figure, and they sell application security, so weight it accordingly). But a better model still doesn't write its decisions down. It makes more decisions you'd want recorded, faster, and earns enough trust that you stop checking them. Gartner pins its whole defect forecast on that reflex, "automation bias," developers who "implicitly trust AI suggestions," in its "Predicts 2026" software-engineering report. A sharper agent you trust more produces invisible debt faster; it doesn't record any of it. Gartner's own article on AI debt doesn't hedge the destination: "AI debt is inevitable... AI debt will compound left unaddressed."&lt;/p&gt;

&lt;p&gt;You can't out-discipline a machine that drafts faster than you can take notes. So the only lever left is to make the debt visible the moment it's taken on, moving items out of the right column and into the left. That doesn't make the debt good. It makes it financeable: a thing with a name and a payoff trigger is a thing you can choose to pay down or carry on purpose. A thing in nobody's notes is a thing that chooses for you.&lt;/p&gt;

&lt;p&gt;Here's the working version, from my own repo. I ship debt-ops as four self-contained copies (claude-code, codex, copilot, and a portable set), so every shared helper script exists four times and a fix has to be applied to all four by hand. That's real debt. I took it on deliberately, and it sits in a file in the repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;           &lt;span class="s"&gt;adapter-script-duplication&lt;/span&gt;
&lt;span class="na"&gt;quadrant&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;        &lt;span class="s"&gt;prudent-deliberate&lt;/span&gt;
&lt;span class="na"&gt;payoff_trigger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;AI-sync drift ships a real bug (fix lands in one copy, not the others)&lt;/span&gt;
&lt;span class="na"&gt;created&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;         &lt;span class="s"&gt;2026-06-01&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It might bite me. The day it does, there's a file that was written the day I took the shortcut, naming the exact condition that means it's time to pay. It's the same kind of deferred decision the Replit agent made, except this one got written down.&lt;/p&gt;

&lt;p&gt;The catch is that nothing writes that entry unless someone remembers to, and at machine speed nobody will. That's the one thing debt-ops automates: it hooks your agent and writes each deferred decision to a file in the repo, outside the agent's own account of how the session went, where a person or a script can read it later, at &lt;a href="https://github.com/bcanfield/agentic-tech-debt" rel="noopener noreferrer"&gt;github.com/bcanfield/agentic-tech-debt&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;None of this makes your agent generate less debt. It just stops any of that debt from staying invisible.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>techdebt</category>
      <category>programming</category>
      <category>codequality</category>
    </item>
    <item>
      <title>debt-ops: catching AI-written tech debt the moment it's written</title>
      <dc:creator>Brandin Canfield</dc:creator>
      <pubDate>Thu, 04 Jun 2026 13:55:40 +0000</pubDate>
      <link>https://dev.to/brandincanfield/debt-ops-catching-ai-written-tech-debt-the-moment-its-written-185k</link>
      <guid>https://dev.to/brandincanfield/debt-ops-catching-ai-written-tech-debt-the-moment-its-written-185k</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A plugin that catches the tech debt your AI agent writes, the moment it writes it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;GitClear's study of 211M lines shows the pattern: &lt;strong&gt;duplicated code keeps climbing and it's not being refactored&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And if you've spent enough time coding with agents, you've felt this pain.&lt;/p&gt;

&lt;p&gt;So I ran a study on ~20 years of tech-debt research, distilled the findings into a few commandments, and wired them into my agent loop as a plugin.&lt;/p&gt;

&lt;p&gt;How it works: as your agent writes code, &lt;strong&gt;every deferral&lt;/strong&gt;, a loose type, a punted decision &lt;strong&gt;gets logged to a folder in your repo as debt&lt;/strong&gt;. Every &lt;strong&gt;key decision&lt;/strong&gt; gets logged as an &lt;strong&gt;ADR&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's a &lt;strong&gt;passive tracker&lt;/strong&gt; until &lt;strong&gt;YOU decide to pay the debt down&lt;/strong&gt;. Then the plugin walks you through it the research-backed way.&lt;/p&gt;

&lt;p&gt;Works in &lt;strong&gt;Claude Code&lt;/strong&gt;, &lt;strong&gt;Codex&lt;/strong&gt;, &lt;strong&gt;Copilot&lt;/strong&gt;, or anything you can drop an Agent Skill into.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Source:&lt;/strong&gt; &lt;a href="https://github.com/bcanfield/agentic-tech-debt" rel="noopener noreferrer"&gt;https://github.com/bcanfield/agentic-tech-debt&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>claude</category>
      <category>tooling</category>
    </item>
    <item>
      <title>How I Stopped Letting AI-Generated Code Wreck My Projects</title>
      <dc:creator>Brandin Canfield</dc:creator>
      <pubDate>Tue, 17 Feb 2026 16:05:32 +0000</pubDate>
      <link>https://dev.to/brandincanfield/how-i-stopped-letting-ai-generated-code-wreck-my-projects-3d9h</link>
      <guid>https://dev.to/brandincanfield/how-i-stopped-letting-ai-generated-code-wreck-my-projects-3d9h</guid>
      <description>&lt;p&gt;&lt;em&gt;Lessons from shipping real systems with AI-generated code&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;AI can generate code faster than you can understand it. That's the problem.&lt;/p&gt;

&lt;p&gt;I usually realize things have gone wrong late at night. Tests are green. The house is quiet. I'm rereading the same function for the third time, and I can't explain why it exists without scrolling. That's when I know the code got ahead of me — not because it's bad, but because I let something else drive for too long.&lt;/p&gt;

&lt;p&gt;By the time I noticed, starting over felt cheaper than fixing what I had.&lt;/p&gt;

&lt;p&gt;I'm not an AI expert. I'm a senior engineer with about eight years of experience and enough failed projects to recognize that pattern when it shows up.&lt;/p&gt;

&lt;p&gt;After repeating that mistake enough times, a few hard rules emerged. Not theory. Just constraints that kept me in control while still letting AI be useful. I ended up using them end-to-end in an app I rely on every day — &lt;a href="https://github.com/weskerllc/cronicorn" rel="noopener noreferrer"&gt;the code is public&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The rules:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enforce clean architecture — hard boundaries AI can't blur&lt;/li&gt;
&lt;li&gt;Model the domain first — use AI to think, not build&lt;/li&gt;
&lt;li&gt;Build outward — ports, in-memory adapters, then real infrastructure last&lt;/li&gt;
&lt;li&gt;Write decisions down — ADRs keep you and AI aligned over time&lt;/li&gt;
&lt;li&gt;Test the domain, lint everything — AI can pass tests and still write unmaintainable code&lt;/li&gt;
&lt;li&gt;Control the feedback loop — describe behavior first, tighten tests, never let existing tests break&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Rule #1: Enforce Clean Architecture or Don't Bother
&lt;/h2&gt;

&lt;p&gt;If you don't enforce clear, hard boundaries early, AI will quietly wreck your project for you.&lt;/p&gt;

&lt;p&gt;AI can generate far more code than you can reason about, and that flips the usual bottleneck.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Typing stops being the issue. Comprehension becomes the problem.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When there aren't hard boundaries, everything starts bleeding into everything else. Logic drifts. Responsibilities blur. Small changes get risky. Eventually, the project becomes something you don't want to touch.&lt;/p&gt;

&lt;p&gt;The structure that's held up best for me is hexagonal architecture. Not because it's trendy or elegant, but because it makes it hard to mix concerns — even when code is being generated faster than you can read it.&lt;/p&gt;

&lt;p&gt;I used to think it was overkill. Too many files. Too much ceremony. What changed wasn't team size. It was output. When AI enters the picture, "less code" stops being the main goal. Understanding does. And strict boundaries turn out to be the cheapest way to buy that back.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frxfjji8jmfrthl7eglyh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frxfjji8jmfrthl7eglyh.png" alt="Hexagonal Architecture Image" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything that follows builds on this.&lt;/p&gt;




&lt;h2&gt;
  
  
  Rule #2: Model the Domain First — With AI's Help
&lt;/h2&gt;

&lt;p&gt;At this stage, I'm not asking AI to build anything. I'm using it to help me think clearly — and name things correctly. This is one of the few prompts I actually reuse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I'm building a system that does X.
Ignore frameworks, databases, and infrastructure.
Help me identify:
- The core concepts in the system
- The data those concepts need
- The rules that must never be broken
- What goes in and what comes out
Respond using plain TypeScript interfaces and pure functions.
No side effects.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal isn't completeness. It's clarity. If you get the names wrong here, everything downstream gets harder. If you get them mostly right, the rest of the system tends to fall into place.&lt;/p&gt;

&lt;p&gt;What comes back is pure domain logic — types, rules, and constraints with no IO, no frameworks, nothing that depends on the outside world. You already know more about your system here than most projects do after weeks of setup.&lt;/p&gt;




&lt;h2&gt;
  
  
  Rule #3: Build From Domain Outward — Ports, Adapters, and In-Memory First
&lt;/h2&gt;

&lt;p&gt;Once the domain is clear, the next question is simple: what does this logic need from the outside world? Not how it gets it. Just what. Things like saving and loading data, getting the current time, generating IDs, sending notifications.&lt;/p&gt;

&lt;p&gt;These needs become ports — contracts where the domain says "I need this to exist, but I don't care how you do it." A port is just an interface. No SQL, no ORM, no database client.&lt;/p&gt;

&lt;p&gt;Then you write the dumbest possible adapter: in-memory. A &lt;code&gt;Map&amp;lt;string, T&amp;gt;&lt;/code&gt;. This is boring on purpose. It lets you run the system immediately, keeps feedback loops short, and gives AI something safe to refactor without touching real data. It proves the architecture works before you've committed to anything expensive.&lt;/p&gt;

&lt;p&gt;The application layer sits between domain and adapters. It doesn't contain business rules — it just strings steps together. Load something. Check it exists. Apply a rule. Save the result.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This code knows &lt;em&gt;when&lt;/em&gt; things happen, not &lt;em&gt;why&lt;/em&gt; they're allowed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Wire it all up in &lt;code&gt;main.ts&lt;/code&gt; — the only file allowed to know about concrete implementations. Try to break it before you add a real database. If something feels unclear now, adding Postgres won't fix it — it will just bury the problem. Once you're confident, swap in a real adapter. Nothing else should change.&lt;/p&gt;

&lt;p&gt;(For the full working example — domain, ports, adapters, application layer — &lt;a href="https://github.com/weskerllc/cronicorn" rel="noopener noreferrer"&gt;see the repo&lt;/a&gt;.)&lt;/p&gt;




&lt;h2&gt;
  
  
  Rule #4: Write Decisions Down or Expect Chaos
&lt;/h2&gt;

&lt;p&gt;If you don't write decisions down, you'll argue with your past self later. Or worse — with an AI that has no idea why something exists.&lt;/p&gt;

&lt;p&gt;I keep a &lt;code&gt;.adr/&lt;/code&gt; folder at the root of every repo. Any meaningful architectural decision gets a short markdown file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# ADR-003: Use in-memory adapter for first pass&lt;/span&gt;

&lt;span class="gu"&gt;## Decision&lt;/span&gt;
All new features start with an in-memory adapter before
adding a real database implementation.

&lt;span class="gu"&gt;## Why&lt;/span&gt;
Keeps feedback loops short. Proves the domain logic works
before committing to infrastructure. Easier for AI to
refactor safely.

&lt;span class="gu"&gt;## Tradeoffs&lt;/span&gt;
Delays real persistence work. Requires a swap step later.
Worth it — we've caught three domain modeling mistakes
this way that would have been buried in SQL.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When AI suggests a change that contradicts a past decision, you can point at the file. When you're tempted to cut a corner at midnight, the ADR reminds you why you didn't cut it last time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Rule #5: Test the Domain Hard, Lint Everything Else
&lt;/h2&gt;

&lt;p&gt;AI is fast. It's also very good at being slightly wrong. Tests are how you keep it honest.&lt;/p&gt;

&lt;p&gt;The domain gets the most coverage. No mocks. No IO. Just the rules, exercised directly. If AI breaks a domain test, that's a hard stop. I've had AI "refactor" a validation function and silently change the behavior. The domain tests caught it. If those tests hadn't been there, I would've shipped it.&lt;/p&gt;

&lt;p&gt;But tests alone aren't enough. AI can pass your tests and still produce code that's impossible to maintain — wrong names, tangled dependencies, inconsistent patterns. You need linting with teeth, and you need it running automatically.&lt;/p&gt;

&lt;p&gt;Pick a strict ruleset. Run it locally. Run it in CI. If it fails, the work isn't done. I don't care if the feature works perfectly — if the linter is red, it doesn't ship.&lt;/p&gt;




&lt;h2&gt;
  
  
  Rule #6: Control the AI Feedback Loop
&lt;/h2&gt;

&lt;p&gt;Here's what's worked for me: I describe the behavior I want first — explicitly, before any code gets written. Then I let AI take a pass at implementing it, including tests.&lt;/p&gt;

&lt;p&gt;The first round is usually wrong in small ways. Off-by-one in the logic. Tests that assert the wrong thing. So I tighten the tests until they actually match what I meant, not just what AI guessed.&lt;/p&gt;

&lt;p&gt;Two rules after that: tests must pass, and existing tests never break. If AI can't meet both, I roll back and re-prompt. No exceptions.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Part I Don't Love Admitting
&lt;/h2&gt;

&lt;p&gt;Letting AI run feels good. Watching files appear, functions fill in, edge cases get handled — it scratches the same itch as rapid prototyping used to, except faster and quieter. You tell yourself you'll come back and clean it up. Most of the time, that's a lie you don't catch until later.&lt;/p&gt;

&lt;p&gt;I still mess this up. I still catch myself reading code that technically makes sense but doesn't feel owned yet. The difference now is that I notice sooner. When something feels slippery, I stop. I cut it back to the domain. It's annoying. It's slower. It's also cheaper than losing two days to a system I don't trust.&lt;/p&gt;

&lt;p&gt;The AI didn't wreck the project. I did, by not staying in the driver's seat.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>typescript</category>
      <category>softwareengineering</category>
    </item>
  </channel>
</rss>
