Closer/app
null 18e6cf7b30 fix(auth): GoogleProfileMerger must not be able to kill a successful sign-in
Self-review of the last four commits against the codebase's own error-handling
conventions. Two real defects found, both in GoogleProfileMerger, both mine:

1. Its writes could crash sign-in. The class doc said "best-effort by design",
   but createUser/updateDisplayName/updatePhotoUrl were unwrapped, and merge()
   runs inside the view model's onSuccess block in viewModelScope — a throw
   there is an unhandled coroutine exception, after authentication has already
   succeeded. The words claimed a contract the code didn't deliver. merge() now
   never throws: the seed runs under runCatching and failures are recorded.
   (The pre-rework copies had the same unwrapped createUser, so this is older
   than my refactor — but I rewrote the class and kept the hole, and the doc
   claiming best-effort made it worse than inherited.)

2. It was the only file in domain/ using android.util.Log. The house pattern
   for use cases is an injected CrashReporter (DailyQuestionResolver is the
   model): recordException for failures, log() for breadcrumbs. Swapped over;
   a swallowed failure now actually surfaces in Crashlytics instead of dying
   in logcat on a device we'll never see.

Also aligned: the two Kotlin assert() calls in RecoveryPhraseNormalizationTest
were the only ones in the suite and silently depend on the JVM -ea flag — now
assertNotEquals like everything else; RecoveryScreen's OutlinedButton is
imported rather than fully qualified (the file's lone qualified call was the
anomaly, not the rule).

GoogleProfileMergerTest pins the contract: a failed read writes nothing and is
recorded (C-AUTH-001's conflation), a failed write is recorded not thrown, a
stub is not seeded over, a complete profile is untouched, and only blank fields
are filled. Mutation-checked by removing the runCatching — and that check also
caught a bug in the test itself: the "complete profile" fixture had defaulted
photoUrl to "", so the merger legitimately tried to fill it and the strict
mock's throw was swallowed by the very runCatching under test — a test passing
for the wrong reason. Fixture fixed; the mutation now kills exactly the one
test that asserts the contract.

Hilt graph validated via assembleDebug; full unit suite green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 01:37:16 -05:00
..
schemas
src fix(auth): GoogleProfileMerger must not be able to kill a successful sign-in 2026-07-15 01:37:16 -05:00
build.gradle.kts feat(avatar): frame a picked photo, and fall back to initials not a heart 2026-07-14 23:19:37 -05:00
proguard-rules.pro