6.5 KiB
OpenSpec Change: network-plugin-intra-relay
- Change ID: network-plugin-intra-relay
- Package:
@suaveplan/network-plugin-intra-relay(new) - Status: PROPOSED
- Type: new-package
- Date: 2026-04-29
Why
The WebRTC mesh (network-plugin-webrtc) connects peers directly, but symmetric NAT, corporate firewalls, and restrictive ISPs prevent direct peer-to-peer connections between some peers. The existing network-plugin-relay handles cross-mesh routing (Mesh A → Mesh B), but there is no mechanism for intra-mesh relay: routing messages between two peers in the same mesh when they cannot connect directly. Without intra-mesh relay, a single symmetric NAT can partition the mesh from within.
This plugin provides indirect peer-to-peer communication through intermediate peers within the same mesh. It discovers relay candidates, selects optimal relay paths, maintains relay connections, and prevents relay loops.
What changes
- ADDED:
IntraRelayPluginclass implementingNetworkPlugin. - ADDED:
RelayDiscovery— discovers potential relay nodes from the mesh topology. Candidates are peers that have direct connections to both the source and target. Excludes leaf-tier peers (they cannot forward traffic). - ADDED:
RelaySelector— selects the optimal relay from candidates using strategies:LowestLatency— minimize end-to-end RTT through relayHighestReliability— maximize stability score (uptime, packet loss)FewestHops— prefer direct relay over multi-hopTierOptimized— prefer higher-tier peers (more capable hosts)LoadBalanced— avoid overloading a single relay peer
- ADDED:
RelayConnectionManager— tracks active relay paths per peer pair. MaintainsRelayConnectionstate:pending → active → degraded → closed. - ADDED:
RelayMessageEnvelope— wraps originalMessageEnvelopewith relay metadata:relayPath(array of peer IDs),hopCount,maxHops,visitedNodes(for loop prevention). - ADDED:
RelayPerformanceMonitor— tracks relay path quality: RTT, packet loss, bandwidth, stability. Publishesrelay:degraded/relay:recoveredonNetworkBus. - ADDED:
RelaySecurityManager— authenticates relay nodes using peer identities fromnetwork-plugin-crypto-messages. Validates relay message integrity (signature + hop count). Enforces relay rate limits per peer to prevent DoS. - ADDED:
LoopPrevention— drops messages wherehopCount >= maxHops(default 8) or wherevisitedNodescontains the current peer. - ADDED:
NETWORK_INTRA_RELAY_CODES— frozen error registry.
Relay path example
Peer A wants to send to Peer B, but direct ICE fails.
Peer A ──► Relay R (Tier 1 host, connected to both A and B)
Relay R ──► Peer B
Envelope from A:
original: { senderId: "A", targetId: "B", payload: ... }
relay wrapper: {
relayPath: ["A", "R", "B"],
hopCount: 0,
maxHops: 8,
visitedNodes: ["A"]
}
R forwards to B with hopCount: 1, visitedNodes: ["A", "R"]
Out of scope
- Cross-mesh relay → handled by
network-plugin-relay. - TURN server integration → future
network-plugin-turn. - STUN server discovery → handled by
network-plugin-webrtcICE.
Deferred to follow-up changes
To keep this initial change feature-complete on the surface it claims (per openspec/AGENTS.md §2c), the cryptographic relay-node authentication is split into a separate proposal so the core relay primitives ship without coupling to network-plugin-crypto-messages. None of the listed ## ADDED registry elements are removed — the security manager and its conformance test (security.spec-conformance.test.ts) migrate to the follow-up:
- RelaySecurityManager → follow-up
network-plugin-intra-relay-security. Authenticates relay nodes via thePeerIdentityVerifierfromnetwork-plugin-crypto-messages, validates relay-message signatures, and enforces per-peer relay rate limits to prevent DoS.
The core change shipped here covers: RelayDiscovery, RelaySelector (all 5 strategies), RelayConnectionManager (full FSM), RelayMessageEnvelope (with helper functions), LoopPrevention (max-hops + visited-nodes), RelayPerformanceMonitor (RTT-based degraded/recovered with hysteresis), and the IntraRelayPlugin facade.
Source mapping
This derives from docs/old-network-planning/RELAY_SECURITY_IMPLEMENTATION_PLAN.md §Relay Module and PHASE_2_5.md §RelayConnectionManager.
| Requirement | Source lines | Notes |
|---|---|---|
| Relay discovery from topology | RELAY_SECURITY_IMPLEMENTATION_PLAN.md §RelayDiscovery |
reworded; uses NetworkBus instead of direct topology import |
| Relay selection strategies | RELAY_SECURITY_IMPLEMENTATION_PLAN.md §RelaySelector |
reworded; 5 strategies |
| Relay message envelope | RELAY_SECURITY_IMPLEMENTATION_PLAN.md §RelayMessage |
reworded; wraps genesis MessageEnvelope |
| Loop prevention | RELAY_SECURITY_IMPLEMENTATION_PLAN.md §Loop Prevention |
verbatim: hop count + visited-node tracking |
| Relay security | RELAY_SECURITY_IMPLEMENTATION_PLAN.md §Relay Security |
reworded; uses crypto-messages for identity |
Requirements with no source line
| Requirement | Justification |
|---|---|
RelayConnectionManager FSM |
Required for graceful relay lifecycle management |
RelayPerformanceMonitor |
Required to detect degraded relay paths and trigger re-selection |
| Exclude leaf-tier from relay candidates | Leaf peers lack forwarding capacity; relaying through them would saturate their connection |
Verification approach
src/discovery/discovery.spec-conformance.test.ts— pins candidate discovery, leaf exclusion, topology awareness.src/selector/selector.spec-conformance.test.ts— pins 5 strategy behaviors, tie-breaking, load balancing.src/connection/connection.spec-conformance.test.ts— pins relay path establishment, teardown, degradation.src/envelope/envelope.spec-conformance.test.ts— pins relay wrapper format, hop count increment, visited tracking.src/loop/loop.spec-conformance.test.ts— pins max-hops drop, visited-node drop, no infinite loops.src/security/security.spec-conformance.test.ts— pins relay authentication, rate limiting, DoS prevention.src/monitor/monitor.spec-conformance.test.ts— pins RTT tracking, degradation detection, recovery.src/error-codes.spec-conformance.test.ts— frozen registry.tests/dep-graph.test.ts— pins no direct import of webrtc or topology packages.
Migration impact
None — additive only.