Both sides now declare what they will talk to, and enforce it. Two axes kept
deliberately separate, because conflating them is the trap:
protocol_version — CAN these builds talk. The correctness axis. Below 1.0.0
the minor is the breaking axis, per SemVer §4.
release window — MAY they, per policy. [min, max), advertised in the
profile, overridable by the operator.
The server refuses out-of-window apps with 426 and a body naming both versions
and the accepted range; the app checks the profile in both directions before a
run rather than discovering mid-measurement that it will be refused.
Three rules that shape the rest:
- GET /v1/profile is never gated. It is where a refused client learns which
version it needs; gating it leaves the user with a network error instead of
an answer, which is precisely the confusion this exists to remove.
- An unparseable or absent version is "unknown", and is allowed. Development
builds report "dev", and a client too old to send the header cannot be
identified anyway.
- Bounds sit at breaking boundaries, not at releases, so shipping a patch
never requires editing a range. The app's server minimum is 0.4.2 for a
stated reason: earlier multi-homed servers mis-addressed granted sends and
the client measured 100% downstream loss that never happened.
The app's versionCode is now derived from its SemVer instead of being a second
number someone has to remember to bump.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Echolot
Free software for detecting and debugging local network issues from an Android phone — built for people who actually know what a neighbor table is.
Most "wifi analyzer" apps show you signal bars. Echolot aims at the layer where home and office networks actually break: duplicate DHCP servers, broken IPv6 RAs, MTU black holes, NAT64 weirdness, multicast that dies at the AP, DNS that answers differently than it should. It records what it observed, separates observation from interpretation, and exports the whole run so you can argue with it later.
Status: pre-release. The capability prober runs on real hardware; the production app and the probe server are not built yet.
Repository layout
docs/ design docs — the contract for everything below
echolot-prober/ capability prober: validates the no-root feasibility matrix on real devices
The Go probe server and the production app land here as siblings.
Design docs
The three specs are draft-complete and reviewed; treat them as the contract.
| Doc | What it defines |
|---|---|
| docs/feature-catalog-and-feasibility.md | Full feature list + the no-root feasibility matrix |
| docs/measurement-schema.md | Archived/exportable measurement JSON (observation vs finding, two-clock rule, anonymization) |
| docs/probe-protocol.md | Client↔server wire protocol (pinned TLS control plane, binary UDP data plane, STUN, canary DNS) |
| docs/build-status.md | Running log of decisions and next steps |
Privilege tiers
Every result records which tier produced it:
app— no root, no special setup. The bulk of the functionality.shizuku— ADB-shell privileges via wireless pairing, no root. Shipped in v1.root— future optional module.
Licensing
| Part | License | Why |
|---|---|---|
| All code (app, prober, server) | GPL-3.0-or-later | The value here is the platform-API research; copyleft keeps derivative apps free |
docs/ (the specs) |
CC-BY-4.0 | A wire protocol and a measurement format should be implementable by anyone, without license anxiety |
Full texts: LICENSE (GPLv3) and docs/LICENSE (CC BY 4.0).
Sources carry SPDX-License-Identifier headers.
If you want to build a compatible server or client, the protocol and schema docs are deliberately permissive — go ahead.
Building
See echolot-prober/README.md. Short version, from echolot-prober/:
echo "sdk.dir=/path/to/Android/sdk" > local.properties
./gradlew :app:assembleDebug