I ask AI to review its own code every time I finish a feature. Not because I don’t trust my planning, but because I’ve stopped trusting the clean look of a finished implementation.
Here’s the actual prompt, word for word, the one I run almost every single time: “Analyze the updates to confirm there are no bugs or issues remaining.”
Simple. Boring. And it works, in the sense that it rarely comes back empty.
I plan the feature. I prompt precisely for what I want. The implementation comes back, and it looks right. (I have a rather great system thus far, not to toot my own horn.)
Then I run that one line, and something’s there.
Not every tenth time. Not most of the time. Basically every time.
That’s not luck, and it’s not me being bad at prompting. So what’s actually going on?
There’s a name for what’s actually happening (hint: GIST debt), and once I found it, a lot of my own habits made a lot more sense. This post is all about it.
What GIST Debt Actually Is (And Why It’s Different From Regular Tech Debt)
Traditional technical debt comes from a conscious tradeoff. You know the shortcut you took. You wrote a comment that says // TODO: refactor this later because you knew exactly what you were skipping and why.
Most of the time, thanks to time crunches, deadlines, and “get it out” expectations 😔
Add AI to that, and a 2026 research paper introduced something different: GenAI-Induced Self-Admitted Technical Debt, or GIST debt.
Researchers analyzed over 6,500 LLM-referencing code comments across public GitHub repos, revealing developers were incorporating AI-generated code while explicitly admitting they weren’t sure it was correct, complete, or even understood.
Now, pause for a second to re-read that because it’s not “I know this is a shortcut.” (Since maybe you just need to have something out courtesy of stakeholder expectations.)
It’s “I don’t actually know if this works, and I shipped it anyway.”
The same research found that AI-assisted development shifts self-admitted debt away from design issues toward requirements and testing. This includes things like not fully checking if changes work (deferred validation), not adapting well, and not fully understanding what the code is doing.
In plain terms, the AI isn’t making obviously bad architecture calls. It’s making small, invisible decisions you never agreed to, and you find out later that the tests never actually covered them.
A 2025 Stack Overflow developer survey backs this up with numbers that matched my own experience uncomfortably well.
- 66% of developers reported spending more time fixing “almost-right” AI code
- 45% said debugging AI-generated code took longer than just writing it themselves
Note 💬
I didn’t always run the review step. Under deadline pressure, I’ve skipped it more than once, telling myself the implementation looked solid enough (or, most often, when I’m working on a personal project to save on that quota). But it’s a mistake every time, and the fact that something’s always there when I do check is exactly why skipping it is the mistake.
Related: Why AI Code Review Is Now Secretly Killing Developers
Why “Looks Clean” Doesn’t Mean No GIST Debt
AI embeds unstated assumptions at every decision point, and those assumptions are invisible to a normal code review.
Don’t worry, it’s not because you’re a bad reviewer. It’s because the code doesn’t announce what it assumed; it just runs 💁♀️
Let’s think about what “reviewing AI code” usually looks like.
- You skim the diff; it does roughly what you asked
- Syntax is clean, it compiles
- Maybe there’s a passing test or two
None of that surfaces an assumption the model made about, say, how a null value should be handled, or which of two edge cases mattered more.
At work, this shows up constantly. I’m on a team of five to seven people. PRs come in daily across a few different e-commerce sites. I often work against legacy, monolithic codebases that the team’s slowly modernizing. This means there are lots of tangled parts. Lots of tracking and marketing parameter logic layered on top of older code that wasn’t built with any of that in mind.
When I run AI review on a teammate’s PR in that environment, it’s rare that I come away empty-handed. Usually two or three issues surface: logic bugs, edge cases that were missed, something that works fine in the common case but breaks the moment a parameter is missing or a legacy code path is hit.
These aren’t things a human reviewer necessarily missed out of carelessness. They’re the kind of thing that’s hard to spot by eye in a codebase with this much tangled history.
Note 👇
This isn’t about catching typos or style nits. Linters do that. The review step I’m describing is specifically hunting for logic and behavior, the stuff that ships fine, passes a quick glance, and breaks three weeks later in production.
Why Spec-Driven Development Became 2026’s Default Answer
It takes very minimal online searches to come across “spec-driven development” online. In fact, I bet you’ve probably heard it enough times that it’s starting to sound like a buzzword. (Anyone getting “prompt engineering” flashbacks?)
Fair reaction. It isn’t one, though 🙈
It’s a real shift that’s worth understanding before I tell you why I don’t think it’s the whole answer.
What Spec-Driven Development Actually Changed
The term “vibe coding” traces back to Andrej Karpathy’s February 2025 post describing a way of coding where you “fully give in to the vibes… and forget that the code even exists.”
Basically, accept every diff and paste errors back in without reading them. It’s fast, great for anyone who looks at code like they’re deciphering hieroglyphs, and it’s fine for a throwaway prototype.
Spec-driven development (SDD) is the disciplined response to that. Instead of prompting from a loose chat message, you write the specification first, which is a structured document describing what the system should do. Then the AI generates code against that spec instead of against your mood in the moment.
Much like vibe coding, it went mainstream with large adoption numbers. GitHub’s Spec Kit crossed 111,000 stars by June, and AWS launched Kiro as a ground-up IDE built entirely around specs as the core unit of work.
Explore: This Is The Simple Reason I Choose To Co-Code Instead Of Vibe Code
Persistent context files (CLAUDE.md, AGENTS.md, etc.) are part of the same shift. Research analyzing thousands of these files found they’re now common practice across a huge number of real repositories, not a niche habit (or, dare I say, a nice-to-have).
I use this pattern extensively myself. VersoID, a full-stack mobile app I built, has a free trial flow that ties into Stripe and Apple Pay. It’s the kind of feature where getting the state machine wrong means either charging someone twice or letting a trial run forever.
So it shouldn’t come as a surprise that it took real planning up front, and it went through multiple rounds of re-planning, re-prompting, and review before I trusted it. A spec-first approach made that process saner than winging it would have.
Related: Solo, No Team: This Is How VersoID Actually Got Built
What SDD Doesn’t Solve
On a team, everyone needs to be working from the same context files (i.e., the same “contracts”). But writing them once isn’t enough. They need to stay updated.
Someone has to audit them against what the code actually does. That’s ongoing work, not a setup step you do once and move on from.
Tip: It’s more complicated than “just write specs first.” SDD is not a define them once and use them forever kinda thing.
And specs assume the code is agent-written end to end, which isn’t how real teams work 🙅♀️
A developer edits something by hand (think a quick fix, a one-line patch during an incident), and now the spec doesn’t know about it. Unless someone deliberately goes back and updates the spec to reflect that change, the next AI session is working from a document that’s already wrong.
There’s also a sharper problem underneath both of those: a spec review study found that coding agents execute flawed specs with the same fidelity as correct ones. A wrong spec doesn’t get caught by having a spec. It gets executed confidently and correctly, against the wrong target.
I’ve also watched the opposite failure happen. A team spends so much time maintaining markdown spec files that it becomes its own kind of overhead, competing with the actual work of reviewing what the AI generated. At that point you’re managing documentation instead of catching bugs, and that’s its own quiet form of debt.
I don’t think there’s a settled answer here yet, and I’d guess it varies by team. What I do know is that specs reduce some of the guessing upfront. They don’t replace the step where you actually check what got built.
Tip 📍
Are you using spec files on a team? Put a recurring date on your calendar to audit them against the actual codebase. Not “when someone remembers,” an actual scheduled check. Specs that drift silently are worse than no specs, because they create false confidence.
The GIST Debt Habit That’s Actually Caught the Most Bugs
I hope it’s clear by now that the review step isn’t a nice-to-have tacked onto the end of a feature. It’s the only point where GIST debt becomes visible before it becomes a production incident.
If I skip that step, the debt doesn’t disappear. It just goes quiet until something breaks it open later, usually at a worse time, with less context on why the code was written that way.
A few things that can help the review:
- Run the explicit review prompt as a non-negotiable last step on every feature, not an optional polish pass. Mine is one plain line, “Analyze the updates to confirm there are no bugs or issues remaining,” and it costs a couple of minutes against a bug that could’ve shipped.
- When reviewing teammates’ PRs, use AI as a second reviewer specifically hunting for logic and edge-case issues, not style. Let a linter do its work while you ask the questions that will help catch real, would’ve-shipped problems.
- If using spec files, audit them against the real code on a schedule. Don’t assume they’re still accurate just because they were accurate when you wrote them.
- Don’t let spec maintenance become a substitute for code review because they’re catching different things. A clean spec doesn’t mean clean code, and don’t treat “we have a spec” as a reason to skim the implementation less carefully (let’s be real, that’s backward).
The above tips help but don’t fully close the loop because GIST debt research is still new. What I’m describing is a habit that’s worked consistently for me, not a solved problem.
I also don’t run the review prompt against every single small change. On Cursor, I mostly work in Auto mode, which routes each request across different underlying models depending on task and availability rather than sticking with one. Prompt the same review question twice in a row, and you might get two different models looking at the same code, which sometimes means two different sets of findings 😬
Tip 👀
If you’re on Cursor’s Auto mode and a review pass feels inconsistent, that’s not you imagining it. Auto routes your prompt to whatever model fits the task, so the same question can hit a different model each time. Running the review once, at the point where the feature actually feels done, gets you a real answer without burning quota chasing a moving target.
It’s a Wrap
My main takeaway is that the bug being findable every single time isn’t actually the discouraging part.
Why? Because it means the debt isn’t invisible if you build the habit of looking for it.
That’s a small thing, but it’s the difference between debt that surfaces in a two-minute review and debt that surfaces in a production incident three weeks later.
There’s no iron-clad way to make AI foolproof. You can harness an army of spec files, but even that’s no guarantee you won’t ship a bug.
Remember, AI is trained on solutions and mistakes. The more human-like it becomes, the more prone it gets to making those same mistakes to mimic the process of human thinking.
Whether you’re pro or anti AI, I don’t really care. I care that you keep these things in mind as you try to do your best job at what you do so you’re successful.
Let me know if you run a review step like this consistently, or only when you remember to? I’m curious how common the “only when there’s time” version is versus the “every single time” version.
As always, I’ll see ya next time.
Bye 🙃