diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index ccbea3e..60b7ea3 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -2436,6 +2436,36 @@ TOKEN or `dc2` by POSITION -- the DC1/DC2 ambiguity item 3.1 retired elsewhere, here deciding certificate identity. Both live certs carry `dc0.vr0`, the VR0 region, wrong under either reading. A12 refuses rather than picking. + **>>> THE TWO PARAGRAPHS IMMEDIATELY ABOVE ARE SUPERSEDED 2026-07-30 (DOCFIX-205; GA-R1/C2 -- + measurement corrects the document). THE "RULING-SHAPED GAP" WAS NOT ONE: IT WAS RULED ON + 2026-07-13 BY D-117.** Kept above as history, per this document's in-place supersession + precedent. Measured, the correction is: + - **The token-vs-position fork is CLOSED.** D-117 (ADOPTED 2026-07-13, four days after D-106) + names the supersession in its own Status line -- "Supersedes ... the D-106 `dc1`/`dc2` zone + labels" -- and its amendment rules the replacement: "The repo's `dc1`/`dc2` labels are + retired in favour of `dc0`/`dc1`." Substrate `vr1-dc0` -> `dc0`, `vr1-dc1` -> `dc1`. The + VR1 zones are `omega.dc0.vr1.cloud.neumatrix.local` / `omega.dc1.vr1.cloud.neumatrix.local`. + D-008's four-label shape is unchanged, and D-119's single `vr1-dc0` token is NOT adopted for + DNS (its bare-`dcN` rule targets a token read alone; here the next label IS the region, and + D-117's own replacement labels are bare `dc0`/`dc1`). + - **WHY IT RESURFACED, and this is the reusable half.** D-117 ruled that the ADOPTED decision + texts D-101/D-106/D-111/D-115 be ANNOTATED in place. **Measured 2026-07-30: zero of the four + carried any D-117 annotation.** It stayed invisible because D-117's OWN Status line claimed + "FULLY EXECUTED BY D-119", while D-119 scopes its discharge to the SELECTOR half only + ("region-qualify the shell SELECTORS across the three surfaces D-117 never touched"). A + reader checking whether the annotation was owed was told it was done. All four are annotated + and D-117's Status line is corrected as of DOCFIX-205. + - **"BLOCKING" WAS WRONG AS STATED.** Measured live on voffice1 both DCs, A12 is in its INERT + branch and PASSES -- `os-public-hostname` is set in no deploy artifact (B5 IP-only). It arms + at D-106's Stage-7 work. It was never blocking current work. + - **A12 IS NOW AN ASSERTION, NOT A REFUSAL.** It derives the expected zone from the site token + (`${SITE%%-*}` -> region, `${SITE#*-}` -> DC label; never typed) and asserts every DNS SAN + falls in it. Harness **23/23** -- T21 REPLACED (the refusal became a pass on the correct + zone; replaced, not deleted), plus new **T21b** (the OTHER DC's label in the right region + FAILS -- the cross-DC mix-up F1 proved possible, which region-only checking passed) and + **T21c** (`vr1-dc1` derives its own zone, proving it is not a dc0 constant). + - The F9 reissue obligation STANDS unchanged: both live certs carry `dc0.vr0` and must be + reissued into their DC's zone before `os-public-hostname` is set. **A PRECEDENCE BUG THE HARNESS CAUGHT:** REFUSE was checked before FAIL, so once A12 armed, a CONFIRMED wrong-region SAN reported as "could not evaluate". A known defect outranks an unevaluated one; the verdict now reports FAIL first and still names the refusal. diff --git a/docs/changelog-20260730-docfix205-d117-annotation.md b/docs/changelog-20260730-docfix205-d117-annotation.md new file mode 100644 index 0000000..6539593 --- /dev/null +++ b/docs/changelog-20260730-docfix205-d117-annotation.md @@ -0,0 +1,169 @@ +# Changelog 2026-07-30 -- DOCFIX-205: the D-117 annotation half, and A12 becomes an assertion + +Session changelog (GA-R2/D1: ONE per session). Branch `dc-dc-stage5-preconditions`. +Status claims live ONLY in `docs/CURRENT-STATE.md` (GA-R1). + +**Trigger.** The operator asked to rule on queued question Q1 +(`docs/audit/queued-findings-20260730.txt`): whether substrate `vr1-dc1` is `dc1` by TOKEN or +`dc2` by POSITION for DNS/certificate identity. Measured before presenting options, per the +standing discipline ("a finding is an observation, not a conclusion"). **The question was +WITHDRAWN, not ruled: its premise had been retired by D-117 on 2026-07-13.** What follows is +the repair, approved by the operator as a batch ("All four + code fixes"). + +**No new D-number (GA-R3).** Recording a supersession that D-117 already ruled is not +architectural consequence beyond the stage; the runbook and script fixes are OPS. Doubt +resolves DOWN. Next-free UNCHANGED: D 138 / DOCFIX 205 -> 206 after this / BUNDLEFIX 053. + +--- + +## 1. D-106 annotated -- the causal surface + +`docs/design-decisions.md`, D-106. Added an ANNOTATION block after the Status line recording +that the `dc1.vr1` / `dc2.vr1` zone labels in the Decision block are SUPERSEDED by D-117, with +the read-through mapping (`dc1.vr1` -> `dc0.vr1`, `dc2.vr1` -> `dc1.vr1`), the unchanged D-008 +shape, why D-119's single `vr1-dc0` token is NOT adopted for DNS, and the selector-is-not-a-label +warning with the derivation. The Decision block itself is UNTOUCHED, per D-117's own ruled +treatment ("ADOPTED decision text: ANNOTATE in place, do NOT rewrite"). + +**Evidence.** D-117 Status line: "Supersedes ... and the D-106 `dc1`/`dc2` zone labels." +D-117 amendment: "The repo's `dc1`/`dc2` labels are retired in favour of `dc0`/`dc1`." + +**Revert.** Delete the `**ANNOTATION 2026-07-30 (DOCFIX-205) -- THE ZONE LABELS BELOW ARE +SUPERSEDED BY D-117.**` block through the line ending "the mechanism that hid it." + +## 2. D-101, D-111, D-115 annotated -- the other three D-117 owed + +Same ruled treatment; each scoped to what that entry actually carries. + +- **D-101** -- the hardest, because it carries BOTH namespaces. Annotation reads the entry BY + DATE: the 2026-07-09 text uses `DC1`/`DC2` for VR1's first/second DC (and `DC0` for VR0's), + while amendments dated 2026-07-14+ already use `vr1-dc0`/`vr1-dc1` correctly. This is D-117 + TRAP 2 where it bites hardest -- the token `dc1` means DIFFERENT datacenters in the two + halves of one entry. Also restates that the ULA hextet tracks the GUA site nibble, not the + DC index, and must not be "fixed". +- **D-111** -- read `dc1` -> `vr1-dc0`, `dc2` -> `vr1-dc1`; the ULA indexing is unchanged in + substance. Additionally flags that its "Out of scope" line -- which defers the G5 site rename + to "its own D-number when executed" -- is now HISTORICAL: that ruling IS D-117 and it went the + other way (apex not renamed). A future session must not execute the rename it describes. +- **D-115** -- read `DC1` -> `vr1-dc0`, `DC2` -> `vr1-dc1`, but NOT the "VR0 DC1" table row + (a different region, correctly labelled). Records that the OFFICE is explicitly out of + D-117's scope and keeps its number, quoting the operator refinement. + +**Revert.** Delete the three `**ANNOTATION 2026-07-30 (DOCFIX-205) ...**` blocks in D-101, +D-111 and D-115. + +## 3. D-117's Status line corrected by measurement (GA-R1/C2) + +It read "FULLY EXECUTED BY D-119 (2026-07-14) -- the 'PARTIALLY EXECUTED' caveat below is +DISCHARGED". **That overstated what D-119 did, and the overstatement is the mechanism by which +the un-done half survived 17 days.** D-119 scopes its own discharge to the SELECTOR half: +"executes D-117's own amendment (region-qualify the shell SELECTORS) across the three surfaces +D-117 never touched" -- `lib-net.sh`, `lib-hosts.sh`, `opentofu/`. It never claimed, and never +performed, the "ADOPTED decision text -- ANNOTATE in place" row of D-117's treatment table. + +Status now reads "EXECUTED IN TWO HALVES", with an EXECUTION CORRECTION block recording the +measurement (zero of four annotated), the concrete consequence (a Stage-5 session filed a +retired question as a blocking ruling), and the standing lesson: **a ruling's Status line is a +CLAIM ABOUT EXECUTION, not evidence of it** -- where a decision rules several treatments across +surface kinds, a later decision discharging ONE does not discharge the rest, and no gate reads +prose. + +The `**Status:**` token still reads ADOPTED first, so `ledger-scan` (which keys on the LAST +`**Status:**` line per block) is unaffected -- verified, scan output unchanged. + +**Revert.** Restore the two-line Status line from git and delete the EXECUTION CORRECTION block. + +## 4. `runbooks/dc-dc-phase6-designate-cos-magnum.md` -- an executable defect fixed + +**The defect.** Step 3 built `os-public-hostname` as +`"keystone.omega.${DC}.vr1.cloud.neumatrix.local"` while `$DC` is the D-119 region-qualified +selector. Measured expansion: **`keystone.omega.vr1-dc0.vr1.cloud.neumatrix.local` -- the region +TWICE.** The runbook's own variable line read `DC=vr1-dc0|dc2`, mixing both naming systems in +one expression. This would have been baked into `os-public-hostname` and then into Vault-issued +SANs at Stage 7, in a runbook phase-4 Step 4 delegates to "verbatim". + +**Root cause, stated generally:** the D-119 SELECTOR token and the D-008 `` LABEL are +different strings, and the runbook interpolated one into the other. + +**Fix.** Step 0 now derives both labels from the selector and builds the zone once: + + DC_REGION="${DC%%-*}" # vr1-dc0 -> vr1 (D-008 ) + DC_DNS_LABEL="${DC#*-}" # vr1-dc0 -> dc0 (D-008 , 0-indexed per D-117) + DC_ZONE="omega.${DC_DNS_LABEL}.${DC_REGION}.cloud.neumatrix.local" + +All nine FQDN sites now use `$DC_ZONE` (Step 3 os-public-hostname, Step 6 zone + 2 recordsets, +Step 7 neutron dns-domain, Step 9's getent/dig/curl). The variable line is corrected to +`DC=vr1-dc0|vr1-dc1`. The D-106 blockquote at Step 1.3 is left VERBATIM (it quotes ratified +text) with a following note that the quoted labels are superseded and must not be pasted. + +**Verified by execution, not by reading:** the block was run for both sites and yields +`omega.dc0.vr1.cloud.neumatrix.local` and `omega.dc1.vr1.cloud.neumatrix.local`. + +**Revert.** `git checkout -- runbooks/dc-dc-phase6-designate-cos-magnum.md`. + +## 5. `scripts/octavia-pki.sh` A12 -- refusal becomes assertion + +A12 previously asserted only the REGION and then `nrefuse`d on the DC label, citing the +now-dead premise. It now derives the full expected zone from the site token -- `${SITE%%-*}` +region, `${SITE#*-}` DC label, never typed -- and asserts every DNS SAN falls inside it. +Armed, a wrong zone FAILS; a cert with NO DNS SAN at all now also FAILS (previously the empty +loop passed silently). Unarmed, it still reports INERT and passes, recording any mismatch as +F9's reissue obligation. + +`nrefuse` remains in use by seven other call sites; only A12's use was removed. + +**Revert.** `git checkout -- scripts/octavia-pki.sh`. + +## 6. `tests/octavia-pki/run-tests.sh` -- assertion REPLACED, not deleted + +Per the standing rule ("when a test asserts a literal finding string, remediating the finding +turns the harness red: REPLACE the assertion with the new invariant and say so, never delete it +to go green"): + +- **T20** re-pinned to the new message (`is not in this DC's expected zone '...'`), same rc=1. +- **T21 REPLACED** -- was "armed + right region REFUSES on the unruled DC label" (rc=3); is now + "armed + the D-117-correct zone PASSES" (rc=0). The comment records what it used to assert + and why the premise died. +- **T21b NEW** -- the capability the refusal never had: the OTHER DC's label in the RIGHT region + FAILS. This is the cross-DC mix-up F1 proved possible on the PKI paths; region-only checking + passed it. +- **T21c NEW** -- `vr1-dc1` derives its own zone, proving the expectation is per-DC and not a + dc0 constant wearing a variable. + +Harness **21/21 -> 23/23 PASS**. + +**Revert.** `git checkout -- tests/octavia-pki/run-tests.sh`. + +## 7. Status surfaces corrected in the same commit (repo-lint L10 / GA-R1 C1) + +- `docs/CURRENT-STATE.md` -- the two paragraphs claiming a BLOCKING ruling-shaped gap are kept + as history with a superseding block above them recording: the fork is closed by D-117; why it + resurfaced; that **"BLOCKING" was wrong as stated** (A12 measures INERT and PASSES on both DCs + live -- `os-public-hostname` is set in no deploy artifact); that A12 is now an assertion at + 23/23; and that the F9 reissue obligation STANDS. +- `docs/session-ledger.md:274` -- the 2026-07-30 bookend line carrying the same wrong premise + now carries a one-line WITHDRAWN correction pointing at CURRENT-STATE. + +**Revert.** `git checkout -- docs/CURRENT-STATE.md docs/session-ledger.md`. + +--- + +## Verification + + bash tests/octavia-pki/run-tests.sh -> 23/23 PASS + bash scripts/repo-lint.sh -> 0 fail, 1 warn (L1 legacy carve-out, 239 bytes, + UNCHANGED -- new content is ASCII) + bash scripts/run-tests-all.sh -> GAUNTLET: ALL GREEN (89 harnesses) + bash scripts/ledger-scan.sh -> unchanged: 3 decisions, 21 SEC, + D 138 / DOCFIX 205 / BUNDLEFIX 053 + +## What this batch deliberately does NOT do + +- **No cert reissue.** Both live certs still carry `dc0.vr0`. F9's obligation stands and is now + asserted rather than refused; reissue is a gated mint blocked by the D-137 fork-1 guard by + design, and is not this batch's scope (hard rule 1). +- **No `` label ruling.** `omega` is D-008's `` label carried unchanged by D-106; + nothing here reopens it. +- **No change to D-008's shape.** Collapsing `.` into D-119's single token was + considered and rejected on the reasoning recorded in the D-106 annotation; it would amend a + ratified shape no ruling has touched. diff --git a/docs/design-decisions.md b/docs/design-decisions.md index 221ab0d..a115a4a 100644 --- a/docs/design-decisions.md +++ b/docs/design-decisions.md @@ -2066,6 +2066,25 @@ **Status:** ADOPTED 2026-07-09 (operator ruling), AMENDED same day: (a) metal-admin gains a ULA leg (reverses this decision's own stated lean, see the family matrix below); (b) D-102 (IPv6 tenant addressing and MTU sub-policy) is MERGED into this decision per operator ruling -- D-102's entry is retained for numbering/history only, see its own Status line. Activates the developed family-follows-reachability IPv6 plan for VR1. NetBox (vcloud-local) is the IPAM authority for all literals. +**ANNOTATION 2026-07-30 (DOCFIX-205) -- DC LABELS IN THE ORIGINAL BLOCK ARE PRE-D-117; THIS +ENTRY CARRIES BOTH NAMESPACES AND THEY ARE NOT INTERCHANGEABLE.** Recorded per D-117's ruled +treatment ("ADOPTED decision text: ANNOTATE in place, do NOT rewrite"). D-117 (2026-07-13) +retired the repo's `dc1`/`dc2` labels in favour of `dc0`/`dc1`; D-119 (2026-07-14) then +region-qualified them to `vr1-dc0`/`vr1-dc1`. Read this entry by DATE: + + Original decision + same-day amendments (2026-07-09), PRE-D-117: + "DC1" = VR1's FIRST DC = `vr1-dc0` "DC2" = VR1's SECOND DC = `vr1-dc1` + "DC0" in "DC1 INHERITS the DC0 six-plane v4 layout" = VR0's DC0 = `vr0-dc0` + Amendments dated 2026-07-14 or later (e.g. the 2026-07-27 dual-stack and R9 blocks): + `vr1-dc0` / `vr1-dc1` used with their D-119 meanings, already correct. + +**This is D-117 TRAP 2 in the one entry where it bites hardest:** the token `dc1` appears in +BOTH halves of this entry meaning DIFFERENT datacenters -- VR1's first DC in the 2026-07-09 +text, VR1's SECOND DC in the 2026-07-27 amendments. Never carry a bare `dcN` out of this entry +without checking the date of the block it came from. The v6 literals are unaffected either way: +per D-119 the ULA hextet tracks the GUA site nibble (`f02` -> `:2NN`, `f03` -> `:3NN`), NOT the +DC index, and must not be "fixed" to match it. + **Context:** v1 / DC0 is IPv4-only on 10.12.0.0/16 (six planes in `scripts/lib-net.sh`). The developed IPv6 plan (in-project, not yet committed) classifies planes by reachability: GUA for external clients, ULA for internal-only, IPv4 where forced. DC-DC is the phase that activates it. **GOVERNING RATIONALE -- recorded 2026-07-27 from the operator, verbatim, because it @@ -2558,6 +2577,43 @@ **Status:** ADOPTED 2026-07-09 (operator ruling). SUPERSEDES D-019 (Designate deferral); REACTIVATES D-008 (DNS architecture). +**ANNOTATION 2026-07-30 (DOCFIX-205) -- THE ZONE LABELS BELOW ARE SUPERSEDED BY D-117.** +Recorded per D-117's own treatment table ("ADOPTED decision text: ANNOTATE in place, do NOT +rewrite -- ratified prose is a historical record"), so the Decision block is left exactly as +ratified and this block carries the correction. + +D-117 (ADOPTED 2026-07-13, four days after this entry) names this supersession in its own +Status line -- "Supersedes ... and the D-106 `dc1`/`dc2` zone labels" -- and its amendment +rules the replacement: "The repo's `dc1`/`dc2` labels are retired in favour of `dc0`/`dc1`." +READ the labels below as: + + `dc1.vr1` -> `dc0.vr1` (substrate `vr1-dc0`, NetBox site `vr1-dc0`, GUA f02::/48) + `dc2.vr1` -> `dc1.vr1` (substrate `vr1-dc1`, NetBox site `vr1-dc1`, GUA f03::/48) + +The SHAPE is unchanged: D-008's `....cloud.neumatrix.local` still +governs, so the VR1 FQDNs are `.omega.dc0.vr1.cloud.neumatrix.local` and +`.omega.dc1.vr1.cloud.neumatrix.local`. + +**Do NOT collapse `.` into D-119's single `vr1-dc0` selector token.** D-119's +standing rule ("never write a bare `dcN` for a VR1 datacenter again ... region-qualify it") +states its own rationale as "a reader who does not know which cloud the sentence is about" -- +a hazard that does not exist here, because in this FQDN the very next label IS the region. +D-119 also says it COMPLETES D-117 rather than reversing it, and D-117's ruled replacement +labels are themselves bare `dc0`/`dc1`; a rule forbidding those in every context would +invalidate the ruling D-119 says it completes. Collapsing the two labels would additionally +amend D-008's ratified shape, which no ruling has done. + +**The selector token and the D-008 `` label are DIFFERENT STRINGS.** Do not interpolate a +`$DC` selector value into an FQDN -- `vr1-dc0` in the `` position yields +`omega.vr1-dc0.vr1.cloud...`, which carries the region TWICE. Derive both halves from the site +token instead: `${SITE%%-*}` -> region (`vr1`), `${SITE#*-}` -> DC label (`dc0`). Verified for +`vr1-dc0`, `vr1-dc1` and `vr0-dc0`. + +**Why this annotation exists.** It was owed from 2026-07-13 and never written. On 2026-07-30 a +Stage-5 session read this un-annotated text as live, re-derived the already-retired +`dc1`-vs-`dc2` question from it, and filed it as a blocking ruling -- see the D-117 Status +correction of the same date for the mechanism that hid it. + **Decision:** - Designate is deployed in-bundle in each DC, backend `designate-bind` (bind9, the Charmed-OpenStack-native backend, lowest delta). - Naming per D-008 instantiated with the VR1 labels: `.omega.dc1.vr1.cloud.neumatrix.local` and `...dc2.vr1...`. Per-DC INDEPENDENT zones (independent Keystones), served with A and AAAA records (AAAA for the v6-enabled planes per D-101). @@ -2866,6 +2922,21 @@ **Status:** ADOPTED 2026-07-11 (operator deferred to Code stream's recommendation; ratifies `docs/dc-dc-netbox-buildout-scope.md` sub-decision #1). +**ANNOTATION 2026-07-30 (DOCFIX-205) -- DC LABELS BELOW ARE PRE-D-117.** Recorded per D-117's +ruled treatment ("ADOPTED decision text: ANNOTATE in place, do NOT rewrite"). D-117 +(2026-07-13) retired the repo's `dc1`/`dc2` labels in favour of `dc0`/`dc1`; D-119 (2026-07-14) +region-qualified them. Read `dc1` -> `vr1-dc0` and `dc2` -> `vr1-dc1` throughout this entry -- +including the ULA indexing line, which is UNCHANGED IN SUBSTANCE: the hextet tracks the GUA +site nibble (`f02::/48` -> `...:02xx`, `f03::/48` -> `...:03xx`), NOT the DC index. D-119 says +so explicitly and warns against "fixing" it to match the DC number, which would break the +already-imported sandbox prefixes. + +**The "Out of scope" line below is now HISTORICAL and its recommendation was REJECTED.** It +says the G5 DC-site rename (`vr1-dc0`/`vr1-dc1` -> `vr1-dc1`/`vr1-dc2`) is "a distinct ruling, +recorded under its own D-number when executed." That ruling was taken -- it is D-117 -- and it +went the OTHER WAY: the apex is NOT renamed, the REPO adopted the apex's 0-indexed +`vr1-dc0`/`vr1-dc1`. No such rename is owed; a future session must not execute it. + **Decision:** - `netbox/dc-dc-prefixes-import.py`'s per-plane v6 subcarve is aligned to the DEPLOYED VR0-DC0 / Willamette net-byte (NN) mnemonic, replacing the original contiguous-plane-index proposal (which was explicitly un-ratified). Each plane gets a `/60` container + `/64` active, mirroring the live template: - provider-public (GUA, out of `DC_GUA_PREFIX`): `/60` + `/64` active at `:10`, API-VIP `/64` at `:11`. @@ -3350,6 +3421,20 @@ IPAM carve matters MORE than the deployment already standing on it -- "we can always change the current IP addressing on the deployment; getting the IPAM carve proper and correct is more important than going back and correcting deployment work." Nothing here is blocked; Office1 runs. + +**ANNOTATION 2026-07-30 (DOCFIX-205) -- DC LABELS BELOW ARE PRE-D-117, BUT THE OFFICE IS NOT.** +Recorded per D-117's ruled treatment ("ADOPTED decision text: ANNOTATE in place, do NOT +rewrite"). This entry was ruled 2026-07-13, the SAME DAY as D-117 and before its rename landed. +Read the DC labels as `DC1` -> `vr1-dc0` and `DC2` -> `vr1-dc1` throughout (so "DC2 moves INSIDE +the Cloud /16: 10.12.64.0/19" is `vr1-dc1`'s supernet, which is what was built), and note that +in the `X03::/48` table row "VR0 DC1" means VR0's SECOND DC -- a different region, correctly +labelled, and NOT subject to this remap. + +**The OFFICE is explicitly OUT of D-117's scope and keeps its number.** D-117's operator +refinement, verbatim: "go ahead and rename the DC numbers. The office number is fine." So +Office1 stays Office1 -- NetBox site `vr1-off1`, and `voffice1` / `office1-local` / +`office1-netbox` / `~/vr1-office1-creds` all stand. Nothing office-side in this entry is +renamed, and the accepted asymmetry with VR0's `vr0-off0` is documented, not a defect. This is about ratifying or replacing what it runs on, BEFORE NetBox/GitBucket land on it. ### What the IPAM apex actually encodes (MEASURED 2026-07-13 against netbox.baldurkeep.com) @@ -3557,8 +3642,33 @@ ## D-117: VR1 site naming -- the apex says DC0/DC1, the repo says DC1/DC2 (G5) -**Status:** **ADOPTED 2026-07-13 (operator ruling: Option B, DC-only). FULLY EXECUTED BY D-119 -(2026-07-14) -- the "PARTIALLY EXECUTED" caveat below is DISCHARGED; read D-119 for the end state.** +**Status:** **ADOPTED 2026-07-13 (operator ruling: Option B, DC-only). EXECUTED IN TWO HALVES: +the SELECTOR half by D-119 (2026-07-14) -- the "PARTIALLY EXECUTED" caveat below is DISCHARGED +FOR THAT HALF; read D-119 for the end state -- and the DECISION-TEXT ANNOTATION half not until +DOCFIX-205 (2026-07-30). See the execution correction immediately below.** + +**EXECUTION CORRECTION 2026-07-30 (DOCFIX-205; GA-R1/C2 -- measurement corrects the document).** +This Status line previously read "FULLY EXECUTED BY D-119 (2026-07-14) -- the 'PARTIALLY +EXECUTED' caveat below is DISCHARGED". **That overstated what D-119 did, and the overstatement +is the mechanism by which the un-done half survived for 17 days.** D-119 scopes its own +discharge precisely: it "executes D-117's own amendment (region-qualify the shell SELECTORS) +across the three surfaces D-117 never touched" -- `lib-net.sh`, `lib-hosts.sh`, `opentofu/`. +It never claimed, and never performed, this decision's OTHER ruled treatment: the +"ADOPTED decision text (D-101, D-106, D-111, D-115) -- ANNOTATE in place" row of the treatment +table below. + +MEASURED 2026-07-30: **zero of those four entries carried any D-117 annotation.** Because this +Status line said "fully executed", a reader checking whether the annotation was owed was told +it was already done and stopped looking. The consequence was concrete -- a Stage-5 session read +un-annotated D-106 as live, re-derived the retired `dc1`-vs-`dc2` question, and filed it as a +blocking ruling on a premise this decision had retired on 2026-07-13. All four entries are +annotated as of DOCFIX-205; this correction records why they were not. + +**Standing lesson (the reusable half): a ruling's Status line is a CLAIM ABOUT EXECUTION, not +evidence of it.** Where a decision rules several DIFFERENT treatments across surface kinds, a +later decision discharging ONE of them does not discharge the rest -- and no gate reads prose, +so nothing in this repo can catch a Status line that says otherwise. Check the artifact, not +the decision. The REPO moves to the apex's 0-indexed convention **for the DATACENTERS**. NetBox is the IPAM apex and is NOT bent to fit the repo. Supersedes the `docs/dc-dc-netbox-buildout-scope.md` G5 recommendation (which proposed the opposite, Option A) and the D-106 `dc1`/`dc2` zone labels. diff --git a/docs/session-ledger.md b/docs/session-ledger.md index ce68ab3..b2e4a4f 100644 --- a/docs/session-ledger.md +++ b/docs/session-ledger.md @@ -272,6 +272,7 @@ - **`scripts/octavia-pki.sh verify` NEW** (harness 21/21): asserts the SAN set nothing asserted before (F8's SAN-less cert), and **A12 ARMS ITSELF** from `os-public-hostname` so F9 cannot be missed. - **Gate integrity:** decorative HA, machines-overlay no-op, cloud-assert arity, G17 node check, gauntlet locale. P4 DC-aware (DC refs 1 -> 45); 3.7 closed; lib-net dc1 arm. - **NEW ruling-shaped, now BLOCKING:** D-008 + D-106:2563 do not say whether substrate `vr1-dc1` is `dc1` by TOKEN or `dc2` by POSITION -- item 3.1's ambiguity inside a ruling, deciding cert identity. A12 REFUSES rather than picking. + **^ WITHDRAWN 2026-07-30 (DOCFIX-205): NOT a ruling gap.** D-117 ruled it 2026-07-13 (`dc1`/`dc2` retired for `dc0`/`dc1`) and says so in its own Status line; D-106 read as open only because D-117's annotation half was never executed (zero of four) while its Status line claimed "FULLY EXECUTED". Also not blocking -- A12 measures INERT and passes. Now an assertion on the derived zone; status in CURRENT-STATE.md. - **Headend reconcile found a gate RED ON THE ONLY HOST THAT DEPLOYS** (`opentofu-validate` fmt walking gitignored tfvars). Fixed + scoped; **both hosts now ALL GREEN (89)**, repo-lint 0 fail. - **Three wrong records found, none catchable by any gate:** D-124 told a reader to source a provider MAC from a file holding only boot MACs (would have bridged `br-ex` onto the PXE NIC); the skill cites D-107 for a tailnet path it does not rule; `office1-tailscale` is labelled a subnet router and advertises none. - **A "backup set" asserted on three surfaces did not exist.** Built for the PKI (1.0-GEN.e) and the inner tfstates (phase-2 step 13), declared, restores proven. Forward requirement recorded: the pinned secrets-storage solution MUST absorb both. diff --git a/runbooks/dc-dc-phase6-designate-cos-magnum.md b/runbooks/dc-dc-phase6-designate-cos-magnum.md index e09b0fc..857bc81 100644 --- a/runbooks/dc-dc-phase6-designate-cos-magnum.md +++ b/runbooks/dc-dc-phase6-designate-cos-magnum.md @@ -124,11 +124,22 @@ ```bash # Set once per DC-pass through this runbook -- MEASURE from Stage 4's as-built # record, never guess a naming scheme: -# DC=vr1-dc0|dc2 +# DC=vr1-dc0|vr1-dc1 # the D-119 region-qualified selector. Bare +# # dcN is REJECTED loudly by lib-net/lib-hosts. # DC_CONTROLLER= # DC_MODEL= +# DERIVE the two D-008 FQDN labels from the selector -- NEVER interpolate $DC +# itself into a name (DOCFIX-205). The D-119 SELECTOR token and the D-008 +# LABEL are different strings: "omega.${DC}.vr1..." expands to +# "omega.vr1-dc0.vr1..." and carries the region TWICE. Same shell parameter +# expansions octavia-pki.sh uses; verified for vr1-dc0, vr1-dc1 and vr0-dc0. +DC_REGION="${DC%%-*}" # vr1-dc0 -> vr1 (D-008 ) +DC_DNS_LABEL="${DC#*-}" # vr1-dc0 -> dc0 (D-008 , 0-indexed per D-117) +DC_ZONE="omega.${DC_DNS_LABEL}.${DC_REGION}.cloud.neumatrix.local" +echo "$DC_ZONE" # EXPECT omega.dc0.vr1.cloud.neumatrix.local (vr1-dc0) + juju controllers # confirm DC_CONTROLLER is listed and reachable juju switch "${DC_CONTROLLER}:${DC_MODEL}" juju status -m "${DC_MODEL}" --format=short | grep -vE 'active|idle' || echo "all active/idle" @@ -212,6 +223,15 @@ > Per-DC INDEPENDENT zones (independent Keystones), served with A and AAAA > records (AAAA for the v6-enabled planes per D-101). +**THE QUOTED LABELS ABOVE ARE SUPERSEDED -- do not paste them (DOCFIX-205).** The +quote is D-106's ratified 2026-07-09 text and is reproduced unchanged, but D-117 +(ADOPTED 2026-07-13) retired the repo's `dc1`/`dc2` labels in favour of +`dc0`/`dc1`, naming this supersession in its own Status line. The VR1 zones are +therefore `omega.dc0.vr1.cloud.neumatrix.local` (substrate `vr1-dc0`) and +`omega.dc1.vr1.cloud.neumatrix.local` (substrate `vr1-dc1`). Use the derived +`$DC_ZONE` set in Step 1 rather than typing either. D-106 now carries a D-117 +annotation recording this. + ### 1.3 -- The reversal is bigger than "add one application" -- flag this honestly D-106's bootstrap order includes `os-public-hostname` per API charm as its @@ -321,7 +341,7 @@ ```bash # Populate /etc/hosts on each unit with THIS DC's own measured # pairs, one line per API charm, using D-106's naming: -# .omega.${DC}.vr1.cloud.neumatrix.local +# .${DC_ZONE} -- derived in Step 1; NEVER "omega.${DC}.vr1..." # Do not template a value you have not just measured. ``` **GATE:** every host/LXD container in this DC resolves every other API @@ -334,7 +354,7 @@ **RUN -- jumphost, per charm (repeat for every clustered API charm listed in Step 1.3)** ```bash -juju config -m "${DC_MODEL}" keystone os-public-hostname="keystone.omega.${DC}.vr1.cloud.neumatrix.local" +juju config -m "${DC_MODEL}" keystone os-public-hostname="keystone.${DC_ZONE}" # ... repeat per charm: glance, neutron-api, nova-cloud-controller, placement, # cinder, octavia, barbican, magnum, openstack-dashboard, ceph-radosgw ``` @@ -490,7 +510,8 @@ Per-DC INDEPENDENT zone (D-106). The zone name itself is the one place this runbook cites a literal beyond a live measurement, and it is cited from D-106's -own ratified naming text, not invented: `omega.${DC}.vr1.cloud.neumatrix.local`. +own ratified naming text as corrected by D-117, not invented: `$DC_ZONE` (derived +in Step 1 = `omega.dc0.vr1.cloud.neumatrix.local` for `vr1-dc0`). The A/AAAA record VALUES are NOT cited from any decision text -- they are this DC's real, live, measured VIP addresses. Populate them from what Step 3/4 just proved live, never from a planning number. @@ -498,19 +519,19 @@ **RUN -- jumphost (designate-scoped or admin, per this DC's own admin-openrc)** ```bash openstack zone create --email hostmaster@neumatrix.local \ - "omega.${DC}.vr1.cloud.neumatrix.local." + "${DC_ZONE}." # per API charm, MEASURE the live provider VIP (A) and, if this DC's GUA plane # is up (D-101), the live provider-public GUA address (AAAA) -- do not invent # either: KEYSTONE_VIP_V4=$(openstack ... ) # MEASURE: this DC's live keystone provider VIP -openstack recordset create "omega.${DC}.vr1.cloud.neumatrix.local." \ +openstack recordset create "${DC_ZONE}." \ keystone --type A --records "$KEYSTONE_VIP_V4" # AAAA only if D-101's v6-enabled planes are confirmed up for this DC -- gate # on that confirmation, do not assume: KEYSTONE_VIP_V6=$(openstack ... ) # MEASURE: this DC's live GUA provider address -openstack recordset create "omega.${DC}.vr1.cloud.neumatrix.local." \ +openstack recordset create "${DC_ZONE}." \ keystone --type AAAA --records "$KEYSTONE_VIP_V6" # repeat per API charm ``` @@ -527,7 +548,7 @@ ```bash DESIGNATE_VIP=$( ... ) # MEASURE: this DC's live designate-bind / designate API VIP juju config -m "${DC_MODEL}" neutron-api \ - dns-domain="omega.${DC}.vr1.cloud.neumatrix.local." \ + dns-domain="${DC_ZONE}." \ dns-servers="${DESIGNATE_VIP}" ``` **GATE:** `neutron-api` returns to `active/idle`; `openstack network show @@ -562,9 +583,9 @@ ```bash source ~/capi-mgmt-net.env # this DC's own env file, per phase-06 Step 6.2 -- confirm it is THIS DC's, not the other DC's stale file ssh ... ubuntu@"$MGMT_FIP" bash -s <<'REOF' -getent hosts keystone.omega.DC.vr1.cloud.neumatrix.local # substitute the real DC label -dig +short AAAA keystone.omega.DC.vr1.cloud.neumatrix.local # if AAAA populated -curl -sk https://keystone.omega.DC.vr1.cloud.neumatrix.local:5000/v3 -o /dev/null -w '%{http_code}\n' +getent hosts keystone.${DC_ZONE} # substitute the real DC label +dig +short AAAA keystone.${DC_ZONE} # if AAAA populated +curl -sk https://keystone.${DC_ZONE}:5000/v3 -o /dev/null -w '%{http_code}\n' REOF ``` **GATE:** the FQDN resolves (A, and AAAA where populated); the HTTPS call diff --git a/scripts/octavia-pki.sh b/scripts/octavia-pki.sh index 9c93767..894cf9d 100755 --- a/scripts/octavia-pki.sh +++ b/scripts/octavia-pki.sh @@ -295,15 +295,29 @@ # merged deploy input (D-106's Stage-7 work), the assertion goes live. A scheduled fix depends # on a future session reading a note; this depends on nothing. # -# WHAT IT CAN AND CANNOT ASSERT, and the difference is a real gap in a RULED decision: -# D-008 fixes the shape `....cloud.neumatrix.local`, and D-106 -# instantiates VR1 as `...omega.dc1.vr1...` / `...dc2.vr1...` -- while the substrate's DCs are -# `vr1-dc0` and `vr1-dc1`. So `vr1-dc1` maps to `dc1.vr1` by TOKEN or `dc2.vr1` by POSITION, -# which is the DC1/DC2 ambiguity item 3.1 retired elsewhere, here deciding certificate identity. -# The REGION is unambiguous and is asserted. The DC label REFUSES pending a ruling rather than -# blessing a name that cannot be validated. +# WHAT IT ASSERTS: the FULL expected zone, not just the region. DOCFIX-205 (2026-07-30) +# replaced this check's former REFUSAL with a real assertion. It used to refuse on the DC +# label, on the grounds that D-008's shape plus D-106's `dc1.vr1`/`dc2.vr1` instantiation left +# open whether substrate `vr1-dc1` is `dc1` by token or `dc2` by position. THAT PREMISE WAS +# ALREADY DEAD: D-117 (ADOPTED 2026-07-13) names the supersession in its own Status line +# ("Supersedes ... the D-106 `dc1`/`dc2` zone labels") and rules the replacement -- "The repo's +# `dc1`/`dc2` labels are retired in favour of `dc0`/`dc1`". D-106 read as un-annotated because +# D-117's annotation half was never executed; both are fixed as of DOCFIX-205. +# +# So the expected zone is fully derivable from the site token and is NEVER typed: +# REGION = ${SITE%%-*} vr1-dc0 -> vr1 (D-008 ) +# DC_DNS = ${SITE#*-} vr1-dc0 -> dc0 (D-008 , 0-indexed per D-117) +# zone = omega...cloud.neumatrix.local +# `omega` is D-008's label, carried unchanged by D-106's VR1 instantiation. +# +# Deliberately NOT collapsed to D-119's single `vr1-dc0` token: D-119's bare-dcN rule targets a +# token read ALONE ("a reader who does not know which cloud the sentence is about") and here the +# next label IS the region; D-119 completes D-117 rather than reversing it, and D-117's own +# replacement labels are bare `dc0`/`dc1`. Collapsing would also amend D-008's ratified shape. if [ -f "$CON_CERT" ]; then - REGION="${SITE%%-*}" # vr1-dc0 -> vr1 (derived, never typed) + REGION="${SITE%%-*}" # vr1-dc0 -> vr1 (derived, never typed) + DC_DNS="${SITE#*-}" # vr1-dc0 -> dc0 (derived, never typed) + EXP_ZONE="omega.${DC_DNS}.${REGION}.cloud.neumatrix.local" # Is the posture armed? Look for a real option KEY in the merged input, not prose. ARMED=0 for f in "$REPO_ROOT/bundle.yaml" "$REPO_ROOT/overlays/${SITE}-vips.yaml" \ @@ -314,21 +328,26 @@ DNSN="$(printf '%s' "${SAN_RAW:-}" | grep -oE 'DNS:[^,[:space:]]+' | sed 's/^DNS://')" if [ "$ARMED" -eq 0 ]; then ok "A12 DNS SANs are INERT -- os-public-hostname is set in no deploy artifact (B5 IP-only), so nothing resolves them; this assertion ARMS ITSELF when D-106 sets it" - case "$DNSN" in - *".${REGION}."*) : ;; - *) ok "A12 (recorded, not failed) the DNS SANs do not carry this DC's region '$REGION' -- harmless while inert, and F9's reissue obligation" ;; - esac + BAD=0 + for n in $DNSN; do + case "$n" in *".${EXP_ZONE}") : ;; *) BAD=1 ;; esac + done + if [ -n "$DNSN" ] && [ "$BAD" -ne 0 ]; then + ok "A12 (recorded, not failed) the DNS SANs are not in this DC's expected zone '$EXP_ZONE' -- harmless while inert, and F9's reissue obligation" + fi else # Armed: the names are now load-bearing. BAD=0 + if [ -z "$DNSN" ]; then + nfail "A12 os-public-hostname IS SET, so DNS SANs are load-bearing -- the controller cert carries NO DNS SAN at all; it must be reissued with names in '$EXP_ZONE'"; BAD=1 + fi for n in $DNSN; do case "$n" in - *".${REGION}."*) : ;; - *) nfail "A12 os-public-hostname IS SET, so DNS SANs are load-bearing -- '$n' does not carry this DC's region '$REGION' (F9); the certificate must be reissued"; BAD=1 ;; + *".${EXP_ZONE}") : ;; + *) nfail "A12 os-public-hostname IS SET, so DNS SANs are load-bearing -- '$n' is not in this DC's expected zone '$EXP_ZONE' (D-008 shape, D-117 labels; F9); the certificate must be reissued"; BAD=1 ;; esac done - [ "$BAD" -eq 0 ] && ok "A12 DNS SANs carry this DC's region '$REGION'" - nrefuse "A12 the per-DC DC-LABEL cannot be validated: D-008's shape plus D-106's VR1 instantiation ('dc1.vr1'/'dc2.vr1') do not say whether substrate '$SITE' is 'dc0'/'dc1' by token or 'dc1'/'dc2' by position. That mapping needs a ruling before an FQDN cert can be blessed." + [ "$BAD" -eq 0 ] && ok "A12 DNS SANs are all in this DC's expected zone '$EXP_ZONE'" fi fi diff --git a/tests/octavia-pki/run-tests.sh b/tests/octavia-pki/run-tests.sh index 0cfe384..381a0ca 100755 --- a/tests/octavia-pki/run-tests.sh +++ b/tests/octavia-pki/run-tests.sh @@ -253,21 +253,42 @@ printf ' os-public-hostname: keystone.omega.dc0.vr0.cloud.neumatrix.local\n' \ >> "$E/repo/overlays/vr1-dc0-vips.yaml" run "$E" vr1-dc0 -[ "$RC" = 1 ] && printf '%s' "$OUT" | grep -q "does not carry this DC's region 'vr1'" \ +[ "$RC" = 1 ] && printf '%s' "$OUT" | grep -q "is not in this DC's expected zone 'omega.dc0.vr1.cloud.neumatrix.local'" \ && ok "T20 ARMED + a wrong-region DNS SAN FAILS (F9, self-arming)" \ || { no "T20 armed A12 must fail a wrong-region SAN (rc=$RC)"; printf '%s\n' "$OUT" | sed 's/^/ /'; } -# T21 -- ARMED with the RIGHT region still REFUSES, because the per-DC label is genuinely -# unruled: D-008's shape plus D-106's `dc1.vr1`/`dc2.vr1` instantiation do not say whether -# substrate `vr1-dc1` is `dc1` by token or `dc2` by position. Refusing to bless a name it -# cannot validate is the correct outcome -- "could not look" is never "nothing there". +# T21 -- ARMED with the CORRECT zone now PASSES. ASSERTION REPLACED, NOT DELETED (DOCFIX-205): +# this case previously asserted a REFUSAL (rc=3, "DC-LABEL cannot be validated") on the grounds +# that D-008 + D-106's `dc1.vr1`/`dc2.vr1` left the per-DC label unruled. That premise was +# already dead -- D-117 (2026-07-13) retired `dc1`/`dc2` in favour of `dc0`/`dc1` and says so in +# its own Status line. The label is derivable, so the check asserts it instead of refusing. E=$(mkfix dnsregionok vr1-dc0 "VR1 DC0" full "omega.dc0.vr1.cloud.neumatrix.local") printf ' os-public-hostname: keystone.omega.dc0.vr1.cloud.neumatrix.local\n' \ >> "$E/repo/overlays/vr1-dc0-vips.yaml" run "$E" vr1-dc0 -[ "$RC" = 3 ] && printf '%s' "$OUT" | grep -q "DC-LABEL cannot be validated" \ - && ok "T21 ARMED + right region REFUSES on the unruled DC label rather than blessing it" \ - || { no "T21 armed A12 must refuse the unruled label (rc=$RC)"; printf '%s\n' "$OUT" | sed 's/^/ /'; } +[ "$RC" = 0 ] && printf '%s' "$OUT" | grep -q "A12 DNS SANs are all in this DC's expected zone" \ + && ok "T21 ARMED + the D-117-correct zone PASSES (assertion replaces the former refusal)" \ + || { no "T21 armed A12 must pass the correct zone (rc=$RC)"; printf '%s\n' "$OUT" | sed 's/^/ /'; } + +# T21b -- the capability the refusal never had: a WRONG DC LABEL in the RIGHT region. This is +# the exact cross-DC mix-up F1 proved possible on the PKI paths (dc1's material under dc0's +# name). Region-only checking passed it; the derived-zone assertion catches it. +E=$(mkfix dnswrongdc vr1-dc0 "VR1 DC0" full "omega.dc1.vr1.cloud.neumatrix.local") +printf ' os-public-hostname: keystone.omega.dc1.vr1.cloud.neumatrix.local\n' \ + >> "$E/repo/overlays/vr1-dc0-vips.yaml" +run "$E" vr1-dc0 +[ "$RC" = 1 ] && printf '%s' "$OUT" | grep -q "is not in this DC's expected zone 'omega.dc0.vr1.cloud.neumatrix.local'" \ + && ok "T21b ARMED + the OTHER DC's label in the right region FAILS (cross-DC mix-up)" \ + || { no "T21b armed A12 must fail a wrong DC label (rc=$RC)"; printf '%s\n' "$OUT" | sed 's/^/ /'; } + +# T21c -- vr1-dc1 derives its OWN zone, so the check is not a dc0 constant wearing a variable. +E=$(mkfix dnsdc1ok vr1-dc1 "VR1 DC1" full "omega.dc1.vr1.cloud.neumatrix.local") +printf ' os-public-hostname: keystone.omega.dc1.vr1.cloud.neumatrix.local\n' \ + >> "$E/repo/overlays/vr1-dc1-vips.yaml" +run "$E" vr1-dc1 +[ "$RC" = 0 ] && printf '%s' "$OUT" | grep -q "A12 DNS SANs are all in this DC's expected zone 'omega.dc1.vr1.cloud.neumatrix.local'" \ + && ok "T21c vr1-dc1 derives dc1.vr1, proving the zone is per-DC and not hardcoded" \ + || { no "T21c vr1-dc1 must derive its own zone (rc=$RC)"; printf '%s\n' "$OUT" | sed 's/^/ /'; } # T14 -- args. A bare `dcN` has been a live defect class; it must be REJECTED, not guessed. RC=0; bash "$CHECK" verify dc0 >/dev/null 2>&1 || RC=$?