# Bug Tracker > Vibe Reader - Known issues, challenges, and their resolution status > Last Updated: 2026-08-26 --- ## Format Each bug follows this structure: - **ID:** Unique identifier (BUG-XXX) - **Status:** `Open` | `In Progress` | `Resolved` | `Won't Fix` - **Severity:** `Critical` | `High` | `Medium` | `Low` - **Description:** What is happening - **Steps to Reproduce:** How to trigger the issue - **Root Cause:** Technical explanation (if known) - **Resolution:** How it was fixed (if resolved) --- ## Open Issues ### BUG-012: Local Data Wiped Between Dev Builds **Status:** In Progress (fix applied 2026-08-26; verification pending) **Severity:** High **Reported:** 2026-08-26 **Related:** [[Project - Vibe Reader/Build & Iterate/Technical Decisions#TDR-014|Technical Decisions > TDR-014]], [[Project - Vibe Reader/Build & Iterate/Technical Decisions#TDR-001|Technical Decisions > TDR-001]], [[Project - Vibe Reader/Build & Iterate/Technical Decisions#TDR-011|Technical Decisions > TDR-011]] #### Description Surfaced through routine daily use and the push to expand the tester population: the library - books, sessions, captures - gets wiped when a new build lands on the device. Rapid iteration is the point of the current phase, but every reinstall that costs a tester their data costs us their trust and their next session. Silent data loss was the ultimate vibe killer inside the app (BUG-R010); this is the same failure one level up, in the delivery loop. #### Root Cause Two independent causes, both self-inflicted opt-outs from Android's default (data *survives* normal reinstalls): 1. `fallbackToDestructiveMigration()` in `AppDatabase` - any schema version bump nukes the database. 2. Signing mismatch between install paths - local Android Studio builds and CI builds are signed with different debug keystores, so installing one over the other fails the signature check and forces an uninstall, which wipes app data. #### Resolution Per [[Project - Vibe Reader/Build & Iterate/Technical Decisions#TDR-014|Technical Decisions > TDR-014]], applied 2026-08-26: 1. `AppDatabase`: `exportSchema = true`, `fallbackToDestructiveMigration()` removed. Future schema changes = version bump + AutoMigration (or hand-written Migration). Next local build regenerates `schemas/1.json` - commit it. 2. CI workflow: new "Restore shared debug keystore" step signs CI APKs with the local `debug.keystore` (via `DEBUG_KEYSTORE_B64` secret; warns loudly if unset). **Remaining to close:** add the `DEBUG_KEYSTORE_B64` repo secret; run the verification protocol - build N → capture data → build N+1 → data intact, from both install paths. --- ## Resolved Issues ### BUG-R010: Captures With No Active Session Vanished Silently **Status:** Resolved **Severity:** High **Reported:** 2026-08-01 **Resolved:** 2026-08-01 **Related:** Product Log 2026-08-01 #### Description Triggering a capture with no active session dropped the word or quote with no feedback. The capture appeared to succeed from the user's side, then simply did not exist. Silent data loss is the ultimate vibe killer. #### Resolution Captures with no active session now surface a toast explaining why nothing was saved. Shipped in the same hardening pass (commit `bbdefef`): `startForegroundService` for session start (API 26+ correctness) and Quick Settings tile updates moved to the main thread. --- ### BUG-R011: CRLF Phantom Diffs (29 Files of "Lost Work") **Status:** Resolved **Severity:** Medium **Reported:** 2026-08-01 **Resolved:** 2026-08-01 **Related:** [[Project - Vibe Reader/Build & Iterate/Technical Decisions#TDR-011|Technical Decisions > TDR-011]], Product Log 2026-08-01 #### Description On re-entry after the six-month gap, 29 files showed as uncommitted changes that looked like lost or diverged work. Every diff was line-ending noise (CRLF vs LF) - a classic Windows git gotcha that cost real archaeology time and a scare. #### Root Cause No line-ending normalization policy in the repo; Windows checkouts rewrote endings. #### Resolution Added `.gitattributes` + autocrlf configuration and renormalized the index. This class of problem cannot recur. --- ### BUG-R007: No Feedback on "Tap to Look Up" for Converted Words **Status:** Resolved **Severity:** High **Reported:** 2026-01-18 **Resolved:** 2026-02-07 **Related:** [[Project - Vibe Reader/Build & Iterate/User Feedback#Session-002|User Feedback > Session-002]] #### Description When a Quote is converted to a Word (via swipe-right), the definition is set to "Converted from quote - tap to look up". However, tapping on the word in Session Detail did nothing. #### Resolution Implemented tap-to-relookup functionality: 1. Added `updateWord()` DAO method 2. Added `relookupWord()` function in `SessionViewModel` (Dictionary API → Wikipedia fallback) 3. Made undefined words tappable in `SwipeableWordItem` 4. Added "Tap to look up" hint text below undefined definitions 5. Once looked up successfully, word updates and is no longer tappable --- ### BUG-R008: Lock Screen Media Controls Inconsistent **Status:** Resolved (Approach Changed) **Severity:** Critical **Reported:** 2026-01-18 **Resolved:** 2026-02-07 **Related:** [[Project - Vibe Reader/Build & Iterate/Technical Decisions#TDR-002|Technical Decisions > TDR-002]] #### Description The MediaSession "Trojan Horse" approach was unreliable due to Android platform restrictions: - Notification shade would not collapse - Cold-start failures due to background activity launch restrictions #### Resolution **Abandoned MediaSession approach entirely.** Replaced with: 1. **Quick Settings Tile** (`QuickCaptureTileService`) as primary capture trigger 2. **Simplified foreground notification** with action buttons 3. Removed all `MediaSessionCompat` code from `ReadingSessionService` 4. Changed foreground service type from `mediaPlayback` to `specialUse` This approach: - Uses stable, system-supported APIs - Works reliably from lock screen - Simplifies codebase for future iOS port - Trades one extra tap for 100% reliability --- ### BUG-R009: Play Button Shows Pause After Tap **Status:** Resolved (No Longer Applicable) **Severity:** Medium **Reported:** 2026-01-18 **Resolved:** 2026-02-07 **Related:** [[#BUG-R008]] #### Description After tapping play button, the icon changed to pause and stayed that way. #### Resolution No longer applicable. MediaSession approach was removed entirely. The Quick Settings tile does not have this issue. --- ### BUG-R006: Book Detail View Crashes App **Status:** Resolved **Severity:** Critical **Resolved:** 2026-01-24 **Device:** Pixel 10 Pro, Android 13 **Related:** [[Project - Vibe Reader/Build & Iterate/Feature Backlog#Book Layer View|Feature Backlog > Book Layer View]] #### Description Tapping a Book card in the Library view to open Book Detail crashed the application. Only the first book's sessions would load; others caused crashes. #### Root Cause In `ReviewScreen.kt`, the `LaunchedEffect` was collecting `Flow` emissions inside a `forEach` loop. The first `collect` call blocks indefinitely, preventing subsequent books from having their sessions loaded. ```kotlin // BROKEN: collect blocks, only first book works LaunchedEffect(books) { books.forEach { bookWithMetrics -> viewModel.database.vibeReaderDao() .getRecentSessionsForBook(bookWithMetrics.book.bookId, 5) .collect { sessions -> ... } // Blocks here! } } ``` #### Resolution Wrapped each Flow collection in its own `launch {}` coroutine to run in parallel: ```kotlin // FIXED: Each book gets its own coroutine LaunchedEffect(books) { books.forEach { bookWithMetrics -> launch { viewModel.database.vibeReaderDao() .getRecentSessionsForBook(bookWithMetrics.book.bookId, 5) .collect { sessions -> ... } } } } ``` Added import: `import kotlinx.coroutines.launch` --- ### BUG-R004: Capture Activity Does not Re-launch After Close **Status:** Resolved **Severity:** Critical **Resolved:** 2026-01-18 **Related:** [[Project - Vibe Reader/Build & Iterate/User Feedback#Session-002|User Feedback > Session-002]] #### Description After closing or dismissing the `SpeechCaptureActivity` (via Cancel, error state, or system back), subsequent attempts to trigger capture from the lock screen or notification did not restart listening. #### Root Cause The activity was launched with `FLAG_ACTIVITY_SINGLE_TOP`, which reuses existing instances. When the activity was already in the back stack but not destroyed, Android called `onNewIntent()` instead of `onCreate()`. Without an `onNewIntent()` handler, `startListening()` was never re-invoked. Additionally, stale `SpeechRecognizer` state from the previous session was not being cleaned up when the activity went to background. #### Resolution 1. Added `onNewIntent()` override that resets capture mode and calls `startListening()` 2. Added `onStop()` override that calls `speechRecognizer.stopListening()` and `speechRecognizer.cancel()` ```kotlin override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) setIntent(intent) captureMode = /* parse from intent */ startListening() } override fun onStop() { super.onStop() speechRecognizer.stopListening() speechRecognizer.cancel() } ``` --- ### BUG-R005: Quote-to-Word Conversion Crashes **Status:** Resolved **Severity:** High **Resolved:** 2026-01-18 **Related:** [[Project - Vibe Reader/Build & Iterate/User Feedback#Session-002|User Feedback > Session-002]] #### Description Swiping right on a Quote to convert it to a Word occasionally caused a silent crash. No error shown to user; conversion simply did not happen. #### Root Cause Unhandled exception during database operations. The conversion required both inserting a new Word and deleting the Quote, but if either operation failed, the entire transaction would fail silently. #### Resolution Wrapped conversion operations in try-catch blocks with error logging: ```kotlin fun convertQuoteToWord(quote: Quote) { viewModelScope.launch { try { dao.insertWord(Word(...)) dao.deleteQuote(quote) } catch (e: Exception) { Log.e("SessionViewModel", "Failed to convert quote to word", e) } } } ``` --- ### BUG-R001: Notification Buttons Invisible on Android 12+ **Status:** Resolved **Severity:** Critical **Resolved:** 2025-11-12 **Related:** Product Log 2025-11-12 #### Description Notification action buttons ("Define", "Quote", "End") were not visible on devices running Android 12+. #### Root Cause Android 12+ requires notification actions to have valid icon resources. Actions without icons are silently hidden by the OS. #### Resolution Added explicit icon resources to all notification actions: ```kotlin .addAction(android.R.drawable.ic_menu_search, "Define", definePendingIntent) .addAction(android.R.drawable.ic_input_add, "Quote", quotePendingIntent) ``` --- ### BUG-R002: Button Tap "Glows" But Nothing Happens **Status:** Resolved **Severity:** High **Resolved:** 2025-11-12 **Related:** Product Log 2025-11-12 #### Description Notification buttons showed visual feedback (glow animation) when tapped, but capture overlay did not appear. #### Root Cause Race condition: The UI was starting the Service and writing to the database simultaneously. The Service would wake up, query for active session, find nothing (DB write not yet committed), and exit. #### Resolution Passed `session_id` directly to the Service via Intent extra, removing dependency on database query timing. --- ### BUG-R003: Gradle/KSP Version Mismatch with Hilt **Status:** Resolved (by removing Hilt) **Severity:** High **Resolved:** 2026-01-10 **Related:** [[Project - Vibe Reader/Build & Iterate/Technical Decisions#TDR-004|Technical Decisions > TDR-004]] #### Description Build failures with error: `ksp ... is too old for kotlin...` #### Root Cause Hilt's KSP processor version was incompatible with the project's Kotlin version. The Hilt → KSP → Kotlin version matrix is fragile. #### Resolution Removed Hilt entirely; switched to Manual DI / Singleton pattern. Build stability restored immediately. --- ## Issue Template ```markdown ### BUG-XXX: [Title] **Status:** Open **Severity:** [Critical/High/Medium/Low] **Reported:** YYYY-MM-DD **Device:** [Device + Android version] **Related:** [[Link to related docs]] #### Description [What's happening] #### Steps to Reproduce 1. Step one 2. Step two 3. **Expected:** [What should happen] 4. **Actual:** [What actually happens] #### Root Cause [Technical explanation if known] #### Resolution [How it was fixed, or workaround] ``` --- ## Bug Metrics | Status | Count | |--------|-------| | Open | 0 | | In Progress | 1 | | Resolved | 11 | | Will not Fix | 0 | | Severity | Open | Resolved | |----------|------|----------| | Critical | 0 | 4 | | High | 1 | 5 | | Medium | 0 | 2 | | Low | 0 | 0 |