Files
rippr/docs/port/REAL-RIDE-CHECKLIST.md
Dylan a3bcd014c0 T22/T24/T26: uploader, integration tests, and release readiness
T22 -- TelemetryUploader on package:http with MockClient standing in for
MockWebServer, tested against a real in-memory Drift database rather than a fake
DAO. Upload runs on its own timer, injected as a callback so the engine has no
opinion about HTTP and tests need no network. Config on shared_preferences with
a hand-rolled UUID v4. Still no UI for the endpoint, exactly as in the native
app. 7 tests.

T24 -- integration_test/app_test.dart, 4 tests passing on the iOS simulator.
These cover what widget tests cannot: Drift opening against real platform
storage, plugin registration, go_router driving a real Navigator, cold start.

T26 -- RELEASE-IOS.md. Usage strings are specific rather than generic, which is
the leading Guideline 5.1.1 rejection cause; privacy-label answers decided; a
pre-submission list covering the bundle-id switch back to com.rippr, the still
default app icon, a release build, and a demo video for review notes.

T25 written up as REAL-RIDE-CHECKLIST.md but outstanding by nature. Two items
decide real things: force-stopping mid-ride on Android confirms the 111 km
crash-gap bug is fixed, and parking 15 minutes mid-recording on iOS decides
whether geolocator is sufficient or the paid engine is needed.

Two prefer_initializing_formals lints suppressed with a reason: Dart forbids a
named parameter beginning with an underscore, so the suggested fix will not
compile.

178 tests passing, analyze clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 22:20:39 -05:00

4.5 KiB

T25 — the real-ride checklist

This is the only task in the plan that cannot be automated, and it is the one that matters most. 171 unit and widget tests plus 4 integration tests are green, and none of them prove the app records a ride correctly.

Adapted from the native repo's docs/TESTING.md, extended for two platforms.


Why a green suite proves nothing here

Neither simulator produces velocity. adb emu geo fix teleports the device and iOS's simulated locations are no better, so every recorded speedKmh is 0.0. That makes the following structurally unverifiable without riding:

  • max speed, average moving speed
  • moving time (everything sits under the 1.5 km/h noise floor, so it stays 00:00:00)
  • speed colouring on the map — the whole path renders in one colour
  • elevation gain against real, correlated GPS altitude error
  • battery over a multi-hour ride
  • whether iOS suspends a stationary app mid-ride

And the subtler trap, which cost v2.0 a release: when a value cannot change under test, the UI around it cannot be judged either. Max speed as the headline looked perfectly fine on an emulator where every number was zero. On a real ride it read as a frozen, broken screen.


Before you ride

Install both apps. They have different application ids on purpose (com.rippr and com.rippr.port), so they coexist:

flutter build apk --debug && flutter install         # Flutter port
adb install -r ~/dojo/samplez/rippr-2.0.1-debug.apk  # native reference

Run both simultaneously on the Android ride. Recording the same ride twice gives a direct numeric comparison, which is far stronger evidence than either app alone.


The ride

Do this once on Android and once on iOS. Pocket the phone — that is the founding use case.

# Check Why it is here
1 Start, pocket, ride ~20 min, stop The actual usage pattern
2 Max speed plausible against the speedometer Unverifiable on any simulator
3 Distance plausible against the odometer Guards the cross-batch anchor
4 Moving time excludes stops Noise floor behaviour on real data
5 Elevation gain near zero on flat ground The most likely silent bug; synthetic noise is uniform, real error is correlated
6 Pause at a stop, resume — no straight line across the gap The segment guarantee
7 Speed colouring visibly varies along the path Cannot render in more than one colour on a simulator
8 A short ride (under 100 m) still shows streets The v2.0 zoom bug
9 GPX opens correctly in Google Earth or Strava Schema-valid is not the same as accepted
10 Battery drain over a multi-hour ride Never measured, on either app
11 Pause/resume survives a screen-off stretch Android wake lock, iOS background mode

Android only

# Check
A1 The ongoing notification appears and persists with the screen off
A2 Force-stop the app mid-ride, relaunch — the ride resumes into a new segment, and the dead time is not added to distance
A3 Compare totals against the native app recording the same ride

A2 is the fix for a real bug found in the native app. See T11 in PROGRESS.md: the native version measures straight through the dead time, which a synthetic test showed adding 111 km. Confirm the port does not.

iOS only — the genuine unknown

# Check
I1 The blue background-location indicator appears while recording
I2 Lock the screen for 10 minutes of riding — fixes keep arriving
I3 Park for 15 minutes without stopping the recording, then ride again. Does recording resume?
I4 Take a phone call mid-ride; recording survives
I5 Swipe the app away mid-ride — what happens? Document it, whatever it is

I3 is the decisive test for the whole platform strategy. If iOS suspends the app when stationary and does not reliably resume, geolocator is not sufficient and the LocationSource seam exists precisely so flutter_background_geolocation (~$500/yr) can be swapped in as one new implementation. Do not make that call without this data.


Recording the results

Append findings to PROGRESS.md under a T25 heading, including the numbers from both apps where Android was recorded twice. If elevation gain on flat ground is implausible, do not tune it blind — the native backlog says so explicitly, and the port's parity harness (tool/parity/run.sh) means any change can be checked against the Kotlin implementation first.