Chapter 14 — Reps
These reps are not warm-ups beside the milestone. They are the milestone, taken in order, on your own project. Work them Monday through Thursday and Milestone 14 is mostly assembled by Friday.
Ground rules
- Your project, not an example. PantryPilot and TraceLens are illustrations. Every rep operates on your actual repository.
- Evidence, not intent. A rep is not done when you know how you would do it. It is done when there is a transcript, a timestamp, a commit, or a file in the repo.
- Commit as you go. Small commits with real messages. The repository is the record; “I did it but didn’t commit” is indistinguishable from “I didn’t.”
- Anything generated gets executed before it gets committed. Container definitions, setup scripts, and CI workflows from an assistant are drafts until they have run in a clean environment.
- Log your hours as you work, not from memory on Sunday night. Round to the nearest quarter hour and be honest about the hour you lost.
- Every rep ends with writing. Two to four sentences of plain prose. If you skip the writing, you did the motions and not the rep.
Reproducibility
Rep 1 — The hostile inventory
Hunt for everything your project needs that is not in the repository.
# absolute paths and assumed-running services
grep -rInE '(/Users/|/home/[a-z]|C:\\\\|localhost|127\.0\.0\.1)' . | grep -v node_modules
# what your shell knows that your repo does not
env | grep -iE '(api|key|token|db|database|url|secret)'
Put every hit into a table with three columns: what it is, why it works on my machine, what a stranger would have to do. Aim for at least eight rows.
Reflect: Which row surprised you? Almost everyone has one — a tool, a variable, or a running service they had genuinely forgotten was not part of the project. Name yours and say how long it has been invisible.
Rep 2 — Pin what floats
Open your dependency manifest. For each direct dependency, answer: is the version pinned, floating within a range, or unspecified?
git ls-files | grep -iE '(package-lock|yarn.lock|poetry.lock|requirements.*txt|Gemfile.lock|go.sum|Cargo.lock|pom.xml)'
If your lock file is not committed, commit it now. If your project has no lock mechanism, write down the exact versions you are running and how you got them.
Reflect: If someone installed your project six months from now with floating versions, what is the single most likely thing to break? Name the dependency and the failure.
Rep 3 — Rewrite .env.example as a contract
Every variable your code reads gets an entry, and every entry answers four questions: what it does, required or optional, where to get it, and a safe local value.
Then check the contract against a real environment:
python3 code/check_config.py .env.example # your shell vs the contract
python3 code/check_config.py .env.example .env # your local file vs the contract
Fix every FAIL and every UNDOCUMENTED warning. Undocumented means your code reads something the contract never mentions — the most dangerous kind of drift, because it works for you.
Reflect: How many variables did you find that your code reads but the contract never listed? Each one would have been a silent failure for your successor. Write down the number.
Rep 4 — Make required config fail loudly
Find one place where a missing configuration value produces a confusing downstream error, and replace it with a startup check that names the variable and exits.
Before: TypeError: Cannot read properties of undefined (reading 'query')
...forty lines of stack trace, three files away from the cause
After: FATAL: DATABASE_URL is not set.
Copy .env.example to .env and fill it in, then re-run.
See README.md → "Configuration".
Reflect: How far from the actual cause did the old error appear — same file, or a different subsystem? That distance is what you just deleted from somebody’s afternoon.
Rep 5 — The amnesia test
Prove the repository is self-contained. Run the preflight harness against a fresh clone:
chmod +x code/preflight.sh
./code/preflight.sh . "<your documented setup command>" "<your smoke test command>"
Whatever it reports missing, fix — either commit the file or declare the prerequisite in README.md. Re-run until it passes, then record the total time.
Reflect: What was not committed? There is almost always something. Say what it was, and how long your successor would have spent before figuring it out on their own.
Rep 6 — One path, and delete the other
Decide, in writing, whether your supported setup path is a script or a container. Write it as a six-line decision, the same shape as your Week 5 ADRs:
Decision: <scripted setup | containers>
Context: <services required, target platforms, who runs this next>
Consequence: <what your successor must install before step 1>
Rejected: <the other one>, because <the real reason, not "no time">
Evidence: ran clean on <environment> on <date>, <n> minutes
Then delete the abandoned path from the repository and remove every mention of it from README.md.
Reflect: Did you keep a half-working alternative “just in case”? Say why, and then delete it anyway. Explain in one sentence what it would have cost the next person to discover it was dead.
Secrets and Licensing
Rep 7 — The secret hunt
Search the working tree, then the history. The history is the part people skip and the part that matters.
# working tree
git ls-files | xargs grep -InE '(api[_-]?key|secret|passwd|password|token)\s*[:=]\s*["'\'']?[A-Za-z0-9_\-]{12,}' 2>/dev/null
# every version of every file, ever
git log -p --all | grep -nE '(api[_-]?key|secret|password|token)\s*[:=]' | head -50
A dedicated scanner (gitleaks, trufflehog) does this far better; install one if you can. If you find anything real: rotate the credential first, today, before anything else. Then decide separately whether history rewriting is worth it.
Reflect: What did you find, and how old is the commit? If you found nothing, say what you searched and why you believe the search was adequate — “I ran one grep” is not a clean bill of health.
Rep 8 — Rotate one key on purpose
Pick a real credential your project uses and rotate it end to end, on a timer: issue the new one, install it locally and in the deploy target, verify the app still works, revoke the old one.
Write the procedure down in docs/handoff.md as numbered steps, including the order (new key live before the old one dies) and what breaks in between.
Reflect: How long did it take, and what broke while both keys were in play? Your successor will have to do this the week you graduate. Give them the real number, not an estimate.
Rep 9 — License in, license out
Two halves, one hour.
Out: choose a license, add LICENSE at the repository root, and put the SPDX identifier in README.md. Write two sentences in docs/handoff.md saying why that license and not the others. Check your institution’s intellectual-property policy first; if you cannot find it, email the program and keep the reply.
In: run your ecosystem’s license lister across your dependencies and put the output in THIRD-PARTY-NOTICES.md. Flag every row that carries an actual obligation — attribution, notice retention, copyleft.
Reflect: Which dependency’s license surprised you? Was there anything you would have shipped in violation of, purely because you never looked?
Release and Handoff
Rep 10 — Tag, release, and roll back
Do the whole release loop once, on a candidate, before you do it for real.
git tag -a v0.9.0-rc.1 -m "release candidate: <one line>"
git push origin v0.9.0-rc.1
Write the release notes yourself first — Added / Changed / Fixed / Known issues, with your FR and DEF identifiers. Then look at what your platform auto-generates from merged pull requests and compare. Finally, deploy the tag, deploy something deliberately broken on top of it, and roll back using only the numbered steps in docs/runbook.md, with a timer running. Save the terminal transcript.
Reflect: Compare your notes with the auto-generated ones. What did the generator get right, and what did it miss that only a human who knew why the change happened could supply? And: how long did the rollback take, and what did you have to improvise because it was not written down?
Rep 11 — The bus-factor sweep
Set a timer for thirty minutes and answer one question repeatedly: what have I had to remember instead of read? Write down everything, no filtering.
| Knowledge only I have | What it costs my successor | Minutes to write down | Where it goes |
|---|---|---|---|
Then close every row, preferring in this order: make it impossible (a guard, a test, a loud failure), make it visible (runbook, architecture doc), make it findable (handoff landmines).
Reflect: How many rows, and what is the total minutes column? Most students find between five and fifteen items totaling well under an hour. Say what the worst one would have cost if you had never written it.
Rep 12 — The successor simulation
Hand a classmate your repository URL. Say nothing for thirty minutes — no hints, no “oh, you also need to.” Write down every question they ask and every place they stall, with timestamps.
Then do the same for them.
Reflect: What was their first blocker, and how many minutes in did it appear? Every question they had to ask is a documentation defect. File the top three as issues with acceptance criteria, and fix at least one before Friday.
Done? One Last Thing.
The capstone rep — assemble the handoff package
Copy code/handoff-template.md into your repository as docs/handoff.md and fill it completely — no angle brackets left, no section deleted. Pull in what you already produced this week: the config contract from Rep 3, the rotation procedure from Rep 8, the license reasoning from Rep 9, the rollback timing from Rep 10, the bus-factor register from Rep 11, and the documentation defects from Rep 12.
Then groom your backlog. The top five open issues each get a real title, the requirement or defect ID, acceptance criteria, and the files most likely involved. One of them gets labeled good-first-issue and becomes the successor’s week-one task in §2 of the handoff guide.
Now run The Handoff Readiness Auditor on the chapter page a second time and compare it to Monday’s score. Work its remediation list from the top until you run out of week.
Finally, walk code/release-checklist.md top to bottom and tag v1.0.0.
Reflect (write this one properly — half a page): Your successor opens this repository at nine o’clock on a Monday morning a year from now. Walk their first day, hour by hour, honestly. Where do they get stuck? What do they have to guess? What would they email you about if they could — and since they cannot, where is that answer written down now?
Up next: Milestone 14