Part of #324 (strangler-migrate debug logging to AppLog). Also resolves the logcat PII leak
in Backlog #297.
Sequencing: PARALLEL with the other migration areas, after the Seam ticket merges
(needs the AppLog.w(tag, msg, throwable) overload + accountLogRef(...)). Touches mail/ImapClient, data/sync/SendWorker, push/IdleService — no collision with siblings.
Scope (files)
app/src/main/kotlin/org/libremail/mail/ImapClient.kt — 2 raw Log.d.
app/src/main/kotlin/org/libremail/data/sync/SendWorker.kt — 1 raw Log.w(PII: email).
app/src/main/kotlin/org/libremail/push/IdleService.kt — 2 raw (Log.i, Log.w(PII: email)).
Tests: ImapClientTest, SendWorkerTest (both currently mockkStatic(Log::class) — rewrite
to assert the buffer + no-PII).
Migrate + scrub these call sites
ImapClient.kt (TAG "LibreMailIdle"):
:477Log.d(TAG, "IDLE connected") -> AppLog.d(TAG, "IDLE connected"). No PII. Keep it
account-agnostic — idle() only holds ImapConnectionParams (host/username = PII), which
must not be logged; account attribution belongs to the IdleService caller (below).
:482Log.d(TAG, "IDLE push: ${event.messages.size} new message(s)") -> AppLog.d(TAG, same).
Message count only — safe (never log subjects/senders/content).
SendWorker.kt (TAG "SendWorker"):
:146Log.w(TAG, "Graph send failed for ${account.email}; falling back to SMTP", e) -> PII fix (#297):AppLog.w(TAG, "Graph send failed for ${accountLogRef(account.id)}; falling back to SMTP", e).
The throwable e may embed the email/host in its message -> the Seam StackTraceScrubber
redacts it on buffer-record.
IdleService.kt (TAG "IdleService"):
:94Log.i(TAG, "encrypted cache locked; deferring IDLE push until the app is unlocked") -> AppLog.i(TAG, same). No PII.
:215Log.w(TAG, "IDLE for ${account.email} dropped; retrying in ${backoffMs}ms", e) -> PII fix (#297):AppLog.w(TAG, "IDLE for ${accountLogRef(account.id)} dropped; retrying in ${backoffMs}ms", e).
New breadcrumbs (IMAP connect/IDLE/drop, send attempt/result/fallback)
SendWorker.doWork: on entry with pending work AppLog.i(TAG, "outbox drain: ${pending.size} queued");
per message success AppLog.i(TAG, "sent ${accountLogRef(account.id)} via ${if (Graph) "Graph" else "SMTP"}");
per message failure AppLog.w(TAG, "send failed for ${accountLogRef(account.id)}; will retry")
(NO subject/recipients/body). The Graph->SMTP fallback line above is the fallback breadcrumb.
PII (hard rule)
Never log account.email, host, username, recipients, subject, or body. Account attribution = accountLogRef(account.id) only. Counts/backoff/booleans are safe. This ticket is the one that closes#297's raw-Log.w("…${account.email}…") leak to Logcat.
Test expectation (unit)
Rewrite SendWorkerTest + ImapClientTest to install a real RingLogBuffer via AppLog.install(...) instead of mocking Log. Assert: (a) the fallback / IDLE-drop /
outbox-drain breadcrumbs are captured at the right level; (b) regression for #297 — with a
known test account email, assert no buffer line (and no Log argument) contains that
address. Removing the Log mock also drops import android.util.Log from these tests (needed
by the guard-rule ticket).
Per repo DoD, extend a connectivity/send E2E (e.g. the GreenMail send path) to assert the send
breadcrumb lands PII-free; IdleService per-account attribution is validated via the accountLogRef unit + the SendWorker/ImapClient buffer tests where a JVM Service harness
isn't available.
Parallelism: parallel with auth/lock, DB/keystore, sync-engine, stragglers — after Seam.
Part of #324 (strangler-migrate debug logging to AppLog). **Also resolves the logcat PII leak
in Backlog #297.**
**Sequencing: PARALLEL** with the other migration areas, **after the Seam ticket merges**
(needs the `AppLog.w(tag, msg, throwable)` overload + `accountLogRef(...)`). Touches
`mail/ImapClient`, `data/sync/SendWorker`, `push/IdleService` — no collision with siblings.
## Scope (files)
- `app/src/main/kotlin/org/libremail/mail/ImapClient.kt` — 2 raw `Log.d`.
- `app/src/main/kotlin/org/libremail/data/sync/SendWorker.kt` — 1 raw `Log.w` **(PII: email)**.
- `app/src/main/kotlin/org/libremail/push/IdleService.kt` — 2 raw (`Log.i`, `Log.w` **(PII: email)**).
- Tests: `ImapClientTest`, `SendWorkerTest` (both currently `mockkStatic(Log::class)` — rewrite
to assert the buffer + no-PII).
## Migrate + scrub these call sites
`ImapClient.kt` (TAG "LibreMailIdle"):
- `:477` `Log.d(TAG, "IDLE connected")` -> `AppLog.d(TAG, "IDLE connected")`. No PII. Keep it
account-agnostic — `idle()` only holds `ImapConnectionParams` (host/username = PII), which
must **not** be logged; account attribution belongs to the `IdleService` caller (below).
- `:482` `Log.d(TAG, "IDLE push: ${event.messages.size} new message(s)")` -> `AppLog.d(TAG, same)`.
Message **count** only — safe (never log subjects/senders/content).
`SendWorker.kt` (TAG "SendWorker"):
- `:146` `Log.w(TAG, "Graph send failed for ${account.email}; falling back to SMTP", e)` ->
**PII fix (#297):** `AppLog.w(TAG, "Graph send failed for ${accountLogRef(account.id)}; falling back to SMTP", e)`.
The throwable `e` may embed the email/host in its message -> the Seam `StackTraceScrubber`
redacts it on buffer-record.
`IdleService.kt` (TAG "IdleService"):
- `:94` `Log.i(TAG, "encrypted cache locked; deferring IDLE push until the app is unlocked")` ->
`AppLog.i(TAG, same)`. No PII.
- `:215` `Log.w(TAG, "IDLE for ${account.email} dropped; retrying in ${backoffMs}ms", e)` ->
**PII fix (#297):** `AppLog.w(TAG, "IDLE for ${accountLogRef(account.id)} dropped; retrying in ${backoffMs}ms", e)`.
## New breadcrumbs (IMAP connect/IDLE/drop, send attempt/result/fallback)
- `IdleService.watchAccount` start: `AppLog.i(TAG, "IDLE watch start ${accountLogRef(account.id)}")`.
- `SendWorker.doWork`: on entry with pending work `AppLog.i(TAG, "outbox drain: ${pending.size} queued")`;
per message success `AppLog.i(TAG, "sent ${accountLogRef(account.id)} via ${if (Graph) "Graph" else "SMTP"}")`;
per message failure `AppLog.w(TAG, "send failed for ${accountLogRef(account.id)}; will retry")`
(NO subject/recipients/body). The Graph->SMTP fallback line above is the fallback breadcrumb.
## PII (hard rule)
Never log `account.email`, host, username, recipients, subject, or body. Account attribution =
`accountLogRef(account.id)` only. Counts/backoff/booleans are safe. This ticket is the one that
closes #297's raw-`Log.w("…${account.email}…")` leak to Logcat.
## Test expectation (unit)
- Rewrite `SendWorkerTest` + `ImapClientTest` to install a real `RingLogBuffer` via
`AppLog.install(...)` instead of mocking `Log`. Assert: (a) the fallback / IDLE-drop /
outbox-drain breadcrumbs are captured at the right level; (b) **regression for #297** — with a
known test account email, assert **no** buffer line (and no `Log` argument) contains that
address. Removing the `Log` mock also drops `import android.util.Log` from these tests (needed
by the guard-rule ticket).
- Per repo DoD, extend a connectivity/send E2E (e.g. the GreenMail send path) to assert the send
breadcrumb lands PII-free; `IdleService` per-account attribution is validated via the
`accountLogRef` unit + the `SendWorker`/`ImapClient` buffer tests where a JVM Service harness
isn't available.
**Parallelism:** parallel with auth/lock, DB/keystore, sync-engine, stragglers — after Seam.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Part of #324 (strangler-migrate debug logging to AppLog). Also resolves the logcat PII leak
in Backlog #297.
Sequencing: PARALLEL with the other migration areas, after the Seam ticket merges
(needs the
AppLog.w(tag, msg, throwable)overload +accountLogRef(...)). Touchesmail/ImapClient,data/sync/SendWorker,push/IdleService— no collision with siblings.Scope (files)
app/src/main/kotlin/org/libremail/mail/ImapClient.kt— 2 rawLog.d.app/src/main/kotlin/org/libremail/data/sync/SendWorker.kt— 1 rawLog.w(PII: email).app/src/main/kotlin/org/libremail/push/IdleService.kt— 2 raw (Log.i,Log.w(PII: email)).ImapClientTest,SendWorkerTest(both currentlymockkStatic(Log::class)— rewriteto assert the buffer + no-PII).
Migrate + scrub these call sites
ImapClient.kt(TAG "LibreMailIdle")::477Log.d(TAG, "IDLE connected")->AppLog.d(TAG, "IDLE connected"). No PII. Keep itaccount-agnostic —
idle()only holdsImapConnectionParams(host/username = PII), whichmust not be logged; account attribution belongs to the
IdleServicecaller (below).:482Log.d(TAG, "IDLE push: ${event.messages.size} new message(s)")->AppLog.d(TAG, same).Message count only — safe (never log subjects/senders/content).
SendWorker.kt(TAG "SendWorker")::146Log.w(TAG, "Graph send failed for ${account.email}; falling back to SMTP", e)->PII fix (#297):
AppLog.w(TAG, "Graph send failed for ${accountLogRef(account.id)}; falling back to SMTP", e).The throwable
emay embed the email/host in its message -> the SeamStackTraceScrubberredacts it on buffer-record.
IdleService.kt(TAG "IdleService")::94Log.i(TAG, "encrypted cache locked; deferring IDLE push until the app is unlocked")->AppLog.i(TAG, same). No PII.:215Log.w(TAG, "IDLE for ${account.email} dropped; retrying in ${backoffMs}ms", e)->PII fix (#297):
AppLog.w(TAG, "IDLE for ${accountLogRef(account.id)} dropped; retrying in ${backoffMs}ms", e).New breadcrumbs (IMAP connect/IDLE/drop, send attempt/result/fallback)
IdleService.watchAccountstart:AppLog.i(TAG, "IDLE watch start ${accountLogRef(account.id)}").SendWorker.doWork: on entry with pending workAppLog.i(TAG, "outbox drain: ${pending.size} queued");per message success
AppLog.i(TAG, "sent ${accountLogRef(account.id)} via ${if (Graph) "Graph" else "SMTP"}");per message failure
AppLog.w(TAG, "send failed for ${accountLogRef(account.id)}; will retry")(NO subject/recipients/body). The Graph->SMTP fallback line above is the fallback breadcrumb.
PII (hard rule)
Never log
account.email, host, username, recipients, subject, or body. Account attribution =accountLogRef(account.id)only. Counts/backoff/booleans are safe. This ticket is the one thatcloses #297's raw-
Log.w("…${account.email}…")leak to Logcat.Test expectation (unit)
SendWorkerTest+ImapClientTestto install a realRingLogBufferviaAppLog.install(...)instead of mockingLog. Assert: (a) the fallback / IDLE-drop /outbox-drain breadcrumbs are captured at the right level; (b) regression for #297 — with a
known test account email, assert no buffer line (and no
Logargument) contains thataddress. Removing the
Logmock also dropsimport android.util.Logfrom these tests (neededby the guard-rule ticket).
breadcrumb lands PII-free;
IdleServiceper-account attribution is validated via theaccountLogRefunit + theSendWorker/ImapClientbuffer tests where a JVM Service harnessisn't available.
Parallelism: parallel with auth/lock, DB/keystore, sync-engine, stragglers — after Seam.