Use case
A service needs to verify that one exact server event was delivered to an expected private channel without acquiring any mutation authority. The observer is provisioned by an operator, authenticates with its own Nostr key, and is explicitly present in only the channels it may observe.
This is narrower than #2475 / #3673: it needs no public link, self-service claim, desktop UI, guest writes, or new data plane.
Current gap
On a membership-gated relay, direct NIP-42 members receive every known scope. NIP-98 event submission similarly reconstructs the full scope set after checking membership. Several HTTP paths treat membership alone as mutation authority, and WebSocket COUNT does not enforce the MessagesRead scope used by REQ. Adding a cosmetic observer label would therefore still permit writes, joins/leaves, uploads, Git, huddle, GIF, and workflow operations.
Proposed minimal contract
- Add one operator-provisioned relay principal class for a read-only observer.
- Resolve the effective direct-member role once at the shared membership boundary.
- Grant an explicit non-empty read-only scope set; initially MessagesRead only.
- Continue to use existing channel membership for exact private-channel visibility.
- Permit only WebSocket REQ/COUNT and HTTP query/count reads that pass the existing channel and community gates.
- Deny event submission and every other HTTP surface by default, including media, Git, huddle, GIF, workflow, membership, join, and leave mutations.
- Do not allow NIP-OA delegation from an observer principal in the initial version.
- Preserve existing owner/admin/member behavior.
- Cover direct read, write denial, cross-channel denial, cross-community denial, and NIP-OA denial through production seams.
Non-goals
No new observer endpoint, event store, token format, public guest flow, UI, reconciliation service, or changes to event payloads.
Would maintainers accept this narrow role-aware principal boundary independently of the broader scoped-guest work in #3673?
Use case
A service needs to verify that one exact server event was delivered to an expected private channel without acquiring any mutation authority. The observer is provisioned by an operator, authenticates with its own Nostr key, and is explicitly present in only the channels it may observe.
This is narrower than #2475 / #3673: it needs no public link, self-service claim, desktop UI, guest writes, or new data plane.
Current gap
On a membership-gated relay, direct NIP-42 members receive every known scope. NIP-98 event submission similarly reconstructs the full scope set after checking membership. Several HTTP paths treat membership alone as mutation authority, and WebSocket COUNT does not enforce the MessagesRead scope used by REQ. Adding a cosmetic observer label would therefore still permit writes, joins/leaves, uploads, Git, huddle, GIF, and workflow operations.
Proposed minimal contract
Non-goals
No new observer endpoint, event store, token format, public guest flow, UI, reconciliation service, or changes to event payloads.
Would maintainers accept this narrow role-aware principal boundary independently of the broader scoped-guest work in #3673?