Chapter 16 · Security, Reliability, and Governance
Retention, Privacy, Lineage, and Data Quality
Governance becomes real only when ownership, retention, lineage, and quality expectations are represented by executable processes and evidence. Keeping data forever is not neutral: it increases cost, legal exposure, and the impact of security failures.
Learning outcomes
Turn governance expectations into repeatable controls
Design retention schedules from purpose, legal need, and operational value.
Distinguish deletion, anonymization, pseudonymization, archival, and legal hold.
Record lightweight lineage between sources, transformations, and outputs.
Define measurable data-quality dimensions and executable checks.
Assemble ownership, evidence, remediation, and review into a governance operating model.
Data has a lifecycle
Lifecycle controls should be triggered by events and reviewed against documented purpose, not by indefinite storage defaults.
Retention policy as data
CREATE TABLE retention_policy ( policy_code TEXT PRIMARY KEY, object_name TEXT NOT NULL, trigger_event TEXT NOT NULL, active_days INTEGER NOT NULL CHECK (active_days >= 0), archive_days INTEGER NOT NULL CHECK (archive_days >= 0), terminal_action TEXT NOT NULL CHECK ( terminal_action IN ('delete','anonymize','review') ), owner TEXT NOT NULL, legal_basis TEXT NOT NULL, reviewed_at TEXT NOT NULL) STRICT;INSERT INTO retention_policy VALUES('customer_profile','customer','account_closed',30,0,'anonymize','privacy','service + legal review','2026-08-01'),('sales_order','sales_order','order_completed',2555,365,'review','finance','financial recordkeeping','2026-08-01'),('security_audit','security_audit','event_created',365,730,'delete','security','security monitoring','2026-08-01');SELECT * FROM retention_policy ORDER BY object_name;Deletion, anonymization, and pseudonymization
| Action | Meaning | Can the original identity return? |
|---|---|---|
| Deletion | Remove the record and dependent copies according to policy | Not from the deleted system; backups need separate expiry handling |
| Irreversible anonymization | Transform data so the person is no longer reasonably identifiable | Designed not to be reversible |
| Pseudonymization | Replace direct identifiers with a token while retaining a re-identification path | Yes, by an authorized holder of the mapping or key |
| Archival restriction | Move data to a less accessible tier for required retention | Yes; access is limited, not eliminated |
| Legal hold | Temporarily suspend normal deletion for specified records | Yes, until the hold is released |
Privacy-aware erasure workflow
Do not delete blindly from the parent table. Discover obligations, active orders, legal holds, downstream copies, analytical exports, search indexes, and backups. Then execute an approved workflow with evidence.
BEGIN IMMEDIATE;-- Example eligibility: already deleted and no non-cancelled orders.UPDATE customerSET email = 'deleted+' || customer_id || '@invalid.example', full_name = 'Deleted Customer', date_of_birth = NULL, marketing_consent = 0WHERE customer_id = :customer_id AND deleted_at IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM sales_order AS o WHERE o.customer_id = customer.customer_id AND o.status <> 'cancelled' );-- Remove a token that is not needed for financial recordkeeping.UPDATE sales_orderSET payment_token = NULL, customer_id = NULLWHERE customer_id = :customer_id AND status = 'cancelled' AND changes() = 1;COMMIT;Production code should verify affected-row counts explicitly and record the policy, approval, request ID, and outcome. Avoid relying on a long implicit chain of changes() calls.
Lineage as a graph
Lineage records which data products depend on which sources and transformations. It supports impact analysis, incident response, reproducibility, and ownership.
CREATE TABLE lineage_edge ( upstream_object TEXT NOT NULL, downstream_object TEXT NOT NULL, transformation TEXT NOT NULL, owner TEXT NOT NULL, code_version TEXT NOT NULL, observed_at TEXT NOT NULL, PRIMARY KEY (upstream_object, downstream_object, transformation)) STRICT;INSERT INTO lineage_edge VALUES('commerce.customer','reporting.customer_order_summary','join + aggregate','analytics','git:4ab7c2e','2026-08-05'),('commerce.sales_order','reporting.customer_order_summary','join + aggregate','analytics','git:4ab7c2e','2026-08-05'),('reporting.customer_order_summary','dashboard.executive_sales','semantic projection','bi-team','dashboard:v12','2026-08-05');SELECT upstream_object, downstream_object, owner, code_versionFROM lineage_edgeORDER BY upstream_object, downstream_object;Quality dimensions and contracts
| Dimension | Question | Example metric |
|---|---|---|
| Completeness | Are required values present? | Non-null email rate |
| Validity | Do values satisfy format, domain, and range rules? | Percentage of recognized status codes |
| Uniqueness | Are business identifiers duplicated? | Duplicate active email count |
| Referential integrity | Do references resolve? | Orphan order count |
| Timeliness | Is the data recent enough for its purpose? | Minutes since latest successful load |
| Consistency | Do related representations agree? | Order total versus line-item sum |
| Accuracy | Does the value reflect the real-world fact? | Sampled reconciliation against authoritative source |
Executable quality checks
CREATE TABLE data_quality_result ( check_name TEXT NOT NULL, measured_at TEXT NOT NULL, observed_value REAL NOT NULL, threshold_value REAL NOT NULL, comparison TEXT NOT NULL CHECK (comparison IN ('<=','>=','=')), passed INTEGER NOT NULL CHECK (passed IN (0,1)), details TEXT, PRIMARY KEY (check_name, measured_at)) STRICT;INSERT INTO data_quality_resultSELECT 'active_customer_email_completeness', datetime('now'), AVG(CASE WHEN email IS NOT NULL AND trim(email) <> '' THEN 1.0 ELSE 0.0 END), 1.0, '>=', AVG(CASE WHEN email IS NOT NULL AND trim(email) <> '' THEN 1.0 ELSE 0.0 END) >= 1.0, 'Expected 100% for active customer records'FROM customerWHERE deleted_at IS NULL;INSERT INTO data_quality_resultSELECT 'orphan_order_count', datetime('now'), COUNT(*), 0, '=', COUNT(*) = 0, 'Orders whose non-null customer_id does not resolve'FROM sales_order AS oLEFT JOIN customer AS c ON c.customer_id = o.customer_idWHERE o.customer_id IS NOT NULL AND c.customer_id IS NULL;SELECT * FROM data_quality_result ORDER BY check_name;Governance operating loop
Governance is a feedback system with owners and remediation, not a static spreadsheet.
Governance review
- Why is indefinite retention a security decision?
- Why does pseudonymized data often remain sensitive?
- How does lineage help during a breaking schema change?
- What must happen when a quality check fails?
Review the answers
More retained data increases breach impact and operational exposure. Pseudonymization preserves a re-identification path and may remain linkable. Lineage identifies downstream consumers and owners before deployment. The failure needs severity, owner, evidence, remediation, and a decision on whether to block publication or continue under an explicit exception.
Chapter capstone checklist
| Control family | Required artifact | Verification |
|---|---|---|
| Identity and access | Role matrix, owners, grants, exception approvals | Automated success and denial tests |
| Injection prevention | Parameterized data-access layer and identifier allow-lists | Security unit tests and code review |
| Recovery | Backup inventory, keys, restore runbook, dependency map | Scheduled isolated restore with measured RPO/RTO |
| Protection and audit | Classification catalog, encryption boundaries, audit schema | TLS verification, log review, key-recovery test |
| Lifecycle and quality | Retention schedule, holds, lineage, quality contracts | Deletion/anonymization drill and quality evidence |
Chapter summary
- Authenticate every identity and authorize through role-based least privilege.
- Keep untrusted values separate from SQL syntax with parameterized queries.
- Measure recoverability through recurring restore tests, not backup-job success alone.
- Layer encryption, masking, auditing, and classification according to explicit threats.
- Govern data through purpose, retention, privacy workflows, lineage, quality checks, owners, and evidence.
Chapter 17 moves from governance to practical database access: SQL dialects, command-line and graphical tools, drivers, connection pools, prepared statements, ORMs, query builders, raw SQL, migrations, seed data, and database changes in Git.