Skip to main content
Wildo.ai Coming soon

Privacy and subject rights

Remove personal details while preserving required records

Coordinate deletion and declared field scrubbing while keeping retained records hidden and frozen.

Personal field values are scrubbed while the retained record remains stored under its declared treatment.

Remove personal details while preserving required records

Erasing a person’s information does not always mean deleting every related record. Some records must remain, while names, contact details or other personal values must be removed from them.

Wildo separates those decisions. Relationships determine what happens to dependent records; retention and field treatments determine what survives and what is scrubbed.

Example — Close a contact’s data journey

A contact’s name is replaced and optional personal details are cleared. Related records follow their declared lifecycle treatment. The retained contact row remains for its stated purpose, outside ordinary reads and edits.

For engineers

RETAIN_AND_IMPERSONALIZE keeps, hides and freezes a row while scrubbing declared fields. RETAIN_ONLY is for rows with no personal field values to scrub. The actual USERS configuration combines the retained-row decision with the separate session-principal decision:

Source: users.shared.resources-config.schemas.ts (selected declarations; intervening comments omitted).

  retentionPolicy: {
    mode: ErasureRetentionMode.RETAIN_AND_IMPERSONALIZE,
  },
  dataSubjectPolicy: { kind: ResourceDataSubjectKind.SELF_PRINCIPAL },

Fields declare .impersonalizeWith(...): REMOVE clears a clearable field, MASK writes a schema-valid replacement, and RESET restores a supported static default. The factory rejects contradictions such as treatments on RETAIN_ONLY or a scrubbing mode without any effective scrub. A retained row is not an anonymous row, nor proof that re-identification is impossible.

Invoke SystemAccessService.eraseSubjectAsSystem(resourceType, explicitIds, options) through your application’s request workflow. It classifies dependent edges and refuses unclassified destructive decisions before writing. Dependents are handled before the subject, making a retry possible when work cannot finish. IMPERSONALIZE_AND_RETAIN on a relationship is an edge decision; immediate versus lazy execution is a separate timing choice.

Inspect subjectImpersonalized, each edge’s disposition and executed, and external effect outcomes before recording completion. An executed empty edge means there was nothing to remove; a declined destructive edge requires follow-up. Administrative continuity acknowledgements are explicit per-request controller decisions, not defaults to switch on.

Adding retention changes the persisted schema and uniqueness treatment. Register the resource coherently and apply the corresponding database migration. The operator decides why a record is retained and for how long; erasure retention does not itself set an expiry schedule.

Give each personal field a concrete treatment

Illustrative schema fragment using the existing field decorators, paired with RETAIN_AND_IMPERSONALIZE:

const contactFields = z.object({
  name: z.string().impersonalizeWith(RedactionType.MASK, { maskValue: 'Erased contact' }),
  personalNote: z.string().nullish().impersonalizeWith(RedactionType.REMOVE),
});

The replacement must satisfy the field schema; REMOVE writes null, so the receiving field must accept null. These treatments scrub the personal values while the retention policy keeps the row out of ordinary use. The contact’s separate data-subject policy must also state whether it represents an account.

Usage excerpt after the application has verified the request and resolved its service and scope:

const receipt = await systemAccessService.eraseSubjectAsSystem(
  subjectResourceType,
  verifiedSubjectIds,
  { scopeContext },
);

const unresolvedExternalEffects = receipt.externalEffects.filter(effect =>
  isIncompleteSubjectErasureExternalEffect(effect.status),
);

The selector comes from @wildo-ai/saas-models. It includes partial, failed, unregistered and acknowledged-non-erasure outcomes. Controller acknowledgement does not make retained third-party data disappear. Inspect these outcomes alongside subjectImpersonalized, edge execution and session resolution before closing the request; do not turn successful local return into an unconditional completion status.

Building a B2B product or an internal tool?

Wildo is not self-service yet. Tell us what you have in mind and we will say plainly whether it fits, and what happens next.