Skip to content

Fix the real bugs hiding in the detekt baseline#11

Merged
Azyrn merged 2 commits into
mainfrom
fix/baselined-exception-bugs
Jul 13, 2026
Merged

Fix the real bugs hiding in the detekt baseline#11
Azyrn merged 2 commits into
mainfrom
fix/baselined-exception-bugs

Conversation

@Azyrn

@Azyrn Azyrn commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary

PR #10 baselined 258 detekt findings to get the Quality Gate green. Buried in the exception-handling findings were three genuine bugs — one of which destroys user data. This PR fixes them plus the surrounding swallowed-exception findings, and shrinks the baseline accordingly (207 → 191, deletions only).

1. History data-loss chain (severe)

HistoryManager.saveHistory() did a non-atomic truncate-then-write; a process kill mid-write left scan_history.json unparseable, getHistory() swallowed the error and returned emptyList(), and the next saveItem() wrote that empty list back — permanently destroying all stored scans. Now:

  • writes are atomic (tmp file + rename)
  • unreadable history is preserved as scan_history.corrupt.json instead of overwritten
  • the JSON codec is extracted into pure parseHistoryJson/historyToJson seams with JVM regression tests (truncated JSON → null, [] → empty list, 50-item round-trip)

2. Silent API-key loss

KeyCipher.decrypt() returned null on any exception. When Android invalidates the Keystore key (e.g. lock-screen change), saved BYOK keys silently became "not configured". Catches are narrowed, and the failure class (never the payload) is logged, with KeyPermanentlyInvalidatedException called out explicitly.

3. Broken coroutine cancellation

AiScanViewModel and OcrViewModel caught Exception around coroutine bodies, swallowing CancellationException. Both now rethrow it first, per the existing KeyVerifier/ProviderExecutor idiom.

Hygiene (behaviour unchanged)

ActionExecutor (9 sites narrowed + logged alongside existing toasts), ScanExporter gallery-save rollback logged, PdfHelper narrowed, ProviderClient chains the SerializationException cause into TransientAiException, plus smaller cleanups in RetryUtils, OpenLibraryEngine, KeyVerifier, ProviderExecutor.

Out of scope (stay baselined): complexity and MagicNumber findings.

Verification

  • ./gradlew testDebugUnitTest green, including the new HistoryManagerJsonTest
  • ./gradlew lint green
  • detekt 1.23.8 CLI (same invocation as CI) exits 0 with the regenerated baseline; injected printStackTrace + magic-number probe still fails with exit 2
  • End-to-end on device (SM-S731B): seeded a 2-item history, truncated it mid-array, relaunched — History shows empty, bytes preserved as scan_history.corrupt.json; a subsequent real gallery-image OCR scan wrote a fresh scan_history.json without touching the corrupt file

🤖 Generated with Claude Code

Azyrn and others added 2 commits July 13, 2026 10:35
A process kill during the non-atomic writeText() left the file
truncated; getHistory() swallowed the parse error and returned an
empty list, which the next saveItem() persisted — destroying every
stored scan. Now writes go through a tmp-file rename, unparseable
history is preserved as scan_history.corrupt.json instead of being
overwritten, and the JSON codec is extracted into pure functions
with regression tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- KeyCipher: narrow decrypt() catch and log the failure class (never
  the payload); call out KeyPermanentlyInvalidatedException so silent
  BYOK key loss after a lock-screen change is at least diagnosable
- AiScanViewModel/OcrViewModel: rethrow CancellationException before
  the generic catch and log history persistence failures
- ActionExecutor: narrow the nine intent-launch catches to
  ActivityNotFoundException/SecurityException/IllegalArgumentException
  and log alongside the existing toasts; parseEventMillis catches
  ParseException
- ProviderClient: chain the SerializationException into
  TransientAiException; rethrow cancellation as a catch clause
- ScanExporter/PdfHelper: log why a gallery save rolled back / narrow
  the PDF-viewer catch
- RetryUtils/OpenLibraryEngine/KeyVerifier/ProviderExecutor: smaller
  hygiene fixes

Regenerated detekt-baseline.xml: 207 -> 191 entries, deletions only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
scanly Ready Ready Preview, Comment Jul 13, 2026 9:36am

@Azyrn Azyrn merged commit 3ea5810 into main Jul 13, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant