feat(reporting): opt-in debug reporting client (capture + review/submit) #42

Merged
JMR-dev merged 3 commits from feat-debug-reporting into main 2026-07-01 15:28:45 +00:00
3 Commits
Author SHA1 Message Date
JMR-devandClaude Opus 4.8 291c9a2b4d Merge branch 'main' into feat-debug-reporting
Resolve conflicts from #40/#41/#44:
- build.gradle.kts: keep DEBUG_REPORT_ENDPOINT field + val, take #40's
  outlookRedirectScheme (gmailRedirectScheme was deleted).
- LibreMailApp.kt: function takes BOTH appViewModel (start-dest gating, #44)
  and startupViewModel (crash dialog, #42); use renamed AccountPickerScreen.
- SettingsScreen.kt: keep both the Diagnostics (#42) and Backup (#41) sections.
Verified locally: assembleDebug + testDebugUnitTest + lintDebug + ktlintCheck + detekt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 10:18:28 -05:00
JMR-devandClaude Opus 4.8 3ea166607c test(reporting): compile instrumented SettingsScreen test with onReportProblem
The #32/#33 change added a required onReportProblem parameter to SettingsScreen
but left the existing instrumented SettingsScreenTest calling the old signature,
so :app:compileDebugAndroidTestKotlin failed in every E2E job (the local fast
gate never compiles the androidTest variant). Pass onReportProblem = {} in the
test. Verified with :app:compileDebugAndroidTestKotlin on JDK 21.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 08:41:01 -05:00
JMR-devandClaude Opus 4.8 d1b0593a8c feat(reporting): opt-in debug reporting client (capture + review/submit)
Implements #32 and #33: a strictly opt-in, F-Droid-safe debug reporting
client. Nothing ever leaves the device unless the user taps Submit.

#32 capture:
- CrashReporter installs a Thread.setDefaultUncaughtExceptionHandler (wired in
  LibreMailApplication) that persists a structured crash record (stack trace +
  app/version/device metadata + recent log ring buffer) locally, then delegates
  to the previous handler. Never auto-sent.
- RingLogBuffer + AppLog: a bounded in-memory, non-PII log ring buffer.
- DiagnosticsCollector assembles a minimal bundle: app version, Android/device,
  a fixed non-PII settings allow-list, and the log buffer.
- ReportStore persists pending reports as JSON files (not Room, so crash-time
  saves are robust and independent of the encrypted/migrating DB).
- "Report a problem" entry point in Settings creates a report on demand.

#33 review & submit:
- ReportReviewScreen shows the full payload verbatim (exactly what would be
  sent), a free-text comment field, and a prominent PII disclaimer, with
  explicit Submit / Discard and Copy / Save-to-file alternatives.
- Submission is user-initiated only: ReportUploadWorker (WorkManager, queue +
  retry, success/failure surfaced) POSTs to BuildConfig.DEBUG_REPORT_ENDPOINT,
  which is EMPTY by default (ingest server #34 is out of scope for this repo).
- On next launch a saved crash report is offered for review via a dialog.

Tests: 23 JVM unit tests covering crash capture + persistence (offered next
launch), diagnostic-bundle assembly (minimal, non-PII), JSON round-trip, and
the "nothing sent without Submit" invariant.

Closes #32
Closes #33

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 00:03:13 -05:00