Notation
| Step | Standard | Looks like |
|---|---|---|
| Why and scope | Proposal | work/changes/004-invoices/proposal.md |
| Requirement | EARS | ### invoices.R2 — Totals + When an invoice is saved, the BFF shall round its total to 3 decimals. |
| Acceptance | BDD / ATDD | #### invoices.R2.S3 — Rounding edge @boundary + Given / When / Then |
| Choosing cases | ZOMBIES | one tag per scenario |
| Tests | Traceability | it("invoices.R2.S3 rounds 0.0005 up") |
| Test data | ZOMBIES on data | -- @fixture invoices.R2.S3 @boundary |
| QA | Checklist | one item per scenario |
EARS requirements
EARS (Easy Approach to Requirements Syntax) limits each requirement to one sentence in one of these shapes:
| Pattern | Template |
|---|---|
| Ubiquitous | The <system> shall <response>. |
| Event | When <trigger>, the <system> shall <response>. |
| State | While <state>, the <system> shall <response>. |
| Unwanted | If <condition>, then the <system> shall <response>. |
| Optional | Where <feature>, the <system> shall <response>. |
| Complex | While <state>, when <trigger>, the <system> shall <response>. |
Name a concrete system ("the BFF", "the invoices page"), one behaviour per requirement, and measurable outcomes (within 15 minutes, answers 409). agent-kit specs lint rejects any other shape.
Scenarios (BDD / ATDD)
Each requirement has scenarios written as examples — Given a context, When an action, Then an observable outcome (And / But extend a step). They are agreed before code and are the acceptance tests.
ZOMBIES
Pick the scenarios (and the test cases) with ZOMBIES and tag each scenario with the one category it covers:
| Tag | Ask | Example |
|---|---|---|
@zero | nothing / empty | no invoices → empty state |
@one | the single basic case | one line totals correctly |
@many | several, order, duplicates | three lines in two currencies |
@boundary | limits and edges | the 5th failed login blocks; last day of a period |
@interface | the contract | 403 for another provincia; API shape |
@exception | bad input, failure | invalid code → clear error, nothing saved |
@simple | the happy path | create and see it in the list |
Lint warns when a requirement has no @exception or @boundary scenario. Money, permissions and data rules always get them.
Traceability
A test that proves a scenario starts its name with the scenario id:
it("auth.R2.S2 shows the login page for an expired session", () => { /* … */ })
A scenario proven without a test (a visual check, a manual flow, an SQL check) gets a ✅ row in the change's tasks.md:
| auth.R2.S2 | manual: reloaded with an expired token, login shown | ✅ |
agent-kit specs trace and agent-kit work trace NNN list ✗ not covered scenarios; preflight blocks a done change with any.