Building Relay

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

Source: SRS — Software Requirements Specification

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:

  1. Did every ★ moment produce a requirement, and do those carry your top priority?
  2. Does every row have exactly one verification method — and could you start writing that test/demo/inspection/analysis tomorrow?
  3. 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.)
  4. 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: