Spec-driven development without waterfall
Writing specifications that help coding agents, and keeping those specifications open to correction.
The attraction of spec-driven development is easy to understand. Give a coding agent a clear account of the intended behaviour, let it implement that behaviour, and assess the result against the account. There is useful engineering discipline here: consequential decisions become available for inspection before other work depends on them.
The difficulty is that a specification can be clear, executable and wrong. An agent can implement exactly what it says; tests derived from the same premise can pass; the resulting software can still fail to meet the need that justified building it. A different agent agreeing with the first does not resolve this problem unless the review brings some independent basis for judging the expected behaviour.
There are therefore four separate judgements to make:
Scroll horizontally to see all columns.
| Question | What must be assessed |
|---|---|
| Is the spec good enough? | Whether its rules express a justified need and are sufficiently clear, consistent, feasible and verifiable for the next commitment. |
| Is the spec good enough for this agent? | Whether the agent can retrieve the current contract, understand its discretion, work in the available environment and produce useful evidence. |
| Does the code correctly implement the spec? | Whether actual behaviour conforms to the applicable rules, including failure effects and shared constraints. |
| What if the spec was faulty? | Whether evidence challenges the requirement itself, and which decisions, code, tests and released effects need correction. |
This guide treats a specification as a maintained contract for a capability. Decide what the next increment must do, on what evidence, and which choices remain open. Revisit a decision when new evidence challenges its basis, before more work depends on it.
For a practical entry point, jump to the starting structure, the small contract or the adoption trial. The research and its limits are in Appendix A.
1. Start with the next consequential question
"Administrators can export filtered invoices" sounds like a bounded request. An agent can turn it into an endpoint, a background worker, a download link and a set of tests. Along the way, it must settle what "filtered" means, which version of the data belongs in the file, when permissions apply and what a failed export leaves behind.
Those choices become behaviour that people encounter and other code may depend on. If nobody supplied the answers or bounded the assignment, the implementation has acquired commitments nobody deliberately made.
The first useful step is to identify the uncertainty controlling the next commitment. Sometimes that calls for a specification; sometimes it calls for looking at the system, talking to its users or trying something small enough to discard.
Scroll horizontally to see all columns.
| Situation | First action | Decision enabled |
|---|---|---|
| Unclear user problem or value | Observe the work and test a proposed outcome with users. | Is this capability worth building? |
| Clear value, uncertain feasibility | Run a bounded prototype, benchmark or design experiment. | Can the required guarantee be achieved? |
| Existing system, unclear behaviour | Trace one capability and characterise its consumers and effects. | What must be preserved or deliberately changed? |
| Defect with unclear cause | Reproduce it and investigate competing explanations. | Is the fault in code, intent or an assumption? |
| Clear, bounded behavioural change | Agree its delta, examples and preservation requirements. | Is this increment ready for implementation? |
| Mechanical local change | Make the focused change and check its result. | Did the intended local correction occur? |
Several of these may apply at once. Start with the question whose answer could invalidate the most dependent work. Give an experiment a question, a time limit and an observation that would change the decision. Requiring a complete delivery specification before that experiment would demand the very knowledge it is meant to obtain.
Establish what the existing system actually promises
In an existing system, the temptation is to ask an agent to describe the code and call the result a specification. That description can be useful evidence, but it needs four distinctions:
- Observed behaviour is supported by code, tests or operational evidence.
- Required behaviour is an actual promise that should be retained.
- Accidental or defective behaviour has been observed without necessarily being approved.
- Proposed change is the deliberate difference to introduce.
Characterisation tests help retain the evidence while intent is resolved. Promoting a generated account of current code directly into an approved requirement can instead give bugs and incidental mechanics the standing of a promise.
For a defect, obtain a reproduction or other credible evidence before deciding to edit the specification. The intended rule may already be right, in which case it can stay. A missing business case requires a decision about the expected result; the existing implementation cannot supply that decision merely by having produced one.
Migrations make this distinction especially consequential. Before dependent implementation, identify what must hold while versions coexist, work remains in flight, data already exists and recovery is under way. Individually correct local specifications can still disagree over shared state. Someone must own the interaction, and its invariant must be explicit.
2. Decide when to commit without freezing discovery
A large delegated assignment can turn one unanswered question into many dependent implementation choices before anyone reviews the first. That gives early investigation a practical purpose. Exposing a question, investigating it and committing to an answer remain three different acts, however; treating them as one can freeze discovery before the evidence warrants a decision.
For invoice exports, exposing the question means recognising that access revocation might affect downloads. Acquiring evidence means examining user expectations, existing contracts and technical feasibility. Committing means adopting a guarantee that both the implementation and its consumers may rely on. The more expensive that guarantee will be to reverse, the earlier its basis deserves investigation. The commitment itself should follow when the evidence and dependencies justify it.
Deadlines sometimes force decisions while uncertainty remains. Record the assumption and its consequences. A deadline changes the time available to decide; it does not turn an assumption into a fact.
Fowler's January 2026 commentary emphasises experimentation and feedback in specification, while Agile's principles support frequent delivery and changing requirements. These provide methodological foundations. Neither establishes a universally optimal planning horizon.
Match detail to the commitment
A project needs enough direction to make local work coherent, and an increment needs enough precision to be implemented and assessed. Giving distant possibilities the same detail as imminent work obscures which decisions are actually ready to bear dependencies.
Scroll horizontally to see all columns.
| Horizon | Make explicit | Keep provisional |
|---|---|---|
| Project | Problem, outcomes, known binding constraints, critical invariants and major risks. | Complete feature catalogue, speculative abstractions and distant task plans. |
| Next increment | Observable behaviour, applicable failure cases, shared contracts and acceptance evidence. | Independent later capabilities and reversible implementation choices. |
| Later possibilities | Candidate outcomes, dependencies and unresolved questions. | Detailed promises that depend on discoveries not yet made. |
This still requires system-level thought. A small increment handling private data needs its isolation rules now; a high-risk consistency decision may need a model before any implementation. The relevant measure is the consequence of being wrong, not the apparent size of the feature.
For each consequential open decision, retain the evidence, its owner, the work depending on it and the event that should resolve it. When an agent reaches that dependent work, the available choices are to resolve the question, exclude the work or authorise a bounded experiment. Leaving the answer blank must not silently grant authority to decide the product's behaviour.
Preserving an option often means leaving a capability unimplemented. A generic interface, plugin system or configurable framework is itself a set of design commitments. Uncertainty alone does not justify one.
Let delivery return evidence to discovery
An accepted investigation returns findings to the next decision; release follows acceptance of a delivery increment. Returning through this loop reopens the affected decision. It need not restart the project, and it may end by removing a proposed feature altogether.
Patton describes discovery and delivery as concurrent work involving the same team, explicitly warning against separate teams handing off finished decisions. The same concern applies when the division is between a planning agent and an implementation agent: the assignment must retain a route for questions and discoveries to change the proposed work.
Waterfall risk grows as commitments accumulate faster than feedback can change them. Dividing implementation into short sprints cannot fix a process that specifies the entire product upfront and then treats discoveries as deviations. The next increment needs a precise contract, with a way to revise it when its basis fails.
3. Write a bounded specification for the agent
A useful specification distinguishes acceptable results from plausible mistakes. An agent also needs to retrieve the current decisions, tell obligations from suggestions and recognise questions it has no basis to answer. These demands favour precision about consequential behaviour within a bounded scope. They say little about document length: pages of happy-path description can still omit the one rule that determines whether the implementation is acceptable.
Include what determines the result
The following are prompts for judgement, not a form whose empty sections must be filled. A local correction should remain local.
Purpose and outcome. Who or what benefits, the problem being addressed and how success will be observed. Retain the rationale relevant to the decision.
Scope and preservation. Behaviour to add or change, relevant non-goals and existing promises that must remain true. Distinguish excluded work from prohibited behaviour.
Domain terms. Definitions where ordinary language permits different interpretations: "duplicate", "active", "latest", "owner", "completed". Use the terms consistently.
Inputs and outputs. Accepted values, units, identity, required fields, defaults and observable results. Include schemas or signatures when a component or consumer depends on them.
Behavioural rules. Preconditions, state changes, postconditions and invariants. Use stable identifiers where they help connect rules to decisions and evidence.
Boundaries and failure behaviour. Applicable empty, invalid or oversized inputs; partial failure; permissions; retries; ordering; concurrency; time and lifecycle. Select the categories that affect this work.
Binding constraints. Compatibility promises, supported environments, mandated dependencies and architectural boundaries, with their reasons and sources.
Quality requirements. Relevant latency, capacity, resource, accessibility or operational obligations, including the conditions and means of assessment. "Fast" and "robust" cannot decide acceptance on their own.
Acceptance evidence. Agreed scenarios, representative examples, boundary cases, counterexamples and properties. Link to verification that can assess the rule without taking its expected result from the proposed implementation.
Decision state. Accepted rules, provisional assumptions and open questions. For consequential unknowns, identify who or what can resolve them and which work depends on the answer.
Consider "complete within two seconds". To make it a dependable performance requirement, specify the operation, workload, environment and measurement convention. If those remain unknown, commission the measurement or mark the target as provisional. A precise number cannot compensate for unspecified conditions.
Negative obligations deserve equal attention. "Exporting must not mutate invoices" restricts behaviour; "scheduled exports are deferred" restricts scope. Likewise, a rejected batch leaving no partial writes may be central to correctness. Folding all these statements into a list of non-goals would lose the distinction between work that is absent and behaviour that is forbidden.
NASA's requirements guidance supplies established checks for clarity, consistency, rationale, traceability and verifiability. Engineers can use those checks selectively without adopting the whole systems-engineering process.
Give supporting material a clear role
An agent may need design notes, repository guidance and a task plan as well as the specification. Keep their roles clear and their relevant contents accessible. A suggested approach can otherwise become indistinguishable from a binding constraint, while a real constraint can disappear because it lives in another file.
Keep imagined future features as hypotheses or backlog items until evidence and dependencies justify commitment. Record guessed product decisions as uncertainty, with the decision still needed. Repeating a generated assumption must not promote it into an accepted rule.
Put proposed private classes, helpers, file layouts or algorithms in design notes, or leave them to implementation. Make an approach binding only when a real constraint or justified design decision requires it, and record the reason. A task plan can carry the coding sequence; required domain protocols and state transitions belong in the contract.
Keep necessary working instructions and repository conventions in the task brief or repository guidance. Present the current contract with links to its decision history, clearly marking rejected and superseded alternatives. Reference discoverable code at the relevant boundary, explaining surprising facts and preservation requirements without duplicating a directory inventory. For other references, give the agent precise paths, sections or versions, explain what each governs and check that it can retrieve them.
Keep test setup, selectors and adapters in test code, with agreed expected behaviour in the specification or its canonical executable examples. Replace confident adjectives with criteria. Select examples that distinguish materially different interpretations.
A public API's error codes, a message schema, memory-ownership rules or a mandated numerical algorithm may define correctness. Whether a returned buffer survives the next iterator call is an observable contract; how a private buffer is allocated is usually a design choice. Both are technical, but they impose different obligations on callers and implementers.
The same distinction matters when work is divided among implementers. Shared interfaces and interaction invariants need agreement before dependent implementation. Private methods do not all acquire that status merely because several agents are working on the project. Where an agreed design companion is required, supply it: a constraint the agent cannot retrieve is an inadequate basis for delegation.
Separate precision, coverage and prescription
"More detail" can mean three different changes. They should be assessed separately.
Scroll horizontally to see all columns.
| Dimension | Recommended level |
|---|---|
| Semantic precision | High wherever alternative interpretations change a consequential result. Exact comparisons, units, time boundaries and failure effects often matter. |
| Scope coverage | Deep enough for the next commitment and the system invariants it touches. Later capabilities can remain provisional. |
| Implementation prescription | Require mechanisms where a binding constraint or justified design decision calls for them. Leave other implementation choices open. |
A narrow feature can have precise behaviour and substantial implementation freedom. That combination is useful: the implementer knows what must survive a design change without having to preserve every detail of the first design.
Two questions help test the boundary. Could two competent implementations satisfy the text yet disagree on an outcome a user or dependent component cares about? Clarify that outcome or explicitly delegate the choice. Could a substantially different implementation preserve every promise? Examine whether the prescribed mechanism is necessary.
These questions also expose a common ambiguity in the specification itself. Ordering that is explicitly unconstrained grants discretion; omitted ordering may simply be an oversight. An unresolved product question does not grant the same freedom as choosing a private data structure. State the distinction wherever it affects dependent work.
Add detail where a wrong guess would cause significant rework, break a consumer or invalidate the increment. If the answer lacks evidence, investigate it. Expanding the prose cannot settle what the author does not yet know.
For the invoice export, deciding whether membership and values reflect request time or processing time resolves a consequential ambiguity. Choosing a worker class leaves it untouched. The small contract below applies the same reasoning to a data transformation.
Start compactly, then justify additions
A starting structure can be as small as this:
# Capability or change
Status, scope/version and responsible decision-maker
## Purpose and scope
Outcome, included change, non-goals and promises to preserve
## Contract
Terms, applicable inputs/outputs, rules, invariants and failure behaviour
References to binding interfaces and constraints
## Acceptance
Decisive examples/properties and how the result will be assessed
## Open decisions
Assumptions, evidence needed and work blocked by unresolved questions
Adapt it to the repository. These are information roles, not five required files. GitHub Spec Kit's template also includes user scenarios, functional requirements and measurable success criteria; that makes it an example of a convention, not evidence that every section improves every assignment.
A paragraph earns its place by enabling a decision, preventing an important misunderstanding or making evidence accessible. Before removing it, check whether it contains a constraint, rationale or exception that would be difficult to recover. The reviewed research establishes no universal word count or mandatory template; its limits are set out in Appendix A.
Precision in a small contract
"Remove duplicate contacts" leaves four consequential choices unanswered: identity, retained record, output order and invalid-input behaviour. Naming a hash map in ContactDeduplicator settles a mechanism while leaving every one of those choices open.
The following hypothetical contract makes the decisions explicit. They are invented for this example; a real system would need domain agreement before adopting them.
Purpose: Collapse repeated entries before displaying an imported contact list.
Input: A finite ordered sequence of records containing a non-empty string
contact_id. Other fields are opaque to this operation.Rules: Equal
contact_idstrings identify duplicates, using exact case-sensitive comparison. Retain the first complete record for each ID, unchanged. Return retained records in their original relative order. Do not mutate the input.Failure: If any record lacks a valid
contact_id, reject the entire operation with an invalid-input error and return no partial result. Empty input succeeds with an empty result.Scope: Matching by email, merging fields and persistent writes are excluded. The algorithm is an implementation choice.
The acceptance examples now distinguish implementations that the original request would have left indistinguishable:
Scroll horizontally to see all columns.
| Input or condition | Expected result |
|---|---|
a/Ada, b/Bo, a/Amal in that order | a/Ada, b/Bo; the first record wins and order is retained. |
IDs a and A | Both remain; comparison is case-sensitive. |
| One valid record followed by a record without an ID | The whole operation fails; no partial output. |
| Empty sequence | Empty successful result. |
Here, a/Ada abbreviates an ID and another field; it specifies no wire format. The runtime signature and error representation come from the enclosing API contract. If there is no such contract, agree them before integration.
A compact table can express these examples. The rules also support broader checks: output IDs are unique under the stated comparison, retained records match their first occurrence, and applying the operation twice preserves the result. Those obligations remain the same whichever algorithm implements them. Tests should exercise the obligations without requiring a hash map.
4. Use BDD to discover and express acceptance criteria
"Export the filtered invoices" can sound settled until finance expects a snapshot and the developer expects whatever the database returns when the worker runs. A concrete example makes that disagreement visible: an invoice changes after the request is accepted but before the file is assembled. Which value belongs in the file? The answer changes the contract and may change the design.
Behaviour-driven development gives that discussion a place in development. It predates coding agents: Dan North's original account connects TDD with analysis and acceptance testing through behaviour and shared language, and recognises that a failing test may expose an outdated premise. Cucumber describes the practice as an iterative combination of discovery, formulation and automation, applied to small upcoming changes and revisited as questions arise.
BDD is optional. Where it helps, its examples can supply much of a specification's behavioural content without adding another document layer.
Let concrete cases expose disagreement
Example Mapping separates rules, examples, questions and deferred scope. Its value appears when apparent agreement dissolves under a particular case, as with the invoice that changes during export. The question becomes something the participants can answer and the implementation can later be checked against.
That requires perspectives capable of challenging one another. Domain expertise explains the need, development examines feasibility and boundaries, and testing probes examples and omissions. These are contributions to continuing collaboration; they do not require exactly three people or a new approval board.
An agent can propose edge cases, expose inconsistent wording and retrieve repository evidence. Three agents can examine different sources and find contradictions. Assigning them the personas of business representative, developer and tester does not, by itself, supply independent evidence of user intent. On a solo project, observations and domain sources still have to challenge the author's assumptions; simulated agreement cannot do that work for them.
Hold detailed scenario discussions close enough to implementation that the assumptions meet evidence promptly. Cucumber recommends discovery workshops near the start of the relevant story's development. Project-level risks and expensive feasibility questions may need attention earlier. Writing the entire product's scenarios before building anything would preserve the waterfall problem, however readable the notation.
Make scenarios part of the contract
Agreed BDD scenarios belong among the acceptance criteria: they state concrete situations and the outcomes required for acceptance. Keep the general rule with them. Otherwise a collection of examples leaves the implementer to infer what happens in every unlisted case.
Scroll horizontally to see all columns.
| Element | Export example | Maintained home |
|---|---|---|
| Behavioural rule | Each new download request requires current account authorisation. | Capability specification. |
| Acceptance scenario | Access is revoked before download; the request is denied and no invoice data is returned. | Specification acceptance criteria, or a referenced feature file that owns the scenario. |
| Other acceptance criterion | A stated workload must meet an agreed latency bound. | Specification, with its measurement method. |
| Verification implementation | Setup, download request, assertions and benchmark harness. | Test code linked to the criteria. |
The practice discovers and agrees the examples; the scenarios record them; test code connects them to the system. An automated scenario can therefore be both a readable acceptance criterion and an executable check. Neither every criterion nor every test needs Given/When/Then.
Give each rule and scenario one maintained home. If a feature file owns an example, reference it from the specification's entry point. Changes to test code must preserve the assertion's meaning; moving a scenario into an executable file does not relieve anyone of maintaining its relationship to the agreed outcome.
Choose the notation for the people who will use it
Gherkin provides a scenario notation, and Cucumber provides tools that connect scenarios to executable checks. Collaborative examples and ordinary tests can serve the same development practice without a Gherkin runner. In a Go library, domain-reviewed cases may become table-driven tests. Add the translation layer when the shared executable representation helps people review and maintain behaviour; if its only readers already work comfortably in test code, it may add little.
Where Gherkin is useful, describe observable outcomes and keep replaceable mechanics in the automation. The Gherkin reference distinguishes a business rule from the scenarios illustrating it and directs assertions towards observable results. An unchanged domain rule should usually survive a move from a web interface to an API. Browser interactions belong in the scenario when the interaction itself is required; elsewhere, selectors and clicks can conceal the obligation being tested.
Keep the examples alive during implementation
Automate selected examples at the boundary they concern, and establish that the checks detect the relevant violation. A discovered case may send the work back to the domain rule; an agreed case can remain as regression evidence. TDD supplies a smaller loop of failing test, implementation and refactoring within this work.
A meaningful passing check supports its expectation under the conditions exercised. That expectation still needs a sound basis. Adding Cucumber after implementation may produce useful regression tests, but examples guide development only when they participate in its decisions.
5. Assess the spec and decide what evidence acceptance needs
An export can contain exactly the specified columns and still be unusable for reconciliation. This is the distinction between verification and validation: verification examines conformance to the applicable contract; validation examines whether the requirements and delivered behaviour serve the intended need. An activity may inform both, but success in one does not settle the other.
Choose evidence while agreeing the contract, when an obligation can still be examined rather than merely handed to an implementer:
Scroll horizontally to see all columns.
| Claim to examine | Useful evidence |
|---|---|
| A permission rule produces the agreed result. | Domain-reviewed scenario and a check at the relevant boundary. |
| A transformation preserves an invariant across many inputs. | Property-based tests or fuzzing with an explicit oracle. |
| Interacting components agree on a message or API contract. | Consumer/provider contract and integration checks. |
| Failures and retries preserve a state invariant. | State model, fault injection or model checking where justified. |
| Latency or memory use stays within a bound. | Repeatable measurement under a specified workload and environment. |
For suitability, examine user and operational evidence: can finance complete its reconciliation with the exported data? Usability and accessibility may need both checks against stated criteria and observation of actual use. Those observations can challenge the criteria themselves.
Writing a latency requirement as a scenario does not remove the need to measure it under the agreed conditions. Nor does a collection of failure scenarios enumerate concurrent executions, or agreement between two components establish every system-wide property. The form of the prose cannot extend the reach of the evidence.
Amazon's formal-methods experience shows how precise models can expose distributed-system design defects beyond ordinary reviews and tests. The result remains about the represented system and stated properties; establishing correspondence with an implementation is further work.
There is another dependency beneath all this checking: the expected result. The test oracle problem concerns how to determine what the correct result should be. A second agent handed the same mistaken premise may faithfully reproduce it. Seek an independent basis in agreed domain examples, an external contract, a justified reference or a separately reasoned property. Examples explain interpretation, properties generalise obligations, and experiments challenge assumptions; choose the combination that addresses the risk.
Is the spec good enough for the next commitment?
Clarity is necessary, but it can make a wrong requirement exceptionally easy to implement. Review the draft against its purpose and evidence:
- Justified: Consequential rules and the intended outcome have a credible domain basis; reviewers can explain why they matter.
- Consistent: Rules agree with one another and with applicable external and shared contracts. Deliberate changes are identified.
- Sufficiently complete: The increment's important outcomes, failure effects and boundaries are covered, with remaining questions explicit.
- Feasible: Critical assumptions have supporting evidence, or investigating them is the bounded next assignment.
- Verifiable: Acceptable and unacceptable outcomes can be distinguished, and suitable evidence can be obtained.
Domain examples, user observations, external contracts and feasibility results can challenge the draft. Repeating its assertions cannot validate them. The review should end in a concrete choice: implement the bounded scope, investigate the uncertainty controlling it, or revise the contract.
An unresolved point blocks dependent implementation when different answers could change a promised outcome, break a consumer, violate a shared invariant or invalidate the work. Resolve it or narrow the assignment. Independent later capabilities can remain open, as can private implementation choices that preserve the obligations.
6. Give the agent a workable assignment, then review the result
A specification may be sound while the assignment is unusable. The rule can be perfectly clear in a document the agent cannot retrieve; the check can be appropriate for a dependency the environment cannot run. Changing the product requirement would fix neither problem. Delegation has to connect the obligation to the repository, the agent's discretion and the available means of verification.
Is the spec good enough for this agent?
State the work to perform now, the relevant repository state, where supporting material lives, what checks are available and which decisions the agent may take. Repository instructions supply working conventions; design records supply agreed mechanisms and their reasons. These roles can share a file if that makes the material easier to maintain.
Readiness belongs to the combination of spec, assignment, agent and environment. Check that:
- Current rules and critical constraints are accessible, and the agent can distinguish governing references from superseded decisions.
- The relevant repository and tools can be used; unavailable dependencies and checks are identified.
- Scope, preservation requirements and implementation discretion are explicit, including product questions on which dependent work must wait.
- The assignment fits both the agent's ability to retain relevant context and the reviewers' ability to examine the result.
- Expected verification can be performed. If it cannot, the limitation leads to a suitable investigation or a narrower deliverable.
For consequential or unfamiliar work, ask for a brief read-back: the important outcomes, their governing rules, materially different interpretations, and the intended checks. Repository questions should be answered through inspection. Use this to find concrete gaps, not to certify an agent because its paraphrase sounds convincing. A small trial can expose capability or environment problems that the read-back leaves uncertain.
Supply the authoritative contract, relevant design decisions and a task record for questions and evidence, using the repository's existing organisation. Keep current obligations, historical reasons and proposed work distinguishable. Anthropic's context guidance likewise favours relevant information while warning against both vague direction and brittle instruction recipes.
Implement a path that reaches the relevant boundaries
A vertical slice should reach an observable result through the integration boundaries that matter to it. For the export, that might be one authorised request through to a complete downloadable file, including the denial and failure cases that bound the behaviour. Synchronous and asynchronous implementations remain possibilities; either must satisfy the contract.
Keep the increment small enough to examine its implementation and evidence together. Establish that important checks can fail for the violation they are intended to catch, then record what ran and what it established, including limits of the environment and fixtures.
Does the code correctly implement the spec?
Begin with an identified contract version and code revision or recorded workspace state. Attach the evidence to that code state, the relevant configuration and the checks performed. A result obtained before a change may no longer describe the reviewed implementation; rerun the checks whose evidence the change could invalidate.
The review has four parts:
- Connect consequential obligations to the implementation paths responsible for them and to their evidence. Include preserved behaviour and shared invariants.
- Follow those paths through success, rejection, partial failure and relevant interactions. Look for omissions, unintended side effects and behaviour introduced outside the agreed scope.
- Inspect the checks. They need to reach the relevant boundary, use justified expectations and detect the claimed violation. Use a targeted negative control where necessary to establish that a critical check does useful work.
- Record each assessed obligation as supported by stated evidence, violated or unverified. Explain exclusions and preserve the conditions and limits of the result.
Check for obligations the suite never exercises. Critical unverified obligations remain unresolved for acceptance.
Record who owns acceptance and what they decided: accept the bounded deliverable, return it for correction, or defer or narrow it pending evidence. Acceptance requires resolving violations and unknowns that block that deliverable. Changing a requirement invokes the decision process in section 7; it is not an implicit escape from a failing check.
Take the small contract through acceptance
Return to the contact-deduplication contract from section 3. Suppose the next assignment is to implement that operation in an existing library. Supply contract version 1, the enclosing API's signature and error convention, the relevant repository paths and runnable checks. Email matching, field merging and persistent writes remain excluded. The agent inspects those boundaries and undertakes the library change; the assignment has an observable result small enough to review together with its evidence.
The following acceptance record is hypothetical. The labels contract-v1 and code-c1 identify illustrative states, not artefacts produced for this guide.
Scroll horizontally to see all columns.
| Record | Hypothetical review result |
|---|---|
| Basis | code-c1 assessed against contract-v1 and the enclosing API, using the recorded supported-runtime configuration. |
| Selection and ordering | Example and generated-input checks support exact case-sensitive identity, first-record retention and original relative order. Review follows the corresponding selection and output paths. |
| Preservation | Checks compare complete retained records and input state before and after success and rejection; review examines copying and mutation paths. |
| Rejection and empty input | Missing, empty and non-string IDs, including after valid records, produce the agreed error without partial output. Empty input succeeds. Checks reach the public operation. |
| Check sensitivity | Targeted mutations that retain the last duplicate or return a partial result cause the relevant checks to fail. The recorded passing results apply to the restored code-c1. |
| Decision | With no blocking violation or unverified obligation identified for this bounded change, the responsible maintainer accepts it for merging. Excluded capabilities remain outside this decision. |
The record identifies what was accepted and the evidence supporting that decision. It needs neither a promise about every future contact feature nor another discovery cycle before this change can proceed. If the code or applicable contract changes before merging, reassess the affected evidence.
7. Diagnose disagreement before changing the contract
The specification states intended behaviour. Code, deployed configuration and observation supply evidence of actual behaviour. When they disagree, editing whichever is easier can hide the information needed to identify the fault.
Classify the finding first:
Scroll horizontally to see all columns.
| Finding | Response |
|---|---|
| Code violates a valid rule. | Fix the code, retain the rule and add or strengthen the relevant check. |
| A check misrepresents a valid rule or exercises the wrong boundary. | Correct and rerun the verification; retain the justified requirement. |
| A rule misstates the intended need. | Revisit the domain decision, then revise affected examples and implementation. |
| The design is inefficient but its behaviour remains right. | Change the design while preserving the contract. |
| Requirements are mutually incompatible. | Expose the conflict and decide which commitment changes. |
| A new case has no agreed answer. | Preserve the counterexample and resolve intent before dependent work proceeds on a guess. |
| An environmental assumption fails. | Reassess the affected guarantee and recovery behaviour. |
| A previously valid need has changed. | Record the new requirement and transition obligations, preserving why the earlier decision was valid. |
An explicit change in required behaviour can justify changing a test. Weakening the expectation solely to accommodate a defect destroys evidence. Approval cannot make an incorrect requirement correct, but discovering an error does not silently revoke a promise to consumers either.
What if the spec was faulty?
Faithful implementation of a faulty requirement can produce the wrong result. Conversely, deviation from that requirement does not, by itself, establish a code defect: the code may already deliver the intended behaviour. Assess actual behaviour and the intended outcome separately before deciding what to change.
When evidence undermines a requirement:
- Preserve the counterexample, the applicable rule version and the evidence showing why the expected outcome is wrong, missing or impossible.
- Revisit the domain decision with the relevant expertise. Establish whether the cause is an original mistake, a changed need or a failed environmental assumption.
- Identify affected examples, checks, code, dependent work and consumers. For shipped behaviour, examine consequences for existing data and operations before choosing recovery steps.
- Record the corrected decision and its reason, update the current rule and acceptance evidence, and reconcile dependent assignments. Change code where its behaviour conflicts with the corrected contract.
- Check conformance to that contract and validate the disputed outcome using evidence beyond the old spec. Preserve unrelated decisions and the history of the correction.
After a correction, maintain a readable current contract. Mark cancelled requirements as cancelled, and give resumed agent sessions the active scope and decisions. Decide which completed change records become history and how accepted changes enter the current contract. Spec Kit leaves that maintenance strategy to teams; OpenSpec supports updating planning artefacts during implementation. The responsibility to reconcile them remains with the team.
Include work already running. Suppose an agent is implementing contract version 1 when a corrected permission rule becomes applicable in version 2. Identify and pause the affected work until the agent has the changed rule and can revise its plan; independent work can continue.
At the next review, identify the version actually used and reconcile the implementation and evidence with the applicable contract before acceptance. Updating a shared document does not establish that an active agent has incorporated the change, and a result correct against version 1 may no longer be acceptable.
SpecPath examined different presentation histories for equivalent final contracts; When the Specification Emerges examined progressive disclosure of a fixed target. Neither evaluated product discovery in which learning changes that target. Their results and limits appear in Appendix A.
8. Follow the export through a changed decision
Consider the request from the opening: administrators can export filtered invoices. It is short enough to look straightforward. The difficulty appears when someone has to decide which invoices, whose access and what point in time the file represents.
The following walkthrough is hypothetical. Its rules are selected clauses for an investigation, with release obligations deliberately left visible; it is not a complete production specification.
Find the decisions hidden in the request
Finance needs a file for reconciliation. Before designing the exporter, confirm that a file, rather than a report view, serves the actual workflow. Even with that settled, "matching the requested filters" leaves a consequential choice: membership and values could reflect request time, processing time or download time. An invoice updated halfway through assembly makes the difference concrete. An administrator losing account access after the file is prepared exposes another boundary.
A discussion of those examples also identifies the supported selection size and defers scheduling, notifications and large-export support. One feasibility question remains: can the existing data access path supply a consistent snapshot at that size? Developing the examples collaboratively to resolve behaviour is BDD discovery. Benchmarking the access path is a technical experiment. The distinction matters because neither a plausible example nor a desired rule establishes that the existing mechanism can satisfy it.
Assume the domain discussion selects these desired rules for investigation:
- EXP-01: A permitted administrator may request an export for one account and an explicit filter.
- EXP-02: Membership and values reflect one logical snapshot established when the request is accepted.
- EXP-03: Up to 10,000 matching invoices are supported. A larger selection is rejected without making a partial file available.
- EXP-04: Only a complete result becomes downloadable. Exporting does not change invoice state.
- EXP-05: Each new download request requires current authorisation for the account.
Retry and retention behaviour remain undecided. Those decisions are needed before releasing a retained-export API, but the snapshot and access boundaries can be investigated without pretending the whole feature is ready to build.
The rules now support acceptance examples whose expected outcomes can be agreed before anyone writes the checks:
Scroll horizontally to see all columns.
| Example | Agreed expectation | Main rule |
|---|---|---|
| An invoice is updated after request acceptance. | The export retains its snapshot value. | EXP-02 |
| Exactly 10,000 invoices match. | The selection is permitted. | EXP-03 |
| 10,001 invoices match. | The selection is rejected and no file is available. | EXP-03 |
| Assembly fails before completion. | No partial result can be downloaded. | EXP-04 |
| Access is revoked before a new download request. | The request is denied. | EXP-05 |
For the last example, Gherkin is an optional way to record the acceptance criterion:
Feature: Invoice export downloads
Rule: Each download request requires current account authorisation
Scenario: Access is revoked after an export is prepared
Given an administrator has a completed export for account "A"
And the administrator no longer has access to account "A"
When the administrator requests that export
Then the download is denied
And no invoice data is returned
The scenario identifies the state, action and observable result. A queue, object store, helper function or database layout remains a design choice. Give the scenario one maintained home and link it to EXP-05; copying it into several files would create more places for the same promise to drift.
Assign an investigation the agent can actually perform
Suppose the team assigns a two-hour prototype to investigate snapshot consistency and download authorisation, with observations, blockers and a recommendation as its deliverable. Temporary fixtures and output formats are experimental choices. They create no external API commitment, and delivering a retained-export API remains outside the assignment.
The agent needs the clauses, the existing snapshot access path, the account-authorisation boundary and the available integration checks. In a brief read-back, it identifies EXP-02 and EXP-05 and locates the mechanisms for changing an invoice and revoking access in the test environment. This establishes a basis for attempting the investigation. If those mechanisms are inaccessible, repair the context or narrow the assignment. A replacement fake cannot establish that the real boundary works.
Build one path from an authorised request to a complete temporary file, including denial and failure behaviour. Where needed, compare synchronous and background processing against the same rules. The question is whether the desired snapshot and authorisation behaviour can be achieved together, so the investigation must exercise both boundaries. A running prototype is still an investigation result.
For EXP-05, establish revoked access through the relevant permission mechanism, request the actual download boundary and check that no protected data is returned. A fake that always denies access would merely demonstrate that the fake denies access. Smaller internal behaviour can be developed through TDD within this acceptance check, but its expected results need their own basis: use an agreed export fixture, rather than calculating the expected result by calling the production export query again.
Separate a broken mechanism from a missing decision
Suppose the initial design returns a long-lived direct object-store URL, and a former administrator can still use it after revocation. Checking access when creating the link plainly fails EXP-05 for later requests. The mechanism must change, unless the commitment is explicitly reconsidered through the decision process.
There is also an unanswered question: what happens if access changes after an authorised download has started? That is a gap in the contract. Correcting the direct-link mechanism will not, by itself, supply the missing domain decision.
For illustration, assume the product selects authorisation at the start of each download request; an already authorised transfer may finish. Refine EXP-05 to state that boundary. Retain the denied-download scenario and add a scenario for revocation during an active transfer. Requiring immediate interruption instead would impose a stronger promise, with correspondingly stronger demands on the design and its feasibility evidence. Neither choice can be made by quietly adjusting a test until it passes.
A mediated download is one possible design. It still needs evidence about the permission boundary's freshness and failure behaviour; introducing a proxy does not establish either property.
Report what the investigation established
Suppose review of the direct-link prototype yields these observations:
Scroll horizontally to see all columns.
| Obligation | Observation from the hypothetical investigation | Review outcome |
|---|---|---|
| EXP-03, selection limit | Boundary checks accept 10,000 invoices and reject 10,001 without exposing a file. | Supported for those checked boundaries. |
| EXP-05, download authorisation | A revoked administrator can start a new download through the existing direct link. | Violated; the mechanism needs correction. |
| EXP-02, snapshot consistency | The fixture never changes invoice values during assembly. | Unverified for that case; strengthen the evidence. |
Attach the findings to the code state and configuration actually assessed. The person responsible for the increment accepts the investigation's findings and defers feature acceptance: there is useful evidence, including a demonstrated violation and a case the checks never exercised. The next work is to correct the access mechanism, examine the missing snapshot case and resolve the remaining delivery obligations. None of that makes the prototype acceptable for release.
For the snapshot follow-up, coordinate the relevant reads and mutations instead of hoping their timing overlaps. One possible check pauses assembly after request acceptance and before subsequent reads, commits changes to a selected invoice's value and to which invoices match, then resumes assembly and compares the result with the agreed pre-change snapshot. Use instrumentation that reaches the actual data boundary, and record the interleaving exercised. This gives repeatable evidence for that case; it does not establish every concurrent execution.
Examine a spec that was wrong from the outset
Now consider an alternative starting specification. It requires an authorisation check at export creation and says nothing about later downloads. Code and scenarios could satisfy those clauses while allowing a former administrator to start a new download.
Suppose a review uncovers an account-access policy that already applied when the specification was approved: revocation must prevent new downloads. The original spec omitted an existing obligation. Its defect was present before the implementation began, even if every scenario derived from it passes.
Preserve the policy evidence, correct the rule, add the revocation example and change implementation that conflicts with the corrected contract. Code that already performs the stronger check may survive this review unchanged. Had the policy been newly adopted, the diagnosis would instead be a changed requirement, with transition obligations. The distinction preserves why the old decision was made and identifies what now requires correction.
Passing the original scenarios cannot justify omitting the existing access obligation. The mistake has to be challenged at the level where it entered the work.
Let use challenge the proposed outcome
A faulty specification need not conflict with another written policy. In a separate hypothetical example, the proposed file contains invoice dates and amounts, and finance tries a sample against its existing reconciliation records. Two invoices share those values; the user cannot tell which record to reconcile because the required reference is absent. The sample can satisfy every proposed column rule while failing the task that motivated it.
Keep that observation and revisit the output decision with finance. Assume the domain review establishes which existing reference identifies the record: add it to the output requirement and retain the ambiguous pair as an acceptance example. Have finance repeat the reconciliation using the revised sample before committing to the representation. This corrects an overlooked need in the existing workflow; it supplies no evidence yet about production snapshot or access behaviour.
Decide whether delivery is now justified
Retain the findings, revised rule, reasons, affected scenarios and actual verification results. Revisit unfinished tasks that depended on the earlier interpretation, leaving unrelated decisions intact.
A delivery assignment still needs answers about retry and retention behaviour, file representation and applicable operational bounds. Resolve the controlling questions, then assess the resulting contract and the agent's assignment again. Release requires reviewing the implementation and evidence against those obligations; the partial investigation cannot supply feature acceptance.
After release, examine whether finance can complete representative reconciliations and whether operational behaviour remains acceptable. The sample exercise informs the output decision; actual use can expose conditions it missed.
9. Recognise when specifications stop helping
The export investigation exposed an access failure, an untested snapshot guarantee and requirements that still needed decisions. Its value came from making those problems visible before release. A specification process stops helping when it conceals that uncertainty or prevents the team from responding to it.
Three failure patterns deserve particular attention.
Requirements harden before their assumptions are tested
A team can approve detailed requirements before examining whether the proposed behaviour is useful or feasible. Once implementation depends on those decisions, changing them becomes expensive. Approval can then become a reason to defend an assumption rather than investigate it.
In the export example, promising a snapshot at request acceptance would be premature if nobody had established whether the existing data access path could provide it. The next assignment should investigate that guarantee before dependent delivery work begins.
Keep detailed commitments close to the work that can test them. Record assumptions as assumptions, keep the relevant domain and technical perspectives involved, and reopen affected decisions when contrary evidence appears. An approved specification records a decision; it does not establish that the decision was correct.
Scenarios multiply without clarifying behaviour
More examples do not necessarily produce a clearer contract. A team can generate many happy-path scenarios while leaving the controlling rule unanswered. Examples that prescribe private classes or incidental interface mechanics can also make the implementation look settled before the required behaviour is understood.
For invoice exports, dozens of scenarios about creating a file cannot settle what happens when access is revoked. The useful discussion is about when authorisation applies. Once that rule is agreed, a few decisive examples can express its consequences.
Keep each rule and its examples in one maintained place. Use domain language, include perspectives that can challenge the expected outcomes, and leave replaceable test mechanics in the automation. Choose Gherkin when it helps that collaboration; the notation alone cannot supply it. Cucumber's discussion of BDD myths explains why collaboration and the timing of examples matter more than adopting a tool.
Passing checks become a substitute for acceptance
Code and tests can agree because they repeat the same mistaken interpretation. Checks can also pass at individual components while missing a failure across their interaction.
The direct download link illustrates the second problem. A permission check at export creation may work correctly while the later download still exposes data after revocation. Acceptance requires examining the whole obligation, including the boundary where protected data becomes available.
Review what each check establishes, whether its expected result has a justified basis, and which obligations remain unverified. Keep the change small enough to inspect meaningfully. Completed tasks and successful commands are useful records of activity; acceptance needs evidence about the promised behaviour.
10. Try the approach on one bounded change
Use a small trial to determine whether this discipline improves your work. The purpose is to reduce misunderstanding and rework while preserving quick feedback.
Choose a change and record the starting point
Select one maintained capability that repeatedly causes ambiguity. Identify the next useful behaviour and the uncertainty most likely to invalidate it.
Before the trial, examine a few reasonably comparable recent changes. Record the effort spent preparing, implementing, reviewing and correcting them, together with the time taken to reach useful feedback. Incomplete historical records are still informative if their limitations remain explicit. Agree what result would justify retaining the extra work, such as less ambiguity-related rework without an unacceptable delay to useful feedback.
Specify, implement and review one increment
Agree the observable behaviour, relevant failure cases, promises to preserve and a few decisive acceptance examples. Investigate any unresolved question that blocks the chosen scope. Add Gherkin only if it improves shared understanding.
Give the agent the current contract, relevant repository context and available checks. Review the result against the agreed obligations, retaining discoveries and correcting decisions when their basis fails. After release, examine whether the change serves its intended use and behaves acceptably in operation.
Decide which parts earned their cost
Compare the trial with the earlier changes. Did clearer requirements reduce ambiguity-related rework? Did preparation and review delay useful feedback? Which checks found material mistakes?
Eberhardt's 2025 Spec Kit experiment reported substantial Markdown-review overhead for small increments. Its scope and tool versions limit generalisation, but review cost is part of the work and belongs in the evaluation.
Repeat the comparison across several changes where practical, recording differences in difficulty, tools and available evidence. This informs a local decision; it does not establish a general productivity result.
Retain the steps that improve decisions or expose consequential errors. Simplify those that repeatedly consume attention without doing either. The useful output is working behaviour and evidence that can change the next decision.
Appendix A. Evidence and limitations
The recommendations in this article are engineering judgments, not a complete method validated by the studies below. The research helps examine four narrower questions. It establishes no universal specification length, mandatory template or productivity gain.
Does clarification help?
ClarifyGPT asks whether targeted questions improve code generation. Orchid examines what happens when requirements still permit different interpretations.
ClarifyGPT, FSE 2024
ClarifyGPT detects ambiguity, asks targeted questions and supplies the clarified requirement before code generation. In a study with ten participants, GPT-4's Pass@1 rose from 70.96% to 80.80% on MBPP-sanitized. Pass@1 estimates how often a single generated solution passes the supplied tests. MBPP-sanitized is a hand-verified subset of Mostly Basic Python Problems, a benchmark of short Python programming tasks.
The result supports targeted clarification for the evaluated tasks. It does not establish whether an answer reflects the right product decision. This is peer-reviewed function-generation research; the larger automated evaluation used simulated responses. It does not validate a whole-project workflow or an optimum specification format.
Orchid ambiguity study, April 2026 preprint
Orchid compared clear and deliberately ambiguous requirements across 1,304 function tasks and 5,216 variants. The evaluated models generally lost correctness and produced more divergent behaviour when ambiguity was introduced.
The practical concern is that plausible interpretations can produce different results. Examples and questions can help expose which interpretation is intended. However, the ambiguity was synthetic, and the evaluated model versions limit transfer to repository agents. Clear wording still cannot establish whether the intended requirement is right.
Does more context help?
Additional repository instructions and the history of a specification are different kinds of context. The following studies examine them separately.
AGENTS.md evaluation, February 2026 preprint
This study examined whether repository instruction files help coding agents resolve issues. The evaluation included SWE-bench Lite, a benchmark of repository issue-resolution tasks, and 138 tasks from 12 additional Python repositories. Generated instructions often reduced task success; human-written files generally offered modest gains. Both added execution cost.
The finding motivates scrutiny of redundant instructions and their cost. It does not justify omitting necessary requirements. The study concerns supplemental repository guidance, not feature specifications or specification length. Some task descriptions and tests used LLM assistance, and effects varied across agents.
SpecPath, August 2026 preprint
SpecPath held the final contract constant while varying its presentation history through duplication, overrides, cancellation and split instructions. Across five source tasks, the histories produced similar aggregate success but different individual outcomes. Similar overall results therefore did not mean that each task produced the same behaviour under every history.
For this guide, the practical concern is whether an agent has incorporated the applicable contract after instructions change. Providing a clear current contract and checking the resulting behaviour address that concern. The study does not establish one uniquely effective documentation strategy.
Execution began after the complete history was available. The study does not establish a single cause of the individual differences, and it did not evaluate ongoing product discovery.
What happens when requirements arrive progressively?
When the Specification Emerges, March 2026 preprint
This study compared implementations derived from 20 machine-learning papers when a fixed target was supplied initially or disclosed progressively. Progressive disclosure produced lower average composite implementation-fidelity scores. That combined score measures faithfulness to the specified design and structural integration, including reuse of earlier modules; it is not simply a count of correct outputs.
The distinction matters when interpreting the result. Semantic fidelity concerns whether the implementation follows the specified computation. Loss on that measure was concentrated on Claude Code, while Codex's semantic score was essentially unchanged. A lower combined score should not be read as the same kind of correctness loss for both platforms.
The result motivates attention to retaining and reconciling requirements across long interactions. Its scope is limited to two coding platforms, synthetic interactions and partly model-based scoring. The target was fixed throughout: the study did not evaluate product discovery in which learning changes what should be built.
Does a more elaborate workflow justify its cost?
Spec Kit Agents, April 2026 preprint
Spec Kit Agents examined additional grounding and validation in an agent workflow. These additions improved a model-judged quality score and increased full-workflow latency. A model-judged score means another language model rated the output for qualities such as correctness and maintainability; it is an evaluation proxy, not direct evidence of user value.
Human reviewers compared pull requests produced by the full workflow with and without the additions. Across six tasks, their 60 judgements included 33 ties, 19 preferences for the workflow without the additions and eight for the augmented workflow.
The result supports measuring the trade-off locally, including the time spent on the whole workflow. The small human comparison does not establish whether the additions justify their cost for a particular team. Review checkpoints were automatically approved, so the study also cannot establish the value of real human review during development.
What the other sources contribute
NASA's requirements guidance informs the checks for clarity, consistency, rationale and verifiability. Anthropic's context guidance argues for relevant information and a balance between vague direction and brittle instruction recipes. Neither supplies an experimentally established token budget for a specification.
The BDD, Agile and dual-track sources cited in the main article explain collaboration and feedback cycles. Framework templates show how their authors organise work. These are methods and conventions; they do not establish an effect size for introducing them into agent-assisted development. Spec-Driven Development for Agentic Software Engineering: Harnessing Human-Agent Teamwork is a conceptual framework that calls for empirical validation.
Boeckeler's first-hand experiments reported an agent recreating classes described in research notes about an existing system. The incident illustrates the distinction between describing what exists and requesting a change. It is a historical observation, not evidence that current tool versions necessarily behave the same way.
The six study summaries were checked against their linked primary sources. Their findings apply within the tasks, agents and measures examined. The methodological sources contribute guidance, and this article combines them into a proposed engineering approach. Its examples are hypothetical, no development experiment was run for the article, and the approach should be assessed on actual changes. Tool documentation remains mutable.