feat(relay): channel labels as t tags on group-state events

A channel can carry up to 8 labels that group channels across channel
types. kind:9007 sets them with ["t", <label>] tags. On kind:9002 the t
tags replace the whole set, a lone ["t", ""] clears it, and an edit
without t tags leaves the set unchanged. Only an owner or admin may change
labels.

The relay refuses, before storage, a label that is not 1-64 characters
from a-z, 0-9, '.', ':' and '-', a label equal to a channel type name, an
empty label mixed with other labels, and more than 8 distinct labels.

Migration 0061 adds channels.labels (TEXT[], default empty, at most 8).
The relay publishes each label as a t tag after the channel type tag on
kinds 39000, 39001 and 39002, and buzz-admin reconcile does the same.
Clients read the first t value as the type; the CLI and buzz-acp parsers
used the last one and now use the first.

Signed-off-by: Logan Johnson <loganj@squareup.com>
Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
This commit is contained in:
Logan Johnson
2026-10-09 18:14:17 -04:00
parent 212dc1e0fd
commit eb7480ba99
19 changed files with 647 additions and 55 deletions

View File

@@ -842,6 +842,7 @@ async fn reconcile_channels(
tags.push(Tag::parse(["closed"])?);
tags.extend(group_state_identity_tags(
&channel.channel_type,
&channel.labels,
&channel.created_by,
)?);
tags.push(channel_created_at_tag(channel.created_at.timestamp())?);
@@ -859,6 +860,7 @@ async fn reconcile_channels(
let mut tags: Vec<Tag> = vec![Tag::parse(["d", &channel_id_str])?];
tags.extend(group_state_identity_tags(
&channel.channel_type,
&channel.labels,
&channel.created_by,
)?);
for m in members
@@ -882,6 +884,7 @@ async fn reconcile_channels(
let mut tags: Vec<Tag> = vec![Tag::parse(["d", &channel_id_str])?];
tags.extend(group_state_identity_tags(
&channel.channel_type,
&channel.labels,
&channel.created_by,
)?);
for m in &members {