Emerging from the WebRTC CustomTransport spike on #25: instead of teaching iroh about non-IP transports through the (upstream-blocked) custom-transport seam, present the transport as an IP address behind the wasi:sockets shim we already own on every target. The shim assigns a synthetic address per peer, routes datagrams for it over the real transport (webrtc data channel, websocket, anything datagram-shaped), and the application's own connection machinery does the rest. For iroh specifically: Endpoint::add_external_addr feeds the synthetic addr into the NAT-traversal candidate exchange, the peer's holepunch probes are "terminated" by the shim (there is no NAT; the probes simply arrive over the channel), the path validates as a normal multipath IP path, and the selector migrates the live connection — relay→webrtc live migration with zero iroh changes and no unstable features.
Why this may deserve its own project
The mechanism is not iroh-specific. It is the overlay-network pattern (Tailscale/TUN, ZeroTier, onion addressing, mesh sidecars): a synthetic address vocabulary over a controlled network surface, with the app's connection machinery driving transports it cannot name. It generalizes to most network applications given:
- an injectable address vocabulary (config, API, DNS);
- semantics the transport can honor (unreliable datagrams for UDP-speakers; a reliable stream or a shim-side TCP for TCP-speakers);
- a way to hide transport unreadiness — app retry, protocol retransmit, or shim-side buffering/blocking (the shim controls when failure becomes visible);
- path agility owned somewhere: rich apps (iroh multipath, MPTCP, QUIC) let the shim stay thin; dumb apps need shim-side session continuity under a stable synthetic address.
Our position is unusually favorable: the shim is not an added interception layer — it is the only network surface a wasip2 component has, on every deployment target including browsers. A generic polymorph-overlay would own: synthetic address allocation (collision-resistant, e.g. random-prefix ULA), the routing table (per-peer routes learned at signaling time), transport adapters (polymorph:webrtc-datachannels, polymorph:websocket, ...), readiness signaling to the guest, and the control protocol — with component-iroh as its first consumer instead of carrying iroh-shaped bridge code.
Known warts any design must carry (from the spike review)
- The address fiction leaks. iroh treats the synthetic addr as real: it may publish it to discovery records where stock peers can see it. Needs scoping (suppress publication, or accept bounded probe waste) — there may be no "advertise in-band but don't publish" knob upstream.
- Collision. Any synthetic range can exist in someone's real network. Random-prefix IPv6 ULA plus dynamic per-peer routes bounds this; hardcoded IPv4 ranges (100.64/10 et al.) do not.
- Nested control loops. QUIC-over-SCTP-over-DTLS: chunk loss amplifies for large packets; MTU discovery runs over a fiction. Per the repo's measured-claims policy, these are numbers to produce, not assumptions.
- Observability lies. Path listings show synthetic IPs that look like LAN peers.
- The shim becomes load-bearing network infrastructure — correctness we own, not the kernel.
Gate
Validate with iroh first (in progress on #25: live relay→webrtc migration on a single connection via add_external_addr). Only after that lands and the warts have measured shapes does splitting a generic project make sense. This issue is the marker for that decision, not a work order.
Emerging from the WebRTC
CustomTransportspike on #25: instead of teaching iroh about non-IP transports through the (upstream-blocked) custom-transport seam, present the transport as an IP address behind the wasi:sockets shim we already own on every target. The shim assigns a synthetic address per peer, routes datagrams for it over the real transport (webrtc data channel, websocket, anything datagram-shaped), and the application's own connection machinery does the rest. For iroh specifically:Endpoint::add_external_addrfeeds the synthetic addr into the NAT-traversal candidate exchange, the peer's holepunch probes are "terminated" by the shim (there is no NAT; the probes simply arrive over the channel), the path validates as a normal multipath IP path, and the selector migrates the live connection — relay→webrtc live migration with zero iroh changes and no unstable features.Why this may deserve its own project
The mechanism is not iroh-specific. It is the overlay-network pattern (Tailscale/TUN, ZeroTier, onion addressing, mesh sidecars): a synthetic address vocabulary over a controlled network surface, with the app's connection machinery driving transports it cannot name. It generalizes to most network applications given:
Our position is unusually favorable: the shim is not an added interception layer — it is the only network surface a wasip2 component has, on every deployment target including browsers. A generic
polymorph-overlaywould own: synthetic address allocation (collision-resistant, e.g. random-prefix ULA), the routing table (per-peer routes learned at signaling time), transport adapters (polymorph:webrtc-datachannels,polymorph:websocket, ...), readiness signaling to the guest, and the control protocol — with component-iroh as its first consumer instead of carrying iroh-shaped bridge code.Known warts any design must carry (from the spike review)
Gate
Validate with iroh first (in progress on #25: live relay→webrtc migration on a single connection via
add_external_addr). Only after that lands and the warts have measured shapes does splitting a generic project make sense. This issue is the marker for that decision, not a work order.