Chapter 3 — Reps
Twelve reps. Done in order, they are Milestone 3 — the decisions, the design, the plan, and the skeleton, built one bone at a time. Nothing here is a paper exercise.
Ground rules
- Everything happens in your own repository. Every rep leaves a commit, a file, an issue, or a CI run behind. If a rep produced nothing you can point at, you did not do it.
- Do them in order. The design reps feed the plan; the plan feeds the skeleton; the skeleton is what proves the design. Skipping forward to the code is the failure mode this week is built against.
- Time-box hard. Twenty hours is the whole budget and eight of them are already spoken for by the skeleton and CI. If a rep runs 50% over its suggested box, stop, log the overrun, and move on. A finished-enough document beats a perfect unfinished one, every week, but especially this one.
- Log your hours as you go, not on Sunday night from memory. Quarter-hour precision, real numbers, in
docs/hours-log.csv. Week 4’s audit is only as honest as this file. - AI is allowed and expected — and everything it writes gets read by you before it is staged. Every generated artifact that survives into a commit gets a dated line in
docs/ai-usage.md: what you asked for, what you kept, what you rejected and why. - Stack-agnostic. Commands below are written in the Node/PostgreSQL shape of the PantryPilot example. Translate them into your stack; the shape of the rep does not change.
Block A — Decide (about 3.5 hours)
Rep 1 — The brief diff
Open the Fast-Start brief you adopted in Appendix B beside your own docs/requirements.md. One row per piece of the suggested stack.
| Suggested piece | What justified it in the brief | Still true after my Week-2 edits? | Verdict |
|-----------------|--------------------------------|-----------------------------------|---------|
The verdict is adopt, deviate, or delete. A piece whose justification you removed in Week 2 gets deleted from the diagram today, not carried.
Produce: the table, committed as a section of docs/architecture.md.
Reflect (3–4 sentences): which piece were you keeping out of momentum rather than need? What would it have cost you in Week 6 if you had not caught it?
If you brought your own project: run the same table against the brief you used as a template, and against the stack you assumed in Week 1 before the requirements existed.
Rep 2 — Count your novelty load out loud
List every piece of your stack. Beside each, write shipped (built it, deployed it, debugged it at 11 p.m.) or new. Read the new column and total it.
Produce: the count, and — if it is 2 or more — a named demotion. Not “I’ll be careful.” A specific substitution, or a requirement cut. Reflect: where is your one innovation token going, and what makes that the piece closest to what your project is actually about?
Rep 3 — Write the three ADRs
From code/adr-one-page.md, into docs/adr/, numbered from 0001. One for the load-bearing data store, one for every deviation from the brief, one for hosting and CI. Ninety minutes for all three.
Every record must carry: the Adopt / Deviate field, at least two real options, negative consequences with budgeted hours, a revisit trigger with a number or a date in it, and a verification table for any version, price, limit, or license claim.
Produce: three committed records. Reflect: read your Consequences sections. If any one of them has no cost in it, you did not decide — you agreed with a suggestion. Rewrite that one before you go on.
Block B — Design (about 4 hours)
Rep 4 — Containers, responsibilities, and the single-owner audit
Copy Part 1 of code/design-pack-template.md to docs/architecture.md. Draw the context and container diagrams in a text-based tool and commit both source and image under docs/diagrams/. Every box gets a responsibility and a technology; every arrow gets a direction, a payload, and a protocol.
Then fill the component responsibility table and audit it with three questions:
1. Does every responsibility sentence start with a verb, with no "and" in it twice?
2. Does every piece of state have exactly ONE owning component?
3. Can I follow "Depends on" from any component and arrive back where I started?
A yes to (3) means those components are really one component you have not admitted to.
Produce: two diagrams and a responsibility table with the audit answered inline. Reflect: read your responsibility sentences aloud in a row. The bad ones sound like job titles — “handles the data layer.” The good ones sound like verbs a person could do. Which of yours are job titles?
Rep 5 — The risky path, and the table that is worth more than the diagram
Pick the flow that crosses a boundary you do not control. Sequence it — participants, numbered steps, real data. Then, beneath it, the failure table:
| Step | What can go wrong | System behavior | User sees |
Every external call gets a timeout in seconds, a retry policy with a hard cap, a fallback, and an answer to does the user find out? “The default” is not a timeout; on some clients the default is forever.
Produce: one flow and its failure table in docs/architecture.md.
Reflect: name one thing the failure branch changed in your interface contract. If it changed nothing, you drew it after you decided instead of to decide — go back and let it break something.
Rep 6 — The data model that survives Week 6
Specify every entity: purpose (what one row is in the real world), key, columns with type and nullability, invariants a test could check, relationships, volume by Week 8, and lifecycle. Then decide the four conventions once, in writing: timestamps in UTC converted in exactly one place; money in minor units as integers; enumerations constrained; a deletion policy per entity.
Then the migration mechanism, and the one sentence that makes it real: how does a stranger run these?
Produce: the data model section, plus migrations/0001-….sql (or your tool’s equivalent) applied by script/setup.
Reflect: point at one column whose NULL meaning you can state in words. Now point at one you cannot. That second column has two concepts in it — split it before Friday, because after Friday it holds data.
Rep 7 — One interface contract, for the interface you understand least
Not the easy one. The one you are fuzziest on — that is where the design is still vague, and finding out costs twenty minutes today or two days in Week 6. Eight facts: purpose and the requirement it serves, auth, inputs with validation, success shape with an example, every error, idempotency, side effects, limits.
BAD: POST /items — adds an item. Returns the item. Errors return an error.
Then decide one error envelope for the whole system, here, once. A codebase with three error shapes has a client with three error handlers and a bug in two of them.
Produce: one complete contract and the system-wide error envelope. Reflect: how many decisions did writing it remove from Week 6? Count them. That number is the return on this rep.
Block C — Plan (about 2 hours)
Rep 8 — The capacity arithmetic, and the cut
Copy Part 2 of code/design-pack-template.md to docs/plan.md. Build your Weeks 4–8 capacity table, subtract the course overhead honestly, declare a 25% buffer, and write the plannable number at the top.
Then decompose your Must list into tasks of 1–6 hours, each with a requirement identifier, a three-point estimate, and a done-when somebody else could check. Total the calibrated estimate against the plannable line.
raw total ______ h × calibration factor ______ = ______ h
plannable (about 53 h) -> VERDICT: fits by ____ h | OVER by ____ h
It will come out over. That is what a first work breakdown does. Now cut, today, in writing — Coulds first, then Shoulds, and a Must only with a scope-decision row that names the identifier.
Produce: docs/plan.md with a verdict line and a scope-decision table.
Reflect: which task has a P / O spread over 4? That is a task you do not understand. Split it or time-box a spike, and say which you chose.
Rep 9 — Six risks that can actually be detected
Write twelve candidate risks fast — an assistant is genuinely good at this breadth — then cull to six by exposure. Each survivor is one sentence in the form cause → uncertain event → consequence, with impact scored in hours you would lose, plus the three columns that make it a control: an observable trigger, an owner by name, and a response that is already a task in docs/plan.md.
Produce: docs/risk-register.md, six rows, sorted by exposure.
Reflect: cover the Response column and read your triggers. Could a person who is not you tell, from the trigger alone, that the risk is happening? Any trigger that fails that test is a feeling with a border around it.
Block D — Stand it up (about 8 hours)
Rep 10 — The script contract and the stranger’s machine
Create script/ with six one-word verbs, each doing its whole job in one command:
mkdir -p script
touch script/setup script/lint script/test script/build script/start script/smoke
chmod +x script/*
script/setup goes from a fresh clone to a runnable project: dependencies from the lock file, database created, migrations applied, one row seeded. Then write the ## Run it section of README.md — the prerequisite, the exact commands, and what success looks like.
Now prove it, on a timer:
git clone <your repo> /tmp/clean-clone
cd /tmp/clean-clone
# follow YOUR README exactly. No shortcuts, no memory, no cd back.
If you hit a step your README does not mention, stop the timer, fix the README, start over.
Produce: six executable scripts, the ## Run it section, the elapsed time, and the list of every fix you had to make.
Reflect: how many restarts? Every restart is a defect a grader would have hit in Week 8, found for free on a Wednesday.
Rep 11 — Ship the pipeline, then break it on purpose
Copy code/ci-starter.yml to .github/workflows/ci.yml, fill in the two marked blocks, push it on a branch, open a pull request. Expect two or three failures before green — each one is something your laptop was hiding from you. Ninety-minute box: if you are not green, delete stages until you are, then add one back per commit.
Then, twice:
- Push a deliberately failing assertion. Confirm red. Open the log and find the exact line that reports it.
- Revert. Push a deliberate lint error. Confirm red again.
- Fix both and get back to green.
If either push stayed green, your pipeline is decorative. The usual culprits are || true, a suite collecting zero tests, and a lint config with everything disabled.
Produce: one green run URL, two red run URLs, and the fix commits, all recorded in docs/skeleton-trace.md.
Reflect: for each green-to-red failure, was it a real portability problem or a workflow-syntax problem? Name what your laptop had that a clean machine does not — that is the valuable one.
Done? One Last Thing.
Rep 12 — The walk, recorded
This is the milestone in miniature. Do it end to end, without stopping.
- Copy
code/skeleton-smoke.shtoscript/smoke, change the three defaults, and wire it in as the last CI stage. - Run the honesty test: stop your data store and run
./script/smoke. It must fail. If it passes, fix the test, not the database. git cloneyour own repository into a directory you have never used.- Run two commands from your README and nothing else.
- Load the page — or run the command — and watch one real request travel every hop.
- Record it: a screen capture or a series of screenshots showing the clone, the two commands, the result, and the green CI run on the same commit.
- Complete
docs/skeleton-trace.md: the hop table with honest yes/no/stubper hop, the requirement traceability rows, the date and commit where the skeleton first walked, the green run URL, and the red run URL.
If any step needs a command that is not in your README, that is the finding. Fix the README and start the recording over.
Reflect (a paragraph, in your notes — you will reuse it in the milestone): what did the skeleton teach you about your architecture that three days of documents did not? Name one specific thing you now know that on Wednesday you only believed. Then name the hop you are still stubbing, and the week and issue where it becomes real.
Up next: Milestone 3