Spec-driven development: why AI code misses what you meant

When the code is right and the answer is wrong

A notebook page showing how ambiguous prompts lead AI models to produce code that quietly misses intent, and why late discovery costs more.

The AI writes your function in thirty seconds. It compiles. The tests pass. Then you run it on real data and it does something different from what you asked.

Maybe it handles a missing value by returning zero instead of raising an error. Maybe it silently rounds a number that should never be rounded. Maybe it reaches out to an external service you never intended it to touch. The code is not broken the way a bug is broken. It is broken the way a misunderstanding is broken: quietly, and only obvious once the consequences arrive.

That gap, between what you typed and what you meant, is the central problem of using AI to generate code. And the model is not the weak point. Your instructions are.

A 2026 study on AI code generation found that ambiguity in requirements consistently degrades generation quality across all tested models (arXiv cs.SE). The models cannot detect or resolve that ambiguity on their own. The same ambiguous prompt produces implementations that behave differently from each other. You could ask the same question twice and get two programs that agree on the happy path but quietly disagree on every edge case.

Why this costs more than a rewrite

The software engineering body of knowledge, SWEBOK, covers this under Software Requirements. That section is about how requirements are found, written down, and checked before code is written. The lesson has not changed in decades: the cost of a misunderstood requirement grows the later you catch it. Find the mistake in the specification, and you fix a sentence. Find it after deployment, and you fix a system.

AI agents make code arrive faster. They do not change that curve. A 2026 paper from Microsoft Research described the core challenge for reliable AI-generated code: the gap between informal natural-language intent and precise program behaviour (arXiv cs.SE, Microsoft Research). AI agents amplify that gap. They do not close it.

When you ask a model to "add a payment function", the model writes something. It probably compiles. But "payment function" can mean many things depending on your currency rules, your error-handling policy, and your data types. The model picks one interpretation. It generates code for it. It does not tell you which interpretation it chose. It does not ask.

The consequence is that more code in the world does not mean better code. It means more code that needs checking. And checking code for intent misalignment, rather than simple bugs, takes longer.

Researchers have tested this pattern across multiple frontier models and it holds regardless of which one you use. The answer is a better starting point: written, structured, and clear before the model starts.

What a spec is, and what it is not

A notebook page contrasting a vague ticket with a structured spec, showing how a spec turns intent into a verifiable contract.

A spec, in this context, is a short structured document that makes your intent checkable. It is not a README, which describes what a project is. It is not a ticket description, which records what someone wants done. It is not a code comment, which explains what the code is already doing. It is a set of statements precise enough that you, a colleague, or the model itself could use them to verify whether a piece of code matches what you asked for.

Think of it as a recipe before you start cooking. A recipe does not tell you which chef to hire or which pan to use. It tells you what goes in, in what amounts, what the result should look like, and what "done" means. Without it, two cooks working from the same verbal instruction will produce two different dishes. Both will be convinced they followed your directions correctly. That is not a failure of skill. That is a failure of specification, and the cooks are not to blame.

Spec-driven development, applied to AI code generation, means writing that recipe before you ask the model to cook. The spec is not a formal document for a specialist. It is a short plain file that closes the doors you do not want the model to walk through.

One way to see the difference: a ticket says "we need a function that handles payments". A spec says what the function receives, what rules it follows, and what the result looks like for two specific inputs. The ticket is an intention. The spec is a contract.

The three things a spec must contain

A notebook page listing the three parts of a useful spec and citing a study showing structured preambles cut security findings sharply.

A useful spec for AI code generation has three parts. Each one removes a category of guesses the model would otherwise make without telling you.

  1. Inputs. What data arrives at this function, in what format, and what are the edge cases? If you write "accepts a date", the model might accept a string, a Unix timestamp, a datetime object, or a locale-specific formatted value. All of those are, technically, "a date". Specify the type, the format, and the limits. "The function receives a Unix timestamp as an integer. Zero and negative values are invalid and must raise an error." Now the model has one door to walk through, not four. That one sentence closes more ambiguity than a paragraph of vague description.

  2. Constraints. What must this code not do, and what rules govern it? This is where most prompts are thinnest. "Do not make external network calls" or "all monetary values are integers in the smallest currency unit, never floats" are rules the model will not infer from a vague description. The OWASP Top 10 for LLM Applications is a practical security checklist for teams building with AI models. One item it flags is what it calls improper output handling. That is what happens when you use a model's output without checking it against what you actually asked for. Constraints in your spec give you something concrete to check against. Without them, that check has nothing to grip.

  3. Expected behaviour. What does "correct" look like for at least two concrete cases? One happy path and one edge case. "Given the integer 1700000000, the function returns the string '2023-11-14'. Given a negative integer, it raises a ValueError with the message 'invalid timestamp'." A model with those two examples can check its own output against them before returning. A model without them has no anchor.

The three parts work together. Inputs tell the model what it is working with. Constraints tell it what it is not allowed to do. Expected behaviour tells it what success looks like. A model that has all three can fail in far fewer ways. A model that has none of them can fail in more ways than you would think to check.

A 2026 pre-registered evaluation tested five frontier models. Adding a structured specification preamble to prompts reduced independent security scan findings from 53 to 11, compared to bare prompts (arXiv cs.SE). The spec did not change the model. It changed what the model had to work with, and the results at every stage of the quality check were different.

That drop, from 53 findings to 11, is not a marginal improvement. It is the difference between code you can ship and code that needs a full audit. It came from a document you could write in the time it takes to make a coffee.

How it runs in practice: one agent, one spec

A notebook page showing the spec-model-code-check loop that makes spec-driven AI development work in practice.

In my own projects, the agent that handles code generation reads a short spec file before it writes anything. The file carries all three parts: expected inputs, constraints, and concrete examples of correct behaviour. The agent's instructions tell it to compare its generated output against the spec before returning a result. When I added that file to a task that converts timestamps for financial records, the rate of mismatched outputs on test data dropped sharply. The cases that still failed were immediately traceable to a constraint I had not written down. That traceability alone was worth the effort.

The sketch I use to explain this to teams is a single arrow from "spec" to "model" to "code", with a loop from "code" back to "spec". The loop is the point. Without the spec, there is nothing to loop back to. You end up checking the output against your memory of what you asked, which is a remarkably relaxed quality-control process.

The short version

Inputs, constraints, and expected behaviour in a short structured document, written before you reach for the model: that is spec-driven development, and that is how you close the gap between what you typed and what you meant.

The practical rule is simple. If you would be annoyed to rewrite the code because the model guessed wrong, write the spec first. If the task is a throwaway script you can eyeball in thirty seconds, the spec is optional. The spec earns its place when the cost of a wrong guess is higher than the time to write three clear sentences. That cost includes debugging, rework, and any silent error that reaches your users before you do.

Most tasks in a production system meet that bar. Most prompts written today do not.

A question worth sitting with

Think about the last time an AI generated code that was technically correct but missed what you actually needed. Which part was absent from what you asked: the inputs, the constraints, or the expected behaviour?

Sources

The post on one page
The post on one page