Skip to main content

Model file retention

Archiving a model version only changes its status: its checkpoints, reports and bundles stay in object storage. Model file retention deletes those files whole, either automatically some days after the archive or on request, and records every step. What exactly is deleted and kept is normative in the data deletion policy.

Six operations (API reference) cover it. The writes need an org role of admin or above, or an API key with the admin scope; the reads need read.

OperationRequestWhat it does
getModelFileRetentionGET /model-file-retentionThe project's setting, retention_days: null (off) until set.
putModelFileRetentionPUT /model-file-retentionSets retention_days (1 to 365, or null), optionally guarded by expected_version.
listModelFilesGET /model-files?status=The file lifecycle of every model version with a record, newest change first.
getModelFilesGET /model-files/{model_id}One model version's file lifecycle, holds included.
purgeModelFilesPOST /model-files/{model_id}:purgeRequests the deletion of an archived model version's files.
cancelModelFilePurgePOST /model-files/{model_id}:cancel-purgeWithdraws that request before the deletion starts.

Turn retention on​

A subscription-analytics team keeps archived churn models for 30 days:

PUT /v1/model-file-retention
Content-Type: application/json

{"retention_days": 30, "expected_version": 0}
{
"project_id": "proj_01j9zq4k6w3m8c2r5t7v9x1b3d",
"retention_days": 30,
"version": 1,
"updated_by": "user_01j9zq4m2p6r8t0v2x4z6b8d0f",
"updated_at": "2026-10-14T09:12:00Z"
}

From the next worker cycle on, every archived model version of the project, in both environments, is scheduled with trigger retention and due_at 30 days after its archive. Changing the value moves the due dates of every model whose deletion has not started; null turns retention off and unschedules what retention planned, but not explicit requests. An identical value writes nothing, and a stale expected_version is refused with reason version_mismatch, so two admins never overwrite each other silently.

Delete one model's files now​

A payments team replaced a fraud model and wants the old version's files gone. Archive it first, then request the deletion:

POST /v1/model-files/mdl_01j9zr2b4d6f8h0k2m4p6r8t0v:purge
Content-Type: application/json
Idempotency-Key: <unique-key-per-request>

{"reason": "replaced by the recalibrated version"}

The answer is 202 with the model version's state. A request is due 24 hours after it is made at the earliest, and never inside the 24-hour drain after the archive and the model's last activity, so the state is held by a drain_window hold until due_at:

{
"model_id": "mdl_01j9zr2b4d6f8h0k2m4p6r8t0v",
"status": "held",
"trigger": "explicit",
"archived_at": "2026-10-02T16:40:00Z",
"due_at": "2026-10-15T10:05:00Z",
"not_before": "2026-10-15T10:05:00Z",
"requested_by": "user_01j9zq4m2p6r8t0v2x4z6b8d0f",
"requested_at": "2026-10-14T10:05:00Z",
"holds": [
{"reason": "drain_window", "until": "2026-10-15T10:05:00Z", "since": "2026-10-14T10:05:00Z"}
]
}

(Fields that are still null, such as started_at, are omitted here.) A model version that is not archived is refused with reason model_not_archived, and one whose kind of files retention does not cover yet with family_not_supported. Asking again, or retrying with the same Idempotency-Key, writes nothing.

Cancel a request​

Until the deletion starts, the request can be withdrawn:

POST /v1/model-files/mdl_01j9zr2b4d6f8h0k2m4p6r8t0v:cancel-purge
Content-Type: application/json

{"reason": "the replacement failed its shadow week"}

The row returns to retained, or to the retention plan when retention is on. A cancel never makes a deletion start sooner than the request allowed, even when retention is shortened, or turned off and on again, before the request's 24 hours are over. Once the deletion has started, the cancel is refused with reason purge_already_started: the files are being or have been deleted.

Holds and the drain​

A planned deletion starts only when nothing still uses the model, re-checked by the worker right before it starts:

HoldIt clears when
active_bundleno slot names one of the model's bundles as its active bundle
source_bindingno source is bound to one of its bundles
work_in_flightits training, evaluations, backtests, preparations, replays and labeled jobs are finished
drain_windowthe 24 hours after the archive, the model's last activity, and an explicit request have passed
project_purge_pendingthe project is restored (a completed project purge deletes everything anyway)
legal_holdthe organization's legal hold is released
integrity_check_failedan operator repairs the report or bundle the deletion must preserve

A logistics team whose demand model still serves a shadow slot sees active_bundle with the slot's id until it activates another bundle there.

Follow a deletion​

GET /v1/model-files/{model_id} reads one state, and GET /v1/model-files?status=held lists every held deletion. A deletion moves scheduled (or held) → deleting → awaiting_gcs_hard_delete → deleted:

  • deleting: the deletion has started. From then on the model can never be activated, rolled back to, bundled or evaluated again, and its evaluation report and card are no longer served.
  • awaiting_gcs_hard_delete: no readable file remains (files_deleted_at); the storage provider removes its soft-deleted copies by provider_retained_until. deleted and deleted_by_kind count what was deleted.
  • deleted: no copy of any kind remains.

The console shows the same state in each model's Files section, with Delete files now and Cancel deletion for admins, and the setting under Settings → File retention. Every write and every step is in the audit trail (model_file_retention.update, model_files.purge_request, model_files.purge_cancel, model_files.purge_hold, model_files.purge_start, model_files.files_deleted, model_files.purge_complete).

Dataset builds​

A dataset build's files (its shards, manifest, encoders, audit and derived-label files, its build state, and its baseline evaluations without a model) follow the same lifecycle, with their own retention setting beside the model file one. What exactly is deleted and kept is normative in the data deletion policy. Six more operations (API reference) cover it, with the same roles and scopes:

OperationRequestWhat it does
getDatasetFileRetentionGET /dataset-file-retentionThe project's dataset build setting, retention_days: null (off) until set.
putDatasetFileRetentionPUT /dataset-file-retentionSets retention_days (1 to 365, or null) after a build became idle, optionally guarded by expected_version.
listDatasetFilesGET /dataset-files?status=The file lifecycle of every build with a record, newest change first.
getDatasetFilesGET /dataset-files/{dataset_id}One build's file lifecycle, holds, snapshot pin and waiting erasures included.
purgeDatasetFilesPOST /dataset-files/{dataset_id}:purgeRequests the deletion of a finished build's files, optionally with its archived models'.
cancelDatasetFilePurgePOST /dataset-files/{dataset_id}:cancel-purgeWithdraws that request before the deletion starts.

A build is idle once it has finished, every model version trained on it is archived, and nothing reads it; retention counts its days from then. Set both retentions to the same value and an old model and its build go in the same worker cycle. Settings → File retention has a partner preset that sets both to 6 days.

Delete a build together with its old models​

A gaming studio retrained its churn model on a fresh build after an erasure and archived the old version. To delete the old build and the old model's files in one request:

POST /v1/dataset-files/ds_01j9zs6c8e0g2j4l6n8q0s2u4w:purge
Content-Type: application/json
Idempotency-Key: 2b7e9a10-retire-churn-build-11

{"reason": "rebuilt after the erasure", "include_archived_models": true}

The answer is 202 with the build's state, held by its 24-hour window and by referenced_by_model until the old model's own files start deleting (the same call requested that, with the reason with dataset {dataset_id}):

{
"dataset_id": "ds_01j9zs6c8e0g2j4l6n8q0s2u4w",
"kind": "dataset",
"status": "held",
"trigger": "explicit",
"idle_since": "2026-10-03T08:00:00Z",
"due_at": "2026-10-15T11:20:00Z",
"not_before": "2026-10-15T11:20:00Z",
"holds": [
{"reason": "referenced_by_model", "resource_id": "mdl_01j9zr2b4d6f8h0k2m4p6r8t0v", "since": "2026-10-14T11:20:00Z"},
{"reason": "drain_window", "until": "2026-10-15T11:20:00Z", "since": "2026-10-14T11:20:00Z"}
],
"snapshot": {"snapshot_id": "esn_01j9zs4a6c8e0g2j4l6n8q0s2u", "pin": "pinned"},
"blocking_erasures": 1
}

(Fields that are still null are omitted.) blocking_erasures is the number of entity deletions waiting for this build's snapshot: once the files are deleted and the pin released, they complete. A build still building is refused with dataset_not_terminal; one with a model version that is not archived with dataset_in_use, the models listed in model_ids. Without include_archived_models, the build waits held until its models' file deletions start. cancelDatasetFilePurge withdraws the build's request before it starts (the models' requests are withdrawn on each model), with the same window rule as a model's; after it starts the cancel is refused with purge_already_started.

From deleting on, the build can no longer train or evaluate and the same request cannot build it again (reason dataset_files_purged); its record and frozen manifest stay readable. The console shows each build's Files section on its dataset page. Every write and step is audited (dataset_file_retention.update, dataset_files.purge_request, dataset_files.purge_cancel, dataset_files.purge_hold, dataset_files.purge_start, dataset_files.files_deleted, dataset_files.purge_complete).