Data Retention Matrix
What this is. One privacy map for the data probectl keeps: what kind of data it is, why it exists, where it lives, and what clock deletes it. ELI5: every data set is a labeled box. The label says what is inside, why we are allowed to keep it, which shelf it sits on, and which timer removes it.
This page is a governance/control map, not a new retention engine. Today,
retention is still enforced by the owning stores and lifecycle paths:
ClickHouse TTLs plus ClickHouse hourly rollups, the in-memory TSDB window,
derived identity-cache pruning, audit pruning after durable export, AI-answer
pruning on write, and tenant/subject erasure. The audit-retention runner wakes
hourly in every profile. The single deployment profile defaults to 0
(provider rows keep forever), while a finite tenant audit_retention_days
override can still tighten its own local rows. multi-tenant and regulated
default to a finite 8760h (365-day) deployment maximum and require WORM/SIEM
watermark configuration before startup.
/v1/lifecycle/retention lets a tenant set stricter per-plane clocks for
flow, OTLP, eBPF, path, audit, persisted AI answers, object artifacts, and
derived identity caches; NULL means the deployment default remains in force.
Where a backing store cannot safely delete one tenant's older rows locally
(for example a remote aggregate TSDB or object store lifecycle), the sweeper
emits an honest delegated/not-capable receipt instead of pretending it pruned.
The machine-checkable data inventory lives in internal/govern.DataInventory().
The privacy gate fails if a row lacks owner, data classes, retention,
processors, export behavior, tenant deletion semantics, or subject deletion
semantics. Current inventory IDs: audit-evidence, ai-artifacts,
backups-snapshots, device-endpoint-state, ebpf-telemetry,
flow-telemetry, identity-rbac-scim, object-artifacts,
otlp-traces-logs, path-topology, probe-results, shared-open-data,
siem-cursors.
Enforcement Model
- Tenant first, then purpose. Every retained row, object key, metric, and export cursor is tenant-scoped before RBAC or governance policy is considered. If the tenant cannot be proven, the read/delete path returns nothing.
- Age retention is store-owned. High-volume ClickHouse stores use delete TTLs for raw rows and hourly rollup tables for lower-resolution history; the in-memory TSDB uses an arrival-time window; audit logs prune only after WORM/SIEM export proves the evidence survived elsewhere.
- Lifecycle deletion is wider than age retention. Tenant erase and subject erase are the privacy "big brooms": they remove or project data across live stores even when a store has no age TTL.
- Policy and proof commit together. A tenant retention-policy update and
its explicit
lifecycle.retention_setaudit event use the same tenant-scoped PostgreSQL transaction. If either write fails, neither becomes visible. - Engine-owned prunes are audit-gated. Before the lifecycle engine deletes
session detail, flow/OTLP/eBPF/path rows, persisted AI answers, endpoint
history, or derived topology/endpoint cache entries, a bounded provider-audit
intent must commit. Its non-secret
attempt_idpairs it with anenforced/failedcount-only terminal receipt. Failed intent means no prune; failed terminal append is returned to the scheduler instead of being hidden in a warning. - Delegated clocks are receipts, not triggers. The tenant
objectsclock describes external object lifecycle, so the lifecycle engine emits onedelegatedreceipt and does not claim an intent or deletion it did not invoke. Audit is different: its dedicated hourly runner resolves the tenant's effective bounded window and emitsaudit.retention_pruneonly when a SIEM-watermarked prefix is actually removed. - Copies keep their own clock. Backups, WORM exports, and customer SIEM destinations are not live stores. probectl records the configured backup window and export cursor, but the destination system owns its own retention.
- No object-store age TTL is enforced by FSStore. The filesystem object store keeps objects until tenant erase/subject erase, explicit prefix delete, or the operator's bucket/filesystem lifecycle policy removes them.
Data-Class And Purpose Matrix
| Data set | Default class | Purpose | Primary home | Retention and deletion clock |
|---|---|---|---|---|
| Synthetic/canary probe results, including DNS answers | pii for IPs/targets; internal for labels; result attributes may carry tenant data |
Network and SLO troubleshooting: "did this tenant's path resolve and respond?" | TSDB series, result views, and bus payloads under tenant_id |
Lightweight mode uses PROBECTL_TSDB_MEMORY_RETENTION (0 means the built-in 1h window). Remote Prometheus/VictoriaMetrics retention is configured in that TSDB. Tenant erase deletes in-memory series or calls the Prometheus admin delete-series path when enabled; otherwise the attestation records the manual step. Subject export/erase covers in-memory metric names and labels via tsdb_metrics; remote TSDB subject workflows are recorded as aggregate-backend/manual delete-series or retention age-out. DNS answers live inside result attributes, so they follow the probe-result clock. |
| Flow telemetry | pii for source/destination IPs; confidential for ports/protocols/ASN enrichment |
Traffic accounting, segmentation evidence, incident context, and cost attribution | ClickHouse probectl_flows plus hourly probectl_flow_rollups_hour, or in-memory flow store |
PROBECTL_FLOW_RETENTION_DAYS defaults to 90 days and applies a ClickHouse delete TTL to raw rows; 0 is an explicit keep-forever opt-out. Hourly rollups are tenant-partitioned and backfillable. Migration v5 stores the raw row's subject-match identity values in subject_keys, so new rollups remain verifiably subject-erasable after raw rows age out; it also replaces still-backfillable pre-v5 rollups without deleting older rollup-only history. Per-tenant flow_retention_days can tighten the raw-row clock. |
| eBPF host/L7 flow telemetry | pii for peer IPs and process/user-adjacent labels; confidential for service edges |
Host/service dependency mapping, L7 observability, and NDR-lite signals | ClickHouse eBPF tables or in-memory eBPF store | PROBECTL_EBPF_RETENTION_DAYS defaults to 30 days and applies eBPF ClickHouse TTLs; 0 disables that age TTL. Tenant erase removes the tenant's live eBPF rows. Subject lifecycle removes/export matches from backends with subject-capable workload-label filtering and otherwise records the aggregate age-out clock. |
| Path/traceroute evidence, Topology labels, and device identity-conflict claims | pii for hop/management/interface IPs; internal or confidential for hostnames, device/interface labels, sites, source agents, and topology annotations |
Change-aware topology, path RCA, blast-radius reasoning, and review of conflicting attribution | ClickHouse path tables plus hourly path hop/link rollups and tenant-partitioned internal/topology memory/index stores |
PROBECTL_PATH_RETENTION_DAYS defaults to 90 days for raw path/traceroute ClickHouse TTLs. Hourly hop/link rollups keep lower-resolution tenant-scoped history while raw path rows age out. The topology memory/index store is a replayable derived identity cache: PROBECTL_DERIVED_IDENTITY_RETENTION_DAYS defaults to 90 days and prunes stale nodes, edges, and normalized identity-conflict claims from query/export surfaces, with lifecycle.retention_sweep receipts for deleted evidence. Conflict storage is capped per tenant and contains normalized provenance only—never raw telemetry or credentials. Tenant erasure drops the entire tenant graph and every conflict claim. Subject lifecycle filters/removes matching topology labels and connected edges in subject-capable graph stores; device nodes are counted separately in the receipt. A tighter tenant flow_retention_days also tightens this derived-cache clock. |
| OTLP traces and logs | pii or restricted when attributes/bodies contain user IDs, IPs, emails, tokens, or request data |
Application/host correlation with network incidents | ClickHouse OTLP store or memory store | PROBECTL_OTEL_RETENTION_DAYS defaults to 30 days for ClickHouse trace/log TTLs; 0 disables that TTL. Attribute/body caps and redaction reduce blast radius, but tenant/subject erase is the privacy deletion path for matching OTLP data. |
| Device telemetry, LLDP/CDP neighbor evidence, endpoint/DEM metrics, and SNMP/gNMI attributes | pii for management/interface IPs and endpoint-user identifiers; confidential for hostnames, physical adjacency, inventory, and config posture |
Device health, physical-link correlation, endpoint experience, and operational inventory | TSDB, forced-RLS device_neighbor_evidence, device/endpoint stores, topology device nodes, and tenant-scoped API views |
Metric samples follow the TSDB retention clock (PROBECTL_TSDB_MEMORY_RETENTION in memory mode or the remote TSDB's policy). LLDP/CDP rows are current-snapshot evidence: each source snapshot replaces its prior rows, storage is capped at 256 rows/device and 16,384 rows/tenant, reads at 500, and evidence older than 24h is pruned on write. Tenant deletion cascades all neighbor rows. Endpoint latest-view labels are a derived identity cache pruned by PROBECTL_DERIVED_IDENTITY_RETENTION_DAYS with lifecycle.retention_sweep receipts. Subject lifecycle removes/exports matching endpoint labels and topology device nodes where supported; aggregate copies report their retention basis. The device agent's correlation cache prunes stale sysName/interface labels with PROBECTL_DEVICE_CORRELATION_RETENTION (default 90 days, 0 disables). Durable inventory/config rows are lifecycle-managed and erased with the tenant or data subject. |
| User directory attributes, RBAC, SCIM, sessions, and tenant membership | pii for names/emails; restricted for credentials/tokens; confidential for roles and groups |
Authentication, authorization, provisioning, and audit attribution | Postgres tenant tables with RLS and envelope-sealed secrets where applicable; the global pre-tenant locator contains only credential kind/row UUID/hash/tenant/inactive timestamps, never identity or session PII | Kept while the identity/tenant is active. User deprovision, subject erase, and tenant erase are the deletion paths, including deletion of locator/revocation metadata. Tokens/secrets are stored as hashes or sealed values; no age TTL exists for directory rows unless the owning subsystem adds one. |
| Audit entries, provider audit, break-glass records, and WORM segments | confidential to restricted because they prove who touched what |
Non-repudiation, compliance evidence, incident response, and break-glass accountability | Postgres audit chains, tenant-routed audit_subject_erasures hash projections, plus optional signed WORM object segments |
PROBECTL_AUDIT_RETENTION defaults to 0 (provider keep forever) in the single profile and to 8760h (365 days) in multi-tenant / regulated. A finite tenant audit_retention_days value tightens its own window; positive deployment windows are hard maxima and longer tenant values are rejected. Production-like profiles fail closed unless PROBECTL_AUDIT_WORM_DIR, a stable WORM signing key, and SIEM export are configured. Tenant rows prune only below the durable siem_delivery cursor; provider rows always use the deployment window and prune only below the signed WORM segment watermark. The pruner deletes only a contiguous eligible prefix and emits an audit.retention_prune receipt with the effective window. Before an exported privacy.subject_erase marker can leave that prefix, its tenant-scoped one-way hash is atomically captured in the append-only projection table; this lets later eligible rows progress while reads/exports stay redacted. Un-exported evidence is never deleted. /readyz.audit_retention and /metrics expose the deployment-level provider posture. |
| AI prompts and answers, feedback, citations, and model/config hashes | pii or restricted when evidence contains tenant telemetry, operator text, or secrets |
RCA reproducibility, dispute resolution, and answer quality feedback | Optional privacy-minimized Postgres answer artifacts and feedback rows; remote model side only when explicitly enabled | PROBECTL_AI_PERSIST_ANSWERS=false means answers are not persisted by default. When enabled, the stored answer and ai.ask audit question are tokenized before they enter Postgres; PROBECTL_AI_ANSWER_RETENTION defaults to 2160h (90 days) and is pruned opportunistically on write. Tenant/subject erase removes matching persisted answers. Remote model retention is outside probectl and is allowed only through the remote-AI egress gates. |
| Shared incident evidence snapshots | confidential after mandatory tenant/secret stripping plus the configured privacy redaction (PII and IP masking are default-on) |
Reproduce a cited incident-room investigation for another authorized tenant user | Postgres incident_share_artifacts with forced RLS and explicit tenant_id predicates |
Each snapshot has a mandatory expiry: seven days by default, shortened by a tighter tenant object_retention_days value. Expired/revoked rows are unreadable and are pruned opportunistically on creation; tenant erase removes all rows by tenant cascade. Every successful create/read is audited. |
| Incident investigation journal | confidential; bounded human-authored plain text plus IDs/details from an already-redacted cited share |
Preserve local hypotheses, checkpoints, and conclusions through an incident | Postgres incident_journal_entries with forced RLS, explicit tenant_id predicates, and a composite tenant+incident foreign key |
Entries expire after 90 days by default, shortened by a tighter tenant object_retention_days value. Reads return at most 200 live rows. Checkpoint sources are re-authorized on append and read; expired/revoked/missing/foreign references expose no evidence details. Expired rows are pruned opportunistically, tenant erase cascades them, and subject export/erasure covers matching body/author data. Appends and reads are audited. |
| Incident correlation overrides | confidential; operator identity, reason text, and network target/prefix |
Preserve an explicit human decision to split falsely grouped incident evidence until reversal | Postgres incident_correlation_overrides with forced RLS and composite tenant-bound foreign keys |
Retained with the incident unless explicitly reversed or deleted by lifecycle. Tenant erase cascades all rows. Subject export/erasure count-verifies deletion when the subject matches creator/reverser identity, target/prefix, or reason text; the immutable tenant audit chain keeps a hash-projected receipt without retaining the erased subject literal. |
| Saved dashboards, report schedules, and PDF/CSV report artifacts | confidential; exact values may include tenant topology/traffic posture, while owner/generator fields may be pii |
Repeatable tenant evidence snapshots and operator-requested local report delivery | Postgres dashboard_views, dashboard_report_schedules, and capped dashboard_report_artifacts, all with forced RLS and composite tenant foreign keys |
Kept until the saved dashboard or tenant is deleted; tenant deletion cascades through all three tables. Core currently exposes no artifact age-TTL or single-artifact delete route, so operators must include these tables in their PostgreSQL retention policy instead of assuming the tenant object_retention_days clock applies. Artifact download and every create/delivery action are audited. |
| Object artifacts: support bundles, lifecycle exports, test bundles, browser artifacts, backup/WORM files | Usually confidential; may be restricted when logs, configs, screenshots, or audit evidence are included |
Portability, support, test distribution, backup/restore, and immutable audit export | Object store: filesystem, S3, or MinIO under tenant prefixes/buckets | No object-store age TTL is enforced by FSStore. Tenant erase deletes the tenant prefix through the objectstore DeletePrefix path. Backup files follow PROBECTL_BACKUP_RETENTION_DAYS and PROBECTL_BACKUP_RETENTION_NOTE in the deletion attestation, plus the operator's bucket/object-lock lifecycle policy. |
| Open-data and threat-intel shared feeds | public or source-license-governed shared data |
Enrichment: ASN/RPKI/peering, outage context, CT/threat-intel matches | Shared feed caches and threat/opendata stores | These are ingested once, read-only, and scoped when joined to tenant data. They are not tenant telemetry. Retention/cache TTL is source-specific and must honor source AUP/provenance; source outages degrade gracefully. |
| SIEM-exported copies and SIEM cursors | Exported events are confidential; redaction removes known secrets/PII keys before forwarding |
Customer SOC correlation and long-term security evidence | Customer SIEM plus probectl's per-tenant delivery cursor | SIEM retention is owned by the destination SIEM. probectl keeps only the cursor needed to resume delivery without dropping events; audit retention may prune local events only after durable WORM/SIEM export. |
| Backups and snapshots | Same class as the source data, usually restricted |
Disaster recovery and regulated rollback | Operator backup system, sealed backups, database/object-store snapshots | Live-store erasure does not instantly purge historical backups. PROBECTL_BACKUP_RETENTION_DAYS records a concrete backup-erasure deadline in the tenant-erasure attestation; PROBECTL_BACKUP_RETENTION_NOTE records the operator's human-readable backup policy. |
Config Clocks
| Clock | Default | Scope | What it controls |
|---|---|---|---|
PROBECTL_TSDB_MEMORY_RETENTION |
0 = built-in 1h |
Deployment | In-memory TSDB sample window. |
PROBECTL_FLOW_RETENTION_DAYS |
90 |
Deployment, with tenant override via flow_retention_days |
ClickHouse raw-flow delete TTL; hourly flow rollups remain until lifecycle deletion. |
PROBECTL_EBPF_RETENTION_DAYS |
30 |
Deployment | ClickHouse eBPF delete TTL. |
PROBECTL_PATH_RETENTION_DAYS |
90 |
Deployment | ClickHouse raw path/traceroute delete TTL; hourly path rollups remain until lifecycle deletion. |
PROBECTL_OTEL_RETENTION_DAYS |
30 |
Deployment | ClickHouse OTLP trace/log delete TTL. |
PROBECTL_DERIVED_IDENTITY_RETENTION_DAYS |
90 |
Deployment, tightened by tenant flow_retention_days |
Topology and endpoint latest-view identity labels derived from source stores; deletion emits lifecycle.retention_sweep receipts. |
PROBECTL_DEVICE_CORRELATION_RETENTION |
2160h |
Device agent | In-agent SNMP/gNMI correlation cache for sysName/interface labels; 0 disables agent-local age pruning. |
PROBECTL_AUDIT_RETENTION |
0 in single; 8760h in multi-tenant / regulated |
Deployment maximum, tightened by tenant audit_retention_days |
Provider rows use this window; 0 keeps them forever. Tenant NULL inherits it and a finite tenant value can tighten even a keep-forever single deployment. Tenant rows require the SIEM cursor, provider rows require the WORM watermark, and actual prune receipts carry the effective window. Production-like profiles reject 0 and missing WORM/SIEM watermarks. |
PROBECTL_AI_PERSIST_ANSWERS |
false |
Deployment | Whether AI answers are stored at all. |
PROBECTL_AI_ANSWER_RETENTION |
2160h |
Deployment | Age window for persisted AI answers when persistence is enabled. |
PROBECTL_BACKUP_RETENTION_DAYS |
0 = note-only |
Deployment/operator policy | Backup-erasure deadline recorded in deletion attestations. |
PROBECTL_BACKUP_RETENTION_NOTE |
Generic fallback | Deployment/operator policy | Human-readable backup retention statement in deletion attestations. |
Practical Reading
- If an auditor asks "how long do flow rows live?", start at the flow row and
check
PROBECTL_FLOW_RETENTION_DAYS, then check whether the tenant has a tighterflow_retention_daysoverride. - If they ask about topology or endpoint labels, check
PROBECTL_DERIVED_IDENTITY_RETENTION_DAYS; a tenant's tighterflow_retention_daysshortens that derived-cache window too. - If they ask about a person, use subject export/erase. Age TTLs are coarse
timers; subject lifecycle is the tenant-scoped privacy control. Its manifest
lists every privacy-relevant plane with exported/deleted counts, projected
audit status, not-deployed status,
covered_by_parentfor RUM labels covered bytsdb_metrics,retained_encrypted_evidencefor the provider-only IR sidecar that ordinary subject reads cannot access, ornot_capableplus the age-out/delete-series basis for aggregate backends that cannot safely delete one subject locally. A subject erasure receipt iscomplete:trueonly when every deployed plane was erased, count-verified clean, or explicitly preserved as separately encrypted evidence; any deployednot_capableplane keeps itcomplete:falsewhile the report is still hashed and written to provider audit. - If they ask about backups or SIEM, give the probectl attestation/cursor plus the operator's SIEM or backup policy. probectl cannot truthfully promise the destination deleted its copy.