Support permanent deletion of a cell and its replicated state
- Dominant language
- Rust
- Stars
- 4.6k
- Forks
- 171
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
Please add a supported way to delete one cell so its pre-delete state can never be restored and celld-managed bucket objects containing that state are eventually reclaimed.
This is about one cell / Durable Object instance. Class deletion (`deleted_classes`) is a related compatibility gap, but it can be handled separately.
## Use case
We run one cell per agent session. A user-facing session deletion must remove the product record immediately and must eventually remove the durable session history. Application-level encryption plus key destruction can make retained bytes unreadable, but it does not reclaim storage and should not be the only lifecycle mechanism.
`storage.deleteAll()` gives the application an empty current database, but celld retains the cell identity and its replicated history. A future restore reads the full LTX lineage from transaction zero and replays the deletion; pre-delete bytes remain in the fleet bucket.
## Current v0.4.0 behavior
- [`celld cell list` is the only cell command](https://github.com/denoland/celld/blob/v0.4.0/crates/celld/cell_cli.rs#L182-L188). There is no cell delete/purge command or operator route.
- No code path purges all objects under `cells//` (`own.json` or `ltx/...`). Eviction removes local SQLite files but retains bucket state.
- Ownership release [rewrites `own.json` as unowned with a conditional CAS](https://github.com/denoland/celld/blob/v0.4.0/crates/celld/ownership_store.rs#L386-L399); it does not record that the scope was deleted.
- Recent rows can exist in shared multi-cell bundles at `log//bundle/...`. Recovery folds rows from those bundles back into per-cell LTX prefixes, so deleting only `cells//` can be undone by later recovery.
- Alarms and placement have separate references under `wake/...` and `node-cells/...`; out-of-line KV values use `kv/blobs-v2//...`.
- `deleted_classes` is explicitly rejected with: “Class rename, delete, transfer, and non-SQLite migration semantics need an explicit persisted-state contract before deployment” ([deploy validation](https://github.com/denoland/celld/blob/v0.4.0/crates/celld/deploy.rs#L1683-L1694)).
The only related existing issue I found is [#168](https://github.com/denoland/celld/issues/168), which fixed `storage.deleteAll()` dropping Litestream control tables. It does not provide history deletion or storage reclamation.
## Required observable contract
After deletion completes:
- activating the same scope cannot restore pre-delete data;
- stale owners, followers, dead-node recovery, and bundle drains cannot reintroduce pre-delete rows;
- alarm and placement references for the cell are gone;
- celld-managed current bucket objects that contain the cell's data are eventually deleted or compacted away, subject to the object store's own versioning/backup policy;
- `celld cell list` no longer returns the cell until a new activation creates empty state;
- repeated delete requests are safe and report whether deletion is pending or complete.
The operation may be asynchronous because a shared bundle can contain rows from several cells. It can remain pending until those rows are covered per-cell and the bundle reaches normal GC.
## Possible shape (not a requirement)
An operator command or HMAC-authenticated route, for example:
```text
celld cell delete
stop admission and evict the cell
publish a durable deletion tombstone at a newer epoch
drain or cover retained bundle rows
purge the cell LTX prefix, wake entries, placement markers, and KV blobs
make every recovery path skip the tombstoned scope
retain the tombstone until every prior node session is fenced
report deletion complete once the last celld-managed copy is reclaimed
```
The existing code already has useful pieces: conditional ownership updates, drain barriers that wait for bundle coverage, bundle GC, wake-entry deletion, and dead-node cleanup. The missing part appears to be the persisted cell-deletion contract that composes them safely.
## Compatibility precedent
Cloudflare's class lifecycle has an explicit permanent-delete tombstone: deleting a class “removes its namespace and all of its stored data permanently — this is not a soft delete.” This is class-level rather than an exact per-instance API match, but it establishes permanent deletion as part of the Durable Object lifecycle contract:
https://developers.cloudflare.com/durable-objects/reference/durable-objects-migrations/#delete-a-durable-object-class
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with crates/celld/cell_cli.rs, ownership_store.rs, deploy.rs, and the existing drain-barrier, bundle-GC, wake-entry, and dead-node cleanup paths described in the issue. Trace how cell identity, bundles, recovery, ownership, alarms, placement, and KV blobs are persisted, then verify the observable contract: repeated deletion is safe, recovery cannot restore prior rows, references are removed, and cell list omits the cell until fresh activation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust, sqlite
- Domain
- databases, distributed-systems
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100