Skip to content

feat(relay): accept NIP-32 labels (kind:1985) - #5127

Open
magks wants to merge 1 commit into
block:mainfrom
magks:feat/nip32-labels
Open

feat(relay): accept NIP-32 labels (kind:1985)#5127
magks wants to merge 1 commit into
block:mainfrom
magks:feat/nip32-labels

Conversation

@magks

@magks magks commented Aug 7, 2026

Copy link
Copy Markdown

Summary

Registers kind:1985 (NIP-32 labels) as an ordinary member write, so Buzz accepts
labels and advertises 32 in its NIP-11 document.

required_scope_for_kind returns Err for unregistered kinds and the relay
rejects them, so a kind:1985 event is refused at ingest today.

A label is deliberately not routed the way kind:1984 is. A report is a private
signal to moderators and is suppressed from fanout; a label is a public claim, so
it takes the normal store-and-fanout path and the same membership gate as any
other message write. #h scopes it to a channel, per the existing convention.

The reason to want this in Buzz specifically: a relay may label a pubkey with its
own key
, and paired with the NIP-11 self identity Buzz already publishes, that
makes the label attributable to the relay that issued it rather than merely to
some keypair. A reader cannot establish that any other way.

No migration, no new HTTP surface, no side-effect handler.

Related issue

Discussion in #5126 — opened first, per CONTRIBUTING, since this adds a new
event kind. That issue carries the motivation; this PR is the implementation so the
proposal is reviewable rather than abstract. Happy to close this if the direction
isn't wanted — the issue is the part worth your time.

Searched open issues and PRs for NIP-32 / 1985 / labeling — none found.

Testing

just check and just test-unit pass. Unit coverage:

  • no_duplicate_kind_values now covers 1985 — KIND_LABEL is registered in
    ALL_KINDS. Verified the guard is real by adding a duplicate entry:
    duplicate kind value: 1985.
  • required_scope_for_kind(KIND_LABEL)Scope::MessagesWrite.
  • kind:1985 collides with none of the special-routing branches in handle_event
    (reports, gift wraps, etc.), so a label cannot be silently diverted off the
    ordinary path.
  • NIP-11 advertises 32.

End-to-end (crates/buzz-test-client/tests/e2e_nostr_interop.rs):

  • test_nip32_label_is_accepted_and_readable publishes a label over the
    WebSocket, then reads it back through the same generic POST /query surface a
    third-party client would use, asserting the L/l/p tags survive.
    Acceptance alone would also be satisfied by a relay that ACKs and discards, so
    the read-back is the half that matters.

The e2e test was checked against stock Buzz as a control — it fails there with
restricted: unknown event kind. It discriminates rather than passing vacuously.

Run it with:

cargo test -p buzz-test-client --test e2e_nostr_interop -- --ignored test_nip32_label

Docs

NOSTR.md "What Works" gains a kind:1985 row, including the #h scoping note — a
label published without one is accepted but never matches a channel-scoped
subscription, which presents as the relay silently dropping it.

Not in this PR

  • No client UI. Nothing in the desktop app composes or renders labels yet; this is
    the relay half only.
  • No label-specific query surface. A label is an ordinary event and is read with
    ordinary filters, deliberately.

`required_scope_for_kind` returns Err for unknown kinds and the relay rejects
them, so kind:1985 is refused at ingest today. This adds it as an ordinary
member write and advertises NIP-32.

A label is deliberately NOT routed like kind:1984. A report is a private signal
to moderators and is suppressed from fanout; a label is a public claim, so it
takes the normal store-and-fanout path and the same membership gate as any
other message write.

Registered in ALL_KINDS, which is what makes `no_duplicate_kind_values` cover
1985 — without it a future kind could silently reuse the number.

Tests:
  - kind.rs collision guard now covers 1985 (verified by adding a duplicate:
    "duplicate kind value: 1985").
  - required_scope_for_kind returns MessagesWrite for KIND_LABEL.
  - kind:1985 collides with no existing special-routing branch.
  - NIP-11 advertises 32.
  - e2e (buzz-test-client): a label is accepted, then read back through the
    same generic POST /query surface a third-party client uses, with its L/l
    pair intact. Acceptance alone would also be satisfied by a relay that ACKs
    and discards, so the read-back is the half that matters.

The e2e test was checked against stock buzz as a control: it fails there with
"restricted: unknown event kind", so it discriminates rather than passing
vacuously.

Docs: NOSTR.md "What Works" gains a kind:1985 row, including the `#h` scoping
note — a label published without one is accepted but never matches a
channel-scoped subscription, which presents as the relay silently dropping it.

Signed-off-by: magks <magks@protonmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant