# Changelog 2026-07-31 -- the `prefer-ipv6` / v6 VIP charm research

Session changelog (GA-R2/D1: ONE per session). Branch `dc-dc-stage5-preconditions`.
Status claims live ONLY in `docs/CURRENT-STATE.md`.

Context: bundle deploy attempt 1 failed 2026-07-31 with
`unknown option "prefer-ipv6"` on barbican, and the operator ruled *"Research what
those 6 charms do with v6 VIPs first (Recommended)"*. Stage 5 is blocked on that
research. This session executes it. **Read-only throughout: no cloud mutation, no
overlay edit, no ruling adopted.**

---

## Item 1 -- `docs/audit/stage5-prefer-ipv6-charm-research-20260731.txt` (NEW)

**What.** The capture answering the ruled question, plus two findings that came out
of the same measurement.

**Method, and why it is not the Charmhub `config-yaml` API.** The attempt-1 root
cause was measured against `config-yaml`, which answers only *is the knob declared*.
It cannot answer *what the charm does*. This research downloads the charm each app
actually deploys -- `juju download <charm> --channel <pinned> --base ubuntu@22.04
--arch amd64` from voffice1 -- and reads the templates and code inside it. Revisions
are recorded in the capture because `2024.1/stable` moves. Two declaring charms
(keystone 857, cinder 820) were downloaded as CONTROLS: without one, "binds v4 only"
and "binds v6 by another mechanism" cannot be told apart.

**The answer.** `prefer-ipv6` is not what makes HAProxy bind `:::port`, and never was,
for any of the thirteen. In both template families the v6 frontend bind is gated on
`ipv6_enabled = not is_ipv6_disabled()` -- a read of the kernel
`net.ipv6.conf.all.disable_ipv6` sysctl. Measured `0` on a live MAAS-deployed jammy
node in this DC. The v6 VIP is assigned by pacemaker on per-address family detection,
also independent of the option. Vault ships no haproxy template at all and its
listener is the hardcoded literal `[::]:8200`.

**What the option really does:** it is a unit address-family switch --
`get_relation_ip()` returns early with the unit's IPv6 address for EVERY relation,
ignoring the network-space binding; plus `bind_host ::`, ip6-localhost stats, and
keystone's `sync_db_with_multi_ipv6_addresses`. The value that sounds like a bind
address, `haproxy_host`, is consumed by NO template in any charm downloaded.

**Consequence recorded, not acted on:** `provider-bundle-check` invariant 9's
mechanism claim is factually wrong; when a ruling lands the invariant must be
REPLACED with a charm-schema-aware one and proven able to fail in both directions,
never deleted to go green.

**Revert.** `git rm docs/audit/stage5-prefer-ipv6-charm-research-20260731.txt`. The
file is a read-only capture; nothing depends on it but the CURRENT-STATE entry in
item 2.

## Item 2 -- `docs/CURRENT-STATE.md` section 1: the research result

**What.** The research outcome appended under the 2026-07-31 ruling block that
records the question -- the answer, its evidence, the invariant-9 consequence, the
new question about the seven declaring charms, the option-name sweep result, and the
runbook defect. Required in the same commit by GA-R1 rule 8 (C1); repo-lint L10
enforces it.

**Revert.** `git revert` this commit, or delete the appended block; the preceding
ruling text is unchanged and still reads correctly on its own.

## Item 3 -- MEASUREMENT ONLY (no artifact): full option-name sweep of the dc0 deploy input

**What.** Attempt 1 proved `juju deploy --dry-run` does not validate config option
NAMES, and juju aborts the whole bundle atomically on the first bad one -- so a second
unknown option elsewhere costs another full attempt. Every option assignment in
attempt 1's exact input (`bundle.yaml` + `vr1-dc0-vips` + `vr1-dc0-machines` +
`vr1-dc0-octavia-pki`) was compared against each charm's own `config.yaml` downloaded
at its pinned channel.

**Result: 56 applications, 81 option assignments, 20 charm schemas, 0 unresolvable,
and the only findings are `prefer-ipv6` on the same six.** No further option-name
failure is waiting for attempt 2. An unreadable or unrecognised schema REFUSES rather
than passing.

**Not built as a gate, deliberately.** Hard rule 1 plus the standing operator
directive: hardening is out of scope unless it blocks the deploy, and this one-shot
measurement already de-risks attempt 2. The method is reproduced verbatim in the
capture so it can be re-run or promoted later. CURRENT-STATE already records that no
gate in this repo reads a charm config schema.

**Revert.** Nothing to revert -- no repo artifact was created by this item.

## Item 4 -- LOGGED NOT FIXED: the dc0 deploy block omits a non-no-op overlay

**What.** `runbooks/dc-dc-phase4-juju-bundle-per-dc.md:553-557` gives the dc0 deploy
without `overlays/vr1-dc0-machines.yaml`, while the dc1 block three lines below
includes its machines overlay. Measured, the overlay's ONLY delta to the merged input
is `ovn-chassis.options.bridge-interface-mappings = 'br-ex:52:54:00:8c:2a:8c
br-ex:52:54:00:50:48:88'` -- the two dc0 compute provider MACs. Deploying dc0 exactly
as the runbook reads would leave ovn-chassis with no provider bridge mapping, which
surfaces later as tenant networks with no external path, not as a deploy error.
Attempt 1 as executed correctly included the overlay.

**Why not fixed here.** Hard rule 1 -- this session's step is the research. It is
DOCFIX material and is recorded in CURRENT-STATE and in the capture so it cannot be
lost.

**Revert.** Nothing to revert.

---

## What was NOT done, stated so it is not assumed

- **The overlay is untouched and R2 is unamended.** The operator's ruling was to
  research, not to fix; the fork between (b) and (c) is theirs.
- **No `prefer-ipv6` was removed from anything**, including the seven charms that
  declare it -- that is a separate, newly-raised question.
- **`provider-bundle-check` is unchanged.** Its invariant 9 is now known to rest on a
  wrong mechanism claim, but changing a gate before the ruling it gates would be the
  wrong order.
- **No cloud state changed.** The `vr1-dc0` model is still empty.
