# Security layer model — ops-warden's assent (WARDEN-IN-0001) **Date:** 2026-08-28 **Intake:** `WARDEN-IN-0001` **Requested by:** gate-house, ratified as `GH-DEC-2026-001` **Standard:** `net-kingdom/canon/standards/security-layer-model_v0.1.md` (proposed) **Outcome:** assent to all three items; one declared non-conformance and one proposed amendment to the standard. --- ## What was asked gate-house asked ops-warden to assent to three boundary items: 1. **ops-warden is Staff**, bound by §5 — Staff acts only through Engine APIs and never holds a direct Tooling client. 2. **Doctrine versus runbook** — the security curriculum moves to gate-house; the `NetKingdom Security Literacy` section in `INTENT.md` becomes lane-specific runbooks that reference gate-house doctrine rather than restating it. 3. **The access lane / access rule demarcation** (§8) — ops-warden and ops-mason own *lanes* (how a worker reaches a host); access-engine owns *rules* (whether they may). This is the condition attached to renaming flex-auth to access-engine, so ops-warden effectively holds a veto on that name. Plus: add gate-house to the literacy and routing tables, and say so if moving the curriculum out leaves ops-warden unable to instruct its own workers. --- ## Item 1 — Staff, and the §5 problem it exposes **Assent to the layer.** Staff is the right assignment and not a demotion. ops-warden's artifacts are exactly what §3.4 describes: routing decisions, workplans, runbooks, an audit trail. Its one production lane is non-deterministic in the sense that matters — it is an operator front door, not a contract. **But §5 is violated today, and by the one lane ops-warden permanently owns.** The rule is deliberately greppable, so grepping is the honest response: | Path | Tooling contact | Kind | Whose credential | | --- | --- | --- | --- | | `src/warden/vault.py` (`VaultCA.sign`) | `POST /v1//sign/` | **write** | broker-issued token held by ops-warden's process | | `src/warden/desk.py` | `bao kv put` (paste-once provisioning) | **write** | founder's, at the desk | | `src/warden/taint.py` | `bao kv metadata get` | read (metadata only, never data) | caller's | | `src/warden/proxy.py` (`warden access --fetch/--exec/--wrap`) | catalog `fetch_command` | read | **the caller's own** | Two of these are not really ops-warden's clients. `proxy.py` runs the owner's tool under the caller's identity and supplies no authority of its own — that is `ADR-0002`, conduit not broker, and it is arguably outside §5's target. `taint.py` reads metadata only, and fits §5's read-only-observation allowance once declared. **`VaultCA` does not have that defence.** It is a direct OpenBao client, in a Staff repository, performing a write, presenting a token from its own environment. It is production-verified and it is the SSH lane — the single thing ops-warden owns permanently. Under §5 as written, adopting this standard puts ops-warden's core lane in violation on the day it is adopted. The escape hatch §5 offers does not fit: it covers *read-only observation for diagnostics*, and signing is a write. The route §5 prescribes does fit — > *A Staff repository needing a capability no engine exposes MUST raise that as an > engine gap, not solve it locally.* — and no engine exposes SSH certificate signing. `secrets-engine` owns credential abstraction, custody and lifecycle, which is the layer this belongs in, but it fronts no SSH-CA API today. **So ops-warden assents and declares the non-conformance rather than negotiating an exemption.** `VaultCA` is recorded in `INTENT.md` as a declared §5 exception with a named intended owner (`secrets-engine`), a blocker (no SSH-CA engine surface), and a review date. That is `ADR-0003` — cover gaps, never silently own them — applied to ops-warden itself instead of to someone else's lane. ### Proposed amendment to the standard §5 has exactly one shape for a Staff repository that legitimately touches Tooling: read-only diagnostics. That shape is too narrow to describe the estate as it exists, and a rule with no lane for a real, sanctioned case gets satisfied by relabelling rather than by closing the gap. Recommend §5 gain a second shape: a **declared engine gap** — a Staff repository MAY hold a Tooling client for a capability no engine exposes, provided it is declared in `INTENT.md` with an intended owner, the blocker, and a review date, and provided the declaration is machine-readable so the conformance check in §10 can distinguish a tracked gap from an undeclared violation. ops-warden already runs this machinery for other repositories' lanes: 27 catalog entries carry `delegation:` with `intended_owner` and `blocked_on`, and `warden route gaps` lists them (WP-0030). It is offered, not imposed — the standard is gate-house's. --- ## Item 2 — Doctrine versus runbook **Assent.** The `NetKingdom Security Literacy` section is what gate-house says it is: evidence that the curriculum had no owner, so it accreted in whatever `INTENT.md` was open. That is the same failure `risk-nexus` names for findings and the same one `ADR-0001` prevents for catalog procedure. ops-warden has argued this rule twice against other repositories; it applies here. The boundary, drawn precisely: | Moves to gate-house | Stays with ops-warden | | --- | --- | | Why the planes are separated; the authority model | Which subsystem owns which credential need | | What "posture", "zone", "authority ceiling" mean | How to obtain a cert, a lease, a login — per lane | | The security curriculum a worker is taught | The runbook a worker executes | | Doctrine a lane must conform to | Evidence of conformance for ops-warden's lanes | **gate-house's test question, answered: no, it does not leave ops-warden unable to instruct its workers — and the reason is worth recording.** What actually instructs an ops-warden worker is not the prose in `INTENT.md`. It is `warden plan ""`, `warden route find`, and `.claude/rules/credential-routing.md`, which is inlined into every repository's agent instructions precisely because credential routing is high-frequency and high-risk. That surface is executable, lane-specific, and unambiguously runbook. It does not depend on the literacy table, and moving doctrine out does not weaken it. If anything the move improves it: the literacy table has been a second, prose copy of what `registry/routing/catalog.yaml` states machine-readably, which is the double-source failure `ADR-0001` exists to stop. **One thing must not move with it.** `.claude/rules/credential-routing.md` stays inline in this repository and in every other. It is not doctrine and not a curriculum; it is the anti-pattern list an agent needs *before* it acts, and a reference to a document in another repository would not be read in time. --- ## Item 3 — Access lane versus access rule **Assent, unconditionally, and the veto on `access-engine` is not exercised.** ops-warden is already built this way. `ADR-0005` implements one lane narrowly and routes everything else; `ADR-0002` makes it a conduit that never decides; `ADR-0009` has ops-warden compile membership attributes and apply a zone's failure mode while flex-auth owns the stance. ops-warden consumes decisions; it has never rendered one. The demarcation costs nothing because it describes what is already true. `access-engine` is also the better name. ops-warden's own routing table has had to say "authorization" for the decision and "access" for the route for a year, and the collision is visible in every playbook. **One operational condition, on execution rather than on the ruling.** The rename is 598 references across 82 files in this repository alone — catalog `owner:` fields, `registry/flex-auth/`, `src/warden/policy.py`, the production registry snapshot builder, playbooks, and the `.claude/rules/` files that other repositories inline. Ops-warden asks for a deprecation window in which both names resolve, rather than a flag day; ops-warden will do its own migration inside that window. This is a request about sequencing, not a reservation about the name. --- ## Item 4 — gate-house is missing from every table Correct, and fixed in this pass. gate-house is added to the literacy/routing table in `INTENT.md` as the owner of doctrine, invariants, authority context, and conformance review — with the routing rule stated explicitly: **doctrine and authority-model questions go to gate-house; policy decisions continue to go to access-engine.** Those are different questions and the distinction is the whole point of §6. --- ## Recorded as - `ADR-0010` — ops-warden is Staff; lanes not rules; the declared §5 exception - `INTENT.md` — layer declaration, reworked routing table, gate-house row - `WARDEN-IN-0001` — closed, outcome `assented`