Skip to main content

One post tagged with "product management"

View All Tags

Spec-Driven Development for AI Coding: What to Define Before Code

· 13 min read
TokLis Solutions
Software delivery and digital marketing insights

Spec-driven development blueprint connecting AI coding requirements to acceptance tests

AI can turn a product request into working code before a team has agreed what "working" means. Spec-driven development addresses that mismatch by making product decisions, constraints, and acceptance evidence explicit before implementation starts.

The goal is not a bigger prompt or a document that predicts everything. It is a shared, versioned answer to three questions: what must happen, what must never happen, and how will the team know the difference? AI can then accelerate a defined path instead of committing one person's assumptions to code.

Why faster code exposes weak requirements

A product discussion can feel complete because each participant fills gaps from their own experience. The product owner imagines one permission model. A developer assumes another. A tester discovers a third interpretation while trying an edge case. Nothing forces those mental models to collide until software exists.

An AI coding agent shortens the distance between request and implementation. That is useful when the request has a stable target. When it does not, the agent can still produce coherent screens, data models, and flows. The output may look finished while encoding choices nobody approved.

This is why code review cannot ask only, "Does the code run?" GitHub's guide to reviewing AI-generated code tells reviewers to run tests, verify that a change fits the project's intent, and look for ignored constraints or incorrect logic. Review needs an explicit statement of intent to compare against.

The broader TokLis guide to AI coding tools for software teams makes the same workflow distinction: generation is only one part of a verified delivery path.

What spec-driven development means here

The phrase covers approaches ranging from a short spec written before one feature to systems where a maintained specification drives implementation. For most product teams, the useful starting point is simpler:

A specification is the current agreement about behavior, boundaries, and evidence. It is detailed enough to prevent materially different interpretations, but no larger than the decision requires.

This is established requirements work adapted to a faster implementation loop. The ISO/IEC/IEEE 29148 requirements-engineering standard describes a software requirements specification as a structured collection of essential functions, performance needs, design constraints, attributes, and external interfaces. It also treats requirements as material to discover, analyze, verify, validate, communicate, document, and manage throughout the lifecycle.

A technical assignment can provide that shared foundation. For AI-assisted delivery, it becomes more useful when every important requirement is connected to an observable acceptance result.

The specification must settle seven kinds of decisions

Use this structure for the product or feature. A short, low-risk change may need a page. A multi-role workflow with valuable data may need far more detail.

1. Goal, outcome, and non-goals

State the user problem and the observable outcome. Then state what this release will not do. Non-goals stop a coding agent or developer from completing the picture with plausible extras that change scope.

2. Actors, permissions, and ownership

List each user and system role. Define who can view, create, change, approve, retry, cancel, and delete. Include ownership transitions, not just button visibility. A hidden button is not an authorization rule.

3. User flows and state transitions

Describe the normal journey, alternate paths, and the states that can exist between them. For each transition, name its preconditions, trigger, resulting state, and visible outcome.

4. Data and invariants

Define the important records, required fields, identifiers, relationships, ordering rules, and retention needs. An invariant is a condition that must remain true, such as "one event identifier is processed at most once" or "a completed result cannot return to an in-progress state without an authorized correction."

5. Interfaces and boundaries

Record what crosses a boundary: API inputs and outputs, browser events, third-party responses, file formats, time zones, and dependency failures. Specify which system owns each value and which assumptions are outside the team's control.

6. Errors, retries, and recovery

For each failure, define what the user sees, what the system records, whether an action can be retried, and how duplicate work is prevented. Include timeouts, partial completion, stale data, and events arriving in an unexpected order when they matter to the workflow.

7. Quality constraints and release conditions

Add the non-functional requirements that change design or acceptance: security boundaries, accessibility needs, supported environments, performance expectations, auditability, and operational recovery. Avoid adjectives such as "fast" or "secure" without a testable condition and an owner who can approve it.

Finish with the release conditions. Name the checks that must pass, the decisions that require a product owner, and the known limitations that may be accepted for an initial release.

Example: a team-based game platform

Consider an illustrative platform for a team-based game. The game mechanics can be thoroughly discussed while the platform behavior remains underspecified. A coding agent still has to choose an answer for every unresolved technical question.

Unstated questionPlausible interpretationsWhat the specification must decide
When can a match start?Full roster, configured minimum, manual approval, or scheduled timePreconditions, authorized role, state change, and response when a precondition fails
What if score events arrive twice or out of order?Keep the first, keep the latest, merge, reject, or request reviewEvent identity, ordering rule, conflict rule, final-state rule, and audit record
What happens after a player reconnects?Restore the prior view, rebuild from server state, or ask the player to rejoinSource of truth, session rule, visible recovery state, and timeout behavior
Who can correct a completed result?Nobody, team captain, moderator, or administratorPermission, reason requirement, downstream effects, and history of the change
What happens when a request partly succeeds?Retry everything, resume, roll back, or flag for supportTransaction boundary, idempotency rule, user message, and recovery owner

Each interpretation can produce reasonable code. The defect appears only when the implemented choice differs from the product owner's unstated choice.

Do not solve this by making the document longer everywhere. Resolve the decisions whose alternatives would change data, permissions, user progress, or release acceptance. Record lower-impact uncertainties as open questions with an owner and a decision date.

Turn every critical requirement into acceptance evidence

Acceptance criteria translate intent into observable conditions. NASA's software acceptance-criteria guidance has a specialized aerospace context, but its planning principle travels well: customer and development roles define criteria and acceptance activities early enough to prepare the necessary reviews and tests.

A useful criterion is:

  • specific about the starting state and actor;
  • observable at a public interface or meaningful system boundary;
  • clear about the expected result and what must remain unchanged;
  • traceable to one requirement;
  • paired with the evidence and owner needed for acceptance.

Cucumber's Gherkin reference provides a practical format: Given an initial context, When an event occurs, Then an expected outcome follows. Cucumber can connect these examples to executable tests, but the format is also useful for clarifying behavior before automation.

For example:

Given a match is waiting and the captain is authenticated
And the configured start conditions are not met
When the captain tries to start the match
Then the match remains in the waiting state
And the captain sees which start condition is missing

The example deliberately says "configured start conditions." The product still has to define those conditions elsewhere. An acceptance scenario cannot repair an undefined business rule.

Use a requirement-to-test matrix

The matrix below is illustrative. Replace its rules with the decisions approved for your product.

RequirementObservable acceptancePrimary evidence
R1: only an authorized role can start a matchAn authorized request changes the state once; an unauthorized request does notAuthorization unit tests, API integration tests, and one browser journey
R2: the same score event is processed at most onceRepeating an event identifier leaves totals and history unchanged after the first accepted eventIntegration test with duplicate and reordered fixtures
R3: a reconnecting player receives the current server stateA new browser session shows the current match, role, and allowed next actionBrowser test with a recreated session
R4: a failed state change remains recoverableThe user sees a useful error, no partial state is committed, and an allowed retry succeeds onceFailure-injection integration test plus browser assertion

The matrix creates traceability without pretending every requirement needs a browser test. It also exposes orphaned work: a requirement with no acceptance evidence is difficult to approve, while a test with no requirement may be protecting an accidental implementation detail.

Use a test portfolio, not one type of test

The specification and tests complement each other. The specification records the intended rules. Tests provide repeatable evidence that an implementation satisfies selected examples and constraints.

Use the lowest test level that can prove the behavior, then reserve a smaller set of browser tests for critical journeys:

Test levelBest questionExample
UnitDoes one business rule handle boundaries correctly?Can this role perform this state transition?
IntegrationDo components, storage, and interfaces preserve the rule together?Is a duplicate event ignored without corrupting the stored total?
ContractDo two systems agree on inputs, outputs, and failure responses?Does a score event schema reject a missing identifier?
Browser or end-to-endCan a user complete a high-value journey through the real interface?Can a captain start a valid match and see the next state?
Exploratory and user testingWhat did the team fail to anticipate or make usable?Can a new participant recover after an interruption without help?

Playwright's testing guidance recommends verifying user-visible behavior instead of relying on implementation details. That is where browser tests add distinct value: they can reveal broken navigation, stale UI state, missing controls, and failures across the browser, API, and data path.

Browser coverage should stay selective. The practical test pyramid recommends translating a small number of high-value user journeys into end-to-end tests while covering more cases at faster, lower levels. A large, slow browser suite can create its own maintenance burden.

No automated portfolio proves that the product is complete or pleasant to use. Realistic exploratory sessions and user feedback still matter. Their findings should improve the specification and add regression tests where repeatability is valuable.

Keep the specification lightweight and alive

Spec-driven development does not require freezing the product before learning begins. It requires making the current decision visible.

  1. Scale detail by consequence and uncertainty. Spend more effort where a wrong interpretation affects permissions, money, valuable data, irreversible actions, or several downstream systems.
  2. Review before implementation. Ask product, engineering, and testing roles to identify terms that allow two materially different outcomes.
  3. Version the spec with the code. When a decision changes, update the requirement, its acceptance examples, and the affected tests in the same change.
  4. Separate decisions from hypotheses. A required rule belongs in the acceptance contract. A question that needs user evidence belongs in a learning plan.
  5. Keep implementation choices where they belong. The product owner defines outcomes and constraints. Engineers choose internal design unless that choice changes an agreed boundary or risk.

AI can help draft examples, identify contradictions, list edge cases, and trace requirements to tests. It should not silently decide product policy. A human with the right authority must approve choices that affect users and the business.

Decide what must be correct before real users arrive

Testing often produces a long list of small issues. The hard question is not whether any issue remains. It is whether the team understands what each issue means.

Classify every known issue against the specification:

  • Blocks release: it violates an acceptance criterion, threatens a critical constraint, corrupts important data, breaks a core journey, or creates an unacceptable security or authorization risk.
  • Requires an explicit exception: it misses an agreed condition, but the product owner accepts a documented limitation, workaround, owner, and follow-up decision.
  • Needs user learning: the implementation meets the current contract, but the team needs real use to evaluate comprehension, usefulness, or preference.

This classification turns "when do we stop fixing?" into a product decision. It also prevents the team from calling a known requirement failure an experiment.

A pre-code review sequence

Before asking an AI agent or developer to implement a feature:

  1. Read the goal, non-goals, actors, and main journey aloud.
  2. Mark every term that can produce two materially different behaviors.
  3. Resolve high-impact product decisions and assign the remaining questions.
  4. Draw the states and allowed transitions for workflows that can pause, fail, retry, or finish.
  5. Review data ownership, identifiers, ordering, duplication, and recovery.
  6. Write acceptance examples for the normal path, important boundary cases, and expected failures.
  7. Map each critical requirement to its primary evidence and acceptance owner.
  8. Agree on the release conditions before implementation changes the cost of the discussion.
  9. Give the coding agent the approved spec, relevant repository context, and required checks.
  10. Review the result against the requirements and evidence, not against how plausible the interface looks.

The result is not certainty. It is a controlled way to move disagreement, missing decisions, and test design earlier, while changes are still cheap to discuss.

Common questions

Does spec-driven development mean waterfall?

No. A specification can be small, iterative, and versioned. The important distinction is whether the current product decisions are explicit before implementation, not whether every future decision is frozen.

How detailed should the specification be?

Detailed enough that two capable implementers would not choose materially different user behavior, data rules, permissions, or error recovery. Add depth where consequences and uncertainty are high.

Who owns the specification?

The product owner is accountable for product behavior and priorities. Engineering, design, testing, security, and operations should challenge feasibility, ambiguity, risk, and evidence. Shared authorship does not remove decision ownership.

Can AI write the specification?

AI can produce a first draft, ask questions, identify inconsistencies, and suggest scenarios. It cannot know which unresolved interpretation is correct for the business unless an authorized person decides and records it.

Are unit tests enough?

No single test level is enough for a product with multiple components and user journeys. Unit tests protect focused rules. Integration and contract tests protect boundaries. A selective set of browser tests checks that critical journeys work through the interface users actually encounter.

What happens when requirements change?

Change the specification first or in the same reviewed change as the code. Update the acceptance examples and affected tests so the repository keeps one current account of expected behavior.

Make the next build easier to judge

AI makes implementation faster, but speed is valuable only when the team can judge the result. A compact, testable specification gives product, engineering, and QA one reference for that judgment.

Start with one critical workflow. Write its states, data rules, failure behavior, and acceptance matrix. If the exercise reveals unresolved product or technical decisions, learn how TokLis approaches structured software planning and delivery before turning those gaps into code.