<!-- [doc->REQ-DEVICE-LINK-IROH] -->
# The device link is iroh, via an embedded Rust slice in the app

Phones change IP constantly (wifi roaming, 4G/5G handoff); the device link must be identity-addressed, not IP-addressed. We ruled: the app embeds a thin Rust core (JNI, built with cargo-ndk) that dials the host binary's **iroh node key** — relay + hole-punching + connection migration come from the same transport spt-core already rides, with zero new networking invented for spt-mobile and zero external dependencies.

## Considered options

- **Tailnet + WebSocket/JSON** — rejected: solves roaming but adds a tailscale dependency on every device, invents a bespoke throwaway protocol, and duplicates auth outside the pairing token. "Quick" v1 that defers riding spt-core's infra indefinitely.
- **FCM-relayed or cloud-brokered link** — rejected out of hand: third party in the message path, against the self-hosted grain of the ecosystem.
- **iroh in-app (chosen)** — node-key addressing makes roaming a non-event; the Rust slice reuses spt-core's proto/format crates and rides the same iroh transport.

## Consequences

- The Rust-on-Android toolchain (cargo-ndk, aarch64) exists from day one — deliberately: this slice IS the first Android build target of spt-core code, the on-ramp for the hybrid "full node later" path (ADR-0001).
- The host binary owns its own iroh endpoint, separate node key from the daemon's; pairing (QR: node key + token) authenticates the phone to the binary, not to the subnet.
- Crate boundary (amended 2026-07-06, source-independence rule in AGENTS.md): **no spt-core
  crate/path dependencies at all** — spt-mobile builds against the public contract
  (<https://sabermage.github.io/spt-releases>) only. Wire/format parity (the `<EVENT>`
  envelope, send-outcome lines, digest shapes) is implemented clean-room from the public
  docs and pinned by round-trip tests; the spt CLI is the api surface. The device link uses
  its own iroh dependency (pinned `=0.98.2` to match spt-core's, per released docs) with its
  own ALPN (`spt-mobile/link/0`) and its own bearer-token pairing layer.
- The iroh connection is held by a foreground service for inbound push; deep doze may delay delivery into maintenance windows — accepted for v1 (host spool makes it late, never lost).
- Optional dev nicety, not contract: the host binary may also serve the same frames over loopback WS for emulator/curl debugging.
