The gate stands before the work.

INSIGHTS · VSDD & quality

VSDD — Verified Spec-Driven Development

Spec first, test first, a review that pushes back. Why “done” needs two questions instead of one.

The build is green, every test passes — and the feature is still wrong. Not broken: wrong. It does precisely what nobody needed.

The run-up is the same almost everywhere. Two weeks of work, a clean pull request, forty green tests, two approving reviewers, merged on Thursday. In Friday's demo somebody from the business side says one sentence: “Oh — that isn't what we meant.” Then five people spend forty minutes deciding whose fault it is. It is nobody's fault. The code does exactly what the ticket said. The ticket said something the customer did not mean.

The uncomfortable part is not the mistake. It is the mood in the room afterwards: two weeks of work, nobody cut a corner, and somebody still has to say it cannot stay like this. That kind of conversation does more damage than the code did.

Green is not a verdict on correctness. Green means the code agrees with an expectation somebody wrote down. If the expectation is wrong, green is just a faster way to be wrong — and the better your coverage, the more reliably you set the mistake in concrete. This is where VSDD starts: Verified Spec-Driven Development. Not another layer of testing. A second question.

Writing the spec is the design work

The usual picture of a spec is a companion document: you know what to build, and you write it down so somebody else can implement it. In that order the document really is dead weight. It repeats what was already clear, and it goes stale the moment anyone starts typing.

The order is simply wrong. The design happens while the spec is being written. Every vague spot you notice as you write is a decision nobody would otherwise make deliberately — it still gets made, at four in the afternoon, inside an if-statement, by whoever happens to be at the keyboard, with no record and no question asked.

A sentence like “the user is notified when something important changes” looks harmless and contains three open decisions. Which user — the author, the assignee, everybody involved? What counts as important — any edit, the state only, certain fields only? And what does notified mean: a dot in the interface, an email, both, immediately or batched? Three questions, ten minutes. In delivery they become three assumptions, and two of them are wrong.

HOW IT ARRIVES

"The invoicing module needs to be more flexible."

HOW IT BECOMES BUILDABLE

"Accounting issues one consolidated invoice per quarter for a customer with several projects, itemised by project."

The same wish, written down twice. Only one of them can be built.

There is one reliable test for a spec: it is written for somebody who was not in the room. Hand it to a colleague from another team. If they ask how to build it, the spec is good. If they ask what it means, you have just saved two days.

And it is not written once and filed. The spec is kept current: the moment the implementation departs from it, one of the two is wrong, and somebody has to decide which. Avoid that decision long enough and you end up with both — a document nobody believes, and a system nobody can explain.

Test first — and a review that pushes back

If the spec is the design, the tests are its teeth. A criterion you cannot turn into a check is not a criterion, it is a mood. “The export should be performant” is a mood. “5,000 rows in under two seconds, measured at the 95th percentile” is a criterion. The difference between those two sentences is not precision for its own sake; it is whether anyone has to argue about the result later.

So test first does not mean coverage first. It means: before code exists, it is settled how you would recognise the outcome. Write the test afterwards and you write it against what the code does. That is an honest description of the implementation and a worthless judgement on the requirement. A green suite over the wrong behaviour is built exactly like this — not out of carelessness, but out of the wrong order.

Then comes the part most teams skip, because it is uncomfortable: the adversarial review. Not a friendly “looks good to me” under a pull request, but a pass over the spec before a line of code exists, with one instruction: break it. Find three readings that all fit this text and produce three different products. Name the case that isn't in there.

A gate does not slow the work down — it pins down what would otherwise run on.

A spec nobody can misread is half the implementation.

It takes twenty minutes and it feels wrong, because it looks like wilfully pulling apart a finished document. That is the point. A misunderstanding caught in review over the spec costs a paragraph. The same misunderstanding after the merge costs a sprint. In front of the customer it costs trust, which is the one currency in a project you cannot order more of.

It helps to say this out loud: an adversarial review is not distrust of the person who wrote the draft. It is the last point at which being wrong costs nothing but twenty minutes. Teams that have felt that once end up defending those twenty minutes harder than anyone.

Why this order has become more important in the last few years rather than less fits into one sentence. A person handed an incomplete brief asks a question. An agent does not. It fills the gap plausibly, quickly and with complete confidence — and delivers clean, tested code for a requirement nobody ever made.

Verified means two questions

In most teams “done” is answered with a single question: was it built the way it was specified? That question can be answered without leaving the room — code against spec, tests green, tick. It is also the only question a status column has ever been able to answer.

The second question cannot be answered from the inside: does it deliver the outcome we built it for? The same feature can answer yes to the first and no to the second. That is the case at the top of this article, and it is not an edge case. It is the normal case anywhere more than two handoffs sit between the ask and the implementation.

Which is why “verified” has two stages rather than one. The first is a claim: the implementation says it delivered what was specified. The second is a confirmation: somebody who needs the outcome says this is the outcome. Two senders, two moments. Where both collapse into the same tick, the tick means nothing.

"Done" answers one question. Built — and built right — are two.

In one place the model in angajuu already keeps those two ends apart. The implementation status of a product requirement carries four values, and the last one is verified. The Jira sync explicitly refuses to map any Jira status onto it — verification is a human judgement, not something that wanders in from outside and lands in a column.

What that checklist is not: the criteria belonging to the requirement itself. Today those live, if they get written at all, as prose inside the description — under a heading Claude is instructed to add while drafting. Prose in a text field can be read. It cannot be queried, it cannot be checked, and nobody is tracking whether it was met.

In progress In angajuu, acceptance criteria become first-class data: every requirement carries its own criteria, and fulfilment is recorded in two stages — as a claim from implementation, and as a confirmed acceptance.

That split is not bookkeeping. It is the difference between “we delivered” and “it works” — and therefore between a status report you read out and one people believe.

What to do on Monday

Not adopt a method, and certainly not a template. Take the next requirement that is coming anyway, and write down three things before anybody opens a ticket.

  • What is needed — in the words of the person who needs it, not in yours.
  • How you would recognise that it has been met. A number, a condition, an observable behaviour.
  • What is explicitly not included. That is the one everybody leaves out, and the one that saves the most argument.

Then hand that half page to somebody who was not there, with exactly one instruction: find the place where you would have to guess. Twenty minutes. What comes back is not criticism of your writing. It is the list of decisions that would otherwise have been made during delivery — by somebody else, later, and without asking you.

And write down at the end who confirms that it works, and what they will look at. If nobody comes to mind for that question, that is the most useful thing you will learn all day: you have a requirement with no recipient, and green tests will not make it right.

The first time, a name will come to mind. The second time, you notice that this person would never find out if the feature quietly failed. That is the exact point where “done” stops being a claim.

How the same discipline shifts when an agent, rather than a colleague, builds from your brief is the subject of AI-driven development starts before the prompt — the context a model cannot guess, and why supplying it is product work. And if you would rather see what a spec that holds up feels like in an ordinary week than read it as a method, A day in the dev team walks through one sprint day, from the ticket in the morning to the question of what the work actually covered.

Write the first sentence.

Free for 5 users, 5 projects, 200 requirements.

Start free