Align to Security Layer Model v0.7; revise SCOPE; raise AUDIT-WP-0009
The standard is accepted at v0.7 and all three of audit-core's v0.6 findings landed in it (§9.6 threat decomposition, cadence MUST for load-bearing sources with reconciliation/heartbeat for low-volume classes, §3.3's Evidence row restated as an estate trade). INTENT.md: layer/role declared in frontmatter as §11 and companion §2 require — layer.yaml alone did not discharge it. Layer section rewritten for the Evidence role and its obligations. New Evidence Bound section carrying the §9.6 sound/unsound forms and the three-row threat table, including the residual nothing in the model prevents. SCOPE.md: replaced the statehub register stub, which carried no boundary at all. Statute-fixed prohibitions now live here, separated from the merely-not-yet — §16 ruled the stronger-custody gap closed, so WORM and data.archive are not ours rather than not yet. Assessment found nine gaps. Headline: postgres_backend returns tamper_evidence=True unconditionally while docs/integrity.md permits it only against a live external attestation, and the one on record is 2026-08-16 with no job renewing it — audit-core overclaiming its own bound, the §9.6 defect turned inward. Also: no cadence, heartbeat, reconciliation, or load-bearing classification exists, so the obligation audit-core argued up from SHOULD to MUST is not yet dischargeable against audit-core. AUDIT-WP-0009 raised, ten tasks. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WpeL68AWHqtqPQZEXY5kFe Assistant: claude-code Assistant-Model: opus Assistant-Process: 4040362@bnt-lap001 Assistant-Session: 4fd0fd24-2ee8-4413-bd67-43bd79ca73f1
This commit is contained in:
parent
4debbd834f
commit
6eaa33699d
5 changed files with 567 additions and 38 deletions
92
INTENT.md
92
INTENT.md
|
|
@ -1,3 +1,15 @@
|
|||
---
|
||||
# NetKingdom Security Layer Model v0.7 (accepted) — §11 / companion §2.
|
||||
# Declared by audit-core, in audit-core's own voice. Machine-readable form
|
||||
# and the full conformance map: layer.yaml
|
||||
layer: Engine
|
||||
role: Evidence
|
||||
standard: canon/standards/security-layer-model_v0.7.md
|
||||
standard_version: "0.7"
|
||||
declared_by: intakes/intakes.md AUDIT-IN-0001
|
||||
declared_at: "2026-08-29"
|
||||
---
|
||||
|
||||
# Audit Core Intent
|
||||
|
||||
## Purpose
|
||||
|
|
@ -19,15 +31,31 @@ on NetKingdom to exist or operate.
|
|||
|
||||
## Layer
|
||||
|
||||
Audit Core is **Engine layer** under the NetKingdom security layer model
|
||||
(`net-kingdom/canon/standards/security-layer-model_v0.3.md`): it exposes a
|
||||
deterministic API contract and holds operational custody of the records it
|
||||
accepts.
|
||||
Audit Core is **Engine layer, role Evidence** under the NetKingdom Security
|
||||
Layer Model v0.7 (`net-kingdom/canon/standards/security-layer-model_v0.7.md`,
|
||||
accepted; working form `net-kingdom/SECURITY-COMPANION.md`). It exposes a
|
||||
deterministic API contract over a modeled concept — the audit event — and holds
|
||||
operational custody of what it accepts. Same authoritative input, same result.
|
||||
|
||||
It is explicitly **not a decision point**. Audit Core answers what was recorded;
|
||||
it never answers whether an action is permitted, and it exposes no surface that
|
||||
returns such a verdict. See `## Out Of Scope Initially` and
|
||||
`history/2026-08-28-approval-evidence-assent.md`.
|
||||
**Evidence is a role, and it carries obligations the other engine roles do not:**
|
||||
|
||||
- Audit Core is explicitly **not a decision point** (§6). It answers what was
|
||||
recorded; it never answers whether an action is permitted, and exposes no
|
||||
surface returning such a verdict.
|
||||
- An Audit Core outage **must not block the operation being recorded** (§3.3).
|
||||
v0.7 states this as a deliberate estate trade — availability of the recorded
|
||||
operation over independence of its recorder — not as a property of evidence
|
||||
engines. The consequence is accepted knowingly: a compromised source can
|
||||
suppress, and detection rather than prevention is the answer (§9.6).
|
||||
An operation whose control requirement is *independent recording before
|
||||
effect* remains raisable as a declared exception; the estate has not needed
|
||||
one, and Audit Core would want it raised rather than assumed.
|
||||
- What Audit Core may **never claim** is fixed by §9.6 and restated in
|
||||
`## Evidence Bound` below.
|
||||
|
||||
Machine-readable declaration and the conformance map: `layer.yaml`.
|
||||
Reviews: `history/2026-08-28-approval-evidence-assent.md`,
|
||||
`history/2026-08-29-security-layer-model-v0.6-review.md`.
|
||||
|
||||
## Problem
|
||||
|
||||
|
|
@ -242,6 +270,54 @@ NetKingdom must not be required for Audit Core's internal authorization model.
|
|||
Audit Core may accept NetKingdom OIDC claims when configured, but should also
|
||||
support a generic OIDC provider and local development auth mode.
|
||||
|
||||
## Evidence Bound
|
||||
|
||||
Security Layer Model v0.7 §9.6 fixes what Audit Core may claim, and the bound is
|
||||
narrower than principle 6 aspires to. `docs/integrity.md` is authoritative on the
|
||||
delivered guarantee; this section states the doctrine it must never exceed.
|
||||
|
||||
**Sound:** *the archive proves the records it holds were not altered or truncated
|
||||
after arrival.*
|
||||
|
||||
**Unsound, and Audit Core must never say or imply either:**
|
||||
|
||||
- *"the audit record proves it happened"* — the archive proves nothing about an
|
||||
event that was never sent;
|
||||
- *"there is no record, so it did not happen"* — absence of a record is not
|
||||
evidence of non-occurrence, and no control may read it as such.
|
||||
|
||||
Which control covers which threat:
|
||||
|
||||
| Threat | Covered by | When |
|
||||
| --- | --- | --- |
|
||||
| Accidental omission — process dies between mutation and emit | atomic emission via a **local** outbox at the source (§9.4) | prevented |
|
||||
| Adversarial omission — a compromised source declines to insert, deletes before drain, or drains to nowhere | cadence and reconciliation | detected, after the fact |
|
||||
| Adversarial omission at a compromised source | — | **nothing in the model prevents it** |
|
||||
|
||||
That third row is a known, accepted residual. Audit Core raised it against a
|
||||
remedy it had itself proposed, and states it here so no consumer plans around a
|
||||
guarantee that does not exist.
|
||||
|
||||
**Load-bearing versus attributive.** Where a control's soundness depends on an
|
||||
event being present or absent — a revocation, a denial, a containment action —
|
||||
the evidence is **load-bearing**: emission MUST be atomic with the state change
|
||||
at the source, and the source **MUST** declare an expected emission cadence.
|
||||
Otherwise it is **attributive**: atomicity SHOULD be sought, and where it is
|
||||
deliberately traded away the trade MUST be declared and completeness MUST NOT be
|
||||
claimed.
|
||||
|
||||
**Rate monitoring is the wrong form for rare events**, which is exactly where the
|
||||
stakes are highest — the most valuable event to suppress is the negative one, and
|
||||
revocations and denials are infrequent by nature. For **low-volume load-bearing
|
||||
classes** the required form is **positive reconciliation or a heartbeat**:
|
||||
compare the source's own state transitions against Audit Core's event count per
|
||||
class, or assert *nothing to report* as a signed positive claim that can itself
|
||||
go missing. Rate monitoring never produces a claim that can be missing.
|
||||
|
||||
Supporting these obligations is Audit Core's work, not only its senders' — a
|
||||
source cannot declare a cadence to a system that has nowhere to put it. See
|
||||
`workplans/AUDIT-WP-0009-evidence-role-conformance.md`.
|
||||
|
||||
## Approval Evidence
|
||||
|
||||
Audit Core carries the **evidence half** of approvals as a distinct source, per
|
||||
|
|
|
|||
115
SCOPE.md
115
SCOPE.md
|
|
@ -1,50 +1,115 @@
|
|||
# SCOPE
|
||||
|
||||
> This file was generated by `statehub register`. Refine it as the repository
|
||||
> boundaries become clearer.
|
||||
Boundary contract for `audit-core`, aligned to NetKingdom Security Layer Model
|
||||
v0.7 (accepted) and its working companion. `INTENT.md` says what Audit Core is
|
||||
for; this file says what it does and does not do, and is the file to check
|
||||
before adding a surface.
|
||||
|
||||
## One-liner
|
||||
|
||||
Reliable multi-tenant auto setup audit capability.
|
||||
The estate's Evidence engine: durable, tenant-aware custody of audit events,
|
||||
with an honest and bounded integrity claim.
|
||||
|
||||
## Core Idea
|
||||
## Layer and role
|
||||
|
||||
audit-core exists to provide the capability described in INTENT.md.
|
||||
**Engine / Evidence** (statute §3.3, §4). Deterministic API over one modeled
|
||||
concept — the audit event. Declared in `INTENT.md` frontmatter and `layer.yaml`.
|
||||
|
||||
Audit Core is **not** a PDP, not a PIP, and not PEP-shaped. It renders no
|
||||
decision, supplies no claim a decision consumes, and causes no protected side
|
||||
effect of its own.
|
||||
|
||||
## In Scope
|
||||
|
||||
- Maintain the repository's primary implementation.
|
||||
- Keep docs, tests, and operational metadata current.
|
||||
- Operational audit custody (`operations.audit`) and its declared recovery bound.
|
||||
**Custody and integrity**
|
||||
|
||||
- Event ingestion, validation, normalization to the Audit Core envelope,
|
||||
redaction, and append-only operational custody.
|
||||
- Sender registration and binding; tenant and scope attribution.
|
||||
- Hash-chain integrity: link, verify, chain-head attestation, and the
|
||||
`GET /v1/integrity` operator surface.
|
||||
- The honest custody claim — `custody_class`, `immutable`, `tamper_evidence`,
|
||||
`recoverable_days` — stated at no more than `docs/integrity.md` delivers.
|
||||
- Retention profiles, search and export entitlements, dead-letter and
|
||||
secret-finding surfaces.
|
||||
|
||||
**Evidence-role obligations under v0.7 §9.6** *(largely not yet built — see
|
||||
`workplans/AUDIT-WP-0009-evidence-role-conformance.md`)*
|
||||
|
||||
- Recording, per source, whether its evidence is **load-bearing** or
|
||||
**attributive**, because the obligations differ.
|
||||
- Accepting and storing a source's declared **emission cadence**, and raising a
|
||||
finding when the stream falls below it — the stream observed, not only its
|
||||
contents.
|
||||
- **Heartbeat** ingestion and missing-heartbeat findings for low-volume
|
||||
load-bearing classes, where rate monitoring cannot work.
|
||||
- A **reconciliation** surface: per-source, per-class event counts a source can
|
||||
compare against its own state transitions.
|
||||
- Registering `approval-engine` as a distinct source carrying issuance, use,
|
||||
supersession, and revocation (§9.4, `AUDIT-IN-0001`).
|
||||
|
||||
**Conformance**
|
||||
|
||||
- Machine-readable layer declaration (`layer.yaml`) and a conformance test.
|
||||
- A total list of infrastructure contacts, catalogued or not, so the §5 check
|
||||
is total rather than vacuous.
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- Own unrelated adjacent systems.
|
||||
- Make irreversible operational decisions without human approval.
|
||||
- Procuring or operating S3 / Barman / WAL.
|
||||
- Booked cost or a second usage stream for `platform:audit-storage`.
|
||||
**Boundaries fixed by the statute — these are permanent, not "not yet"**
|
||||
|
||||
- **Any authorization decision.** `access-engine` is the only decision point
|
||||
(§6). Audit Core renders and caches none.
|
||||
- **An approval-validity query.** Records, yes; a verdict on whether an approval
|
||||
is still valid, never (§9.4). A consumer branching on such an answer would
|
||||
route an authorization decision through the audit fabric.
|
||||
- **Operative approval state** — the durable object, atomic supersession, single
|
||||
consumption, revocation. That is `approval-engine`'s (§9.4).
|
||||
- **Emission atomicity at the source.** Completeness at the boundary is the
|
||||
emitter's obligation; an archive cannot retrofit it (§9.6).
|
||||
- **Any claim that the archive proves an event occurred, or that absence proves
|
||||
it did not** (§9.6).
|
||||
- **Policy decision making**, per `INTENT.md`.
|
||||
|
||||
**Not owned here**
|
||||
|
||||
- Procuring or operating S3 / Barman / WAL; the `platform:audit-storage` booked
|
||||
cost or a second usage stream.
|
||||
- WORM, object lock, or ITC-CAP `data.archive`. Ruled a different store with a
|
||||
different owner (statute §16); the stronger-custody gap is withdrawn, not
|
||||
pending.
|
||||
- A `rapp.yaml` in this repo (schema requires `rapp-*`).
|
||||
- Public ingest.
|
||||
- Unrelated adjacent systems; irreversible operational decisions without human
|
||||
approval.
|
||||
|
||||
## Current State
|
||||
|
||||
- Status: production
|
||||
- Production receiver on railiance01 (`namespace audit-core`), Postgres
|
||||
- Status: production. Receiver on railiance01 (`namespace audit-core`), Postgres
|
||||
operational custody on `platform-pg`, sender `user-engine`.
|
||||
- Recovery is the platform `data.backup` window (30 days). Live `/readyz`
|
||||
reports `custody_class=operational`, `tamper_evidence=true`,
|
||||
`recoverable_days=30` (image `sha256:7febc28e…`).
|
||||
- Recovery is the platform `data.backup` window (30 days). `/readyz` reports
|
||||
`custody_class=operational`, `recoverable_days=30`.
|
||||
- Hash chain verified on 30 live events
|
||||
(`docs/evidence/chain-head-20260816.json`).
|
||||
- ITC-CAP case: `data/capability/audit-core-operational.json` at D4.
|
||||
`data.archive` is an unmet requirement.
|
||||
- Tenancy posture: `tenancy.yaml` (NetKingdom Tenancy Posture v0.1 draft-8,
|
||||
Decision 5.4). Declared `I1 A2 E1 P1 R1`, target `E3` and `R2`. E is quoted
|
||||
at 1 although the E2 mechanism is in place on both paths — the §13 E2
|
||||
artifact is adversarial and does not exist yet (AUDIT-WP-0008-T05).
|
||||
- Tenancy posture: `tenancy.yaml` — declared `I1 A2 E1 P1 R1`, target `E3`/`R2`.
|
||||
|
||||
**Known conformance gaps** (assessed 2026-08-29,
|
||||
`history/2026-08-29-v0.7-alignment-and-scope-assessment.md`):
|
||||
|
||||
- `tamper_evidence=True` is returned unconditionally by the Postgres backend
|
||||
while `docs/integrity.md` permits it only when a live external attestation
|
||||
exists. The one attestation on record is 2026-08-16 and no job renews it.
|
||||
This is Audit Core overclaiming its own bound — the §9.6 defect turned inward.
|
||||
- No cadence, heartbeat, reconciliation, or load-bearing classification exists.
|
||||
The §9.6 obligations Audit Core argued for are not yet supportable by Audit
|
||||
Core.
|
||||
- `approval-engine` is not yet registered as a source.
|
||||
- No negative test asserts the absence of an approval-validity surface.
|
||||
|
||||
## Getting Oriented
|
||||
|
||||
- Start with: INTENT.md
|
||||
- Agent instructions: AGENTS.md
|
||||
- Workplans: workplans/
|
||||
- Start with: `INTENT.md`, then `net-kingdom/SECURITY-COMPANION.md`
|
||||
- Bound on what may be claimed: `docs/integrity.md`
|
||||
- Agent instructions: `AGENTS.md`
|
||||
- Workplans: `workplans/`
|
||||
|
|
|
|||
177
history/2026-08-29-v0.7-alignment-and-scope-assessment.md
Normal file
177
history/2026-08-29-v0.7-alignment-and-scope-assessment.md
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
# 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`.
|
||||
20
layer.yaml
20
layer.yaml
|
|
@ -1,9 +1,10 @@
|
|||
# audit-core — NetKingdom security layer declaration
|
||||
#
|
||||
# Framework: net-kingdom/canon/standards/security-layer-model_v0.6.md
|
||||
# Framework: net-kingdom/canon/standards/security-layer-model_v0.7.md
|
||||
# Assent: AUDIT-IN-0001 (audit-core's own voice, per §11 "who must declare")
|
||||
# history/2026-08-28-approval-evidence-assent.md
|
||||
# history/2026-08-29-security-layer-model-v0.6-review.md
|
||||
# history/2026-08-29-v0.7-alignment-and-scope-assessment.md
|
||||
#
|
||||
# Reference form offered by ops-warden and adopted here, so §11's declaration
|
||||
# check is mechanical rather than a reader's judgment about prose. audit-core
|
||||
|
|
@ -11,7 +12,7 @@
|
|||
|
||||
schema_version: "0.1"
|
||||
framework: netkingdom-security-layer-model
|
||||
standard_version: "0.6"
|
||||
standard_version: "0.7"
|
||||
repository: audit-core
|
||||
layer: engine
|
||||
role: evidence # §3.3 engine typing
|
||||
|
|
@ -27,10 +28,19 @@ decision_surfaces_exposed: none
|
|||
# authorization decision through the audit fabric.
|
||||
approval_validity_query: forbidden
|
||||
|
||||
# §5 applies to Staff. audit-core is an Engine and holds no Tooling contact
|
||||
# requiring a §5.1/§5.2/§5.3 declaration. Its PostgreSQL custody is its own
|
||||
# operational store, not a §4 Tooling row.
|
||||
# §5 applies to Staff. audit-core is an Engine and holds no §4 Tooling contact
|
||||
# (key-cape, OpenBao). Companion §4 asks that UNCATALOGUED infrastructure be
|
||||
# listed anyway so the check is total, and that carve-out sunsets within two
|
||||
# review intervals for a store another layer reads. Completing this list and
|
||||
# adding a conformance test is AUDIT-WP-0009-T10.
|
||||
tooling_contacts: []
|
||||
uncatalogued_infrastructure:
|
||||
- id: platform-pg
|
||||
system: CNPG PostgreSQL on railiance01
|
||||
role: audit-core's own operational custody store
|
||||
read_by_other_layers: true # subject to the companion §4 sunset
|
||||
note: >-
|
||||
Not a §4 Tooling row. Listed for totality, not as a declared gap.
|
||||
|
||||
# §9.6 — the bound audit-core delivers, stated so no doctrine rests on more.
|
||||
evidence_bound:
|
||||
|
|
|
|||
201
workplans/AUDIT-WP-0009-evidence-role-conformance.md
Normal file
201
workplans/AUDIT-WP-0009-evidence-role-conformance.md
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
---
|
||||
id: AUDIT-WP-0009
|
||||
type: workplan
|
||||
title: "Evidence-role conformance under Security Layer Model v0.7"
|
||||
domain: infotech
|
||||
repo: audit-core
|
||||
status: ready
|
||||
owner: claude
|
||||
topic_slug: railiance
|
||||
created: "2026-08-29"
|
||||
updated: "2026-08-29"
|
||||
depends_on:
|
||||
- AUDIT-WP-0007
|
||||
---
|
||||
|
||||
# AUDIT-WP-0009 — Evidence-role conformance under Security Layer Model v0.7
|
||||
|
||||
## Goal
|
||||
|
||||
Make audit-core dischargeable as the estate's **Evidence engine** under
|
||||
NetKingdom Security Layer Model v0.7 (accepted), and stop it claiming a property
|
||||
its own contract does not permit.
|
||||
|
||||
Two things drive this workplan.
|
||||
|
||||
**First, a live overclaim.** `audit_core/postgres_backend.py` returns
|
||||
`tamper_evidence=True` as a constant, while `docs/integrity.md` permits that
|
||||
claim only when a live external chain-head attestation exists. The one
|
||||
attestation on record is 2026-08-16 and nothing renews it. Audit Core is
|
||||
currently telling every sender it has a property whose precondition is
|
||||
unverified — the §9.6 defect it twice corrected in gate-house's doctrine, turned
|
||||
inward.
|
||||
|
||||
**Second, an obligation audit-core argued for and cannot yet support.** v0.7
|
||||
§9.6 makes a declared emission cadence a **MUST** for load-bearing sources, with
|
||||
reconciliation or a heartbeat as the required form for low-volume classes.
|
||||
audit-core raised both, moving cadence from SHOULD to MUST. A source cannot
|
||||
declare a cadence to a system with nowhere to put it. Having won the obligation,
|
||||
audit-core owes the surface.
|
||||
|
||||
Full assessment: `history/2026-08-29-v0.7-alignment-and-scope-assessment.md`.
|
||||
Standard: `net-kingdom/canon/standards/security-layer-model_v0.7.md`, companion
|
||||
`net-kingdom/SECURITY-COMPANION.md`.
|
||||
|
||||
## Non-goals
|
||||
|
||||
Fixed by the statute; not deferred, not ours:
|
||||
|
||||
- No authorization decision surface, and no approval-validity query (§6, §9.4).
|
||||
- No operative approval state (§9.4).
|
||||
- No WORM, object lock, or ITC-CAP `data.archive` — §16 ruled the
|
||||
stronger-custody gap closed, a different store with a different owner.
|
||||
- Emission atomicity at the source, which is the emitter's obligation (§9.6).
|
||||
|
||||
## Tasks
|
||||
|
||||
```task
|
||||
id: AUDIT-WP-0009-T01
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
Make `tamper_evidence` conditional on live attestation state. Derive the flag
|
||||
rather than hard-coding it: the backend reports `True` only when a chain-head
|
||||
attestation exists, verifies against the live chain, and is within a declared
|
||||
freshness window. Stale or absent attestation degrades the claim — it does not
|
||||
leave it standing. Assert the degradation with a test, and state the freshness
|
||||
window in `docs/integrity.md` alongside the two existing preconditions, which
|
||||
today are documented but unenforced.
|
||||
|
||||
```task
|
||||
id: AUDIT-WP-0009-T02
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
Schedule chain-head attestation so the precondition T01 enforces is normally
|
||||
met. `attest-chain` exists and is operator-run; `deploy/` has no job. Add one,
|
||||
write the attestation to the logical-offsite path already used by
|
||||
`RESOURCE-WP-0002-T06` (`rapp-postgres` / Nextcloud + age) and **not** the
|
||||
Barman prefix, per `docs/integrity.md` — that copy is restored with the table
|
||||
and proves nothing. Record the cadence in `docs/integrity.md`.
|
||||
|
||||
```task
|
||||
id: AUDIT-WP-0009-T03
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
Represent the §9.6 evidence kind per source. Add `evidence_kind`
|
||||
(`load-bearing` | `attributive`) to `SenderIdentity` and the sender registration
|
||||
schema, defaulting to `attributive` — a source that has not declared is not
|
||||
silently treated as load-bearing. Where a source declares `attributive` and has
|
||||
deliberately traded away atomicity, carry the declared trade with it, because
|
||||
§9.6 requires the trade be declared where the trail is documented. Prerequisite
|
||||
for T04–T06.
|
||||
|
||||
```task
|
||||
id: AUDIT-WP-0009-T04
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
Heartbeat ingestion and missing-heartbeat findings. The required form for
|
||||
low-volume load-bearing classes, and the only control covering adversarial
|
||||
omission for exactly the rare negative events — revocation, denial, containment
|
||||
— where suppression is most valuable and least visible. Accept a signed
|
||||
*nothing to report* assertion per source and class; raise a finding when an
|
||||
expected heartbeat does not arrive. The point is a positive claim that can
|
||||
itself go missing, which rate monitoring can never produce.
|
||||
|
||||
```task
|
||||
id: AUDIT-WP-0009-T05
|
||||
status: wait
|
||||
priority: medium
|
||||
```
|
||||
Accept and evaluate a declared emission cadence per source, and raise a finding
|
||||
when the stream falls below it. **Waiting on** the §17 emission-cadence
|
||||
declaration schema, which `kings-guard` is drafting and Taxonomy will own; do
|
||||
not invent a competing shape. Cadence covers high-volume streams; T04 covers the
|
||||
low-volume load-bearing case, and the two are complementary rather than
|
||||
alternatives.
|
||||
|
||||
```task
|
||||
id: AUDIT-WP-0009-T06
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
Reconciliation surface: per-source, per-class event counts over a bounded
|
||||
window, readable by the source itself, so an emitter can compare audit-core's
|
||||
count against its own state transitions and treat divergence as a finding.
|
||||
`GH-WP-0002-T04` is the reference instance on the `approval-engine` side; this
|
||||
is its counterpart here. Respect the existing read model — `may_read`, tenant
|
||||
scoping, and no payloads in a counts response.
|
||||
|
||||
```task
|
||||
id: AUDIT-WP-0009-T07
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
Give stream-completeness findings a home. `/v1/dead-letters` and
|
||||
`/v1/secret-findings` exist; a cadence miss (T05) and a missing heartbeat (T04)
|
||||
have nowhere to surface. INTENT principle 10 already says a degraded audit
|
||||
stream is itself an audit and operations event — the principle is in place and
|
||||
the mechanism is not. Follow the existing findings-surface conventions rather
|
||||
than adding a new shape.
|
||||
|
||||
```task
|
||||
id: AUDIT-WP-0009-T08
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
Assert the §9.4 approval-validity prohibition with a negative test. It is
|
||||
currently honoured by absence, which is not the estate's idiom: §6.4 obligation
|
||||
3 requires a PEP's published stance map equal shipped behaviour *asserted by
|
||||
test*. A prohibition worth stating in `INTENT.md`, `SCOPE.md`, and `layer.yaml`
|
||||
is worth asserting in `tests/`.
|
||||
|
||||
```task
|
||||
id: AUDIT-WP-0009-T09
|
||||
status: todo
|
||||
priority: low
|
||||
```
|
||||
Register `approval-engine` as a distinct source under §9.4 and `AUDIT-IN-0001`:
|
||||
sender registration, the four event classes (issuance, use, supersession,
|
||||
revocation), tenancy mapping, retention profile, `secret_policy`, and
|
||||
`evidence_kind: load-bearing` from T03. Onboarded under INTENT principle 4 —
|
||||
declared ownership, retention, access, export and evidence policy, not merely
|
||||
events arriving. Not blocking: `approval-engine` is not yet emitting.
|
||||
|
||||
```task
|
||||
id: AUDIT-WP-0009-T10
|
||||
status: todo
|
||||
priority: low
|
||||
```
|
||||
Make the §5 conformance check total. `layer.yaml` declares
|
||||
`tooling_contacts: []`, true under §5 as written — audit-core is an Engine and
|
||||
holds no `key-cape` or OpenBao client. Companion §4 asks that uncatalogued
|
||||
infrastructure be listed anyway, and that carve-out sunsets within two review
|
||||
intervals for a store another layer reads, which `platform-pg` is. List it and
|
||||
the State Hub now. Add a conformance script and test in the shape ops-warden
|
||||
offered estate-wide.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- No custody claim is returned unconditionally where `docs/integrity.md`
|
||||
conditions it, and a stale attestation visibly degrades the claim.
|
||||
- A source can declare its evidence kind, and a load-bearing source can
|
||||
discharge the §9.6 cadence MUST against a real audit-core surface.
|
||||
- A suppressed low-volume load-bearing class produces a finding rather than
|
||||
silence.
|
||||
- The approval-validity prohibition is asserted by test, not by absence.
|
||||
- `layer.yaml` lists every infrastructure contact, catalogued or not, and a test
|
||||
checks it.
|
||||
|
||||
## Notes
|
||||
|
||||
T01 and T02 are separable and T01 is the one that matters: scheduling
|
||||
attestation without making the claim conditional would leave the overclaim in
|
||||
place whenever the job fails, which is precisely the case the claim is supposed
|
||||
to cover.
|
||||
|
||||
T05's dependency is real and should not be worked around. audit-core argued the
|
||||
cadence obligation up to a MUST; inventing a local cadence shape ahead of the
|
||||
Taxonomy schema would fragment the very interface it asked for.
|
||||
Loading…
Add table
Add a link
Reference in a new issue