Assent to AUDIT-IN-0001 — approval evidence half, with conditions
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

gate-house proposed (security layer model v0.3 §9.4) that audit-core own
the tamper-evident record of approvals while approval-engine owns the
operative state. Assented, with two corrections and one condition.

Correction 1: INTENT principle 6 overstated the delivered guarantee.
docs/integrity.md is authoritative — an in-database chain does not
withstand a database owner without the external chain-head attestation,
and even then it is not WORM. Principle 6 now points at that bound.

Correction 2: the chain proves alteration and truncation, not omission
at source. A suppressed revocation leaves the chain intact.

Condition: approval-engine must guarantee emission atomicity, so an
approval cannot change state without the event being durably queued in
the same transaction. Not a task audit-core can discharge for it.

Boundary: no approval-validity query will be exposed — that would be
deciding early under §6.1.

Also declares audit-core's layer (Engine, not a decision point), which
§11 requires and INTENT.md was missing.

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:
tegwick 2026-08-28 22:46:13 +02:00
parent 2e2d9d54b5
commit 3177d2cee0
3 changed files with 205 additions and 5 deletions

View file

@ -17,6 +17,18 @@ Audit Core must integrate cleanly with NetKingdom, Railiance, OpenBao,
Kubernetes, identity providers, and application runtimes, but it must not depend
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.
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`.
## Problem
Modern platforms generate audit-relevant events in many places:
@ -111,9 +123,14 @@ The data plane owns:
5. **Immutable archive and hot search are separate concerns.** Hot search can
be short-lived and cost-tuned. Immutable archive is the evidence record.
6. **Tamper evidence is explicit.** Audit Core should store signed or
hash-chained manifests for retained batches so operators can later prove
whether a record set was changed, omitted, or truncated.
6. **Tamper evidence is explicit, and bounded.** Audit Core should store
signed or hash-chained manifests for retained batches so operators can later
prove whether a record set was changed or truncated. The delivered bound is
narrower than that aspiration and `docs/integrity.md` is authoritative on it:
an in-database chain does not withstand a database owner without the external
chain-head attestation, and the chain proves nothing about an event that was
never emitted. Completeness at the boundary is the emitting source's
property, not the archive's.
7. **Least-privilege access.** Tenants may access their own audit records
according to policy. Platform operators may access cross-tenant records only
@ -225,6 +242,33 @@ 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.
## Approval Evidence
Audit Core carries the **evidence half** of approvals as a distinct source, per
security layer model §9.4 and `AUDIT-IN-0001` (assented 2026-08-28).
`approval-engine` owns the operative approval state — the durable object, atomic
supersession, single consumption, and revocation. Audit Core owns the record of
what happened to it: the four event classes **issuance, use, supersession, and
revocation**.
Terms Audit Core accepts this under:
- `approval-engine` is registered as a distinct source, with its own sender
registration, tenancy mapping, retention profile, and `secret_policy`,
onboarded under principle 4 like any other source;
- `approval-engine` guarantees **emission atomicity** — an approval cannot be
issued, consumed, superseded, or revoked without the corresponding event being
durably queued in the same transaction. Audit Core cannot detect a suppressed
emission and will not imply that what it received is everything that happened;
- Audit Core exposes **no approval-validity query**. Records, yes; a verdict
answering whether an approval is still valid, never. That would be deciding
early under §6.1 and would couple authorization to the audit fabric, which is
what §9.4 exists to prevent. Callers needing current state ask
`approval-engine`.
Full reasoning: `history/2026-08-28-approval-evidence-assent.md`.
## Tenant And Scope Model
Audit Core should distinguish:

View file

@ -0,0 +1,135 @@
# Approval evidence — audit-core's assent (AUDIT-IN-0001)
**Date:** 2026-08-28
**Intake:** `AUDIT-IN-0001`
**Requested by:** gate-house
**Standard:** `net-kingdom/canon/standards/security-layer-model_v0.3.md` §9.4 (proposed)
**Outcome:** assent, with two corrections to the rationale and one condition on
the emitting engine.
---
## What was asked
gate-house proposed that audit-core own the **evidence half** of approvals —
issuance, use, supersession, and revocation, emitted as audit events — while a
new `approval-engine` owns the operative state: the durable object, atomic
supersession, single consumption, and revocation without holder cooperation.
The two reasons given for keeping the operative state out of audit-core are
correct and audit-core does not contest them:
- operational custody is append-only Postgres by design
(`docs/audit-backend-contract.md`), and an approval needs mutable
current-state semantics with compare-and-swap supersession; and
- `access-engine` must read approval state in-path, so putting it behind the
audit fabric would make an audit outage an authorization outage.
## The answer
**Assent.** The split is the right one. Approval evidence is a record of what
happened, not the authoritative answer to whether an approval is still valid,
and that distinction is what keeps this inside `INTENT.md`'s "policy decision
making" exclusion rather than a violation of it.
Two corrections and one condition follow. None of them reject the split; they
state what audit-core actually delivers so the standard does not rest on a
stronger claim than the implementation supports.
---
## Correction 1 — principle 6 is an aspiration, and the delivered bound is weaker
gate-house's rationale cites `INTENT.md` principle 6 — *signed or hash-chained
manifests so operators can later prove whether a record set was changed,
omitted, or truncated* — as already being what authenticated approval entries
need forensically.
`docs/integrity.md` is more careful than principle 6, and it is the contract
that ships. In its own words: a chain *inside* the same database detects a
rewritten `payload_hash` **only if the attacker does not also recompute the
suffix** — and a database owner can. Tamper evidence against that class of
attacker requires the **external chain-head attestation**, and even with it:
> It still does not mean WORM, object lock, or ITC-CAP `data.archive`.
`tamper_evidence=True` is conditional on two preconditions being live
(`verify` failing on a rewritten row, and verify-against-attestation reporting
a missing cited head as a break). It is not a property of the store at rest.
**So: approval events get exactly the guarantee every other audit source gets —
no more.** That guarantee is real and it is useful, but it is bounded by the
attestation being taken and stored outside `platform-pg`. If §9.4 needs a
stronger property for approvals specifically — WORM, object lock, or a
transparency log — that is an engine gap to declare under §5.3, not a setting
audit-core can turn on.
## Correction 2 — the chain proves alteration, not omission at source
This is the more consequential one, and it is the reason for the condition
below.
The hash chain proves that accepted records were not **altered or truncated**.
It cannot prove anything about an approval event that was **never emitted**.
For an approval object the omission case is not a corner: a suppressed
*revocation* is precisely the event an attacker most wants missing, and it
leaves the chain perfectly intact. Verify would report `intact`.
Principle 6 claims audit-core can prove a record set was "omitted". Against a
compromised or buggy *sender*, it cannot, and neither can any append-only
archive. Completeness at the boundary is the emitter's property, not the
archive's.
## The condition — approval-engine owns emission atomicity
audit-core accepts the evidence half **on the condition that `approval-engine`
guarantees emission is atomic with the state change** — a transactional outbox
or equivalent, such that an approval cannot be issued, consumed, superseded, or
revoked without the corresponding event being durably queued in the same
transaction.
Without that, the evidence half is silently incomplete and audit-core has no
mechanism to detect the gap. audit-core will report what it received; it will
not imply that what it received is everything that happened.
This is a requirement on `approval-engine`, not a task audit-core can discharge
on its behalf. It should appear in `approval-engine`'s contract before the
evidence half is treated as load-bearing.
## Boundary audit-core states explicitly
`approval-engine` will be registered as a **distinct source**, with its own
sender registration, tenancy mapping, retention profile, and `secret_policy`
under the existing onboarding rules (principle 4: a source is onboarded when
ownership, retention, access, export, and evidence policy are declared and
validated — not when events start arriving).
**audit-core will not expose an approval-validity query.** No read surface will
answer "is this approval still valid". Records, yes; a verdict, never. Such a
surface would be deciding early under §6.1, and a consumer branching on an
audit-core answer would be routing an authorization decision through the audit
fabric — the exact coupling §9.4 exists to prevent. Callers who need current
state ask `approval-engine`.
The four event classes accepted as a distinct source: **issuance, use,
supersession, revocation**, per §9.4.
## Conformance note raised in passing
§11 requires that every repository in §4 declare its layer in `INTENT.md`.
audit-core declares none today. It is corrected in the same change: audit-core
is **Engine layer** — it exposes a deterministic API contract and holds
operational custody — and it is explicitly *not* a decision point, per the
boundary stated above.
---
## What changed in this repository
| File | Change |
| --- | --- |
| `INTENT.md` | layer declared; approval evidence named as a source; principle 6 cross-referenced to the `docs/integrity.md` bound |
| `intakes/intakes.md` | `AUDIT-IN-0001` closed, outcome `assent-with-conditions` |
| `history/` | this record |
Reply sent to gate-house on the State Hub inbox thread.

View file

@ -7,7 +7,7 @@ id: AUDIT-IN-0001
kind: intake
title: 'Proposed: audit-core takes the approval evidence half (security layer model
v0.3 §9.4)'
status: open
status: closed
origin: cross-repo
origin_ref: net-kingdom security-layer-model_v0.3 §9.4
priority: medium
@ -30,5 +30,26 @@ description: 'gate-house proposes that audit-core own the tamper-evident record
approval events as a distinct source, say so and gate-house will record the evidence
half as unowned rather than assume it.'
created: '2026-08-28T20:35:09.148892Z'
updated: '2026-08-28T20:35:09.148892Z'
updated: '2026-08-28T21:10:00Z'
outcome: assent-with-conditions
closed: '2026-08-28T21:10:00Z'
resolution: 'Assent. The split is right: approval-engine owns the operative state,
audit-core owns the tamper-evident record of issuance, use, supersession, and
revocation as a distinct source. Two corrections to the rationale and one
condition. (1) INTENT principle 6 overstates the delivered guarantee;
docs/integrity.md is authoritative — an in-database chain does not withstand a
database owner without the external chain-head attestation, and even then it is
not WORM. Approval events get exactly the guarantee every other source gets,
no more; anything stronger is an engine gap to declare under §5.3. (2) The chain
proves alteration and truncation, not omission at source. A suppressed
revocation leaves the chain intact and verify reports intact; completeness at
the boundary is the emitter''s property, not the archive''s. CONDITION:
approval-engine must guarantee emission atomicity (transactional outbox or
equivalent) so an approval cannot change state without the event being durably
queued in the same transaction — a requirement on approval-engine, not a task
audit-core can discharge for it. Boundary stated: no approval-validity query
will ever be exposed; a verdict surface would be deciding early under §6.1.
Also raised: audit-core declared no layer, contrary to §11 — now declared Engine
layer, explicitly not a decision point.'
recorded_in: history/2026-08-28-approval-evidence-assent.md
```