mirror of
https://github.com/block/buzz.git
synced 2026-10-27 04:30:52 +00:00
feat(relay): channel labels (#8175)
🤖 ## Summary A plugin or agent often needs to tag its own channels and then find them again, for example "my attention-config channel" or "all channels of this workspace". Today a channel has no labels: the relay ignores any `t` tags in create or edit requests. This PR adds channel labels. - A create request can carry up to 8 labels as `["t", "<label>"]` tags. - An edit request with `t` tags replaces the label set. `["t", ""]` alone clears it, the same convention as `["ttl", ""]`. Only owners and admins can change labels, as for the name. - The relay publishes each label as a `t` tag on the channel's state events, after the channel type tag. Part 2 of 3, stacked on part 1. ### Related issue None found. ### Details - **Rules.** A label uses 1–64 characters from `a-z`, `0-9`, `.`, `:` and `-`. The relay refuses a label equal to a channel type name (`stream`, `forum`, `dm`, `workflow`, `system`), so a label cannot make a channel look like another type. - **No trust from labels.** Any admin can set a label. Only the relay-written creator tag (part 1) says who made a channel. - **Storage.** New migration `0061_channel_labels.sql` adds `channels.labels TEXT[] NOT NULL DEFAULT '{}'`. Channels without labels look and behave as before. - **Readers.** The CLI and `buzz-acp` read the channel type from the first `t` tag. Before this PR they used the last one, which would now be a label. - **Spec.** NIP-CL gets a "Channel labels" section with these rules. ### Testing - Relay tests: labels at creation appear after the type tag, edit replaces and clears them, invalid labels are refused, and members who are not admins cannot change them. - Unit tests for the label rules: allowed characters, length, reserved type names, the 8-label cap and the clear marker. - `buzz-acp` test: the channel type comes from the first `t` tag, not a label. ### Stack These are two stacks. Merge them in this order. Client support (creating, labeling and finding these channels) will be in block/buzz-app, not the buzz SDK and CLI. **Stack 1: channel labels and creator lookup (#8174–#8176)** 1. #8174 channel type and creator tags, and the channel creation time 2. #8175 channel labels ← this PR 3. #8176 database-side label and creator match, and the rule for choosing one channel **Stack 2: system channels (#8180–#8182)**, stacked on stack 1 because it uses labels and the creator tag 4. #8180 the system channel type 5. #8181 leave system channels out of reads that do not name them 6. #8182 channel-state filters opt in to system channels --------- Signed-off-by: Logan Johnson <loganj@squareup.com> Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
This commit is contained in:
18
NOSTR.md
18
NOSTR.md
@@ -50,10 +50,10 @@ PGPASSWORD=buzz_dev psql -h localhost -U buzz -d buzz -c \
|
||||
| **Reactions (kind:7)** | ✅ | Standard NIP-25; channel derived from target event's `#e` tag (client `#h` ignored) |
|
||||
| **Deletions (kind:5)** | ✅ | Standard NIP-09; self-authored only. `#h` optional, `#e` required |
|
||||
| **User profiles (kind:0)** | ✅ | NIP-01 metadata; synced to users table (display_name, avatar, about, NIP-05). NIP-05 handles must canonicalize to this relay's domain — off-domain or invalid handles are silently cleared. If a NIP-05 handle collides with another user's (UNIQUE constraint), the handle is skipped but other profile fields (display_name, avatar, about) are still synced. |
|
||||
| **Group creation (kind:9007)** | ✅ | NIP-29; include `name` tag, optional `visibility` and `channel_type` |
|
||||
| **Group creation (kind:9007)** | ✅ | NIP-29; include `name` tag, optional `visibility`, `channel_type` and label `t` tags |
|
||||
| **Add user (kind:9000)** | ✅ | Open: any user, subject to target's `channel_add_policy` (`owner_only`/`nobody` can block). Private: owner/admin only. Self-add bypasses agent policy but not private-channel auth. |
|
||||
| **Remove user (kind:9001)** | ✅ | Self-remove allowed (with last-owner guard). Removing others: owner/admin only. |
|
||||
| **Edit group metadata (kind:9002)** | ✅ | `name`/`about` tags: owner/admin. `topic`/`purpose` tags: any member. |
|
||||
| **Edit group metadata (kind:9002)** | ✅ | `name`/`about`/label `t` tags: owner/admin. `topic`/`purpose` tags: any member. |
|
||||
| **Admin delete event (kind:9005)** | ✅ | Event author can always delete own. Otherwise owner/admin required. Target must be in same channel. |
|
||||
| **Group deletion (kind:9008)** | ✅ | Owner only. |
|
||||
| **Leave group (kind:9022)** | ✅ | Any member. Last-owner guard prevents orphaned groups. |
|
||||
@@ -113,7 +113,9 @@ All discovery events include a `d` tag set to the channel UUID (NIP-29 addressab
|
||||
| **39001** | `d=<uuid>`, `t=<channel_type>`, `P=<creator>`, `p` tags with role label (`owner`, `admin`) | Admin list |
|
||||
| **39002** | `d=<uuid>`, `t=<channel_type>`, `P=<creator>`, `p` tags for all members | Member list |
|
||||
|
||||
On all three kinds the channel type `t` tag comes first, then `P`. `P` is
|
||||
On all three kinds the channel type `t` tag comes first, then one `t` tag
|
||||
per channel label, then `P`. Clients read the first `t` value as the
|
||||
channel type. `P` is
|
||||
the public key that signed the channel's kind:9007. The relay writes it
|
||||
from the database, and it does not change when ownership moves. Uppercase
|
||||
`P` follows NIP-22, NIP-34 and NIP-72, where it names the author of the root
|
||||
@@ -124,6 +126,16 @@ kind:39000 also carries `["created_at", <unix seconds>]`: the time the
|
||||
channel was created. The event's own `created_at` is the time of the last
|
||||
edit, so use the tag to find the older of two channels.
|
||||
|
||||
**Channel labels.** A label groups channels across channel types, for
|
||||
example `["t", "workspace"]`. Set labels with `["t", <label>]` tags on
|
||||
kind:9007. On kind:9002 the `t` tags replace the whole set, and
|
||||
`["t", ""]` with no other `t` tag clears it; a kind:9002 without `t` tags
|
||||
leaves the labels as they are. Only an owner or admin may change labels.
|
||||
The relay refuses a label set with more than 8 distinct labels, a label
|
||||
that is not 1-64 characters from `a-z`, `0-9`, `.`, `:` and `-`, or a
|
||||
label equal to a channel type name (`stream`, `forum`, `dm`, `workflow`,
|
||||
`system`).
|
||||
|
||||
Events are stored **channel-scoped** so access control applies — private channel member lists are
|
||||
only visible to members. Discover groups via historical REQ:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user