D-119: region-qualify the VR1 DC namespace -- C3 / gap #19 CLOSED (Stage 3 unblocked)
THE BUG: the token `dc0` meant TWO DIFFERENT CLOUDS depending on the file --
VR0's LIVE testcloud in scripts/lib-net.sh, VR1's FIRST DC in the NetBox
importer. One string, two clouds, one of them in production.

THE RULING (operator): the repo adopts the apex's names verbatim.
  vr0-dc0  VR0's DC0        the LIVE testcloud (a DIFFERENT region)
  vr1-dc0  VR1's FIRST  DC  GUA 2602:f3e2:f02::/48
  vr1-dc1  VR1's SECOND DC  GUA 2602:f3e2:f03::/48
Bare dc0/dc1/dc2 are now REJECTED LOUDLY everywhere.

D-119 COMPLETES D-117, it does not reverse it: it executes D-117's own amendment
across the three surfaces D-117 never touched. ZERO NetBox writes -- the apex was
already correct and self-consistent (MEASURED: f02::/48 -> vr1-dc0, f03::/48 ->
vr1-dc1); the REPO was the only surface out of step. Renaming the apex to match
the repo was considered and REJECTED (production IPAM write; VR1 would become the
only 1-indexed region; and vr1-dc1 would mean VR1's FIRST DC while vr0-dc1 means
VR0's SECOND).

THE PRIZE: the importer's DC->site map is now an IDENTITY -- there is no offset
table left to get wrong, and an assert enforces it. The original defect was
precisely a WRONG LOOKUP TABLE. The bug class is deleted, not defended.

TWO REAL BUGS the naming fix ALONE would NOT have closed (found by review sweep):

- BREAK-1: descriptions were built with f"VR1 {dc.upper()} ..." -- under D-119 that
  renders "VR1 VR1-DC0 provider-public" on all 36 prefixes. Same class as the
  original bug (deriving a label by munging a token), hidden in the description
  field where slug-focused review missed it. Now looked up from SITES[name].

- BREAK-2 (the important one): DC_GUA_PREFIX was NEVER cross-checked against --dc.
  `--dc vr1-dc0 DC_GUA_PREFIX=<f03>` was ACCEPTED: it writes the SECOND DC's GUA,
  carved with the FIRST DC's ULA nibble, scoped to the FIRST DC's site -- a
  silently mis-bound datacenter assembled from two disagreeing sources. Identity-
  mapping the slug leaves the ADDRESSING free-floating. Now guarded by EXPECTED_GUA.

ALSO: vdc1/vdc2 -> vvr1-dc0/vvr1-dc1 (D-114 amendment). D-114's own DR primitive is
`virsh destroy vdc1`, which read as "destroy VR1 DC1" while MEANING "destroy VR1
DC0". A mislabelled destroy command in a DR drill is not cosmetic. Neither VM is
built, so it is free. voffice1/Office1 KEEP their number (operator ruling).
Env var: DC1_/DC2_V4_SUPERNET -> VR1_DC1_V4_SUPERNET (both old names rejected).
rbd-mirror's --site-name aligned: `--dc vr1-dc0 --site-name dc1` was a re-created
two-namespace collision on one command line.

TESTS: dc-selector 21->30, prefixes-import 40->82 (identity invariant; EXPECTED_GUA
in BOTH mismatch directions; mismatched run writes NOTHING; matching pair still
succeeds; no munged description). GAUNTLET ALL GREEN (57). repo-lint 0 fail.
The old harnesses PINNED THE WRONG MAPPING -- they would have gone green while
enforcing the bug.

THE tofu apply IS NOT DONE -- IT IS GATED. Plan: 11 to add, 0 to change, 11 to
destroy (libvirt object names are ForceNew; moved{} makes the plan reviewable but
cannot suppress a replace). MEASURED SAFE: all 11 are EMPTY -- no guests, no
volumes, Stage 3 hasn't run. Office1's live objects are not in the plan.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent da6c473 commit c79ad6308b1638cae85eeb900550102ae2dffb91
@JANeumatrix JANeumatrix authored 21 hours ago
Showing 35 changed files
View
docs/changelog-20260714-d119-region-qualified-dc-namespace.md 0 → 100644
View
docs/dc-dc-deployment-workflow.md
View
docs/design-decisions.md
View
docs/session-ledger.md
View
docs/vr1-office1-as-built.md
View
netbox/README.md
View
netbox/dc-dc-prefixes-import.py
View
opentofu/main.tf
View
opentofu/modules/cloudinit-vm/variables.tf
View
opentofu/variables.tf
View
runbooks/dc-dc-phase0-vcloud-prep.md
View
runbooks/dc-dc-phase1-office1-standup.md
View
runbooks/dc-dc-phase3-maas-enlist-deploy.md
View
runbooks/dc-dc-phase4-juju-bundle-per-dc.md
View
runbooks/dc-dc-phase5-dr-failover-drill.md
View
runbooks/dc-dc-phase6-designate-cos-magnum.md
View
scripts/carve-host-interfaces.sh
View
scripts/dc-dc-ceph-disk-budget.sh
View
scripts/dc-dc-dr-drill.sh
View
scripts/dc-dc-radosgw-multisite.sh
View
scripts/dc-dc-rbd-mirror.sh
View
scripts/lib-hosts.sh
View
scripts/lib-net.sh
View
scripts/phase-00-maas-standup.sh
View
scripts/reenroll-hosts.sh
View
scripts/site-headend-install.sh
View
tests/carve-host-interfaces/run-tests.sh
View
tests/dc-dc-ceph-disk-budget/run-tests.sh
View
tests/dc-dc-dr-drill/run-tests.sh
View
tests/dc-dc-prefixes-import/test_logic.py
View
tests/dc-dc-radosgw-multisite/run-tests.sh
View
tests/dc-dc-rbd-mirror/run-tests.sh
View
tests/dc-selector/run-tests.sh
View
tests/phase-00-maas-standup/run-tests.sh
View
tests/reenroll-hosts/run-tests.sh