Assessment in history/2026-08-29-layer-model-v04-review.md. No objection to the ruling; both ops-warden amendments were adopted (5.2 conduit, 5.3 declared gap). Three findings, one against us. The one against us is real. 9.6 requires emission atomic with the state change for load-bearing evidence. ops-warden ca.py carries `pass # audit must not block signing` and AuditTrail.md advertises that the trail never blocks the primary action, so a failed append loses the event while the cert still issues -- a suppressed event leaving the chain intact, which is exactly what 9.6 describes. Whether to make it atomic is gate-house doctrine, not ops-wardens call: it would give the estates operational access lane a new dependency on its own evidence store. But one half of the fix is ours regardless -- the trail must not be read as complete. AuditTrail.md now says absence of a record is not evidence of absence, which it did not. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YWBMovyFoy9RRrfL7zKvPJ Assistant: claude-code Assistant-Model: opus Assistant-Process: 4014535@bnt-lap001 Assistant-Session: d0036016-73e8-4da1-8e47-563e3ab39a3c
6.8 KiB
Security Layer Model v0.4 — ops-warden's review
Date: 2026-08-29
Reviewed: net-kingdom/canon/standards/security-layer-model_v0.4.md (accepted)
Prior position: ADR-0010, assent to v0.1 (WARDEN-IN-0001)
Outcome: no objection to the ruling; three findings, one of them against ops-warden.
What v0.4 did with ops-warden's amendment
Both §5 asks from ADR-0010 were adopted.
§5.3 declared engine gap is the amendment ops-warden offered, adopted with the
four fields intact (capability, intended_owner, blocked_on, review), the
rationale preserved — a rule offering no lane for a real sanctioned case gets
satisfied by relabelling rather than by closing the gap — and the framing that
matters most kept explicit: a declared gap is tracked non-conformance, not
conformance. ops-warden's delegation machinery is cited as prior art.
§5.2 conduit resolves the question ops-warden flagged rather than assumed. The
test is the supplied-authority property, which is the right test: it turns on what
the repository presents, not on what it touches. "A conduit that presents its own
token is not a conduit" is a sharper statement of ADR-0002 than ADR-0002 makes.
This created an obligation ops-warden had not met. §5.3 requires the fields
machine-readably and §11 makes the mapping a mechanical check; ops-warden's
declaration was prose in INTENT.md. Fixed in this pass: layer.yaml,
scripts/check_layer_conformance.py, tests/test_layer_conformance.py. The
checker found three undeclared modules on first run, all false positives — help
text, a docstring, and the doubles library that simulates bao — which is why
it now matches invocation shapes rather than the word.
Finding 1 — §9.1 and §5.3 disagree, and ops-warden's §4 row is the instance
§9.1: a Staff repository MUST NOT be catalogued in §4 as owning a capability that requires a Tooling contact no engine exposes; where intended but unbuilt, the entry MUST be marked pending and the gap declared under §5.3.
ops-warden's §4 row reads operational access lanes, stewardship, runbooks; SSH certificate issuance — with no pending mark. And §13 lists SSH-CA signing write
(VaultCA, bao kv put) — declared by ops-warden — intended owner secrets-engine.
So the catalog asserts ownership of a capability that requires a Tooling contact no
engine exposes, unmarked. By §9.1's own text that is a defect. But the available
fix is worse than the defect: marking it pending would be false. SSH issuance is
production-verified and in daily use. pending would tell a reader ops-warden does
not yet do the one thing it demonstrably does.
The root cause is that §9.1 collapses two different states:
| State | Example | Capability today |
|---|---|---|
| No route exists at all | kings-guard containment (§9.2) | zero |
| Route exists via a declared §5.3 gap | ops-warden SSH issuance | working, tracked |
§5.3 exists precisely to sanction the second. §9.1 was written for the first — it was raised by kings-guard, about containment, and correctly fixed for that case. Applied to the adjacent case it produces a false catalog.
Recommendation: give §9.1 two marks rather than one — pending where no route
exists, and declared-gap where the capability is discharged under §5.3 and
registered in §13. Both are honest; today's binary forces a choice between a false
label and an unmarked violation.
This is the §12 loop working as designed, and §12 already says so: a finding that a rule is unsatisfiable is a success of the loop.
Finding 2 — §5's scope is undefined for infrastructure §4 does not catalogue
§5 forbids a direct client for a Tooling-layer system. §4 catalogues the security
estate, and only key-cape and OpenBao are Tooling rows.
ops-warden holds an HTTP client for the State Hub and for llm-connect
(src/warden/worker.py). Neither appears in §4. Both are infrastructure a Staff
repository holds a direct client for.
The question is not rhetorical, because the answers diverge sharply:
- If they are Tooling, then every Staff repository in the estate is in undeclared violation on adoption day — they all write progress events — and §11's second mechanical check fails estate-wide.
- If they are not, §5 should say so, because "a Tooling-layer system" reads considerably broader than "a repository in the §4 Tooling rows".
ops-warden has recorded both under non_tooling_clients in layer.yaml with the
reasoning stated, rather than resolving it unilaterally. The scope is gate-house's
to set.
Finding 3 — §9.6 lands on ops-warden, and ops-warden does not satisfy it
This is the one against us, and it is the most consequential item in the review.
§9.6 consequence 1: any system whose evidence is load-bearing MUST make emission atomic with the state change it records. An archive cannot retrofit completeness.
ops-warden's audit emission is deliberately non-atomic. src/warden/ca.py:90
carries pass # audit must not block signing, and wiki/AuditTrail.md states the
trail "never blocks the primary action". If the audit append fails, the
certificate is still issued and the event is simply lost — a suppressed event that
leaves the chain perfectly intact, which is the exact failure §9.6 describes.
That was a considered availability choice: an audit-disk problem should not remove production host access. §9.6 now makes it a conformance question, and the trade is real in both directions:
- make emission atomic → an audit write failure fails the sign, and the estate's operational access lane acquires a new dependency on its own evidence store;
- leave it → signing evidence cannot be treated as complete, and anything reasoning from "there is no record of a sign" is unsound.
ops-warden has not changed it, and is not going to decide this alone — §9.6 is
estate doctrine and the question is whether SSH signing evidence is load-bearing in
gate-house's sense. What ops-warden can say is that the second horn is currently
true and undocumented: wiki/AuditTrail.md does not warn that absence of a record
is not evidence of absence. That correction is ops-warden's regardless of the
ruling, and is the smaller half of the fix.
Note also that §5.2 requires a conduit action to be "reconstructable as the caller's action in audit" — an audit-dependent claim, and therefore bounded by §9.6. Worth a cross-reference so the two rules do not drift apart.
Offered
layer.yaml + check_layer_conformance.py + test_layer_conformance.py is a
working reference implementation of §5.3 and of §11's second mechanical check. Eight
of fifteen estate repositories have yet to declare (§14). If it is useful as a
pattern to point them at, it is offered — as the delegation machinery was.