Skip to main content

Recycle bin

Deleting a datasource or a data asset in Measured Cloud does not destroy it. The object — and everything Measured Cloud owns underneath it — is moved to the recycle bin: soft-deleted, hidden from every normal list and query, but recoverable. Items sit in the bin for RECYCLE_BIN_RETENTION_DAYS (30 by default), after which a daily cron purges them for good. Until then you can restore an item back to exactly where it was, or purge it early.

This replaces the older hard-delete-blocked-by-a-guard behaviour (#722): a datasource with assets, or an asset included in a validation, used to return 409 Conflict and refuse to delete. Now the delete always succeeds as a reversible move to the bin.

What gets binned, what is kept​

A delete tombstones only the owned subtree of the thing you deleted — the resources that exist solely because that datasource or asset exists — under a single deletion_group_id. Restore clears that group; purge destroys it. The whole group is treated as one unit, so restoring a binned datasource also brings back its assets.

Binned (hidden, purged after the window):

Delete a……and these are binned with it
Datasourcethe datasource, all of its data assets, and each asset's rules
Data assetthe asset and its rules

Kept, never touched by a delete:

  • Validations — a validation that includes a binned asset drops it while it's binned: the asset leaves the validation's Assets list and its asset count, and runs skip its rules. A restore puts it back exactly as it was (its rules are binned with the same deletion_group_id, and the validation's membership rows are never changed). A permanent purge removes the asset's membership rows along with its rules. The validation itself is a shared object and survives.
  • Validation results and execution runs — the historical run record is immutable and is never deleted, even on a permanent purge. A purged asset's past results stay, detached from it.
  • Agent tokens — untouched.

The distinction is ownership: the recycle bin only ever bins the resources that belong exclusively to the thing you deleted. Anything shared stays live.

The retention window​

While an item is in the bin:

  • It is invisible everywhere a live object would appear — datasource / asset lists, search, and validation runs. A database-session filter (deleted_at IS NULL) hides binned rows from every read path automatically, so nothing surfaces a tombstoned object by accident.
  • Its purge_at is deleted_at + RECYCLE_BIN_RETENTION_DAYS. The recycle-bin list shows both timestamps so you can see how long you have.
  • A daily worker cron (03:45 UTC) hard-deletes every item whose window has elapsed. Purge reuses the same cascade a manual purge does — it destroys the owned subtree and leaves shared objects (validations, results, agent tokens) intact.

Lower RECYCLE_BIN_RETENTION_DAYS for a shorter safety net or raise it to keep deleted objects recoverable longer — see reference/configuration.md.

Operations you can do​

The bin is exposed at /api/v2/organizations/{org_id}[/workspaces/{ws_id}]/recycle-bin. Every route is workspace-isolated — you only ever see and act on items in workspaces you can reach.

  • List the bin — GET .../recycle-bin returns the top-level restorable entries: every binned datasource, plus assets that were binned on their own (their parent datasource is still live). An asset binned as part of a datasource delete is covered by the datasource's entry, not listed separately. Each entry carries resource_type, id, name, deleted_at, purge_at, and deletion_group_id.
  • Preview a delete's blast radius — GET .../recycle-bin/preview/datasource/{id} (or .../preview/data-asset/{id}) counts what a delete would bin (assets and their rules, profile runs, anomaly events, AI suggestions) and how many validations it would leave in place (rule_groups_kept), plus the retention_days. The full count keys are listed in the API reference. Use it to warn a user before they delete a large subtree.
  • Restore — POST .../recycle-bin/datasources/{id}/restore (or .../data-assets/{id}/restore) clears the tombstone for the whole deletion_group_id, so the object and its owned subtree reappear where they were. Restoring an asset whose parent datasource is also in the bin returns 409 and tells you to restore the datasource first. If the asset and datasource were binned in the same delete they share a group, so restoring the datasource brings the asset back with it; if the asset was binned independently and its datasource binned later (separate groups), restoring the datasource clears only its own group and you restore the asset afterward.
  • Purge (permanent delete) — DELETE .../recycle-bin/datasources/{id} (or .../data-assets/{id}) hard-deletes a binned item's owned subtree immediately, without waiting for the retention window. Shared objects and validation results are still preserved. This is irreversible.

Who can do what​

The recycle bin follows the same authority gradient as the catalog it protects. Deleting a datasource is an editor-tier action, deleting an asset needs a workspace admin, and permanently destroying anything needs a workspace admin or super admin.

ActionMinimum role
Delete a datasource (move to bin)editor
Delete a data asset (move to bin)workspace admin
List the bin / preview / restoreeditor
Permanent purge (DELETE .../recycle-bin/...)workspace admin

Restore and purge are audit-logged (a restore / purge audit event naming the object and, for a restore, the per-table restored-row counts). See Restore or permanently delete from the recycle bin for the task walkthrough and the API reference for the endpoint contracts.