# 2026-07-16 -- D-124 adopted; vr1-dc0 MAAS rack (vvr1-dc0) wired; rack-mgmt NetBox importer

## Context

Continuation of the Stage-3 batch prep. The operator ruled the MAAS model (region on Office1 +
rack controller per DC, D-123) and the rack<->region management addressing (D-124 Scheme A: a
transit link on the office1<->dc0 mesh leg) + rack sizing. This lands the `vvr1-dc0` rack wiring
and the NetBox importer for the addressing. NO cloud mutation -- authoring + offline validation
only; the NetBox `--commit`, the `tofu apply`, and the rack install stay operator-gated.

## What changed

**D-124 (ADOPTED 2026-07-16).** `docs/design-decisions.md`. The Office1-region<->DC-rack management
overlay. Answers "why not metal-admin?": the rack's node-facing leg IS metal-admin, but D-100 rules
metal-admin DC-LOCAL and a RULED sub-item makes the Office1<->DC mesh the management path -- so the
rack straddles metal-admin (nodes) + the mesh transit (region). **Scheme A** (transit-numbered mesh,
a /30 or /31 point-to-point) + rack sizing **4 vCPU / 8192 MiB / 80 GiB** ruled. The specific transit
CIDR + rack IP are assigned in office1-netbox (apex; operator-held token) via the D-124 importer -- no
literal invented in-repo.

**`vvr1-dc0` rack wired (`opentofu/`).**
- `main.tf`: `module "vvr1_dc0"` (cloudinit-vm) -- 4/8192/80, base = the noble image, `expose_nested_virt
  = false` (rack-only; the region + its LXD host compose, not the rack), two legs
  (`network_names = [metal-admin plane, mesh-vr1-dc0-office1]`), static `network_config` on both legs
  with IPs from NEW `vr1_dc0_rack_*` variables (NetBox-assigned via tfvars, not invented) + a route to
  the Office1 region (`10.10.0.0/22`, as-built D-115) over the transit. The interface-naming trap
  (enp1s0/enp2s0 predicted, confirm on first boot) is flagged in-block.
- `variables.tf`: `vr1_dc0_rack_metal_admin_ip`, `vr1_dc0_rack_transit_ip`, `vr1_dc0_rack_transit_prefix`,
  `vr1_dc0_rack_transit_peer_ip` (no defaults).
- `modules/mesh-link/outputs.tf`: added a `network_name` output (for the rack's transit-NIC reference).
- **Step-9 `maas-vm-host` DELIBERATELY STILL DEFERRED (DOCFIX-179):** adding the `provider "maas"` block
  it needs would force EVERY plan -- including the Steps 1-8 substrate apply -- to demand MAAS creds,
  and vr1-dc0's MAAS does not exist until vvr1-dc0 is up. Wire it as its own step once the rack MAAS is
  reachable.
- `tofu validate` -> Success; `scripts/opentofu-validate.sh` -> 11/11 modules PASS.

**`site-headend-install.sh` rack-only mode.** Added `--role <region+rack|rack>` (default `region+rack`,
100% backward-compatible). `--role rack` enrolls a DC rack controller to Office1's EXISTING MAAS region
(D-123): disable timesyncd -> install the `maas` snap (3.7/stable) -> `maas init rack --maas-url <url>
--secret <from --enroll-secret-file>`. It SKIPS all region+rack work (PostgreSQL, region init, admin/
login, LXD, the LXD vm-host, compose-DHCP) -- a DC rack runs no DB, composes nothing (the DC nodes are
OpenTofu-created + discovered via the vcloud virsh vm-host on the region), and metal-admin DHCP is a
region-side runbook step. Traps 1-3 (LXD/dnsmasq) do not apply in rack mode; trap 4's spirit (rack
configures NO DHCP) holds. The enroll secret is read from the file at mutate-time and NEVER echoed
(dry-run prints `<read from ...; never printed>`; the harness asserts the sentinel never leaks). The
`maas init rack --maas-url --secret` form is CONFIRMED against the MAAS snap docs/discourse (3.x-stable,
so it holds for the 3.7 pin), not assumed. Harness `tests/site-headend-install/` 19 -> 32 checks
(rack arg-contract, secret-non-leak, region-step-absence, backward-compat). Gauntlet stays 62.

**Rack-mgmt NetBox importer (`netbox/dc-rack-mgmt-import.py` + `tests/dc-rack-mgmt-import/`).**
Registers the D-124 addressing in office1-netbox: the transit prefix (role `transit`, site-scoped
vr1-dc0) + the rack's metal-admin IP. Stdlib-only, mirrors `dc-edge-wan-import.py`: whole-plan preflight
(transit is /30|/31 with host-bits clear + subnet_of the container; rack IP in `10.12.8.0/22` static
band `.2-.49`, not the `.1` gateway; the transit role + container + vr1-dc0 site exist), DRY-BY-DEFAULT,
`SANDBOX_HOSTS` guard. Both literals are REQUIRED inputs (`--transit-cidr`/`--rack-ip`) -- no invented
CIDR. Harness **96/96** (29 static + 67 behavioral).

**Scoping flags surfaced by the importer (operator-facing, logged NOT resolved):**
1. **The `transit` role must be seeded in office1-netbox** (die-if-absent precondition, like `edge`
   was). No transit/management role exists in the frozen draft; `infra` exists but is explicitly SHARED
   infra ("ptp transit, device loopbacks, RR loopbacks, anycast"), so D-124's "own role, mirroring the
   Edge role" is a NEW dedicated `transit` role to seed.
2. **The transit may need its OWN supernet, not `10.12.0.0/16` (Cloud).** D-124 mirrors the Edge role,
   which got a dedicated `172.30.0.0/16`. If office1-netbox assigns the transit from a dedicated
   management/transit supernet (NOT subnet_of Cloud), the importer correctly REFUSES at preflight and
   the fix is a one-line `CONTAINER` constant update. Decide the transit supernet when assigning.
3. Transit prefix scope = `dcim.site:vr1-dc0` (mirrors the DC-edge /24s); a region scope may be
   preferred -- operator's call at assignment.

## Tests / verification

- `cd opentofu && tofu validate` -> Success; `bash scripts/opentofu-validate.sh` -> 11/11 PASS.
- `bash tests/dc-rack-mgmt-import/run-tests.sh` -> 96/96 PASS.
- `bash scripts/repo-lint.sh` -> 0 fail, 1 legacy WARN.
- `bash scripts/run-tests-all.sh` -> GAUNTLET: ALL GREEN (62 harnesses).

## Operator `--commit` (ready; apex token operator-held)

    NETBOX_URL=http://10.10.1.10:8000 NETBOX_TOKEN=<apex-token> \
      python3 netbox/dc-rack-mgmt-import.py \
        --transit-cidr <office1<->dc0 transit /30|/31> --rack-ip <10.12.8.2-.49>   # dry-run; add --commit to write

(Seed the `transit` role + confirm the transit supernet first -- see scoping flags 1/2. Then fill the
`vr1_dc0_rack_*` tfvars with the assigned values.)

## Revert

- `git checkout opentofu/main.tf opentofu/variables.tf opentofu/modules/mesh-link/outputs.tf`
  (removes the `vvr1_dc0` block, the rack vars, the mesh-link output).
- `git rm netbox/dc-rack-mgmt-import.py && git rm -r tests/dc-rack-mgmt-import`.
- Delete the `## D-124:` section from `docs/design-decisions.md`.
- No cloud state touched.
