Skip to Content
EngineeringRunbooksTenant offboarding

Tenant offboarding

Offboarding an organisation is an export followed by a deletion, done by one worker job (export_and_delete_org) and audited as organization.offboard. The procedure is designed for the R2 gate and belongs to the data-processing agreement together with the retention and purge rules; this page is the operator view of what the job does so it can be reviewed before it exists in code.

Audit rows and signatures are never deleted while the tenant exists: the application role cannot delete them and their foreign keys refuse deletion of what they reference. Offboarding is the one procedure that removes a tenant’s data, and it keeps the hash of the final audit export so the export can be verified later.

Order

  1. Freeze. Archive every program (org.programs.manage), disable every connection, drain the interactive lane for the organisation and confirm no running agent runs remain. Programs are archived, not deleted.
  2. Export. For each program, in CSV and JSON: Evidence, Plans, Review and Progress records with their origin, agent_run_id and illustrative flags; threads with messages, artifacts (every version), tool calls, interrupts and run snapshots; documents (locator and hash only for customer_internal; full text where the licence allows); signatures with their statements and record_hash; the audit trail with the envelope, entry_seq, row_hash and, from R2, the chain columns. Every file carries the provenance footer and the attribution blocks of cited knowledge sources.
  3. Hand over and hash. Deliver the export through the agreed channel; compute and record sha256 of the audit export. This hash is retained after deletion.
  4. Delete. In this order: the documents bucket prefix <org_id>/, document_chunks and documents, agent memory namespaces (R3), notifications, connection secrets and provider references under <org_id>/connections/..., then the remaining program and organisation rows through the owner role (the application role cannot delete audit or signature rows, so this step runs in the migrate Job’s context with the offboarding script, never from the API).
  5. Audit. Write organization.offboard with actor_kind = human, the operator, the export hash and the counts deleted. This row lives in the platform’s own retention, not the tenant’s.

What is retained

ItemRetainedWhy
sha256 of the audit exportyeslets the delivered export be verified later
Record locators and hashes of customer_internal documentsin the export onlythe customer can prove what was referenced without the content leaving twice
Platform-level audit row organization.offboardyesthe offboarding itself is a recorded decision
Any tenant contentnodeleted in step 4

Checks that prove it finished

  • The bucket prefix lists no objects; SELECT count(*) FROM document_chunks WHERE organization_id = ... is 0.
  • No secret under trovensa/<env>/<org_id>/connections/ remains.
  • The organisation is absent from /orgs queries and every host answers 404 for its programs.
  • The organization.offboard audit row exists with the recorded export hash.
  • A dry run against a scratch copy (see backup and restore) was performed before the first real offboarding.

agent_events.text_delta compacted after complete and deleted after 30 days; webhook_deliveries 90 days (rejected 30); launch_ids swept 24 h after expiry; notifications 180 days after read; threads redacted to tombstones after organizations.settings.thread_retention_months (default 24); customer_internal documents archived then purged after programs.settings.document_hold_days (default 30); tool_calls, run_interrupts, run_snapshots, signatures and audit_events kept for the tenant’s life.

Source: PRODUCT-CONTRACT.md sections 10.4 and 10.7, PRODUCT-PLAN.md Part 4 sections 5 (retention), 5.4 and 8 (tenant offboarding), api/app/worker.py (job registry), api/app/integrations/secret_store.py, infra/k8s/base/SECRETS.md

Last updated on