Design an enterprise audit platform that records every AI action from prompt and retrieved context through model response, tool calls, permissions, human approvals, and final side effect. Auditors need reproducible exports and tamper evidence. Privacy teams need retention, legal hold, and deletion across derived data. Resolve the apparent conflict between “immutable” and “delete.”
Receipts Without Forever
Design an immutable, cryptographically verifiable audit trail for AI actions that can still honor retention, legal holds, data residency, and derived-data deletion lineage.
Opening prompt
The interviewer gives a deliberately broad application problem. The candidate creates structure before drawing boxes.
I’ll define immutability as: no actor can silently rewrite the history that remains under policy. It does not mean retain every sensitive byte forever. I’ll separate a minimal append-only receipt ledger from encrypted payload objects, derived indexes, and retention metadata. Deletion appends a verifiable tombstone and completion attestation, then removes or crypto-erases in-scope payloads according to lineage; legal hold narrows and overrides that workflow with explicit authority.
We record observable inputs, outputs, versions, permissions, tool effects, approvals, and reason codes—not hidden model chain-of-thought, which may be unavailable, sensitive, or misleading.
Scope the contract
Actors, boundaries, correctness, latency, and what deliberately waits for a later phase.
Scope actors, functions, SLOs, and exclusions.
Actors: application/agent services, human approvers, tenant admins, security responders, privacy/deletion officers, legal-hold custodians, auditors, and platform SREs. Required: durable receipt ingestion; event correlation; context/tool/permission manifests; payload redaction/classification; hash-chain and checkpoint verification; search and timeline views; scoped exports; retention schedules; subject/artifact lineage; deletion and hold workflows; backup purge/expiry; privileged-access audit; and completeness reconciliation against producers.
Mock NFRs: 50M actions/day, 12 receipt events/action, 99.99% ingest availability, durable ack p99 under 200 ms, searchable within 60 seconds, seven-year maximum policy with tenant overrides, standard deletion completion under 30 days, export of one action under two minutes, zero cross-tenant access. Out of scope: storing private reasoning, proving that a model’s claim is true, guaranteed unlearning from third-party foundation models, and using the audit plane as the operational workflow database.
Agent/app producers, approvers, tenant admins, security, privacy officers, legal custodians, auditors, SRE.
Receipts, payload vault, correlation, tamper proofs, search/export, retention, holds, lineage deletion, backup reconciliation.
Observable evidence only; canonical hashes; sequence completeness; deletion tombstones; no false unlearning/reproducibility claims.
50M actions/day; ingest 99.99% p99 <200 ms; searchable <60 s; export <2 min; deletion <30 days; seven-year max.
Tenant/region isolation, envelope keys, HSM signing, dual-control export/hold, redaction, purpose-bound ABAC.
Private chain-of-thought, truth proof, third-party model unlearning guarantee, audit store as workflow database.
Back-of-the-envelope math
These numbers are supplied mock constraints. Change them to see where the design bends.
Use 50M actions/day, 12 events/action, 2 KB/event, 4:1 compression, seven years, and three replicas. Calculate.
That is 600M events/day, 6,944 events/s average; at a 10× burst, roughly 69K/s. Logical ingress is 1.2 TB/day. At 4:1 compression and three replicas, physical ledger storage is about 900 GB/day, 328.5 TB/year, or 2.3 PB over seven years—before indexes and payload blobs. Indexing every field would be financially and privacy-prohibitive.
So the hot search tier keeps a bounded window and selected low-cardinality metadata; older partitions remain columnar/WORM and are queried asynchronously. Large prompts, context, tool results, and outputs live as encrypted content-addressed objects with retention classes; ledger events carry hashes and minimal safe metadata. Sampling is unacceptable for compliance events, but detailed telemetry can be sampled separately.
Receipt ledger storage and ingestion
Data, keys, and APIs
Names turn ambiguous boxes into durable contracts. The primary keys below are part of the answer.
Define the records, keys, and APIs. What exactly is in an AI action receipt?
An Action gets a tenant-scoped sortable ID and parent/root correlation IDs. Each producer owns an independently ordered stream identified by (tenant_id, producer_id, stream_epoch); the primary append key adds sequence_no. A reset must open a new signed epoch rather than reuse sequence numbers. Each ReceiptEvent also includes event type, actor/service/workload identity, timestamp and trusted ingest time, policy decision ID, permission snapshot digest, input/context/output object digests, model/provider/endpoint/config, prompt-template digest, tool name/version/arguments digest/result digest, approval IDs, side-effect business key/receipt, previous-event hash, and canonical event hash.
Payload objects have classification, subjects/artifacts, region, envelope-key reference, retention schedule, and lineage parents. An audit export pins a query scope and policy, then returns events, authorized/redacted payloads, object proofs, checkpoint/Merkle proofs, signatures, schema dictionary, and a standalone verifier. APIs use producer idempotency keys and sequence reconciliation; deletion and hold are asynchronous, approval-gated jobs.
Records and access paths
| Record | Primary / idempotency key | Important immutable fields | Main access path |
|---|---|---|---|
Action | (tenant_id, action_id) | root/parent IDs, workflow/business key, class, region, start/end/outcome | timeline; producer reconciliation |
ReceiptEvent | (tenant_id, producer_id, stream_epoch, sequence_no) | event ID/type, action ID, actor, object/version hashes, prev hash, canonical hash | producer append/gap scan; action index; integrity proof |
PayloadObject | (tenant_id, object_digest) | classification, region, key ref, subjects/artifacts, retention, lineage parents | authorized retrieval; deletion traversal |
MerkleCheckpoint | (tenant_id, partition_id, checkpoint_no) | root, event range, signing key/version, external anchor receipt | inclusion/consistency proof |
LineageEdge | (tenant_id, parent_digest, child_digest, transform_id) | artifact types, transform version, subject tokens, discovered_at | forward deletion; reverse impact |
PolicyState | (tenant_id, subject_or_artifact_id, policy_version) | retention basis, holds, deletion request, authority, effective time | serialize deletion/hold decisions |
DeletionNodeResult | (tenant_id, request_id, node_id, lineage_version) | action, worker, pre/post digest, status, proof, retry | completion/reconciliation/attestation |
AuditExport | (tenant_id, export_id) | scope/query hash, approval, redaction policy, checkpoint roots, bundle digest | download; independent verification |
External contract
POST /v1/receipt-events Producer-Id + Stream-Epoch + Sequence + Idempotency-Key
POST /v1/payloads/presign classification + region + subject tokens
GET /v1/actions/{id}/timeline include sequence/completeness state
POST /v1/audit-exports scope + redaction policy + approvals
GET /v1/audit-exports/{id}/bundle signed bundle + standalone verifier
POST /v1/deletion-requests verified subject/artifact + legal basis
POST /v1/legal-holds custodian + scope + effective time
GET /v1/deletion-requests/{id}/lineage-plan versioned node actions
GET /v1/checkpoints/{id}/proof?event_id= inclusion + anchor chain
POST /v1/stores/{id}:reconcile-tombstones deletion watermarkEnd-to-end architecture
Control truth stays authoritative; expensive or probabilistic work is asynchronous, bounded, and replayable.
Walk through architecture and consistency. The model calls a payment tool after human approval.
The application writes workflow state and an audit outbox row in one transaction. A relay sends canonical events to a regional append gateway, which authenticates workload/tenant, validates schema/sequence, durably writes replicated log segments, and acknowledges. Stream processors classify payloads, store encrypted objects, build the lineage graph and hot search, and reconcile event gaps. Periodic partition Merkle roots are signed by a protected key and anchored in a separately administered store.
The action records context manifest before the model call, model response hash, proposed tool call, authorization decision, human approval referencing that exact proposal digest, tool dispatch intent, and final receiver receipt. The payment service must implement a business idempotency key; timeout becomes OUTCOME_UNKNOWN and is reconciled by lookup. We do not claim a global transaction between audit log and payment, but the transactional outbox plus sequence/gap alarms gives detectable completeness.
Prove inclusion and integrity—state the limit
Canonical event hashes, chained ordering, Merkle checkpoints, split-control anchors, and producer reconciliation provide different guarantees.
Deep dive on cryptographic integrity. A database admin controls the log store. What can you prove, and what can’t you?
Canonical serialization and hash chaining detect event modification, deletion, insertion, and reordering within a stream. Per-partition Merkle trees make compact inclusion proofs. Periodic roots are signed with a hardware-protected, rotated key and anchored to a separately controlled system or external transparency service, so a log admin cannot rewrite history and generate matching anchors. WORM retention and split duties add operational resistance.
This proves that exported bytes are included in an anchored ledger version and that the chain is structurally intact. It does not prove the producer told the truth or emitted every real-world action. Completeness needs producer sequence numbers, outbox backlog/gap reconciliation, cross-checks against model gateway/tool/payment logs, and independent control totals. Compromised producer keys can submit lies, so workload identity, key rotation/revocation, anomaly detection, and trusted timestamps matter.
| Mechanism | Proves | Does not prove |
|---|---|---|
| Event hash | Bytes match digest. | Producer told the truth. |
| Hash chain | Detected change/order gap in one stream. | Every real action was emitted. |
| Merkle proof + anchor | Event inclusion in externally fixed partition root. | Business action was legitimate. |
| Sequence/outbox reconciliation | Detectable producer emission gaps. | Uninstrumented side effects. |
| Receiver receipt | External system observed a business key/result. | Global exactly-once semantics. |
Delete payloads; preserve accountable history
Policy serialization, derived-data lineage, rederivation, tombstones, backup replay, and honest model-unlearning limits reconcile competing duties.
Deep dive on deletion lineage. A person asks to be erased. Their data is in prompts, chunks, embeddings, caches, eval sets, exports, and backups; some artifacts contain other people too.
A subject-resolution service verifies identity and maps subject tokens to source artifacts without exposing identity broadly. The lineage graph traverses from sources to chunks, prompts, model outputs, indexes, caches, evaluation items, exports, and backup retention sets. A versioned deletion plan classifies each node: delete bytes, crypto-erase a subject-specific key, redact/rederive a shared artifact, expire on backup schedule, preserve under hold, or retain minimal nonpersonal receipt metadata under legal basis.
Workers are idempotent on (deletion_request_id,node_id,lineage_version). Shared documents cannot be destroyed with one person’s key if others’ lawful data would disappear; we redact and rederive downstream objects under new digests, then tombstone old objects. Search indexes and caches delete immediately and are reconciled by scans. Backups are immutable: we record expiry, ensure deleted data is not restored to serving, and reapply the tombstone journal after restore. Model training requires a dataset manifest and model lineage; unlearning is a separate risk decision—never falsely attest deletion from a third-party model we cannot control.
node_action ∈ {
DELETE_BYTES, CRYPTO_ERASE, REDACT_AND_REDERIVE,
DELETE_INDEX_ENTRY, EXPIRE_WITH_BACKUP,
PRESERVE_RESTRICTED_UNDER_HOLD,
RETAIN_MINIMAL_NONPERSONAL_RECEIPT
}Failure injection I
The design changes under pressure. The candidate preserves correctness before convenience.
A privileged operator deletes three payload objects and recomputes local segment hashes. Six hours later auditors ask for an export.
The anchored Merkle root no longer matches the recomputed segment, and object hashes referenced by receipt events fail retrieval/integrity verification. The export returns an explicit incomplete status, proof of ledger inclusion, missing-object IDs/classifications, and incident reference—it never fabricates success. We preserve affected storage and access logs for forensics, revoke credentials, rotate keys, and compare replicas/object-lock histories.
To reduce the blast radius, no single operator controls storage deletion, signing keys, and anchors; payload deletion requires the policy workflow; WORM/object lock protects retained classes; signed roots are frequent enough to bound the rewrite window. Completeness dashboards continuously sample full proof construction, not only during an audit.
Failure injection II
Partial failure, stale inputs, duplication, and unknown external outcomes are normal distributed states.
A legal hold and deletion request race. Then a regional restore resurrects old search documents that should have been deleted.
Hold and deletion operate on a serialized policy state per subject/artifact with monotonic version. A hold established by authorized legal personnel before a node’s destructive commit changes it to PRESERVE_RESTRICTED; later hold does not magically reverse already lawful deletion. Workers check the current policy version immediately before delete and write an append-only result. The audit shows the race order and authority.
Restore boots in quarantine, loads the latest signed tombstone/hold journal, and replays deletions before indexes or application reads are enabled. A deletion watermark in each derived store is compared with the global ledger; stale stores fail readiness. Continuous reconciliation looks for forbidden subject tokens/object digests. Held bytes use separate keys and tightly restricted purpose, and are deleted when the hold releases if no other basis remains.
Security and operations
Tenant isolation, backpressure, observability, evaluation, SLOs, recovery, and cost belong in the core design.
Cover backpressure, tenant isolation, security, observability, exports, and DR.
Ingress partitions by tenant and time with quotas plus reserved compliance capacity; large payloads go directly to object storage so events stay bounded. We preserve minimal receipts before optional enrichments, shed search/index freshness rather than durable capture, and isolate bulk exports/deletion scans from live ingest. Finite retries and DLQs retain sequence visibility; producers spool locally with encrypted bounds when the gateway is unavailable and alert before overflow. If the transactional outbox or bounded spool cannot durably accept a high-impact action such as a payment or deployment, that action fails closed; lower-risk reads may defer emission but may never silently drop a receipt.
Tenant/region is enforced in identity, storage accounts or partitions, encryption contexts, queues, indexes, caches, lineage, and export workers. Anchors contain roots and signatures only, so integrity proof does not move regulated payloads across residency boundaries. ABAC binds case/purpose; export needs dual approval and field-level redaction; download URLs expire. Observe ingest gaps, sequence lag, event/object mismatch, Merkle checkpoint/anchor age, proof failures, search lag, deletion node states/SLA, backup expiry, hold access, cross-tenant denial, export completeness, cost/TB, and key health. DR replicates immutable segments/objects within approved regions and anchors under separate control; restore is gated by integrity verification plus tombstone replay.
Ingest EPS/latency/error, producer sequence gaps, local spool depth, outbox age, DLQ, event/payload mismatch.
Checkpoint/anchor age, hash/proof failures, missing objects, key/signature verification, WORM policy violations.
Deletion SLA/node failures, lineage unknowns, index/cache reconciliation, backup watermark, hold access/release, resurrected tokens.
Reserved compliance ingest, per-tenant quota, bounded events, payload direct upload, search/export/deletion isolated from capture.
Tenant+region storage/keys/indexes/workers, ABAC purpose/case, HSM split duties, dual-approved export, redacted telemetry.
Replicate ledger/objects/anchors, verify before serve, replay latest tombstone/hold journal, rebuild indexes, prove restore.
Rollout and trade-offs
A credible production answer defines how it earns trust and how it retreats safely.
How do you roll this out and explain the immutability-versus-deletion trade-off?
First define the receipt schema and threat model with auditors/privacy/legal; instrument one low-risk workflow using outbox and sequence checks; run dual capture against existing logs; verify proof/export tooling independently; add payload classification and lineage; pilot deletion end to end including cache/index/backup restore; enable holds; then expand to tool/payment actions and more tenants. Keep completeness error budgets and periodic third-party verification.
The trade-off is audit fidelity versus data minimization. Storing full prompts forever makes replay easy but raises privacy, breach, and cost risk. I retain immutable minimal receipts and hashes under policy, encrypt payloads separately with precise lineage/retention, and make deletion itself an auditable event. Some regulated replay may be impossible after lawful deletion; the export must say that honestly.
- Agree on observable receipt schema, retention basis, and threat model.
- Instrument one workflow with transactional outbox and producer sequences.
- Dual-capture and reconcile against model/tool/receiver logs.
- Verify hash/Merkle/export bundle with an independent tool/team.
- Add payload classification, subject tokens, and lineage.
- Pilot deletion through caches, indexes, shared artifacts, and backup restore.
- Enable legal hold race tests and dual-control exports.
- Expand by action class only when completeness, proof, privacy, cost, and SLO gates pass.
One-minute spoken recap
Practice this synthesis until it sounds conversational rather than memorized.
One-minute close.
I’ll summarize observable receipts, tamper evidence, completeness limits, and policy-driven lineage deletion.
Reference shelf
Definitions, traps, and the final checklist stay outside the timed mock.
- Canonical serialization
- One deterministic byte representation used to compute stable hashes.
- Cryptographic erasure
- Destroying a data-encryption key so ciphertext becomes unreadable.
- Hash chain
- Each event commits to the previous event hash, exposing mutation or reordering.
- Legal hold
- Authorized preservation that suspends normal deletion for defined material and purpose.
- Lineage graph
- Edges from source artifacts to every derived artifact/transformation.
- Merkle tree
- Hash tree enabling compact proof that an item is included in a fixed root.
- Observable receipt
- Record of inputs, versions, decisions, tool calls, approvals, outputs, and effects—not private reasoning.
- Outbox reconciliation
- Checking transactionally captured producer intents against emitted ledger sequences.
- Redact and rederive
- Remove one subject from a shared object and regenerate descendants under new hashes.
- Tombstone journal
- Append-only record of material that must remain deleted after rebuild/restore.
- Transparency anchor
- A root stored under independent control so history cannot be silently re-rooted.
- Unlearning
- Attempt to remove training influence from a model; distinct from deleting source/evaluation artifacts.
- Equating immutable with “retain all prompts forever.”
- Storing hidden chain-of-thought as a trustworthy audit fact.
- Hashing events without externally anchoring the root.
- Claiming hashes prove the producer told the truth.
- Ignoring missing producer events and uninstrumented side effects.
- Putting full sensitive payloads in the hot searchable ledger.
- Deleting a shared artifact key and erasing other people’s lawful data.
- Promising third-party foundation-model unlearning without control/evidence.
- Restoring a backup directly to service before tombstone replay.
- Letting one admin control storage, signing keys, and anchors.
- Blindly retrying a payment after an unknown timeout.
- Returning a “complete” audit bundle when payloads/proofs are missing.
- Clarified actors, authority, business harm, and out-of-scope.
- Did correct BOTEC and named the variable that changes the architecture.
- Defined stable IDs, versions, access paths, and idempotency keys.
- Separated authoritative state from derived indexes and model output.
- Explained consistency, retries, backpressure, and unknown outcomes.
- Revised the design after both failure injections.
- Covered tenant isolation, secrets, least privilege, deletion, and audit.
- Named golden signals, domain quality metrics, rollout gates, and rollback.