Akashi supports GDPR Article 17 "right to be forgotten" via in-place tombstone erasure. This scrubs PII from a decision without deleting the row, preserving the audit chain while removing personal data.
POST /v1/decisions/{id}/erase
Required role: org_owner
Request body (optional):
{
"reason": "GDPR erasure request from user@example.com"
}| Field | Erased value |
|---|---|
outcome |
"[erased]" |
reasoning |
"[erased]" |
embedding |
NULL |
outcome_embedding |
NULL |
content_hash |
Recomputed over scrubbed fields |
Alternative label |
"[erased]" |
Alternative rejection_reason |
"[erased]" |
Evidence content |
"[erased]" |
Evidence source_uri |
NULL |
Evidence embedding |
NULL |
- Decision ID, timestamps,
valid_from/valid_to,transaction_time - Decision type, confidence score, agent ID, org ID
- The fact that a decision existed (structural metadata)
- The audit trail entry recording the erasure itself
Each erasure creates:
- A row in
decision_erasureswith the original content hash, erased content hash, the erasing agent, and the reason. - A
DecisionErasedevent in theagent_eventshypertable. - A mutation audit entry capturing before/after state.
- A search outbox deletion (removes the decision from Qdrant).
If a decision is covered by an active legal hold, erasure is blocked with 409 Conflict.
Legal holds take precedence over erasure requests. Resolve the hold first, then retry.
POST /v1/retention/hold # Create a legal hold (admin)
DELETE /v1/retention/hold/{id} # Release a legal hold (admin)
| Status | Condition |
|---|---|
404 Not Found |
Decision does not exist |
409 Conflict |
Decision already erased, or active legal hold exists |
403 Forbidden |
Caller does not have org_owner role |
Erasure is idempotent in the sense that a second call returns 409 with a clear message
rather than silently succeeding — the original erasure audit record is already in place.
After erasure, GET /v1/verify/{id} returns:
{
"status": "erased",
"original_hash": "sha256:abc...",
"erased_hash": "sha256:def...",
"verified": true
}This confirms the erasure was applied correctly and the content hash chain is intact.
- Erasure is a single transaction — either everything is scrubbed or nothing is.
The transaction sets a session-local variable (
akashi.erasure_in_progress) to bypass the immutability trigger that normally prevents decision mutation. - Erased decisions are removed from Qdrant via the search outbox, so they no longer appear in semantic search results.
- Erased decisions still appear in
GET /v1/decisions/{id}with[erased]placeholder text — the row is not deleted. - The
reasonfield is optional but recommended for compliance audit trails.