Test Design
/test-cases designs cases into
syntaxis/qa/cases/<area>.md. It runs nothing and proves nothing: a case is a
specification of an observation someone will make later, by hand or through
automation.
Cases come from requirements
Section titled “Cases come from requirements”The source of truth, in order:
syntaxis/context/current-feature.md— the active spec’s done-when criteria, the primary sourcesyntaxis/build-plan.md— the item and its stable numbersyntaxis/qa/test-plan.md— scope, risk priority, target platformssyntaxis/context/project-overview.md— product rules
The implementation is read last, and only to find reachable states a requirement implies but does not spell out. When the code contradicts the spec, that is a defect to report, not a requirement to encode into a case.
Coverage derivation
Section titled “Coverage derivation”For each requirement, cases cover:
| Dimension | What it means |
|---|---|
| Expected path | The requirement met, in the normal way |
| Boundaries | Empty, minimum, maximum, one past maximum, zero, negative, largest realistic |
| Invalid input | Wrong type, wrong format, malformed, and hostile input where untrusted users reach the field |
| State and permission | Logged out, wrong user, insufficient role, expired session, another user’s record |
| Interruption | Network loss, failed dependency, duplicate submit, back-navigation mid-flow |
Mobile surfaces add permission grant and denial, background and resume, offline and reconnect, rotation, display sizes, and interruption by a call or notification — but only for platforms the test plan actually targets.
Coverage is derived from what the requirement claims. Cases are never padded to hit a count, and a requirement with no observable outcome is reported as untestable rather than given a case that asserts nothing.
Anatomy of a case
Section titled “Anatomy of a case”### TC-014 [P1] manual - Checkout rejects an expired card
**Covers:** feature 7 / done-when 3**Preconditions:** A signed-in account with one saved expired card.**Steps:**1. Open the cart with one item and choose Checkout.2. Select the saved card ending 4242.3. Submit the order.**Expected:** The order is refused, the message names the expiry as thereason, the cart keeps its item, and no charge is created.**Platforms:** web, iOS**Notes:**The header line is a machine-readable contract:
### TC-<id> [<priority>] <automation status> - <title>| Field | Rules |
|---|---|
TC-NN |
Sequential across the whole cases/ tree. Never reused, never renumbered. |
| Priority | P0–P3, by the consequence of the behaviour failing |
| Automation status | manual, automated, or retired. /automate owns the move to automated. |
Covers
Section titled “Covers”Required, and must name a real build-plan item, done-when criterion, or
documented product rule. This is the traceability link: it is what lets
/test-cases report which requirements have no coverage.
Expected
Section titled “Expected”One observable outcome per case, specific enough that two people would agree on pass or fail. “Works correctly” is not an expected result.
State the negative half when there is one. “The cart keeps its item and no charge is created” is two assertions, and a test that only checks the error message does not cover this case.
What a tester does, in the user’s terms. Never internal functions, database tables, or component names.
Identifiers are durable
Section titled “Identifiers are durable”TC-NN values are sequential across the whole tree, one past the highest ID
present anywhere. They are never reused and never renumbered, even after a case
is retired.
This matters because old cycle records in syntaxis/qa/runs/ reference them. A
renumbered case silently rewrites history that was already recorded as evidence.
Retire rather than delete. Set the status to retired and say why in
Notes.
Coverage reporting
Section titled “Coverage reporting”/test-cases finishes by stating honestly:
- requirements with no case
- cases whose Covers no longer matches a live requirement
- areas the test plan calls high risk that remain thin
- untestable requirements, and why
- contradictions found between spec and implementation, which go to
/fixor/debug
Assembling a regression set
Section titled “Assembling a regression set”/test-cases regressionThis selects from existing cases across areas. It does not invent new ones.