|
|
|
@@ -32,6 +32,90 @@ A feature spec is the implementation-level contract for one feature or component
|
|
|
|
|
2. **An "Out of scope" section is mandatory.** If you do not draw the boundary, the implementer (you, future-you, or another agent) will guess wrong.
|
|
|
|
|
3. **Every technical decision in "Technical approach" must have a rationale.** A decision is any choice where a reasonable alternative existed and was not taken. "Use Postgres" is not a decision; "use Postgres because the rest of the stack uses it and we need transactions across user + invoice" is.
|
|
|
|
|
|
|
|
|
|
## EARS-lite acceptance criteria
|
|
|
|
|
|
|
|
|
|
Measurable criteria answer "is it done?". They do not always answer "what should it do
|
|
|
|
|
when X happens?" — and behavioural requirements written as prose are where ambiguity
|
|
|
|
|
survives review. For any criterion that is conditional or event-driven, use EARS-lite
|
|
|
|
|
instead of prose:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
WHEN <trigger> THE SYSTEM SHALL <observable response>
|
|
|
|
|
WHILE <state> THE SYSTEM SHALL <observable response>
|
|
|
|
|
IF <unwanted condition> THEN THE SYSTEM SHALL <observable response>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
There is a fourth, unconditional form. Use it for invariants — the properties that must
|
|
|
|
|
hold with no trigger at all, which are usually the ones that matter most:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
THE SYSTEM SHALL <observable response>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Worked, deliberately from a domain unlike whatever you are specifying:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
THE SYSTEM SHALL reject a firmware image whose signature does not verify
|
|
|
|
|
WHEN a sensor reports a temperature above the shutdown limit
|
|
|
|
|
THE SYSTEM SHALL open the contactor within 200ms
|
|
|
|
|
WHILE the contactor is open
|
|
|
|
|
THE SYSTEM SHALL refuse every start command
|
|
|
|
|
IF a sensor reading is missing or stale by more than one interval
|
|
|
|
|
THEN THE SYSTEM SHALL treat it as above the limit
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The example is off-domain on purpose. An on-domain example gets copied: a spec written
|
|
|
|
|
against an invoice-flavoured example inherited a requirement about extraction confidence
|
|
|
|
|
that its feature request never mentioned, and the author only noticed on review. Read
|
|
|
|
|
the shapes, not the content.
|
|
|
|
|
|
|
|
|
|
Each conditional line names a trigger and one observable response, which usually maps
|
|
|
|
|
onto a single test. The `WHILE` and unconditional forms are universally quantified —
|
|
|
|
|
"every start command", "a firmware image" — so they map onto a property or a set of
|
|
|
|
|
cases, not one assertion. That is still worth writing: it closes the requirements half
|
|
|
|
|
of the audit trail, which is otherwise issue-body prose.
|
|
|
|
|
|
|
|
|
|
**This is an option, not a replacement.** Threshold criteria ("p99 < 200ms under 100
|
|
|
|
|
RPS") stay as they are — EARS phrasing adds nothing to a number. Use it for conditional
|
|
|
|
|
behaviour, error handling, and state-dependent rules.
|
|
|
|
|
|
|
|
|
|
## Context snapshot
|
|
|
|
|
|
|
|
|
|
The executor of this spec will not see the conversation that produced it, and often
|
|
|
|
|
cannot see the architecture document either — a different agent, a fresh session, a
|
|
|
|
|
different machine. A spec that says "see the architecture doc" hands them a lookup they
|
|
|
|
|
may not be able to perform.
|
|
|
|
|
|
|
|
|
|
So inline the specific facts this spec depends on, not the whole document:
|
|
|
|
|
|
|
|
|
|
```markdown
|
|
|
|
|
## Context snapshot
|
|
|
|
|
Taken from <source> @ <commit-or-date>. Re-check before implementing if stale.
|
|
|
|
|
|
|
|
|
|
- The mailbox poller writes rows to `invoices` with `state = 'received'`.
|
|
|
|
|
- The payment-file writer reads `invoices` and emits one file per batch.
|
|
|
|
|
- Money is int64 minor units plus an ISO-4217 code; float is banned repo-wide.
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Three rules keep this from becoming a second source of truth, which is the real
|
|
|
|
|
objection to inlining and a good one:
|
|
|
|
|
|
|
|
|
|
1. **Snapshot what the implementer cannot look up and cannot proceed without.** That is
|
|
|
|
|
wider than "facts this spec's decisions rest on" — a table name may underpin no
|
|
|
|
|
decision here and still be the thing that blocks writing the migration. It is still
|
|
|
|
|
narrower than the whole document: if a fact changes nothing and blocks nothing, leave
|
|
|
|
|
it out, and say what you left out so the omission reads as deliberate.
|
|
|
|
|
2. **Always cite source and version.** A snapshot without provenance cannot be
|
|
|
|
|
revalidated, and an unrevalidatable copy is exactly the drift everyone fears.
|
|
|
|
|
3. **If you could not read the source either, say so in those words.** Writing a spec
|
|
|
|
|
against a document you cannot open is common and is not a reason to skip the section
|
|
|
|
|
— it is a reason to mark the whole block `UNVERIFIED — reconstructed, not read`, and
|
|
|
|
|
to make confirming it the implementer's first task, before the first failing test.
|
|
|
|
|
An unmarked guess is the only genuinely dangerous version.
|
|
|
|
|
4. **The snapshot is evidence, not authority.** Open the section with one line to that
|
|
|
|
|
effect — "where this disagrees with the source, the source wins and this spec is
|
|
|
|
|
stale" — rather than annotating each fact.
|
|
|
|
|
|
|
|
|
|
## Spec Template
|
|
|
|
|
|
|
|
|
|
```markdown
|
|
|
|
@@ -42,12 +126,21 @@ A feature spec is the implementation-level contract for one feature or component
|
|
|
|
|
What problem does this feature solve? For whom? Why now?
|
|
|
|
|
(2-4 sentences. If you cannot answer "why now," ask before writing the rest.)
|
|
|
|
|
|
|
|
|
|
## Context snapshot
|
|
|
|
|
[Facts the implementer cannot look up, with source and version. See "Context snapshot" above.]
|
|
|
|
|
|
|
|
|
|
## Success Criteria
|
|
|
|
|
|
|
|
|
|
- [ ] Criterion 1 — measurable and verifiable
|
|
|
|
|
- [ ] Criterion 2 — measurable and verifiable
|
|
|
|
|
- [ ] Criterion 3 — measurable and verifiable
|
|
|
|
|
|
|
|
|
|
### Behavioural criteria (EARS-lite)
|
|
|
|
|
|
|
|
|
|
[Conditional and event-driven behaviour, one trigger and one observable response per
|
|
|
|
|
line. Not checkboxes — these are properties, and several need more than one test each.
|
|
|
|
|
Omit the subsection entirely if the feature has no conditional behaviour.]
|
|
|
|
|
|
|
|
|
|
## Constraints
|
|
|
|
|
|
|
|
|
|
Non-negotiable requirements the solution must satisfy.
|
|
|
|
|