Repository navigation
fix(import): rethrow cancellation in Android CSV import - #1355
Conversation
CancellationException extends Exception, so the Android CSV importer treated a cancelled import as a failed row and kept writing. Rethrow it from both catches and from the analytics import caller. Co-authored-by: Devil <9thLevelSoftware@users.noreply.github.com>
| importResult = result | ||
| showImportResultDialog = true | ||
| } catch (e: Exception) { | ||
| e.rethrowIfCancellation() |
There was a problem hiding this comment.
WARNING: This rethrow never fires on iOS - CsvImporter.ios.kt still swallows the cancellation
AnalyticsScreen lives in phoneMain, so it is the caller on both platforms, but the iOS importer keeps the two catch (e: Exception) blocks this PR is fixing on Android:
shared/src/iosMain/kotlin/com/devil/phoenixproject/util/CsvImporter.ios.kt:72records the cancelled row as aFailed to save session (...)error and keeps writing the remaining rows.shared/src/iosMain/kotlin/com/devil/phoenixproject/util/CsvImporter.ios.kt:93turns a cancelled read into aCsvImportResultwhose only error isImport failed: ....
Because the iOS importer returns a result instead of throwing, this line never sees a CancellationException on iOS, so a cancelled iOS import still opens the import-failed dialog. Add e.rethrowIfCancellation() to both iOS catches (identical to CsvImporter.android.kt:73 and :95) so the two platforms behave the same.
| 2026-03-12,09:00:00,Row,OldSchool,8,0,8,8,40.0,0,30,No,100 | ||
| """.trimIndent().byteInputStream() | ||
|
|
||
| private class ThrowingStream(private val error: Exception) : InputStream() { |
There was a problem hiding this comment.
SUGGESTION: ThrowingStream is a verbatim copy of the one in UriContentReaderCancellationTest.kt:132
Both are the same 4-line private helper. Move it to shared/src/androidHostTest/kotlin/com/devil/phoenixproject/testutil/ (which already holds the Android-only test helpers) and use it from both tests. Optional cleanup - the duplication is harmless.
| repository.saveSessionAttempts.map { it.exerciseName.orEmpty() } | ||
|
|
||
| private fun historyCsv(): InputStream = """ | ||
| Date,Time,Exercise,Mode,Target Reps,Warmup Reps,Working Reps,Total Reps,Weight,Progression,Duration (s),Just Lift,Eccentric Load |
There was a problem hiding this comment.
SUGGESTION: The history header is hardcoded although PhoenixCsvCodec.HISTORY_HEADER already exists
PhoenixCsvCodec is in the same package, so the fixture can use ${PhoenixCsvCodec.HISTORY_HEADER} instead of the duplicated literal and stay in step with the codec. Optional - the literal currently matches.
Code Review SummaryStatus: 3 Issues Found | Recommendation: Address before merge Overview
Issue Details (click to expand)WARNING
SUGGESTION
Files Reviewed (3 files)
VerdictComment only - the Android cancellation fix is correct and the new Robolectric test covers it; the open items are an iOS parity gap and two optional test nits. Correctness / Safety Findingsimportant: No other correctness or safety findings. The Android change itself is sound:
Ponytail Review
Ponytail net: -4 lines. Suggested Minimal PatchOne file, two lines:
Optional, not required: move No other files need to change. Final Merge GuidanceCan merge; the Android fix is correct and the new tests cover the changed behavior. This PR was already merged at 2026-10-28T16:02:07Z, so the iOS parity gap (2 lines) should land as a follow-up. The Ponytail items are optional cleanup. Fix these issues in Kilo Cloud Reviewed by minimax-m3 · Input: 98K · Output: 33.3K · Cached: 1.5M Review guidance: REVIEW.md from base branch |
Summary
Android CSV import catches
Exception, andCancellationExceptionis anException. On current main (622e6033; the audit was against525e5bc7) a cancelled import kept going:saveSessionwas stored asFailed to save session (...): ...and later rows were still written.Import failed: ...instead of stopping.AndroidCsvImporternow rethrows cancellation from both catches withrethrowIfCancellation(), so no further rows are written. The analytics caller rethrows it too, so leaving the screen does not show an import-failed message. A real read or save failure still returnsCsvImportResultas before.AnalyticsScreen.ktis also in open PR #1326, which only passespolarBleManagerinto the workout tab. This change is limited to the CSV import catch. It does not touch the Polar files or drafts #1347, #1348, and #1353.Test
./gradlew -Pskip.supabase.check=true :shared:testAndroidHostTest --tests 'com.devil.phoenixproject.util.AndroidCsvImporterCancellationTest'Before the fix the two cancellation tests returned a result (
imported=2withFailed to save session (Squat): import scope cancelled, andImport failed: left screen). After the fix those tests throwCancellationExceptionand do not write later rows.Full host suite after the fix:
./gradlew -Pskip.supabase.check=true :shared:testAndroidHostTest518 suites, 5346 tests, 0 failures, 0 errors, 0 skipped.
BUILD SUCCESSFUL.