Part 0 · Chapter 0.4
Requirements you can test
You will produce: An SRS slice with IDs, priorities, verification methods · about 100 minutes including the exercise
Chapter 0.3 left us with journey maps and their ★ moments, and they are the best product thinking we have produced so far. They are also, still, stories — and stories don't gate releases. When someone asks "is the reconnection work done?", a journey map answers with a feeling. What we need is a sentence so precise that a machine, a teammate, or a skeptical future version of ourselves can answer yes or no — and prove it. That is what a requirement is, and this chapter converts our maps into a ledger of them. The thesis, up front: a requirement without a test plan is an opinion.
The anatomy of a requirement
Here is one line of Relay's SRS, chosen because you have already met it twice — it is Tuan's tunnel, made precise:
FR-MSG-04 · The system shall accept a client-supplied idempotency key on
send. A repeated key within 24 hours shall return the original message
with 201-equivalent semantics and shall not create a duplicate.
Priority: P1 · Verification: T
Four parts, each doing real work. The ID is a permanent address: FR (functional requirement), MSG (the messaging family), 04 (never reused, even if the requirement is someday removed — an ID that could mean two things across the document's history is worse than no ID). The statement uses shall, the load-bearing verb of specification writing: not "should" (an aspiration), not "will" (a prediction) — an obligation, with a concrete object and a measurable outcome. The priority ties the line to the delivery roadmap. And the verification method answers the question that separates engineering from wishing: how would we know?
The SRS uses four verification methods, and choosing between them is a skill worth having. T — test: an automated check can pass or fail it; FR-MSG-04 is a T, because a script can send the same key twice and count the messages. D — demonstration: a human shows it working; FR-DSH-01 — the dashboard shall display a development API key on the first screen following signup — is a D, because "first screen" is a thing you watch, not assert. I — inspection: you examine an artifact; EIR-API-07's published OpenAPI specification is verified by reading it, not running it. And A — analysis: the subtlest one. FR-MSG-06 reads, in its entirety, "An acknowledged message shall not be lost." No single test run can prove a negative over all futures — verifying it takes reasoning about the design plus fault-injection evidence, which is exactly what "analysis" means. When you cannot name any of the four for a draft requirement, you have not written a requirement yet.
The ledger discipline
Relay's SRS currently holds 224 requirements. That number should alarm you for about five seconds — until you see the second half of the discipline: every requirement carries a priority from P1 to P5, and the priorities are not vibes, they are phases. P1 is the core loop — the product does not exist without it; P2 is the platform surface; P3 is analytics and metering (and now media); P4 is developer experience; P5 is recorded but unscheduled. Of the 224, exactly 57 are P1. The SRS says it plainly: Phase 1 is the realistic first milestone, and everything beyond it is sequenced, not simultaneous. A requirements document without priorities is a wish list with formatting.
And where did the P1s come from? Look at their fingerprints. Server-assigned ordering, idempotent sends, reconnection backfill, tenant isolation — these are chapter 0.3's ★ moments wearing IDs. The stages we starred are the stages that got the highest priorities, which is precisely what the stars were for.
Trace one: Tuan's tunnel becomes three IDs
Follow one ★ all the way down. Tuan's lose-signal moment demanded, in journey language: retrying must be safe, catching up must be exact, reconnecting must not melt the battery. In the SRS those sentences have addresses. The safe retry is FR-MSG-04 above. The exact catch-up is FR-RTM-03 — on reconnection with a resume cursor, deliver everything with a sequence number greater than the cursor, for every channel the user belongs to (P1, T). The battery is FR-SDK-04 — automatic reconnection with exponential backoff and jitter, capped at 30 seconds (P4, T — the SDK ships in Phase 4, which is itself a sequencing decision: the protocol supports resume from day one; the polished client machinery arrives later).
Trace two: Priya's Tuesday, and the most important line in the document
Priya's reconstruct ★ demanded a history that can distinguish "never sent" from "deleted" from "edited". That single stage justifies a small constellation: FR-MSG-07 (immutable edit history, every prior version timestamped), FR-MSG-08 (deletion produces a tombstone, in place, in order), FR-MSG-10 (history responses include the tombstones), and FR-MOD-01 (moderators can retrieve complete history via API key, unrestricted by membership). Four IDs, one Tuesday.
But the SRS reserves its strongest language for a different line. It annotates FR-TEN-05 as the single most important requirement in this document:
FR-TEN-05 · No API operation shall return, modify, or reveal the
existence of data belonging to another tenant, under any input.
Priority: P1 · Verification: T, A
Notice everything this one row teaches. A violation is classified Sev-0 — not a bug severity assigned after the fact, but a promise made in advance. The verification is both T and A: an automated cross-tenant attack suite runs against every endpoint on every build, and the design itself is analyzed so isolation is structural rather than tested-in. Its companion NFR-MNT-02 sets the coverage floor: business logic at 70%, but ordering, idempotency, and tenant isolation at 100% branch coverage — the three subsystems where a missed branch is a lost message or a leaked tenant. Testability is not bureaucratic garnish; it is how a two-person team makes a promise a Fortune-500 security reviewer will accept.
A spec absorbs change without lying
Here is the part most requirements tutorials skip: what happens when the product changes its mind? Relay just did — you watched it. Chapter 0.1 recorded "no hosted file storage" as a non-goal, then reversed it out loud when a design answered every stated reason. Watch what that reversal did to the SRS: it did not rewrite history. It arrived as a brand-new section — §4.14, FR-MED-01 through FR-MED-14, fourteen new IDs with their own priorities and verification methods — while every existing ID kept its meaning. The ledger grew; it never lied.
And the new section immediately re-joined the old conversations. Read FR-MED-09:
FR-MED-09 · A rejected attachment shall render as an explicit rejection
marker in history — never as a broken link — preserving the record that
something was sent (Priya's reconstruction must distinguish "rejected
upload" from "deleted message").
Priority: P3 · Verification: T
A requirement written months after Priya's journey was mapped, citing her ★ by name. The paperwork is not a phase we completed; it is a living instrument that new work must answer to.
Your turn
Time to write the requirements your journey maps have been implying — 8 to 15 of them, no more. (Still on the vet-clinic scheduler? Good.)
Exercise 1 — the slice. Work through your two journey maps, ★ stages first.
Invent a family-prefix ID scheme once — VET-REM-01 for reminders, VET-PRT-01 for
the portal, whatever fits — and keep it forever. For each requirement, write the full
row: the ID; a shall-statement with a concrete object and outcome; a priority with
a one-line phase rationale ("P1 — the product is pointless if reminders don't
arrive"); and exactly one verification method, T, D, I, or A. Your ★ moments must
surface as your top priorities — if they don't, either the stars or the priorities
are wrong.
Exercise 2 — the opinion hunt. Now attack your own slice. For every row, write the single test, demonstration, inspection, or analysis that could fail it. Not verify it — fail it. Here is the drill on the classic offender:
Before: The system shall be fast.
Nothing can fail this. "Fast" has no object, no number, no observer. It is an opinion wearing a shall.
After:
VET-REM-03· A reminder shall be delivered within 5 minutes of its scheduled time for 99% of reminders in a calendar month. Priority: P1 · Verification: A (measured over production traffic; a single test cannot establish a monthly percentile).Now three things can fail it: the measurement, the percentile, the deadline.
Any row of yours where nothing could fail is an opinion — rewrite it with a number and an observer, or cut it.
Self-checks. Each answers yes or no:
- Did every ★ moment produce a requirement, and do those carry your top priority?
- Does every row have exactly one verification method — and could you start writing that test/demo/inspection/analysis tomorrow?
- Did the opinion hunt kill or repair at least one row? (If not, hunt harder — a first draft with zero opinions has never been observed in the wild.)
- Could your ID scheme survive three years of the product changing around it?
Keep the slice with your other Part 0 artifacts, in the repository. Chapter 0.5 decides the architecture — and it will be judged by exactly one standard: whether it can satisfy these rows.
Takeaways
If you read nothing else in this chapter, keep these:
- A requirement without a test plan is an opinion. Every row answers "how would we know?" with one of four methods: test, demonstration, inspection, analysis.
- IDs are promises. Stable, never reused, family-prefixed — a permanent address that code, tests, and tutorials can cite for years.
- Priorities are phases, not vibes. 224 requirements, 57 in Phase 1 — sequenced, not simultaneous. Your ★ moments become your P1s.
- The most important requirement is the one you test on every build. FR-TEN-05's cross-tenant suite and the 100%-branch-coverage trio show what "non-negotiable" looks like in practice.
- A living spec absorbs change with new IDs, never edits. The FR-MED section is a reversed non-goal arriving as fourteen testable sentences — the paperwork chain closing itself in real time.