Annotations
This content is for 0.1. Switch to the latest version for up-to-date documentation.
Core annotation models — the data map vocabulary, storage-agnostic.
Authoring helpers that attach these to concrete ORMs live in
effaced.adapters (SQLAlchemy first). The models here are pure data:
they validate, serialize, and never import a database library.
PiiSpec
Section titled “PiiSpec”class PiiSpec(BaseModel): category: PiiCategory description: str | None = None erasure: ErasureStrategy = ErasureStrategy.DELETE legal_basis: LegalBasis | None = None purpose: str | None = None retention: RetentionPolicy | None = NoneFull declaration for one personal-data field.
Built by the adapter authoring helpers (e.g.
effaced.adapters.sqlalchemy.pii); read back by
effaced.manifest.DataMap.
Fields:
- category (
PiiCategory): What kind of personal data this is. - description (
str | None): Optional human note for audits and the PII linter. - erasure (
ErasureStrategy): What happens on Art. 17 erasure. Defaults toDELETE. - legal_basis (
LegalBasis | None): Why the data is processed at all (Art. 15 metadata). - purpose (
str | None): Processing purpose, surfaced verbatim in export bundles. - retention (
RetentionPolicy | None): Required whenerasureisRETAIN(and allowed withANONYMIZEto document why the record itself survives).
RetentionPolicy
Section titled “RetentionPolicy”class RetentionPolicy(BaseModel): basis: LegalBasis = LegalBasis.LEGAL_OBLIGATION duration: timedelta | None = None reason: str = Field(min_length=1)Why and how long a value must outlive an erasure request.
Fields:
- basis (
LegalBasis): The lawful basis that overrides erasure. - duration (
timedelta | None): How long the duty lasts, if bounded.Nonemeans indefinite / determined externally. - reason (
str): Human-readable legal duty (e.g."§147 AO invoice retention").
SubjectLink
Section titled “SubjectLink”class SubjectLink(BaseModel): is_subject_table: bool path: str subject_id_column: str = Field(default='id', min_length=1)How a table’s records reach the data subject.
A dotted relationship path from the annotated table to the subject
table, e.g. "order.user" for an order_items table whose records
belong to the user owning the parent order. The subject table itself
uses the empty path "".
Fields:
- is_subject_table (
bool): Whether this link marks the subject table itself. - path (
str): Dotted relationship path;""marks the subject table. - subject_id_column (
str): Identifier field on the subject table that callers pass to export/erasure entry points. Defaults to"id".
SubjectRef
Section titled “SubjectRef”class SubjectRef(BaseModel): extra: dict[str, str] = Field(default_factory=dict) kind: str = Field(min_length=1, max_length=255) value: str = Field(min_length=1, max_length=255)Opaque reference to one data subject, passed to resolvers.
Resolvers receive references (e.g. a Stripe customer id), never the subject’s rich PII — the library moves identifiers, not data.
Fields:
- extra (
dict[str, str]): Additional identifiers a resolver may need (string-typed on purpose — refs must stay loggable and PII-light). - kind (
str): Namespace of the identifier ("stripe","email"). Refs are routed to the resolver whosenameequals the ref’skind(ADR 0008). - value (
str): The identifier itself.