# Security layer model v0.7 — alignment, scope revision, and gap assessment **Date:** 2026-08-29 **Standard:** `net-kingdom/canon/standards/security-layer-model_v0.7.md` — **accepted** **Companion:** `net-kingdom/SECURITY-COMPANION.md` v0.2 **Scope of this review:** align `INTENT.md`, revise `SCOPE.md`, assess scope against intent and against the shipped implementation, and raise the work. **Result:** `INTENT.md` and `SCOPE.md` updated; nine gaps found, one of them a live overclaim; `AUDIT-WP-0009` raised. --- ## 1. Disposition of audit-core's v0.6 findings All three landed in v0.7: | v0.6 finding | v0.7 | | --- | --- | | atomicity closes accidental, not adversarial, omission | §9.6 gained the three-row **threat decomposition**, including the explicit *nothing in this model prevents it* residual | | cadence is a SHOULD and is the only control in its class | §9.6 cadence is **MUST for load-bearing sources**, with positive reconciliation or a heartbeat as the required form for low-volume classes | | §3.3's Evidence row states a trade as a property | restated as an estate trade, leaving independent-recording-before-effect raisable as a declared exception | The standard is now accepted. What follows is not review of gate-house's text but assessment of audit-core against it. ## 2. What v0.7 binds audit-core to Audit Core is **Engine / Evidence** (§3.3, §4). Its obligations: 1. Declare the layer in `INTENT.md` **frontmatter** plus prose in its own voice (§11, companion §2). `layer.yaml` alone does not discharge this. 2. Render and cache no decision; expose no approval-validity query (§6, §9.4). 3. Never claim more than the archive delivers, in either direction (§9.6). 4. **Support** the §9.6 obligations it argued for: the load-bearing/attributive distinction, declared emission cadence, and reconciliation or heartbeat for low-volume load-bearing classes. 5. Register `approval-engine` as a distinct source (§9.4, `AUDIT-IN-0001`). 6. Keep the §5 conformance check total by listing infrastructure contacts even where uncatalogued (companion §4), noting that carve-out sunsets within two review intervals. Point 4 is the one with teeth. audit-core argued cadence up from SHOULD to MUST and specified the reconciliation form. **A source cannot declare a cadence to a system with nowhere to put it.** Having won the obligation, audit-core owes the surface that makes it dischargeable. ## 3. Scope versus intent `SCOPE.md` was a `statehub register` stub — *"audit-core exists to provide the capability described in INTENT.md"* — carrying no boundary at all. Against an `INTENT.md` that had grown a Layer section, an Approval Evidence section, and a corrected principle 6, the gap was total: **every statute-fixed prohibition lived only in INTENT and none of it in SCOPE**, which is the file a contributor checks before adding a surface. `SCOPE.md` is rewritten to carry the permanent boundaries explicitly — no decision, no validity query, no operative approval state, no completeness claim — and to separate them from the merely-not-yet. The distinction matters: §16 ruled the stronger-custody gap **closed**, so WORM and `data.archive` are now *not ours* rather than *not yet*, and the old scope line implying a pending archive requirement was stale. Intent and scope now agree. The disagreement that remains is between both of them and the code. ## 4. Gaps ### G1 — `tamper_evidence` is claimed unconditionally *(headline)* `audit_core/postgres_backend.py:306` returns `tamper_evidence=True` as a constant. `docs/integrity.md` permits that claim **only when**: 1. `verify` exists and fails on a rewritten row; **and** 2. an external head attestation exists, and verify-against-attestation reports a missing cited head as a break. Condition 2 is operational, not structural. The only attestation on record is `docs/evidence/chain-head-20260816.json` — thirteen days old — and `deploy/` contains no job that renews it. Every sender reading `/readyz` is therefore told audit-core has a property whose precondition is unverified and probably stale. This is §9.6's defect turned inward: **audit-core claiming more than its bound delivers**, in the exact idiom it corrected in gate-house's own doctrine twice. It is the highest-priority gap for that reason, independent of severity. Fix: derive the flag from live attestation state, and make a stale or absent attestation degrade the claim rather than leave it standing. ### G2 — no load-bearing / attributive classification `SenderIdentity` (`audit_core/senders.py:30`) carries `sources`, `tenants`, `may_write`, `may_read`, `secret_policy`, `expires_at`. Nothing records which kind of evidence a source produces, so audit-core cannot tell which sources owe a cadence. §9.6's central distinction is unrepresentable. ### G3 — no cadence declaration Nothing accepts, stores, or evaluates a declared emission cadence. `grep` for `cadence` across `audit_core/`, `docs/`, and `tests/` returns nothing; the `reconcile` hits are duplicate-event reconciliation, an unrelated concept. Depends on the §17 emission-cadence schema, which `kings-guard` is drafting. ### G4 — no heartbeat, and no missing-heartbeat finding The required form for low-volume load-bearing classes does not exist. This is the gap that matters most substantively: it is the only control covering adversarial omission for exactly the rare negative events — revocations, denials, containment — where suppression is most valuable and least visible. ### G5 — no reconciliation surface A source cannot compare its own state transitions against audit-core's event count per class, because no endpoint exposes those counts. `GH-WP-0002-T04` is the reference instance and has no counterpart here. ### G6 — stream-completeness findings have no home `/v1/dead-letters` and `/v1/secret-findings` exist; a stream-observation finding has no surface. INTENT principle 10 already says degraded audit streams are themselves audit and operations events — the principle is in place and the mechanism is not. ### G7 — `approval-engine` not registered Committed to in `AUDIT-IN-0001`. Needs sender registration, the four event classes, tenancy mapping, retention profile, and `secret_policy`, onboarded under principle 4 — declared policy, not merely arriving events. Not blocking: `approval-engine` is not yet emitting. ### G8 — no negative test on the approval-validity prohibition §9.4's MUST NOT is currently honoured by absence. The estate's own idiom for a published-equals-shipped property is a test (§6.4 obligation 3 requires exactly that of a PEP stance map). A prohibition worth stating is worth asserting. ### G9 — Tooling contact list is empty rather than total `layer.yaml` declares `tooling_contacts: []`, true under §5 as written since audit-core is an Engine holding no `key-cape` or OpenBao client. But companion §4 asks that uncatalogued infrastructure be listed anyway so the check is total, and the carve-out sunsets within two review intervals: `platform-pg` is a store another layer reads. Listing it now costs nothing and pre-empts the sunset. ## 5. What is already conforming Not everything is a gap, and the assessment would be dishonest without this: - **No decision surface exists.** The §6 prohibition is met in fact. - **The integrity contract is honest.** `docs/integrity.md` states the proof bound, names the attacker class it does not cover, and explicitly disclaims WORM and `data.archive`. G1 is a defect in the *code's* claim, not the document's — the doctrine was right and the implementation drifted from it. - **Custody claims are otherwise sober**: `custody_class=operational` rather than `archive`, recovery cited to the platform window rather than `retention_days`. - **Tenant isolation and redaction** are built and tested. - **`immutable=True`** is correctly qualified in-code as not a claim against the database owner. The pattern is worth naming: where audit-core wrote doctrine it was accurate; where a value was hard-coded it drifted optimistic. G1 is the one place the two diverge, and it diverges in the direction the estate is least able to detect. ## 6. Priority | Gap | Priority | Why | | --- | --- | --- | | G1 `tamper_evidence` | **high** | live overclaim to every sender; audit-core's own doctrine violated inward | | G2 classification | high | prerequisite for G3–G5 | | G4 heartbeat | high | only control covering the adversarial residual for rare events | | G3 cadence | medium | blocked on the §17 schema | | G5 reconciliation | medium | `GH-WP-0002-T04` counterpart | | G8 negative test | medium | cheap; closes a MUST NOT by assertion | | G6 findings surface | medium | needed for G3/G4 to be actionable | | G7 approval-engine source | low | not blocking; no emitter yet | | G9 contact list | low | pre-empts a sunset | Raised as `AUDIT-WP-0009-evidence-role-conformance.md`.