The canary-DNS zone and the STUN host were compiled in as c.echo-lot.app and fmr-1.echo-lot.app, so every copy of the app measured against this particular deployment whatever server its owner had enrolled with. On someone else's install those two tests describe our infrastructure and report the result as a fact about their network. The zone comes from the server's own profile, which has advertised canary_zone all along — the app simply never read it. It is cached in settings because the canary probe runs at device tier, before anything has contacted the control plane, and a probe that had to make a call first would fail on exactly the networks worth measuring. The STUN host is derived from the configured server URL rather than stored, since a second copy of the server's name goes stale the moment someone re-enrolls elsewhere. With no server configured both now report SKIPPED. StunProbe previously would have reported FAILED on a blank host, which reads as a finding about the network when the truth is that no packet was ever sent — the same conflation between "measured nothing" and "measured a fault" that the ICMPv6 finding had. 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.