Day 87 — Capstone 5/5 freeze
Day 87 — Capstone 5/5 freeze
Stage VIII · ~4h
Goal: Feature freeze the Capstone A MVP: no new services or toys—only bugfixes, doc fixes, and checklist honesty—so Days 88–89 test a stable, tagged artifact.
After today’s tag, the only legitimate code changes before Day 88 wipe are P0 blockers that make rebuild or health checks impossible. Everything else goes in docs/POST-FREEZE.md.
Why this day exists
Wipe/rebuild (Day 88) against a moving target is chaos. Freeze creates a known baseline: annotated git tag, green CI, known gaps explicitly waived with risk. Without freeze, disaster-recovery drills measure luck, not process.
Experts freeze early relative to demos. Amateurs keep “just one more module” until the disk wipe and then invent history.
Theory 1 — What “freeze” means
| Allowed | Forbidden |
|---|---|
| Bugfixes for P0/P1 with issue id | New apps / node roles / hostnames |
| Doc corrections that match code | “Quick” plugin or package installs |
| Test stability fixes (flakes, waits) | Refactors without bug id |
| Checklist updates (honest ticks) | Starting Capstone B |
| Dependency bumps only if build broken | Casual nix flake update |
| Typo/typo-level RUNBOOK fixes | New sops keys without re-documenting DR |
Tag shape
git tag -a capstone-a-freeze -m "Capstone A feature freeze"
git push origin capstone-a-freeze # if remote exists
git rev-parse capstone-a-freeze
git rev-parse HEADRecord the full commit hash in docs/CAPSTONE-A.md and docs/FREEZE.md. Annotated tags (-a) carry a message and date; lightweight tags are easier to lose meaning.
Theory 2 — Near-green checklist policy
Every Capstone A box must be one of:
- [x] done with a proof command (or CI URL) written next to it, or
- [ ] waived with written reason + risk + follow-up date
No silent partials. “Mostly works” is not a checkbox state.
Example waiver (copy pattern)
- [ ] CI cache push — WAIVED: no Cachix token in personal forge;
CI still builds toplevel (`https://…/actions/runs/…`).
Revisit: 26.11 window. Risk: slow cold CI; deploy still local-builds.Example done-with-proof
- [x] Reverse proxy edge — proof: `curl -f http://127.0.0.1/` → 200
from day84/proxy.log; TLS mode: lab HTTP documented in docs/TLS.mdWaivers that are usually unacceptable at freeze
| Waiver | Why it fails freeze |
|---|---|
| “Secrets later” | Day 88 needs keys; Day 84 was the path |
| “Deploy only on the box” | Capstone A requires remote deploy story |
| “No tests, trust me” | Day 89 cannot verify |
| “CI red but laptop green” | Impurity; not frozen |
Preferred-not-met items (e.g. cache push) may be waived once with risk—prefer that over lying.
Theory 3 — Bug triage before freeze
Keep docs/BUGS.md or forge issues with a short table:
| ID | Sev | Symptom | Repro | Fix / defer |
|---|---|---|---|---|
| B01 | P0 | myapp fails without secret path | remove sops key | must fix pre-88 |
| B02 | P1 | deploy fails second time | redeploy without GC | fix or document |
| B03 | P2 | README host typo | visual | defer post-90 |
Severity guide
| Sev | Meaning for freeze |
|---|---|
| P0 | Blocks deploy, boot, secret decrypt, or health probe |
| P1 | Degrades ops; workaround exists; fix if time |
| P2 | Polish / docs nits |
P0 open at end of day ⇒ you are not frozen. Fix, reduce scope (disable the feature and update checklist), or postpone Day 88.
Theory 4 — Pre-DR readiness (prepare Day 88)
Before freeze ends, verify you have offline (not only on the VM you will wipe):
| Asset | Why |
|---|---|
Git remote or git bundle |
Rebuild source of truth |
flake.lock (in git) |
Exact pins |
| Age/sops private keys | Decrypt secrets on rebuild |
| Disko / partition notes | Disk layout without guessing |
| Network/IP/DNS notes | Reachability after boot |
| Hardware/VM config (CPU, disk, firmware) | Recreate lab shape |
| deploy SSH keys / known_hosts policy | Optional if rebuild is local-only first |
| Backup repo password (Day 69) if state restore is in scope | State half of DR |
# Example: offline git bundle on admin machine or encrypted USB
git bundle create /media/usb/capstone-a-freeze.bundle --all
# verify:
git clone /media/usb/capstone-a-freeze.bundle /tmp/capstone-verifyPut a sealed checklist in docs/DR-ASSETS.md: paths to key storage, not the keys themselves in git.
If your only copy of the age private key is on the lab disk you will wipe tomorrow, stop. Copy it offline today. Day 88 cannot invent lost keys.
Theory 5 — What “green” means at freeze
Minimum freeze gate (all should pass on the freeze commit):
nix flake metadata # lock present, inputs known
nix flake check -L # or explicit critical checks
nix build .#nixosConfigurations.<lab>.config.system.build.toplevel -L
# deploy once more if remote path is Capstone-claimed
# CI green on the same commit (or note forge lag)
Optional but strong:
nix build .#checks.x86_64-linux.<proxy-or-app-test> -LIf flake check is too heavy, document the exact attrs CI and you both run—still no red builds.
Theory 6 — Freeze documentation set
| File | Role |
|---|---|
docs/FREEZE.md |
Date, hash, tag name, waivers summary, “no new features” rule |
docs/DR-ASSETS.md |
Offline asset locations for Day 88 |
docs/DR-PLAN.md |
Ordered wipe/rebuild steps (mental rehearsal) |
docs/POST-FREEZE.md |
Parking lot for ideas after Day 90 |
docs/BUGS.md |
Open/closed with severity |
docs/CAPSTONE-A.md |
Checklist done/waived with proof |
FREEZE.md sketch:
# Capstone A freeze
- Date: YYYY-MM-DD
- Tag: capstone-a-freeze
- Commit: <full sha>
- Nix: <nix --version>
- nixpkgs: <from flake metadata>
- Host: lab (x86_64-linux)
## Green proof
- CI: <url>
- Local: flake check + toplevel (logs under ~/lab/.../day87/)
## Waivers
- …
## DR assets confirmed
- [x] keys offline
- [x] bundle or remote
- [x] Disko notesWorked example — Reducing scope instead of shipping broken
You planned ACME + public DNS; lab has neither; proxy works on HTTP localhost.
Wrong freeze move: leave ACME enabled, CI red, “fix during Day 88.”
Right freeze move: set lab HTTP mode, document prod ACME path in docs/TLS.md, tick proxy with proof, waiver “public ACME” with risk “no real cert automation proven.”
Scope reduction is a feature freeze skill, not failure.
Lab 0 — Status snapshot
mkdir -p ~/lab/90daysofx/02-nixos/day87
cd /path/to/capstone-flake
git status | tee ~/lab/90daysofx/02-nixos/day87/status.txt
git log --oneline -15 | tee ~/lab/90daysofx/02-nixos/day87/log.txt
nix flake metadata | tee ~/lab/90daysofx/02-nixos/day87/metadata.txt
nix --version | tee ~/lab/90daysofx/02-nixos/day87/nix-version.txtConfirm branch is the Capstone branch you intend to freeze (not a random experiment).
Lab 1 — Full green gate
cd /path/to/capstone-flake
nix flake check -L 2>&1 | tee ~/lab/90daysofx/02-nixos/day87/check.log
nix build .#nixosConfigurations.lab.config.system.build.toplevel -L \
2>&1 | tee ~/lab/90daysofx/02-nixos/day87/build.logDeploy once more if remote deploy is claimed on Capstone A:
# deploy-rs
deploy .#lab 2>&1 | tee ~/lab/90daysofx/02-nixos/day87/deploy.log
# OR Colmena
# colmena apply --on lab 2>&1 | tee ~/lab/90daysofx/02-nixos/day87/deploy.logPost-deploy health:
ssh lab 'systemctl --failed; curl -fsS http://127.0.0.1/ | head'Fix failures only—no drive-by dependency updates.
Lab 2 — Checklist pass (no ambiguity)
Open docs/CAPSTONE-A.md. For each line:
- Mark done with proof command/log path, or
- Formal waiver with reason + risk + follow-up
Cross-check against Day 83–86 claims (secrets, proxy, deploy, CI, tests, runbook). If architecture diagram disagrees with code, update the diagram today—code is truth at freeze.
Lab 3 — Bug bash (timebox 90–120 min)
- Sort
docs/BUGS.mdby severity.
- Reproduce top P0/P1.
- Fix or reclassify (with evidence).
- Re-run checks after each fix.
When tempted to add a feature: append one line to docs/POST-FREEZE.md and stop.
# POST-FREEZE.md
- [ ] Add second vhost for metrics (idea only)
- [ ] Try Attic instead of Cachix
- [ ] Capstone B: third nodeLab 4 — DR assets offline
- Confirm age/sops private keys exist off the lab disk.
- Confirm git remote push works or write a bundle to USB/admin.
- Fill
docs/DR-ASSETS.mdwith locations (password manager item names, USB label)—not secret material.
- Confirm Disko/partition and network notes match last known-good boot.
Optional integrity check:
# On admin machine, after cloning/bundling:
nix flake lock --no-update-lock-file
nix build .#nixosConfigurations.lab.config.system.build.toplevel -LLab 5 — Tag, FREEZE note, mental rehearsal
git add docs
git status
git commit -m "day87: capstone A feature freeze documentation"
git tag -a capstone-a-freeze -m "Capstone A feature freeze"
git rev-parse capstone-a-freeze | tee ~/lab/90daysofx/02-nixos/day87/freeze-sha.txtWrite docs/FREEZE.md (Theory 6). Write docs/DR-PLAN.md: ordered steps you will run tomorrow (wipe → install/disko → clone → keys → rebuild → health), with rough time estimates. Do not wipe yet.
Lab 6 — Freeze audit (pair or rubber-duck)
Without looking at git history, answer from docs only:
- What commit is frozen?
- How do you decrypt secrets after wipe?
- What is the one-command deploy?
- What is waived and why?
If any answer needs “I just know,” fix the docs before you trust Day 88.
Common gotchas
| Mistake | Fix |
|---|---|
| “One more service” at 23:00 | POST-FREEZE.md only |
| Untagged mush of commits | Annotated tag + hash in FREEZE.md |
| Waivers without risk | Add risk + date |
| Keys only on the VM you’ll wipe | Offline backup now |
| CI red at freeze | Not frozen—fix or waive honestly |
Freeze then flake update |
Only if build is broken; retag if you must |
| DR plan lives only in your head | DR-PLAN.md |
| Checkbox theatre | Proof commands or explicit waiver |
Checkpoint
- CI/check/build green on freeze commit (or honest limited attr set)
- Annotated tag
capstone-a-freeze
- CAPSTONE-A fully done or waived with proof/risk
docs/FREEZE.md+docs/DR-ASSETS.md+docs/DR-PLAN.md
- P0 bugs closed or scope reduced
- Deploy health verified once more if claimed
- Three personal gotchas
Commit
git add .
git commit -m "day87: capstone A feature freeze"
# tag if not already tagged on this commitWrite three personal gotchas before continuing.
Tomorrow
Day 88 — Disaster recovery: wipe the lab disk/VM; rebuild solely from flake + keys; time the recovery against today’s freeze tag.