Chapter 07 · Reps

Document, Deploy, and Hand It Off — Reps

← Back to Chapter 7

Chapter 7 — Reps

These reps are not warm-ups beside the milestone. They are Milestone 7, taken in order, on your own project. Work them Monday through Thursday and Friday is assembly rather than panic. Each one produces a file, a transcript, or a commit — nothing here ends in “I thought about it.”

Ground rules

  • Your project, not an example. PantryPilot and TraceLens are illustrations. Every rep operates on the repository you have been building for six weeks.
  • Evidence, not intent. A rep is done when there is a transcript, a timestamp, a commit, or a file in the repository. “I know how I would do it” is not done.
  • Nothing counts until you have run it. A command typed into a document but never executed is a claim, not documentation.
  • Paste real output. Not what you remember it saying. Copy it from the terminal.
  • Placeholder secrets only. sk-REPLACE_ME, <your-api-key>, .env.example. If a real credential ever reached a commit, rotate it — deleting the line does not remove it from history.
  • Commit as you go. One artifact, one commit, a message that says what changed. docs: runbook failure catalogue from defect log beats updates.
  • Log AI use honestly. Anything an assistant drafted gets a row in docs/ai-usage.md, including what you found wrong when you ran it.
  • Log your hours as you work, to the nearest quarter hour, in docs/hours-log.csv. Not from memory on Sunday night.
  • Every rep ends with writing. Two to four sentences of plain prose. Skip the writing and you did the motions, not the rep.

Group A — Diagnose what you actually have (Monday, ~3 hours)

Rep 1 — Score your README before you touch it

Open README.md as it stands right now. No cleanup first — the point is the honest baseline. Score each of the nine graded sections: 2 = present and complete, 1 = present but thin or vague, 0 = missing.

 1. What it is / who it is for / what it does NOT do   ___
 2. Prerequisites with versions and check commands     ___
 3. Install                                            ___
 4. Configure                                          ___
 5. Run (+ the action that proves it works)            ___
 6. Test                                               ___
 7. Project layout                                     ___
 8. Troubleshooting                                    ___
 9. License                                            ___
                                              TOTAL: ___ / 18

Then paste the same file into The Handoff Readiness Auditor on the chapter page and compare the two numbers. Save the widget’s projected time-to-first-successful-run; you will compare it on Friday.

Reflect: Where did you score yourself higher than the widget did, and why? That gap is the exact size of your curse of knowledge.


Rep 2 — The hostile inventory

Hunt everything your project needs that is not in the repository. Two mechanical passes, then one only you can do.

grep -rInE '(/Users/|/home/[a-z]|C:\\|localhost|127\.0\.0\.1)' . | grep -v node_modules
env | grep -iE '(api|key|token|db|database|url|secret)'

Then list every external thing that installs nothing: an API key, a database you created by hand in a GUI in Week 3, an OAuth application registered under your personal address, a table you seeded manually and never scripted. Put every hit in one table: 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 3 — Rewrite .env.example as a contract

Every value 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 it mechanically:

python3 handoff_audit.py .            # contract vs. your shell
python3 handoff_audit.py . --env .env # contract vs. your local file

Use code/handoff_audit.py. Fix every ERROR. The dangerous finding is a variable your code reads that the contract never mentions — it works for you and fails silently for everyone else.

Reflect: How many variables did you find that the contract never listed? Write down the number, and say what each one would have done to a successor: a crash, or a wrong answer with no error.


Group B — Write the set (Tuesday and Wednesday, ~7 hours)

Rep 4 — Every command gets an expected result

Rewrite the Install, Configure, and Run sections of README.md so that every command is followed by what success looks like. Run each one as you write it, from the repository root, in order.

{{command}}

Expected: {{the real last line of successful output}} — takes about {{N}} seconds. If you see {{the common failure}}, {{the fix}}.

Finish with the verification action: one concrete thing a stranger can do to prove the system works, not merely that it started. Write it down; it is your clean-machine acceptance action.

Reflect: Which command’s real output surprised you — a warning you had stopped seeing, a prompt you answer automatically, a line that looks like an error but is not? Write down what you had trained yourself to ignore.


Rep 5 — Four runbook entries, mined from your defect log

Open docs/defect-log.md from Week 6. Pick the four defects most likely to recur — the outages, the config mistakes, the third-party failures. Convert each one:

### F-0N — <symptom in the operator's words>
- Symptom:       <exact error text>
- First check:   <command> → healthy looks like <output>
- Likely cause:  <cause, with the defect ID it came from>
- Fix:           <command or numbered steps>
- Verify:        <the check that should now pass>
- If that fails: <next step, or STOP and escalate>

At least one entry must name a destructive command the operator must not run. Then write §1 (where it runs), §2 (deploy, from the tag), §3 (start/stop/restart plus the health check), and §4 (normal readings) — the deployment record lives here in this edition.

Reflect: Which of the four did you have to go look up because you no longer remembered how you fixed it, six weeks later? That is your bus factor talking.


Rep 6 — The architecture overview, timeboxed to forty minutes

Set a timer. Produce §0 — Overview at the front of docs/architecture.md: one diagram (four to eight boxes, every arrow labeled) and five paragraphs — what the system does, the components and what each owns, the data and what is authoritative, one end-to-end flow traced through every box, and the consequential decisions with links to their records.

The fifth paragraph must end with the literal sentence: “The thing that would surprise a new reader is ___.”

Do not delete the Week-3 specification sections to make room. Update them as built, underneath §0.

Reflect: What is the surprise, and how long had it sat in your system undocumented? Would you have remembered it in Week 8?


Rep 7 — The ADR index, and the decision nobody recorded

Build docs/adr/README.md as a table: number, decision in one line, status (Proposed / Accepted / Superseded by NNNN / Deprecated), and the consequence a reader would notice. Mark every superseded record honestly; delete nothing.

Then find the decision with no record. There is one. In this edition it is very often the point where you deviated from your Fast-Start brief’s suggested stack, or the thing you chose in a Week-5 afternoon under pressure. Write the record now, dated when you actually made it, with the context and alternatives you actually had.

Reflect: Why did that decision never get written down at the time? Too obvious, too rushed, or too uncomfortable to defend?


Group C — Ship it and hand it over (Wednesday and Thursday, ~7 hours)

Rep 8 — Tag, release, and roll back on a timer

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 transcript.

Reflect: What did the auto-generated notes get right, and what did they 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 9 — One path, and the secret hunt

One path. Decide in writing whether your supported setup is a script or a container, in the same six-line shape as your Week-3 records:

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 every mention of it from README.md.

The secret hunt. Search the working tree, then the history — the history is the part people skip and the part that matters.

git ls-files | xargs grep -InE '(api[_-]?key|secret|password|token)\s*[:=]' 2>/dev/null
git log -p --all | grep -nE '(api[_-]?key|secret|password|token)\s*[:=]' | head -50

A dedicated scanner (gitleaks, trufflehog) does this far better; use one if you can. If you find anything real: rotate the credential first, today, and write the rotation procedure into docs/handoff.md §3 as numbered steps, including the order (new key live before the old one dies).

Reflect: Did you keep a half-working alternative path “just in case”? Say why, then delete it anyway. And on secrets: what did you find, how old is the commit, and if you found nothing, what exactly did you search — “I ran one grep” is not a clean bill of health.


Rep 10 — Let an assistant draft, then count what was wrong

Give an assistant your docs/defect-log.md and your README.md and ask it to draft a troubleshooting table. Then run every command it produced, in order.

| # | Command the assistant wrote | Ran it? | Correct? | What was actually wrong |
|---|---|---|---|---|

Write the row for docs/ai-usage.md: tool used, what it drafted, how many of its commands required correction, what you did about it. Report the count exactly — do not round it down.

Reflect: What kind of thing did it get wrong — paths, versions, flags, expected output, or things that were true three commits ago? That pattern is the failure mode you will keep meeting for the rest of your career.


Rep 11 — The bus-factor sweep and the groomed backlog

Set a timer for thirty minutes and answer one question repeatedly: what have I had to remember instead of read? Write everything down, no filtering.

Knowledge only I haveWhat it costs my successorMinutes to write downWhere it goes

Close every row, preferring in this order: make it impossible (a guard, a test, a loud failure), make it visible (runbook or architecture doc), make it findable (handoff landmines).

Then groom the backlog. Your top five open issues each get a real title, the requirement or defect ID, acceptance criteria, and the files most likely involved. One gets labeled good-first-issue and becomes §2 of your handoff guide.

Reflect: How many rows, and what is the total in the minutes column? Most students find five to fifteen items totaling well under an hour. Say what the worst one would have cost if you had never written it down.


Done? One Last Thing.

Run A of the clean-machine test — the reproduction run. You do this one yourself, and you do it before you ask anyone else for an hour of their life.

  1. Get an environment that is not your development machine: a fresh container from a bare base image, a fresh cloud development environment, a re-imaged lab machine, a borrowed laptop. (Appendix A has the options, including the no-admin browser path.)
  2. Copy code/clean-machine-protocol.md into your repository as docs/clean-machine-test.md and write your acceptance action at the top before you start.
  3. Start a stopwatch. Clone fresh. From here on you may read only what is in the repository — no shell history, no notes, no memory. If you catch yourself typing something the docs do not say, stop and log it as a friction entry.
  4. Reach the acceptance action or hit sixty minutes. Record the time either way, and paste the real transcript including every failed attempt.
  5. Fix every friction entry, commit, and note which document changed.

If Run A takes more than twenty minutes, Run B with a real tester will fail — fix the top three friction entries before you recruit anyone. If it comes in under fifteen and you honestly used nothing but the repository, you are ready for a tester.

One warning, because everyone gets caught by it: you will unconsciously cheat. You will type a command from muscle memory, land in the right directory by habit, answer a prompt without reading it. That is not a character flaw; it is the curse of knowledge doing what it does. The fix is mechanical — narrate each step out loud as “the README says to…”, and if you cannot finish that sentence, you have found a friction entry.

Then do two things before Friday. Recruit your tester for Run B — ask three people, one will say yes; discovering on Thursday night that nobody is free is the single most common way this milestone goes wrong. And re-run the Handoff Readiness Auditor, compare it with Monday’s score, and work its remediation list from the top until you run out of week.

Up next: Milestone 7