# Per-rule overrides layered on top of detekt's defaults # (`--build-upon-default-config` on the CLI invocation in the Android lane). # # The pre-2.0 `build:` top-level was removed; failure is controlled by the CLI's # exit code instead. naming: # Composables conventionally use PascalCase function names. Matches every # mainstream Compose codebase, and mirrors the ktlint exemption in # android/.editorconfig — the two tools have to agree or one of them is always # wrong. FunctionNaming: ignoreAnnotated: - "Composable" style: MagicNumber: ignoreAnnotated: - "Composable" # Colour literals and dp constants are declared as named properties, which is # exactly the "define it as a well-named constant" the rule asks for — the # number simply appears in the declaration itself. Flagging # `private val Brand = Color(0xFFF5C518)` would demand a constant holding the # constant. ignorePropertyDeclaration: true complexity: # Compose breaks the PREMISE of both rules below, not just their thresholds. # # * LongParameterList assumes a long list means an over-general function. A # composable's parameters ARE its UI contract — Material's own TextField # takes twenty — and collapsing them into a parameter object makes the call # site worse, not better, because named arguments are what keep a Compose # tree readable. # * LongMethod assumes length tracks branching. A composable's length tracks # how many ELEMENTS are on the screen; a full-screen editor with a title, a # body, a checklist, labels and a reminder row is long because it renders # five things, and cutting it into five one-call wrappers would add # indirection without removing a single decision. # # Scoped to @Composable rather than disabled: on ordinary functions both rules # are right, and one of them still fires below (see BoardViewModel). LongParameterList: ignoreAnnotated: - "Composable" LongMethod: ignoreAnnotated: - "Composable" exceptions: TooGenericExceptionCaught: # Catching broadly is DELIBERATE in these two places, and each site says so. # # * the ViewModel — a note that fails to save must become a visible error # banner, never a crash. Narrowing this would mean an unanticipated # failure takes the app down instead of being reported, which is strictly # worse for the user. # * the Application — the store failing to open is the one thing that must # still let the app start, so it can explain itself. # * the background Worker — it runs with nobody present, so an escaping # exception is a crash report for a job the person never asked for. Every # realistic failure there (no route, server down, token rotating) has the # same right answer, which is Result.retry(). # * the reminder BroadcastReceiver — same argument, one step worse: it can be # woken at 3am by an alarm or by BOOT_COMPLETED, and every path inside it # has already logged its own failure by the time this catches anything. # # Scoped to those paths rather than disabled globally: elsewhere the rule is # right and still applies. excludes: - "**/ui/**" - "**/ThoughtSyncApplication.kt" - "**/SyncWorker.kt" - "**/ReminderReceiver.kt"