# Changelog 2026-07-10 -- DOCFIX-179: OpenTofu scaffold, first real validation + apply

**Context.** First-ever execution of the `opentofu/` tree against a real `tofu`
binary (OpenTofu v1.12.3), on the vcloud host, executing
`runbooks/dc-dc-phase0-vcloud-prep.md` Steps 8-11. The tree had carried a
**SCAFFOLD, UNVALIDATED** banner since authoring (no `tofu` had ever run it).
Two real bugs blocked `tofu init`/`plan`; both fixed here, then the Stage-1
module slice was validated, planned, and applied clean (13 libvirt objects).

## What changed

### FIX 1 -- per-module `required_providers` (the `tofu init` blocker)
- `tofu init` failed: child modules use `libvirt_*`/`maas_*` resources but did
  not declare their own `required_providers`, so OpenTofu inferred the
  `libvirt_` prefix as **`hashicorp/libvirt`** (nonexistent) instead of
  `dmacvicar/libvirt`. Provider SOURCE mapping is NOT inherited by child
  modules -- only provider CONFIGURATION is.
- Added `versions.tf` (source-only; version stays pinned at the root) to every
  module using a provider resource: 8 libvirt modules (`dc-planes`, `mesh-link`,
  `dc-storage-pool`, `office1-network`, `node-vm`, `base-image`, `cloudinit-vm`,
  `opnsense-edge`) + 1 maas module (`maas-vm-host`). `netem-link` uses only the
  built-in `terraform_data`, so it needs none. Fixed comprehensively (all
  modules, not just Stage 1's four) so Stage 2/3 do not re-hit it.

### FIX 2 -- `tofu fmt` (the whole never-fmt'd scaffold)
- `tofu fmt -recursive opentofu/` normalized 11 files (attribute alignment,
  comment reflow) that had drifted because no `tofu` had ever formatted them.

### CHANGE 3 -- `provider "maas"` deferred to Stage 3
- The root `provider "maas"` block forced `tofu plan` to demand `maas_api_url`
  AND the **sensitive** `maas_api_key` for a Stage-1 plan that creates ZERO
  MAAS resources -- which would bake a fake key into `phase0.tfplan` and
  `terraform.tfstate` (the DOCFIX-175 plaintext-secret surface). Operator ruled
  (2026-07-10) to fix structurally rather than use the runbook's placeholder
  workaround. Removed the `provider "maas"` block from `main.tf` and the
  `maas_api_url`/`maas_api_key` variables from `variables.tf`, with in-file
  notes to re-add them at Stage 3 (when `maas-vm-host` is instantiated). `maas`
  stays in the ROOT `versions.tf` `required_providers` (version pinned,
  `.terraform.lock.hcl` complete for Stage 3).

### FIX 4 -- repo-lint must skip OpenTofu's `.terraform/` provider cache
- After the first real `tofu init`, `repo-lint` FAILED L1 (ASCII) on a
  downloaded provider plugin's README inside `opentofu/.terraform/`. DOCFIX-175
  gitignored `.terraform/` for git, but `repo_lint.py`'s `all_text()` scans the
  filesystem, not git. Added `".terraform" in p.parts` to `all_text()`'s skip
  set (alongside `.git`/`__pycache__`) -- third-party, gitignored, not repo
  content. `tests/repo-lint/run-tests.sh` -> 34/34 PASS.

### Result
- `tofu validate` -> Success. `tofu plan` -> 13 to add / 0 / 0, with NO MAAS
  vars required. `tofu apply` -> **13 added, 0 changed, 0 destroyed** (6 DC1
  planes + dc1/office1/dc2 pools + office1-local + 3 mesh legs, all MTU 9000).
- `.terraform.lock.hcl` is now generated -- **commit it** (pins provider
  hashes: `dmacvicar/libvirt` 0.9.8, `canonical/maas` 2.7.2).
- `opentofu/README.md` status banner updated: Stage-1 module slice VALIDATED +
  APPLIED; the not-yet-instantiated Stage 2/3 modules remain UNVALIDATED.

## Verification
- `bash scripts/opentofu-validate.sh` (== `tofu fmt -check` + `init` + `validate`)
  -> clean after the fixes.
- `bash scripts/repo-lint.sh` -> 0 fail.

## Revert
- `git rm opentofu/modules/*/versions.tf` (the 9 added files) -- restores the
  original `tofu init` inference failure.
- Re-add the `provider "maas"` block to `main.tf` and the two `maas_*` variables
  to `variables.tf` from this changelog / git history.
- `tofu fmt` reverts are cosmetic; `git checkout` the 11 files to undo.
- (Live infra: `runbooks/dc-dc-teardown-rollback.md` / `tofu destroy` -- not part
  of a repo revert.)

## Follow-up (logged)
- Stage 3's runbook must re-add the `provider "maas"` block + the two variables
  when it wires `maas-vm-host` -- noted in `main.tf`/`variables.tf` in-file.
