# Changelog 2026-08-06 -- phase-03 Step 3.4: G3 domain-manager probe (named check + live PASS)

Session: continue Stage 5 (dc0) from the 2026-08-06 part-3 close. Branch
`dc-dc-stage5-preconditions`. Under blanket approval the changelog is the review surface:
each item states WHAT, WHY (evidence), and HOW TO REVERT.

Operator grounding this session (applied, not a ruling to adopt): (1) this is the D-121 HA
scale-up deployment -- reconcile any single-DC/non-HA-era step or gate against the current HA
census before grading it; (2) the standing IPAM ruling is IPv6-PRIMARY (v6 wherever possible,
v4/dual-stack only where forced, per D-101/D-139); D-141's v4-active/v6-reserved is the
NARROW, necessity-driven state of the container-hosted API-charm VIPs (juju LP #1723240), not
a cloud-wide posture. Recorded here so the sequence's Decision B (Step 12 Ceph/geneve-over-v6)
is framed as "verify the v6 target per-layer", not "defer v6".

## Item 1 -- NEW gate tool: scripts/g3-domain-manager-probe.sh + its harness

WHAT: added `scripts/g3-domain-manager-probe.sh` and `tests/g3-domain-manager-probe/run-tests.sh`.
The script is the appendix-C C.4 behavioral probe (phase-03 Step 3.4 stage 2, gate G3) turned
into a NAMED EXECUTABLE CHECK: as a domain-scoped `manager` it proves PASS (create user +
project in-domain, grant member + load-balancer_member), DENY (grant an unmanaged role
`manager` -> refused; read `admin_domain` -> refused), and UNAFF (cloud-admin sees all
domains). All fixtures live under a unique dated throwaway domain `g3-probe-<UTC>`; a trap
tears the domain + contents down on ANY exit. Exit 0 PASS / 11 PASS-case miss / 12 DENY LEAK
(security) / 14 precondition. Self-contained (sources no lib-*), so it pipes cleanly to a
rack via `bash -s`.

WHY: hard rule 4 -- no tested artifact existed for this job (the probe was a manual runbook
walk only); GA-R6 wants Step 3.4 to close on a named check whose output the commit cites; and
Stage 5 is per-DC, so dc1's Step 7 reuses this identical probe. Grounded in the real policy:
`policies/domain-manager-policy.yaml:103` `identity:create_grant = (domain_manager_grant AND
is_domain_managed_role) OR cloud_admin ...` -- so granting `manager`/`Admin` is refused and
granting `member`/`load-balancer_member` is allowed, exactly what the probe asserts.

HARNESS: 12/12, every exit path (0/11/12/14) has a failing-direction fixture; teardown proven
on both the happy and the failure path; all three groups proven to run. Writing it caught two
real defects before delivery: (a) the happy case was run inside `$(...)` so its pass/fail
accounting happened in a subshell and was LOST -- a genuine happy failure would have been
invisible (fixed: account in the parent shell, capture output via a file); (b) a fake
`domain list` emitted non-hex ids while the script counts hex (real keystone shape) -- the
subshell fix immediately exposed it as a real happy-case exit 11. gauntlet ALL GREEN (100).

REVERT: `git rm scripts/g3-domain-manager-probe.sh && git rm -r tests/g3-domain-manager-probe
&& bash scripts/run-tests-all.sh --record-manifest` (drops the manifest line too).

## Item 2 -- tests/HARNESS-MANIFEST recorded 99 -> 100

WHAT: `bash scripts/run-tests-all.sh --record-manifest` added `g3-domain-manager-probe`
(line 39). The drift check FAILED the gauntlet until recorded (present-but-unpinned); the diff
was exactly one addition, zero removals.
REVERT: covered by Item 1's re-record.

## Item 3 -- LIVE G3 probe on dc0: PASS, zero residue

WHAT: ran `ssh vr1-dc0-rack 'bash -s' < scripts/g3-domain-manager-probe.sh` (operator-approved
mutation). Result: `G3 PASS -- persona works and is bounded`, 7 ok / 0 fail, exit 0. Capture:
`docs/audit/g3-dc0-probe-20260806.txt`. Teardown VERIFIED clean by a follow-up read-only check
(`openstack domain list` back to admin_domain/service_domain/Default; no g3-mgr/g3-user/g3-proj).

WHY: closes phase-03 Step 3.4 stage 2. Stage 1 (override loaded) was verified read-only the
same session: `juju resources keystone` shows `policyd-override` attached (rev 2026-08-04) and
all THREE keystone units carry `PO: Unit is ready` -- note the app-status AGGREGATE read
"Application Ready" (no PO:), so verifying at the UNIT level is what prevented a false
"override missing" report (assert-before-check).

REVERT: none required -- the probe self-cleans and touched only objects it created; no
persistent cloud change. (The capture file is evidence; remove with `git rm` if unwanted.)

## Item 4 -- CURRENT-STATE: Step 3.4 recorded RESOLVED

WHAT: section-1 phase-03 block -- item (b) "Step 3.4 ... STILL NOT RUN" -> RESOLVED with the
capture cited; header count reconciled. The phase-03 exit gate now turns on the Horizon
reachable/login-works item (D-044 cookie + D-075 root-redirect per-rebuild + the VR0
nginx-repoint vs VR1 metal-admin-VIP-over-tailnet access-model reconciliation = the sequence's
Decision C), which is measured + ruled next.
REVERT: `git checkout HEAD~1 -- docs/CURRENT-STATE.md` (or revert the single hunk).

## Gates at delivery
- gauntlet ALL GREEN (100 harnesses); g3 confirmed EXECUTED in-gauntlet (12 pass / 0 fail).
- repo-lint 0 fail / 1 legacy warn (D-001..018 ASCII carve-out).
- ledger-scan: decisions + SEC unchanged; no D/DOCFIX/BUNDLEFIX number consumed (new tooling).
