From ecb8dd2c11704a9170190121aef4fa84d8efe746 Mon Sep 17 00:00:00 2001 From: Paperclip Builder Date: Fri, 16 Oct 2026 11:35:59 +1100 Subject: [PATCH] docs: record Phase 1 ADB link proof Capture the commands, evidence and port-discovery method for the proven wireless ADB link from .13 to the Pixel 8a over Tailscale. Includes the copied-key rationale (no pairing code) and the moving-port scan. --- docs/phase-1-adb-link.md | 127 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 docs/phase-1-adb-link.md diff --git a/docs/phase-1-adb-link.md b/docs/phase-1-adb-link.md new file mode 100644 index 0000000..4e8749c --- /dev/null +++ b/docs/phase-1-adb-link.md @@ -0,0 +1,127 @@ +# Phase 1 — Prove the ADB link + +Status: **proven**. Originally verified on `.13` on 2026-10-16 and re-verified on +2026-10-16 during Phase 2 work. + +Phase 1 is the risk phase. Its Definition of Done is: *the view tree of a real +phone screen is fetched.* That is done. + +--- + +## 1. What was proven + +| Item | Value | +|---|---| +| Host | `.13` (`nixos-desktop`, LAN `192.168.20.13`, tailnet `100.114.62.46`) | +| adb | `android-tools-36.0.1`, installed with `nix profile install nixpkgs#android-tools` | +| adb server | listening on `127.0.0.1:5037` | +| Trusted key | `.27`'s `~/.android/adbkey` copied to `.13`; fingerprint `QAAAAOHiKYXfHo1i36gZXZqqoTErVCGXiEGc1Jv9atu+BHbi+JiNmPjQxUML` | +| Device | `100.101.49.17:46689` → `device product:akita model:Pixel_8a device:akita` | +| View tree | `adb shell uiautomator dump` → 14955 bytes, 42 nodes, all `com.tailscale.ipn` (first proof) | +| Screenshot | `adb exec-out screencap -p` → 174977 byte PNG, 1080x2400 (first proof) | + +The first proof captured the Tailscale app screen. Text and bounds are both +present in the dump, so FR-2 (read the screen) and FR-4 (find by text) are +viable: + +``` +[TextView] samuelrolfe@gmail.com bounds=[221,155][798,217] +[TextView] Connected bounds=[221,217][453,277] +[TextView] sams-pixel-8a bounds=[89,946][431,1022] +[TextView] nixos-desktop bounds=[89,1145][428,1221] +``` + +## 2. Commands + +Run these on `.13`. Every command is bounded with `timeout` so nothing can hang. + +```sh +# tool and server +adb version +ss -ltn | grep 5037 + +# connect (port changes — see section 4) +adb connect 100.101.49.17:46689 +adb devices -l + +# read the screen +adb shell uiautomator dump /sdcard/artemis_window_dump.xml +adb exec-out cat /sdcard/artemis_window_dump.xml + +# screenshot +adb exec-out screencap -p > shot.png +``` + +Expected device line: + +``` +100.101.49.17:46689 device product:akita model:Pixel_8a device:akita transport_id:2 +``` + +## 3. Why the copied key works, and no pairing code is needed + +The phone's ADB trust list is keyed by **public key**, not by host. A copy of +`.27`'s private key is therefore indistinguishable from the original, so the +phone already trusts `.13`. No pairing code and no re-pairing step is required. + +`adb mdns services` is **not** available in this build +(`error: unknown host service 'mdns:services'`), and mDNS does not cross the +tailnet anyway. ADB cannot auto-discover the phone, so Artemis must be told the +tailnet address and must discover the port itself. + +## 4. Finding the port when it changes + +The wireless-debugging port changes on **every phone reboot or toggle of +wireless debugging**. `36291` and `38989` are dead ports from earlier sessions. +Never hardcode the port. + +Android opens **two** TCP ports: a pairing port (which refuses `adb connect`) +and the connect port (which succeeds). On 2026-10-16 the open ports were +`38989` (pairing, refused) and `46689` (connect, worked). + +Artemis implements the scan in Go: + +```sh +artemis connect # scan 30000-65535 on ARTEMIS_PHONE, then adb connect +artemis connect # connect directly when the port is known +``` + +The equivalent scan by hand: + +```sh +# 1. find open ports in the wireless-debugging range +for p in $(seq 30000 65535); do + (timeout 1 bash -c "echo > /dev/tcp/100.101.49.17/$p" 2>/dev/null && echo "$p") & +done | sort -n + +# 2. try adb connect on each open port; the one that yields "device" wins +adb connect 100.101.49.17: +adb devices -l +``` + +Or ask Sam to read the port from **Settings → System → Developer options → +Wireless debugging**. + +## 5. Re-verification (2026-10-16, Phase 2 run) + +``` +$ adb version +Android Debug Bridge version 1.0.41 +Version 36.0.1-android-tools + +$ adb devices -l +100.101.49.17:46689 device product:akita model:Pixel_8a device:akita transport_id:2 + +$ adb exec-out cat /sdcard/artemis_p1.xml | wc -c +64735 +``` + +The byte count differs from the first proof because the phone was showing +Spotify rather than Tailscale. The link, key, device and port all match. + +## 6. Constraints carried forward + +- Never run `nixos-rebuild` on `.13`. It runs the Hub, MQTT and every service, + and `/etc/nixos` has uncommitted changes. +- adb lives in the **user profile** (see AGENTS.md §13, Q4), not a system module. +- Bound every adb command with a timeout.