Retention and purge
Delete revokes access; purge removes retained representations and returns a signed receipt. Guarantee classes, purge generations, and how resurrection is prevented.
Vague retention promises are easy to make and impossible to verify. Zumik splits deletion into two operations with sharply different meanings, returns signed evidence for the stronger one, and never claims a guarantee its underlying infrastructure cannot actually deliver.
Delete is not purge
| Operation | Meaning |
|---|---|
DELETE /v2/artifacts/{id} | Revoke the customer's access to a handle immediately |
POST /v2/purge-jobs | Remove retained representations and generate evidence |
GET /v2/purge-jobs/{id}/receipt | Retrieve the signed purge receipt |
A delete is instant and cheap: the handle stops working. A purge is a workflow that reaches into every place a representation might persist and produces a receipt you can audit.
What a purge job does
Revoke and tombstone
Public handles stop working immediately; artifacts and bundles are marked tombstoned; dependent sessions and snapshots are invalidated.
Bump the namespace generation
The isolation-namespace purge generation increments. This is the resurrection-prevention step (see below).
Remove canonical state
Object-store blobs and materializations are removed; retained traces are removed according to their trace mode; runtime cache namespaces are invalidated.
Request provider-side deletion
Where the provider supports it (read from its capability manifest), provider-side deletion is requested and acknowledgments recorded.
Issue a signed receipt
A signed receipt records each processor's status, the overall guarantee class, and any remaining backup or provider-expiry window.
The receipt
{
"id": "pur_01jy...",
"object": "purge_receipt",
"requested_at": "2026-06-09T20:00:00Z",
"completed_at": "2026-06-09T20:04:10Z",
"scope": { "project_id": "prj_...", "artifact_ids": ["art_..."] },
"guarantee": "verified_namespace_invalidation",
"processors": [
{ "name": "state_store", "status": "purged" },
{ "name": "object_store", "status": "purged" },
{ "name": "byoc_runtime", "status": "namespace_invalidated" },
{ "name": "backup_store", "status": "expires_by",
"expires_at": "2026-07-09T20:04:10Z" }
],
"receipt_digest": "sig_..."
}Guarantee classes
The guarantee field states exactly how strong the deletion is, from weakest to strongest:
| Class | Meaning |
|---|---|
access_revoked | Customer handles stop working immediately |
best_effort_expiry | A provider-controlled cache expires under provider policy |
verified_namespace_invalidation | Stale physical cache can no longer be reused |
verified_physical_purge | Managed storage and cache processors confirmed deletion |
cryptographic_purge | Key destruction makes encrypted retained bytes unreadable |
The receipt's overall guarantee is the weakest across all processors. One expiry-bound backend caps the whole receipt at best_effort_expiry, even if every other processor confirmed a physical purge. The platform never reports the strongest path and hides a weaker one.
This is why guarantees are honest. A provider whose manifest says manual_cache_clear_supported: false cannot be physically purged on demand, so a purge touching it yields at most best_effort_expiry with the expiry window stated - not a false claim of immediate deletion.
Resurrection prevention
The hardest part of deletion is making sure deleted content cannot quietly come back. After a purge:
- old public IDs stay invalid forever;
- the namespace generation has incremented, so every stale KV entry now fails the KV-compatibility check and cannot be served;
- re-uploading identical content creates a brand-new opaque handle - it does not restore the old one;
- internal fingerprint matches do not automatically rebuild deleted relationships.
The namespace generation lives inside the KV-compatibility key. Bumping it by one is enough to orphan every prior physical cache entry in that namespace at once, which is why purge can guarantee that stale state will not be reused even before every byte is physically gone.
Capability manifests
Versioned, per-provider records of exactly what each provider and profile supports - the source of truth that routing decisions and purge claims both read.
OpenAI migration guide
Point an existing OpenAI client at Zumik with no body changes - the full /v1 compatibility surface, the base-url swap, what carries over unchanged, the optional Agent-* headers, and a testing checklist.