server-release / release (push) Failing after 41s
The wireless-adb findings, report-collection workflow, build-number convention, per-device Shizuku matrix, and the JDK constraint now live in the repo so a session on any machine starts with them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
86 lines
4.7 KiB
Markdown
86 lines
4.7 KiB
Markdown
# Echolot — context for Claude Code
|
||
|
||
This repo is the **capability prober** for the Echolot project: an F/OSS Android app for detecting
|
||
and debugging local network issues (target audience: network engineers). The prober validates the
|
||
no-root feasibility matrix on real hardware before the production app is built.
|
||
|
||
## Project facts
|
||
|
||
- **Name:** Echolot. Domain echo-lot.app. URI scheme `echolot://`. Namespace `app.echo_lot.*`
|
||
(hyphen→underscore; appIds/packages can't contain hyphens). Prober appId: `app.echo_lot.prober`.
|
||
- **Stack:** native Kotlin + Jetpack Compose. No Flutter (all value is in platform APIs;
|
||
Flutter would be a Dart skin over a full Kotlin app + F-Droid build friction).
|
||
- **Tiers:** `app` (no root), `shizuku` (ADB-shell privileges via wireless pairing, shipped in v1),
|
||
`root` (future module). Every result records which tier produced it.
|
||
- **License:** code is **GPL-3.0-or-later** (`LICENSE`), the specs in `docs/` are **CC-BY-4.0**
|
||
(`docs/LICENSE`). New source files get the two-line SPDX header the existing ones carry.
|
||
The server, when it lands, is GPL too — not AGPL (see `docs/build-status.md` for the reasoning).
|
||
|
||
## Design docs (source of truth, in `docs/`)
|
||
|
||
- `docs/feature-catalog-and-feasibility.md` — full feature list + no-root feasibility matrix.
|
||
- `docs/measurement-schema.md` — the archived/exportable measurement JSON format (observation vs
|
||
finding separation, two-clock rule, columnar trains, anonymization types).
|
||
- `docs/probe-protocol.md` — client↔server wire protocol (pinned-TLS control plane, binary UDP data
|
||
plane with anti-amplification HMAC, STUN, canary DNS reference records).
|
||
- `docs/build-status.md` — running log of decisions, what is delivered, and the next steps.
|
||
|
||
The three specs are draft-complete and user-reviewed; treat them as the contract. `build-status.md`
|
||
is the mutable one — update it as work lands.
|
||
|
||
Keep prober result IDs aligned with the measurement-schema test-type registry.
|
||
|
||
## Layout
|
||
|
||
Monorepo. The prober is one deliverable; the Go server and the production app land as siblings.
|
||
|
||
```
|
||
docs/ design docs (above) — apply repo-wide, not just to the prober
|
||
echolot-prober/ the capability prober (self-contained Gradle build)
|
||
app/src/main/java/app/echo_lot/prober/
|
||
MainActivity.kt Compose host, runs probes sequentially
|
||
probe/ Probe interface + all app-tier probes + OS ABI helper
|
||
shizuku/ AIDL UserService + ShizukuRunner (shell command exec)
|
||
export/Report.kt JSON report + share intent
|
||
ui/ProberScreen.kt result cards colored by verdict
|
||
```
|
||
|
||
## Conventions
|
||
|
||
- Every probe returns a `ProbeResult` — never throws to the caller (MainActivity wraps anyway).
|
||
- Uncertain OS API paths (getsockoptInt, recvmsg, nat64Prefix) are reached via reflection/runCatching
|
||
and reported, not assumed — the prober's purpose is to discover what exists.
|
||
- Hardcoded Linux sockopt ABI numbers live in `OsAbi.kt` with rationale; do not "fix" them to
|
||
OsConstants names that don't exist.
|
||
|
||
## Build
|
||
|
||
From `echolot-prober/`: `./gradlew :app:assembleDebug` (needs local Android SDK; set `sdk.dir` in
|
||
`echolot-prober/local.properties`). The Gradle build is rooted there, not at the repo root.
|
||
First build downloads AGP/Compose/Shizuku from Google Maven + Maven Central.
|
||
|
||
## Working with test devices (hard-won lessons)
|
||
|
||
- **Prefer USB for adb.** Wireless debugging dies constantly: probe runs churn the wifi the
|
||
debug link rides on, the Lenovo tablet's ZUI power management kills the listener anyway, and
|
||
the port rotates on every restart. Deploys over wireless work between runs; never drive a
|
||
probe run over adb.
|
||
- Collection loop that works: install over adb → the **user** runs the probes and exports the
|
||
JSON manually → archive it under `echolot-prober/reports/` and record findings in
|
||
`docs/build-status.md`.
|
||
- Bump `versionCode` on every deployed prober change — it shows on screen and as `proberBuild`
|
||
in the report; that's how a report is matched to a build.
|
||
- Known devices: OnePlus 15 (CPH2747, A16) — Shizuku UserService works;
|
||
Lenovo TB330FU (A15, multi-user) — UserService never binds, the `newProcess` fallback carries
|
||
it. Full history in build-status.md.
|
||
- Gradle needs JDK 17–21 (`JAVA_HOME`); a system JDK 25 breaks AGP 8.7. On machines with
|
||
Android Studio, its `jbr` directory works.
|
||
|
||
## Likely next steps
|
||
|
||
1. Run on physical devices; collect JSON reports across Android versions/vendors.
|
||
2. If `trace.errqueue_reachable` is PARTIAL, add the C-over-JNI errqueue shim (recvmsg + cmsg parse)
|
||
as a `:native` module and a real `traceroute.udp4` probe.
|
||
3. Fold the confirmed capabilities + Shizuku dump-format samples back into the production
|
||
`core-probe` / `core-shizuku` modules.
|