feat(deletion): add durable whole-community deletion - #4425
Open
kalvinnchau wants to merge 27 commits into
Open
Conversation
kalvinnchau
force-pushed
the
am/community-deletion-safety-79536ff
branch
from
August 3, 2026 03:15
88cfa22 to
43a5f21
Compare
kalvinnchau
marked this pull request as draft
August 3, 2026 17:14
kalvinnchau
force-pushed
the
am/community-deletion-safety-79536ff
branch
2 times, most recently
from
August 3, 2026 22:48
bda58dc to
c8c7301
Compare
kalvinnchau
marked this pull request as ready for review
August 3, 2026 23:35
kalvinnchau
force-pushed
the
am/community-deletion-safety-79536ff
branch
from
August 4, 2026 19:51
b8e03aa to
29e44b5
Compare
Co-authored-by: npub122y0pqkertljmedu303rl0aqrj3w8pvu43t6jxm6875lzg6f2pwqegc3xc <5288f082d91aff2de5bc8be23fbfa01ca2e3859cac57a91b7a3fa9f12349505c@buzz.block.builderlab.xyz> Signed-off-by: npub122y0pqkertljmedu303rl0aqrj3w8pvu43t6jxm6875lzg6f2pwqegc3xc <5288f082d91aff2de5bc8be23fbfa01ca2e3859cac57a91b7a3fa9f12349505c@buzz.block.builderlab.xyz>
Co-authored-by: npub122y0pqkertljmedu303rl0aqrj3w8pvu43t6jxm6875lzg6f2pwqegc3xc <5288f082d91aff2de5bc8be23fbfa01ca2e3859cac57a91b7a3fa9f12349505c@buzz.block.builderlab.xyz> Signed-off-by: npub122y0pqkertljmedu303rl0aqrj3w8pvu43t6jxm6875lzg6f2pwqegc3xc <5288f082d91aff2de5bc8be23fbfa01ca2e3859cac57a91b7a3fa9f12349505c@buzz.block.builderlab.xyz>
Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
Co-authored-by: npub122y0pqkertljmedu303rl0aqrj3w8pvu43t6jxm6875lzg6f2pwqegc3xc <5288f082d91aff2de5bc8be23fbfa01ca2e3859cac57a91b7a3fa9f12349505c@buzz.block.builderlab.xyz> Signed-off-by: npub122y0pqkertljmedu303rl0aqrj3w8pvu43t6jxm6875lzg6f2pwqegc3xc <5288f082d91aff2de5bc8be23fbfa01ca2e3859cac57a91b7a3fa9f12349505c@buzz.block.builderlab.xyz>
the checkpoint removed the pre-lease fence assert from ingest_event_inner without a replacement, leaving the shared ws/http persistent-event seam unfenced during community deletion. restore it as a fail-closed is_serving_active pre-check: inactive communities reject with the same restricted: wire text as the ephemeral path, and a fence-lookup outage maps to internal/500 instead of admitting the write or blaming the client. regressions: unit tests pin the three mapping arms, and an ignored postgres test drives the real deletion lifecycle (submit, freeze inventory, approve, claim, fence) and proves the exact predicate ingest consults flips from admit to refuse. Signed-off-by: Kalvin Chau <kalvin@block.xyz> Co-authored-by: npub122y0pqkertljmedu303rl0aqrj3w8pvu43t6jxm6875lzg6f2pwqegc3xc <5288f082d91aff2de5bc8be23fbfa01ca2e3859cac57a91b7a3fa9f12349505c@buzz.block.builderlab.xyz> Signed-off-by: npub122y0pqkertljmedu303rl0aqrj3w8pvu43t6jxm6875lzg6f2pwqegc3xc <5288f082d91aff2de5bc8be23fbfa01ca2e3859cac57a91b7a3fa9f12349505c@buzz.block.builderlab.xyz>
Order fencing behind admitted serving-write leases, keep external write heartbeats live through durable finalization, and make Git publication hold the community lock through the relay event commit. Harden tenant trigger coverage for cross-community updates and future tables, then fail startup and readiness closed on live catalog drift. Co-authored-by: npub122y0pqkertljmedu303rl0aqrj3w8pvu43t6jxm6875lzg6f2pwqegc3xc <5288f082d91aff2de5bc8be23fbfa01ca2e3859cac57a91b7a3fa9f12349505c@buzz.block.builderlab.xyz> Signed-off-by: npub122y0pqkertljmedu303rl0aqrj3w8pvu43t6jxm6875lzg6f2pwqegc3xc <5288f082d91aff2de5bc8be23fbfa01ca2e3859cac57a91b7a3fa9f12349505c@buzz.block.builderlab.xyz>
Give unarchive membership signals unique event ids, derive live-test authorities and media URLs from the configured relay, use metadata-free PNG bytes, respect community-scoped Git pointer keys, and let the subscription-cap proof coexist with the independent admission quota. Co-authored-by: npub122y0pqkertljmedu303rl0aqrj3w8pvu43t6jxm6875lzg6f2pwqegc3xc <5288f082d91aff2de5bc8be23fbfa01ca2e3859cac57a91b7a3fa9f12349505c@buzz.block.builderlab.xyz> Signed-off-by: npub122y0pqkertljmedu303rl0aqrj3w8pvu43t6jxm6875lzg6f2pwqegc3xc <5288f082d91aff2de5bc8be23fbfa01ca2e3859cac57a91b7a3fa9f12349505c@buzz.block.builderlab.xyz>
Signed-off-by: npub122y0pqkertljmedu303rl0aqrj3w8pvu43t6jxm6875lzg6f2pwqegc3xc <5288f082d91aff2de5bc8be23fbfa01ca2e3859cac57a91b7a3fa9f12349505c@buzz.block.builderlab.xyz> Co-authored-by: Kalvin Chau <kalvin@block.xyz> Signed-off-by: Kalvin Chau <kalvin@block.xyz>
Signed-off-by: npub122y0pqkertljmedu303rl0aqrj3w8pvu43t6jxm6875lzg6f2pwqegc3xc <5288f082d91aff2de5bc8be23fbfa01ca2e3859cac57a91b7a3fa9f12349505c@buzz.block.builderlab.xyz> Co-authored-by: Kalvin Chau <kalvin@block.xyz> Signed-off-by: Kalvin Chau <kalvin@block.xyz>
Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
replace the full-bucket inline inventory with prefix-scoped enumeration and a chunked side-table manifest: - inventory lists only the three tenant prefixes (_meta/, _uploads/, repos/); unknown-key detection moves to a decoupled fleet-wide taxonomy sweep (new deletions sweep command) gated on freshness at submit/approve - destructive freeze stores per-prefix count/bytes/sha256-digest summaries on the request row and streams full key lists into community_deletion_manifest_keys (~10k keys/row); freeze validates chunks against the frozen digests in the same tx - drained stage deletes via batched s3 DeleteObjects with per-chunk checkpoints; NoSuchKey/NoSuchVersion map to already-missing for idempotent resume; versioning artifacts fail permanent - per-key HEAD verification replaced by a bucket-level versioning probe and a final empty-prefix listing check - fenced stage reordered: serving-write drain is verified before the destructive freeze, closing the late-write window - chunk rows are trigger-guarded (immutable except the deleted_at stamp; delete only pre-freeze or terminal) and purged at logically_verified; schema folded into unmerged 0027 - record_taxonomy_sweep clamps completed_at server-side so sweeper clock skew cannot violate the completed_at >= started_at check env knobs: BUZZ_DELETION_STORAGE_MAX_OBJECTS (per community), BUZZ_DELETION_SWEEP_MAX_OBJECTS, BUZZ_DELETION_SWEEP_MAX_AGE_SECS, BUZZ_DELETION_MANIFEST_CHUNK_KEYS Signed-off-by: Kalvin Chau <kalvin@block.xyz>
added 5 commits
August 4, 2026 12:51
Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
kalvinnchau
force-pushed
the
am/community-deletion-safety-79536ff
branch
from
August 4, 2026 19:59
29e44b5 to
4ce597e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a durable, operator-controlled V1 for deleting an entire Buzz community without deleting another tenant's data.
The workflow is exposed through
buzz-admin deletions:sweeprecords independent fleet storage-taxonomy observationssubmit,list,inspect, andapprovemanage a deletion requestrunanddrainexecute bounded workRequests advance through a PostgreSQL-backed state machine and stop at
retention_pendingafter logical deletion has been independently verified across PostgreSQL, object storage, and Redis.This PR ships the engine and CLI, not a continuously running worker or Kubernetes packaging. For V1, a cluster/VM administrator invokes
/usr/local/bin/buzz-adminfrom the existing relay image, for example withkubectl execor an equivalent container/VM exec path.What whole-community V1 removes
For the target community, V1 removes:
_meta/<community>/and_uploads/<community>/repos/<community>/buzz:<community>:*The community row survives as a permanent tombstone, and deletion control-plane records remain as evidence of the request, approval, execution, and result.
Safety model
Deletion is not a broad
DELETE CASCADEfollowed by optimistic cleanup. The destructive boundaries are durable and fail closed.1. Inventory and approval
submitresolves the target and freezes the schema plus summary-only storage inventory._meta/<community>/_uploads/<community>/repos/<community>/2. Quiesce, fence, and destructive freeze
quiescingand then establishes the durable fence.3. Checkpointed destruction
community_id, including the guarded NIP-RS hard-delete path discovered with real Desktop kind30078read-state data.UNLINKs onlybuzz:<community_id>:*. Natural expiry is insufficient because some keys, including tunnel generation counters used as fencing state, are deliberately persistent.4. Independent verification
logically_verifiedtoretention_pending.What V1 deliberately does not erase
Shared content-addressed storage
Per-community deletion removes bindings, metadata, attribution records, and Git pointers. It does not physically delete fleet-shared CAS bytes that another community may still reference:
manifests/,packs/, andidx/)Safe reclamation requires a separate fleet-wide reachability and retention GC. Unknown keys elsewhere in the shared bucket do not block one community's deletion; malformed or unrecognized keys inside that community's three owned prefixes still fail closed.
External retained copies
The online logical-deletion proof does not erase object versions/replicas, database backups/WAL, CDN copies, provider retention copies, or observability exports. Those require their own retention and purge controls.
Member-only erasure
This PR erases a whole community. It does not implement the different operation "erase one npub while preserving the community."
Removing membership or accepting NIP-09 is not member erasure. A member-only workflow would need to find and selectively remove or redact authored event content and pubkeys, profile data, DMs, reactions, mentions, memberships/roles, tokens, workflows/subscriptions, upload attribution, moderation/audit history, repository attribution, and identity embedded in tags or JSON. It would also need explicit rules for ownership transfer, surviving replies and thread metadata, audit-chain integrity, immutable Git history, and shared-CAS reachability. That requires a pubkey-level fence and selective graph rewrite; it is a separate deletion product, not a safe extension of this whole-tenant worker.
In scope
0027_community_deletion.sql: requests, approvals, leases, manifest chunks, checkpoints, tombstones, and the universal write-fence catalogsweep,submit,list,inspect,approve,run, anddraincommandsschema/schema.sqlsupport without requiring a SQLx migration ledgerDeferred / not covered
buzz-admin deletions workerpoll loop and worker-only health serverThe removed continuous-worker implementation is preserved on
am/community-deletion-worker-followupfor separate review.Validation
Current PR head
Current head:
c8c73018e03751de7da5f156eb1c6d61b0654626, rebased onto985cdcc6eac33ccd77bc50c26e22c701d07eda4e.At this head:
cargo fmt --all -- --checkpassedbuzz-db,buzz-media,buzz-deletion, andbuzz-relay; the known relay telemetry test failed once in a combined run, then the complete relay rerun passed with 844 library and 11 binary testsExact-head-before-final-prefix-change destructive matrix
The full destructive rerun used source
bda58dc06a4f638077c60009eded5f796421a832and immutable imagebuzz-e2e:sha-bda58dc06a4f(sha256:79a146bf341614854b0ca3c557ff679bcd1327f0f30e730ae2a82d733abc1575). That run covered:30078NIP-RS statefenced, durable retry metadata, and successful resume10,000 + 1, deleting all target bindings, and cleaning the side tablesweep → submit → approve → runEvidence:
/tmp/buzz-e2e/20260803T204244Z-bda58dc06a4f/(CASE_LEDGER.md, 179-entrySHA256SUMS, and raw artifacts). Compose resources and the Kubernetes namespace were removed afterward.The final commit changed only deletion inventory/gating semantics: it replaced fleet-wide deletion-path listing with the three target-prefix listings, removed the deletion-path cap and sweep dependency, retained fail-closed validation under owned prefixes, and added writer-coverage tests. The full destructive Compose/Kubernetes matrix has not been rerun at
c8c73018e; this description does not relabel the older image evidence as exact-head evidence.One boundary remains explicitly untested: deterministic post-S3/pre-checkpoint crash injection. The product exposes no deterministic fault point there, and a timing kill would manufacture confidence rather than evidence.
Rollout constraint
Do not approve a deletion during a mixed-version relay rollout. Apply migration 0027, roll every serving replica to this release or newer, verify old replicas are gone and deletion serving-lease metrics are healthy, then invoke deletion execution. Older replicas do not participate in the external-effect lease protocol required to make fencing safe.