Open app

Evidence, not a badge

GDPR Compliance Matrix

The machine-verifiable map from GDPR obligation to the control implemented in this repository. test_compliance_matrix.py asserts that every cited code path and test exists, that every roadmap row carries a date, and that no cell contains an overstated compliance claim. MedLineage acts as a processor; rows marked controller describe what the software provides *to* the controller, who remains responsible for their own obligations. This document supports an audit conversation; it is not legal advice.

Status vocabulary: implemented | partial | roadmap(YYYY-MM).

ArticleObligationRoleControlCodeTestsStatus
Art. 5(1)(b)Data collected for specified explicit purposes onlysharedConsent rows carry an explicit purpose; external-output routes check consent per purpose when MEDRECORD_CONSENT_ENFORCEMENT_ENABLED is on (posture depends on deployment flag)consent.pytest_consent.pyimplemented
Art. 5(1)(c)Data minimizationprocessorAudit log rejects free-text inputs; verification-demand ledger stores graph ids and enums only; agent audit stores content hashes, never raw payloads; structured logs carry tenant hash, never raw patient idsaudit.py, verification_demand.py, agent_runtime.pytest_audit.py, test_verification_demand.pyimplemented
Art. 5(1)(d)Accuracy; inaccurate data correctedsharedClinician attestation ledger (correct/incorrect/unclear verdicts), demand-weighted review prioritization, extraction-corrections storeledger.py, verification_demand.py, migrations/0015_extraction_corrections.sqltest_ledger.pyimplemented
Art. 5(1)(e)Storage limitationprocessorOffline opt-in retention sweeper over packets, feedback JSONL, and (explicit opt-in) access_log; cadence set by operator per docs/GDPR/RETENTION.mdretention.py, docs/GDPR/RETENTION.mdtest_stage1_gdpr.pypartial
Art. 6Lawful basis for processingcontrollerController determines the basis; the software records a basis string on consent rows and the Connect ingest surface carries a legal_basis field per pushconsent.py, api/connect_v1_routes.pytest_consent.pyimplemented
Art. 7(1)Demonstrable consentsharedPOST /api/consent writes a consent row plus an append-only consent_event trailconsent.pytest_consent.py, test_api/test_api_consent_audit.pyimplemented
Art. 7(3)Withdrawal as easy as giving consentsharedPOST /api/consent/withdraw; subsequent gated reads are denied and the denial is loggedconsent.py, audit.pytest_consent.py, test_api/test_api_consent_audit.pyimplemented
Art. 9(2)Special-category (health) data conditionscontrollerHealth data processed only under controller instruction; the DPA template's processing annex scopes categories and purposesdocs/GDPR/DPA_TEMPLATE.md-implemented
Art. 12Transparent information to data subjectssharedIntended-use disclaimer rendered on PDF page 1, frontend not-medical-advice modal, public PRIVACY.mdui_strings.py, export.py, PRIVACY.mdtest_intended_use.pyimplemented
Art. 15Right of access (SAR)processorGET /api/audit/access?patient_id= projects the per-patient access history; per-patient Data Room and account export produce the data copyaudit.py, data_room.py, account_data.pytest_audit.py, test_data_room.pyimplemented
Art. 16RectificationprocessorOperator-mediated: attestation verdict incorrect plus extraction-corrections store; no patient self-service rectification APIledger.py, migrations/0015_extraction_corrections.sqltest_review_console.pypartial
Art. 17Erasureprocessordelete_patient hard-deletes every patient-scoped table plus feedback JSONL; POST /api/connect/erase for partner-driven erasure; access_log retained under Art. 17(3)(b)patient_graph.py, account_data.pytest_api/test_account_data.py, test_erasure_cascade.pyimplemented
Art. 18Restriction of processingprocessorNo restriction mechanism yet; erasure and consent withdrawal are the available levers--roadmap(2026-10)
Art. 20Portability (structured, machine-readable)processorByte-deterministic Data Room tar.gz with canonical JSON and a FHIR R4 bundle; tenant-scoped account exportdata_room.py, fhir.pytest_data_room.pyimplemented
Art. 21Right to objectcontrollerController-side decision; the software provides the withdrawal and erasure channels the controller invokesconsent.py, account_data.pytest_consent.pyimplemented
Art. 22No solely-automated decisions with legal or similar effectprocessorNon-diagnostic by design: deterministic scoring, safety guardrails redact violating sections, recommendation-verb lints on every user-facing surfacesafety.py, scoring.pytest_safety.pyimplemented
Art. 25Data protection by design and by defaultprocessorAll persistence surfaces default OFF; pseudonymous HMAC-derived patient ids; content-addressed ids carry no PHI; per-purpose signing-key domain separationconfig.py, graph_ids.py, signing.pytest_graph_ids.py, test_signing.pyimplemented
Art. 28Processor contractsharedFill-in DPA template plus sub-processor schedule shipped with the productdocs/GDPR/DPA_TEMPLATE.md, docs/GDPR/SUBPROCESSORS.md-implemented
Art. 30Records of processing (ROPA)processorOne access_log row per external-output access, allowed or denied, with flag-off short-circuit rows so enabling enforcement later leaves no gap; GET /api/audit/access is the ROPA viewaudit.pytest_audit.py, test_api/test_api_consent_audit.py, test_api/test_connect_v1_summary.pyimplemented
Art. 32Security of processingprocessorPBKDF2 operator credentials, HMAC-signed ledger with boot-time secret guard, per-IP rate limiting, upload validation, HSTS when forced HTTPS, tenant partition isolation; no encryption at rest yetaccounts.py, signing.py, api/ratelimit.py, api/uploads.py, tenant.py, docs/GDPR/TOMS.mdtest_auth.py, test_api/test_security.py, test_multitenant_isolation.pypartial
Art. 32(1)(c)Restore availability after incidentsharedBackup and restore runbook for the SQLite statedocs/GDPR/BACKUP_RESTORE.md-implemented
Art. 33, 34Breach notification (authority, data subjects)sharedOperator runbook template; structured JSON logs and optional Sentry for detection; no automated notification toolingdocs/GDPR/INCIDENT_RESPONSE.md, config.py-partial
Art. 35DPIAcontrollerDPIA support template plus data-flow narrative maintained alongside the codedocs/GDPR/DPIA.md, docs/GDPR/DATA_FLOW.md-implemented
Art. 44-49Third-country transferssharedSub-processor schedule documents each transfer (Anthropic API) and its safeguard; operator chooses deployment regiondocs/GDPR/SUBPROCESSORS.md-implemented

Open gaps, ranked by cost/value

Art. 5(1)(e) sweep coverage — the retention sweeper covers packets, feedback, and access_log; newer tables accumulate outside it. roadmap(2026-09).

Art. 16 self-service — rectification is operator-mediated today. A patient-facing channel is a product decision, not scheduled.

Art. 32 encryption at rest — deliberate V1 boundary (partition-key separation, not crypto). roadmap(2026-12).

Art. 33/34 tooling — runbook only; automated breach-notification tooling unscheduled.

Art. 18 restriction — roadmap(2026-10).

Notes: comms_inbound is keyed by phone + business_ref (no patient_id column); its erasure path is the business_ref delete, invoked from the comms lifecycle, and is out of the patient-cascade's mechanical scope.