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.
| Operation | Request | What it does |
|---|---|---|
getModelFileRetention | GET /model-file-retention | The project's setting, retention_days: null (off) until set. |
putModelFileRetention | PUT /model-file-retention | Sets retention_days (1 to 365, or null), optionally guarded by expected_version. |
listModelFiles | GET /model-files?status= | The file lifecycle of every model version with a record, newest change first. |
getModelFiles | GET /model-files/{model_id} | One model version's file lifecycle, holds included. |
purgeModelFiles | POST /model-files/{model_id}:purge | Requests the deletion of an archived model version's files. |
cancelModelFilePurge | POST /model-files/{model_id}:cancel-purge | Withdraws 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:
| Hold | It clears when |
|---|---|
active_bundle | no slot names one of the model's bundles as its active bundle |
source_binding | no source is bound to one of its bundles |
work_in_flight | its training, evaluations, backtests, preparations, replays and labeled jobs are finished |
drain_window | the 24 hours after the archive, the model's last activity, and an explicit request have passed |
project_purge_pending | the project is restored (a completed project purge deletes everything anyway) |
legal_hold | the organization's legal hold is released |
integrity_check_failed | an 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 byprovider_retained_until.deletedanddeleted_by_kindcount 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:
| Operation | Request | What it does |
|---|---|---|
getDatasetFileRetention | GET /dataset-file-retention | The project's dataset build setting, retention_days: null (off) until set. |
putDatasetFileRetention | PUT /dataset-file-retention | Sets retention_days (1 to 365, or null) after a build became idle, optionally guarded by expected_version. |
listDatasetFiles | GET /dataset-files?status= | The file lifecycle of every build with a record, newest change first. |
getDatasetFiles | GET /dataset-files/{dataset_id} | One build's file lifecycle, holds, snapshot pin and waiting erasures included. |
purgeDatasetFiles | POST /dataset-files/{dataset_id}:purge | Requests the deletion of a finished build's files, optionally with its archived models'. |
cancelDatasetFilePurge | POST /dataset-files/{dataset_id}:cancel-purge | Withdraws 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).