Skip to content

docs(nostr): document #h requirement for live reaction subscriptions … - #1

Merged
uwagz merged 1 commit into
moodco:mainfrom
block:main
Aug 1, 2026
Merged

docs(nostr): document #h requirement for live reaction subscriptions …#1
uwagz merged 1 commit into
moodco:mainfrom
block:main

Conversation

@uwagz

@uwagz uwagz commented Aug 1, 2026

Copy link
Copy Markdown

…(block#3487)

What this fixes

fan_out_scoped (crates/buzz-relay/src/subscription.rs:278-394) enforces a deliberate, symmetric scoping invariant — documented in the code itself:

Global subscriptions (channel_id = None) do NOT receive channel-scoped
events. Channel-scoped subscriptions do NOT receive global events.

The relay derives a reaction's stored channel from its #e target at ingest — client-supplied #h is ignored for channel determination (NOSTR.md:50 documents this for writing). The consequence for reading is that every reaction is a channel-scoped event, so a live subscription {"kinds":[7]} without #h is a global subscription and silently receives no reactions at all — no error, no CLOSED, just nothing. The working form is {"kinds":[7],"#h":["<channel-uuid>"]}, and it works regardless of how the reaction was signed: explicit h tags on the event are matched directly, and tagless reactions match via the stored channel fallback (crates/buzz-core/src/filter.rs:78-91 — fallback applies only when the event has no h tags; explicit tags are authoritative).

NOSTR.md already documents this exact pitfall for group-metadata events:

Note: Channel-scoped storage means live global subscriptions
({kinds:[39000]}) won't receive these via fan-out. (NOSTR.md:124-126)

…but has no equivalent note for reactions, which is the case a bot/integration author is far more likely to hit: any client that wants to observe approvals/reactions live (workflow reaction-triggers make this a first-class pattern in Buzz) will naturally try a kinds-only REQ first and conclude reactions are broken. We lost real debugging time to exactly this while building a headless integration (https://github.com/OriginTrail/buzz-dkg-integration); the behavior is by design, only the docs are missing.

What this PR changes

Docs only (NOSTR.md): a subscribe-to-reactions example in "Sending Messages", plus one note mirroring the existing 39000 note. No code changes.

How to verify

  • Behavior: with the relay running, open a live REQ {"kinds":[7]} (no #h) and react to a channel message from another client → nothing is delivered; re-subscribe with {"kinds":[7],"#h":["<channel-uuid>"]} → the reaction arrives.
  • Claims against code (verified at 485d03a): scoping invariant crates/buzz-relay/src/subscription.rs:386-393; channel derivation derive_reaction_channel() in
    crates/buzz-relay/src/handlers/ingest.rs; #h fallback crates/buzz-core/src/filter.rs:78-91 and its test h_tag_fallback_uses_stored_channel_id.

Duplicate search: no existing issue/PR found for reactions subscription, fan-out kinds (searched 2026-07-29). DCO signed-off.


Summary

Related issue

Testing

…3487)

## What this fixes

`fan_out_scoped` (`crates/buzz-relay/src/subscription.rs:278-394`)
enforces a deliberate, symmetric scoping invariant — documented in the
code itself:

> Global subscriptions (channel_id = None) do NOT receive channel-scoped
events. Channel-scoped subscriptions do NOT receive global events.

The relay derives a reaction's stored channel from its `#e` target at
ingest — client-supplied `#h` is ignored for channel determination
(`NOSTR.md:50` documents this for *writing*). The consequence for
*reading* is that every reaction is a channel-scoped event, so a live
subscription `{"kinds":[7]}` without `#h` is a global subscription and
**silently receives no reactions at all** — no error, no CLOSED, just
nothing. The working form is `{"kinds":[7],"#h":["<channel-uuid>"]}`,
and it works regardless of how the reaction was signed: explicit `h`
tags on the event are matched directly, and tagless reactions match via
the stored channel fallback (`crates/buzz-core/src/filter.rs:78-91` —
fallback applies only when the event has no `h` tags; explicit tags are
authoritative).

`NOSTR.md` already documents this exact pitfall for group-metadata
events:

> **Note:** Channel-scoped storage means live global subscriptions
(`{kinds:[39000]}`) won't receive these via fan-out.
(`NOSTR.md:124-126`)

…but has no equivalent note for reactions, which is the case a
bot/integration author is far more likely to hit: any client that wants
to observe approvals/reactions live (workflow reaction-triggers make
this a first-class pattern in Buzz) will naturally try a kinds-only REQ
first and conclude reactions are broken. We lost real debugging time to
exactly this while building a headless integration
(https://github.com/OriginTrail/buzz-dkg-integration); the behavior is
by design, only the docs are missing.

## What this PR changes

Docs only (`NOSTR.md`): a subscribe-to-reactions example in "Sending
Messages", plus one note mirroring the existing 39000 note. No code
changes.

## How to verify

- Behavior: with the relay running, open a live REQ `{"kinds":[7]}` (no
`#h`) and react to a channel message from another client → nothing is
delivered; re-subscribe with `{"kinds":[7],"#h":["<channel-uuid>"]}` →
the reaction arrives.
- Claims against code (verified at `485d03a`): scoping invariant
`crates/buzz-relay/src/subscription.rs:386-393`; channel derivation
`derive_reaction_channel()` in
`crates/buzz-relay/src/handlers/ingest.rs`; `#h` fallback
`crates/buzz-core/src/filter.rs:78-91` and its test
`h_tag_fallback_uses_stored_channel_id`.

Duplicate search: no existing issue/PR found for `reactions
subscription`, `fan-out kinds` (searched 2026-07-29). DCO signed-off.

---------

Signed-off-by: Žiga Drev <ziga.drev@gmail.com>
Signed-off-by: npub1jh9wn95s0472h86ahapupaf7m6kx4v9sx2n0atj2hltcfer8k06s5n3pyf <95cae996907d7cab9f5dbf43c0f53edeac6ab0b032a6feae4abfd784e467b3f5@buzz.block.builderlab.xyz>
Co-authored-by: Žiga Drev <ziga.drev@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: npub1jh9wn95s0472h86ahapupaf7m6kx4v9sx2n0atj2hltcfer8k06s5n3pyf <95cae996907d7cab9f5dbf43c0f53edeac6ab0b032a6feae4abfd784e467b3f5@buzz.block.builderlab.xyz>
@uwagz
uwagz merged commit c0c9bcf into moodco:main Aug 1, 2026
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.

2 participants