Requirements at Speed
What makes a word trustworthy?
Chapter 2 — Requirements at Speed
“The hardest single part of building a software system is deciding precisely what to build.” — Frederick P. Brooks, Jr., “No Silver Bullet — Essence and Accident in Software Engineering” (1987)
“Let what you say be simply ‘Yes’ or ‘No’; anything more than this comes from evil.” — Matthew 5:37 (ESV)
Why This Matters
Last Friday you signed a charter. You adopted a brief from the Fast-Start Catalog, or you brought your own project and used a brief as the template, and either way you now hold something most students in a capstone course do not hold in Week 2: a written, scoped, sized commitment. That was the whole point of Week 1, and it is the only place this edition buys its time back. This week you spend some of it. You put on the hat of the business analyst — the person on a funded team whose entire job is to stand between a vague human desire and an engineer who needs to be told exactly what to build — and you keep a second hat on top of it, risk owner, because you do not get a separate week for the requirements nobody writes down. In the sixteen-week edition this is two weeks and roughly thirty hours: one for what the system does, one for how well it does it, what it must never do, and what you are betting on. You have twenty hours and one week for all of it.
Here is how that is possible, and it is not by cutting anything. Your brief already contains eight to ten drafted functional requirements with acceptance criteria and four to six non-functional requirements with measurable targets. You are not starting from a blank page. You are starting from somebody else’s page, and your job this week is to make it yours — which is a different skill, faster than authoring, and considerably easier to do badly. The signature failure of this edition is a requirements document that quietly describes the brief’s project instead of yours: a household when your users are a club, a barcode integration you dropped on day three, a persona nobody in your life resembles. Those sentences look finished. They pass every linter. They are wrong in a way that does not surface until Week 6, when you build one and nobody wants it.
Everything downstream reads from what you write in the next twenty hours. Week 3’s architecture decision records answer this document. Week 4’s design review audits you against it. Weeks 5 and 6 build exactly the Must list you set here, and nothing else, because there is nothing else in the budget. Week 8’s rubric grades whether the thing you shipped is the thing you said you would ship. And one week is an eighth of your term, so falling behind is proportionally twice as expensive as it would be in the long edition. There is no catch-up week. There is only the next week, already full.
The AI thread runs hard through this one from both sides. As a tool, an assistant is a genuinely excellent interrogator: hand it your adapted requirement set and ask it to enumerate the situations no requirement covers, and it will find real gaps in ninety seconds that you would not find in an hour. As a hazard, its output is the most dangerous artifact in a compressed course, precisely because it is fluent. Ask it to “write the requirements for my app” and you will get forty confident, well-formatted, plausible sentences, a third of them for features you never intended, none of them traceable to a human being who wants them — and in an eight-week term you will not have time to discover which third. As a workload, if your project has an AI feature, this is the week you learn to specify something whose output is probabilistic, which is possible only if you stop specifying the output and start specifying the envelope around it.
Which brings the week’s question, and in this edition it has a sharper edge than usual: what makes a word trustworthy? You are about to sign your name to a document made largely of sentences you did not originally write. Some of them came from a brief. Some of them may have come from a model. The document will be judged as yours, because it is. Let’s find out what that actually costs, and what it is worth.
2.1 — Adapting Beats Authoring: Where the Two Weeks Went
The sixteen-week edition spends Week 3 eliciting and drafting functional requirements from nothing, and Week 4 on the non-functional half, the constraints and obligations, the traceability matrix, and the definition of done. Roughly thirty hours across two weeks. You are doing the same list to the same standard in twenty hours, in one.
| The long edition | This edition |
|---|---|
| Week 3: elicit, then write 18–35 functional requirements from a blank page | You inherit 8–10 drafted functional requirements and decide, one at a time, which survive contact with your project |
| Week 4: non-functional requirements, constraints, assumptions, dependencies, obligations, traceability, definition of done | The same list, the same standard, the same week — because the brief already handed you 4–6 measurable NFR targets to argue with |
| ~30 hours, two weeks, blank page | 20 hours, one week, inherited draft |
Call the saving roughly ten hours. That is this edition’s central design assumption, and it is an assumption about drafting, not about thinking: the brief removes the typing and the staring, and it does not remove a single decision.
| The brief gives you | The brief cannot give you |
|---|---|
| A real problem and a named user archetype | Your user, with a name and a date on the conversation |
| 8–10 drafted functional requirements with acceptance criteria | Which of them your 160 hours can actually carry |
| 4–6 non-functional targets with numbers in them | Your data volume, your device, your connection — the conditions those numbers must be measured under |
| A suggested stack sized to the budget | Your skills, your administrator rights, your institution’s hosting |
| A what-to-cut-first list | The cut you will actually have to make in Week 4 |
| The genuinely hard part, named in advance | The judgment to keep going when you hit it in Week 6 |
Read the right-hand column again. Every row of it is a decision only you can make, and together they are what this week is for. The brief is scaffolding, not a specification. A student who copies the left column into docs/requirements.md and commits it has produced a document with the shape of professional work and none of the content, and they will find out in Week 4, in front of a reviewer.
You still talk to one human. This is the one piece of the long edition’s elicitation work that does not compress, and I will not pretend otherwise. Thirty minutes, one person who actually has the problem your project solves — not a classmate being polite about your idea. One question does most of the work: “walk me through the last time you did this.” Not “what do you need,” which produces a wish list, and not “would you use an app that…,” which produces politeness. People are unreliable about general preferences and remarkably reliable about what they actually did on Tuesday. Write the notes up the same day as docs/elicitation-notes.md, dated, marking every sentence F (a fact about today), W (a want), or O (an opinion). Ninety minutes total including the write-up, and it is the highest-value ninety minutes in this chapter, because it is the only evidence in your document that a real person exists.
Coach’s Note — The workaround is the requirement. When somebody describes an awkward thing they do to get around a problem — the spreadsheet tab named
temp2, the text message they send themselves, the photo of the whiteboard — you have found a requirement already validated by the fact that a human was willing to do manual work to get it. One of those is worth ten features a brief suggested and nobody asked for twice.
2.2 — The Anatomy of a Functional Requirement
A functional requirement says what the system does. In this course it has six parts, and it is not finished until all six are present — whether you wrote it or inherited it.
| Part | Question it answers | Example |
|---|---|---|
| Identifier | How do we refer to this in a board card, a branch, a test, a commit? | FR-EXP-02 |
| Actor | Who or what triggers it? | a signed-in household member |
| Action | What can they do? | view |
| Object | To or with what? | every pantry item |
| Condition | Under what circumstance, with what bound? | whose expiry date falls within the next seven days, ordered soonest first |
| Priority | Must, Should, Could, or Won’t this release | Must |
Assembled, in the house sentence shape: FR-EXP-02 — Expiring-soon view, Priority: Must — “A signed-in household member shall be able to view every pantry item whose expiry date falls within the next seven days, ordered soonest first.” That is PantryPilot, the running example of both editions of this book and brief #1 in the Fast-Start Catalog: a small web application that lets a shared household track what food it has, what is about to expire, and what can be cooked from it tonight. The book’s second example, TraceLens, is its opposite — a command-line log analyzer with no interface, no accounts, and exactly one user who is tired and in a hurry. Your project will look like neither. The shape transfers.
Three rules about identifiers, and they matter more than they look.
- Format
FR-<AREA>-<nn>, or flatFR-<nnn>— pick one this week and never mix them. The area-scoped form is what I recommend and what this chapter’s templates use: the prefix (INV,EXP,SCAN,REC,ACC) lets you read a branch name or a commit message and know what part of the system it touches without opening anything. The flat form is legal. Mixing them is not —FR-014andFR-EXP-14are the same requirement to you and two different rows to every script you will ever run against this file. - Assign once. Never reuse. Never renumber. When a requirement dies, mark it
Withdrawnand leave the number in the document. This rule bites harder in this edition than in the long one, because you will be withdrawing inherited requirements all week, and the temptation to tidy up afterward is enormous. Renumbering silently breaks your board, your branches, your tests, and your traceability matrix. - If you adopted a brief, renumber the brief’s identifiers exactly once — at the start, before anything references them. The catalog’s drafted requirements ship with their own numbers. Adopt them wholesale or restate them in your scheme, but do it in the first hour of the week, and record in the change log that you did. After that, the freeze applies.
On shall. It reads stiff, and that is exactly why it is used: it marks a binding obligation, and nothing else in English does that job as cleanly. Keep “should,” “may,” and “will” out of requirement sentences entirely and put the strength in the priority field, where it can be sorted, counted, and cut. IEEE Std 830-1998 was the long-standing recommended practice here and has since been superseded; ISO/IEC/IEEE 29148 is the current requirements-engineering standard, and you should check its current revision rather than trusting a year quoted in a textbook. Both converge on the same short list of qualities for an individual requirement, and it is the list you are graded against: unambiguous, verifiable, singular, feasible, necessary, implementation-free, traceable. Seven words. Tape them above your desk for eight weeks.
2.3 — Acceptance Criteria a Stranger Could Verify
A requirement without acceptance criteria is an opinion. The criteria are what make it checkable by someone who is not you — which is the entire point, because in Week 8 someone who is not you decides whether you built it. The house form is Given a specific starting state / When a specific actor does a specific thing / Then a specific, observable result. The word doing the work is observable. “Then the item is saved” is weak — saved where, visible to whom? Every Must and Should carries at least two criteria: the happy path, and one thing going wrong.
Given a signed-in member on the pantry screen,
when they submit a name, quantity, unit, and expiry date,
then the item appears in the household pantry list within one page
refresh and is visible to every member of that household.
Given a submission missing the item name,
when the member submits,
then the system rejects the submission and states which field is missing.
Notice what the second one did. It turned “validation” — a word you would have waved at — into a decision made in writing: rejection, not silent default, with a message that names the field. That is a design decision made in Week 2 for free instead of in Week 6 under pressure, and in a course this short, free is the only kind you can afford.
Three tests for a criterion. The stranger test: could someone who has never seen your code run this and get an unambiguous pass or fail? The number test: does every quantity have a number — “soon,” “recent,” “large,” and “several” are not numbers. The failure test: have you said what happens when the input is bad, the network is down, or the list is empty?
And one test unique to this edition. The inheritance test: does this criterion name data, a role, or an integration that exists in your project? A criterion that says “given two household members” in a project with one user is not a weak criterion. It is somebody else’s criterion.
When the output is probabilistic
If your project has an AI feature — a recommendation, a summary, a classification, a generated draft — you cannot write “the system shall return the correct answer,” because there is no single correct answer and the same input will not always produce the same output. Stop specifying the output. Specify five things around it.
| What you specify | For PantryPilot’s recipe suggester |
|---|---|
| The envelope — input preconditions, output shape and count, latency bound | ≥ 5 pantry items in; 1–3 suggestions out; within 8 seconds |
| The guardrails — what it must never do | Never present an ingredient the household does not have as on hand; never state a nutrition or allergen claim |
| The fallback — behavior when the model is slow, unavailable, or returns garbage | After 8 seconds or on a malformed response, show the three items closest to expiry with no suggestion, and say why |
| The evaluation set — a fixed set of inputs with a pass bar, written before you build | 20 pantry states committed to the repository; ≥ 16 must satisfy the envelope |
| The disclosure and the override — what the user is told, and how they refuse it | Output labeled as generated; a dismissed suggestion is not re-shown that day |
Three things about that table are easy to skim past. The evaluation set is the acceptance criterion — fixed in advance, committed this week, unchanged after you see the results; once you have seen the output, every failing case will look like a case that “doesn’t count.” The pass bar is a fraction, not a promise — “16 of 20” is an honest requirement for a probabilistic feature; “all suggestions shall be good” is a hope with a shall in front of it. The fallback is a Must even when the feature is a Should, because your provider will be slow or down at some point in eight weeks and the most likely moment is the Week-8 demo.
One accuracy note that will cost you money if you skip it: model pricing, free-tier allowances, rate limits, and context windows change frequently and vary by vendor, plan, and region. Never write a number into your specification from memory or from a blog post. Look it up on the vendor’s own page, write the number with the date you checked it, and put it in your assumptions table.
2.4 — Inherited Requirements That No Longer Fit Your Project
This is the section this edition exists for. You are holding a set of drafted requirements written by someone who did not know you, your users, your skills, or your semester. Most of them are good. Some of them describe a project you are not building. And the dangerous ones are not the obviously wrong ones — those you delete in ten seconds. The dangerous ones are the plausible ones: a requirement that fits the brief’s problem so naturally that you never stop to ask whether it fits yours.
Every inherited requirement gets exactly one of four verdicts, in writing, with a reason.
| Verdict | When | What you do |
|---|---|---|
| Keep | The actor, the object, the condition, and the acceptance data all still exist in your project | Nothing but restate the identifier in your scheme and record Kept |
| Adapt | The capability is right; one or more of the six parts names something that changed | Repair the specific part — usually actor, condition, or the numbers in the criteria — and record what changed and why |
| Split | Your change turned one obligation into two independently verifiable ones | Two identifiers, two priorities. Watch what happens to the priorities once they are separate |
| Withdraw | The capability belongs to a scope you dropped, an integration you cut, or a user you do not have | Mark it Withdrawn, leave the number, write the one-line reason. Do not delete the row |
Three questions decide the verdict, and you can run all three in under a minute per requirement.
- Does my actor appear in it? If the sentence says “household member” and your users are a fourteen-person rowing club sharing a boathouse fridge, the actor is wrong and so, probably, is the ownership model underneath it.
- Does my scope still contain it? If you dropped barcode scanning on day three, every requirement whose condition mentions a scanned code is withdrawn — including the one three rows down that only mentions it in an acceptance criterion.
- Does the acceptance data exist in my project? “Given a pantry containing items expiring in 2, 6, and 20 days” is fine. “Given two members of the same household with notifications enabled” is not, if you have no notifications.
Here is the move worked end to end. A student adopts brief #1 and adapts it for CrewPantry — the same problem, but the users are a rowing club that shares one boathouse kitchen, and the student cut barcode scanning in Week 1 to fit the budget. CrewPantry is that student’s project, not yours and not the brief’s: it appears in this section only, to show you what the adaptation move looks like when somebody actually does it. The rest of this book keeps illustrating with PantryPilot as the catalog wrote it, so you always have the unadapted original to compare against.
INHERITED FR-ACC-01 (Must) — A person shall be able to enter a household
by supplying its six-character join code, receiving a session
scoped to that one household and lasting fourteen days.
VERDICT Adapt + Split.
ADAPTED FR-ACC-01 (Must) — A person shall be able to enter the club
kitchen by supplying a join code issued to one named person on
the roster, receiving a session bound to that roster entry and
lasting fourteen days.
SPLIT OUT FR-ACC-06 (Should) — A roster owner shall be able to remove a
member from the roster and revoke that member's code, after
which the removed member's items remain in the kitchen
inventory and are reassigned to the roster owner.
WHY One code the whole house knows is a fair trade for four people
who already share a front door. Fourteen rowers with three-year
turnover cannot revoke a code nobody owns, so the code went
per-member — and the moment it did, removal became a second,
independently verifiable obligation, and the orphaned-items
question had to be answered somewhere or it becomes a Week-6
defect.
The withdrawal is shorter and just as deliberate. FR-SCAN-01 — add an item by barcode — is marked Withdrawn with a dated one-line reason: barcode lookup cut in the Week-1 scoping decision; the integration and its failure paths were estimated at 14 hours against a 160-hour budget. The number stays in the document. And FR-SCAN-02, the requirement describing what happens when the lookup service is unavailable, goes with it, because its entire subject is the behavior of a service this project no longer calls. That second one is the row students miss: the withdrawal you forget is never the headline feature, it is the failure path attached to it.
The tell for a stale requirement is almost always a noun that appears nowhere else in your charter. Household. Barcode. Administrator. Tenant. Subscription. Run that sweep mechanically: python3 check_requirements.py docs/requirements.md --stale-terms household,barcode,admin using code/check_requirements.py, and it will list every requirement still carrying a word from a project you are not building. It takes four seconds and it catches the thing a careful human read reliably misses, because a careful human read is exactly what makes an inherited sentence look normal.
The assistant as interrogator
An assistant is very good at one job this week and very bad at the adjacent one. The bad job first, because roughly everyone will attempt it: “write the functional requirements for a pantry-tracking app.” Thirty to fifty polished sentences in eight seconds, organized, using shall correctly, several of them vague in exactly the ways section 2.8 catalogues, a third of them for features nobody mentioned, and none of them traceable to a human who wants them. In a sixteen-week course that costs you a week. In this one it can cost you the project, because you will not have time to discover which sentences were invented before you start building them.
The good job is interrogation. Three prompts that earn their tokens, and in all three the model never produces the artifact:
STALE SWEEP "Here is my charter and my adapted requirement set, which came
from a template for a different project. List every requirement that still
assumes something my charter does not contain -- a user role, an integration,
a data volume, a deployment target. Quote the exact phrase. Rewrite nothing."
FIND THE HOLES "Here are my 16 functional requirements. Do not rewrite them.
List every situation a user could get into that none of these covers, and for
each, name the identifier that should have covered it."
ATTACK ONE "Here is one requirement and its acceptance criteria. Find every
way two engineers could read this sentence and build different things."
STALE SWEEP is this edition’s prompt and the highest-leverage one you will run all week — the model has no attachment to the brief’s wording, which is precisely the attachment you have. FIND THE HOLES is a genuine model strength and a genuine human weakness. ATTACK ONE is a free ambiguity review. And the failure modes, which you must be able to name in the Week-4 review:
- Invention. It produces requirements for features nobody mentioned, with the same confidence as the ones you asked for. Every requirement in your document carries a
Source:line naming a human, an observation, a brief, or a decision you made and recorded.Source: the model suggested itgets a real source or gets deleted. - Fluency mistaken for precision. Generated requirements read as polished. Run the linter over anything a model touched.
- Over-scoping. An assistant has no concept of your 160 hours. It will cheerfully specify a system that takes 900. You are the only one in the loop who knows the budget.
- No accountability. A requirement is a promise, and a promise requires somebody who can be held to it. The model cannot be held to anything. You can.
The spine rule for the week: the assistant may ask, enumerate, and critique. You decide, you type the sentence, and you sign it. Log every substantive use in docs/ai-usage.md — tool, prompt shape, what you kept, what you threw away and why. An honest log with real “I discarded this” entries reads far better in Week 8 than a suspiciously empty one.
Coach’s Note — The most expensive sentence in an accelerated capstone is the inherited requirement you never questioned, because it costs nothing in Week 2, nothing in Week 3, and a full weekend in Week 6 when you finally build it and realize nobody in your project has the role it was written for. Question every line once, early, on purpose. That is the whole week’s insurance policy and it costs about three hours.
2.5 — Non-Functional Requirements, Made Measurable This Week
A functional requirement says what the system does. A non-functional requirement says how well it does it, under what conditions, and what it must never do. Gerald Weinberg’s definition is the one to keep — “quality is value to some person” — because it forces the question every vague quality word dodges: value to whom, and how much. The long edition gives this its own week; you are doing it in about three and a half hours, and you can, for one reason: your brief already handed you four to six targets with numbers in them. What it did not hand you is the condition and the method, and those are the two fields that make a requirement real.
Four fields. Every non-functional requirement, no exceptions.
| Field | The question | Example |
|---|---|---|
| Metric | What number are we talking about? | 95th-percentile page load time |
| Threshold | What value counts as pass? | under 1.5 seconds |
| Condition | Under what circumstances? | 200 seeded records, throttled “Fast 3G,” cold cache |
| Method | How will anyone check? | 20 loads in browser dev tools; p95 recorded in docs/measurements.md |
Method is the field students skip and the field that makes the requirement real. A threshold with no method is a number you made up and will never test; write the method and you have accidentally written a Week-6 test case. And use p95, not the average, for anything a human waits on: if nineteen loads take 0.4 seconds and one takes twelve, the average is a comfortable 1.0 second and one user in twenty just had a terrible time. Two rewrites, because the move never changes. “The system shall be fast” becomes NFR-PERF-01 (Must) — the pantry list view renders at a p95 under 1.5 s with 200 seeded items on a throttled Fast 3G profile with a cold cache; measured by 20 loads in browser dev tools with throttling applied, p95 recorded in docs/measurements.md each iteration. And “the system shall be secure” — which is three requirements in a trench coat — becomes NFR-SEC-01 (Must), no credential, API key, or token appears in the repository at any commit in history; measured by a secret-scanning step in CI over full history, zero findings, plus NFR-SEC-02 (Must), every write endpoint verifies server-side that the caller owns the target record; measured by one negative test per write endpoint asserting a 403 for a non-owner.
Eight categories exist. Five is the working minimum here — one fewer than the long edition asks for, scaled to a project two-thirds the size, and it is the only number in this book that moves. Every artifact still ships and every requirement still carries four fields. For each category you skip, write one sentence saying why it does not apply to your project. “Not applicable” alone earns nothing; the sentence is the work.
| Category | The question | A defensible student-scale target | How you check it in an afternoon |
|---|---|---|---|
| Performance | How long does a person wait? | p95 under 1.5–2 s for the primary view at your real data volume | Dev-tools throttling, 20 loads, record p95 |
| Reliability | What happens when something breaks? | Zero unhandled exceptions on identified failure paths | One test per failure mode |
| Security | What must never happen? | No secrets in history; server-side authorization on every write | CI secret scan; negative tests |
| Privacy | Whose data do you hold, and can they get out? | Deletion removes every row; nothing personal leaves without opt-in | Delete-and-query test; a redaction unit test |
| Accessibility | Who can use this? | Keyboard-operable, 4.5:1 text contrast, labeled inputs | Unplug the mouse; run a contrast checker |
| Usability | Can a stranger do the main task? | First-time user completes the primary task unaided in under 3 minutes | Two observed sessions, timed |
| Maintainability | Can the next person work here? | Clean clone to running in under 10 minutes; suite runs with one command | The clean-machine test |
| Portability | Where does it run? | Two current major browser versions, or two OSes for a CLI | Manual smoke of the three core flows |
Do not copy enterprise numbers. “99.99% availability” is roughly 52 minutes of downtime a year on a free tier that idles your service after inactivity — you cannot deliver it, measure it, or detect a violation, and you will be graded against it. Every measurement method must fit in an afternoon with tools you already have; a modest requirement you actually check beats a heroic one you never do. Security is easiest to make verifiable, because most of it is prohibitions, and a prohibition is trivially testable. Write at least three: no credential in the repository at any commit; every write authorized server-side, not by hiding a button; all persistence through parameterized queries or the framework’s query builder. If you handle passwords at all, store only hashes from a maintained, memory-hard password-hashing library — or better, delegate sign-in and hold zero credentials. The OWASP Top Ten (https://owasp.org/www-project-top-ten/) is the standard starting reference; read the current list, pick what applies to your architecture, and turn each item into a requirement with a test. Do not paste the list in as-is.
Privacy starts with an embarrassingly simple table that almost nobody makes.
| Data element | Why you need it | Where it lives | How long you keep it | How a user gets rid of it |
|---|---|---|---|---|
| Email address | Sign-in, roster invites | users table | Until account deletion | Account deletion |
| Item names sent to a hosted model | FR-REC-01 | Not stored; sent in-flight | Vendor’s terms — verify and cite | N/A |
| Session logs | Debugging | Hosting provider’s logs | Provider default — verify and cite | N/A |
The two rows marked verify and cite are the two that matter. You do not know a vendor’s retention policy; neither do I, and neither does an assistant. Read the vendor’s own page, write the URL and the date you checked into your document, move on. That habit — primary source plus date checked — is the most professional thing in this chapter, and it applies equally to licensing. Your project needs a LICENSE file this week or next, named by its SPDX identifier (https://spdx.org/licenses/); https://choosealicense.com/ is a reasonable plain-language orientation. Permissive licenses (MIT, Apache-2.0, BSD) are the common default for a portfolio project; copyleft licenses attach conditions to how derived or combined work may be distributed, and how those conditions reach your project depends on the specific license and on how the code is combined. Read the license text, not a summary — not mine, and not a chatbot’s. For accessibility, the reference is the W3C’s Web Content Accessibility Guidelines; Level AA is the bar people actually contract to, and you should check https://www.w3.org/WAI/ for what is current rather than citing a version from memory. You will not conform to all of it in eight weeks and I will not pretend otherwise. Pick four criteria covering the most common, most excluding failures, write them measurably, and actually check them — most of the checks take ninety seconds. Unplug the mouse. Set the display to grayscale. If your project has no graphical interface, accessibility changes shape rather than evaporating: never signal severity by color alone, honor a --no-color flag, keep output parseable when piped, and use exit codes correctly. A CLI has neighbors too.
Coach’s Note — Ask the roommate question: if the person whose data this is were reading over my shoulder while I wrote this line, would I write it the same way? For PantryPilot the roommates are literally the users. For your project, someone is.
Finally, the three tables the long edition gives a whole section and this one gives thirty minutes: constraints (limits you did not choose — 160 hours, solo, zero budget — which you design inside), assumptions (things you are treating as true without proof, each with an owner, a verify-by date, and the consequence if false), and dependencies (things outside your control, each with a pinned version or plan, a failure mode, and a fallback). Write the consequence column first. “If the free hosting tier does not survive the term, I demo from a local run and record a fallback video in Week 7” turns a vague worry into a calm decision. Every unverified assumption becomes a row in Week 3’s risk register, in docs/risk-register.md. Nothing stays on the assumptions list forever, and in eight weeks “forever” is about ten days.
2.6 — MoSCoW Against a 160-Hour Budget: The Must List Is the Schedule
MoSCoW sorts requirements into four buckets, and in this edition the arithmetic behind them is not a suggestion.
| Bucket | Meaning | The honest test |
|---|---|---|
| Must | Without it, the release is not the thing you promised | If this is missing, would you refuse to demo? |
| Should | Painful to omit; the release is still real | Would you ship without it and feel bad? |
| Could | Genuinely nice; the first thing cut under pressure | Would anyone notice it was missing? |
| Won’t (this release) | A decision, recorded | Will you be tempted by this in Week 6? |
Now the arithmetic, and it is the most important paragraph in this chapter. Chapter 1 did the division; here is what it means for your Must list. Of the 160 hours, about 54 are hands on code — eight in Week 3 for the walking skeleton, forty across Weeks 5 and 6, six in Week 7 for deployment. But fourteen of those are skeleton and deployment plumbing, and twelve are verification in Week 6: the test plan, the test cases, the defect triage. What remains — the hours in which a new feature actually gets built — is about thirty, effectively all of it in Weeks 5 and 6, with a hard ceiling near forty that you can only reach by borrowing from testing and documentation.
Two numbers, and you must not confuse them. Build capacity is the roughly fifty engineering hours Weeks 3, 5, and 6 contain; that is what your Week-3 work plan allocates. Net feature construction is the thirty inside it that new features can have. Your Must list is checked against the thirty.
Thirty hours, at seven to nine hours per vertical slice in a stack you know — or twelve to twenty in one you do not — is three to four Must features. Not five. Not “five if things go well,” because things will not go well; the brief told you in advance which part is genuinely hard, and that part will take longer than you think. This is the two-thirds rule stated as division rather than as advice: 160 hours buys a project about two-thirds the size of a sixteen-week capstone, and the single most common way to fail an accelerated course is to attempt a full-length project in half the calendar.
So there are two checks on your Must list, and you run both.
- The ratio check, inherited from the long edition: Musts at no more than about half your total requirements. A draft that comes in at 90% Must has not been prioritized; it has relabeled “everything” in project-management vocabulary.
- The hours check, which is this edition’s: estimate every Must as a full vertical slice, sum it, and compare to thirty. If the sum exceeds thirty you do not have a scheduling problem to solve in Week 3 — you have a Must list to cut, this week, while cutting is free. Past forty you are no longer borrowing from slack; you are spending Week 8’s documentation points. Do the sum in writing and put it in the document; Milestone 2 grades it.
The Won’t-have list is a first-class deliverable, and in this edition it starts half-written: your brief shipped a what-to-cut-first list, and every line of it that you are not building belongs in your out-of-scope table with a reason attached. Five rows minimum. It is the only defense against scope creep — in Week 6 you will have an idea, everyone does, and without a written list you will build it because it is more fun than fixing the defect log. And it is the difference, to a grader, between a student who considered a feature and rejected it and one who never thought of it at all.
Coach’s Note — The hardest No is the one you say to yourself. Half your Won’t list will be features you were excited about. Write them down anyway with the honest reason: “fourteen hours the budget does not have.” That sentence, written today, is what lets you finish in Week 7 instead of shipping something broken in Week 8. Luke 14:28 has the builder sitting down to count the cost before laying the foundation, and the reason given is not prudence for its own sake — it is so that he is not mocked for a tower he could not finish.
2.7 — Traceability and the Definition of Done
Two small artifacts close the week, and together they turn a document into a mechanism. A requirements traceability matrix is one row per requirement and a handful of columns that answer three questions nothing else answers. Is every requirement actually being built? A requirement with no design element is an orphan — you promised it and nothing is responsible for it. Is everything I am building actually required? Work with no requirement behind it is gold-plating — real hours spent on something nobody asked for, and you have thirty. Is every requirement tested? No test means no evidence, and no evidence means it does not count.
The columns that earn their keep at this scale: req_id · type · priority · requirement · source · design_element · test_id · measurement_method · status. This week the design and test columns mostly hold placeholders, and that is correct — Week 3 fills the design column, Week 6 fills the test column. Start from code/traceability.csv, which is deliberately broken in three places so you can learn to see the breaks at a glance, then run:
python3 check_requirements.py docs/traceability.csv
The same script lints both artifacts — point it at a .md and it checks requirement blocks, point it at a .csv and it checks traces. It exits non-zero on a blocker, so once your matrix is supposed to be clean you can run it in CI from Week 3 and let the pipeline nag you instead of a reviewer in Week 4.
A definition of done is a single checklist that applies to every work item, not to the project. It is not acceptance criteria — those are per-requirement and answer “does this feature do the right thing?” The definition of done is universal and answers “is this work finished to the standard I work at?” Here is the version that fits eight weeks:
An item is Done when:
1. It traces to a requirement ID in docs/requirements.md.
2. Every acceptance criterion for that requirement passes when run, not when read.
3. At least one automated test covers the new behavior; the whole suite passes.
4. The pipeline is green on the merge commit.
5. No secret, key, or real user data was added to the repository.
6. The most likely failure path shows a message naming what failed.
7. New user-facing surfaces are keyboard-operable and labeled (or, for a CLI,
readable with color disabled).
8. Anything a stranger needs to know is in README.md, CHANGELOG.md, or docs/runbook.md.
9. AI assistance is recorded in docs/ai-usage.md; hours are logged the same day.
Every item is answerable yes or no by someone who is not you. That is the test. And then the rule that makes it worth having — the honesty rule: if you will not do it every time, take it off the list. Eight to ten items you genuinely honor beats twenty aspirational ones, and in this edition I would rather see eight, because a list you start skipping in Week 5 teaches you that written commitments are decorative. The starter file is definition-of-done.md in the companion code for Chapter 5 — ten checks with the bracketed parts you adapt to your stack, and the bad version annotated line by line beneath them. It ships with Week 5 because Week 5 is where you start applying it without mercy, but you write yours this week: copy it in as docs/definition-of-done.md, cut it to the items you will actually honor, and link it from README.md.
2.8 — The Bad-to-Good Gallery, Accelerated
Eight real-looking bad requirements — the exact sentences that appear in capstone drafts every semester — with their defects named from a fixed palette and a rewrite that would survive review. The palette is the one the widget uses, and it has one entry the long edition does not: ambiguous · unverifiable · compound · solution-biased · missing actor · missing condition · unmeasurable · inherited.
1 · “The system shall be user-friendly.” — ambiguous · unverifiable · unmeasurable · missing actor — NFR-USE-01 (Should) — “A first-time user, given only the task ‘add the milk in the fridge and set it to expire Friday,’ completes it without assistance in under 3 minutes,” measured by two observed sessions with people who have not seen the app, time and stumbles recorded in the usability notes. A quality is real only when it is measured: name the metric, the threshold, the condition, and the method.
2 · “Users can manage their pantry.” — ambiguous · compound · unverifiable · missing condition — “Manage” hides somewhere between two and eight features. Split it into four: add, edit, list, remove. One of them becomes FR-INV-04 (Must) — “A signed-in member shall be able to mark a pantry item as consumed, which removes it from the active pantry list,” with the criterion given an item in the active list, when a member marks it consumed, then it no longer appears in the active list. Watch how differently the four get prioritized once they are separate.
3 · “The system should send notifications when food is about to expire.” — unmeasurable · missing condition · priority hidden in “should” — FR-EXP-05 (Should) — “The system shall send one notification per kitchen per day, at a configured time, listing every item expiring within the next three days, to each member who has enabled notifications.” Three decisions were hiding in “about to expire”: the window, the cadence, and the recipient rule. Each was going to be decided anyway; the only question was whether you decided it in writing now or by accident in Week 6.
4 · “The app will use React and PostgreSQL to store the pantry data.” — solution-biased · compound · missing actor — FR-INV-06 (Must) — “Pantry items entered by any member shall persist across sessions and across devices, remaining available after the member signs out and back in on a different device.” A requirement states the need; the stack is an answer to the need and belongs in an architecture decision record next week. Write the technology into the requirement and you delete your own ability to change your mind in Week 3, which is the week this edition gives you for exactly that.
5 · “The system shall handle errors gracefully.” — ambiguous · unverifiable · missing condition — FR-SYNC-02 (Must) — “When the roster service does not respond within five seconds, the system shall present the manual entry form with any data the member has already entered preserved,” accepted when given the service is unreachable, when a member submits, then within six seconds the manual form appears with the entry retained and a message stating that lookup is unavailable. “Gracefully” is not a behavior. You will not enumerate every error case; enumerate the three that will actually happen.
6 · “A person shall be able to enter a household by supplying its six-character join code, receiving a session scoped to that one household.” — inherited
This sentence has no defect the long edition’s palette can name. It is well formed, it has all six parts — the actor is deliberately anyone holding the code — it has verifiable criteria, and the linter passes it. It is also FR-ACC-01 exactly as brief #1 ships it, written for four roommates who already share a front door, and your project is a fourteen-person rowing club with a roster owner and three-year turnover, where a code nobody owns is a code nobody can revoke. Adapt the sharing model to a per-member code, then split out removal, as in section 2.4 — or keep it untouched if your project really is one small household with no turnover, or withdraw it outright if your project has one user and nothing to join. The defect is not in the sentence. It is in the relationship between the sentence and your charter, which is why no tool will find it for you and why you run the stale-noun sweep by hand once, deliberately, this week.
7 · TraceLens: “The tool shall parse log files.” — ambiguous · missing condition · unverifiable
FR-PARSE-01 (Must) — The tool shall parse log files in Common Log Format and
in newline-delimited JSON, writing any line it cannot parse to a rejects file
with its line number, and continuing without terminating.
Acceptance: Given a 10,000-line file with 12 malformed lines, when the tool
runs, then 9,988 records are parsed and the rejects file contains 12 entries
with their original line numbers.
Naming the formats converts an infinite obligation into a finite one. The rejects behavior is the part students forget and the part that decides whether the tool is usable at 2 a.m.
8 · “The AI shall suggest good recipes.” — every defect on the palette
FR-REC-02 (Should) — Given at least five items in the kitchen inventory, the
system shall return between one and three recipe suggestions within eight
seconds, each listing the items it uses and any ingredients not on hand.
Acceptance: against the fixed 20-case evaluation set committed to the
repository, at least 16 cases return 1-3 suggestions within 8 s, each using
>= 3 on-hand items, with zero suggestions presenting a missing ingredient as
on hand.
You cannot specify what a probabilistic system will say. You can specify the envelope it must stay inside, and you can fix the evaluation set in advance. Six worked requirements set inside a real document, with their rationale, source, and adaptation lines intact, are in code/srs-template.md — read the worked half before you write your own, because seeing the finished shape saves an hour of guessing you do not have.
2.9 — Interactive Lab: The Requirement Adapter
Below this chapter on the website is The Requirement Adapter. Do the whole run in one sitting, before you touch your own document. This is the drill built for the accelerated skill, which is editing rather than authoring.
Each item shows you a starter requirement lifted from a Fast-Start brief and one changed circumstance — your users are a club, not a household; you dropped the barcode integration; your project has one user and no accounts. You choose a verdict: keep, adapt, split, or withdraw. When you adapt, you repair the pieces that broke — the identifier, the priority, the condition, and the acceptance criteria — and the widget scores every field against an answer key. It flags the classic accelerated failure explicitly: a requirement you kept that no longer matches the project you are building.
The panel that will change how you work is the running MoSCoW balance. Every verdict updates a Must count and an estimated Must-hours total against the thirty hours of net feature construction from section 2.6, and you will watch your own Must list grow past what 160 hours can carry — usually around the seventh item, usually because you kept something you should have adapted down to a Should. Seeing that happen in a widget in four minutes is cheaper than discovering it in Week 4 in front of a reviewer. Score under 70% on the verdicts? Run it again before you open your own document. This is conditioning, and conditioning is cheap.
2.10 — What Makes a Word Trustworthy?
“Let what you say be simply ‘Yes’ or ‘No’; anything more than this comes from evil.” (Matthew 5:37, ESV)
Jesus is addressing a culture of oaths. People had developed an elaborate grammar of swearing — by heaven, by earth, by Jerusalem — and the grammar existed for a reason familiar to anyone who has read a bad specification: plain speech was not trusted, so speech got inflated to compensate. If your ordinary yes might mean anything, you need an oath to signal that this time you mean it. And once oaths exist they stratify: some bind you and some do not, and now there is a whole technology for sounding committed while remaining free.
His answer is not a better oath; it is a plainer word. Read this week’s gallery again with that in your ear. “The system shall be user-friendly.” “Errors shall be handled gracefully.” These sentences are not lies, and the student writing them is not dishonest. But notice what they are doing: they use the vocabulary of commitment — shall, the numbered heading, the whole formal apparatus — while carefully keeping an escape hatch. In Week 8, when somebody asks whether the system is user-friendly, there is no answer that can be wrong. That is the point of the sentence. It is oath-language without obligation. Vagueness in a specification feels like humility; it is not. Humility is “I do not know yet, and here is the open question with a date on it.” Vagueness is deniability — language engineered so that no future outcome can convict it.
This edition adds a second problem, and it is the one worth sitting with. Most of the sentences in your document this week did not originate with you. They came from a brief. Possibly some came from a model. Does a word you did not write count as your word?
It does the moment you keep it. That is what the four verdicts in section 2.4 are actually for. Keep is not the absence of a decision; it is a decision, and it makes the sentence yours as completely as if you had typed it from nothing. This is not a technicality. It is how every professional document in the world works — a lawyer who signs a boilerplate clause has made a promise, a builder who accepts a stock drawing owns the wall. The failure mode of a compressed course is not that students plagiarize. It is that they drift into agreement: they never explicitly decide, so the promise gets made by nobody, and in Week 6 there is no one who can be asked why. The remedy is small and it is entirely mechanical. Four verdicts. One reason each. Written down.
And the No is half the verse, which is the half students skip. The Won’t-have list is a document full of Nos, said plainly, in advance, with reasons, and it is harder to write than the Musts because a No forecloses something. “Like clouds and wind without rain is a man who boasts of a gift he does not give” (Proverbs 25:14, ESV). A requirements document that promises thirty features and delivers eleven has not been ambitious; it has been clouds and wind. Eleven promised and eleven delivered is a smaller document and an incomparably more trustworthy one — and in eight weeks it is also the only one of the two that ends in a working system.
There is one more turn, and it keeps this from becoming legalism. Requirements change. You will learn something in Week 5 that makes a Week-2 requirement wrong. Is changing it breaking your word? No — concealing the change is. The psalmist praises the one “who swears to his own hurt and does not change” (Psalm 15:4, ESV), and there is real weight in that; sometimes keeping a commitment costs you and you keep it anyway. But there is a difference between a promise abandoned quietly because it got inconvenient and a promise revised openly because the world turned out different than you thought. The change log at the bottom of docs/requirements.md is where that difference lives. One row, dated, with a reason. It converts a broken promise into an honest revision, and it is the cheapest integrity you will ever buy.
Finally, the thing that makes this urgent in exactly this semester. An assistant can generate a hundred requirements in eight seconds, every one fluent, formatted, confident, and using shall correctly. What it cannot generate is the thing that makes a word trustworthy in the first place: a person standing behind it who can be held to it. Trust is not a property of a sentence’s grammar. It is a property of the relationship between the sentence and whoever signed it. That is why your name goes at the top of the document, and it is why “the brief said so” and “the model wrote it” will never be a defense in this course or in any job you take afterward. Let your yes be yes. Then be the kind of person whose yes means something.
2.11 — Common Pitfalls
Pitfall: Adopting a brief’s requirements wholesale because they are already well written. Example: Sixteen inherited requirements committed on Monday with no verdict column, three of which describe a barcode integration cut in Week 1 and a household role the project does not have. Fix: Four verdicts — keep, adapt, split, withdraw — one reason each, in writing, on every inherited line. Then run the stale-noun sweep. Three hours on Monday, or a weekend in Week 6.
Pitfall: A Must list sized by enthusiasm instead of by hours. Example: Seven Must features, each honestly worth eight to twelve hours, against thirty hours of net feature construction that has not yet lost a day to anything going wrong. Fix: Estimate every Must as a vertical slice, sum it, compare it to thirty, and cut until the arithmetic works. The two-thirds rule is not encouragement; it is division. Three to four Must features.
Pitfall: Non-functional requirements written as adjectives. Example: “The system shall be fast, secure, and accessible.” Fix: Four fields, always — metric, threshold, condition, method. If you cannot fill all four, you do not yet understand what you want. One adjective usually becomes three requirements; that is the process working.
Pitfall: Renumbering identifiers after the adaptation pass, to tidy up.
Example: You withdraw four inherited requirements on Tuesday and close the gaps, so FR-INV-04 now means something different from what your board card and your branch name refer to.
Fix: Renumber once, in the first hour, before anything references anything. After that, withdraw in place and leave the number. The identifier is the join key for your board, your branches, your tests, and Week 8’s evidence.
Pitfall: Accepting an assistant’s enumeration as a requirement set.
Example: Twenty-two requirements pasted in, including an admin dashboard, social sharing, and a streak counter that no interviewee mentioned and no persona wants.
Fix: Every requirement carries a Source: line naming a human, an observation, a brief, or your own recorded decision. Use the model to ask questions, not to write sentences. And run the linter over anything it touched.
Pitfall: Skipping the one real conversation because the brief already named a user. Example: A persona table with three rows and an evidence column that says “from the brief” three times. Fix: Thirty minutes with one human who has the problem, written up the same day, dated, F/W/O marked. The brief gives you an archetype; it cannot give you evidence, and evidence is what the rubric pays for. Then write the measurement method before the threshold on every quality — the method you write today is a test name in Week 6.
2.12 — Where Your Hours Went This Week
Twenty hours. Log them in docs/hours-log.csv as you go, not on Sunday from memory — Week 3’s planning is only as good as this week’s data, and there is no Week 9 to fix it in.
| Activity | Hours |
|---|---|
| The adaptation pass: keep / adapt / split / withdraw on every inherited requirement, with reasons | 3.0 |
| One 30-minute elicitation conversation with a real user, plus the same-day write-up | 1.5 |
| Writing and repairing functional requirements with acceptance criteria — the bulk of the week | 5.0 |
| Non-functional requirements: four fields, five or more categories | 3.5 |
| Constraints, assumptions, dependencies; obligations verified at primary sources | 1.5 |
| MoSCoW triage, the Won’t-have list, and the Must-hours arithmetic against the budget | 1.5 |
| Traceability matrix, running the linter, and the definition of done | 2.0 |
| The Requirement Adapter lab, the reps, the weekly quiz, and committing everything | 2.0 |
| Total | 20.0 |
If you came in well under fifteen, you almost certainly kept the brief’s requirements without questioning them, and Week 4’s review will find it. If you came in over twenty-four, you are writing prose where a bulleted criterion would do, or designing while you specify — both common, both fixable, and both worth a line in your hours log so Week 3’s estimates know about it.
2.13 — Reps
The reps are in the exercises, and this week they are not warmups — they are the milestone, built one piece at a time. Five of the twelve:
- Rep 2 — the adaptation pass, using
code/adaptation-worksheet.md: a verdict and a reason for every inherited requirement. - Rep 3 — the stale-noun sweep with
--stale-terms, and what it found that you did not. - Rep 4 — the thirty-minute conversation with a real human, written up F/W/O the same day.
- Rep 9 — eight non-functional requirements across five categories, four fields each, in ninety minutes.
- Rep 11 — MoSCoW plus the hour arithmetic: estimate every Must, sum it, and cut until it fits thirty.
Then take the on-page Check Your Reps quiz. It is one of the eight weekly quizzes that make up 15% of your grade, and its real job is to tell you this week, not in Week 6, whether you are on pace.
2.14 — This Week’s Milestone
Milestone 2 — Milestone 2: Software Requirements Specification. One document, docs/requirements.md, containing both halves of the specification: twelve to twenty-two functional requirements with identifiers and acceptance criteria, eight or more measured non-functional requirements across five or more categories, an adaptation record giving every inherited requirement a verdict and a reason, constraints, assumptions and dependencies as three separate tables, an out-of-scope list of five or more rows, a traceability matrix, and a definition of done you will actually honor.
Remember the grading contract, because it is easy to misread. Milestones are graded twice — 25% as their own line, and again inside the 50% final. That is not leniency; it is the opposite. The milestones are the final deliverable, produced one week at a time, and the Week-8 rubric awards points for exactly these artifacts. A weak requirements document does not cost you a few points this week. It costs you the same points in Week 8, plus every hour of rework in between, and there are only six weeks in between. The full contract is in Appendix D.
2.15 — Coach’s Final Word
Here is the thing nobody believes until they have lived it: the requirements document is the cheapest place in the entire project to be wrong. Right now, changing your mind costs a sentence. Next week it costs a diagram. In Week 5 it costs code. In Week 7 it costs code, tests, documentation, and the demo you had already rehearsed. In this edition that curve is steeper than in the long one, because there is no Week 9 to absorb it. Every hour you spend arguing with yourself about what “about to expire” means is an hour that buys back four later, and that is not a motivational claim — it is the arithmetic of the whole discipline.
You will be tempted to rush it, and the temptation is sharper here because you have inherited a draft that already looks finished. Nothing runs this week. Nothing renders. There is no green check mark. Sit with that discomfort, because tolerating it is a large part of what makes an engineer senior. Then do the unglamorous thing: read every inherited line, give it a verdict, write the reason, put a number on every adjective, say No in writing to five things you would enjoy building, and sum your Musts against thirty hours before you tell yourself it will be fine.
Then put your name at the top of the document and mean it. Not because the brief said so. Because you decided.
Let your yes be yes.
See you on Monday.
Up next: the exercises builds the specification rep by rep · Milestone 2 is Milestone 2, the Software Requirements Specification · then Chapter 3 — design decided, decisions recorded, and a walking skeleton running in continuous integration before Week 4. Reference: Appendix B (the Fast-Start Catalog and its adaptation rules), Appendix C (the Document Kit), Appendix D (the grading contract), Appendix E (glossary). Previous: Chapter 1.
Week 2 Knowledge Check
FR-SCAN-01 (add an item by barcode) Withdrawn with a dated reason. Section 2.4 names the row students forget. Which is it?NFR-PERF-01 (Must) — The pantry list view shall render at a p95 under 1.5 seconds. FR-EXP-05 (Should) — The system shall notify household members about items that are expiring soon. Their project serves a fourteen-person rowing club sharing one boathouse kitchen. Which defects does Chapter 2 name?shall — which is exactly what makes it dangerous; the linter passes it. The defect is in the relationship between the sentence and your charter, which is why no tool finds it for you and why you run the stale-noun sweep by hand. The repair fixes both edges at once: one notification per kitchen per day, at a configured time, listing items expiring within three days, to each roster member who has enabled notifications.