Repository navigation
Conversation
…mbership Step 7 of the shared network plan (ADR 0037): the visibility gate. With a publisher key configured, a neighbour is reported to the application, and the automatic effects of discovering it run, only once the membership exchange makes it visible. The decision moves into the core. `neighbor_reachable(peer, transport)` runs discovery and says whether the caller reports `NeighborDiscovered` now; a report for a peer not yet visible is held, and the core emits the event itself, naming the carrier, when the exchange proves membership. `neighbor_unreachable(peer)` says whether `NeighborLost` is reported, which is only for a peer whose discovery was. Every UniFFI and browser emission site goes through the two, so there is one decision for every carrier. `PeerRssi` and a received `__PRESENCE__` ask `app_sees_peer`. The automatic key package push waits for visibility too. It is the one discovery effect that answers a stranger with this node's key material, and it runs when the held report is released. Not gated, on purpose: carriage (relay targets, the outbox flush, custody redelivery), and what the application asked for itself toward a peer it named (subscriptions, shared spaces, Welcomes, the relay presence answers for its watchlist). With no publisher key every peer is visible, which is the behaviour before this change. The browser's peer-stream discovery now also suppresses a blocked peer, as every other site always did.
This was referenced Nov 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Step 7 (and 7a) of the shared network plan (ADR 0037). Stacked on #687.
The gate
When a publisher key is configured, the application learns about a neighbour, and the automatic effects of discovering it run, only after the neighbour proves membership in the exchange.
neighbor_reachable(peer, transport) -> boolruns discovery, then says whether the caller reportsNeighborDiscoverednow.neighbor_unreachable(peer) -> boolreturns true only for a peer whose discovery was reported.notify_neighbor_reachableand the fourNeighborLostsites. In the browser crate it isble_host,nostr_host, andnode(link up and link down).PeerRssiand a received__PRESENCE__are reported only whenapp_sees_peeris true.Not gated, on purpose (7a)
The spec section
control-messages.md#application-membershipnow has a "What visibility gates" list.Behaviour without a publisher key
Unchanged for the bindings:
app_sees_peeris always true and nothing is held. The browser's peer-stream discovery has one change: it now suppresses a blocked peer, which every other site already did.Tests
Six new tests in
protocol::tests::membership:Suite results:
offline-protocollib: 2205 pass.offline-protocol-uniffi: 318 pass.offline-protocol-web: 88 of 89 pass. The one failure isno_shipped_file_names_a_relay, which fails locally on old agent worktrees under.claude/worktreesand is not related to this change.Clippy over the workspace is clean.
Next in the stack
7b: the inbound reply gate (named set and end-to-end proof). Until it lands, a configured member still answers a stranger's key package. This PR gates only what discovery does on its own.