# v1 — the original recorder v1 was specified as **MotoTrack**, a "bare-bones, highly resilient" recorder to capture GPS telemetry during motorcycle group rides. Renamed to Rippr partway through. The original brief is preserved verbatim in [original-spec.md](original-spec.md). **Design priority, quoted from the brief:** *"Unbreakable execution over UI beauty."* That framing drove every architectural choice and still holds. ## What shipped A single-screen app with an un-killable foreground service writing GPS fixes to Room, plus a REST uploader. Validated on a real ride — including max speed, which the emulator cannot produce. ## Deviations from the spec, and why The spec was written as complete, paste-ready code. Most of it was sound; these parts were not, and were changed deliberately. | Spec said | What shipped | Why | |---|---|---| | `super.onCreate()` in `MainActivity` | `super.onCreate(savedInstanceState)` | Would not compile | | `kapt` for Room | **KSP** | kapt is 2–3× slower and unreliable on modern Kotlin/JDK | | Hardcoded `material3:1.2.1` beside a Compose BOM | Version catalog + BOM | Version conflict | | `insertPoint()` per fix from the callback | Unbounded `Channel` + batched writer | A coroutine per fix gives no back-pressure guarantee; disk latency could block GPS | | Activity-local `isRecording` | Process-wide state (later, in v2, the database) | Lied after process death | | 1 Hz polling of two suspend DAO queries | Room `Flow` | Push, not poll | | No stop action on the notification | Stop action + tap-to-open | | | Nothing countering Doze / OEM killers | Battery-optimisation exemption prompt | A multi-hour ride must survive | | No `Theme.MotoTrack`, no launcher icon | Generated both | Referenced by the manifest but never defined | | "Streams over HTTP/REST" in the goal, no task for it | Full uploader: `synced` column, batched POST, retry, offline-safe | Stated as a goal, so it was built | ## Verification The emulator harness built here was reused throughout v2: - Merged manifest checked inside the APK — `foregroundServiceType=0x8` (location) confirmed - 25 synthetic GPS fixes fed; final stored coordinate matched the fed value **exactly** - Foreground service confirmed via `dumpsys` (`isForeground=true`, ongoing notification) - Stop path verified: service gone, notification removed, final flush landed, 81 contiguous point ids **Speed was never verified in v1's automated testing** — the emulator reports zero velocity. It was confirmed only on Dylan's first real ride. ## What v1 lacked Feedback after that ride, which became the v2 brief: > "app is simple and clean. I like that but it's missing stuff. There is no reset or pause > button, there is no concept of a trip, it captures speed data but not path data." Three of those four were the same missing concept — no `Trip` boundary. The fourth was a misconception worth recording: **path data was already being captured.** Every point stored latitude, longitude, altitude and bearing at 1–2 Hz from day one. What was missing was a map to draw it on. ## Icon work The launcher icon was designed in this phase. Five motorcycle-themed concepts were generated locally as SVG, using Google Material Symbols (Apache-2.0) as reference geometry; Dylan picked **Route** — a switchback trace inside a ring. Lesson from that round: the first attempt hand-authored bezier paths without ever rendering them, and they were poor. Building a rasterise-and-look loop (`rsvg-convert`) changed the output quality completely. Generators live in `design/`.