audit-core/docs/erasure-and-audit.md
tegwick 58a106aa4d
Some checks are pending
CI Smoke / host-smoke (push) Waiting to run
CI Smoke / container-smoke (push) Waiting to run
Implement AUDIT-WP-0008 T03, T06, T07, T08.
T08 fixes two defects in our own declaration. provider.R.available quoted a
30-day horizon audit-core does not solely control: at P1 the erasure horizon is
the instance maximum across co-residents, so a co-resident declaring longer
extends what a sender's records remain recoverable for, silently. Decision 4.5.4
names this for tiers; it applies to a provider quoting a number too, and the
provider block now says so. And user-engine, the only consumer, was notified
under Decision 6.1 -- what we declared, that E4 and R4 are unreachable here, and
that the retention number is a floor rather than a ceiling.

T03 writes docs/erasure-and-audit.md: the fact/payload split, why shreddability
is not retrofittable onto a chain committing to cleartext, and why the retained
hash is a confirmation oracle over low-entropy audit records. The framework half
was already resolved as Decision 4.5.3, so what remains is our own position. The
legal basis for retaining audit facts is routed to risk-nexus, open and visible.

T06 closes the review loop with net-kingdom: five findings adopted, declaration
validates clean, and the E line will go stale on an upgrade that Decision 6.1
deliberately does not require anyone to announce.

T07 enumerates the seven dependencies on the accept path and specifies five
recovery scenarios with integrity as a pass condition. It settled one thing: V2
is not reachable from P1 as built, since platform-pg runs instances 1 and
Decision 4.6.1 makes V the minimum across synchronous providers. V1 is the
ceiling here, not the next step. The exercise needs a live window.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:24:55 +02:00

5.5 KiB

Erasure versus audit

Status: audit-core's position. Written for AUDIT-WP-0008-T03. Framework: NetKingdom Tenancy Posture v0.1 (draft-8), §4.5 and §19.11. Declared consequence: tenancy.yaml targets R2. R4 is not a target.

The question

Raised by rapp-postgres as question 11 of the tenancy posture review. The retention axis tops out at R4, verified erasure, reachable either by waiting out the erasure horizon or by encrypting per entity and destroying the key. Crypto-shredding is the established mechanism for erasure under immutable retention.

Applied to an audit service it destroys the evidence the service exists to hold.

The question was asked because a naive "R4 everywhere" fleet target would instruct this service to erase its own trail, and nobody would notice until it mattered.

The shape of the answer, and why it is not enough

The literature's usual resolution is to separate the fact of an event, retained, from its personal payload, encrypted per subject and shreddable. The trail survives erasure with its personal content removed. That shape is right, and we accept it as the shape.

It does not survive contact with this repo's integrity design, in two ways.

1. It is not retrofittable

_record_hash (audit_core/postgres_backend.py) is SHA-256 over the canonical JSON of the cleartext record, and the hash chain commits to that value. Encrypting a payload after the fact severs the binding between payload_hash and the stored record: the chain still verifies, because verify_rows walks stored hashes, but the hash no longer attests to anything present.

Shreddability has to be built as encrypt-then-hash at accept time, with the chain committing to ciphertext. Retrofitting it onto events already accepted means rewriting the chain — which is the single thing AUDIT-WP-0007 was built to make detectable. A design that requires forging the tamper-evidence log in order to comply is not a design.

2. The retained hash is a confirmation oracle

This is the sharper problem and it is easy to miss.

Audit records are low-entropy. An event carries a type, an actor, a tenant, a subject and a timestamp, drawn from small enumerable sets. Given the retained SHA-256, an adversary guesses a plausible record, hashes the guess, and compares. A match confirms the content.

So destroying the key does not make the payload unrecoverable while that hash survives. Key destruction removes the ability to read the ciphertext; it does nothing about a separate commitment that anyone can test guesses against.

The remedies are known — an HMAC under a per-subject key that dies with the key, or a per-record salt destroyed alongside it — and neither is built here.

Conclusion: crypto-shredding does not reach R4 under this design. Claiming it would be an overclaim of exactly the kind §6 exists to prohibit, and worse than most, because the claim being made would be "this data is gone".

This finding was general rather than specific to us, and the framework adopted it as Decision 4.5.3: the key-destroyed route now requires that no retained commitment reveals the erased content. It applies to anyone hashing, chaining or indexing what they intend to shred.

What audit-core therefore declares

  • Target R2, not R4. Retention declared per dataset, erasure horizon published. That is in tenancy.yaml and reflected on /readyz as recoverable_days.
  • R4 is unreachable by design, and §19.11 records audit-core as explicitly exempt from any fleet R4 target.
  • Our provider block says so to senders. A consumer with a verified erasure obligation over its audit trail cannot discharge it here, and is told that rather than left to assume.

The dependency we are not competent to close

Declining to build erasure means that if an Article 17 request arrives naming a data subject who appears in the audit trail, audit-core has no mechanism. The answer will rest on audit evidence being exempt — legal obligation, or legitimate interest in fraud and security investigation.

Those grounds are ordinary and widely relied on. They are also a legal conclusion, and this repo is not competent to reach one. Nothing in INTENT, SCOPE, the capability case, or the framework records anyone in this estate having actually reached it. §19.11 says as much in the framework's own words: "the legal basis for retaining audit facts remains a risk/legal question outside this framework."

Routed to risk-nexus, which owns judging what an external rule demands of the estate (moved there from policy-nexus on 2026-08-17). Open, unowned inside audit-core, and deliberately visible.

The distinction being drawn: a recorded tension is a position someone has taken and can defend. An unnoticed liability is the same technical state with nobody named. An audit service discovering mid-regulator-question that its exemption was assumed rather than established is the specific failure this document exists to prevent.

What would change the position

  • A data.archive provision with per-subject encryption at accept time, making encrypt-then-hash available for new events. Old events remain unshreddable.
  • A ruling or advice from risk-nexus that the retention basis does not hold, which would make the R4 problem urgent rather than theoretical.
  • A sender arriving with a genuine per-subject erasure obligation over its audit trail. Today none exists; the provider block is written so one would find out before building on us rather than after.