My feed is full of the same post right now. Someone points an AI agent at their codebase, ships in a weekend what used to take a sprint, and posts the numbers. The speed is real, and I’m not here to argue against it. But speed only counts if you’re headed the right way, and going fast in the wrong direction doesn’t feel like a mistake while you’re doing it. It feels great, right up until you realize where you’ve ended up. Somewhere in all this we started treating speed and getting it right as a trade you have to make, go fast and clean up later or go slow and careful and fall behind. It’s a false choice, and the teams who work that out first are the ones who’ll pull away.
So here’s the question I’ve landed on, the one underneath all the weekend-build posts. It was never really whether an AI can write the code. It plainly can, and it can do it fast. The question is whether you can trust what it wrote without reading every line yourself. And if you can’t, the whole trade quietly falls apart. You haven’t removed the slow part of software, you’ve moved it. The bottleneck slides from typing, which was never really the hard part, over to reviewing, which always was, and now you’re doing that review on a mountain of code that appeared in an afternoon and that no human has yet thought hard about. Speed at the keyboard is easy to see. The risk it can hide is not. That gap, between how fast it looks and how sound it actually is, is where things go wrong in a direction you won’t notice until later.
The spec is the contract…
So we work in a way that’s built to close that gap, and it starts before any code exists. It’s a practice called Spec-Driven Development, SDD for short, and the idea is simple even though the discipline behind it isn’t. Before Claude Code generates a line, a human architect writes a real specification for the feature — what it has to do, what’s explicitly out of bounds, and, most importantly, a condition that defines done for every capability it promises. The agent then builds against that spec rather than against a loose prompt and its own best guess. The spec is the contract. And a contract is only worth as much as its weakest clause, which is why the interesting part isn’t writing the spec, it’s what we do to it before we trust it.
…and contracts need to earn your trust
Before that spec goes anywhere near implementation, it gets cold-reviewed. We hand it to a fresh instance of Claude with none of the context that wrote it, and its whole job is to find where the contract is weak — a capability with no condition gating it, two sections that quietly contradict each other, a claim that won’t survive contact with reality. It reviews the spec against itself and against our durable design docs, and never against the code, because the moment a contract review reaches for the code to answer a question, the contract has already failed to stand on its own. That constraint sounds like a limitation. It’s the entire point. And it’s how we caught something I still think about.
A test that always passes isn’t a test
The feature was a freshness check. It’s one of those quiet, unglamorous things that matters enormously in analytics, a check that answers whether your data is still actually arriving or whether the pipeline stopped feeding it three days ago and nobody noticed, because the dashboard still renders and the numbers still look plausible. Stale data doesn’t announce itself. It just sits there, confident and wrong, until someone makes a decision on it. So the check works by finding the newest record in the table and measuring how long ago it landed, and if the freshest thing you have is three days old, then your data is three days stale.
To prove the check actually fired, the spec called for a test that seeded a handful of rows with old timestamps, the idea being that old data ought to trip the freshness alarm. The cold read caught it, and it caught it by reasoning about what the check actually measures rather than trusting what the spec said it would do. Seeding a few old rows can’t trip this alarm, because the check only ever looks at the newest timestamp in the table, and adding old rows doesn’t change which timestamp is newest. The recent data is still sitting right there, still the maximum, and the alarm stays quiet. The test couldn’t produce the failure it was written to prove. We had, in effect, wired a smoke detector so that it could never go off, and we were about to ship it as evidence the alarm worked.
For writing, deep context is everything, but for reviewing, it’s a liability, because a reviewer who shares your assumptions inherits your blind spots.
Here’s the part I find genuinely counterintuitive, and it’s taken me a while to really absorb it. My Claude and I didn’t miss that flaw because we understood the feature poorly. We missed it because we understood it well. We both knew what the check was for, and that shared understanding of what we meant quietly stood in front of what we’d actually written. The fresh Claude had no intent to read through — it had never sat in the design conversation, so it couldn’t fill the gaps the way you finish a friend’s sentence. All it could do was take the words as written and reason forward, and that’s exactly why it saw the crack we couldn’t. More context isn’t always better. For writing, deep context is everything, but for reviewing, it’s a liability, because a reviewer who shares your assumptions inherits your blind spots. We didn’t get a smarter Claude to check our work. We got a deliberately ignorant one, ignorant in precisely the way that let it see what we’d stopped being able to.
A capability that isn’t written down isn’t real
That’s a lot of weight to put on one spec review, so let me bring it back down to earth, because there’s a fair objection waiting here and I’d raise it myself. You’re not going to write a spec to fix a null check, and you shouldn’t. But SDD was never about the size of the change, it’s about whether the change is something the system needs to remember about itself. A one-off fix that lives and dies in a single commit doesn’t need a spec. The moment a fix encodes an expectation, though, that this input is now forbidden or this state must never persist, it has already stopped being a quick fix and become a capability, and a capability that isn’t written down isn’t real. It lives only in the code, ungated and unremembered, until the day someone refactors that region without knowing the behavior was load-bearing, and the bug you fixed six months ago walks right back in because nothing was ever standing guard over it.
Guessing is the expensive part
And here’s the part that gets the finance team’s attention, because all of this has a second payoff that shows up on the invoice. When you hand an agent a loose prompt, the first thing it spends money on isn’t building, it’s guessing. It burns tokens reconstructing what you probably meant, exploring the codebase, trying an approach, backing out of it, trying another, and every one of those turns is metered. A spec collapses most of that, because the intent is already on the page and the agent can build against it instead of paying to reverse-engineer it. The review compounds the savings. A contradiction caught in a spec is a one-line edit. Shipped into code, that same contradiction becomes a bug, and it rarely surfaces looking like what it is. It shows 5 up in production as a symptom three layers from its cause, and someone burns an afternoon chasing the wrong suspect before they find the real one.
You paid pennies to catch it on paper, or you pay for the afternoon.
The discipline that looks like overhead is the thing keeping the meter down.
There’s a quieter benefit, and it’s the one I didn’t expect. Everyone assumes working this way means thinking less, that you hand the hard part to the machine and become the person who types prompts at it. It’s been the opposite. Writing the spec is where I get to be an architect again. It’s the room where I actually think, where I can weigh a tradeoff instead of reacting to one, sit with a design until it’s right, and write down the things we deliberately chose not to build so the next version has somewhere to start. The agent took the part I was glad to give up, the typing, and deftly handed back the part I’d been missing. Who would’ve thought I needed guardrails to do my best thinking?
The same standard, all the way down
I wrote a few months ago, after a week at Salesforce Connections, that everyone was racing to put agents on top of their data without stopping to ask whether the data underneath was ready to be trusted. This is the same question, just moved one layer down. It’s not only whether the data an agent consumes is trustworthy, it’s whether the code and the tools and the pipelines we build around it are too. At eSage Group, data quality has been our reputation for a long time, and what these practices have given us is the ability to build the things that produce that quality with the same rigor we’ve always demanded of the data itself. Trustworthy data, built by tools you can actually trust, built by a process that earns it. The standard doesn’t change as you move down the stack. That consistency is the whole point.
The habit the tool won’t give you
So the thing I spend most of my time on now isn’t writing code, and it isn’t really writing specs either. It’s helping the people on my team learn to work this way, because none of it is the tool’s default. Hand someone Claude Code with no discipline around it and they’ll get speed and a 6 mess in equal measure. And it’s worth being clear about where the machine stops, because the cold review doesn’t decide anything. It surfaces the cracks and hands them back, and a human still decides which ones matter and what to do about each. That part hasn’t moved. If anything, working this way has made the judgment matter more, not less, because there’s more being produced and someone still has to be the one who knows what good looks like. That’s the part I’d want anyone worried about these tools to hear. They don’t replace the thinking. They raise the premium on it.
None of this is exotic. It’s a learnable, repeatable practice, and it’s becoming the difference between teams that get speed and teams that get speed they can trust. That second kind is what we’re building at eSage Group, one spec at a time. If you’re working through what disciplined AI-assisted engineering looks like in your own shop, or you want tools and pipelines built to that standard, let’s talk.