| 2026-07-29 |

Render-pipeline step 4: the renderer, reproducing a reviewed artifact byte-for-byte
...
scripts/render-dc-overlays.py. Two stages, split exactly where forward item
F2 froze the interface: `derive` (apex + lib-net.sh -> a per-DC values file)
and `render` (values -> overlay text). `render` is PURE -- no apex, no
network, no clock -- so it is offline-testable and a future CI job re-runs
only `derive`.
ORDER INVERTED BY MEASUREMENT. The plan was ruling-3's VIP extraction first.
Three read-only agents measured two facts that reversed it: the byte-for-byte
reproduction window is still open (the live dc1 overlay is still identical to
the frozen fixture) and closes on its own when the R2/R11 reconciliation
lands; and the extraction's blast radius is far larger than ruling 3's "2
commits" -- it breaks the phase-01 deploy gate (juju deploy runs only on
11/11/0), the Octavia SAN derivation, preflight in two places, and 8 of 30
harness cases. Better done BY the renderer, so dc0's overlay is a validated
output rather than a hand edit.
A TEXT emitter, not yaml.dump: a round-tripper destroys the comment header,
normalises the quoted vip scalar, and imposes its own key order -- all three
are load-bearing bytes. Two things are INPUT rather than invented: the 12-line
comment header (lifted verbatim via --from-overlay, so a reproduction run is
honest about which bytes the tool actually generates) and the ascending-octet
emission order (sorting by name reproduces nothing). The ruled app->octet map
is READ with ast out of dc-plane-apex-import.py rather than restated as a
second drifting copy.
RESULT: output hashes to 3f93ecb3..., identical to both the committed overlay
(1634 bytes) and the frozen fixture. PROVEN ABLE TO FAIL, not merely observed
passing -- three seeded faults all fail the compare (wrong octet, dropped
header, dc0 prefixes against the dc1 artifact).
THE ARITY WORK PAID FOR ITSELF WITHIN THE HOUR. The first dual-family output
was malformed: the values file stores each v6 /64 base with trailing colons
stripped, and the emitter joined with a single colon -- 2602:f3e2:f03:11:50,
not a valid address, and it still looks like one. provider-bundle-check,
fixed yesterday for exactly this class, rejected all 13 applications. Locked
by T13/T13b.
End to end: apex -> values -> renderer -> overlay -> gate. The dual-family
dc1 render with R11's ruled-but-unbuilt apps produces 13 VIPs, all
dual-family, PASSING provider-bundle-check --dc vr1-dc1 including the new
hacluster invariant. Nothing committed has been regenerated by it yet.
tests/render-baseline gains T6, the reproduction case its README invited --
ADDED, with T1-T5 deliberately not repointed at live, and comparing against
the FIXTURE because live is supposed to diverge. T6 proven able to fail by
making the renderer sort alphabetically.
New harness 17/17; render-baseline 10/10 (was 9); gauntlet ALL GREEN (85) on
vcloud, manifest re-recorded after the drift gate correctly caught the
addition; repo-lint 0 fail / 608 files scanned.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|
| 2026-07-28 |

Exercise the dc1 arm of the apex lookup; confirm P2's rc=2 classification
...
T19-T23 all ran at the default --dc vr1-dc0, so the dc1 v6 bands
(f03:11::/64, :320::/64, :321::/64) were resolved by no case at all. The
renderer's first real output is per-DC overlays, and a gate observed in
only one DC mode is the same only-ever-seen-one-way untrustworthiness
T16/T18 exist to rule out.
T29 resolves the dc1 bands and passes. T30 proves a dc0 v6 leg under
--dc vr1-dc1 FAILS, so a cross-DC copy-paste of a rendered overlay
cannot pass -- the v6 analogue of T15.
Also verified rather than assumed: the checker's NEW exit-2 refusal
(dual-family vip + unreadable apex) is classified correctly by preflight.
P2 rc=2 is already ruled could-not-evaluate -> FAIL (preflight.sh:36,81)
and harness case T14 locks it, so a refusal can never downgrade to a
warning. No change needed there.
Harness 28 -> 30. Gauntlet ALL GREEN (84) on vcloud; repo-lint 0 fail /
605 files scanned.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

VIP arity gap CLOSED + R11's three ruled gate changes executed
...
provider-bundle-check.py could not express what R2 and R11 already ruled:
:137 required exactly 3 addresses per vip (a dual-family VIP is 6, so it
would have failed EVERY application) and :149's octet extraction returned
the whole string on a v6 literal, leaving every v6 leg trivially unique
and unchecked. The apex now holds the dual-family set a renderer will
emit, so the only gate that validates overlays could not validate what is
about to be produced.
Arity: a vip is now a v4 triple OR a dual-family sextet. The v6 legs are
validated against the per-DC v6 /64s READ FROM THE APEX RECORD (D-136
option (D)), reusing dc-plane-ipam.sh's (role, kind) keying -- the
provider leg takes the dedicated GUA VIP /64, admin/internal their plane
/64s. The v6 host part must MIRROR the v4 octet textually. prefer-ipv6
and the v6 legs are COUPLED in both directions: the measured L3-9 finding
is that the merge order which keeps prefer-ipv6 while dropping the v6
legs is the one that exits 0. An unreadable apex REFUSES at exit 2; a
v4-only bundle needs no apex.
R11 (D-020 amendment, ruled 2026-07-27), same pass: band 50-60 -> 50-99
in both separately-named sites; VIP_COUNT_EXPECT 11 -> 13;
EXPECT_PUBLIC_VIP deliberately stays 11 (measured -- neither vault nor
designate has a public binding); and an hacluster principal with no vip
now FAILS, since cluster_count is asserted nowhere and a 3->1 rewrite of
all 20 values produces a byte-identical PASS.
Measured consequence, not glossed: two sub-checks flip PASS -> FAIL
(designate's missing VIP; CHECK 1 at OK=11 want 13). preflight was
ALREADY exit 1 before this change and is still exit 1 after -- no deploy
path that was open is closed. Both reds are the ruled gate reporting real
work owed; per R6 the .61/.62 VIPs land before the HA overlay.
Harness 15 -> 28. Three cases RE-POINTED rather than deleted: the fixture
base splits into a pristine repo bundle and one carrying designate's
ruled .62, with new case T16 asserting the pristine bundle DOES trip the
new invariant. When .62 lands, T16 gets re-pointed, not deleted. Proven
able to both fail and pass on the same check (T16 red / T18 green).
Gauntlet ALL GREEN (84) on vcloud; repo-lint 0 fail / 604 files scanned.
Scope was operator-gated: "Fix the arity gap first, then start the
renderer", with the arity-alone vs arity-plus-R11 fork put separately and
answered "Arity gap + R11's three ruled changes (Recommended)". OPS under
GA-R3, no D-number.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|
dc-node-v6-carve harness 9/9; manifest re-recorded (84)
...
Locks the properties that matter: the octet mirror is TEXTUAL (.121 -> ::121,
never a hex conversion); the D-100 raw provider NIC is skipped for having no v4
link while br-ex is included for having one; an interface already carrying a
DIFFERENT v6 refuses rather than adding a second; a vlan with no v6 subnet is a
named error rather than a silent skip; a tag matching no machines REFUSES rather
than reporting a clean zero; and apply is dry by default.
T5 drives a fully-carved fixture to green -- every live run currently fails
because nothing is carved, and a gate only ever observed failing is as
untrustworthy as one only ever observed passing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|
dc1 FIP pool RULED 10.12.65.0-10.12.67.254 (GA-R5); lib-net dc1 arm + assertions re-pointed
...
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

LIVE: D-134's bands now EXIST -- both DCs at pass=24 fail=0, from a 6/18 baseline
...
Operator-gated, dependency-ordered: dc1 v6 carve (6 subnets), dc0 reserve (13
ranges), dc1 reserve (12 ranges). Each pre-apply re-verified in the same session;
every write read back. Subnets 18 -> 30, ipranges 3 -> 28. Machines 18 Ready + 2
Deployed unchanged throughout -- no node, no tfstate, no running service touched.
This closes the "RULED IS NOT BUILT" finding for D-134: its band table had been
prose since 2026-07-23 while MAAS held zero reserved ranges.
FINDING -- MAAS already reserves the entire low IPv6 block. Every explicit v6 band
create failed with "Requested reserved range conflicts with an existing range".
Measured via `subnet reserved-ip-ranges`: MAAS auto-reserves ::1-::ffff:ffff on
every IPv6 subnet plus :: per RFC 4291 s2.6.1, with allocatable space starting at
<prefix>:0:1::. The ruled bands sit entirely inside it, so the write is impossible
AND unnecessary. R4's "v6 bands as a second pass" is not executable in MAAS and
need not be; the tool now verifies coverage instead of writing. Execution-level
correction -- R4's intent is satisfied. Same on ULA and GUA.
Harness T19 asserted a literal string the fix removed. Re-pointed at the surviving
invariant (textual 4-99, never hex 4-63) rather than deleted, per the standing rule
against going green by removing an assertion. 25/25, gauntlet ALL GREEN (83).
dc1's FIP pool still correctly REFUSED -- unset by design, so R4 cannot close for
dc1 until ruled.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

dc-plane-ipam: carve-v6 and reserve actions, dry by default, harness 25/25
...
Both are DRY BY DEFAULT, IDEMPOTENT, and READ BACK every write -- this repo has
been bitten by a script whose `apply` always silently dry-ran, so a create that
reports success is re-read before being called done.
carve-v6 places each v6 plane on the SAME MAAS vlan as its v4 twin, so the plane
is genuinely dual-stack on one L2 rather than a parallel fabric, and REFUSES to
create anything if that vlan cannot be resolved. The provider GUA VIP /64 is
skipped by design.
reserve does the D-134 bands plus the FIP pool. Two deliberate refusals:
- dc1's FIP pool is UNSET in lib-net BY DESIGN ("UNSET so any use fails loud").
Mirroring dc0's shape would be an inferred value, so it refuses and reports
that R4 cannot be fully executed for dc1 until the pool is ruled. Real finding.
- a same-bounds range of the wrong type is REFUSED, not overwritten.
v6 bands are skipped until carve-v6 has run -- R4's forced sequencing, surfaced
rather than silently passing.
TWO BUGS CAUGHT PRE-SHIP, neither by review:
- printf '%x' 50 yields 32, so the v6 bands would have been created at ::32-::63
-- a plausible-looking band that is NOT the one ruled. The ruling mirrors the
DIGITS (v4 .50 -> ::50). T19 locks it.
- `shift 2` with a single argument fails, leaving "$@" holding the action, which
the option loop rejected as an unknown option instead of printing usage. Found
by the harness.
The header claiming the mutating actions were absent is also corrected -- it went
stale the moment they landed.
Gauntlet ALL GREEN (83), repo-lint 0 fail.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

Step 3: dc-plane-ipam.sh check -- D-134's missing executable gate, with a measured baseline
...
R4's D-134 amendment ruled a site-keyed tool that "also gives D-134 an EXECUTABLE
gate instead of prose". This is that gate. Read-only half only; the mutating
actions are deliberately not in this commit (hard rule 3 -- the gate ships and
runs first, so the mutation is planned against a MEASURED baseline).
Expected state is derived, never hardcoded: v4 planes from lib-net's DC selector,
v6 planes from the NetBox apex record (D-136 option (D) applied -- the apex is the
source, so this does not create a second hand-maintained table), bands from the
D-134 2026-07-23 amendment.
LIVE BASELINE, both DCs, symmetric at 6 pass / 18 fail: all six v4 planes present;
ZERO of six v6 planes present; ZERO of twelve D-134 bands reserved. MAAS holds 17
v4 subnets and exactly one v6, which is Office1's -- a third-layer confirmation of
U17. Cloud-wide there are 3 ipranges, all dynamic, matching R4's measurement.
Proven able to BOTH fail and pass: every live run fails because everything it
asserts is absent, so T6 drives a fully-provisioned fixture to green. A gate only
ever observed failing is as untrustworthy as one only ever observed passing. It
REFUSES rather than reporting clean on an unreachable MAAS, an unreadable apex, or
a band of unrecognised type, and distinguishes an ABSENT maas binary from an
unreachable MAAS -- the misdiagnosis class this audit found three times.
The provider GUA VIP /64 is reported but NOT asserted as a MAAS subnet: it holds
hacluster-managed VIPs, not node addresses, so MAAS cannot hand one out. Whether it
should also be a MAAS subnet is left open rather than decided by a gate.
Harness 14/14. Gauntlet ALL GREEN (83) -- the R15(2) manifest gate correctly caught
the new harness as unpinned drift and was re-recorded deliberately, which is the
mechanism working end to end in its first real use.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

R15(2): the gauntlet pins a harness MANIFEST, completing the R15 gate work
...
tests/HARNESS-MANIFEST (82 names) plus a drift gate in run-tests-all.sh, with
--record-manifest for deliberate re-recording. The zero-floor already existed;
what was missing was any pin on WHICH harnesses ran, so a renamed or deleted
harness was neither run nor failed while the gauntlet still printed ALL GREEN.
The figure 81 existed only as prose.
Proven able to fail on both cases, including the one a bare count cannot catch:
renaming a harness is reported, and renaming one WHILE adding a decoy -- so the
count holds at exactly 82 -- is still caught, naming both the missing and the
unpinned entry. That case is why the ruling chose a manifest over a count.
Sequenced LAST of R15's three deliberately: the ruling warns a manifest must be
seeded from a verified tree, not from whatever is on disk. Seeded here from a
tree with the gauntlet ALL GREEN and repo-lint 0 fail in the same session.
The gate runs only on a full gauntlet -- a filtered run legitimately executes a
subset. A missing manifest is itself a FAIL, since ALL GREEN would otherwise be
unfalsifiable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

R15(3): preflight no longer fails open on an unexpected sub-gate exit
...
Reproduced first, in isolation with the exact note() from preflight.sh:27 --
sub-gate exits 127 (command not found), 126 (not executable), 130 (interrupted)
and 3 (undefined) ALL left "PREFLIGHT: PASS -- clear to add-model / deploy".
This is the gate that authorises the deploy.
rc=2 handled PER GATE rather than blanket-remapped, because R15's stated
rationale is only partly right on measurement: repo-lint and pre-flight-checks
both DOCUMENT rc2 as a legitimate warning, while provider-bundle-check and
creds-matrix use it only for could-not-evaluate. A blanket 2->FAIL would have
turned the standing L1 legacy-ASCII warn into a deploy blocker. channel_assert
uses 2 for BOTH meanings, so it is ambiguous in the checker and kept WARN; its
missing-PyYAML root cause is caught by P2 anyway, which shares it and is strict.
Flagged rather than guessed -- fixing that belongs in channel_assert.py.
Harness 16/16 (was 10): T11-T13 lock the fail-open cases, T14/T15 lock
could-not-evaluate -> FAIL, and T16 locks the non-over-correction (P1 rc=2 stays
WARN). Gauntlet ALL GREEN (82). Real-repo preflight still exits 1 for the same
known reasons with no new failure classes fired.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

R15(1): repo-lint can no longer report PASS over zero files
...
Reproduced before fixing, both cases printing "PASS: repo lint (0 fail, 0 warn)"
with exit 0: `repo_lint.py --recordd` and `repo_lint.py /nonexistent-path`. Only
the two known flags were stripped, so any other --flag became argv[0] i.e. the
ROOT; it resolved nowhere, rglob yielded nothing, and zero findings read as
clean. This is the gate whose "0-fail" every GA-R6 stage close in this project's
history cites, and it could not tell a clean repo from an unexamined one.
Fix: reject unrecognised options (the actual root cause) and >1 positional root;
require the root to be a directory carrying repo markers, refusing rather than
defaulting to success; add a files-scanned floor; and PRINT the files-scanned
count -- Phase 0 found repo-lint emitted no such figure at all, so a reader could
not distinguish a thorough pass from a vacuous one.
The floor SCALES, and a flat one was wrong: the first implementation used a flat
100 and failed 20 of the 47 existing harness cases, because tests/repo-lint
legitimately builds ~7-file fixture repos. The strong floor now applies only to a
full checkout of THIS repo, detected by two files no fixture creates; any other
tree must still scan at least one file. Caught by running the harness.
Harness 54/54 (was 47) -- T48-T54 lock each reproduced defect, including that the
floor does NOT punish a legitimate minimal tree. Gauntlet ALL GREEN (82).
repo-lint on the real repo: 0 fail, 1 standing warn, 596 files scanned.
No consumer breaks -- preflight P1 reads the exit code, not the summary text;
harness regexes match the unchanged "PASS: repo lint" prefix. Both verified.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

Render pipeline step 1: carve-outs pinned, reproduction fixtures frozen
...
CARVE-OUTS PINNED at operator request ("in a place they will not be lost as
they will be required items in the future"). New forward items in the workflow
doc: F2 the render-pipeline AUTOMATION half (CI runner / event delivery /
status-back), deferred because two GitBucket requirements are unverified --
reliable webhook emission with retry+replay, and a status-back API without
which the approve-on-rendered-diff gate cannot see a validator verdict -- plus
open Jenkins placement; and F3 the NetBox scope boundary for MACs and VLANs,
permanent rather than pending.
D-136's MAC scope-out was CORRECTED AT SOURCE rather than only contradicted
elsewhere. Its stated reason -- MACs "drift-free across substrate main.tf <->
lib-hosts.sh <-> bundle ovn-chassis <-> discovery" -- is falsified: bundle.yaml
:462 carries 52:54:01:d1:04:02 / :05:02, which lib-hosts:132 identifies as
vr1-dc1's scheme, in the file documented as vr1-dc0's source of truth. The
correct reason is availability (no dcim/devices or dcim/interfaces in the apex
at all), and the consequence changes: ovn-chassis becomes renderer OUTPUT and
must leave the base bundle.
STEP 1 -- tests/render-baseline/ freezes the two known-good artifacts a renderer
can be validated against, BEFORE the R2/R11 reconciliation destroys them. After
that lands there is nothing left to diff against and a renderer's first output
is its own first draft, which is D-136's own objection to option (A).
The harness asserts fixture INTEGRITY and deliberately not agreement with live
-- live is supposed to diverge, and asserting against it would turn the harness
red for the change it exists to support (the creds-matrix T24 trap).
Proven able to fail before being trusted: seeded a silent fixture edit (caught
by T2b) and an unpinned file in fixtures/ where sha256sum -c passed vacuously
and only the coverage assertion T3 caught it.
Harness 9/9; gauntlet ALL GREEN (82, was 81); repo-lint 0 fail.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|
| 2026-07-27 |

set-interface-v4: reload the pf filter on --commit (RULED); appendix-A rewritten
...
RULING (GA-R5) 2026-07-27. Question as presented: (a) add `configctl filter reload` to the
script's --commit path; (b) leave the script and rely on DC standup DoD item 8; (c) put it behind
an opt-in flag. Operator answer, exact utterance: "a". OPS under GA-R3 -- a script fix completing
an already-documented operation, governed by D-113; no new D-number.
DEFECT (appendix-A, measured on the fresh dc1 edge 2026-07-23): --commit ran `configctl interface
reconfigure`, which applies the address to the kernel but does NOT regenerate the pf ruleset, so
OPNsense never creates its automatic outbound-NAT rules for the (re-)addressed LAN. Forwarded LAN
packets left the WAN un-NAT'd and replies never returned -- the edge passed NO LAN traffic while
looking perfectly configured. Self-masking: any later plugin install or config apply reloads the
filter as a side effect, so dc0's 07-20 qga work hid it there until dc1 exposed it.
Option (b) rejected on evidence, not taste: DoD item 8 already existed and did NOT fire at dc1,
and prose-only controls have a measured failure record here (D-137's own enforcement sat as prose
at phase-3:498 and missed BOTH DC standups).
PLACEMENT IS THE SUBSTANCE OF THE FIX, and my first attempt got it wrong -- caught before
shipping. Putting the reload on the next line of the `interface reconfigure` heredoc would have
been a fix that fixes nothing exactly when it matters: re-addressing the interface you arrived on
drops the session DURING the reconfigure, so a following command in that stream never executes --
and that drop case IS this incident's own scenario (dc1's LAN moved 192.168.1.1 -> 10.12.64.1
over the LAN itself). As shipped the reload runs over a FRESH connection to PROBE_HOST.
Also added a `pfctl -s nat` read-back with the `proto carp` boilerplate filtered out, since
boilerplate-only is precisely appendix-A's broken-state signature. REPORTED, not gated: an edge's
first addressing may legitimately have no gateway and so no NAT to generate, and hard-failing
would block a correct run. The hard gate stays address-on-the-kernel.
Harness 59/59 (was 53), cases 15-15f. Case 15f caught a real inconsistency -- appendix-A still
said "not yet ruled". Case 15e caught a bug in my own first draft, which scanned to EOF and so
failed the script for having the very hard gate the case exists to preserve.
appendix-A rewritten: the FIX stays for an edge already in this state, plus a PREVENTED-IN-THE-TOOL
block recording the placement detail and why prose prevention was rejected.
Gauntlet ALL GREEN (81), repo-lint 0-fail. No live edge touched -- both DC edges are already
addressed, so this affects only the NEXT edge addressing.
With this, every substantive Stage 4 in-stage item is closed or split to gate row G17; only the
GA-R6 close-out set remains.
Revert: git revert this commit's script + harness + appendix-A changes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

dc1 full mirror REMOVED (D-135 amendment); dc-cache-proxy.sh now owns its net layer
...
Operator clarified intent, exact utterance: "DC0 is the test of a full mirror. DC1 is the test
of the mirror proxy. DC1 needed the partially created full mirror and associated
script/files/settings removed." Recorded as a D-135 AMENDMENT 2026-07-27 -- the per-DC split
is the DELIBERATE EXPERIMENT, not an interim state. That supersedes both the "PAUSED ... kept
dormant as the fallback" record and the "DC1's proxy is REPLACED by a full mirror afterward"
claim, which sat in THREE places (D-135, CURRENT-STATE:109, dc-cache-proxy.sh:6); all corrected.
dc0 FIRST (gated): sync re-run -> OK 2026-07-27T08:43:46Z ubuntu=0 uca=0 in 20s, confirming
the transient-500 diagnosis. The fixed check now reports PASS -- trustworthy precisely because
the same check FAILED on the same rack twenty minutes earlier. Stage 4 DoD bullet 5 is now MET
for both DCs (dc0 mirror PASS, dc1 proxy PASS), node-side half at G17.
WHY THE ORDER MATTERED. Asked to weigh rip-down-and-rebuild against surgical removal, the
rebuild path turned out to be BLOCKED, not merely slower: dc-cache-proxy.sh did not own its
utility net layer -- it REUSED dc-mirror.sh's <site>-mirror-net.service and refused to install
without it. So on dc1, whose ruled path is the PROXY, three files named dc1-mirror-* (net unit,
apply helper, resolved DNS drop-in) were load-bearing FOR THE PROXY. Consequences: the recorded
removal procedure would have silently killed the proxy, the bullet-5 PASS and the Stage-5 dc1
apt path; and the proxy could not be REBUILT afterward, since nothing but `dc-mirror.sh
install` created the net layer -- rebuilding a PROXY meant reinstalling the whole MIRROR
apparatus, enabled daily debmirror timer included. Operator direction: net layer first, then
rip it all down.
1. NET LAYER MOVED: <site>-cache-proxy-net.service + -net-apply + its own resolved drop-in,
reusing dc-mirror's proven mechanism (bridge from the libvirt net NAME at runtime, hard
rule 3). Proxy-named so a proxy-only DC has NO mirror-named dependency. Idempotent
replace verbs, so both net units coexist safely where a site runs both -- dc0 unaffected.
check asserts the ARTIFACTS, not just the live address/route: asserting only the live
effect would PASS while the layer was really the mirror's, which is the exact failure.
Harness 20/20 (was 15). T12 REPLACED not deleted -- it asserted the superseded design, so
it failed by design; now inverted, plus T12b-T12f. T12b is scoped to non-comment lines on
purpose: the header's account of the removed trap cites dc-mirror.sh install, and deleting
that history to satisfy a grep would lose why the trap existed.
2. INDEPENDENCE PROVEN BEFORE DELETING: a oneshot with RemainAfterExit=yes does not undo its
work on stop, so stopping the mirror unit would have proven nothing. Removed the live state
outright (addr count -> 0, default route count -> 0), applied the proxy-owned unit ALONE,
both restored; check dc1 PASS with dc1-mirror-net.service disabled.
3. WHOLESALE REMOVAL: all mirror units, timer, sync helper, nginx vhost, resolved drop-in, the
debmirror package, and 330G of partial mirror (33,037 files, rm -rf 47.6s; disk 339G ->
9.0G). Zero mirror-named residue, every proxy artifact present, proxy PASS throughout and
never down. Capture docs/audit/dc1-mirror-teardown-20260727.txt.
nginx left installed deliberately: a mirror prereq, but with the vhost gone it is a generic
server on its stock default vhost; removing the metapackage while nginx-core runs is a
half-measure and a full purge is scope creep on a rack host.
Gauntlet ALL GREEN (81), repo-lint 0-fail, dc-cache-proxy 20/20, dc-mirror 24/24.
Revert: `dc-mirror.sh install dc1` (needs debmirror reinstalled) then `sync dc1` to re-pull
~950G; git revert dc-cache-proxy.sh + harness to restore the mirror-owned layer. The 330G
partial is NOT recoverable -- deliberately, per the amendment.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

Stage 4 close-out: fix dc-mirror.sh check false-greening the mirror gate
...
Operator directed closing Stage 4 before resuming the DC1 Stage-5 chain. Verifying the DoD's
fifth bullet ("per-DC mirror reachable") found that the check the gate would close on COULD
NOT FAIL.
scripts/dc-mirror.sh:271-273 tested `[ -f last-sync.status ]` and printed the file's contents
behind an unconditional "OK" -- the status word was displayed but never asserted on, so the
check exited PASS regardless. MEASURED on both racks:
- dc0 read "FAIL 2026-07-27T00:54:54Z ubuntu=255 uca=0" -> printed OK, PASS
- dc1 read "RUNNING 2026-07-23T21:49:35Z", four days stale,
left by the debmirror the D-135 amendment killed by signal -> printed OK, PASS
GA-R6 requires a stage to close on a NAMED executable check whose captured output the closing
commit cites. A check that cannot distinguish "synced" from "failed" or "died mid-run" is not
that check.
FIXED: the status word is case-analysed. OK* passes. FAIL* misses. An ABSENT file misses (it
was a passing `note`, but nothing has attested the content). An unrecognised word REFUSES
instead of defaulting to success. RUNNING* is deliberately neither pass nor plain fail --
in-flight and died-mid-run are indistinguishable from the file alone, so it reports an explicit
UNKNOWN and cross-checks the unit, naming a RUNNING marker with no active unit as a corpse.
Harness 19 -> 24; T20-T24 lock each status word and T24 locks out the return of the exact
defective shape.
PROOF, re-run against both live racks -- the gate is now honestly NOT MET for the first time:
dc-mirror check (dc0): FAIL / dc-mirror check (dc1): FAIL. Capture
docs/audit/stage4-mirror-gate-20260727.txt.
SUBSTANCE (measured, not inferred):
- dc0's mirror CONTENT is complete: 949G ubuntu + 342M cloud-archive, all three dists plus
pool. Only the overnight INCREMENTAL failed -- "Download of dists/jammy/Release failed: 500
read timeout" aborted the ubuntu leg with 255; the UCA leg succeeded. Transient upstream
fetch failure, not mirror damage. Timer re-arms 2026-07-28 00:14:48.
- dc1's PROXY -- its RULED artifact path per the D-135 amendment -- checks PASS genuinely
(apt-cacher-ng on .4:3142 serving archive + UCA Release 200). Its dormant fallback debmirror
is dormant only ACCIDENTALLY: the timer is `enabled` with an EMPTY next-elapse because the
unit sits in failed/Result=signal, so the ruling is enforced by nothing and a reset-failed
would re-arm a 330G -> ~949G pull.
ALSO RECORDED, not yet actioned: DoD bullet 6 ("NTP from the DC's own OPNsense edge") is STALE
and unsatisfiable -- superseded by D-129(iv) 2026-07-21 ("Keep MAAS hierarchy", no NTP role on
the edge) -- and survives in four surfaces needing a DOCFIX before it can be checked at all.
The node-side half of bullet 5 needs an operator decision (gated rescue-boot check vs its own
gate row per GA-R6 E3); nodes are powered off by the READY-handoff ruling, so no node-side
probe can run as things stand. There is no conditional close.
No live state was altered: both racks were read only. repo-lint 0-fail, dc-mirror 24/24.
Revert: git revert the scripts/dc-mirror.sh + tests/dc-mirror/run-tests.sh changes; the check
returns to passing unconditionally on last-sync.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

creds consolidation batch: SEC-021(b) dc0 power key, SEC-025 NetBox GUI, V2 ruled deferral
...
Operator asked whether vcloud holds a consolidated set of login creds for every account that
exists, and what is missing / needs creating / was never moved in. Audited, then cleared the
consolidation batch on operator direction ("clear the whole consolidation batch first").
The audit's own headline: creds-audit read CLEAN on all three sites while the matrix returned
13 findings -- and the two most consequential gaps were in NEITHER surface. They were found by
enumerating the accounts that ACTUALLY EXIST. Absence of a ROW is invisible to the register,
which generalises D-137's founding argument one level up.
VERIFIED POSITIVE (both previously only asserted):
- MAAS account set COMPLETE: all 6 live accounts accounted for; admin + operator passwords on
vcloud, juju-vr1-dc0/dc1 random+unstored BY RULING with API keys present, MAAS +
maas-init-node MAAS-internal.
- tier-3 V1 now MEASURES maas-admin-password byte-identical to the headend source-of-record,
so SEC-020's stale-trap risk is clear as of this date.
DONE:
- dc0 SEC-012 power key consolidated to vcloud + .pub DERIVED (SEC-021(b) as written).
MEASURED FIRST, because the naming looked like a defect and was not: the headend
maas-virsh_ed25519 and the snap's id_ed25519 are the SAME key; it IS dedicated (distinct
from the dc0 service key, which is what SEC-012 requires); and dc0 using the snap's default
identity is SEC-016's RULED design. So no re-mint, no live power path touched.
- dc1 svc .pub backfilled to the headend store (public-key material, sha256-verified).
- NetBox web-GUI admin password consolidated -- a HUMAN login that had never left the VM it
was minted on, the third instance of the SEC-009/SEC-020 miss class. SEC-025 OPENED for the
at-rest exposure the copy CREATES, not the gap it closed. Open rows 20 -> 21.
- V2 taught the ruled-deferral state: SEC-006's standing "revoke at completion of this
deployment" ruling is now ACKNOWLEDGED (still naming the credential live and exposed)
instead of failing every run. Reissuing the token would have CONTRAVENED that ruling, so the
register was what needed to change. Match demands the cased state word AND explicit operator
ruling attribution, and cannot cross a ledger table cell -- T58/T59 lock the evasion out.
- Added --ledger (default unchanged): V2 read the register via --repo, which the harness must
point at the real repo for S4, so V2 had shipped with ZERO harness cases. T56-T59 added.
Findings 13 -> 7. Matrix 82 rows, harness 60/60 (was 56), creds-audit CLEAN x3, gauntlet ALL
GREEN (81), repo-lint 0-fail. The register is NOT green and is not expected to be.
RESIDUAL, all recorded: dc0-edge-api x2 (the opnsense-api.txt re-mint is a live edge mutation,
deliberately EXCLUDED from this batch), S5 x3 (RULED by SEC-016 -- needs a ruled-exception
mechanism, operator decision), S6 conflation x1 (the SEC-020 defect), E4 x2 (Stage-5/6 rows).
LOGGED NOT ACTIONED (hard rule 1): no registered root/console credential at EITHER DC edge
(measured absence of row/manifest/SEC row; what those passwords ARE is UNKNOWN and
deliberately unprobed per hard rule 2 -- vector is the LAN-reachable GUI and serial console,
not SSH, which is key-only and proven); plus the two structural blind spots that let it hide
-- S5 compares only cardinality=per-DC while all six per-site rows are office1-only, and
vm-secret-locations declares no rack/edge/cloud/unit/client location though the checker
accepts them.
Revert: per-item reverts in docs/changelog-20260727-creds-consolidation.md. The headend, snap
and NetBox VM source copies were never modified, so every file move is reversible by deletion.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|
| 2026-07-26 |

D-137 tier 3 behavioural half: V2 declared-state + creds-probe.sh
...
Boundary and cadence operator-ruled: "Full -- including OpenStack service
credentials", "Stage close + DC standup close". I had recommended
passive-only and flagged the costs; the operator ruled otherwise.
V2 (passive, zero authentication) fires TODAY on a real defect: SEC-006 has
recorded the NetBox upstream token as BURNED since 2026-07-12 while the
matrix carried it as a healthy consolidated row. Nothing reconciled the two
surfaces. Keyword matching on ledger prose is fragile, so it is conservative
and reports the matched text as its basis.
creds-probe.sh is SEPARATE by design: a probe must USE a credential, and
creds-matrix.py is metadata-only by an enforced invariant (T22/T51). Folding
probes in would have relaxed that guard, and a guard relaxed once stays
relaxed.
Safety: never retry a failed auth (retry loops lock accounts; the MAAS admin
identity backs 19 call sites), never argv, never echo, stage-aware skips, and
per-tenant credentials REFUSED BY CONSTRUCTION -- a declaration cannot opt
them back in (D-069, ruling 3). Not a deploy gate.
FALSE GREEN in my own first run: ssh inside a while-read loop ate the loop's
stdin, so 1 of 13 probes ran and the run exited 0. A partial run reporting
clean is the exact failure class this tool exists to catch. Fixed with ssh -n
and locked by a total-accounting check that makes a partial run VOID.
13 probes declared: 3 active, 4 stage-pending, 6 declared-only with reasons
recorded. OpenStack credentials declared now, skipping until Stage 5.
tests/creds-probe 9/9; gauntlet 80 -> 81; phase-3 DoD wired.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

D-137 tier 2: local half blocking in P5; --pending-stage -> coupled projection
...
Two operator decisions, both taking the recommendation.
GATE SHAPE: local-only blocking, remote operator-run. preflight P5 now runs
creds-matrix.py --tier2 -- tier 1 STATIC plus tier 2 LOCAL, hermetic (no ssh,
no sudo). It already catches SEC-021's three dc0 on-disk absences without
leaving the jumphost. The remote half stays an operator-run check at
DC-standup close and stage close.
Wiring --remote --privileged into the deploy gate would let a host outage, a
NOPASSWD change, or a MAAS snap refresh turn the gate red for reasons that
are not about credentials, and a gate that fails environmentally is one
people learn to bypass. The repo already made this call once
(run-tests-all.sh:7-8, "different cadence"), and preflight already shows the
failure mode: P4 reads "MAAS unreachable" because it runs on vcloud while
MAAS lives on the headend.
STAGE INPUT: --pending-stage replaced by creds-manifests/stages-reached, a
machine-readable projection of CURRENT-STATE, coupled by new repo-lint L12
(the L10 pattern). A hand-typed gate parameter can be widened silently, and
GA-R1 puts status in CURRENT-STATE alone. A drifted projection would make the
gate defer REAL absences -- a false green.
Exhaustive both ways: an unclassified mint-stage is a hard FAIL, a
classified-but-unused one is a stale-declaration FAIL. That caught `stage4`
immediately -- Stage 4 is open and executing but mints no credential.
Self-inflicted break caught by the existing harness: I first renamed L10's
message to "L10/L12", breaking five cases that grep the established L10 id.
Reverted -- new rules get their own message id, they do not rebrand old ones.
Harnesses: creds-matrix 52 -> 56, repo-lint 45 -> 47, preflight 10.
Gauntlet ALL GREEN (80), repo-lint 0-fail, baseline unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

D-137 tier 3 (VALIDITY) BUILT: cross-copy sha256 provenance
...
Closes the gap the plan names: creds-audit PARSES declared provenance and
never verifies it, so SEC-020's stale-trap warning has been unchecked prose
and its sha256 equality was a ONE-TIME manual act on 2026-07-25.
sha256sum runs as an EXTERNAL command on both sides so only a 64-hex digest
enters the checker -- hashing bytes in Python would meet the letter of "never
transfer content" and not the spirit.
RESULT: 4 groups compared, all byte-identical, INCLUDING the SEC-020 pair
(maas-region-admin, region source-of-record vs jumphost copy). Now
machine-verified instead of remembered. The [ok] line names the groups.
TWO FALSE POSITIVES IN MY OWN DRAFT, caught by verifying before reporting.
Keying digests by (role, site) let an identity's DISTINCT artifacts at one
scope overwrite each other, so it compared unrelated files and reported drift
on maas-region-admin and dc1-svc-key. Manual sha256sum showed both IDENTICAL.
Reporting that would have raised a false credential-rotation alarm.
Root cause was a schema gap: nothing expressed which rows are byte-copies.
custody gains `verbatim-copy` [OPS]. V1 now compares only rows sharing
(id, filename) across scopes, or a source-of-record row against declared
verbatim-copy rows -- SEC-020's exact shape. Everything else is skipped with
a reason: a pair we cannot justify comparing is not a pair we may report
drift on. verbatim-copy is manifest-bearing; it asserts byte-identity, it
does not move the file.
Harness 44 -> 52: T47/T48 regression-lock both false positives; T49 keeps
SEC-020's case from falling into T48's skip; T51 asserts the digest path uses
sha256sum and that no content-transfer verb exists anywhere in the checker.
NOT built: tier 3's behavioural probes. Liveness, expiry, revocation state
and grant/scope drift remain unverified.
Gauntlet ALL GREEN (80), repo-lint 0-fail, finding-class baseline unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

D-137 ruling 1 EXECUTED: tier 1 wired as the blocking preflight P5
...
Operator answer, exact utterance: "wire tier 1 as the blocking preflight Pn"
(2026-07-26), resolving the open sequencing question. Recorded on D-137.
preflight.sh gains P5: credential matrix (D-137 tier 1), blocking, with
worst-exit aggregation, placed AHEAD of the stage-2 reminders block (now P6)
so its verdict participates in the deploy decision. Tier 1 only -- it is
offline and its findings ARE the three ruled failure classes. Tier 2 needs
--remote/--privileged and a caller-supplied --pending-stage, which do not
belong in an unattended gate; that stays an open decision.
FAIL-OPEN in my own wiring, caught by the new test: a missing creds-matrix.py
makes python3 exit 2, which `note` maps to WARN -- so deleting the gate would
have downgraded it to a warning rather than stopping the deploy. P4 already
guarded this class; P5 did not until T9 failed. Now guarded explicitly.
tests/preflight 7 -> 10: T8 a red register FAILS the deploy (blocking, not
advisory); T9 fails closed when the checker is absent; T10 the gate runs
before the reminders block.
CONSEQUENCE, not overclaimed: preflight exits 1 with P5 among the reasons,
but preflight was ALREADY exiting 1 before this change (P4: octavia-pki.yaml
absent, MAAS unreachable from the jumphost). P5 adds a fifth reason to an
already-red gate; it flipped nothing and closes no open deploy path.
Verified by stashing the change and re-running.
Gauntlet ALL GREEN (80), repo-lint 0-fail.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

D-137 phase 3: re-measure the register; SEC-024 opened
...
~21 inferred filenames corrected against their own mint-refs. The session had
owned six; those were only the rows the first sweep physically touched.
Octavia's 8 real basenames plus its THREE SUBDIRECTORIES (the bare
~/octavia-pki/* pattern matched ZERO of the 8 artifacts, two of them CA
private keys); vault's init.txt; the tenant rows' <client>- instance prefix,
with a placeholder matcher so they can match a real basename at all;
kube-config -> config; .maas.cli -> .maascli.db (measured: ~/.maas.cli does
not exist).
sec-ref mis-attribution corrected: both juju-maas-user rows cited SEC-020;
the on-subject rows are SEC-018/-019. This is the SEC-015 class recurring --
one instance was fixed by hand earlier without checking whether it was
systemic. It was.
mint-ref corrected: admin.pass cited a CONSUMER (:452), not the mint (:450);
the RGW key cites a line that takes it as INPUT, so it is operator-terminal.
Rows added: the libvirt SSH power password (standing rotation obligation from
a 2026-06-26 plaintext exposure, in neither the matrix nor the exclusions),
vault-ca-root, and the tfstate siblings. ~/as-executed/ deliberately NOT
declared, reason recorded: it holds session logs, so declaring it made every
log a false UNDECLARED.
Four further defects in my own phase-2 changes, found by RUNNING the sweep:
shlex.quote broke ~ expansion; a non-existent parent read as unreadable
rather than absent; site-key `-` needed shared-location semantics; the
tfstate siblings needed rows.
SEC-024 OPENED -- new exposure found by the fixed checker on its first clean
run: opentofu/terraform.tfstate.backup is mode 0664 and carries the MAAS API
key in plaintext (DOCFIX-175); the live state file is 0600. Invisible to
every prior control because the world-readable check was custody-gated and
the siblings were undeclared. LOGGED, NOT ACTIONED (hard rule 1).
Findings 35 -> 13, all true. Matrix 81 rows. Harness 44/44, creds-audit
15/15, gauntlet ALL GREEN (80), repo-lint 0-fail.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

D-137 phase 2: fix the eight confirmed false-greens, regression-lock each
...
Tier 2 is now scoped by (host-role, SITE-KEY). Keying on role alone merged
all three jumphost creds folders into one basename namespace, so a credential
present at ANY site satisfied the row for EVERY site -- how SEC-021's dc0
opnsense-api.txt absence passed a green sweep while tier 1 flagged it. Four
committee lenses converged on this. vm-secret-locations gains a site column.
Also fixed, each reproduced by the committee and each now regression-locked:
- probe_remote called a successfully-read location UNREACHABLE when its glob
matched nothing, gating the role and turning every absence FAIL there into
an [ok]; a __DONE__ liveness marker now separates "ran, found nothing" from
"could not reach".
- literal-file locations skipped absent/unreadable detection entirely (the
T33 false green surviving in the other path form).
- an EMPTY locations list bypassed ruling 3's refusal.
- a zero-row matrix reported clean over the empty set.
- a mint-ref pointing at a directory crashed with exit 1 -- indistinguishable
from findings -- and skipped S5/S6/S7, silently dropping the conflation and
asymmetry findings.
- mode enforcement was custody-gated, leaving 43 of 77 rows unchecked
including the SEC-020 and SEC-022 stores; a world-readable check now
applies at any custody.
- S5's dc1->dc0 direction was untested; deleting it left the harness green.
- rows with no declared location for their scope are disclosed, not skipped.
- declared paths/targets are charset-validated and shell-quoted: an
unvalidated `;` reached a remote shell, under sudo when --privileged.
- creds-audit sprawl globs now cover dotfiles; the prior widening could not
see .admin.pass, the dotfile sibling of its own motivating secret.
T24 replaced with a checked-in finding-CLASS baseline. The old form grepped
for the literal "IDENTITY CONFLATION", so REMEDIATING that defect would have
turned the gauntlet red for whoever did the right thing -- making "edit the
test" the cheapest response exactly when the guard mattered.
Harness 35 -> 43, creds-audit 13 -> 15, gauntlet ALL GREEN (80), lint 0-fail.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

D-137 tier 2: live read-only sweep + two probe false-greens it exposed
...
SEC-021's ON-DISK half REPRODUCED: vr1-dc0-maas-power_ed25519{,.pub} are
genuinely absent from the dc0 jumphost creds folder, not merely undeclared.
Capture: docs/audit/d137-tier2-sweep-20260726.txt (read-only, no sudo,
stat-over-ssh metadata only; jumphost + voffice1 + office1-netbox).
Running it against real hosts exposed two false-greens in the probe:
1. "absent" vs "could not look". /root/maas-secrets and /root/netbox-secrets
reported "does not exist" -- they exist; SEC-020 is precisely about
admin.pass living in the first. An unprivileged [ -d ] on a root-owned
parent is indistinguishable from a missing directory. The probe now tests
parent traversability and reports UNREADABLE as a FAIL, not a skip.
2. Role-level aggregation manufactured false absences: skipping one location
let a role's other locations cover it, so credentials in the unprobed
location reported EXPECTED-BUT-ABSENT. Absence is now asserted only over
fully-probed roles (14 rows report NOT JUDGED). Refinement: "absent" is a
conclusive observation and does not gate a role; only unreadable and
unreachable do.
Harness 33 -> 35 (T33 unreadable location, T34 absent location).
Gauntlet ALL GREEN (80), repo-lint 0-fail.
OUTSTANDING: the two root-owned dirs need a privileged read, so SEC-022's
shadow-store contents and the SEC-020 region secrets stay UNCONFIRMED. That
is a remote-sudo shape and was not run.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

D-137 tier 2 (EXISTENCE): declared-location bound, existence checks, widened globs
...
Tooling only -- the LIVE three-site sweep has NOT run, so SEC-021's on-disk
half, SEC-022 and SEC-023 are not yet reproduced as live findings.
creds-manifests/vm-secret-locations (ruling 3): the absolute bound on
discovery. Covers the jumphost creds folders, the SEC-022 headend shadow
stores, the SEC-020 region secrets dir, the three dirs outside the SEC-009
convention, plus two the ruling's note did not name -- the in-clone PKI
overlay and the DOCFIX-175 plaintext tfstate. Tenant dirs are LOCAL-only:
no tenant VM/project/host is reachable from this file, so D-069 holds by
construction rather than by good behaviour. `<repo>` is substituted at
runtime (D-110: the repo name is never hardcoded).
creds-matrix.py --tier2 [--remote]: E1 expected-but-absent, E2 mode, E3
undeclared-at-a-declared-location. Probes are `stat` over ssh -- metadata
only, never content. An unreachable host SKIPS with an explicit [ok],
because "could not look" must never read as "nothing there".
--pending-stage is supplied by the CALLER so a not-yet-reached mint stage
defers instead of failing; encoding which stages have run would put a
status claim in code, and GA-R1 puts status in CURRENT-STATE only.
creds-audit.sh sprawl globs widened for the SEC-023 blind spots
(admin.pass, *.apikey, *.key, *.pem, *_ed25519, *_rsa, *openrc*). The old
six patterns could not have matched the SEC-020 secret that sat undetected
12 days, any bare SSH key or PEM, or the predicted Stage-5 ~/admin-openrc.
Harnesses: creds-matrix 33/33 (8 new tier-2 cases), creds-audit 13/13
(was 7; five blind-spot fixtures plus T13 asserting the widening did NOT
become trigger-happy). Gauntlet ALL GREEN (80), repo-lint 0-fail.
FLAGGED DIVERGENCE from the plan's Files list: --remote is implemented in
creds-matrix.py, not creds-audit.sh. Tier 2 IS the preflight Pn and the
matrix plus locations list both live there; splitting it would mean two
implementations of one bounded walk. Ruling 3 names a bound, not a script.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|

D-137 tier 1 (STATIC): credential matrix, checker, harness -- RED by design
...
Schema amended 10 -> 12 columns (operator-ruled 2026-07-26, "go with the
12-column amendment"): adds `custody` + `notes-ref` and re-keys a row to one
(credential, location) pair. A read-first round-trip check of the three
manifests proved the 10-column form could not carry what D-137 ruling 2
forbids dropping -- and ruling 3 puts four deliberate credential copies inside
--remote's declared locations, where creds-audit.sh:63-67 would report each as
UNDECLARED. Implements ruling 2 ("prose must become MATRIX FIELDS"); OPS under
GA-R3, the five sub-rulings untouched.
Ships: creds-matrix.tsv (72 rows), creds-matrix-notes.md (32 keys),
scripts/creds-matrix.py (S1 schema / S2 both-bounds manifest coverage / S3
render drift / S4 mint-ref resolution / S5 per-DC symmetry / S6 ruling-5
principal invariant / S7 notes integrity), tests/creds-matrix 24/24.
Gauntlet ALL GREEN (80, was 79); repo-lint 0-fail.
RED BY DESIGN, 5 findings -- do not go green by deleting rows: the ruling-5
identity conflation on maas-region-admin (the live SEC-020 defect), 3x
EXPECTED-BUT-ABSENT for SEC-021's declaration half, and the S5 asymmetry on
dc0's divergently-named headend power key. 27 operator-terminal rows are the
FINDING 1 reproducibility debt, counted not faulted.
Two self-inflicted false-greens found and closed during the build: S2
enumerated only matrix-mentioned sites (an empty matrix read CLEAN -- the
sandbox-fidelity-check.py:131-143 defect one level up; now the union of both
sides, regression-locked by T9), and the uniqueness key false-failed two
identities sharing one file (T6).
NOT done, stated so the boundary is unambiguous: tiers 2-3, vm-secret-locations,
the SEC-009 demotion, and the ruling-1 preflight Pn -- whose blocking-vs-deferred
sequencing is an OPEN operator question. No manifest rewritten; no cloud state
touched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvCyrwvYTTcDYnRErfMsNf
|
| 2026-07-25 |

netbox: office1-record dumper (source separation) + current apex snapshot
...
Operator-directed: one dump script per SOURCE so a credential/URL can never be
confused (the token never travels -- read from env).
- netbox/office1-record-dump.py (NEW): READ-ONLY dumper for the office1-netbox
RECORD -- the VR1 working apex (10.10.1.10:8000, 4.6.4, v2 token). This is what
every VR1 system actually consumes (DOCFIX-195) and what the dc0/dc1 buildout
edited -- i.e. the CURRENT in-cloud NetBox state.
- netbox/prod-draft-dump.py: docstring clarified -- it pulls ONLY the FROZEN v1
reference (netbox.baldurkeep.com), not the working apex.
- tests/office1-record-dump/run-tests.sh (NEW): offline harness 5/5 (slim /
prefix-scope rewrite / range key / source-target).
- netbox/draft/vr1-office1-current-20260725.json (NEW): the current snapshot --
139 prefixes / 11 sites (incl. vr1-dc0/dc1/off1), dc1 bands 10.12.64/68/72.0/22
present; differs from the 90-prefix frozen reference. For the Chat design
session (NetBox->deploy coupling) which has no live infra.
READ-ONLY: nothing written to NetBox. repo-lint 0-fail.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUjEb7onHpdqFHUnio6iVw
|
| 2026-07-24 |

provider-bundle-check: overlay merge + per-DC VIP bands + placement invariants
...
The committee's non-negotiable placement "spine" so the vr1-dc1 render is
machine-checked, not eyeballed. The checker was placement-blind (D-052 bindings
+ mysql=3 only), so any render could silently ship decorative HA.
- --overlay FILE: juju-like merge -> validates the EFFECTIVE deploy input
- --dc vr1-dc0|vr1-dc1: per-DC VIP bands (default dc0 = base; un-param run
byte-identical to before). Closes the dc1-VIP-outside-the-check gap.
- placement invariants (fire only on a role-separated machines block, self-skip
on the base bundle): no dangling to:; LXD->control, ceph-osd->storage,
nova-compute->compute; num_units>=2 spread across that many DISTINCT machines
(anti-affinity); ceph-osd==storage count, nova-compute==compute count.
Harness 15/15 (7 new behavioral cases); gauntlet ALL GREEN (78); repo-lint 0 fail.
Machines-block overlay merge is confirmed at `juju deploy --dry-run` (VERIFY-LIVE).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUjEb7onHpdqFHUnio6iVw
|

D-135 amendment: DC1 interim apt caching proxy (dc-cache-proxy.sh)
...
Operator-ruled 2026-07-24 (GA-R5, utterance quoted in D-135): DC1 gets an
interim apt caching proxy (apt-cacher-ng) to unblock its build without waiting
on the full ~950 GiB debmirror; DC0 stays the full-mirror deployment under test;
DC1 proxy is replaced by a full mirror afterward. Both artifact-delivery models
thus get exercised this rehearsal (Roosevelt input, D-132/D-133).
- scripts/dc-cache-proxy.sh: site-keyed check/install; apt-cacher-ng proxy mode
at the D-134 utility .4:3142; reuses the <site>-mirror-net layer (fails loud if
absent); caches archive/security/UCA, consumed via juju apt-http-proxy.
- tests/dc-cache-proxy/run-tests.sh: 15 static cases, 15/15 PASS.
- D-135 AMENDED (design-decisions.md) + CURRENT-STATE Stage-4 DC0/DC1 split.
- DC1 debmirror PAUSED at ~330 GiB (kept dormant as fallback); measured that the
vcloud uplink was NOT the shared bottleneck (pausing dc1 did not speed dc0).
Feasibility recon'd read-only first (apt-cacher-ng installable, upstreams 200 via
edge, port free). Live install on the DC1 rack is the separately-gated mutation.
repo-lint 0 fail; gauntlet ALL GREEN (78).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUjEb7onHpdqFHUnio6iVw
|

caveman: disable on live host + SEC-017 + fail-closed compress guardrails
...
Council-reviewed follow-through on the caveman plugin (operator accepted the
recommendations). Three gated deliverables:
1. DISABLED on the live host: enabledPlugins."caveman@caveman"=false at user
(~/.claude, uncommitted) + committed repo scope; env CAVEMAN_DEFAULT_MODE=off
retained; marketplace kept for deliberate re-enable. Stops the per-turn
third-party hook execution (which ran regardless of mode=off) at next
session start.
2. SEC-017 opened (docs/security-ledger.md): supply-chain re-verify obligation
pinning SHA 0d95a81 + self-remeasured baseline hashes; register = OPS (no
D-number per GA-R3; precedent D-129). Open SEC 12->13, reconciled at Stage 4
close (not an L10 trigger; CURRENT-STATE untouched).
3. Guardrails: repo-lint L11 FAILs on any *.original.md (caveman-compress
residue), opt-out marker + harness T42-T44 (45/45 PASS); .claude/settings.json
deny on Bash(*python3 -m scripts*)+Bash(*caveman-compress*); CLAUDE.md
"Tooling guardrails" prohibiting the compressor against any repo-tracked
prose. Rejected the proposed plugin-hash-baseline-in-repo-lint (layering
violation; drift belongs in the SEC-017 re-verify duty).
Harness-config + governance only; no cloud mutation. repo-lint 0 fail;
gauntlet ALL GREEN (77). Changelog: docs/changelog-20260724-caveman-disable.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUjEb7onHpdqFHUnio6iVw
|
| 2026-07-23 |
Delivery batch: lib-hosts VR1 arms, D-133 guards, appendix-A pf entry, DoD 8-9 (gauntlet 77 GREEN)
...
lib-hosts vr1-dc0/vr1-dc1 populated from the measured identity table
(tofu-name keys, pinned boot MACs, D-134 octets, per-DC power URIs +
tags) + host_sysid_by_bootmac (the VR1 resolver) + one-selection guard;
dc-selector rewritten, 48 PASS. reenroll-hosts + carve-host-interfaces
gain explicit vr1-* refusals (VR0 flows superseded by D-133 -- populated
arms must not enable them). lib-net vr1-dc0 VID caveat. Appendix-A:
edge pf-never-regenerated symptom (masking trap named). Phase-2 DoD:
items 8 (filter reload + LAN egress probe) + 9 (dc-mirror), item 4
range corrected to D-134 .201-.254. CURRENT-STATE same-commit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUjEb7onHpdqFHUnio6iVw
|