Day 87 — Capstone 5/5 freeze

Updated

July 30, 2026

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.

Important

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

Freeze is a social contract with yourself

If Capstone is a solo lab, freeze still matters: Day 88 you will be tired and tempted to “fix while rebuilding.” The tag is the line between recovering a known system and redesigning under fire.

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 HEAD

Record 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.md

Waivers 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-verify

Put a sealed checklist in docs/DR-ASSETS.md: paths to key storage, not the keys themselves in git.

Warning

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> -L

If 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 notes

Worked 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.txt

Confirm 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.log

Deploy 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.log

Post-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:

  1. Mark done with proof command/log path, or
  2. 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)

  1. Sort docs/BUGS.md by severity.
  2. Reproduce top P0/P1.
  3. Fix or reclassify (with evidence).
  4. 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 node

Lab 4 — DR assets offline

  1. Confirm age/sops private keys exist off the lab disk.
  2. Confirm git remote push works or write a bundle to USB/admin.
  3. Fill docs/DR-ASSETS.md with locations (password manager item names, USB label)—not secret material.
  4. 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 -L

Lab 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.txt

Write 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:

  1. What commit is frozen?
  2. How do you decrypt secrets after wipe?
  3. What is the one-command deploy?
  4. 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 commit

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