# 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=` — 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.