Concepts

Notation

One standard notation at every step — EARS requirements, Given/When/Then scenarios, ZOMBIES tags, scenario ids in test names.
StepStandardLooks like
Why and scopeProposalwork/changes/004-invoices/proposal.md
RequirementEARS### invoices.R2 — Totals + When an invoice is saved, the BFF shall round its total to 3 decimals.
AcceptanceBDD / ATDD#### invoices.R2.S3 — Rounding edge @boundary + Given / When / Then
Choosing casesZOMBIESone tag per scenario
TestsTraceabilityit("invoices.R2.S3 rounds 0.0005 up")
Test dataZOMBIES on data-- @fixture invoices.R2.S3 @boundary
QAChecklistone item per scenario

EARS requirements

EARS (Easy Approach to Requirements Syntax) limits each requirement to one sentence in one of these shapes:

PatternTemplate
UbiquitousThe <system> shall <response>.
EventWhen <trigger>, the <system> shall <response>.
StateWhile <state>, the <system> shall <response>.
UnwantedIf <condition>, then the <system> shall <response>.
OptionalWhere <feature>, the <system> shall <response>.
ComplexWhile <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:

TagAskExample
@zeronothing / emptyno invoices → empty state
@onethe single basic caseone line totals correctly
@manyseveral, order, duplicatesthree lines in two currencies
@boundarylimits and edgesthe 5th failed login blocks; last day of a period
@interfacethe contract403 for another provincia; API shape
@exceptionbad input, failureinvalid code → clear error, nothing saved
@simplethe happy pathcreate 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.