Worker: W1.2 (Phase 1, container-layer-elimination pass). Date: 2026-08-09. Scope: docs/dc-dc-deployment-workflow.md (stage identity, gates, tooling gap register) and the G-series gate register in docs/CURRENT-STATE.md section 6, read against the CONFIRMED Phase-0 outcome (pass0-admin-report.md): Option 1 (flat node VMs on vcloud libvirt + per-DC non-hypervisor vr1-dcN-client VM), cross-DC isolation handling (a) (new vcloud-level host-isolation control, new SEC-NNN row, mechanical --check gate), MAAS region unchanged (vr1-dcN-maas-01). READ-ONLY. No inferred values -- every claim below cites path:line from docs/dc-dc-deployment-workflow.md, docs/CURRENT-STATE.md, docs/design-decisions.md, or pass0-admin-report.md.
The task brief's example -- "does the Stage-2 substrate / bootstrap-gate stage collapse" -- names the wrong stage number. Measured against the workflow doc:
docs/dc-dc-deployment-workflow.md:60-146) is the Office1 SITE standup (D-114): it builds voffice1, a different containment VM (MAAS-region + LXD 5.21-track + MAAS-composed service VMs). Pass0 confirmed voffice1 is explicitly NOT container-layer (pass0-admin-report.md:19,60, "Office1 arm ... NOT container-layer"). Container-elim does not touch Stage 2's shape. This distinction matters for module design later in this doc: the project will carry TWO different "containment VM" patterns going forward -- one retired (Model B vvr1-dcN), one kept (voffice1's D-114 LXD-composition model) -- and a future session must not conflate them.docs/dc-dc-deployment-workflow.md:149-197) is the actual bootstrap-gate / two-root Model-B DC-substrate stage -- its own Build line says it verbatim: "D-123 Model B (TWO OpenTofu roots + a bootstrap gate between)" (:154). This is the stage container-elim restructures. All findings below key off Stage 3, not Stage 2.| Stage / Gate | Container-layer dependency (measured) | Option-1 change | Maps to (module layer) |
|---|---|---|---|
| Stage 0 (decision ratification) | None | None | N/A (history) |
Stage 1 (:36-57, vcloud host prep) |
None directly, but its 2026-07-10 as-built note (:47-56) shows the six DC planes were originally built HERE, at vcloud level, before D-123 later relocated them into the per-DC inner root (opentofu/main.tf:22-33, quoted at pass0-w4-targets.md:79-80: "the 6 vr1-dc0 planes MOVED to the INNER root ... under Model B"). Nested-KVM enablement here is a shared prerequisite for two different purposes: (i) voffice1's LXD nesting (Stage 2, KEPT) and (ii) the now-eliminated per-DC containment VM's inner libvirtd (Stage 3, GONE). |
Gate content is UNCHANGED (nested-KVM still needed for Stage 2's voffice1; pool/MTU/mesh gates untouched, D-100/D-101 own them regardless). What changes is Stage 1's RELATIONSHIP to Stage 3: under Option 1 the six per-DC planes land back at vcloud level via modules/dc-planes, the SAME level and SAME module family Stage 1 already establishes for the mesh/pools -- Stage 3 RECONVERGES onto Stage 1's own execution shape (single vcloud-local qemu:///system root) rather than diverging into it via D-123's later two-root split. |
IaC module -- vcloud-host-prep (host-wide, invoked ONCE) |
Stage 2 (:60-146, Office1/voffice1) |
NOT a consumer (pass0-confirmed; Section 0 above) | NONE. D-114's containment-VM pattern is architecturally distinct from D-123's Model B and is out of this pass's scope. Flag this explicitly in the Phase-4 change-set so it is not swept in by name-similarity ("containment VM" appears in both stages' prose). | Unaffected -- stays its own IaC module (office1-site) + procedure module (MAAS/LXD compose steps) |
Stage 3 (:149-197, per-DC OpenTofu substrate) -- THE STAGE MOST RESTRUCTURED |
Total. Build line = Model B outer+bootstrap+inner (:154); Gate line = vvr1-dc0 sizing/nested-KVM + "inner node VMs boot at depth-4 (D-114/D-123 boot gate)" (:155); Owns D-103-as-amended-by-D-123, D-122, D-123, D-124, D-125 (:156); Reuse-vs-new explicitly calls it NEW with "no OpenTofu/multi-rack precedent" BECAUSE of the two-root/bootstrap-gate mechanics (:157) |
Collapses to ONE tofu root, ONE apply, ONE execution host. Per pass0-w4-targets.md:69-76,97-111: node VMs, planes, edge, and the new client VM all target vcloud's own qemu:///system DIRECTLY -- no qemu+ssh-from-Office1 dial for the substrate build at all. This means Stage 3's substrate creation shifts from a two-plane execution stage (outer root = Plane 1/vcloud; inner root + bootstrap gate = Plane 2/voffice1 via qemu+ssh, D-128 docs/design-decisions.md:5354-5358) to a Plane-1-ONLY stage -- the entire DC substrate is built from vcloud with local virsh/tofu, matching Stage 1's own execution shape. The "OUTER -> BOOTSTRAP GATE -> INNER" apply-ordering contract (opentofu/main.tf:301-331, cited pass0-w4-targets.md:130-131) disappears outright: no bootstrap gate script (site-headend-install.sh --host-nodes node-host mode retires, pass0-admin-report.md:87), no cross-root state, no D-126 per-env qemu+ssh key auth for the substrate dial. Nesting depth 4 -> 2 (pass0-admin-report.md Section 4, pass0-w4-targets.md:158), so the D-114/D-123 "depth-4 boot gate" concept becomes a depth-2 boot gate -- a materially lower-risk check, closer to Stage 2's already-proven depth-3 (vcloud->voffice1->LXD) shape than to anything Stage 3 has attempted before. Stage 3's own "Reuse vs new" framing (:157, "NEW, no precedent") should be revisited in Phase 4: under Option 1 the stage is now MORE reusable (closer to Stage-1's flat-vcloud-libvirt shape) not less. Owns line changes: D-123 as currently phrased ("Model B site-down + two-root") is VOID under Option 1 and needs its Phase-4-framed amendment/new-D (per SCOPE-AND-EXECUTION-PLAN.md:197-200); D-125's "bridge-in" realization is retired (edge WAN -> direct NAT, pass0-admin-report.md:84,169), so D-125's Owns-line text needs updating alongside whatever D-number the container-elim ruling becomes. D-124's rack-transit addressing survives only for the CLIENT VM's transit leg, not for a rack-sizing purpose (D-124's own Stage-3 entry already flags its sizing clause VOID under Model B, :180; under Option 1 it stays void, now for a different reason -- no rack to size at all, only the small client VM). |
IaC module -- dc-substrate-flat (planes + edge + 12 node VMs + client VM, ONE apply, invoked per DC) -- see Section 3 |
Stage 4 (:200-212, MAAS enlist/commission) |
Indirect, via the rack-hosted services. dc-rack-net.sh (D-131 forwarder) and the per-DC artifact mirror/proxy (.4) run on the containment VM today (pass0-admin-report.md row 6-7, table). G17's dc0 check literal (curl -fsS http://10.12.8.4/...) targets that same host. |
Placement, not mechanism, changes -- and it is UNRESOLVED at Phase 0 (pass0-admin-report.md Section 6 item 3: "client VM / maas-01 / retire-with-evidence", carried into Phase 1 as an open item). Whichever placement is ruled, Stage 4's Gate-line prose (:206, "per-DC artifact source answering on its own address") and G17's check literal both need the new address substituted -- this is a genuine intersection with D-143's 10.12->10.13 re-IP: G17 will need BOTH edits (new address family per D-143, new HOST per container-elim) in the same pass, but they are two distinguishable causes per SCOPE-AND-EXECUTION-PLAN.md:194-196's own instruction, and this doc should record them as two line-items even though they land in one edit. Stage 4's own commission/deploy mechanics (:206-209) are otherwise UNCHANGED -- node VMs still PXE/commission the same way regardless of hypervisor nesting depth. |
Procedure module -- maas-enlist-commission (per-DC); its config INPUT (mirror/forwarder host) changes, its STEPS do not |
Stage 5 (:215-230, Juju + bundle) |
Structural, via D-138. D-138 (docs/design-decisions.md:7118-7180, RULED 2026-07-30) already moved the cloud-facing client (Juju CLI, openstack CLI) INTO the DC because voffice1 has no L3 path to any DC node plane and SEC-010/D-052/D-100 forbid opening one. The concrete host D-138 names is vvr1-dc0 (the containment VM) -- it is currently the D-138 execution host by NECESSITY, not by a separate design choice. |
The D-138 PRINCIPLE is preserved, its concrete host changes. Option 1's vr1-dcN-client VM is explicitly built to BE the D-138 host (pass0-admin-report.md:163-169, "carrying: the D-138 client role"; pass0-w4-targets.md:97-111 confirms the client VM occupies exactly D-138's required shape -- metal-admin + transit legs, an L3 presence). No Stage-5 gate content changes -- preflight.sh PASS, post-deploy cloud-assert.sh --capture, controller backup, geneve-over-v6/Ceph-over-v6 verification (:221) are all unaffected by WHICH VM the Juju client runs from. What DOES change: every literal address/host-alias in Stage-5 runbooks and CURRENT-STATE's version-pins table that names the containment VM's transit IP (e.g. docs/CURRENT-STATE.md:7829, "openstackclient ... INSTALLED ON THE dc0 RACK (172.31.0.2)" -- that IP is vvr1-dc0's transit address) must be re-pointed to the client VM's new address once it exists. D-140 constrains this stage's module mapping directly (Section 4 below) -- the Juju layer itself stays a PROCEDURE module (scripted, bundle-based) for this redeploy by an ALREADY-RULED pin (docs/design-decisions.md:7781-7787), not a design choice this pass is free to make. |
Procedure module -- juju-bundle-deploy (per-DC); execution-host param changes (vvr1-dcN client VM), D-140 keeps it out of IaC scope for now |
Stage 6 (:233-244, DR/failover) |
None found. Ceph replication, radosgw multisite, rbd-mirror all run on deployed OpenStack units, not on the containment layer. | None. | Procedure module -- dr-failover-drill (unaffected) |
Stage 7 (:248-259, Designate/COS/Magnum) |
None found. | None. | Procedure module -- designate-cos-magnum (unaffected) |
Cross-cutting: branch-per-stage/merge-at-close discipline (:424-436) |
Indirect -- Stage 3's branch would carry the container-elim change-set as part of its definition-of-done | Stage 3's branch (whatever it is named for the 10.13 rebuild) is where the module collapse actually lands; its close-out sweep must also reconcile .claude/skills/openstack-cloud-ops/ for the new invariant (per :430-433's standing rule) |
N/A -- process discipline, not a module |
Teardown runbook (dc-dc-teardown-rollback.md, gap #19a, :958-975) |
Direct (pass0 row 9: "vvr1-dcN as the teardown unit; D-122's 'site-down = one virsh destroy'") |
Re-authored around a scripted group-destroy of the flat vr1-dcN-* domain set OR, better, a module-scoped tofu destroy -target=module.vr1_dc0 now that the whole DC is ONE module call under the single flat root -- this would PARTIALLY re-earn the lost D-123 one-command convenience via tofu itself rather than virsh scripting (flagged for Phase 4, pass0 Section 6 item 7 already names this as owed design work) |
IaC-module-scoped teardown, one call per DC module |
Read against docs/CURRENT-STATE.md section 6 (:7786-7813) in full.
:7803) -- keyed to the two-stage apply by its own SEC dependency note: "SEC-010's transit FORWARD-drop is applied+verified at deploy step B via site-headend-install.sh --host-nodes --check on vvr1-dc0 (gate G10)". This gate is CLOSED (historical, dc0's checkpoint build) -- it does not reopen, but it is the template the next DC-substrate apply gate (whatever supersedes it for the 10.13 rebuild) must NOT copy verbatim: under Option 1 there is no outer/inner split for it to key off, so a redrawn gate is a SINGLE apply-and-verify, not a two-step G9+G10 pair.:7804, deploy steps B-E) -- the sub-items most exposed:
--host-nodes --check on vvr1-dc0" -- this exact check RETIRES with site-headend-install.sh's node-host mode (pass0-admin-report.md:87). Its REPLACEMENT is the new cross-DC host-isolation control's own --check (the confirmed Phase-0 gate handling (a), pass0-admin-report.md:288-291) -- but that control is scoped to the WHOLE vcloud host (both DCs' co-residency), not to a single DC's apply step, so it likely does NOT slot into a per-DC G10-style gate at all; it is closer in shape to a Stage-1-level, apply-once gate (see Section 4). This is a genuine stage-home question for Phase 1/2 design, not resolved by this worker's dimension alone -- flagged forward.TF_VAR_maas_api_key" and "netem placeholder" -- both UNAFFECTED (Plane-2/mesh concerns, not containment-layer concerns).:7806, vr1-dc1 build) -- CLOSED/historical, but it is the fullest worked example of what a per-DC Stage-3 gate sequence looks like today (outer apply -> Step B SEC-010 check -> inner apply -> rack standup -> commissioning). Its structure is the thing that collapses; future sessions writing the reshaped gate should read G12's own text as "the shape being replaced," not as a template to repeat.:7811, per-DC artifact source reachable from a node) -- OPEN today, and its check literals directly name the containment-VM-hosted mirror address (10.12.8.4 for dc0). As covered in Section 1's Stage-4 row: this gate's eventual close needs BOTH the D-143 address-family edit and the container-elim placement edit, kept distinguishable per the SCOPE plan's instruction.:7813, lb-mgmt IPAM apex) -- no container-layer dependency found; Octavia's charm-owned lb-mgmt network is unrelated to the substrate hypervisor topology. Named here only to confirm it was checked and correctly excluded (a "manufactured contradiction" risk this repo's own instrument-currency record warns about -- do not let G18 get swept into the container-elim change-set by proximity in the same table).:7795-7802,7805,7807,7809-7810, not assumed from gate NAME.:7808, open SEC rows) -- indirect only: container-elim MIGRATES several credential residencies (SEC-026/-028/-029, vm-secret-locations rack rows, per pass0 row 8) and ADDS at least one new SEC-NNN row for the cross-DC isolation control -- both are G14 COUNT-affecting events when they land, not gate-SHAPE changes. Flag for whoever next runs ledger-scan.sh after this pass's changes land, so the count is not read as unexplained drift (the project's own instrument-currency lesson #25 applies directly here).Net finding: exactly one G-series gate concept is directly restructured (G9/G10's DC-apply sequence); one is a placement-pending intersection with D-143 (G17); the rest are either unaffected or affected only as a downstream credential-count/ledger consequence (G14). No gate needs to be DELETED outright -- G9/G10's successor for the 10.13 rebuild is a simplified redraw, not a removal, since a substrate apply + SEC verification + boot proof + egress test are all still real checks, just fewer steps and one execution host instead of two.
Read against docs/dc-dc-deployment-workflow.md:447-1354 in full.
:499-578) -- RESHAPES. The still-open line "tofu plan/apply has NOT been exercised for the Stage 3 DC substrate" (:537) changes SCOPE under Option 1: the first real exercise of Stage-3 apply becomes a single flat-root apply, not an outer+bootstrap +inner sequence. The module inventory itself shrinks: modules/wan-bridge (D-125 bridge-in) is DELETED (pass0 row 3); the inner-root files (opentofu/vr1-dc0-substrate/, vr1-dc1-substrate/) RETIRE as separate roots, their module CALLS folding into the outer/flat root (pass0 row 2). modules/maas-vm-host's target changes from vvr1-dc0's inner virsh to vcloud's own virsh directly (pass0-w4-targets.md:109-111) -- this closes the DOCFIX-179 deferral note this gap still carries (:553-554, "deliberately NOT maas_vm_host_machine") differently than originally anticipated, since there is no longer an inner virsh to register.:857-933) -- STAYS CLOSED, but its "how it was actually closed" mechanism description (:894-904, the bridge-in shape: outer NAT + inner bridge onto br-vr1-dcN-wan) becomes HISTORICAL under Option 1's direct-NAT attachment (pass0-w4-targets.md:88-93, "exactly like Office1's edge does today ... Model A's item 8"). Flag so a future reader does not rebuild the retired bridge-in mechanism by reading this gap's closing note as current practice; a doc-currency addendum is owed here at the point the container-elim ruling lands, not a reopening of the gap itself.$DC region-qualified namespace, :976-1038) -- UNAFFECTED. D-119's region-qualified selectors (vr1-dc0/vr1-dc1) are an IPAM/naming-layer fix, orthogonal to hypervisor nesting depth.site-baseleg.sh, :1039-1109) -- verdict likely still holds, but the reasoning chain it rests on shifts and should be RE-VERIFIED, not carried forward silently. Today's "no leg required on vcloud" verdict (:1075-1093) rests on D-128: "no vcloud-originated DC operation exists ... Plane 2 ... EXECUTES on voffice1". Under Option 1 the SUBSTRATE build itself now originates from vcloud directly via a local qemu:///system provider (Section 1, Stage 3 row) -- but that is Plane 1 (host-VM creation), the SAME category D-128 already assigns to vcloud today for the outer root, not a new vcloud-originated L3 dial into a DC's own MAAS/Juju/openstack layer (which stays Plane 2, via voffice1, or D-138's client VM). The verdict's PREMISE is therefore probably unchanged, but this gap's own text explicitly warns "If a future change makes vcloud originate to a DC directly, this verdict expires and branch 1 applies" (:1092) -- container-elim is exactly such a change to the SUBSTRATE layer, even if not to the Plane-2 boundary, so a fresh re-measurement (not an inference from today's text) is owed once the flat root is built. Named here as a Phase-2/3 tooling-review item, not resolved by this worker.:1189-1310) -- UNAFFECTED in shape. The tailscale router VM (vr1-dcN-tailscale-01, utility .7) is already one of the 12 flat node-VM siblings inside today's inner root (pass0 table row 2's "12 node VMs") and folds into the flat root exactly like every other node VM -- same re-homing mechanism, no gap-content change. Confirmed explicitly so it is not mis-swept into the container-elim change-set by proximity (it is a D-129(iii) item, not a D-123/Model-B item).:1310-1354) -- NOT a consumer. Confirmed by direct read; this is a D-108 application-layer HA question, unrelated to substrate nesting. Named to record it was checked, per this repo's "a clean negative still needs the check shown" discipline.pass0-admin-report.md Section 5, handling (a)) has no register entry today because it is a Phase-0-confirmed-but-not-yet-designed deliverable. It should land as a NEW numbered item in this register (next-free per the register's own numbering, distinct from the D-NNN/SEC-NNN numbering it also needs) once Phase 1/2 design work produces its concrete shape, so it is trackable the same way every other gap here is.Per SCOPE-AND-EXECUTION-PLAN.md:40-43, "module" means BOTH IaC (OpenTofu) modules for the substrate AND procedure/runbook modules for the orchestration layered on top. This sketch maps today's Stage 1-7 flow onto that split, incorporating Option 1 and the (a) isolation control.
IaC-MODULE LAYER (OpenTofu, vcloud-executed, Plane 1 -- D-128)
[1] vcloud-host-prep (Stage 1) -- ONCE. pools, mesh triangle, MTU, nested-KVM base.
[2] office1-site (Stage 2) -- ONCE. voffice1 containment VM (D-114, UNCHANGED
by this pass -- kept as its own IaC module, its
LXD-compose half stays a procedure step inside it).
[3] cross-dc-isolation (NEW) -- ONCE, vcloud-level. The Phase-0-confirmed (a)
deliverable: nftables/isolation artifact +
mechanical --check + new SEC-NNN row. STAGE-HOME
OPEN (Section 2): candidate slots are (i) folded
into [1] as a host-prep-time control, applied once
and re-verified whenever a second DC lands, or
(ii) its own micro-module invoked once, before the
first per-DC substrate apply. Phase-1/2 design item,
not resolved here.
[4] dc-substrate-flat (Stage 3) -- PER DC (dc0, dc1, futureN). The collapsed module:
6 planes + edge + 12 node VMs + client VM, ONE
apply. Directly supersedes today's
outer+bootstrap-gate+inner three-part sequence.
Gate: single apply-and-verify (Section 2) --
SEC check via [3], depth-2 boot, direct-NAT egress
isolation test.
PROCEDURE-MODULE LAYER (scripted/runbook, mixed Plane 1/2/DC-local execution)
[5] maas-enlist-commission (Stage 4) -- PER DC. Unaffected mechanically; artifact-mirror/
rack-controller/D-131-forwarder PLACEMENT is an
input this module now takes as a parameter (client
VM vs maas-01 vs retire -- pass0 Section 6 item 3),
not a hardcoded containment-VM address.
[6] juju-bundle-deploy (Stage 5) -- PER DC. D-138's client role executes here, now on
the [4]-created client VM instead of the retired
containment VM. STAYS a procedure module, not an
IaC module, by the ALREADY-RULED D-140 pin (Section
1, Stage 5 row) -- this pass's module design must
not silently fold Juju into [4].
[7] dr-failover-drill (Stage 6) -- PER DC (or cross-DC pair). Unaffected.
[8] designate-cos-magnum (Stage 7) -- PER DC. Unaffected.
TEARDOWN (mirrors the IaC layer, module-scoped)
[T] tofu destroy -target=module.<dc> -- PER DC, one call per [4] module instance -- the
candidate re-earning of D-123's lost one-command
site-down (Section 1, teardown row).
Sequencing note for W4.3 (not this worker's dimension, flagged forward): [3] cross-DC isolation logically needs to exist and be verified BEFORE the second DC's [4] apply lands (otherwise dc0-alone co-residency has nothing yet to leak into, but dc0+dc1 co-residency does) -- this is a real ordering constraint on the module-invocation sequence Phase 4 designs, not merely a stage-numbering question.
docs/dc-dc-deployment-workflow.md (full read, 1354 lines); docs/CURRENT-STATE.md:7786-7835 (section 6 gate register + section 7 version pins); docs/design-decisions.md:7118-7180 (D-138 full text), :7781-7787 (D-140 full text), :8083-8143 (D-143 excerpt); pass0-admin-report.md (full read); pass0-w4-targets.md:1-220 (full read, targeted at execution-host/plane detail not fully covered in the admin report's synthesis).