Anvil.PII (Anvil v0.1.1)
View SourcePII (Personally Identifiable Information) field annotation handling.
This module provides functions for managing PII metadata on schema fields, including PII levels, retention policies, and redaction strategies.
PII Levels
:none- No PII expected (e.g., boolean labels, enums):possible- May contain PII (free-text fields with guidelines to avoid PII):likely- Expected to contain PII (e.g., labeler feedback, error reports):definite- Always contains PII (e.g., labeler email, IP address)
Retention Policies
:indefinite- Keep forever (structural labels with no PII)<integer>- Days until eligible for deletion (e.g., 90, 365)
Redaction Policies
:preserve- Keep field unchanged (explicit opt-in):strip- Remove field entirely:truncate- Truncate to first N characters:hash- Hash value (preserves uniqueness for grouping):regex_redact- Apply regex-based redaction patterns
Examples
iex> field_metadata = %{pii: :possible, retention_days: 365, redaction_policy: :truncate}
iex> Anvil.PII.pii_level(field_metadata)
:possible
iex> Anvil.PII.redaction_policy(field_metadata)
:truncate
Summary
Functions
Calculates the expiration date for a field based on retention policy.
Checks if a field is expired based on retention policy.
Returns true if the field has any PII risk (level other than :none).
Returns the PII level for a field based on its metadata.
Returns the redaction policy for a field based on its metadata.
Returns the retention policy for a field based on its metadata.
Checks if a field should be redacted during export based on redaction mode.
Validates PII metadata structure.
Types
@type pii_level() :: :none | :possible | :likely | :definite
@type redaction_policy() :: :preserve | :strip | :truncate | :hash | :regex_redact
@type retention_policy() :: :indefinite | pos_integer()
Functions
@spec expiration_date(map(), DateTime.t()) :: DateTime.t() | nil
Calculates the expiration date for a field based on retention policy.
Returns nil for indefinite retention.
Examples
iex> submitted_at = ~U[2025-01-01 00:00:00Z]
iex> metadata = %{retention_days: 90}
iex> Anvil.PII.expiration_date(metadata, submitted_at)
~U[2025-04-01 00:00:00Z]
iex> metadata = %{retention_days: :indefinite}
iex> Anvil.PII.expiration_date(metadata, ~U[2025-01-01 00:00:00Z])
nil
@spec expired?(map(), DateTime.t(), DateTime.t()) :: boolean()
Checks if a field is expired based on retention policy.
Examples
iex> submitted_at = ~U[2024-01-01 00:00:00Z]
iex> now = ~U[2025-12-01 00:00:00Z]
iex> metadata = %{retention_days: 90}
iex> Anvil.PII.expired?(metadata, submitted_at, now)
true
iex> metadata = %{retention_days: :indefinite}
iex> Anvil.PII.expired?(metadata, submitted_at, now)
false
Returns true if the field has any PII risk (level other than :none).
Returns the PII level for a field based on its metadata.
Defaults to :none if not specified.
@spec redaction_policy(map()) :: redaction_policy()
Returns the redaction policy for a field based on its metadata.
Defaults to automatic policy based on PII level if not specified:
:none->:preserve:possible->:truncate:likely->:strip:definite->:strip
@spec retention_policy(map()) :: retention_policy()
Returns the retention policy for a field based on its metadata.
Defaults to :indefinite if not specified.
Checks if a field should be redacted during export based on redaction mode.
Redaction Modes
:none- No redaction (trusted internal exports):automatic- Apply schema-defined redaction policies:aggressive- Strip all fields with PII level:possibleor higher
Examples
iex> field_meta = %{pii: :none}
iex> Anvil.PII.should_redact?(field_meta, :automatic)
false
iex> field_meta = %{pii: :possible, redaction_policy: :truncate}
iex> Anvil.PII.should_redact?(field_meta, :automatic)
true
iex> field_meta = %{pii: :possible}
iex> Anvil.PII.should_redact?(field_meta, :aggressive)
true
Validates PII metadata structure.
Returns :ok if valid, {:error, reason} otherwise.