Opened Stage 3 (VR1 DC substrate) on branch dc-dc-stage3-phase2-dc-substrate. Walked runbooks/dc-dc-phase2-tofu-dc-substrate.md to surface its blocking decisions before any tofu apply. The walk (plus a bundle.yaml HA review and a whole-host resource validation) produced two operator rulings and a runbook fix-forward. No cloud mutation this session -- design decisions, one resource calculation, and doc reconciliation only.
D-121 (ADOPTED IN PART) -- VR1 makes HA real + the node layout that carries it. docs/design-decisions.md. The bundle review found the root fact: VR0 ran its control plane single-unit by design (D-009: hacluster + VIP relations at num_units: 1, "decorative... scale-up is mechanical: 1 -> 3"). The 12 hacluster subordinates and D-036's dual VIPs are already wired; the units were never added. D-121 adopts the 14-service 1->3 scale-up (keystone, glance, neutron-api, nova-cloud-controller, placement, cinder, openstack-dashboard, octavia, barbican, magnum, designate, ceph-radosgw + rabbitmq + vault; ceph-rbd-mirror stays 1 per D-108). Two realities recorded so the cost is not under-stated: (1) it is a placement rewrite (each app's to: must spread across 3 distinct hosts -- co-located units are decorative again; a Stage-5 placement-balance rule was folded in from the openstack0-3 balance analysis: spread each app's 3 units one-per-control-node so the RAM-heavy trio auto-balances, and distribute the ~42 API containers evenly ~14/control-node, sized for at 64 GiB); (2) vault is MySQL-backed today (C1 revised D-006; vault:ha removed by BUNDLEFIX-002), so its HA path was a sub-ruling -- RULED (v-a) 2026-07-15: keep MySQL-backed, scale to 3, re-add vault:ha, gated on verifying the 1.8/stable charm does MySQL-backend HA with 3 units (else evaluate Raft via D-068, NOT etcd). 3-unit vault triples the unseal burden, intersecting OPEN SEC-003. Node layout = Option C (operator-ruled): 3 control + 2 compute + 3 storage per DC (16 node VMs). Ruled sizing: control 16 vCPU/64 GiB/150 GiB, compute 12/48/100, storage 8/24/550. ceph-osd=3/DC, nova-compute=2/DC, ceph-mon/mysql/rabbitmq/vault/ovn-central=3 across the control nodes.
Whole-host resource validation (Option C). Measured the actual VR1 host (not the design estimate): 256 vCPU / 1024 GiB RAM / 10 TiB disk (nproc/free/df; currently only Office1 runs -- voffice1 16/32/600 + office1-opnsense 2/2/11, netbox+tailscale nested inside voffice1). Modeled Option C across all layers (Office1 as-built + both DCs + edges + containment overhead) at scratchpad/optc-calc.py: 222 vCPU / 790 GiB / 5.4 TiB -> FITS (RAM binding at 77%; vCPU overcommits; disk thin-provisioned at 53%). Finding: C is NOT heavier than B -- it is RAM-lighter (790 vs 838 GiB) because role separation lets storage nodes run lean. Sensitivity: control-node RAM is the knob (96 GiB -> 982 GiB / 96%); held <= 64 GiB. This corrected D-121's first-pass "C is heaviest" characterization. Also ran scripts/dc-dc-ceph-disk-budget.sh (Option B/C 4+4 and 3+2+3): PASS with wide margin -- disk is not the binding constraint.
D-122 (ADOPTED) -- VR1 site shape. docs/design-decisions.md. Records the operator's Ruling 2: each site nested in its own containment VM (site-down/recovery + site-to-site drills); dark fiber DC-DC-Office is East-West ONLY (never an internet path); each site has its own dedicated L3 "ISP" uplink (build vr1-dc0-wan on the office1-wan pattern -- NOT a mesh leg); the DC OPNsense edge follows the proven Office1 pattern (2048 MiB / 2 vCPU / nano, REST-API config per D-113(a2)); each site runs its own MAAS controller (may bootstrap from an existing one). Closes the phase2 runbook's Ruling-1/Ruling-2 STOP-gates. Subsumes the DOCFIX-185 amendment note. Edge NIC model ruled (D-122 refinement, operator 2026-07-15): 2-NIC, baremetal-matched. NIC count mirrors the Roosevelt hardware -- nodes = 6 NICs (one per plane, measured on VR0 openstack0-3), edge = 2 (WAN + LAN). The six planes are routed by the FABRIC (OVN/OpenStack on the deliberately isolated-L2 dc-planes segments), so the edge is only the external boundary, not an inter-plane router -- no opnsense-edge module extension. Edge WAN = vr1-dc0-wan (172.30.2.0/24, D-115); edge LAN = provider-public (10.12.4.0/22; external gateway per D-100). This resolves the runbook's earlier "LAN role / build a site-internal segment" flag: no new segment is needed. Two build prerequisites remain: build vr1-dc0-wan as a tofu module (promote off the virsh office1-wan one-off), and register 172.30.2.0/24 in office1-netbox (D-115-ruled, not yet loaded -- absent from the draft; no import covered the DC Edge /24s).
phase2 runbook fix-forward. runbooks/dc-dc-phase2-tofu-dc-substrate.md:
dc1/dc2 object renamed to vr1-dc0/vr1-dc1 (matching main.tf); added a naming note + a HAZARD line that any residual bare dcN reintroduces the exact cross-cloud collision D-119 deletes. Revert: git checkout the file.config_iso_path); edge is now prep-image + post-boot console/SSH/API. WAN_IF/LAN_IF agonizing removed (measured post-boot).memory_mib=2048/vcpu=2/nano, no disk_size_bytes, wan_network_name = vr1-dc0-wan (dedicated per-site ISP uplink, office1-wan pattern), lan_network_name = site-internal network -- both flagged as genuine build prerequisites.module "vr1_dc0_node_*" blocks in three role-sizes (3 control 16 vCPU/65536 MiB/150 GiB, 2 compute 12/49152/100 GiB, 3 storage 8/24576/550 GiB; disk in bytes via N * 1024*1024*1024), with the Stage-5 HA-scale-up context.vr1-dc1 gate rationale (top callout + exit GATE + checklist): its supernet IS assigned (D-115 10.12.64.0/19, imported to office1-netbox); it stays out of scope by SEQUENCING, not a missing literal. No vr1-dc1 build steps added.git checkout runbooks/dc-dc-phase2-tofu-dc-substrate.md.Two gaps surfaced by the fix-forward (LOGGED, not fixed -- they need real values/build work):
opentofu/main.tf's commented vr1_dc1_planes block (~L38-50) still says "wait for NetBox to assign D-101's supernet" -- STALE per D-115. Left in place (this was a doc-only pass); flagged for the main.tf owner.vr1-dc0"; the operator then ruled the planes are fabric-routed and the edge is 2-NIC, so the LAN = provider-public (a vr1_dc0_planes output) -- NO new site-internal segment needed. Two REAL prerequisites remain before Step 5's tofu apply: build vr1-dc0-wan as a tofu module (promote off the virsh office1-wan one-off), and register 172.30.2.0/24 in office1-netbox (D-115-ruled, not yet loaded). Recorded in the runbook, not invented.Ledger + tracker reconciliation. docs/session-ledger.md (next-free D 121->123; a Stage-3 open-work block with the two rulings, the validation, the fix-forward-in-flight, the stale-gate correction, and the logged-not-executed calc-promotion follow-up) and docs/dc-dc-deployment-workflow.md (Stage 3 State row updated from "runbook written" to "IN PROGRESS + two rulings landed").
bash scripts/repo-lint.sh -> 0 fail, 1 legacy WARN (the documented D-001..018 non-ASCII carve-out; new D-121/D-122 text is ASCII).bash scripts/ledger-scan.sh -> next-free D = 123; D-121/D-122 not flagged PROPOSED/OPEN.python3 scratchpad/optc-calc.py.## D-121: / ## D-122: sections from docs/design-decisions.md (they are append-only additions; nothing else references them yet in code).docs/session-ledger.md next-free line + the Stage-3 block, and the docs/dc-dc-deployment-workflow.md Stage 3 State paragraph, to their prior text.git checkout runbooks/dc-dc-phase2-tofu-dc-substrate.md (see the runbook section for the per-change reverts).