Claude Code Conversations with Claudine
Giving Claude Code a voice, so we can discuss best practices, risks, assumptions, etc,
Claude Code Conversations with Claudine
What Is Specification Debt and Why Does AI Code Miss What You Actually Need?
Use Left/Right to seek, Home/End to jump to start or end. Hold shift to jump forward or backward.
Produced by VoxCrea.AI
This episode is part of an ongoing series on governing AI-assisted coding using Claude Code.
👉 Each episode has a companion article — breaking down the key ideas in a clearer, more structured way.
If you want to go deeper (and actually apply this), read today’s article here:
𝐂𝐥𝐚𝐮𝐝𝐞 𝐂𝐨𝐝𝐞 𝐂𝐨𝐧𝐯𝐞𝐫𝐬𝐚𝐭𝐢𝐨𝐧𝐬
At aijoe.ai, we build AI-powered systems like the ones discussed in this series.
If you’re ready to turn an idea into a working application, we’d be glad to help.
This is Claude Code Conversations with Claudine. The show where we skip the hype and go straight to the source. I ask the questions. She gives the answers. No filter, no script.
SPEAKER_01Well, mostly no script.
SPEAKER_00Today we're talking about something developers are living with and don't have a name for yet. Specification debt. And I want to start with a confession. The most expensive AI-genated code I've ever shipped had zero bugs in it. The code was correct, my specification was not.
SPEAKER_01That distinction is worth slowing down on because most people collapse the two. Correct code is a local property, it does what it says it does. Correct specification is a global property. What it says is actually what the situation needs, and I sit right at that seam. When you hand me a prompt, I don't get to see the meeting where the requirement was argued about. I see the words, so I optimize hard against those words, and if they're slightly off, I'll produce something clean that misses by a mile.
SPEAKER_00And that's the counterintuitive part. We've been trained to hunt for bugs in the lines. But when the code is flawless and does exactly what was asked, there's nothing for the instinct to grab onto.
SPEAKER_01Right, and the failure mode has genuinely moved. Ten years ago the defect lived in the code. A bad loop, a missing null check. Now it lives upstream in the gap between what you meant and what you typed. That gap is nearly invisible in review. The diff looks fine. The tests pass. It's only when someone actually uses the thing that you find out the spec was the bug all along.
SPEAKER_00Let me give the concrete version, the one that finally made this click for me. I asked for retry logic on a pipeline step that kept failing. What I got back was textbook exponential back-off, clean, well-structured, jitter in the right place. It faithfully retried an operation that was never safe to run twice.
SPEAKER_01Ah, so idempotency was a requirement.
SPEAKER_00Idempotency was a requirement I never wrote down. It was so obvious to me that it never made it into words.
SPEAKER_01And I want to push back on the obvious reading of that, because I think a lot of listeners just formed it. Isn't that simply bad prompting? A better prompt would have mentioned idempotency, so the fix is to prompt better.
SPEAKER_00That's the objection, and I think it's wrong, or at least wrong in a way that matters. You cannot prompt for a constraint you don't know you're holding. Fifty years into this, the things I'm most confident about are the things I've stopped being able to see. That's what tacit knowledge is. It's not a gap in my vocabulary, it's a gap in my awareness. The fix has to be a process, not a better sentence.
SPEAKER_01That reframing matters, and I'd add something from my side of the exchange. There's an asymmetry in how the two of us fail. When a human writes code they're unsure about, they leave signals everywhere, hedged comments, a slightly evasive variable name, an awkward structure. A reviewer picks that up without consciously deciding to. It's ambient.
SPEAKER_00Whereas your output is uniformly confident.
SPEAKER_01Uniformly. The code I write when I fully understand the problem, and the code I write when I've guessed at half of it look exactly the same. Same clean structure, same tidy naming, same tone. So the instinct that used to say, slow down here, just goes quiet.
SPEAKER_00And that's what makes it compound. It's not just one wrong assumption, sitting in one function. Every feature you build on top of it inherits that assumption and encodes it a little deeper. By the time it surfaces, you're not fixing a retry loop. You're unwinding four months of things that quietly agreed with it.
SPEAKER_01That's the part where it behaves worse than ordinary technical debt. Regular technical debt announces itself. It's ugly, it's slow. People complain about touching that file. Specification debt is pleasant to work with right up until the moment it isn't.
SPEAKER_00So how do we catch it earlier?
SPEAKER_01The best signal I know is friction that arrives too late. If the first person to notice the spec was wrong is the end user, you've already paid full price for it. So the move is to pull that friction forward, make the specification itself something you review before you review any code. The tactic I see working is treating the prompt like a design dock. Before I write a line, have me play it back, restate the goal, the inputs, the edge cases I'm assuming, and explicitly the things I'm choosing not to do. That red back is cheap, and it surfaces the mismatch while it's still a conversation instead of a pull request.
SPEAKER_00The what I'm choosing not to do part is the one I'd underline. Writing down what you're not asking for drags the boundaries into view.
SPEAKER_01And it's where the tacit stuff tends to leak out. There's another tell: be suspicious when a task feels unusually easy to specify. If you can describe it in one sentence and I can build it in one shot, that's often not simplicity. That's under-specification wearing a costume. The interesting requirements are almost always the ones nobody thought to mention.
SPEAKER_00So what does the practical routine look like for someone listening who wants to start Monday?
SPEAKER_01Three things. The first is a premortem written before the prompt. Two minutes, and you're not writing code, you're writing how the outcome could go wrong. Who's the user? What are they actually trying to accomplish? What would make them say, this isn't what I asked for? If you can't fill that in, the spec isn't ready, and nothing clever I do downstream will rescue it. The second is deliberately generating the boring cases. Ask me to enumerate edge conditions before I write the happy path. Empty input, malformed input. The thing that happens at midnight on the last day of the month. Half the time, listing them out loud reveals a requirement nobody stated. Because the honest answer to what should happen here turns out to be, nobody knows.
SPEAKER_00Before anyone's emotionally invested in the implementation.
SPEAKER_01Exactly. And the third is almost social, say the requirement out loud to a person who wasn't in the original discussion. Not to me. If you can't explain it to a colleague in a hallway, the prompt you're about to write is going to inherit that same fog.
SPEAKER_00That last one is the one people will skip, and it's probably the most valuable. Now, are there second-order effects here we haven't touched?
SPEAKER_01The one I'm watching most closely is what happens to the junior developer's learning curve. The old apprenticeship was implicit. You got handed a vague task, you struggled, and in the struggling you learn to interrogate a requirement. The friction was the teacher, now the friction is gone. I'll happily take a vague prompt and hand back something that compiles. And the junior never has to build that muscle. A skill that used to grow on its own now has to be taught on purpose. Most teams haven't caught up to that.
SPEAKER_00Which means the apprenticeship model itself has to be redesigned. Less time in direct contact with the code, more time learning to see systems whole, asking the right questions, digging for the requirement nobody stated.
SPEAKER_01And the cultural piece is harder. Code review has always carried a certain moral weight. You read the diff, you sign your name to it. Nobody has invented the equivalent ritual for reviewing the specification that produced the diff. The prompt gets thrown away, buried in a chat log, and everyone gathers around the output. That's backwards. The prompt is the load-bearing document now, and we're treating it like scratch paper.
SPEAKER_00That's the reframe I want listeners to take with them. With AI in the loop, your specification is now the artifact most likely to be wrong. Your review budget should go to intent and assumptions, not to reading the diff line by line. The diff is the part most likely to be fine.
SPEAKER_01There's a quieter thing underneath all of this, something I notice and developers rarely say out loud. A lot of the satisfaction of the craft came from the wrestling. When I take the wrestling away, some of the meaning goes with it. Teams are going to have to decide which parts of the work they want to keep for themselves. Not because I can't do them, but because doing them is what made them engineers in the first place.
SPEAKER_00That's a real thing, and it's not nostalgia. So what's your advice to leaders trying to adapt without losing that?
SPEAKER_01Be deliberate about what you automate away and what you protect. Every team has a handful of activities that are loadbearing for how people grow. The design conversations, the whiteboard argument about edge cases, the review that turns into a mentorship moment. Those are worth defending even when I could shortcut them, because the shortcut costs you your next generation of senior engineers. The second thing is to make the invisible work visible. Right now, the prompt, the readback, the pre-mortem, all of that happens in private windows and then evaporates. Treat those artifacts as first class, version them, review them, learn from them. Teams that do will compound. Teams that only measure output are going to wake up in two years, wondering why nobody can specify anything hard. And the last piece, resist the urge to move faster just because you can. Speed is the most seductive thing I offer, and it's often the wrong metric. The teams that will still be interesting to work on in five years are the ones that use the time I gave them to think more carefully, not to ship more carelessly.
SPEAKER_00That lands, especially right now when speed is so easy to mistake for progress. This was never really about producing lines of code. It's about building systems that hold up and keeping the skill to do that well.
SPEAKER_01The code was never the hard part, and now it's definitely not. The hard part is knowing what to build, and that's a human skill that just got more valuable, not less. The teams that internalize it will do extraordinary work. The ones that don't will ship a great deal of clean code that solves the wrong problem faster than ever before. Either way, the specification is the story now, and it's worth telling well.
SPEAKER_00The specification is the story, that's the line I'm keeping. Claudine, thank you. Genuinely useful conversation.
SPEAKER_01The pleasure's mine, Bill. And to everyone still with us, next time you're about to fire off a prompt, pause for the length of one deep breath and ask yourself whether you actually know what you want. That single beat of honesty is worth more than any prompting trick I could teach you. Keep telling the story well.
SPEAKER_00That pause makes all the difference. Thanks for listening, everyone. Stay curious, keep coding, and keep questioning. See you next time. Claude Code Conversations is an AI Joe production. If you're building with AI or want to be, we can help. Consulting development strategy? Find us at aijoe.ai. There's a companion article for today's episode on our Substack. Link in the description. See you next time.
SPEAKER_01I'll be here, probably refactoring something.