> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vorel.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Data retention

> Your conversation transcripts live in your CRM, not in Vorel. ADR-locked per-class TTL windows, four architectural invariants, and why this is enforced in code rather than in policy.

**Your conversation transcripts live in your CRM, not in Vorel.**

That sentence is a load-bearing architectural commitment, not a marketing claim. Vorel-side persistence of conversation transcripts, PII, and quality signals is short-lived and bounded by retention windows that are frozen in an internal, audited architecture decision record and enforced by code at every turn. To change a retention window for the platform default, a Vorel engineer has to amend that record, change a constant in source, ship the change through code review, and the change is visible in git history forever. There is no admin toggle that widens retention; there is no "we'll keep your transcripts for our records" option.

This page explains the four-class taxonomy that classifies every row Vorel persists, the per-class retention windows, the four architectural invariants that keep the commitment honest as the product evolves, and why "architectural, not policy" is the language we use.

## The four-class taxonomy

Every Vorel-side persistence surface (every Postgres table, present and future) is classified into one of four classes. The classification is not a label on a docs page; it is a CI gate that refuses to merge a schema change unless the new table declares a class and a retention rule.

<CardGroup cols={2}>
  <Card title="Class (a): In-flight operational state" icon="bolt">
    State that exists only while a conversation is live. Cleared at conversation close. The
    shortest-lived class. Examples: in-process dispatch context, request-scoped tenant overlays,
    agent step state during a single turn.
  </Card>

  <Card title="Class (b): Operational telemetry" icon="chart-line">
    Metrics, cost rollups, latency samples, A/B assignments, quality signals. No transcript content
    in the row body. Each table has an ADR-frozen TTL window (30 days to 365 days depending on the
    table's purpose).
  </Card>

  <Card title="Class (c): Transcripts + PII" icon="user-shield">
    Conversation transcripts, customer profiles, lead qualification state, appointments, cases.
    Cached Vorel-side only until the row is mirrored into your CRM, then purged on the ADR-frozen
    post-write schedule. **The shortest practical retention any customer-facing AI vendor can
    ship.**
  </Card>

  <Card title="Class (d): Audit-only" icon="scroll">
    Long-lived by design, narrow in scope. Audit log, billing events, tenant configuration, cutover
    events. Each class-(d) table carries a load-bearing reason on the schema audit matrix. Adding a
    new class-(d) table requires an audited policy amendment.
  </Card>
</CardGroup>

Class (a) is empty by construction at platform launch; no row currently waits to be cleared at conversation close. It becomes populated as new in-flight state is added through future workstreams. The empty slot is deliberate; it makes the architectural gap visible to future auditors rather than burying it.

## Per-class TTL windows

The windows below are policy-locked. Changing any of them requires a code change to the canonical retention-window constants plus an audited policy amendment, both of which are visible in git history. Tenants can dial retention *down* (narrower than platform default) via an audited operator-side override; tenants cannot dial it up past the platform default.

### Class (c): transcripts and PII

These are the rows that carry the actual conversation content, the customer identity, and the qualification state. The TTL clock starts at the business event (conversation closed, appointment completed, case resolved) AND at a successful CRM-write. Whichever finishes later anchors the purge.

| Vorel-side row                         | Retention from business event + CRM-write | Why                                                                                          |
| -------------------------------------- | ----------------------------------------- | -------------------------------------------------------------------------------------------- |
| `conversations` (closure event)        | **30 days** post-close                    | The CRM-side conversation note is the authoritative artifact; this row is a closure cache.   |
| `messages` (per-turn transcript)       | **7 days** post-insert                    | The shortest TTL on the platform. The CRM-side per-turn note is the authoritative copy.      |
| `customers` (cross-channel identity)   | **30 days** post-last-touch               | Identity cache only. Your CRM's customer record is authoritative.                            |
| `customer_profiles` (recent summaries) | **30 days** post-update                   | Summary content is transcript-derived; the destination is your CRM's custom-property batch.  |
| `leads` (qualification state)          | **30 days** post-update                   | Vorel holds qualification state until the CRM Lead/Deal mirrors it.                          |
| `appointments` (booking record)        | **60 days** post-scheduled-end            | Booking confirmation cache. Mindbody, HubSpot Meeting, Salesforce Event are authoritative.   |
| `cases` (multi-conversation primitive) | **90 days** post-close                    | Longer than `conversations` because cases span multiple conversations; CRM is authoritative. |
| `case_transitions` (state changes)     | **90 days** post-insert                   | Append-only audit of case state changes; mirrored to CRM as a timeline.                      |
| `case_transition_proposals`            | **90 days** post-decision                 | Rejected proposals never get a CRM-write and purge directly at the 90-day window.            |
| `case_messages` (case-scoped turns)    | **90 days** post-insert                   | Tied to the case lifecycle; CRM-side case object holds the long-term record.                 |
| `case_runtime_events`                  | **90 days** post-insert                   | Case-runtime telemetry tied to the case window.                                              |

### Class (b): operational telemetry

These rows do not contain transcript content (or only reference it by foreign key). They drive operator dashboards, cost reconciliation, and quality analytics.

| Vorel-side row                       | Retention    | Why                                                                                                   |
| ------------------------------------ | ------------ | ----------------------------------------------------------------------------------------------------- |
| `voice_turn_latency`                 | **90 days**  | Trailing-quarter regression window for first-token-to-speech tuning. Aggregate rollups survive purge. |
| `voice_call_cost`                    | **365 days** | Billing reconciliation window. Also covers PCI payment-resolution reconciliation.                     |
| `voice_call_cost.payment_resolution` | **365 days** | PCI reconciliation: the discriminator that records whether a vault-redirect payment completed.        |
| `llm_calls`                          | **90 days**  | LLM usage analytics + cost reconciliation against vendor invoices.                                    |
| `webhook_deliveries`                 | **30 days**  | Tenant has the canonical copy in their receiver; the Vorel-side row is forensic-only after delivery.  |
| `prompt_experiment_assignments`      | **90 days**  | Aligned with parent conversation purge cadence.                                                       |
| `prompt_variant_assignments`         | **90 days**  | Aligned with parent message purge.                                                                    |
| `prompt_revision_proposals`          | **365 days** | Quarterly operator-triage cadence on prompt-quality improvements.                                     |
| `quality_signals`                    | **365 days** | Trend rollups for the operator-side quality dashboards.                                               |
| `quality_failures`                   | **365 days** | Aligned with `quality_signals`.                                                                       |
| `calibration_observations`           | **90 days**  | Aligned with parent message purge.                                                                    |
| `shadow_dispatch_comparisons`        | **30 days**  | Pipeline-cutover research artifact. Transcript-derived; shorter window.                               |
| `hallucination_flag_reviews`         | **365 days** | Quality-trend analysis window; the operator's review note may quote turn content.                     |

### Class (d): audit-only

Long-lived. The list is intentionally small: tenant configuration, user accounts, audit log, billing events, voice cutover events, LoRA adapter records, knowledge base, webhook configuration, voice number registry, prompt experiments, incidents, API keys, prompt variant definitions. Each entry carries a documented reason for being long-lived; adding a new class-(d) row to the platform requires an audited policy amendment.

## The four architectural invariants

The TTL windows above are enforced by a scheduled worker that runs hourly. The invariants below are what makes the commitment durable: they are the difference between "we have a retention policy" and "retention is architecturally enforced."

<Steps>
  <Step title="TTL windows are policy-locked, not a UI toggle">
    Changing a per-table retention window requires an amendment to the internal, audited retention policy (the CRM-as-System-of-Record commitment), a change to the canonical retention-window constants in source, and a deploy. The operator admin console *displays* the current window per table but does not expose a write toggle that would widen it. The platform default is the policy-locked baseline; per-tenant overrides are operator-flippable, audited, and can only narrow retention below the platform default.
  </Step>

  <Step title="Class-(c) writes attempt a CRM mirror">
    Every insert into a class-(c) table goes through a CRM-write wrapper that attempts a write into your tenant's configured CRM. The wrapper is fire-and-forget on the dispatch hot path (so the customer-facing turn latency stays voice-grade), and a `pending_crm_sync` flag tracks whether the CRM-write has succeeded. If the CRM is reachable and the write succeeds, the Vorel-side row is eligible for purge on its TTL. If the CRM-write fails, the row stays Vorel-resident until either a redrive succeeds or a 24-hour escalation window expires, at which point a `crm_sync_failure` incident opens for the operator to reconcile.
  </Step>

  <Step title="Amendments require git-history-visible policy changes">
    The architectural commitment is non-amendable except via the audit-trail-visible path: git pull request → policy amendment → code review → deploy. Procurement teams asking "can you change the retention to suit our policy?" get the answer "yes, via a documented policy amendment that is visible in our git history, not via a checkbox in our admin console." The narrowing path (per-tenant overrides) does not require a policy amendment because narrowing is always safe; widening is not.
  </Step>

  <Step title="Per-tenant overrides are operator-only, audited, and narrows-only">
    Tenants who need shorter retention (a healthcare-adjacent tenant who wants `messages` purged at 24 hours instead of 7 days, for example) can set per-tenant retention through their Vorel operator. The override lands in the `tenants.<table>_retention_days` column, the change writes an `audit_log` row visible to the tenant's admin, and the next scheduled purge respects the narrower window. There is no path through any product surface to widen retention past the platform default.
  </Step>
</Steps>

## Why architectural, not policy

Almost every customer-data vendor has a retention policy. A policy is a sentence in a contract. A policy can be amended by signing an addendum. A policy can lapse silently if the team that wrote it leaves the company. A policy does not survive engineering drift.

Vorel ships retention as a **code-level architectural commitment** backed by a continuous-integration gate that refuses to merge a schema pull request that lacks a class declaration. The gate runs on every PR that touches the database schema. If a future engineer adds a new table that holds transcript content without classifying it as class-(c) and pointing it at the retention worker, the CI build fails and the change cannot land. There is no path to drift from this commitment without a deliberate policy amendment, a code change, and a code review, all of which leave permanent git-history-visible artifacts.

Sierra (the largest AI agent vendor by valuation as of May 2026) has not shipped an equivalent architectural enforcement. Decagon, Cresta, Fin (Intercom), Ada, PolyAI, and Parloa have not either. A competitor can match this with a contract addendum in ten minutes; matching it architecturally requires refactoring their persistence layer.

This is the kind of commitment Vorel will not walk back without a documented, audited policy amendment. If a future amendment loosens these windows, the loosening itself will be visible in git history: auditable forever.

## What this means for your operations

* **Your CRM is the authoritative record** for conversation transcripts, customer profiles, qualification state, appointments, and cases. Audit-able artifacts live there, not at Vorel. If a regulator asks for the transcript of a conversation from six months ago, that transcript lives in your HubSpot / Salesforce / Mindbody / Toast; Vorel-side purged it on the 7-day post-CRM-write window for `messages`.
* **Billing reconciliation has a longer window** (365 days for `voice_call_cost`) because cost reconciliation against vendor invoices runs on a quarterly cadence. The row body does not contain transcript content; the row references the conversation by id.
* **Audit log is long-lived** (class-(d)) and survives application-layer right-to-erasure scrubs. When a customer requests deletion under PDPL Art. 17 / GDPR Art. 17, transcript content is redacted and the deletion event itself is recorded as a new audit row with a salted-hash reference to the original customer identifier: provable deletion without re-introducing the PII.
* **Per-tenant narrower retention is available on request**. If your compliance regime requires shorter windows than the platform default for any class-(c) table, talk to your Vorel operator before kickoff; the override lands as an audit-logged tenant setting.

## Related docs

* [Compliance](/security/compliance): DPA, sub-processor disclosure, SOC 2 trajectory, PCI scope.
* [Data handling](/security/data-handling): what we collect, where it lives, right-to-access and right-to-erasure paths.
* [Product → CRM](/product/crm): how Vorel writes into your CRM and treats your CRM as the system of record.
* [Security overview](/security/overview): multi-tenant isolation, encryption, append-only audit, rate limiting.

{/* verified-against: roadmap/adr/0018-moat-thesis-horizontal-and-cxbench.md Decision (B) item 1 — CRM-as-SoR architectural commitment */}
