# T17 — Uploader trip-awareness **Phase** 7 · **Depends on** T02 · **Status** Done ## Goal Include trip and segment identity in the uploaded payload so a future server can reconstruct rides rather than receiving an undifferentiated point stream. Done when the payload carries `trip_id` and `segment_id` and the existing uploader tests still pass. ## Context `TelemetryUploader` works and is well covered — five unit tests using `MockWebServer` and an in-memory fake DAO, all running on the JVM with no device. Its design principle is stated in its own doc comment and must be preserved: > Upload is strictly secondary to recording: every failure path here is swallowed and > retried later, and nothing in this class can stop the location pipeline. Two facts shape this task: 1. **No server consumes this yet.** The endpoint defaults to blank, which disables upload entirely. So the payload shape can change freely — there is no compatibility burden. 2. **There is still no UI for the endpoint.** It is reachable only via `Config.setUploadEndpoint()`. That remains true after this task; adding settings UI is out of scope and belongs with the v3+ group-ride work that would give it a purpose. `Telemetry.encodeBatch(deviceId, points)` builds the JSON and is directly unit-tested by `TelemetryTest.encodes a batch as the documented payload shape`. That test will need updating in step with the format. ## Design Current payload: ```json { "device_id": "…", "points": [ { "id":…, "ts":…, "lat":…, "lon":…, "speed_kmh":…, "alt_m":…, "acc_m":…, "bearing":… } ] } ``` Add `trip_id` and `segment_id` per point: ```json { "device_id": "…", "points": [ { "id":…, "trip_id":…, "segment_id":…, "ts":…, … } ] } ``` **Per point, not per batch.** A batch is drawn by `getUnsyncedPoints(BATCH_SIZE)` ordered by id, which can straddle a segment boundary — and, after a discard-and-restart, even a trip boundary. Hoisting the ids to batch level would silently mislabel points. Keeping them per point costs a few bytes and cannot be wrong. Segment boundaries are what let a server reconstruct pauses, exactly as GPX `` does in T15. ## Implementation 1. Extend `Telemetry.encodeBatch` to emit `trip_id` and `segment_id`. 2. Update the `TelemetryTest` payload-shape test. 3. Confirm `TelemetryUploader` needs no structural change — it passes points through, so the fake DAO in `TelemetryUploaderTest` just needs the new fields. 4. Sanity-check batching still works across a segment boundary. ## Acceptance criteria - [x] Payload includes `trip_id` and `segment_id` per point - [x] A batch spanning two segments labels each point correctly - [x] All five existing `TelemetryUploaderTest` cases still pass - [x] `TelemetryTest` payload assertions updated, not deleted - [x] Blank endpoint still disables upload with zero requests - [x] Upload failure still leaves points unsynced for retry ## Tests JVM unit tests, extending the existing suite: - Payload shape assertion including the new fields - A batch containing points from two segments — assert per-point labelling - Existing disabled/failure/retry cases unchanged ## Risks / gotchas - **Do not restructure the uploader.** It is correct, tested, and deliberately isolated from the recording path. This is an additive payload change. - **The endpoint has no UI** and stays that way here. Worth stating in the release notes so the feature is not mistaken for broken. - **Do not add trip-level upload state.** `synced` is per point and the backlog logic depends on that granularity. ## Out of scope Settings UI for the endpoint; server implementation; group-ride streaming (v3+).