feat(companion): npub-first pairing — node self-anchor + guaranteed public anchor in the QR
The pairing QR was effectively IP-first: the phone dialed the scanned LAN host and went dark when the LAN renumbered or it left home. FIPS peers on npubs; IPs are only dial hints. fanchors now leads with the paired node ITSELF (fnpub @ current host, npub-keyed so LAN contact is direct p2p over FIPS and survives DHCP), and fips.pair-info always includes the Archipelago vps2 public anchor (pairing hint only — the node's own anchor file is not modified) so the phone can rendezvous through the public mesh when away. Contract doc updated with the REQUIRED app-side changes (built on the Mac). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
e59ea1da69
commit
c58f84c6e9
@@ -38,7 +38,7 @@ Query parameters:
|
||||
| `fip` | no | Node's `fips0` ULA (IPv6). Once the phone is meshed, the node's UI stays reachable at `http://[<fip>]` from anywhere — this is the remote-access address (replaces the old WireGuard 10.44.0.1 flow). |
|
||||
| `fhost` | no | Host the phone's embedded FIPS dials (same host `url` resolved to). |
|
||||
| `fudp` / `ftcp` | no | Mesh transport ports on `fhost` (currently 2121/udp and 8443/tcp). |
|
||||
| `fanchors` | no | Comma-joined `npub@host:port/transport` rendezvous anchors (the node's seed-anchor list, capped at 4). The phone peers with these too so it can route to the node via the public mesh when the direct endpoint is unreachable (away from home / NAT). |
|
||||
| `fanchors` | no | Comma-joined `npub@host:port/transport` rendezvous anchors, capped at 4. **The FIRST entry is the paired node itself** (`fnpub` at its current LAN host — the addr is a dial *hint*, the npub is the identity). The remaining entries are the node's seed anchors, and the node guarantees the Archipelago public anchor (vps2, `146.59.87.168:8444/tcp`) is present even if the operator trimmed their own list — so the phone can always rendezvous through the public mesh when the LAN endpoint is unreachable (away from home / NAT). |
|
||||
|
||||
Examples the web UI actually emits:
|
||||
|
||||
@@ -87,6 +87,31 @@ Examples the web UI actually emits:
|
||||
remote access = the node's fips0 ULA (`fip`), which the WebView falls back to
|
||||
automatically when the LAN address stops answering.
|
||||
|
||||
## npub-first connectivity (2026-07-23 — REQUIRED app-side changes)
|
||||
|
||||
The QR used to be effectively IP-first: the app connected to `url`/`fhost` and
|
||||
broke as soon as the LAN renumbered or the phone left home. FIPS peers on
|
||||
**npubs**; IPs are only dial hints. The app must treat them that way:
|
||||
|
||||
1. **Identity = `fnpub`.** The saved server entry is keyed by the node's npub
|
||||
(fall back to origin only when the QR has no FIPS params). Re-scanning the
|
||||
same npub updates the entry even if every address changed.
|
||||
2. **Peer with the node itself as the first anchor** (`fanchors[0]`): on LAN
|
||||
this is direct p2p over FIPS (mDNS/known-endpoint dial via archy-fips-core
|
||||
v0.4+, which discovers LAN peers without any IP pinning), so it keeps
|
||||
working after DHCP renumbering.
|
||||
3. **Peer with the public anchors too** (remaining `fanchors` entries — the
|
||||
Archipelago vps2 anchor is always included by the node): away from LAN the
|
||||
phone routes to the node's npub via the public mesh and reaches the UI at
|
||||
`http://[<fip>]` (the fips0 ULA).
|
||||
4. **Address selection order** for the WebView: LAN `url` when it answers →
|
||||
ULA `fip` over the mesh otherwise. Never hard-fail because the scanned LAN
|
||||
IP stopped existing.
|
||||
|
||||
(Node-side counterpart shipped 2026-07-23: `fips.pair-info` always includes
|
||||
the vps2 public anchor, and the web UI prepends the node's self-anchor to
|
||||
`fanchors`.)
|
||||
|
||||
## Testing checklist (app side)
|
||||
|
||||
- [ ] Scan demo QR from https://demo.archipelago-foundation.org → auto-connected demo session.
|
||||
|
||||
Reference in New Issue
Block a user