Audit trail per read
Every gated read writes one row before the answer returns: who asked, what clearance and compartments applied, a preview of the question, and what was surfaced. Here is the row, how to query it, what strict mode changes, and what erasure does to the record.
The row
A read is any retrieval that passed through the gate: a search, a chat turn's retrieval, a document listing, an as-of read, a read by id. Each writes one row to an append-only table, and the write is awaited, not fired and forgotten; the answer does not return before the record exists.
| Field | What it holds |
|---|---|
user_id | The principal who asked, as resolved by the platform (not as the caller phrased it). |
principal_clearance, principal_matters | The classification level and compartments that applied to this read. |
query_preview | A preview of the question. |
surfaced_count, surfaced | How many memories were released, and which: what was shown, not what the asker was cleared for. |
identity_source, identity_issuer, token_id | asserted or verified; with verified identity, the issuer and token that proved who asked. |
thread_id, created_at | The conversation, if any, and the time. |
Querying it
GET /api/access/audit?matter=matter:acme&principal=user:maeve&date_from=2026-10-01&date_to=2026-10-22&thread_id=…&limit=500&offset=0
→ {"filters": {...}, "total", "count", "offset", "rows": [...]}
matter returns the reads that surfaced that compartment, which is the question a
review actually asks: not who was cleared, but what was shown. A bare date is that day in UTC; a malformed
date is a 400. The audit read is on the full surface (a chat-profile key), and it is tenant-scoped: an operator
reads the record without reading the memory.
Strict mode
By default a read whose audit write fails still returns, and the failure is logged. With
audit_strict on for the tenant, there is no read without a record: the memory API returns 503 and
chat answers without memory. Set by the operator; off for most tenants, on for the ones whose regulator will
ask.
Decisions are recorded too
The audit of reads sits beside the other ledgers: clearance grants and revocations, grants the conflict graph
refused, mandate decisions (action_audit), lifecycle events on every memory, and
decision_refused when someone tries to approve their own escalation. All of it is in the
tenant export.
Erasure and the record
Ordinary operation never destroys anything; see close and supersede. Destruction is one governed path:
POST /api/access/purge
{"selector": {"principal": "user:maeve"}, // or memory_id | document_id | matter | tenant
"identity": "ops:dpo", "reason": "erasure request 2026-10-20", "dry_run": true}
→ 200 a content-free plan (counts, labels, what it will and will not reach)
→ 202 escalated to a person, with an escalation id, when the mandate requires it
→ 200 executed, with a receipt and one tombstone row per memory
The plan is resolved first and approved exactly as resolved. Execution removes the points from every store
and the side channels, cascades to answers grounded on the erased memory (a paraphrase still holds the
personal data), and scrubs the asker's own words from the audit rows and retrieval logs that carried them: the
rows stay, the text becomes [erased]. Each erased memory leaves a purged row in the
lifecycle ledger. The receipt also says what a purge does not reach: backups are not rewritten, and the report
states how many days at most until they expire.
The tenant export
GET /api/access/export every memory, every ledger row, the entity graph: one NDJSON stream
GET /api/access/export?counts_only=1
Taking the estate is itself a mandated action with an escalation when the mandate requires one. Every erasure proof the platform's own consumers run ends by reading this export, because an erasure that leaves a trace in the export did not happen.
Why this matters. A buyer's security review asks two questions of a RAG system: what did the model see, and can you prove it. The row answers both: Enterprise RAG with access control.
Get a key
Yohanun is in invited beta. Tell us what you are building and we send a key with a developer account; a memory-profile key for your own model, or a chat-profile key if you want the platform to run the model and meter it. There is no card and no self-serve sign-up.
Request an invite