Replace the direct-SQL repair, which needed every relay pod stopped, with
renames that go through the relay's normal kind:9002 path:
- A relay operator may send a name-only kind:9002 for any channel. Every
other privileged change still needs a channel owner or admin. A
moderator gets no new right.
- scripts/maintenance/plan_duplicate_listed_channel_renames.sql lists the
renames (read-only). rename_duplicate_listed_channel_names.sh sends each
one with `buzz channels update`, signed by an operator key, then reads
the plan again and fails if any rename remains. The relay enforces the
name rule and publishes kind:39000 as for any rename, so relays keep
serving while it runs.
- Remove `buzz-admin reconcile-channel-groups --metadata` and the SQL
repair script; nothing needs them now.
- Refuse a kind:9007 with no h tag at ingest, before it is stored. Such a
create used to run in side effects, so a refusal there (a taken name)
still answered accepted. Every first-party client sends h.
Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Logan Johnson <loganj@squareup.com>
Two open channels in a community could share a name, so the channel
directory showed two "square-ios" entries with nothing to tell them
apart. The relay now refuses a create, rename, private-to-open switch or
unlisted-to-listed switch that would give a listed channel (an open, not
unlisted stream or forum that is not deleted) a name another listed
channel in the community already has, ignoring case. An archived channel
keeps its name. Private channels, DMs and other types may still repeat
names: nobody browses them side by side, and refusing a name a private
channel holds would reveal that the channel exists.
The check runs in the same transaction as the write, after it, under a
per-name advisory lock, so two writers claiming one name take turns.
Kind 9007 and 9002 report it as "invalid: an open channel named ...
already exists". The store also reports a write that the follow-up
unique index idx_channels_listed_name refuses as the same error, so this
release stays correct beside that index during its rollout and after a
rollback.
scripts/maintenance/rename_duplicate_listed_channel_names.sql renames
the duplicates that already exist. It locks a batch's rows before any
name lock, checks each locked row again, and gives it a name that no
listed channel has. `buzz-admin reconcile-channels --channel <id>
--metadata` republishes a renamed channel's kind:39000 so clients see
the new name. A live edit can race it, as it can race the relay's own
publisher, so it runs with no relay serving. It signs later than the
stored event, as the relay does, and fails unless the stored event
matches the channel row after its write.
Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Logan Johnson <loganj@squareup.com>