buzz-db: keep the community transition table in one match

The archive flag now comes from the transition match with every other
per-transition value, and the lifecycle UPDATE drops its redundant
deleted_at predicate: the row is locked FOR UPDATE, a tombstoned row is
rejected before the UPDATE, and its state never matches the snapshot.

Co-authored-by: Elrond <28d6302a099e5225b02c4155ac4236e4912603df2ab08dbfc2f4fef08ce598c8@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Luke Tornquist <tornquist@squareup.com>
This commit is contained in:
Luke Tornquist
2026-11-10 08:28:59 -08:00
parent 49adf6dc9d
commit d5592b6fd9

View File

@@ -3425,22 +3425,25 @@ async fn transition_community(
"community {community} is permanently tombstoned"
)));
}
let (new_state, generation, restore_archive, tombstone) = match transition {
// `archive` pins the community archived for every forward step; abort
// restores the pre-deletion `archived_at` instead.
let (new_state, generation, archive, restore_archive, tombstone) = match transition {
CommunityTransition::Quiesce if matches!(old.state.as_str(), "active" | "quiescing") => {
("quiescing", old.generation, None, false)
("quiescing", old.generation, true, None, false)
}
CommunityTransition::Fence if old.state == "quiescing" => (
"fenced",
old.generation.checked_add(1).ok_or_else(|| {
DbError::DeletionSafety("community deletion fence generation overflow".to_string())
})?,
true,
None,
false,
),
CommunityTransition::Tombstone { generation }
if old.state == "fenced" && old.generation == generation =>
{
("tombstone", generation, None, true)
("tombstone", generation, true, None, true)
}
CommunityTransition::Abort {
restored_archived_at,
@@ -3449,6 +3452,7 @@ async fn transition_community(
old.generation.checked_add(1).ok_or_else(|| {
DbError::DeletionSafety("community deletion fence generation overflow".to_string())
})?,
false,
restored_archived_at,
false,
),
@@ -3466,13 +3470,12 @@ async fn transition_community(
deleted_at = CASE WHEN $6 THEN now() ELSE deleted_at END, \
signing_key = CASE WHEN $6 THEN NULL ELSE signing_key END, \
icon = CASE WHEN $6 THEN NULL ELSE icon END \
WHERE id = $1 AND deletion_state = $7 AND deletion_fence_generation = $8 \
AND deleted_at IS NULL",
WHERE id = $1 AND deletion_state = $7 AND deletion_fence_generation = $8",
)
.bind(community.as_uuid())
.bind(new_state)
.bind(generation)
.bind(!matches!(transition, CommunityTransition::Abort { .. }))
.bind(archive)
.bind(restore_archive)
.bind(tombstone)
.bind(&old.state)