Skip to content

Retention, history and safe deletion

Retention is a host-operator configuration change with irreversible data deletion. Project roles cannot raise deployment retention. Before shortening any horizon, obtain data-owner/compliance approval, export required evidence and validate a recoverable backup. All examples are unexecuted; this page does not authorize running a purge.

DataDefaultActual cleanup boundary
Execution summary90 daysBatched deletion by creation time; workflow children cascade with parent
stdout/stderr/structured lines in PostgreSQL14 daysWhole old monthly partitions, not exact per-row 14-day TTL
Execution/workflow I/O14 daysClears payload fields independently, keeping summary rows
Finished async run/result7 daysFinished rows; waiting future queued work is not simply aged out as finished output
Chat message ledger90 daysMessage history rows
Chat peer context180 days inactiveLast activity, not account creation time
Control-plane audit365 daysPlatform audit_logs, not external business audit
File-read audit90 daysPlatform access records
Idempotency key/stored response24 hoursRetry deduplication evidence/response horizon
Script previous versions50 superseded versions, clamp 1..1000Count per script on edits, not days
Published revisions20Pruned on publish, exact knob VIAT_PUBLISH_REVIAT_KEEP

See all retention variables for types, zero handling and scope. There is no general “0 means forever”: zero day counts are accepted and can delete almost everything old at the next pass. Zero interval is invalid for the timer even though numeric parsing accepts it. To preserve a hold, define an approved external evidence process; do not guess at a magic infinite value.

The loop defaults to every 24 hours. At boot it maintains PostgreSQL line-log partition coverage for the current and next five months. Destructive cleanup waits one full interval; it does not immediately purge everything on boot. Each pass logs errors and continues. Multiple instances coordinate the cluster job, but failure handling is idempotent rather than an immutable exactly-once guarantee.

A monthly partition intersecting the line cutoff must remain, so observed line retention can exceed the configured number of days. Conversely, payloads can disappear before the corresponding execution summary. A null captured payload is not proof the original request was empty. Full execution deletion also removes dependent workflow steps. Storage reuse/file shrinking after PostgreSQL DELETE is controlled by database vacuum/storage management, not immediate operating-system space reclamation.

Disabling VIAT_RETENTION_ENABLED also disables the loop’s partition maintenance and expired OAuth/session/ticket/MFA/login-failure cleanup; it is not a safe unbounded-retention strategy without replacement maintenance. Upload-spool and other dedicated sweeps are separate. Do not manually drop active partitions or truncate parent log tables to “fix” a full disk.

  1. Inventory what is kept in PostgreSQL, ClickHouse/Loki, business databases, object stores, container logs, backups and exports. Deleting the platform row does not erase external copies.
  2. Define approved minimum/maximum retention per class. Consider personal data in chat context and execution payloads, compliance evidence in audit, and clients’ retry policy for idempotency.
  3. Export required audit evidence and record a backup/recovery point before lowering horizons. A database snapshot taken afterward cannot restore what was already purged.
  4. Change the relevant deployment variables, forwarding them into Compose explicitly, then restart under a maintenance plan. A smaller value applies to already-existing old rows at the next pass; it is not just a new-row policy.
  5. Watch server retention messages and database disk/row/partition trends. Investigate permission, lock, DDL and storage errors; do not claim cleanup succeeded because the process stayed healthy.
  6. Verify representative old/new records and external stores. Retain the approved change record and remove temporary export files only under your evidence policy.

Example unexecuted policy, not a universal recommendation:

VIAT_RETENTION_EXECUTION_DAYS=90
VIAT_RETENTION_PAYLOAD_DAYS=7
VIAT_RETENTION_LINE_DAYS=14
VIAT_RETENTION_AUDIT_DAYS=365
VIAT_RETENTION_IDEMPOTENCY_HOURS=24
VIAT_RETENTION_INTERVAL_HOURS=24

Shortening idempotency retention can allow an old retry to execute again once its stored key/response is gone. Shortening async-result retention can make callers lose completed output. Keep client behavior aligned with the chosen horizon, and provide durable business storage for outputs that must live longer.

ClickHouse/Loki TTLs, PostgreSQL-resource business audit, S3 lifecycle/versioning, local file bytes, container logs and backups are operator-owned policies, not controlled by the above loop. External secret backends can retain historical values after resource changes; coordinate their lifecycle with retained database references. Rust shared-artifact garbage collection is off by default and unsafe across mixed toolchains/architectures without a complete live set.

A mistakenly shortened horizon cannot be undone by increasing it. Stop further destructive sweeps under approved incident control, preserve the affected state, and restore into an isolated environment first using backup/restore. Reconcile only required data back under a reviewed plan; blindly replacing production with an old database loses newer writes and may resurrect revoked credentials or queued side effects.