Skip to content

Subject erasure (GDPR Article 17) ​

When a data subject exercises their right to be forgotten under GDPR Article 17 (or an equivalent regulation), Moʻolelo deletes every trace of that subject's personal data from the platform — across every region — and produces an audit trail that proves the deletion.

This page is the operator runbook for executing an erasure. It's not a legal guide; check with your DPO before serving any request.

What erasure does, in one sentence ​

It marks every vault token tied to a data subject as erased=true in every regional vault, which makes them permanently unresolvable. The global graph carries only tokens — never PII — so once the tokens become unresolvable, the personal data is gone.

What erasure does not do:

  • Delete the chunks the subject's data appeared in. Chunks reference subjects by token; an erased token renders as [REDACTED] at query time.
  • Delete derived data (entity rollups, aggregate statistics) that doesn't carry tokens.
  • Affect audit-log entries from before the erasure was processed (the audit log itself contains tokens, not PII).
  • Touch source systems. The subject must request deletion from each source separately.

The API ​

The webserver exposes:

text
POST /api/admin/tenants/{tenant}/subjects/{subject_id}/erase
Authorization: Bearer <admin-token>
Content-Type: application/json

{
  "reason": "GDPR Article 17 request — ticket DSR-2026-0142",
  "requestor": "dpo@acme.com"
}

The response includes the count of tokens erased per region:

json
{
  "subject": "person:7f9a4c…",
  "tokens_erased": 1284,
  "per_region": {
    "eu-central": 982,
    "us-east": 302
  },
  "completed_at": "2026-05-12T14:08:22Z"
}

Erasure is synchronous from the caller's perspective — the response only comes back once every regional vault has confirmed the writes. Expect 10–60 seconds for a typical subject; longer if a region is temporarily unreachable (the request will retry up to the configured timeout, then return a partial result with the regions that succeeded so you can re-run for the rest).

Resolving the subject id ​

Erasure runs against a canonical person id (person:<sha256>), not a name or email. To resolve a real-world subject to their canonical id, use the identity-catalog lookup:

text
GET /api/admin/tenants/{tenant}/subjects/resolve?email=jane.doe@acme.com

Returns the canonical id plus the source-system identities that resolve to it (so you can sanity-check that you're erasing the right person):

json
{
  "subject": "person:7f9a4c…",
  "linked_identities": [
    { "source": "github",     "external_id": "jdoe" },
    { "source": "sharepoint", "external_id": "jane.doe@acme.com" },
    { "source": "confluence", "external_id": "62700" }
  ]
}

If the lookup returns zero linked identities, the subject was never ingested and there's nothing to erase — record that fact in the DSR ticket and respond to the requestor.

What the audit trail looks like ​

Every erasure writes a row to the subject_erasures Iceberg table with:

ColumnContent
tenant_id, subject_idWho was erased
requestor, reasonFree-text fields you populated in the API request
tokens_erased, per_region_countsQuantitative proof
requested_at, completed_atTimestamps
regions_succeeded, regions_failedWhich regions confirmed (empty failed list means total success)

Query the table directly via Trino, DuckDB, or any Iceberg client to produce the evidence packet for the requestor:

sql
SELECT *
FROM subject_erasures
WHERE tenant_id = 'acme'
  AND subject_id = 'person:7f9a4c…';

The audit row is itself residency-clean — it carries the subject id, not the subject's name or email. Audit-log retrieval of the original identity requires a separate linked_identities lookup which is itself audited.

Re-ingestion after erasure ​

If the source system still holds the subject's data and the connector runs again, the subject will be re-ingested with a fresh canonical id. Erasure does not blacklist a subject — it only purges existing tokens.

If the regulator's order requires that the subject not be re-ingested, you must either:

  1. Delete the subject from the source system first (the right answer in most cases — Moʻolelo mirrors the source), or
  2. Configure a connector-level exclusion at the source. SharePoint and GitHub allow filtering on uploader / author identity; Confluence does not.

The platform itself does not maintain a "do not re-ingest" list; that's a source-system policy concern.

Partial failure handling ​

If one region is unavailable when erasure runs, the response includes that region in regions_failed. The recommended remediation:

  1. Restore the failed region (consult the region's runbook).
  2. Re-issue the same erasure request — it's idempotent. Tokens already erased stay erased; tokens in the failed region get processed on the retry.
  3. Update the DSR ticket with the final completed_at from the second call.

Do not declare the erasure complete in the DSR ticket until every region has succeeded. The subject_erasures row's regions_failed field is the source of truth.

See also ​

Moʻolelo — self-hosted federated enterprise knowledge platform.