Three facts the client cannot produce alone, kept deliberately separate:
mtu.pmtud_down (largest datagram that arrives unfragmented — meaningful only
because the server sets DF), mtu.frag_delivery (whether larger ones arrive once
fragmentation is allowed), and train.udp_downstream (loss, reordering and
arrival spacing in the download direction, which a round trip cannot separate
from upstream loss).
ServerMeasurement now runs them on the same ProbeSession as the echo train. It
had to: a fresh session restarts client-side sequence numbers and the server's
anti-replay window discards the lot, so the re-primed source is never recorded
and every granted send goes to a socket that has already closed. That produced
four confidently-wrong FAILED tests and a RED verdict on a healthy network.
Live against fmr: path MTU 1500, fragments to 4000, 100/100 downstream, GREEN.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Code: GPL-3.0-or-later (LICENSE, SPDX headers on all .kt/.aidl).
Specs in docs/: CC-BY-4.0 (docs/LICENSE). Rationale in build-status.md;
server decided GPL (not AGPL).
- Root README for the public repo.
- web/: Cloudflare Worker site for echo-lot.app. /apk resolves the newest
APK from the Gitea latest-release API at request time (edge-cached 5 min),
so tagging a release is the only publish step. /fdroid, /source, and a
manual DOWNLOAD_URL fallback are wrangler vars.
- .gitea/workflows/release.yml: tag-driven (v*) signed semver APK builds for
the future production app in echolot-app/. Parked; the prober is
deliberately not CI-built.
- Fix UserService.kt: drop the explicit secondary constructor that
conflicted with the implicit primary (never compiled before — first
local build caught it). Prober now builds: :app:assembleDebug OK.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>