T27: parity audit and handover

PARITY-AUDIT.md walks every row of the v2.0.1 feature table with the evidence
behind each claim, keeping verified, implemented-but-unproven, and gap strictly
apart rather than ticking boxes in bulk.

Carried the durable docs forward: ARCHITECTURE.md with what changed and why,
a README covering status and the parity harness, and the v3 backlog with a
header noting the two items whose status changed. The native repo's README now
opens with a pointer here and records both bugs the port found. All internal
doc links verified.

The cutover step is deliberately left undone: the application id stays
com.rippr.port so both apps can be installed together, because the real-ride
checklist depends on recording the same ride on both at once. That comparison is
worth more than finishing tidily. The native repo is marked superseded rather
than archived -- it is still the only version that has recorded a real ride.

Also corrected an arithmetic slip: 175 tests, not 178.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-15 22:26:56 -05:00
parent a3bcd014c0
commit fc6d8f9dba
5 changed files with 662 additions and 12 deletions

107
README.md
View File

@@ -1,17 +1,102 @@
# rippr
# Rippr
GPS ride recorder for motorcycles
A GPS ride recorder for motorcycles, on **Android and iOS**. Records telemetry into a
local SQLite database, renders the traversed path on a map afterwards, and exports to
GPX/GeoJSON.
## Getting Started
Built for one specific use: **hit start, put the phone in a pocket, ride, hit stop.**
Most of the design follows from that.
This project is a starting point for a Flutter application.
This is a Flutter port of the native Android app in `~/dojo/rippr` (v1 → v2.0.1). The port
is feature-complete; see [docs/port/PARITY-AUDIT.md](docs/port/PARITY-AUDIT.md) for
exactly what is verified and what is not.
A few resources to get you started if this is your first Flutter project:
```
Flutter 3.47 · Dart 3.13 Android minSdk 26 · iOS 12+
~4,600 lines Dart 175 tests (171 unit/widget, 4 integration)
```
- [Learn Flutter](https://docs.flutter.dev/get-started/learn-flutter)
- [Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Flutter learning resources](https://docs.flutter.dev/reference/learning-resources)
## Status
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
| Feature | Status |
|---|---|
| GPS recording, foreground on Android / background mode on iOS | Implemented; **not yet ridden** |
| Trips with pause / resume / stop / discard | Working, 50 tests |
| Live speed + elapsed clock | Working |
| Path on OpenStreetMap, per-segment, speed-coloured | Working; colouring unverifiable without a real ride |
| Ride statistics + charts | Working; bit-identical to the Kotlin original |
| Rename / delete / merge rides | Working |
| GPX + GeoJSON export | Working; byte-identical to the Kotlin original |
| Upload to a REST endpoint | Implemented, **no UI** (as in the native app) |
| Notification actions (Pause/Resume in the shade) | **Absent** — the one capability lost |
| Live map while recording · group ride | Deferred to v3 |
> **The port has never recorded a real ride.** No simulator produces velocity, so max
> speed, moving time, speed colouring, elevation against real GPS error, battery, and iOS
> stationary suspension are all unverified. That is
> [docs/port/REAL-RIDE-CHECKLIST.md](docs/port/REAL-RIDE-CHECKLIST.md), and it is the next
> thing that should happen.
## Quick start
Requires **JDK 17–21** for Android (AGP rejects 25) and Xcode for iOS.
```bash
flutter pub get
dart run build_runner build # Drift codegen
flutter analyze && flutter test
flutter test integration_test -d <device-id>
flutter run
```
**Watch the disk.** A full dual-platform build cycle costs roughly 10 GB, and the Android
emulator needs 7.4 GB free just to boot. Run `flutter clean` before booting it.
## Cross-language parity
The strongest guarantee in this repo. It compiles the **real Kotlin sources** from the
native app and diffs them against the Dart port across twenty fixtures:
```bash
brew install kotlin
JAVA_HOME=<jdk-21> ./tool/parity/run.sh
```
Everything matches to the last digit — including the elevation accumulator at
`38.959594555022136` and byte-identical GPX/GeoJSON. The single expected difference is
speed-derived values, where Kotlin's 32-bit `Float` widens with artefacts Dart's uniform
`double` does not reproduce.
## Documentation
| Document | Contents |
|---|---|
| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Why it is built this way, and what changed from the native app |
| [docs/port/PLAN.md](docs/port/PLAN.md) | The 28-task migration plan |
| [docs/port/PROGRESS.md](docs/port/PROGRESS.md) | What actually happened, including every bug found |
| [docs/port/PARITY-AUDIT.md](docs/port/PARITY-AUDIT.md) | Feature-by-feature, with the evidence behind each claim |
| [docs/port/REAL-RIDE-CHECKLIST.md](docs/port/REAL-RIDE-CHECKLIST.md) | **The outstanding work** |
| [docs/port/RELEASE-IOS.md](docs/port/RELEASE-IOS.md) | App Review readiness |
| [docs/PORT_RESEARCH.md](docs/PORT_RESEARCH.md) | The original research this plan was built on |
The native repo's `docs/v1/`, `docs/v2/` and `docs/v3/BACKLOG.md` remain the record of how
the app got here and where it is going.
## Two bugs this port found in the native app
**Crash recovery measured the dead time as distance.** `restoreAfterProcessDeath` says it
resumes into a new segment; it actually adopts the segment a crash left open, so the
authoritative recomputation measures straight through the gap. Reproduced at **111 km** of
phantom distance. Fixed here.
**The elevation regression guard passes on seed luck.** On a shared fixture the algorithm
yields ~39 m, which would fail the native test's own 35 m bound. It passes only because
`kotlin.random.Random(42)` happens to draw a benign sequence.
## Before shipping
- Switch the application id from `com.rippr.port` back to `com.rippr`. The suffix exists
so the native app can be installed alongside during the port — **keep it until the real
ride comparison is done**.
- Replace the default Flutter app icon; the native artwork is in `~/dojo/rippr/design/`.
- Build and test a release build. Everything so far has been debug.