@@ -355,9 +355,9 @@ Each PII field gets `#[ITKDev\EntityBundle\Privacy\Attribute\Anonymize(strategy:
355355 than `--older-than` (based on `createdAt`) AND scrubs audit rows older than the configured retention
356356 (`itk_dev_entity.audit.retention`, default `P1Y`, with per-entity overrides). Idempotent.
357357
358- The mechanism is law -neutral; the same machinery applies to GDPR, CCPA, LGPD, PIPEDA, etc .
358+ The mechanism is regime -neutral and applies to most privacy laws that recognise a right to erasure .
359359
360- # ## GDPR semantics of strategies
360+ # ## Anonymization vs. pseudonymization
361361
362362Not every strategy produces anonymous data. Pick deliberately :
363363
@@ -366,9 +366,25 @@ Not every strategy produces anonymous data. Pick deliberately:
366366 resulting column is no longer personal data.
367367- ` Pseudonymize` — **pseudonymization.** Output is a deterministic short token derived from the cleartext and
368368 ` kernel.secret` , so rows that shared a value still collide post-scrubbing. Use this when you need to preserve
369- referential equality (e.g. correlating activity across tables) without retaining the cleartext. Under GDPR
370- Recital 26 the result is **still personal data** — apply the same access controls as you would to the cleartext, and
371- do not export it as "anonymized."
369+ referential equality (e.g. correlating activity across tables) without retaining the cleartext. Under most privacy
370+ regimes the result is **still personal data** — apply the same access controls as you would to the cleartext, and do
371+ not export it as "anonymized."
372+
373+ # ## Limitation: free-text fields containing PII
374+
375+ Strategies operate on the **whole value** of an annotated property — they rewrite a column, not substrings inside it.
376+ If a host app stores the subject's name, email, or other identifier inside a free-text column (`notes`, `description`,
377+ ` comment` , …), that text is still personal data and is in scope for erasure under most privacy regimes, regardless of
378+ which column it sits in. The bundle does **not** scan free text for embedded subject identifiers, so consumers face a
379+ coarse choice :
380+
381+ - Annotate the whole free-text column with `#[Anonymize(strategy: Strategy::Redact)]` or `Strategy::NullValue` — safe,
382+ but destroys the entire note (over-removal).
383+ - Leave it unannotated — under-removal; document the residual risk and handle it out-of-band (manual review, a
384+ host-app-specific cleanup task, …).
385+
386+ A finer-grained strategy that scans free text for the subject's known identifiers at scrub time and rewrites only those
387+ substrings is not currently shipped — host apps that need it have to implement it themselves.
372388
373389# # Configuration
374390
0 commit comments