Skip to content
Version: Current

Data Retention Policy

Draft pending counsel review — not legal advice, not in force until approved by the owner

This policy restates the operator’s retention schedule (version 2026-10-20, owner security@tcp.systems, source: ops/docs/trust/retention-schedule.md). Reviewed by: (pending) · Reviewed on: (pending).

UK GDPR sets no fixed periods: each period must be justified, reviewed, and data actually erased or anonymised at the end of it. Accounting records are the one hard number: six years from the end of the relevant financial year - with a penalty for failure. Offline storage is still processing, backups are in scope, and pseudonymised data is still personal data (source: ibid., introduction).

# Data System Live period Justification End-of-life action
1 Account email, account id, session acumen database, tcp while the account is active; 30 days after closure contract performance and account security delete the row; sessions expire
2 API key id, label, scopes, created/revoked timestamps acumen database while active; 90 days after revocation (target) abuse investigation and billing disputes delete; keep only the aggregate usage counter
3 Request metadata: timestamp, model, token count, latency, status, provider Prometheus on tcp 90 days the status page’s 30/90-day uptime history and incident review; no request content age out by Prometheus retention
4 Usage and billing aggregates acumen database 6 years accounting-records duty archive, then delete after the legal period
5 Prompt and completion content not written to the router database; the optional exact-match cache is disabled (2026-10-20) and its bodies purged; upstream provider per its terms transit only delivering the requested inference nothing to erase in the router; provider terms govern the copy they hold
6 Diagnostic content logs, if an operator enables them journald 30 days maximum, enforced by the journald drop-in debugging a specific fault journalctl --vacuum-time=30d
7 Access and application logs journald on tcp (Caddy writes no file access log) 30 days, enforced by the journald drop-in security and fault investigation journald vacuum
8 Harness gate snapshots and gate records git history in tcpsystems/harness indefinite change-management evidence; contains no personal data none required
9 Harness memory events (gate verdicts, decisions, incidents) the harness memory event log, host-local JSONL per memory/README.md 30 days (memory/README.md) operating memory with explicit consent pruned by the harness, redacted before write
10 Security reports and disclosure correspondence postmaster mailbox (maddy), mail backups 3 years evidence of handling a report; legal defence delete from the mailbox; backups age out
11 Other business correspondence postmaster / operator mailbox 24 months ordinary correspondence delete
12 Invoices and accounting records acumen database / accounting records 6 years GOV.UK accounting-records rule archive, delete after six years
13 Mail backups (restic, off-host) restic repository on core 7 daily + 5 weekly + 6 monthly snapshots recovery from deletion or corruption restic forget --prune runs with each backup
14 Ad-hoc database copies (pre-deploy-*, pre-incident-*, pre-routing-*) /var/lib/acumen/ 30 days maximum (policy) rollback artefacts for a deploy or incident delete; no copy is a backup
15 Status page data status service memory only 30-second cache rendering the page process exit
16 Fleet metrics and logs on dsh (VictoriaMetrics, Loki) dsh unknown not established in this pass record the real retention before relying on this row

(Source: ops/docs/trust/retention-schedule.md, “Schedule”. Row 16’s period is unknown in the source, not a number this page invents.)

The router ships an optional exact-match cache. When enabled it stores a complete response body in exact_cache, keyed by sha256 of the post-rewrite request body plus four routing headers, applying only to non-streaming requests with temperature == 0, no tools and no session header. It was enabled by default until 2026-10-20, when it was switched off (ACUMEN_EXACT_CACHE=0, which skips both lookup and write), its 134 rows (417,509 bytes of bodies) were deleted, the WAL was checkpointed and the database vacuumed (source: ibid., “Row 5 in detail”). Two properties made the cache incompatible with this schedule: the stored value is response content, not metadata, and the key carried no account or virtual-key namespace. If the cache is ever re-enabled it must first gain a per-account key namespace, a retention horizon and a scheduled purge, and this table must be rewritten in the same change (source: ibid.).

How long a deletion still exists somewhere (source: ibid., “Erasure latency”):

  • Live database: a verified deletion is effective within 24 hours, followed by VACUUM.
  • Metrics: no per-subject deletion; series are not keyed by subject and age out at 90 days.
  • journald: targeted deletion is not supported; the worst case is the 30-day vacuum window.
  • Mail backups: a deleted message leaves the live mailbox immediately and can persist in retained monthly snapshots for up to about six months.
  • Ad-hoc database copies: deleted within 30 days; a copy can extend the life of a deleted record by that much.

A legal hold (accounting records, an active dispute, or a regulator’s request) suspends deletion for the specific records named in the hold.

No scheduled off-host backup of the acumen database (recovery risk, not a privacy defect); the acumen schema is not yet mapped table-by-table to this schedule; retention on dsh (row 16) is unknown (source: ibid., “Evidence and gaps”). The acumen database purge copy from 2026-10-20 and the four ad-hoc copies it references are themselves row-14 artefacts with a 30-day maximum life (source: ibid.).