# Changelog 2026-07-09 -- Stage 3 runbook: OpenTofu builds each DC substrate (DOCFIX-155)

No live infrastructure touched -- new runbook document only. Authored by a
delegated subagent (general-purpose, briefed with this repo's discipline,
the buildout design, D-103/D-100, the tooling gap register, `opentofu/
README.md` and `templates/README.md`, and the Stage 1 runbook as a style
template), reviewed before this commit -- no changes needed, repo-lint was
clean on the first pass.

## Item

### 1. DOCFIX-155 -- `runbooks/dc-dc-phase2-tofu-dc-substrate.md`
FILES: `runbooks/dc-dc-phase2-tofu-dc-substrate.md` (new), `docs/dc-dc-
deployment-workflow.md` (Stage 3 row updated).

WHAT: command-level runbook for buildout-design Section 4's Phase 2
(OpenTofu builds each DC's node-VM domains, plane networks, and OPNsense
edge, then registers the DC's libvirt host with its MAAS rack controller).
DC1-first; DC2 is treated as a HARD gate (D-101's supernet still
unassigned, gap #3's data half), not merely "do it later" -- the runbook
explicitly instructs not to uncomment `main.tf`'s commented DC2 blocks or
invent placeholder DC2 CIDRs.

**Five `!!!` callouts up front**, each naming a real constraint rather than
glossing over it: (1) hard dependency on Stage 2's MAAS reachability --
Steps 1-8 (libvirt-layer only) can proceed without it, Step 9 onward
cannot; (2) DC2's hard gate; (3) node-VM creation has no Roosevelt analog
(Section 9 shim register); (4) node sizing (vCPU/RAM/disk) is undecided --
the runbook uses `<REAL VALUE>` placeholders in its `.tf` block shapes,
never invented numbers; (5) `tc netem` parameters remain an unruled D-100
sub-item (gap #11) -- the runbook applies ONLY the buildout design's
qualitative "same-metro lean" language as an explicitly-labeled placeholder,
never a specific number presented as measured or ruled.

**A sixth callout** confirms the OPNsense prep tools (`bunzip2`,
`qemu-img`, `genisoimage`/`xorriso`) are not yet confirmed present on the
vcloud host -- Step 2 checks for all of them before anything else proceeds.

**Config.xml token gap named precisely:** `{{WAN_IF}}`/`{{LAN_IF}}` are the
one token pair that genuinely cannot be filled before the OPNsense domain
exists (only measurable via a real boot's `ifconfig` output) -- the runbook
states this plainly as a same-session blocker for the config render step,
rather than guessing a `vtnetN` name.

**The GATE section is deliberately honest**, walking each of Stage 3's four
exit-condition bullets and stating which are achievable this session vs.
conditional on Stage 2, node sizing, a real boot measurement, or D-100's
netem ruling -- concluding "this stage's exit gate is therefore
CONDITIONALLY MET AT BEST," with explicit instruction to update the
tracker doc to the real state, never a blanket DONE.

VERIFIED: `bash scripts/repo-lint.sh` 0 fail, 1 documented legacy warn (no
fixes needed for this file). NOT YET EXECUTED.

REVERT: `rm runbooks/dc-dc-phase2-tofu-dc-substrate.md && git checkout
HEAD~ -- docs/dc-dc-deployment-workflow.md` (safe).

## Next actionable step

Stage 4 (MAAS enlist/commission/deploy) is the direct successor; its
runbook was drafted in parallel tonight and should be reviewed for
consistency with this stage's own MAAS-discovery verification step (Step
10 here hands off to Stage 4's commissioning work).
