# Builds on detekt's default ruleset (see app/build.gradle.kts: buildUponDefaultConfig = true). # Only overrides/additions relative to the defaults belong here -- keep this file small so # upgrading detekt pulls in sane new defaults automatically instead of us silently diverging. style: MagicNumber: ignorePropertyDeclaration: true # assigning a literal to a named property IS the fix this # rule asks for -- `private val SPEEDS = listOf(1.0f, 1.25f, ...)` is named data, and # exploding each element into its own constant would make it less readable, not more. ReturnCount: max: 5 # the feed parser is guard-clause heavy on purpose -- an enclosure with no URL, no # type, or a non-playable type each bail out early. Forcing those into nested conditionals # to satisfy a limit of 2 would make the code harder to read, not easier. MaxLineLength: maxLineLength: 140 # several files carry long, deliberate rationale comments (see # ReaderExtractor.kt) -- 120 (detekt's default) wrapped mid-explanation too aggressively. ForbiddenComment: active: false # this codebase deliberately doesn't use TODO/FIXME markers (see CLAUDE.md # "why these checks") -- nothing to forbid. UnusedImports: active: true # off in detekt's defaults, which is how 71 dead imports accumulated across # nine files -- EpisodeActions.kt was eleven lines of data class under forty of them, # Scaffold and SnackbarHost and LazyColumn included, left behind when the screens were # split per file. An import list is the first thing read to work out what a file does, so a # stale one actively misleads. Kotlin only warns, so nothing enforced it. complexity: TooManyFunctions: thresholdInInterfaces: 22 # Room DAOs are broad by nature -- each query is a method, and # splitting one table's access across several interfaces to satisfy a count would make the # data layer harder to follow, not easier. Raised from 20 when EpisodeDao picked up # downloadedFromServer (the skip-refresh filter): one more genuinely distinct query, not # scope creep. Raised again to 22 for waitingForServer, which cannot reuse queuedDownloads: # a bounded retry must go newest first, or episodes the server has aged out of its newest-8 # window would starve the ones it still has. thresholdInClasses: 21 # same for the view model: it is a flat list of one-line user actions # (enqueue, download, mark played), and splitting it by count rather than by meaning would # scatter related behaviour across types for no gain. 21 with downloadFromPublisher, the # explicit choice the episode screen offers a waiting download. naming: FunctionNaming: ignoreAnnotated: ["Composable"] # Jetpack Compose's own naming convention is PascalCase for # composable functions -- that's the correct style here, not a violation.