Files
AutopilotMonitor/src/Backend/AutopilotMonitor.Functions/DataAccess/TableStorage
Oliver Kieselbach 5ba4fb7dc9 feat(backend): retention/cleanup for previously-unbounded append-only tables
Several append-only tables had no purge mechanism and grew unbounded. Add
age-based retention to the 2h MaintenanceFunction (and the manual path) via a
new CleanupUnboundedTablesAsync orchestrator (per-table try/catch, fixed const
windows, mirroring the DistressReports pattern):

- GlobalNotifications + TenantNotifications: hybrid retention — dismissed rows
  pruned 30d after DismissedAt, any row pruned 180d after CreatedAt. Unread
  (still-actionable) admin warnings survive the dismiss window so they are never
  silently lost; the 180d catch-all bounds the table. Shared pure predicate
  NotificationRetentionFilter.BuildPredicate (unit-tested).
- HardwareRejectionNotificationTracker: 30d (FirstNotifiedAt). Pruning re-arms
  the lifetime dedup, so a model rejected again >30d later re-bells (intended).
- AuditLogs: 180d (system Timestamp, cross-partition).
- UsageMetrics: 180d (PartitionKey date-string range).
- BackupJobs: 365d (QueuedAtUtc).

PlatformStats intentionally excluded — it is a single upserted row, not
append-only. Bootstrap sessions left as-is (feature currently unused).

Each repo delete mirrors DeleteUserActivityOlderThanAsync: server-side
"X lt cutoff" filter + select PK/RK + delete loop. Deletes are resumable across
runs, so a partial run self-heals on the next cycle.

Observability: end-of-run MaintenanceLongRunning Warning OpsEvent if RunAllAsync
exceeds 10min, dual-registered in OpsAlertRulesSection.tsx, to surface a run
climbing toward the 60min functionTimeout before a future hard-abort (which
emits nothing).

Inert until backend redeploy; first post-deploy run bulk-prunes the backlog.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 17:11:28 +02:00
..
2026-05-07 09:58:53 +02:00
2026-05-07 09:58:53 +02:00