Relay selection and delivery

Current implementation

getSignalRelays() reads the explicit fips_signal_relays table. There are no implicit BOT_RELAYS or kind 10050 discovery defaults anymore. Before an invitation is completed, a fresh installation has no signaling relays.

The required relay in a signed invitation is persisted by the inviter and acceptor. Both subscribe to the accumulated explicit relay set, publish adverts there, and send traversal signals there. This provides a common rendezvous point without recipient relay-list discovery. See pairing.

The relay must accept kind 37195 adverts and kind 21059 signaling for the dedicated FIPS identity. The plugin checks advert publication acceptance on the invite relay before returning a signed code; this does not prove subscription health, signaling delivery, peer availability, or UDP reachability. Advert and traversal offer/answer publication now require at least one acknowledgement within eight seconds per relay, with per-relay rejection/timeout reasons logged.

Three distinct server roles

Server Carries Purpose
Nostr relay JSON Nostr events Adverts and encrypted traversal signaling
STUN server UDP binding requests/responses Observe the public mapping of a punch socket
FIPS WebSocket seed Binary FIPS records Provide adjacency into a forwarding mesh

An ordinary Nostr relay cannot be entered as a FIPS WebSocket seed. STUN does not forward app traffic. After successful traversal, app data goes through FIPS encryption over UDP, rather than through Nostr relays.

Deferred discovery and configuration work

If an invite relay becomes unavailable, there is currently no automatic remote relay migration discovery. Known common relays can still carry signals; otherwise users need a new invitation with a reachable relay.

References