EvidenceLocker EU Regulatory Persistence
EvidenceLocker owns the durable persistence substrate for EU regulatory artifacts. CRA, NIS2, DORA, RoI, TLPT, and standards-mapping producers should write audit events, retention metadata, and artifact ledger rows here instead of creating module-local regulatory tables.
Contracts
- Audit events:
docs/contracts/eu-regulatory-audit-events-v1.md. - Artifact ledger and retention metadata:
docs/contracts/eu-regulatory-artifact-ledger-v1.md. - Schema/taxonomy pins:
docs/europe/schema-taxonomy-pin-inventory.md.
Persistence
The embedded baseline 001_v1_evidencelocker_baseline.sql (line 439 onward; folded in from the pre-1.0 007_regulatory_audit_retention_ledger.sql, now archived and not embedded) creates:
evidence_locker.regulatory_audit_eventsevidence_locker.regulatory_retention_recordsevidence_locker.regulatory_artifact_ledger
The same migration adds optional regulatory retention/ledger reference columns to evidence_bundles and decision_capsules. The reference columns are indexes only; canonical replay remains driven by the dedicated EU tables.
All three EU tables are tenant scoped and protected by row-level security using app.current_tenant, matching existing EvidenceLocker tables. Startup convergence is handled by the EvidenceLocker embedded migration runner. Migration 019_regulatory_retention_horizon.sql adds the persisted created_at + retention_years horizon check for new and updated retention rows. It is deliberately NOT VALID, so historical rows remain an explicit operator audit before the constraint is validated.
Runtime API
IRegulatoryEvidenceRepository is the local persistence boundary. EvidenceLocker exposes the source-owned HTTP read API GET /api/v1/regulatory/artifact-ledger for downstream services and CLIs. Graph and other consumers must call that API or a typed client over it rather than reaching into these tables directly. The current repository supports:
- Recording canonical audit events with classified-property redaction.
- Upserting retention records with bounded DORA RoI retention, TLPT minimums, and a persisted calendar-year horizon derived from the row’s original
created_at. - Linking DORA RoI Decision Capsule rows to retention records and returning the linked retention policy id, retention years, retain-until timestamp, legal hold timestamp, and override audit event id through capsule responses and exports.
- Upserting artifact ledger rows with sorted source evidence refs.
- Looking up artifacts by
(tenantId, regime, artifactType, contentHash)for deterministic replay. - Querying ledger rows by tenant with optional regime, artifact type, and reporting-year filters. Results are ordered by reporting year descending, artifact type ascending, artifact hash ascending, and ledger record id ascending. Pagination uses opaque offset cursors.
requireMatch=trueon the HTTP API returns404 artifact_not_foundfor missing prior-year or required artifact lookups.
NIS2 control-register snapshots are projected from Policy as hash-only regulatory artifacts. The ledger stores nis2-control-register-snapshot and nis2-statement-of-applicability records with source refs back to the Policy snapshot/event ids and the EvidenceLocker bundle ref. Policy remains the source of truth for control entries, lifecycle events, and snapshot JSON.
Retention Rules
- DORA RoI default retention is 7 years.
- DORA RoI tenant overrides are bounded to 5-10 years.
- TLPT evidence-pack retention has a 10-year minimum.
- Every retention record must have a non-default
createdAt, andretainUntilmust be at leastcreatedAt.ToUniversalTime().AddYears(retentionYears). Calendar-year/leap-day semantics apply; overflow fails closed. - Legal hold cannot compensate for a shorter declared horizon, and a
shorteningApprovalRefonly authorizes shortening relative to an earlier commitment. It does not exempt the record from its declared minimum. - Shortening a previously committed retain-until date requires an explicit
shorteningApprovalRef; otherwise the rule fails closed.
Privacy Boundary
Audit actor and approver fields must use opaque ids or service references. Human names, email addresses, credentials, and other sensitive details belong in classified properties, where canonicalization hashes Personal values and redacts Sensitive values before persistence.
