engine: downstream MTU and downstream train in the measurement document
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>
This commit is contained in:
co-authored by
Claude Fable 5
parent
ce1aaa332a
commit
14e5fad1b2
@@ -52,6 +52,29 @@ echolot-prober/ the capability prober (self-contained Gradle buil
|
||||
ui/ProberScreen.kt result cards colored by verdict
|
||||
```
|
||||
|
||||
## Client modules (echolot-app/)
|
||||
|
||||
Pure Kotlin/JVM where possible, so the interesting logic is unit-testable without a device and can
|
||||
be exercised against the live server from the PC:
|
||||
|
||||
- `core-protocol` — control plane (pinned TLS) + ELT1 UDP data plane. **One `ProbeSession` per
|
||||
server session, for its whole lifetime**: a second one restarts sequence numbers, the server's
|
||||
anti-replay window discards every packet, and granted sends then target the closed socket.
|
||||
- `core-measurement` — the schema types. `core-engine` — composes probes into documents.
|
||||
- `core-privacy` — the §8 anonymizer (`full` / `balanced` / `strict`). Field classification lives
|
||||
in one table (`Classification.kt`); keep it there rather than annotating models.
|
||||
- `core-archive` — on-device run storage + retention. `enabled` is separate from the three
|
||||
ceilings: all-zeros means "no limits", not "keep nothing".
|
||||
|
||||
**The local archive keeps the unredacted document; anonymization happens per upload, on the way
|
||||
out.** Never redact what is stored locally.
|
||||
|
||||
### Live testing without a device
|
||||
`echolot-app/scripts/test-fmr.sh [gradle-task] [test-filter]` mints an enrollment token over SSH,
|
||||
enrolls, computes the SPKI pin from the served cert and runs a `Live*Test` against fmr. This covers
|
||||
the whole server-facing vertical (granted sends, downstream MTU, uploads) with no phone involved —
|
||||
use it before asking the user to test on hardware.
|
||||
|
||||
## Conventions
|
||||
|
||||
- Every probe returns a `ProbeResult` — never throws to the caller (MainActivity wraps anyway).
|
||||
|
||||
Reference in New Issue
Block a user