How does Crab reclaim unreferenced data safely?
Crab deletes an object only after proving that no retained root reaches it and that its protection window has elapsed.
Deleting a branch does not mean its 400 GB experiment disappears from object storage.
The branch name may be gone while recovery history still reaches its commits, pointers, recipes, and shared xorbs. Crab deletes an object only when two keys turn:
- No retained root reaches it.
- It is older than the grace window.
OBJECT EVIDENCE LAB / SELECT A SPECIMEN
STORAGE OBJECT
xorb 19e2…
models/current/model.safetensors
ROOT TRACE
TWO-KEY DELETION PERMIT
Unreachable from every retained root
BLOCKEDOlder than the 24-hour grace window
CLEARCLASSIFICATION
RETAIN
Age cannot override a live path from main.
EVIDENCE STRUCTURES
Start with one object
Consider xorb d77c…, a 4.2 GB immutable object.
Crab first builds a root set from current refs, the ref journal, workflow artifacts, and recovery history. It walks each pointer through its file recipe and marks every required xorb.
Then it compares the complete storage listing with that mark set:
listed objects − marked objects = unreachable objectsUnreachable does not yet mean deletable. Crab applies object age, storage-class rules, and current coordination evidence before creating a candidate batch.
Recovery history is still a root
Crab retains recovery-history roots without a time or count limit by default.
That is why deleting experiment/branch-17 may reclaim nothing.
These are separate decisions:
| Action | What it removes |
|---|---|
| Delete a branch | An active ref name |
| Prune recovery history | Supported restore points |
| Run GC | Unreachable physical objects |
If the recovery policy needs only the latest 20 generations, preview that change first:
crab recover history prune --keep-last 20Apply it explicitly, then recalculate garbage:
crab recover history prune --keep-last 20 --apply
crab gc --scope repo --dry-runPruning history does not delete xorbs. It removes roots; GC separately proves which objects became unreachable.
Shared data has no single owner
Suppose two repositories reuse chunks stored in xorb f093…. Repo vision
can stop referencing it while repo labs still needs it.
Repository GC stays inside its supported repository boundary. Bucket GC must take the union of every registered repository’s marks. Missing one repository creates a destructive blind spot, so incomplete registration blocks the run.
Use repository scope for routine maintenance. Treat bucket scope as a separate, coordinated operation.
The default grace window is 24 hours
New uploads can exist before their ref transaction publishes. During that gap, a storage listing sees the object but the root snapshot cannot reach it yet.
Crab’s configured default grace period is 24 hours. Non-force runs clamp a shorter value to at least one hour.
crab gc --scope repo --grace-period 24h --dry-runChoose a window longer than the slowest expected push or offline workflow.
CONCURRENCY REPLAY / MOVE THE WRITER
What happens around the snapshot?
A fresh upload looks orphaned only briefly
Grace protects the upload now; the published ref marks it live on the next run.
T0
GC snapshots roots
xorb not present
+2m
Writer uploads xorb
not published yet
+8m
GC sees object
inside 24h grace
+11m
Writer publishes ref
reachable next run
STATE: root set · object age · writer epoch
Two mechanisms protect concurrent work:
- Grace: a recent, unmarked upload stays protected.
- Fencing: writers hold shared admission through publication; destructive GC takes short exclusive sweep fences around reconciliation and delete batches.
If a writer enters between batches, the writer epoch changes. GC stops before another batch instead of trusting an outdated snapshot.
--force bypasses the age key only. It does not bypass reachability, registry,
closure, or coordinator proof.
Preview the exact repository first
Start with integrity verification and structured dry-run output:
crab fsck
crab gc --scope repo --dry-run --jsonA summary includes candidate counts and safety state:
{
"packs_deleted": 3,
"xorbs_deleted": 12,
"shards_deleted": 4,
"bytes_reclaimed": 21743271936,
"dry_run": true,
"partial_enumeration": false,
"delete_failures": 0,
"reconciliation_failed": false
}In dry-run mode, “deleted” fields mean would delete. Save the repository identity, scope, grace period, counts, and bytes with the review.
Do not approve a preview with partial enumeration or unreadable roots. Missing evidence protects objects; it never shrinks the live set by assumption.
Apply the same policy
After review, run the same scope without --dry-run:
crab gc --scope repo
crab fsckDELETION PERMIT / TRY AN OPERATION
Does this run have enough proof?
OPERATOR DECISION
Review the proof without deleting
crab gc --scope repo --dry-run --jsonRepository scope
normal boundary
Root walk complete
no unknown proof
Dry run
zero deletes
Candidate inventory
save for review
Record candidate counts, bytes, policy, and the exact repository identity.
Keep preview and apply close together. A long delay may change repository activity even though the apply run takes a fresh safe snapshot.
Use force only for a documented exception:
crab gc --scope repo --forceThe command asks for confirmation unless --yes is provided. Recent
unreachable uploads lose age protection, so current coordination evidence is
essential.
Read partial failure as progress, not success
An object store can accept some deletes and reject others. Crab reports
successful and failed counts and exits nonzero with CRAB-E0322 when repository
deletion or reconciliation is incomplete.
Fix the provider or permission failure, preserve the output, and rerun GC. Successful deletes are idempotent; already removed candidates do not need to be restored.
Provider versioning, replication, or lifecycle retention can also delay the billing change after Crab’s logical delete.
Why a dry run may reclaim little
A small candidate set is often correct:
- Current branches share most xorbs with deleted branches.
- Recovery history still retains the old commits.
- Interrupted uploads remain inside the grace window.
- Storage-class minimum-retention policy protects early deletion.
Do not shorten the grace window to make the report look productive. Change the recovery policy explicitly or wait for the next safe collection window.
Operator checklist
Before apply, confirm:
- Repository identity and scope are exact.
- Current refs, journals, workflows, and recovery roots are readable.
- The reviewed dry run has complete enumeration.
- The grace window covers the longest expected publication delay.
- Maintenance coordination can seal the sweep.
crab fsckis planned after deletion.
If any answer is uncertain, stop. Extra storage is cheaper than deleting the only durable bytes behind a retained pointer.
For exact flags and structured output, see the crab gc reference. Next, build a cost model before changing storage classes.
KNOWLEDGE PROOF
Check the decision, not your memory.
A branch was deleted. When may Crab delete an object that branch used?