# TASK-019: Recover OAuth callback without an app crash Status: implemented; automated verification complete; device login pending Owner: Codex Reviewer: Claude ## Outcome OAuth approval returns safely to UBGitea. A rejected or malformed callback, corrupt pending transaction, and stale saved route produce a recoverable screen instead of terminating the process or creating a launch-crash loop. ## Writable paths - `app/src/main/java/com/ubisam/ubgitea/core/auth/protocol/OAuthClientConfig.kt` - `app/src/main/java/com/ubisam/ubgitea/feature/repositories/` - `app/src/main/java/com/ubisam/ubgitea/ui/navigation/RouteStackSaver.kt` - matching unit tests - TASK-018/019, ADR-004, and development-log incident evidence ## Acceptance criteria - [x] Production defaults request only the previously device-verified read-only scopes. - [x] A callback-processing exception maps to a recoverable invalid-callback state. - [x] Debug diagnostics contain only stable reason tags and no code, token, verifier, or state. - [x] Malformed/truncated saved routes restore to the repository root without indexing missing fields. - [x] Focused OAuth, repository, and navigation tests pass. - [ ] Physical device login and callback pass with the rebuilt APK. ## Evidence - Incident reproduction: after TASK-018 added `write:user`, Gitea returned `error=server_error`; after app data was cleared, callback approval was followed by process termination and stale-state relaunch failure. - The default scope set is restored to the previously verified read-only set. Gitea-native star mutation remains disabled by lack of write scope until a separate server-compatible authorization design is approved and verified. - Callback and route restoration now fail closed into UI state. No production credential or callback value is surfaced. - `assembleDebug testDebugUnitTest lintDebug` passed: 184 tests across 30 suites, zero failures; lint and diff checks passed.