Files
rippr/docs/port/PROGRESS.md
Dylan f0f9ed8c34 Verify builds on both platforms; pin Android SDK levels
compileSdk 37 (a dependency requires it; the build fails on 36), minSdk 26 for
parity with the native app, targetSdk 36. AGP auto-installed platform 37, CMake
and a 2.8GB NDK during the build since licences were already accepted.

Both artifacts confirmed: Runner.app and app-debug.apk.

Recorded two deprecation warnings against flutter_foreground_task, the plugin
chosen for Android background liveness in T12: no Swift Package Manager support
on iOS, and it applies KGP on Android. Both are future hard errors, so the
LocationSource seam in T10 matters more than assumed.

Also recorded the disk episode: the plan braced for SDK installs, but builds
were what filled the disk (22 GiB to 3.9 GiB). Recovered to 11 GiB.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 20:28:12 -05:00

160 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Port progress log
Running record of what actually happened, task by task — including what went wrong.
The v2 equivalent of this file caught real bugs by making risks explicit before they
were walked into, so the practice carries over.
Plan: [PLAN.md](PLAN.md) · Source of truth for *why*: the native repo's
`docs/ARCHITECTURE.md`, `docs/TESTING.md`, `docs/v2/PROGRESS.md`.
---
## T00 — Disk space + toolchain · **complete**
**Outcome:** `flutter doctor` reports no issues in any category. Flutter 3.47.0 (Dart
3.13.0), Xcode 26.0.1, CocoaPods 1.17.0, Android SDK 36.0.0, iOS 26.0.1 simulator runtime.
### The disk panic was largely a false alarm — but measure twice
Planning measured **16 GiB free at 92%**, which drove a whole cleanup strategy. A second
measurement minutes later, before deleting anything, showed **36 GiB free at 81%**. Most
likely APFS local snapshots aging out.
**Nothing was deleted.** Gradle caches, AVDs, and `~/.cargo` were all left intact.
Post-install the machine sits at ~22 GiB free.
**Lesson:** re-measure immediately before acting on a disk-space number. Had the plan been
followed literally, ~9 GB of still-useful caches would have been destroyed for no reason.
### Things that actually needed fixing
| Problem | Fix |
|---|---|
| `cmdline-tools component is missing` | `sdkmanager --sdk_root=$ANDROID_HOME "cmdline-tools;latest"` — the exact trap already documented in the native repo's `DEVELOPMENT.md`: brew's `sdkmanager` resolves its own SDK root and does not see `~/Library/Android/sdk` unless `--sdk_root` is passed explicitly |
| Android licenses unaccepted | `yes \| sdkmanager --sdk_root=$ANDROID_HOME --licenses` |
| Default JDK is 25, which AGP rejects | `flutter config --jdk-dir=<temurin-21>` — same constraint as the native build, now pinned in Flutter's config rather than relying on an exported `JAVA_HOME` |
| No iOS simulator runtime installed | `xcodebuild -downloadPlatform iOS` (8.05 GB). Note simulator *devices* already existed for a runtime that did not — `simctl list devices` looked populated while `list runtimes` was empty |
| CocoaPods absent, system Ruby 2.6.10 | `brew install cocoapods`, deliberately not `gem install` |
---
## T01 — Repo scaffold · **complete**
`~/dojo/rippr-flutter`, `flutter create --org com.rippr --project-name rippr`.
### Two deliberate deviations from the generated defaults
**Bundle id is `com.rippr.port`, not `com.rippr`.** `--org com.rippr` + name `rippr`
produces `com.rippr.rippr`, which is wrong either way. The choice of `com.rippr.port` is
deliberate and temporary: the plan requires the native app to stay installable as a
reference and fallback, and **two apps cannot share an applicationId**. Keeping them
distinct means both can sit on the same phone — which also enables the strongest possible
validation in T25: record the same ride on both simultaneously and compare the numbers.
> **T27 must switch this to `com.rippr`** at cutover. Recorded here because it is exactly
> the kind of temporary decision that silently becomes permanent.
The Android `namespace` stays `com.rippr` and the Kotlin source was moved from
`kotlin/com/rippr/rippr/` to `kotlin/com/rippr/` to match.
### Builds verified on both platforms
`✓ build/ios/iphonesimulator/Runner.app` and `✓ build/app/outputs/flutter-apk/app-debug.apk`.
Android needed three changes to the generated `build.gradle.kts`:
```kotlin
compileSdk = 37 // a dependency demands it; the build fails outright on 36
minSdk = 26 // parity with the native app (Android 8.0)
targetSdk = 36
```
`sdkmanager` cannot fetch `platforms;android-37` from the stable channel — it reports
"Failed to find package". **AGP installed it automatically** during the build (as
`android-37.0`), along with CMake 3.22.1 and a 2.8 GB NDK, because the licences had
already been accepted. Convenient, but see the disk note below.
### ⚠ `flutter_foreground_task` is on two deprecation paths
Both warnings name the same package — the one chosen for Android background liveness in
T12:
- **iOS:** does not support Swift Package Manager. *"This will become an error in a future
version of Flutter."*
- **Android:** applies the Kotlin Gradle Plugin. *"Future versions of Flutter will fail to
build if your app uses plugins that apply KGP."*
Neither breaks today's build. Both should be re-checked at T12, and they strengthen the
case for the `LocationSource` seam in T10 — the background layer needs to stay swappable.
### The disk problem was real, just not where the plan predicted
The plan braced for SDK *installs* filling the disk. The actual consumption was **builds**:
free space fell from 22 GiB to **3.9 GiB** during the first Android build — Gradle caches
grew 3.7 → 8.0 GB, the NDK added 2.8 GB, and `build/` alone reached 2.7 GB.
Recovery, in order of how safe each step was:
| Action | Reclaimed |
|---|---|
| Delete `build/` + `flutter clean` + the native app's `app/build` | ~3.8 GiB |
| Prune Gradle caches for versions **no project uses** (9.5.0, 9.7.0), `build-cache-1`, and the native project's 8.11.1 distribution | ~3 GiB |
Ended at **11 GiB free (94% used)**. `modules-2` (1.9 GB) was deliberately **kept** —
deleting it forces a re-download of every dependency, which is a real time cost for space
we do not currently need. Only two Gradle versions are actually in use: 9.3.1 (this
project) and 8.11.1 (the native app, whose distribution cache re-downloads on demand).
**Standing risk for T24:** the Android emulator needs a fixed 7.4 GiB free to boot. At 11
GiB that works, but one more full build cycle could eat the margin. Run `flutter clean`
before booting the emulator.
### Dependencies
`flutter_riverpod` · `go_router` · `drift` + `drift_flutter` · `path_provider` ·
`geolocator` · `flutter_foreground_task` · `permission_handler` · `flutter_map` +
`latlong2` · `share_plus` · `shared_preferences` · `http` · `synchronized`.
Dev: `drift_dev`, `build_runner`, `mocktail`, `integration_test`.
**`sqlite3_flutter_libs` resolves to an `+eol`-tagged release (0.6.0+eol).** It was added
explicitly at first, then removed — `drift_flutter` depends on it transitively regardless,
so the pin belongs to drift, not to us. Worth watching when drift next majors, but not
actionable now.
---
## T02 — Geo utilities · **complete**
`lib/src/geo/geo.dart` + `test/geo_test.dart`. **23/23 passing.**
Ported structurally faithfully from `com.rippr.geo.Geo`: haversine (with the
`asin(sqrt(a))` conditioning note), iterative Douglas–Peucker with an explicit stack,
equirectangular perpendicular distance with clamped projection, null-on-empty bounds,
path length. Every test case and tolerance carried over unchanged, including the
Calgary–Edmonton 280.9 km figure that was corrected during v2 after the *test* proved
wrong rather than the code.
**Deliberate API divergence:** Kotlin's `object Geo` namespace became top-level functions,
which is idiomatic Dart. `LatLon` is our own type rather than `latlong2`'s `LatLng` — the
pure layer must not depend on the map package; conversion happens at the render boundary.
### Two things went wrong
**`library;` after the import.** Dart requires the library directive before all other
directives. Caught immediately by the compiler — noted only because a file-level doc
comment is otherwise easy to attach wrongly.
**A hang that was not a hang.** `flutter test` and `flutter build ios` were run
concurrently and both sat at 0% CPU for minutes. The suspicion was Rosetta, because
`flutter_tester` lives under `artifacts/engine/darwin-x64/` — **that was wrong**: the
binary there is arm64 and the directory name is legacy. The real cause was
`ibtool`/`actool` spawning `IBAgent-iOS` and `AssetCatalogSimulatorAgent`, which deadlock
against a booted simulator. Run alone with simulators shut down, the same suite finishes
in under a second.
Two lessons, both echoing v2's harness troubles:
- **Do not run an iOS build against a booted simulator** if anything else needs it.
- **A killed background job still reports exit code 0.** Both jobs "completed
successfully" *because they were killed*. Never read a success code from a process you
terminated — re-run it cleanly.