Chapter 12 — Reps
These reps are not warmups around the milestone. In order, they are Milestone 12. When the last one finishes, you have an integrated, measured, security-reviewed, tagged release candidate and a change log a stranger could follow.
Ground rules
- Work on YOUR project. PantryPilot and TraceLens are examples. Every rep operates on your real repository, your real seams, your real requirement IDs.
- Commit as you go. Each artifact lands with a dated commit.
docs:andtest:are commits too. - Log the hours honestly, per rep. Four weeks remain; this is the last week your velocity number can still change your plan.
- Nothing goes in a document that you did not verify. Advisory IDs get looked up. Performance numbers get measured. “Should be fine” is not evidence.
- Every assistant use gets logged in
docs/ai-usage.md: what you asked, what it produced, what you verified, what you changed. - Write the reflection. A rep is not done until the two-to-four sentences are written. That is where the judgment gets built.
Integration
Rep 1 — The seam map
Open the component diagram in docs/architecture.md. List every line between two boxes. For each seam, fill this row:
| Seam | Crosses (process / network / storage?) | On an acceptance path? | Tested today? |
|------|----------------------------------------|------------------------|---------------|
| | | | |
Then rank them. A seam that crosses a boundary and sits on an acceptance path is a Tier 1 seam. Everything else waits.
Reflect: How many seams did you find that are not in the Week-6 diagram at all? Those are the ones that will hurt — you built them without ever specifying them. Name the worst one.
Rep 2 — One integration test per Tier 1 seam
Write a real integration test for each Tier 1 seam. Not a unit test with mocks on both sides — a test that exercises both components together against the seam’s actual contract.
Go hunting for the seven failure modes from §12.1 on purpose. For each seam, deliberately probe:
[ ] contract drift — send a payload missing an optional field; what happens?
[ ] unit mismatch — grams/ounces, seconds/ms, cents/dollars: assert the unit
[ ] time zone — an item that expires "tomorrow" for a user in another zone
[ ] identity — same logical record submitted twice; duplicate or 409?
[ ] ordering — call B before A has run; does it fail loudly or silently?
[ ] error semantics — make A fail; does B report failure or render "no results"?
[ ] partial failure — kill the process between two writes; is the invariant broken?
Reflect: Which probe found a real bug? Write the defect ID, and one sentence on why eleven weeks of unit tests never saw it.
Rep 3 — Measure a target, do not feel it
Pick one non-functional requirement from Week 4. Generate realistic volume (hundreds or thousands of records, not seven). Run at least 30 requests against the deployed instance. Record p50 and p95 — not the average.
| ID | Target | Method (load, env, sample) | p50 | p95 | Verdict | Action |
|----|--------|----------------------------|-----|-----|---------|--------|
If it misses, make exactly one fix and re-measure. Record both numbers. Put the table in docs/performance.md.
Reflect: How far apart were your p50 and p95? The gap is what your users actually experience on a bad day. Were you judging the system by the number you had never measured?
The hard parts
Rep 4 — The security pass
Copy code/security-pass-checklist.md into your repository as docs/security-review.md and work all seven areas. Fill the evidence column with something re-runnable or re-readable.
Start with secrets, in tracked files and history:
git grep -nIE '(AKIA[0-9A-Z]{16}|BEGIN [A-Z ]*PRIVATE KEY)'
git ls-files --error-unmatch .env 2>/dev/null && echo "TRACKED - fix this"
Then the one every capstone gets wrong: pick an object a user can name by ID — an item, a household, an upload — and try to read it as a different authenticated user. Not by clicking; by calling the endpoint directly.
Reflect: Did the server check ownership, or did it trust the identifier? If it trusted it, that is a Critical defect and it gets an ID today. If it checked, say how you proved it — a test, not a memory.
Rep 5 — Break your dependency on purpose
Pick your riskiest third-party dependency. Make it fail four ways and record what your system does:
| Failure | How I simulated it | What the user saw | Acceptable? |
|------------------|------------------------------------------|-------------------|-------------|
| slow (10 s) | proxy delay / sleep in a stub | | |
| down | wrong host / block the domain | | |
| rate limited | stub returns 429 | | |
| changed response | stub returns a payload with a field gone | | |
Then implement graceful degradation for at least one: a timeout, a fallback path you control, and an honest message. Prove it by re-running the “down” row.
Reflect: Before this rep, what did your app do when that dependency was down? Be specific — “it hung” and “it crashed” and “it showed a blank page” are three different answers, and only one of them is survivable on demo day.
Rep 6 — The assistant as security reviewer, then the advisory database
Ask an assistant to review one real file from your project for injection, missing authorization checks, and unsafe handling of external input. Separately, ask it whether any of your dependencies carry known vulnerabilities.
Now verify. Every advisory identifier it gives you gets pasted into https://github.com/advisories or https://osv.dev/. Record honestly:
Findings claimed: ____
Findings confirmed real: ____
Advisory IDs that existed: ____ / ____
Affected range actually included my version: ____ / ____
Real issues it MISSED that I found myself: ____
Reflect: What was its hit rate? And what class of problem did it miss entirely — was it a whole-system issue that no single file could reveal? Write one sentence on what that means for how you use it in Weeks 13–16.
Change control
Rep 7 — Three requests, three impact analyses
Take three real change requests — from your advisor, a user, a demo conversation, or your own head at 1 a.m. Write each one up as its own file in docs/change-requests/ — CR-0NN-<short-slug>.md, the folder and the naming convention you stood up in Week 8 — using the template in code/change-request-log.md. Inside each file, the analysis is three lines and the decision is one:
Cost: ___ build + ___ test + ___ doc = ___ h; ___ h remain
Blast radius: FR-___ / NFR-___, modules ___, interfaces ___, tests ___, docs ___
Risk: accept -> ___________ ; refuse -> ___________
Disposition: ACCEPT | DEFER -> ______ | REJECT (reason: ______)
At least one must be a REJECT with a reason a stranger would accept, and at least one must be a DEFER with a named destination and a size. Commit all three files, then add one row per CR to the change table at the top of CHANGELOG.md — three files, three rows, one commit.
Reflect: Which one was hardest to refuse, and was the difficulty about the project or about the person who asked? Name it plainly. That is the muscle this week is training.
Rep 8 — The cut you have been avoiding
Compute your real remaining capacity from the hours log: average honest build hours per week × 4 weeks, minus documentation (Week 13), deployment and handoff (Week 14), and presentation prep (Week 15). Write the number down.
Now list your unfinished Must and Should requirements with current estimates. If the total exceeds the number, cut until it does not. A cut is a change request, so each one gets its own file in docs/change-requests/ with all four fields:
What: FR-___
Why: ___ h estimated; ___ h remain; ____________ is not optional
Where it went: docs/backlog.md B-___ , sized, acceptance criteria retained
Reader must know: ____________________________________________
Then mark it Deferred in docs/requirements.md with the date and CR reference. Do not delete the row.
Reflect: Did the arithmetic force a cut you had been arguing yourself out of? Which requirement did you protect instead, and why is that the right trade?
Rep 9 — The Change Request Triage widget, run twice
Run the Change Request Triage widget on the chapter page. First pass: decide on instinct, fast, the way you would in a hallway. Second pass: consult the change-control policy you wrote in Chapter 8 before every decision.
Run 1 (instinct): shipped ___ / slipped ___ ; costliest decision: ____________
Run 2 (policy): shipped ___ / slipped ___ ; costliest decision: ____________
Times my run-1 decisions violated my own written policy: ___
Reflect: What was the gap between the two burn-downs, in hours? That gap is the measured value of change control — on you, not on a textbook student. Which single decision cost the most, and would you have caught it in real life?
The release
Rep 10 — Freeze, gate, tag
Write your exit criteria down before you evaluate against them:
[ ] every Must-have requirement has a passing acceptance test
[ ] zero open Critical or High defects
[ ] security pass complete; every finding fixed or explicitly accepted
[ ] every performance target measured; each miss has a recorded decision
[ ] a clean clone sets up, runs, and passes tests using only documented steps
Then run the gate with your real commands and tag:
TEST_CMD="<your test command>" SETUP_CMD="<your setup command>" sh release-check.sh
git tag -a v0.9.0-rc.1 -m "Release candidate 1: integrated system, Milestone 12"
git push origin v0.9.0-rc.1
Use code/release-check.sh. If the clean-clone check fails, that failure is the most valuable output of your week — fix it before you tag.
Reflect: Which check failed first, and what undeclared state on your machine was it detecting? Write the sentence you will add to README.md in Week 13 so a stranger never hits it.
Rep 11 — Rewrite a bad change-log entry
Here is a real-looking entry. Rewrite it properly using code/changelog-template.md.
## v0.9
- various bug fixes and improvements
- updated dependencies
- refactored the backend
Your rewrite must: group under Added / Changed / Fixed / Security, describe what a user experiences, cite requirement or defect IDs, state anything the reader must do (migrations, new configuration), and carry a Known issues section with at least one honest entry and a workaround.
Reflect: Which of your real changes was hardest to describe in user-visible terms? A change you cannot describe that way is usually internal churn — did it belong in the change log at all?
Done? One Last Thing.
The release-candidate dress rehearsal. End to end, as if a grader is watching, in one sitting:
- On a machine or container you have not been developing on, clone your repository at the tag:
git clone --branch v0.9.0-rc.1 <your repo url>. - Follow only the steps written in
README.md. Do not fix anything from memory. Start a timer. - Run the test suite. Run the three acceptance paths a grader would try first.
- Break your riskiest dependency and confirm the degradation path from Rep 5 still holds.
- Stop the timer. Write the number in
docs/performance.mdas your current time-to-first-successful-run. - Every place you had to deviate from the README becomes a documentation defect with an ID — those are Chapter 13’s work, and now you have a real list instead of a guess.
- Commit:
docs: milestone 12 release candidate — integration, security, performance, change log.
If that loop runs clean, you are ready for Milestone 12 — and Week 13 becomes writing rather than rescuing.
Up next: Milestone 12