Release PR for **spt-core v0.17.0** — robust WAN join + presence truth + picker parity. Cut by deployah off the doyle-gated branch `v0.17.0-robust-join`.

## Contents (5 build waves, doyle-gated; + docs + bump)
- **W1** `7cddaba` feat(net): per-family bind gate — robust WAN join over half-broken IPv6 (`SPT_DISABLE_IPV6`/`IPV4`)
- **W4** `867c7ab` fix(registry): cold perch → Suspended not Dormant (presence truth, no false-ONLINE remote)
- **W2** `a07322c` feat(pair): two-phase meet-before-code join
- **W3** `be1f4d6` feat(pair): diagnosable join (progress + `--verbose` + no silent fail)
- **W5** `54a4540` feat(picker): subnet display parity + status palette
- **CHANGELOG** `68688ed` — `[0.17.0]` section = GH release notes verbatim (doyle-vetted)
- **Public docs** `38965cb` — networking/overview (two-phase join + Troubleshooting a join) + lifecycle/overview (picker status-square palette legend)
- **Bump** `0403ad3` — workspace 0.16.0→0.17.0 + 11 first-party Cargo.lock only (`[twohost]` HEAD)

## Cut mechanics
- **Counter 36** at publish — cross-checked monotonic 35→36 vs PUBLISHED `spt-x86_64-linux.release.json` on spt-releases.
- **Bump surgical**: third-party `netwatch` + `portmapper` (also at 0.16.0) deliberately held — blind replace would dangle the lock.
- **`[twohost]`** on the HEAD commit opts in the two-host rig ladder (W2 handshake-order + W5 gossip/QUIC seam).
- Sign FRESH on the tagged commit at publish.

## Local pre-flight (post-bump, branch HEAD)
- `xtask gen` — no drift · `xtask check` — OK (no token leak) · `traceable-reqs check` — exit 0

⚠️ **twohost trigger note (flagged to doyle):** the ladder gates on `github.event.head_commit.message` (a push-event field, null on `pull_request`) and `on.push.branches` = `[main, dev-freeform]` — so this PR's `pull_request` run fires `test`/`n1-gate`/`traceability` but **not** twohost-a/b. Firing the ladder needs the `[twohost]` commit pushed to a push-trigger branch (dev-freeform pre-merge, or main on merge). Awaiting doyle's directed path.
