| 2026-07-30 |

A12: the DNS SAN check ARMS ITSELF, so F9 cannot be missed
...
Operator direction: make the DNS SANs part of the process so it is not a step that gets missed
in future.
The risk in F9 is not the defect, it is that a future session forgets. So A12 arms from the
change that makes the SANs load-bearing -- os-public-hostname appearing as a real option key in
the merged deploy input -- rather than from a note somebody has to read. Unarmed, it states the
names are inert and why; armed, it asserts them.
WHAT IT CAN ASSERT, AND A GAP IN A RULED DECISION THAT IT CANNOT. D-008 fixes the shape
<service>.<cloud>.<dc>.<region>.cloud.neumatrix.local and D-106:2563 instantiates VR1 as
"omega.dc1.vr1" / "dc2.vr1" -- while the substrate's DCs are vr1-dc0 and vr1-dc1. So vr1-dc1 is
"dc1" by token or "dc2" by position: the DC1/DC2 ambiguity item 3.1 retired elsewhere, surviving
inside a ruling, where it decides 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. Both live certs currently say dc0.vr0 -- the VR0 region, wrong for a VR1 DC under
either reading.
A PRECEDENCE BUG THE HARNESS CAUGHT. Because the armed branch always refuses on the label, a
definite wrong-region SAN was being reported as "could not evaluate" -- REFUSE was checked before
FAIL and masked a confirmed defect. A known defect outranks an unevaluated item, so the verdict
now reports FAIL first and still names the refusal, which is never lost.
Harness 21/21 (was 18). T19 proves the unarmed live posture still PASSES -- without it, arming
A12 would have broken every current verify, the same trap T17 guards for the deleted
intermediates. T20 is F9 armed. T21 proves the right region still refuses on the unruled label.
repo-lint 0 fail.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

tfstate backup path built; E2/E3 closed live; a gate disagreement found and fixed
...
BACKUP PROVEN BY RESTORE, not by existence. Both PKI archives were extracted and compared
byte-for-byte against the live tree: 12/12 sha256 MATCH across both DCs, covering both encrypted
CA keys, both passphrases, both CA serials and both controller bundles. Archives are 600 inside
700 folders and differ between DCs, so per-DC independence survives into the backup.
E2/E3 CLOSED LIVE. Operator ran the chmod and the intermediate removal; octavia-pki.sh verify
now reads PASS 26/0 on BOTH DCs, workspaces 12 -> 10 files, and P5 on the headend fell 18 -> 8.
A GATE DISAGREEMENT, recorded as the pattern rather than the incident. verify read 26/0 while
creds-matrix E2 still reported the CA serial mode 664 on both DCs. The chmod list predated the
serial being declared, and verify's mode assertions covered six private files and three certs --
the serial was in neither. Two gates that can both see a file must not disagree about it. Fixed
in three places: verify now mode-checks the serial (integrity, not secrecy -- rewriting it forces
the next issuance to reuse a serial), the generator's chmod includes it, and T18 pins it. The
harness then caught its own fixture creating the serial at the inherited umask; baseline went red
until the fixture matched the corrected generator. 18/18.
TFSTATE BACKUP as dc-dc-phase2 step 13, 2 rows, notes key n-tfstate-backup. Register 99 rows;
schema, render-drift, mint-ref and notes checks clean.
Three deliberate differences from the PKI backup: tfstate is DYNAMIC so the serial is recorded
both sides and the step must be re-run after every apply (restoring a stale state is actively
dangerous -- tofu then believes everything created since does not exist); the pull block proves
RESTORE by decompressing to check the archive parses as JSON and reports a serial, because a
truncated gzip passes a size check; and mint-stage is stage3, which is REACHED, so P5 correctly
reports these EXPECTED-BUT-ABSENT until the step runs rather than deferring them.
Classification recorded honestly: the outer state is credential-bearing (DOCFIX-175, MAAS API key
in plaintext); the inner states show no credential-shaped key names, consistent with the inner
root using only libvirt over qemu+ssh. Strong evidence, NOT proof -- a name-based absence cannot
exclude material inside a value -- so they are registered and stored as if sensitive. Uncertainty
resolves toward more auditing, and an unaudited backup directory beside audited ones is how the
SEC-022 shadow stores happened.
Two of my own defects caught by the gates: repo-lint L9 rejected a hardcoded clone name in the
new step (the repo has been renamed once, D-110) -- now $REPO; and two mint-refs had drifted when
a later edit added lines above their anchors, which S4 cannot catch because it only checks
line <= EOF. Both re-anchored.
Also corrected: phase-01:605 said the overlay must be in the backup set. It is derivable from the
archived workspace by 1.0-GEN.d, so the line implied a gap that does not exist.
Known, not fixed: both live inner states are 664, group-writable, and they are the authority tofu
trusts. Tightening needs its own gated change plus proof the provider preserves the mode.
creds-matrix 65/65, octavia-pki 18/18, repo-lint 0 fail / 621 files.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

E3 resolved: declare the two artifacts that persist, delete the two intermediates at source
...
Operator-approved disposition after review. The four undeclared per-DC generator outputs were
separated by whether anything will read them again.
DECLARED. The controller certificate, because octavia-pki.sh verify reads it for the subject,
chain and SAN assertions -- a gate that depends on an undeclared artifact is incoherent. And
the CA serial file, because it is issuance STATE rather than residue: delete it and the next
-CAcreateserial starts a fresh sequence, so the same CA can issue a duplicate serial.
Reissuance is scheduled, not hypothetical -- the controller cert is 2-year and F9's D-106 work
will want new SANs.
DELETED AT SOURCE. The signing request is spent the moment the cert is issued. The openssl
config is fully derived from $DC plus the VIP overlay, so the repo already determines it, and
verify now asserts the SAN set on the CERT, which is where the F8 failure actually shows.
WHY NOT DECLARE ALL FOUR, which was lower-risk and less work: a register that accumulates rows
for artifacts that should not exist trains the reader to add a row rather than ask whether the
file belongs -- the register-as-rubber-stamp failure, the same family as this project's
false-green problems. Concretely, both intermediates are 664, so declaring them would have
produced four MORE world-readable findings for files nothing reads.
Also fixed at source, beyond the three requested steps and flagged as such: the generator now
chmod 600s all three certificates, so the next DC is correct by construction instead of by a
remembered follow-up.
Register 95 rows / 22 octavia rows; schema, mint-ref and notes checks clean; no new findings
(still 7 on the jumphost, the same pre-existing set). verify A2 extended 9 -> 10 so the register
and the gate agree on what should exist.
Harness 17/17 (was 15). T16 proves a missing serial FAILS. T17 proves a workspace with the
intermediates DELETED still PASSES -- without it, adding the serial to A2 would have silently
failed every clean workspace.
Gauntlet ALL GREEN (89), repo-lint 0 fail / 621 files.
Still owed, operator-executed: the one-off chmod on the six existing certs and removal of the
four existing intermediates. The guard blocks both for the session -- including the chmod, which
is worth recording as fork-1 evidence since it blocks an operation that strictly improves
posture.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|
| 2026-07-29 |

octavia-pki.sh verify: the SAN assertion the runbook never had (harness 15/15)
...
Operator direction: "Build the verify mode first, then we'll rule the guard fork."
WHY. Step 1.0-GEN is a copy-paste chain, and executing it today surfaced two defects that
only a human noticing caught. F8: the heredoc is a paste hazard whose output is a controller
certificate with NO SANs, while every command in the chain still prints OK -- and NOTHING in
this repo asserted the SAN set. E2: the CA certificates landed group-writable, i.e.
substitutable trust anchors, which this session initially dismissed as harmless. Prose cannot
be tested; a script can, which is the entire argument.
SCOPE, deliberately narrow. verify only. It mints nothing and writes nothing. `generate`
exits 2 by design: whether a sanctioned script may mint is D-137 open fork 1, UNRULED, and
building it now would silently convert the guard from "blocks secret minting" into "blocks
secret minting except through any script". That posture change is the operator's to make.
CANNOT LEAK KEY MATERIAL BY CONSTRUCTION: every openssl call uses -noout, file contents are
only counted or pattern-matched, and there is no cat or base64 anywhere. That property is
what makes it runnable from an agent session.
Asserts, all derived rather than hardcoded: the workspace and its 9 artifacts; private
material 0600 and certificates not group/world WRITABLE; both CA subjects naming THIS DC
(the sibling of F8 -- the runbook guards ${DC:?} but not ${DC_LABEL}); both self-signatures;
the chain against the CONTROLLER CA and, as a negative, NOT against the issuing CA, since
only checking the positive would pass a chain built against the wrong trust domain; the SAN
set against the per-DC VIP overlay; the overlay's mode, key count, ASCII and gitignore state;
and cross-DC independence.
Host binding is READ from creds-manifests/host-identity rather than hardcoded, so it cannot
drift from the register, and on any other host it REFUSES rather than measuring a filesystem
it should not be describing -- the F6 lesson, exit 3.
Harness 15/15. T1 is the non-zero floor. T2 is F8's SAN-less certificate. T13 guards the
opposite error: openssl prints v6 SANs expanded and uppercase while the overlay carries the
compressed form, so a naive compare would FAIL a CORRECT cert. T9/T10 prove REFUSE, T11
proves an un-generated DC FAILS rather than refusing -- we looked, and nothing was there.
Added OCTAVIA_PKI_REPO / _HOME / _THIS_HOST overrides so the harness can point at fixtures.
Not a convenience: creds-matrix.py's V2 check shipped with zero cases precisely because it
had no fixture path, and this repo records that as the reason it went untested.
Manifest 88 -> 89. repo-lint 0 fail.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|