Post-commit 5175365 (Stage-3 sweep C+D), the adversarial re-run + advisor confirmed OBS-3 as material once the operator ruled "DC0 and DC1 have their own ISP connections." Model B nesting had severed the per-DC simulated-ISP egress: modules/site-wan makes vr1-dc0-wan a libvirt NAT that egresses via ITS HOST's default route; under Model B that host is vvr1-dc0 (transit-only, East-West, SEC-010 FORWARD-dropped), so the inner NAT had nowhere to go. Operator ruled bridge-in (single-NAT) over the double-NAT alternative. Governing record: D-125 (cross-ref D-122/D-123). NO cloud mutation; authored present-only; both roots validate. NOT applied, NOT committed, NOT pushed.
New module opentofu/modules/wan-bridge/ (versions/variables/main.tf/outputs.tf). A libvirt forward = { mode = "bridge" } network bound to a pre-existing host bridge (bridge = { name = ... }), no subnet/NAT. Sibling to site-wan (chosen over a site-wan mode flag so every existing NAT user -- office1-wan, the new vr1-dc0-uplink -- stays literally untouched; noted vs. the option preview's "mode param" wording). Schema (bridge is an attribute-OBJECT, not a string) measured from the installed provider, not inferred. Covered by opentofu-validate S3 (standalone [PASS]).
OUTER root (opentofu/main.tf + variables.tf, vcloud).
module "vr1_dc0_uplink" (site-wan NAT) = the SINGLE ISP NAT at vcloud level (egresses via vcloud's uplink). CIDR = new HELD var.vr1_dc0_uplink_cidr (no default; NetBox office1-netbox apex).vvr1_dc0 gains a 2nd NIC (order [transit, uplink] -- transit stays first so SEC-010/--transit-if keep keying on it). Netplan now declares the IP-less uplink port + the br-vr1-dc0-wan bridge (STP off), so the bridge exists before the inner apply. tofu validate Success.INNER root (opentofu/vr1-dc0-substrate/main.tf). module "vr1_dc0_wan" switched site-wan (NAT, 172.30.2.0/24) -> wan-bridge bound to br-vr1-dc0-wan. OPNsense wan_network_name wiring unchanged (same output). OPNsense WAN re-addresses into the vcloud ISP /24 (edge config, D-113 -- HELD). tofu validate Success.
Bootstrap (scripts/site-headend-install.sh node-host mode).
--uplink-if (default uplink) + --wan-bridge (default br-vr1-dc0-wan).node_host_check: WAN-egress guard -- verifies the bridge exists AND the uplink is ENSLAVED (master <bridge>); same fail-open class as the SEC-010 transit-iface check. Prints the DEPLOY-TIME isolation gate (throwaway guest on the bridge must get a vcloud-ISP addr + ping out; FAIL => double-NAT fallback).node_host_setup: SEC-010 rationale corrected (bridge-in has no inner NAT, so the old ip_forward forcing no longer applies); br_netfilter CONSTRAINT -- keep the FORWARD-drop interface-scoped, never global. Verifies the WAN bridge landed (does NOT create it; netplan owns L2). Harness 49 -> 54.Records. D-125 (new); security-ledger SEC-010 (bridge-in + br_netfilter constraint + hardened --check); model-a-fallback-plan B->A delta item 8 + revert step + OPNsense WAN restore; session-ledger (commit 5175365 + OBS-3 RESOLVED-by-D-125 + new HELD gates); references/platform-traps.md 1g (bridge
tofu validate OUTER = Success; INNER = Success; opentofu-validate S3 [PASS] modules/wan-bridge (+ site-wan still [PASS], untouched).tests/site-headend-install = 54/54.repo-lint = 0 fail (1 documented legacy WARN). All edited files ASCII/LF.vr1_dc0_uplink_cidr (vcloud ISP /24) in office1-netbox; set OPNsense WAN static in that /24 (edge config). tofu plan requires the tfvar.uplink/br-vr1-dc0-wan interface names on first boot (enp2s0-vs-ensX naming trap).git rm -r opentofu/modules/wan-bridge; revert opentofu/main.tf + variables.tf (drop vr1_dc0_uplink + vr1_dc0_uplink_cidr + the 2nd NIC/netplan bridge); revert opentofu/vr1-dc0-substrate/main.tf vr1_dc0_wan back to site-wan NAT 172.30.2.0/24; revert the site-headend-install.sh --uplink-if/--wan-bridge block + harness; revert the doc records. This reverts D-125's bridge-in to the (dead-egress) committed Model B state -- the full B->A revert is docs/model-a-fallback-plan.md.