Feature Spec - one page, written before any code
Who fills this in: Product (with input from the table). When: in the first 10 minutes, before Gate 1. Why: this is Way #1: Describe before you generate - the contract and the tests are written from this page, not the other way round. Keep it to one page. If you can’t fill it in, you’re not ready to build (
QUAL-PRINC-SHIFT-LEFT- prevent defects at inception).
Delete the quote-blocks before you hand it to the team. The worked snippet at the bottom is for the /recommend endpoint - copy its shape, don’t copy its content.
1. Problem - one sentence
What can’t the user do today? Whose pain is this?
e.g. “Alice can see her own assessment scores, but has no way to tell whether she’s ahead of or behind her team.”
2. Consumers - who calls this, and what they do with the answer
Name the caller and the screen/job. This is the API-as-a-product mindset (REQ-API-1). One endpoint serves real consumers - list them.
| Consumer | What they do with the response |
|---|---|
3. Success metric - pick exactly ONE
One measurable thing that tells you it worked. Resist the urge to list five. (ENG-PRIN-SIMPLE-STMT - YAGNI applies to metrics too.)
e.g. “The dashboard renders a per-dimension comparison with no client-side maths - the API does all the averaging.”
4. User stories - Given / When / Then
Behaviour, not implementation. Each story is independently demoable. Keep them small (ENG-PRIN-INCR-STMT).
- Given [starting state] When [the user / caller does X] Then [observable result].
- Given … When … Then …
5. Acceptance criteria - the checklist the demo is graded against
Concrete, testable, unambiguous. These become your contract assertions and your tests. “Done” = all boxes ticked (QUAL-PRINC-SDLC - Definition of Done).
- …
- …
- Errors use the shared
Problemenvelope (REQ-API-5).
Worked snippet - /recommend (copy the shape, author your own for your endpoint)
This is what a frozen one-pager looks like for the deliberately-incomplete /recommend endpoint. The team writes this before touching ../../../../stacks/nextjs/openapi.yaml - then the OpenAPI RecommendResponse schema and the tests fall straight out of it.
Problem: Alice has two dimensions she scored as N/A (governance, business_impact) and no idea which lesson to start with. She needs the system to point at her biggest gaps.
Consumers:
| Consumer | What they do with the response |
|---|---|
| Lessons page “Recommended for you” rail | Renders a ranked list: lesson title + a one-line reason + a gap indicator |
| Dashboard nudge | Shows the single top recommendation as a call-to-action |
Success metric (one): The top recommendation is always a lesson targeting the user’s largest gap, and the user has never already completed it.
User stories:
- Given Alice has scored governance and business_impact as N/A, When she opens the Lessons page, Then the top recommendations target those two dimensions first.
- Given Alice has already completed
lesson-10(AI Security Basics), When recommendations are computed, Thenlesson-10never appears. - Given two candidate lessons have the same gap, When they are ranked, Then the
exploring-stage lesson is listed beforebuildingbeforeapplying.
Acceptance criteria:
-
gapScore = 1.0 − userDimensionScore. An N/A dimension (responded:false, value0.0) therefore hasgapScore = 1.0- the maximum. - Lessons the user has completed (
lesson-1, 4, 7, 8, 10) are excluded. - Exactly the top 5 recommendations are returned.
- Sort order:
gapScoredescending, then lessonstage(exploring→building→applying). - Each item carries
lesson, a human-readablereason, andgapScore(matches theRecommendationschema already in the OpenAPI file). - Errors use
application/problem+json(REQ-API-5).
Expected top-5 against the seed data (use this to grade the demo - Alice’s gaps are governance 1.0 and business_impact 1.0):
| # | Lesson | Dimension | Stage | gapScore | Why it ranks here |
|---|---|---|---|---|---|
| 1 | lesson-11 Responsible AI Usage | governance | exploring | 1.0 | Max gap, earliest stage |
| 2 | lesson-16 Measuring AI Productivity | business_impact | exploring | 1.0 | Max gap, earliest stage |
| 3 | lesson-12 Common AI Security Pitfalls | governance | building | 1.0 | Max gap, later stage than #1 |
| 4 | lesson-17 AI ROI for Engineering | business_impact | building | 1.0 | Max gap, later stage |
| 5 | lesson-18 Innovation with AI | business_impact | applying | 1.0 | Max gap, latest stage |
Note:
lesson-10(governance, exploring) would otherwise top the list, but it’s completed, so it’s excluded. That exclusion is exactly the kind of thing your contract test should catch.
Next stop: freeze the contract in ../../../../stacks/nextjs/openapi.yaml, then write the failing tests from test-pyramid-starter.md. Built at Innovation Day - the five ways: ways-of-working.md.
Downloads for this session
Grab the templates and sample files used here.