net-kingdom/SECURITY-COMPANION.md
tegwick 66dc491dc0
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Accept the security layer model; companion v0.2 to the repository root
The standard is accepted at v0.7 on the owner's decision. §14 keeps two things
apart, as ops-warden asked: boundary assent, given by four repositories at the
version named in each record and undisturbed since; and revision review, where
all four reviewed v0.6 and every change in v0.7 is the adopted remedy of a
finding they raised. What is not claimed: nobody has reviewed v0.7 as text.

Accepting a standard nobody has re-read is deliberate. The estate will learn
more from using it than from another round of prose, and the v0.7 changes were
requested rather than invented. Findings against the accepted text stay
welcome — that is §12's normal business, not an exception.

The companion moves from canon/standards to the repository root as
SECURITY-COMPANION.md and becomes v0.2, so onboarding starts at the front door
rather than three directories down. One copy, not two: a second copy of a fact
is how the estate gets two sources for it.

v0.2 closes the gap access-engine found in v0.1 — it said publish your stance
map without saying where, and omitted the inventory obligation, so a repository
could satisfy it faithfully and no register would learn of its stance. It also
carries what v0.7 added: the corrected PEP obligations, the evidence threat
decomposition with its stated residual, cadence as MUST for load-bearing
sources with heartbeat for rare ones, the four agent rules and the glas-harness
seam, and the Railiance axes with their unsettled mapping.

It points readers at ops-warden for how to get things done. The companion says
what the rules are; ops-warden stewards the paths through them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 2564823@bnt-lap001
Assistant-Session: 2a7ed827-4928-4b9f-8613-9135c9cadfe9
2026-08-29 11:28:49 +02:00

10 KiB

id type title domain status version companion_to owner publication_owner created updated review_interval standard_token
netkingdom-security-companion-v0.2 standard-companion NetKingdom Security — Working Companion v0.2 netkingdom accepted 0.2 canon/standards/security-layer-model_v0.7.md gate-house net-kingdom 2026-08-29 2026-08-29 3m security-companion_v0.2

NetKingdom Security — Working Companion

Start here. This is the operative form of canon/standards/security-layer-model_v0.7.md (accepted): the same rules, without the change log or the review history.

The statute governs where the two disagree. A disagreement is a finding — report it to gate-house rather than working around it.

For how to get something done in NetKingdom — which lane, which credential, which route — ask ops-warden. This document says what the rules are; ops-warden stewards the paths through them.


1. The four layers

Layer You are this if you produce Deterministic
Taxonomy terms, semantic contracts, standards n/a
Tooling state and persistence yes
Engine a deterministic API for one modeled concept yes
Staff specifications, decisions, workplans, tasks no

One test decides it: given the same authoritative inputs, do you always return the same result? If your core function is inference or judgment you are Staff, however much of your work happens at runtime.

Engines carry a role — PDP (decides; access-engine only), PIP (supplies facts as claims), Evidence (audit-core), Lifecycle (an API over Tooling it owns). A new engine is a PIP unless the statute is amended.

2. Declare your layer

In your INTENT.md frontmatter, plus prose in your own voice in the body. A layer someone else stated about you is not a declaration.

layer: Staff          # Taxonomy | Tooling | Engine | Staff
role: null            # Engines only: PDP | PIP | Evidence | Lifecycle

Working references, both offered estate-wide: ops-warden's layer.yaml, scripts/check_layer_conformance.py, tests/test_layer_conformance.py; kings-guard's adaptation of the same for a repository with no Tooling contacts at all.

Contest the proposed layer if it is wrong. Three repositories have returned corrections that changed the standard; one talked us out of an exception we had offered. A correction is worth more than a label.

3. The rules that bind everyone

  1. One decision point. access-engine renders authorization decisions. No other repository, in any layer, renders or caches one.
  2. Compiled data that determines an outcome is still deciding. A registry, cache, or schema that resolves a result before the engine runs decided early.
  3. Doctrine arrives as a claim. Anything changing an outcome — authority ceiling, zone stance, posture, maturity level — reaches the decision as a request claim or a versioned policy rule. Never a side channel.
  4. Adaptive systems may only tighten. Reduce, step up, request containment; never manufacture authority.
  5. Staff never touches Tooling directly. Act through Engine APIs. See §4.
  6. Every allow has a lifetime — a TTL, or a binding to a session or obligation that ends.

4. If you touch Tooling

"Tooling" means a system catalogued as Tooling in statute §4 — today key-cape and OpenBao. Uncatalogued infrastructure (State Hub, llm-connect) is outside the rule, but list it anyway so your conformance check is total. That carve-out sunsets: an uncatalogued store another layer reads must, within two review intervals, be catalogued or declared a gap.

Shape When You must
Read-only diagnostic no engine exposes the read declare it; no writes; it is a gap to close
Conduit you run the owner's tool under the caller's identity present no credential of your own, widen nothing, stay reconstructable as the caller
Declared gap you must contact Tooling and no engine exposes it declare capability, intended_owner, blocked_on, review — machine-readably

A conduit presenting its own token is not a conduit. A declared gap is tracked non-conformance — but declaring beats hiding, and it is never scored below silence.

There is deliberately no "operator of third-party Tooling" shape. Someone must run OpenBao, and that stays a declared gap whose review keeps returning, because a clean operator shape would turn a tracked gap into a permanent allowance.

5. If you cause side effects (you are PEP-shaped)

Being PEP-shaped does not change your layer. ops-warden issuing a certificate and ops-mason opening a route are both Staff and both PEP-shaped.

  1. No side effect without a decision record naming the request it was rendered for — or your declared stance permits proceeding and you record the application of that stance in its place. A fail-open result is metadata, never silence.
  2. Do not replay a verdict outside its own binding and lifetime. Within them it is the decision being used as issued. The test is mechanical: replay is permitted iff the canonical request digest matches and the lifetime holds. Caching a DENY is permitted where the refusal is recorded against the request refused and the cache lifetime is declared.
  3. Publish your unreachable-engine stance map — total, per zone or equivalent, no implicit default, no per-call discretion. Publish it at a path named in your layer declaration, and register it in statute §13.1 — a map only you can read is not published. The published map MUST equal shipped behaviour; assert that with a test. Reference: ops-warden ADR-0009 + pep-stance.yaml.
  4. Stay reconstructable, within the bound in §6.

If access-engine is reachable but degraded, the fallback is the engine's. If it is unreachable, the behaviour is necessarily yours — which is why it is declared in advance rather than decided in the moment.

6. What you may never claim about evidence

An append-only archive with a verified chain proves records were not altered or truncated after arrival. It proves nothing about an event never sent.

  • ✗ "the audit record proves it happened"
  • ✗ "there is no record, so it did not happen"
  • ✓ "the archive proves the records it holds were not altered or truncated after arrival"

Which control covers which threat:

Threat Covered by
Accidental omission (crash between mutation and emit) atomic emission via a local outbox — prevented
Adversarial omission (a compromised source suppresses) cadence and reconciliation — detected after the fact
Adversarial omission at a compromised source nothing prevents it. Known residual

If a control's soundness depends on an event being present, that evidence is load-bearing: emission must be atomic with the state change, queued locally, and you MUST declare an expected cadence. For rare load-bearing events — revocations, denials, containment — rate monitoring cannot work, so the required form is reconciliation or a heartbeat: a positive claim that can itself go missing.

Otherwise evidence is attributive: seek atomicity, and if you trade it away deliberately, declare the trade and never describe the trail as complete.

7. If you are an agent

Same layer as your human colleagues, different blast radius:

  1. No standing credential. Authority is per task, time-bounded, attributable to the principal you act for.
  2. Tool use is a conduit or an Engine API. There is no third route. Tool availability is not permission — a callable tool means the operation exists, not that you may invoke it.
  3. Your memory is not a state plane. Memory, tool-call traces, and prompt caches must not become state another layer depends on unless catalogued.
  4. Every action is reconstructable as the caller's action.

Session semantics — session loops, tool policy, harness routing, model selection — are glas-harness's, not this standard's. Rule 2 is the seam between them, and neither side is sufficient alone.

8. Conformance: four states

State Meaning
Conforming no Tooling contact, or only declared diagnostic/conduit shapes
Blocked-clean the capability does not exist because no engine exposes it, and you make no Tooling contact
Declared gap a declared Tooling contact — tracked non-conformance
Undeclared violation anything else

Blocked-clean is not worse than conforming. Declining a shortcut and leaving a capability at zero is compliance at cost, and will never be ranked below a repository that quietly opened a client and said nothing.

9. If you operate workloads (Railiance)

Operations belong to Railiance (railiance-master), not to NetKingdom. A workload is a managed running deployable, operated through four axes: railiance-* ownership, rail-* execution contract, rapp-* managed package, reef-* substrate. rein-* is not a fifth axis — reins are glas-harness agent-harness backends.

What holds for any Railiance consumer of NetKingdom security: decisions come from access-engine and nowhere else; approvals are objects in approval-engine consumed as claims; credentials come from secrets-engine after a decision; evidence goes to audit-core under §6's bound; anything causing a protected side effect is PEP-shaped and owes §5.

How the axes map onto the layer model is not settled — see statute §20.3. Do not assume a mapping; raising the question is welcome.

10. Two things the estate cannot do yet

Stated so nobody plans around a capability that does not exist:

  • Nothing is observed in production. kings-guard has reported it has never seen a real event. Do not cite "observed in operation" as evidence.
  • Nothing can be contained automatically. There is no actuation surface — no API to reduce authority, require step-up, or isolate a workload. The capability is at zero, not degraded, and it is nobody's gap to close alone.

Statute: canon/standards/security-layer-model_v0.7.md — accepted 2026-08-29. Owner: gate-house. Guidance on getting things done: ops-warden.