Part of #324 (strangler-migrate debug logging to AppLog).
Sequencing: LAST — BLOCKED on ALL migration areas. This enables the strangler seam: a
detekt rule that fails the build on any android.util.Log import outside the AppLog facade.
It can only be turned on after the Seam + auth/lock + DB/keystore + connectivity/send +
sync-engine + stragglers tickets have all merged — enabling it earlier fails CI's Static
analysis gate. Do not start until those are green on main.
Scope (files)
config/detekt/detekt.yml — add the ForbiddenImport rule.
Any residual import android.util.Log in app/src/test cleared by the area tickets
(verify none remain except the two facade tests, below).
Change
Add to config/detekt/detekt.yml (merged onto defaults; buildUponDefaultConfig = true):
style:ForbiddenImport:active:trueimports:- value:'android.util.Log'reason:>- Log via org.libremail.reporting.AppLog so lines reach the debug-report RingLogBuffer;
raw android.util.Log bypasses it (epic #324).excludes:- '**/reporting/AppLog.kt'- '**/reporting/AppLogTest.kt'- '**/reporting/AppLogUninstalledTest.kt'
Notes / gotchas
detekt 2.0.0-alpha.5 (dev.detekt plugin). ForbiddenImport is in the style ruleset;
confirm the ruleset id against this alpha's catalog and adjust the YAML section if it moved.
It is import-based, so it needs no type resolution (our code never fully-qualifies android.util.Log).
excludes must cover the facade AND its two tests.AppLog.kt legitimately imports Log (it is the one allowed wrapper). AppLogTest and AppLogUninstalledTest mockkStatic(Log::class) to verify the facade forwards to Logcat, so they import Log too.
Precondition to verify before enabling: every OTHER test that imports Log today
(AppLockViewModelTest, ImapClientTest, AccountSetupViewModelTest, SendWorkerTest) must
have dropped that import during its area migration (they switch from mocking Log to
asserting the RingLogBuffer). Run Grep 'import android.util.Log' app/src and confirm only AppLog.kt + the two facade tests remain; otherwise :app:detekt (which covers test +
androidTest source sets) fails.
Optional hardening: add a ForbiddenMethodCall on android.util.Log.* to also catch
fully-qualified calls — but that requires the detekt type-resolution task, and no current code
fully-qualifies, so ForbiddenImport alone is sufficient.
Test / verification
The gate itself is the test: ./gradlew :app:detekt passes with the rule active (all areas
migrated). Optionally add a raw Log.d to a throwaway file to confirm detekt fails, then
revert. No product-runtime surface, so no E2E is applicable to this ticket specifically —
the migration areas carry the behavioral tests.
Parallelism: NONE — strictly last, after every migration area merges.
Part of #324 (strangler-migrate debug logging to AppLog).
**Sequencing: LAST — BLOCKED on ALL migration areas.** This enables the strangler seam: a
detekt rule that fails the build on any `android.util.Log` import outside the `AppLog` facade.
It can only be turned on **after** the Seam + auth/lock + DB/keystore + connectivity/send +
sync-engine + stragglers tickets have all merged — enabling it earlier fails CI's Static
analysis gate. Do not start until those are green on `main`.
## Scope (files)
- `config/detekt/detekt.yml` — add the `ForbiddenImport` rule.
- Any residual `import android.util.Log` in `app/src/test` cleared by the area tickets
(verify none remain except the two facade tests, below).
## Change
Add to `config/detekt/detekt.yml` (merged onto defaults; `buildUponDefaultConfig = true`):
```yaml
style:
ForbiddenImport:
active: true
imports:
- value: 'android.util.Log'
reason: >-
Log via org.libremail.reporting.AppLog so lines reach the debug-report RingLogBuffer;
raw android.util.Log bypasses it (epic #324).
excludes:
- '**/reporting/AppLog.kt'
- '**/reporting/AppLogTest.kt'
- '**/reporting/AppLogUninstalledTest.kt'
```
## Notes / gotchas
- **detekt 2.0.0-alpha.5** (`dev.detekt` plugin). `ForbiddenImport` is in the `style` ruleset;
confirm the ruleset id against this alpha's catalog and adjust the YAML section if it moved.
It is import-based, so it needs **no type resolution** (our code never fully-qualifies
`android.util.Log`).
- **`excludes` must cover the facade AND its two tests.** `AppLog.kt` legitimately imports
`Log` (it is the one allowed wrapper). `AppLogTest` and `AppLogUninstalledTest`
`mockkStatic(Log::class)` to verify the facade forwards to Logcat, so they import `Log` too.
- **Precondition to verify before enabling:** every OTHER test that imports `Log` today
(`AppLockViewModelTest`, `ImapClientTest`, `AccountSetupViewModelTest`, `SendWorkerTest`) must
have dropped that import during its area migration (they switch from mocking `Log` to
asserting the `RingLogBuffer`). Run `Grep 'import android.util.Log' app/src` and confirm only
`AppLog.kt` + the two facade tests remain; otherwise `:app:detekt` (which covers test +
androidTest source sets) fails.
- Optional hardening: add a `ForbiddenMethodCall` on `android.util.Log.*` to also catch
fully-qualified calls — but that requires the detekt type-resolution task, and no current code
fully-qualifies, so `ForbiddenImport` alone is sufficient.
## Test / verification
- The gate itself is the test: `./gradlew :app:detekt` passes with the rule active (all areas
migrated). Optionally add a raw `Log.d` to a throwaway file to confirm detekt fails, then
revert. No product-runtime surface, so no E2E is applicable to this ticket specifically —
the migration areas carry the behavioral tests.
**Parallelism:** NONE — strictly last, after every migration area merges.
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).
Sequencing: LAST — BLOCKED on ALL migration areas. This enables the strangler seam: a
detekt rule that fails the build on any
android.util.Logimport outside theAppLogfacade.It can only be turned on after the Seam + auth/lock + DB/keystore + connectivity/send +
sync-engine + stragglers tickets have all merged — enabling it earlier fails CI's Static
analysis gate. Do not start until those are green on
main.Scope (files)
config/detekt/detekt.yml— add theForbiddenImportrule.import android.util.Loginapp/src/testcleared by the area tickets(verify none remain except the two facade tests, below).
Change
Add to
config/detekt/detekt.yml(merged onto defaults;buildUponDefaultConfig = true):Notes / gotchas
dev.detektplugin).ForbiddenImportis in thestyleruleset;confirm the ruleset id against this alpha's catalog and adjust the YAML section if it moved.
It is import-based, so it needs no type resolution (our code never fully-qualifies
android.util.Log).excludesmust cover the facade AND its two tests.AppLog.ktlegitimately importsLog(it is the one allowed wrapper).AppLogTestandAppLogUninstalledTestmockkStatic(Log::class)to verify the facade forwards to Logcat, so they importLogtoo.Logtoday(
AppLockViewModelTest,ImapClientTest,AccountSetupViewModelTest,SendWorkerTest) musthave dropped that import during its area migration (they switch from mocking
Logtoasserting the
RingLogBuffer). RunGrep 'import android.util.Log' app/srcand confirm onlyAppLog.kt+ the two facade tests remain; otherwise:app:detekt(which covers test +androidTest source sets) fails.
ForbiddenMethodCallonandroid.util.Log.*to also catchfully-qualified calls — but that requires the detekt type-resolution task, and no current code
fully-qualifies, so
ForbiddenImportalone is sufficient.Test / verification
./gradlew :app:detektpasses with the rule active (all areasmigrated). Optionally add a raw
Log.dto a throwaway file to confirm detekt fails, thenrevert. No product-runtime surface, so no E2E is applicable to this ticket specifically —
the migration areas carry the behavioral tests.
Parallelism: NONE — strictly last, after every migration area merges.