From 3177d2cee01c37186d6d893c343d9a17b3ef996c Mon Sep 17 00:00:00 2001 From: tegwick Date: Fri, 28 Aug 2026 22:46:13 +0200 Subject: [PATCH] =?UTF-8?q?Assent=20to=20AUDIT-IN-0001=20=E2=80=94=20appro?= =?UTF-8?q?val=20evidence=20half,=20with=20conditions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 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 --- INTENT.md | 50 ++++++- .../2026-08-28-approval-evidence-assent.md | 135 ++++++++++++++++++ intakes/intakes.md | 25 +++- 3 files changed, 205 insertions(+), 5 deletions(-) create mode 100644 history/2026-08-28-approval-evidence-assent.md diff --git a/INTENT.md b/INTENT.md index cf5b6e8..2259442 100644 --- a/INTENT.md +++ b/INTENT.md @@ -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: diff --git a/history/2026-08-28-approval-evidence-assent.md b/history/2026-08-28-approval-evidence-assent.md new file mode 100644 index 0000000..2a21481 --- /dev/null +++ b/history/2026-08-28-approval-evidence-assent.md @@ -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. diff --git a/intakes/intakes.md b/intakes/intakes.md index 7db4949..a83eac2 100644 --- a/intakes/intakes.md +++ b/intakes/intakes.md @@ -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 ```