The settings card offered three editable boxes and said nothing about the server itself — which addresses a test will actually use, on which ports, what it can measure. That is the part a person checks before trusting a result, and "which address did this come from" is precisely the question a report leaves open. The server now publishes it. The profile's targets carried one IPv4 and a TODO; it reports both families and both alternates, derived from the UDP listen spec rather than configured separately, so the list cannot drift from what is actually bound. No reservation means no alternate is claimed: announcing a second address as the RFC 5780 alternate when none was set aside would promise a redirect the server will not send. The app renders them read-only, in a panel visibly distinct from the fields above. An editable box that changes nothing is worse than no box, and these are facts to read rather than settings to apply. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Echolot app
The production Android client (spec). Native Kotlin + Jetpack Compose. Multi-module; built bottom-up from a verifiable protocol spine.
Modules
| Module | Type | Status |
|---|---|---|
core-protocol |
pure Kotlin/JVM | done — client half of probe-protocol.md, verified live against the server |
core-measurement |
pure Kotlin/JVM | planned — measurement-schema.md types |
core-probe |
Android lib | planned — app-tier probes, ported from echolot-prober |
core-shizuku |
Android lib | planned — dual-path executor (UserService + newProcess fallback) |
app |
Android app | planned — Compose UI |
core-protocol is deliberately Android-free so it builds and unit-tests on any JDK (no Android
SDK) and can run integration tests against a live server.
core-protocol
Implements the control plane (SPKI-pinned enrollment/profile/sessions via HttpsURLConnection —
Android-API-1 compatible, hostname verification off because trust is the pin), the HKDF-SHA256
session-key schedule, and the binary ELT1 UDP data plane (HMAC gate, ECHO + observation block,
MTU probe) — byte-compatible with the Go server.
./gradlew :core-protocol:test # unit tests (crypto vectors, wire round-trip)
scripts/test-fmr.sh # live end-to-end test against the deployed server
test-fmr.sh mints an enrollment token over SSH, enrolls via the public control plane, computes
the SPKI pin from the served cert, and runs LiveServerTest — proving the client speaks the wire
protocol to the real server (enroll → profile → session → echo+observation → MTU → observations).
The live test self-skips when ECHOLOT_LIVE_* env vars are absent, so unit runs and CI stay green
offline.