# 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. ### 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.