Context
Ley 21.719 is fully in force on 2026-12-01, and erasure is the right that most directly conflicts with how the rest of the system is built. Points ledgers are append-only for accounting integrity; audit logs exist precisely so nothing disappears. DEC-J3 resolves the conflict without pretending it does not exist: the profile and events are deleted; ledger rows are anonymized to a tombstone. Anonymization satisfies the right — the data is no longer attributable to a person — while the accounting stays whole. The committed deadline is ≤30 days and the process is automated, because a manual process is one that is late during the month everyone is busy. Orchestration lives in core rather than in each module. One place decides what erasure means, and the modules obey.Scope (normative)
core.subject_requests: erasure and portability requests with their lifecycle.- Erasure orchestration across every module, with per-module acknowledgement.
- Contact and event deletion; ledger anonymization instructed to loyalty.
- Portability export: everything about the subject in a structured, common format.
- Proof of execution retained after the data is gone.
- The 30-day SLA with escalation before it is breached.
Non-scope (normative)
- Verifying the requester’s identity. That is the tenant’s obligation as controller (DEC-J1); we execute an instruction from an authenticated tenant.
- The member-facing request form —
frontend/portal. - Deleting a tenant. That is offboarding, a different runbook.
Behaviour (normative)
- A request has a lifecycle:
received → validated → executing → completed, with a timestamp at every step. The timeline is the evidence. - The SLA is ≤30 days and escalates at day 21. Discovering a breach on day 31 is discovering it too late.
- Erasure is orchestrated: core instructs each module and waits for acknowledgement. A module that fails to acknowledge blocks completion — a partial erasure reported as complete is the worst possible outcome.
- Per module:
coredeletes the profile, identities, consents and events.loyaltyanonymizes ledger rows to a tombstone and deletes nothing.messagingdeletes send content and keeps aggregate counts.crmdeletes notes and activities. - Suppressions survive erasure, as a hashed identifier with no profile attached. Deleting the suppression would let the same address be emailed again, which is the opposite of what the person asked for.
- Proof of execution survives: an audit row records that the erasure happened, for whom (as an opaque reference), when, and which modules acknowledged. The proof is the one thing that must outlive the data.
- Portability exports everything about the subject in a structured, common format, delivered through a signed link that expires.
- An erasure is irreversible and confirmed before execution. There is no undo, and the API says so.
- Backups age out on their own retention; the request records that and does not claim otherwise. Claiming instant deletion from backups would be a claim we cannot support.
Data (normative)
API (normative)
Events (normative)
core.contact.erased on the outbox, so every consumer — including a tenant’s own webhook — can
drop its copy. A tenant that mirrored our contacts must be told.
Acceptance criteria (normative)
- Erasure deletes the profile, identities, consents and events, and leaves ledger rows anonymized with the program’s total outstanding points unchanged.
- A module that does not acknowledge blocks completion, and the request stays
executing. - The proof-of-execution audit row survives and names the modules that acknowledged.
- A suppression survives as a hashed identifier and still blocks a send to that address.
- Portability export contains every category listed in the RAT and is readable as valid JSON.
- The export link expires and is rejected afterwards.
- Day-21 escalation fires for a request not yet complete.
- Negative: no erasure path deletes a ledger row, and no completion is reported without every module’s acknowledgement.
Execution
Asynchronous pipeline. Orchestrator inbackend/workers, SLA monitoring in backend/scheduler.
Each module exposes an internal erasure handler; core never reaches into another module’s tables.