Skip to main content

D70 — Age-based retention prunes + the config-driven D31 7-year compliance floor (RESOLVED)

Architecture decision record, relocated verbatim from the retired single-file docs/tenancy/ decision log. Status, thematic clusters, and how to record a new ADR: the decision log index.

The three deferred Phase-0 prune follow-ups (docs/tracking/conduit-phase-0-prerequisites.md §B) have LANDED as scheduled console commands, and the D31 7-year KYC/AML + audit retention floor now lives in a single config value — config('foundation.compliance_retention_floor_days') (2555) — the one place every compliance-relevant prune clamps to (env()-free literal; larastan forbids env() outside root config/).

  • foundation:prune-command-dedup-records (daily, onOneServer()->withoutOverlapping()): per-tenant under RLS, SOFT-deletes command_dedup_records claims older than config('foundation.dedup_retention_days') (30 — frees the partial-unique tuple for re-use), then HARD-deletes rows past config('foundation.dedup_hard_delete_after_days') (7). NO floor clamp — a dedup record is exactly-once bookkeeping, not compliance content. Iterates tenants via Stancl\Tenancy\Tenancy::query() (NOT Modules\Tenancy\Models\Tenant) so the Foundation kernel keeps its zero-domain-dependency (ModuleBoundaryTest).
  • rails:prune-vendor-logs (daily): CENTRAL (no tenant iteration), batched DELETE ... WHERE id IN (SELECT id ... LIMIT 5000) on the pgsql_logs connection until drained. Guarded by config('rails.telemetry_only') (default true) — the vendor log is transport/audit TELEMETRY, not the KYB system of record, so it prunes at config('rails.retention_days') (90); flip it false and the cutoff clamps UP to the floor.
  • mirrors:prune-drift (daily): per-tenant under RLS, force-deletes RESOLVED mirror_drift older than max(config('provider-mirror.drift_retention_days') /*365*/, floor). An OPEN drift is NEVER deleted at any age (live evidence); a resolved drift on a regulated resource is evidence, hence the floor clamp.

All three are sanctioned in CqrsBoundaryTest by exact class (the dedup/vendor-log commands use the DB facade; the drift command uses its own MirrorDrift model) — the SideEffectLogWriter / ReconcileStaleMirrorsCommand precedents. Compliance ratification of the exact 7-year window is still pending (§A, D31 / #3) — but it is now a one-line config change, not a code change.


← Decision log index