R2 Lifecycle Rules: `brioso-jobs` Bucket
R2 Lifecycle Rules: brioso-jobs Bucket
Never add a lifecycle rule touching the
litestream/prefix. That
prefix holds Litestream’s DB WAL replication stream. A lifecycle rule that
expires or deletes objects underlitestream/will corrupt backups. This
is not a hypothetical — treat it as a hard boundary when editing rules in
the Cloudflare dashboard.
Why this doc exists
The brioso-jobs bucket is on Cloudflare R2’s 10GB free tier and was
observed at ~16GB. Rather than deleting paid/delivered content, we expire
only artifacts that are either rebuildable, orphaned, or explicitly
time-boxed. Paid or delivered content is never deleted by this system.
Dashboard lifecycle rules
These two rules are hand-configured via the Cloudflare dashboard
(Bucket → Settings → Object lifecycle rules). There is no
Terraform/IaC coverage for this bucket, so if it is ever recreated, these
rules must be re-applied by hand from this doc.
Rule 1 — kits/ prefix, expire after 7 days
Kit ZIPs are rebuildable from their source tracks on demand, so they don’t
need to survive indefinitely. Objects under the kits/ prefix expire 7 days
after upload.
Rule 2 — logos/ prefix, expire after 30 days
Logo uploads that are never attached to a finished kit are orphaned data
with no other reference pointing at them. Objects under the logos/ prefix
expire 30 days after upload.
What is NOT a dashboard rule
Two more retention categories exist but are not representable as
Cloudflare dashboard lifecycle rules, because the dashboard feature has no
awareness of database state (job status, payment status):
failed-job— artifacts belonging to failed or cancelled jobs are
swept after 14 days, excluding artifacts that are children of paid kits
and any job with a paid or free-unlocked track (BRI-374: cancelJob is
legal from any state, so a cancelled job can still hold delivered
content — payment status outranks the sweep). After a whole-prefix sweep
the groomer stamps the job row’sartifacts_purged_attombstone, and the
studio renders those generations as “no longer available” (terminal
state, no player) instead of serving broken playback.watermarked-master— a track’s watermarked master is swept
immediately once the track is marked paid (no grace period). Free-tier
free_unlockedtracks are never touched by this category, since their
watermarked file is their only copy.
Both categories require checking job/track state in the database before
deleting, which the dashboard’s prefix+age model can’t express. They are
handled by a code-side groomer instead:
packages/dispatch/src/storageGroomer.ts.
Keeping this doc in sync
The thresholds above must match packages/storage/src/retention.ts’s
RETENTION_RULES array (the mode: "age" entries) by hand — there is no
automated sync between the dashboard config, this doc, and that file. If you
change a threshold in one place, update the other two in the same change.