Assent to AUDIT-IN-0001 — approval evidence half, with conditions
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:
parent
2e2d9d54b5
commit
3177d2cee0
3 changed files with 205 additions and 5 deletions
135
history/2026-08-28-approval-evidence-assent.md
Normal file
135
history/2026-08-28-approval-evidence-assent.md
Normal 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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue