The Anemic Spec: Spec-Driven Development, AI Agents and Business Rules
A specification can be detailed and still leave business rules implicit.
The “Cancel” button is 120 pixels wide.
Take a meeting room booking service. The spec sets the button color, the confirmation message, the API to call and the response format. The agent even has an implementation plan.
An organizer wants to cancel ten minutes before their booking starts. The spec doesn’t say whether they’re allowed to. The cancellation deadline appears neither in the acceptance criteria nor in the generated tasks.
A business decision is missing. A few lines would be enough to describe it, but someone has to make it first.
With Spec-Driven Development (SDD), agents rely more heavily on specifications to produce code. So we need to be able to find in them the rules to apply, the examples that let us check those rules, and the points that still need clarifying.
The spec as a reference
SDD covers several practices. Birgitta Böckeler distinguishes three approaches: spec-first, where the spec comes before the implementation; spec-anchored, where it is kept for later changes; and spec-as-source, where humans edit the spec and the code is generated from it.
When the spec serves as a reference, a missing rule can have consequences for the software. A developer may recover it through their knowledge of the product, an existing test or a conversation. An agent can explore the repository and ask questions. Both can also move forward on an assumption without getting it validated.
If the tests carry the same assumption, they will confirm that the code respects it. The whole thing can then serve as a reference for further changes. A decision made for lack of information becomes hard to tell apart from a rule the product team actually wanted.
Rules that stay implicit
I call an anemic spec a specification that gathers information but leaves implicit the decisions the expected behavior depends on, and the means to check them.
The term echoes the Anemic Domain Model described by Martin Fowler: objects carry the data, while behavior is organized elsewhere. I’m borrowing that idea of responsibilities placed elsewhere. The analogy has its limits: with an Anemic Domain Model, the rules may be known and correctly applied. In an anemic spec, some of them have sometimes never been defined.
Here’s what I expect from a specification:
| Responsibility | What we need to be able to find |
|---|---|
| Describe the intent | The problem to solve, the desired outcome and the scope. |
| Spell out the decisions | The rules, when they apply, the exceptions and the trade-offs. |
| Enable verification | Examples and expected results able to expose a misinterpretation. |
| Flag uncertainty | Validated decisions, assumptions, open questions and what’s out of scope. |
| Explain where rules come from | Their source and the people who can clarify their meaning or change them. |
| Track changes | What changed, why, and which situations the change applies to. |
Not everything has to fit in a single file. A rule can be referenced in domain documentation, a contract or an acceptance scenario. What matters is being able to find it and knowing which version applies.
The trouble starts when this information stays in an expert’s head or in a conversation nobody can find. Adding pages to the spec doesn’t necessarily solve that.
Two possible implementations
Back to the booking. The functional part fits in a few lines:
Function: handle a cancellation request.
Input: booking identifier.
Output: request status.
Interface: Cancel button and confirmation dialog.
The organizer asks to cancel a confirmed booking, ten minutes before it starts. Two implementations can fill in this spec with different rules:
| Interpretation A | Interpretation B | |
|---|---|---|
| Rule added | Cancellation allowed until the start. | Cancellation allowed until 24 hours before the start. |
| Result | Accepted. | Rejected. |
| Tests written for this interpretation | Green. | Green. |
The spec can’t settle it. Each version added a rule that had never been decided.
Another LLM might suggest a third deadline or ask for clarification. It’s up to the product team to choose the rule that fits the need.
When reviewing a spec, looking for two incompatible business behaviors that the text both allows helps spot this kind of gap. Several architectures can satisfy the same requirement. In this example, the disagreement is directly about the user’s right to cancel.
Keeping uncertainty visible
Demanding every rule before starting assumes you know the need down to the last detail. What we mostly need are the decisions required for the scope at hand, and a clear view of what remains to be clarified.
Example Mapping separates rules, examples and unanswered questions. That separation helps avoid mistaking a well-written assumption for a validated requirement.
Suppose the product team settles on the 24-hour deadline. The spec could contain this:
R-12 - Cancellation by the organizer
Status: decision validated by the product team.
Origin: trade-off on the minimum cancellation notice.
Rule: the organizer can cancel a confirmed booking if it starts at least 24 hours after the time of the request. The notice is an elapsed duration, independent of local time.
Examples:
- Exactly 24 hours before: cancellation accepted.
- 23 hours and 59 minutes before: cancellation rejected.
- When rejected, the booking stays confirmed.
Out of scope: exceptions granted by an administrator.
Open question: what if the notification cannot be delivered?
The examples pin down the boundary and make it testable. They don’t cover the feature’s whole test strategy.
The notification problem stays open. You can experiment with the cancellation rule without having solved it, as long as you know what you’ll be able to evaluate and what will remain incomplete.
Distinguishing between a validated decision, an assumption to test, an open question and a superseded decision lets you work without giving every line of the document the same status.
Versioning keeps track of changes. Their business scope needs stating too. If the cancellation deadline changes, the new rule can apply to future bookings while leaving existing ones under the previous terms. The commit date isn’t enough to define that policy.
Feedback loops
Feedback starts during implementation. Writing the code can reveal a contradiction, an edge case, a technical constraint or a distinction missing from the model. The spec has to be able to evolve from these discoveries.
Kent Beck criticizes approaches that assume implementation will teach us nothing that could change the spec. Work on behavior continues during development, then with feedback from use.
We have two things to check:
- Conformance: the software respects the decisions as stated.
- Relevance: those decisions produce the intended outcome.
Tests can check the 24-hour rule. User feedback may teach us that this rule stops them from releasing rooms that would otherwise sit empty. The software then respects the spec, but that feedback may lead us to revisit the rule.
When a gap appears, the team has to decide whether to fix the code, revisit the rule or keep exploring. Automatically updating the spec to match the code could cement a mistake.
Organizing spec reviews
Having another LLM review a spec can help find contradictions and counterexamples. Agreement between several models doesn’t tell you whether a rule fits the business.
I prefer to ask for specific objections:
Rule in question: ...
Two possible interpretations: ...
Situation that tells them apart: ...
Consequence for the user: ...
Information or decision needed: ...
The team can then fix, experiment with or postpone the point raised. A string of rephrasings and hypothetical cases can also drag the review out without helping anyone decide. The review can stop when the team has the decisions needed for the next increment and knows how to evaluate the result.
The amount of text matters too. In her SDD trials, Böckeler describes a reading load that is sometimes out of proportion for small tasks. If the generated volume exceeds what the team can examine, some parts risk being approved without a real review.
Domain experts and the product team review the rules and expected outcomes described in the spec. Developers review the model, the constraints and their technical consequences. Testing work brings counterexamples and sharpens the observable results. The same person can contribute to several of these activities.
To make this review easier, a rule should be easy to find, along with its rationale and examples. Copying it into five files multiplies the places to fix at the next change.
What DDD brings
Domain-Driven Design (DDD) helps pin down the vocabulary shared with the business (Ubiquitous Language), the boundaries of the model and the invariants to protect. A “cancellation requested”, a “cancellation accepted” and a “booking cancelled” can refer to different facts. Lumping them into a status field without spelling out how they relate leaves part of the behavior undefined.
Bounded Contexts define where that vocabulary applies. Work on Aggregates helps define the boundaries within which invariants must hold. Behavior-Driven Development (BDD) and examples provide concrete situations to discuss these rules and check them.
This work is done with the people who know the domain. Sections titled “DDD”, “Aggregates” or “invariants” in a document don’t guarantee that the corresponding decisions have been made.
Before handing a spec to an agent, I want to be able to check its rules, understand the trade-offs and spot the uncertainties. Spec review relies on examples to check that the described behavior meets the need. It starts again every time feedback leads to changing a rule.
References
Spec-Driven Development
- Birgitta Böckeler, Understanding Spec-Driven-Development: Kiro, spec-kit, and Tessl, martinfowler.com, October 2025: the three approaches, spec-first, spec-anchored and spec-as-source, and the reading load observed on small tasks. martinfowler.com
- Kent Beck, LinkedIn post on descriptions of Spec-Driven Development: the critique of approaches that assume implementation will teach us nothing that could change the spec. linkedin.com
Domain modeling
- Martin Fowler, AnemicDomainModel, martinfowler.com: objects carry the data, behavior is organized elsewhere. martinfowler.com
- Martin Fowler, BoundedContext, martinfowler.com: where a vocabulary applies. martinfowler.com
- Vaughn Vernon, Aggregates, excerpt from Implementing Domain-Driven Design (Addison-Wesley, 2013), InformIT: the boundaries within which invariants must hold. informit.com
Examples
- Matt Wynne, Introducing Example Mapping, Cucumber, December 2015: separating rules, examples and unanswered questions. cucumber.io
The booking scenarios are fictional. The charts are conceptual; they do not represent measured results. Cover illustration generated with AI.