Type to search pages and rules.

Browse pages

Privacy and Retention

Privacy and Retention states how the product handles personal data: the data classes with their erasure positions, the retention schedule, and the extended erasure needs of referenced rows, child rows, handed-over data, requested reach, export guards, conflicts, and restore sweeps. Agents write these records from Intent, and code carries them. The Behavior overview maps the five Behavior pages, and the record language page states how each field, value and record name is written.

Markdown17 provisions

Stack: any Layer: records

Concepts#

Retention Schedule#

The retention schedule is one page holding one row per data class with its purpose, basis, period, enforcement, and the requirement behind personal or sensitive keeping. It states the time limits of a record of processing; the deleting job and the evidence are LiteSpec extensions to that record. The project's counsel confirms the wording. Processors and conflicts sit on the row: where the data forwards, and which demand wins when keeping for audit and erasing for the subject collide, with who records the exception.

FieldMeaning
dataClass, coversThe class and the aggregates holding it.
purposeWhy the data is kept.
basis, period, enforcedByThe statute, business, or engineering basis, the ISO 8601 duration period or { "mode": "none", "reason": "..." }, and the enforcement.
citesThe requirement behind personal or sensitive keeping.
processors{ system, forwarding, basedOn } entries.
conflictsWhich demand wins on a keeping-versus-erasing collision and who records it.

Extended Erasure Positions#

The onErasure field carries one of nine positions. Five cover the common fates: erase, pseudonymize, anonymize, retain, and exempt. Four cover the extended needs: tombstone keeps the row id and the erasure date where references outlive erasure, discard deletes the row where no marker duty exists, cascade-only erases only through a named parent, and transferred hands the data to a named receiver with its handover record. Erasure answering a subject request uses the requested reach and touches only the data the request names. A class that must export before erasure carries exportFirst, and erasure under unchangedSinceExport waits for a fresh export when the data changed since the last export. A restore runbook names the sweep job that re-applies erasure after the restore.

Standards#

Classify Every Aggregate Data Field#

ruleruleguidance
litespec/core/privacy#classify-every-aggregate-data-field
Statement

Each aggregate MUST list its data fields with their meaning, classification, and data class in data.

Applies toartifact: aggregate

Why

Data without a classification is handled by guess: personal facts sit beside public ones with nothing marking which is which. A meaning with a classification of public, internal, personal, or sensitive tells every later reader how each field is handled, and the data class ties the field to its erasure position and its retention row. The fields live in data on the aggregate record file.

Checka reviewer answers

Reviewed forWhich aggregate data fields lack a meaning, a classification, or a data class? Look at data on each aggregate page.

Marked guidance: a reviewer answers this question.

Declare Every Data Class with Its Erasure Position#

rulerulecheckable
litespec/core/privacy#declare-every-data-class-with-its-erasure-position
Statement

Each data class MUST declare its classification, its fields, its purpose, its erasure position, its basis, its retention period, and the enforcement that carries it out.

Applies toartifact: record:retention-schedule

Why

Erasure declared per field drifts: one field keeps a new position while its twin keeps the old one. Declaring the position once per class, with per-field exceptions beside it, keeps one decision in one place. The position is erase, pseudonymize, anonymize, retain, exempt, tombstone, discard, cascade-only, or transferred; the basis is statute, business, or engineering; the period is an ISO 8601 duration or { "mode": "none", "reason": "..." }; the enforcement is reaction/..., job/..., record-expiry, store-ttl, or query-filter. A pseudonymized class stays personal with its basis, and an anonymized class can no longer identify anyone. The erasure-undeclared check reports a personal or sensitive field with no declared position, and retention-enforcement-missing reports a class nothing enforces.

Example

The submitter-contact class declares personal, pseudonymize, its purpose, and its accepting requirement, while the expense-ledger class declares internal, retain, a statutory seven years, and the finance expiry job.

Checkchecked by a tool

Checked bylitespec model check reports erasure-undeclared for a personal or sensitive field with no declared position and retention-enforcement-missing for a class nothing enforces.

Marked checkable: the tool named here checks it.

Accept Every Retained Personal Data Class in Intent#

ruleruleguidance
litespec/core/privacy#accept-every-retained-personal-data-class-in-intent
Statement

Each personal or sensitive data class kept with pseudonymize, retain, or exempt MUST name the Intent requirements or decisions accepting it in basedOn.

Applies toartifact: record:retention-schedule

Why

Keeping personal data past erasure is a business choice, not a technical default: the statute or the business accepts it, with the reason on record. Pseudonymized data stays personal data, so it needs the same acceptance as retained data. Naming those requirements or decisions in basedOn keeps the keeping reviewable where the promise lives. The risk-acceptance-missing check reports a pseudonymized, retained, or exempt personal or sensitive class with no Intent acceptance.

Checka reviewer answers

Reviewed forWhich pseudonymized, retained, or exempt personal or sensitive classes name no accepting requirement or decision? Look at basedOn on each data class.

Marked guidance: a reviewer answers this question.

Route Every External Erasure Through an Operation or Event#

ruleruleguidance
litespec/core/privacy#route-every-external-erasure-through-an-operation-or-event
Statement

Each external system MUST declare its erasure as { "mode": "call", "operation": "external-system/<name>#<operation>" }, { "mode": "event", "event": "integration-event/<name>" }, or { "mode": "impossible", "reason": "..." } with its acceptance.

Applies toartifact: record:external-system

Why

Personal data forwarded to a processor without an erasure route stays there past erasure: the product forgets while the processor remembers. Declaring { "mode": "call", "operation": "external-system/<name>#<operation>" } naming the operation, { "mode": "event", "event": "integration-event/<name>" } naming the forwarding integration event, or { "mode": "impossible", "reason": "..." } with its reason and its Intent acceptance states the route beside the system.

Checka reviewer answers

Reviewed forWhich external systems declare no erasure call, forwarding event, or impossible reason with acceptance? Look at the external systems beside their erasure routes.

Marked guidance: a reviewer answers this question.

Schedule Every Data Class for Retention#

rulerulecheckable
litespec/core/privacy#schedule-every-data-class-for-retention
Statement

Each data class MUST appear on the retention schedule with its purpose, basis, period, enforcement, and the requirement it cites where personal or sensitive.

Applies toartifact: record:retention-schedule

Why

Retention decided per aggregate scatters: one module erases in days what another keeps for years, and no page shows the whole. Listing every data class on one schedule with its purpose, basis, period, enforcement, processors with their forwarding and acceptance, and the conflict rule where keeping and erasing collide states the whole as rows a reviewer judges together. The schedule states the time limits of a record of processing. Personal or sensitive keeping cites its Intent requirement. The retention-enforcement-missing check reports a row nothing enforces.

Checkchecked by a tool

Checked bylitespec model check reports retention-enforcement-missing for a data class nothing enforces.

Marked checkable: the tool named here checks it.

Keep a Tombstone Where Deletion Stays Visible#

ruleruleguidance
litespec/core/privacy#keep-a-tombstone-where-deletion-stays-visible
Statement

A data class whose rows outlive erasure as references MUST use onErasure: tombstone with the fields its marker keeps.

Applies toartifact: record:retention-schedule

Why

Some rows are referenced after they are gone: remote servers hold copies, audit trails cite row ids, and support tools link to deleted accounts. Erasing the row breaks those references, while keeping it breaks the erasure duty. A tombstone keeps the row id and the erasure date and drops every other field, so references resolve to a marker that says the subject is gone.

Example

ZITADEL deletes a user by moving it to a terminal state and deleting its read-model rows while the events stay for audit, and Sentry writes a tombstone for a discarded issue so that later events for it are dropped at intake instead of stored again.

Checka reviewer answers

Reviewed forThe aggregate pages mark referenced-after-erasure classes tombstone with the marker fields each keeps.

Marked guidance: a reviewer answers this question.

Discard Rows That Leave No Trace#

ruleruleguidance
litespec/core/privacy#discard-rows-that-leave-no-trace
Statement

A data class with no duty to keep a marker MUST use onErasure: discard.

Applies toartifact: record:retention-schedule

Why

A tombstone is still a row: it occupies storage, appears in counts, and invites readers to treat a gone subject as present. Where no reference and no audit needs the marker, deleting the row outright keeps the store honest.

Example

Lago discards a customer: the profile is hidden and its relations end, while finalized invoices and credit notes stay as the ledger.

Checka reviewer answers

Reviewed forThe onErasure entries on the aggregate pages carry discard where no marker duty exists.

Marked guidance: a reviewer answers this question.

Remove Child Rows Through Their Parent Only#

ruleruleguidance
litespec/core/privacy#remove-child-rows-through-their-parent-only
Statement

A data class erased only as a cascade from a parent erasure MUST use onErasure: cascade-only with the parent it follows.

Applies toartifact: record:retention-schedule

Why

Some rows have no subject of their own: line items belong to an invoice, receipt files belong to an expense, usage rows belong to a customer. A direct erasure request names the parent, never the child, so the child follows the parent's erasure and refuses a request addressed to itself.

Example

Cal.com deletes a user by removing the account and letting the database cascade remove the rows that hang off it, with no retention schedule; a product at this rung declares cascade-only and names the cascade path.

Checka reviewer answers

Reviewed forThe child class entries name cascade-only with the parent class, and the parent erasure tests clear the children.

Marked guidance: a reviewer answers this question.

Move Data to Its Next Controller Instead of Erasing#

ruleruleguidance
litespec/core/privacy#move-data-to-its-next-controller-instead-of-erasing
Statement

A data class handed to another controller MUST use onErasure: transferred with the receiver and the handover record.

Applies toartifact: record:retention-schedule

Why

Erasure is not the only end of custody: a branch closes and a successor takes its readers, a company is acquired, a contract moves to a new processor. The data survives under a new controller, so the record names the receiver and the handover both sides signed instead of a deletion that never happened.

Example

A support tool sends a loan summary and the reader message to a hosted AI model to draft a reply; the position names the model provider, its region and its retention, and the product stores none of it.

Checka reviewer answers

Reviewed forThe handed-over class entries name transferred with the receiver and the handover record.

Marked guidance: a reviewer answers this question.

Scope Erasure to What the Subject Requested#

ruleruleguidance
litespec/core/privacy#scope-erasure-to-what-the-subject-requested
Statement

Erasure that answers a subject request MUST use reach: requested and touch only the data the request names.

Applies toartifact: record:use-case

Why

A subject who asks to delete one order does not ask to delete the account, and a subject who asks to delete the account names everything. The requested reach ties the erasure to the request it answers, so a narrow request cannot widen into a broad deletion and a broad request cannot stop at one row.

Example

A request naming one hold erases that hold and leaves the reader's other loans untouched.

Checka reviewer answers

Reviewed forThe erasure use cases cite the request they answer and touch only the data it names.

Marked guidance: a reviewer answers this question.

State the Erasure Sentence in Intent#

ruleruleguidance
litespec/core/privacy#state-the-erasure-sentence-in-intent
Statement

The literal sentence the subject reads about an erasure MUST stand in Intent before the erasure ships.

Applies toartifact: record:requirement

Why

The sentence on the confirmation screen is the promise: what goes, what stays, and for how long. Behavior cannot word it, because only the product team decides what the product promises. Stating it in Intent puts the exact sentence readers see beside the requirement it fulfils.

Example

Mastodon shows on its account deletion form that content other servers have cached may persist, next to the promise that the account and its posts are removed; that sentence is the user-facing copy for a requested reach.

Checka reviewer answers

Reviewed forThe confirmation sentence in the Intent requirement stands before the release that shows it.

Marked guidance: a reviewer answers this question.

Complete the Subject Export Before Erasure#

ruleruleguidance
litespec/core/privacy#complete-the-subject-export-before-erasure
Statement

A data class with exportFirst MUST complete the subject export before its erasure runs.

Applies toartifact: record:retention-schedule

Why

Erasure destroys the only copy of data the subject may still want: identity documents, message history, purchase records. Completing the export first gives the subject their data while it still exists, so erasure never destroys what the subject asked to keep elsewhere.

Example

Claimwick makes finance download the tax-relevant data before a shredder runs, and refuses to shred when anything changed after that download.

Checka reviewer answers

Reviewed forThe export-first classes show a completed export before each erasure run in the run evidence.

Marked guidance: a reviewer answers this question.

Require a Fresh Export After Changes#

ruleruleguidance
litespec/core/privacy#require-a-fresh-export-after-changes
Statement

Erasure under unchangedSinceExport MUST stop and ask for a fresh export when the data changed since the last export.

Applies toartifact: record:retention-schedule

Why

An export taken last month does not cover rows written yesterday. When the data changed since the last export, erasing on the stale copy destroys rows the subject never received. Stopping for a fresh export keeps the export-first promise true at the moment of erasure.

Example

A reader who corrected their address after exporting it gets a fresh export first, and the erasure waits for it.

Checka reviewer answers

Reviewed forThe erasure runs after mid-window edits show a fresh export completed first.

Marked guidance: a reviewer answers this question.

Purge Erased Data from Restored Backups#

ruleruleguidance
litespec/core/privacy#purge-erased-data-from-restored-backups
Statement

A restore runbook MUST name the sweep job that re-applies erasure after the restore.

Applies toartifact: record:runbook

Why

A backup holds data as it was, including rows erased since: restoring it resurrects subjects the product promised to forget. The sweep job re-applies every erasure decided before the restore, so the restore brings the system back without bringing the erased data back with it.

Example

The database restore runbook names job/privacy.sweep-restored-erasure, which runs before traffic returns and deletes every row erased since the backup.

Checka reviewer answers

Reviewed forWhich restore runbooks name no sweep job? Look at the restore runbooks.

Marked guidance: a reviewer answers this question.

Record Which Duty Wins Each Conflict#

ruleruleguidance
litespec/core/privacy#record-which-duty-wins-each-conflict
Statement

Each retention conflict MUST name the winning duty and its basis.

Applies toartifact: record:retention-schedule

Why

Keeping for audit and erasing for the subject collide on the same row: the invoice the statute keeps sits beside the name the subject erases. Silence lets each implementer pick a winner. Naming the winning duty with its basis keeps one decision where every reader finds it.

Example

Claimwick keeps the expense ledger for seven years under tax law while erasing the submitter contact. ZITADEL keeps its audit events while erasing the user they describe, under the same rule.

Checka reviewer answers

Reviewed forThe retention schedule rows name the winning duty with its basis.

Marked guidance: a reviewer answers this question.

Conventions#

Keep Tombstone Fields Minimal#

conventiondefaultguidance
litespec/core/privacy#keep-tombstone-fields-minimal
Default

A tombstone keeps the row id and the erasure date, and no other field.

ReplacementA project lists wider tombstone fields with the rule that needs each one.

Applies toartifact: record:retention-schedule

Why

Every field on a tombstone is data kept past erasure. The row id and the date satisfy references and audits, and anything wider needs its own rule.

Checka reviewer answers

Reviewed forThe tombstone entries keep the row id and the erasure date, or the project lists wider fields with the rule behind each.

Marked guidance: a reviewer answers this question.

Run One Sweep Job per Data Class#

conventiondefaultguidance
litespec/core/privacy#run-one-sweep-job-per-data-class
Default

Each sweep job covers one data class.

ReplacementA project names the data classes each sweep job covers.

Applies toartifact: job

Why

One sweep per class keeps the blast radius small: a broken sweep delays one class while the others complete. A shared sweep is one failure away from resurrecting every class at once.

Checka reviewer answers

Reviewed forEach sweep job page covers one data class, or the project names the classes each job covers.

Marked guidance: a reviewer answers this question.