Skip to content

Fix the triaged detekt baseline violations - #70

Merged
AhmadKharfan merged 5 commits into
developfrom
refactor/baseline-triage-fixes
Jul 29, 2026
Merged

Fix the triaged detekt baseline violations#70
AhmadKharfan merged 5 commits into
developfrom
refactor/baseline-triage-fixes

Conversation

@AhmadKharfan

Copy link
Copy Markdown
Owner

Why

All 357 baseline entries were reviewed individually and sorted into fix / keep / adjust-the-rule. This PR contains only the fix group — 50 entries where the rule was right and the code was genuinely worse for the violation.

Nothing here is a mechanical edit to satisfy detekt. Every change stands on its own.

What changed

Stale callbacks in restartable effects (14) — the most valuable group. Lambda parameters were captured inside LaunchedEffect/DisposableEffect, so when the lambda changed the running effect kept calling the old one. Each now goes through rememberUpdatedState. This is a correctness fix, not style: an out-of-date onCreated or onProjectSelected silently navigates using a stale closure.

GitHub OAuth field names (6)GitHubDeviceFlowAuthenticator had snake_case @Serializable fields plus six hand-written accessor properties existing purely to expose camelCase names:

val device_code: String? = null
...
val deviceCode get() = device_code

Two names for every field. Replaced with @SerialName("device_code") val deviceCode, deleting all six accessors. Every @SerialName string was checked character-by-character against the old property name — Json is configured with ignoreUnknownKeys = true, so a typo would fail silently as a null field rather than throwing.

Idiomatic error handling (11)throw IllegalStateException(...)error(...), if (!x) throw ...check(x) { } / require(x) { }. Only where the transformation is exact; sites carrying a cause or rethrowing inside a catch were left alone.

Swallowed exceptions (2)KeystoreException now preserves its underlying cause instead of discarding it.

Composable parameter order (3)modifier moved to first-optional position. GitDiffRoute turned out to be a different violation than expected: a required onBack after an optional commitId. Its caller was converted to named arguments.

Hygiene (14) — 7 missing trailing newlines, a wildcard import, an explicit it lambda parameter, an unused parameter, an empty else block.

An extra improvement found during review

EditorRoute hit exactly 60 lines after the rememberUpdatedState additions. Rather than shave a line, I looked at what was in it: a 12-line hand-rolled DisposableEffect + LifecycleEventObserverduplicated almost verbatim in GitPanelScreen.

Both are replaced with the official LifecycleEventEffect from lifecycle-runtime-compose:

LifecycleEventEffect(Lifecycle.Event.ON_RESUME) { viewModel.onAppForegrounded() }
LifecycleEventEffect(Lifecycle.Event.ON_STOP) { viewModel.flushPendingSaves() }

That removes ~20 lines and a duplicated concept. No new dependency — both files already import collectAsStateWithLifecycle from the same artifact.

Behavior

Three deliberate behaviour changes, all fixes:

  1. Effects now invoke current callbacks rather than stale captured ones.
  2. KeystoreException preserves its cause.
  3. Public composable parameter order changed for three components; all callers audited and updated.

Everything else is behaviour-preserving. The OAuth JSON wire format is unchanged.

Deliberately NOT fixed

Reviewed and kept baselined, with reasons:

  • TooGenericExceptionCaught (18) — all boundary code (JGit, ApkInstaller, ArtifactDownloader, RemoteBuildSystem). Catching broadly at an I/O boundary and mapping to a domain error is correct design.
  • ComplexCondition (17) and LoopWithTooManyJumpStatements (13) — all parsers, lexers and the terminal emulator. Multi-clause conditions and multi-exit loops are inherent to tokenizers.
  • ParameterNaming (20) — compose-rules wants present tense (onFontSizeChange, not onFontSizeChanged). That is churn across composable + interaction listener + ViewModel for convention alone, and several (onCloned, onCreated, onConflictPathOpened) describe genuinely completed events where past tense is correct.
  • ThrowsCount (5 remaining) — boundary code with several distinct failure modes.
  • MultipleEmitters (4), ModifierMissing (5) — changing these alters layout structure or adds parameters to route composables that fill the screen.
  • Two EmptyFunctionBlock sites are required no-op interface overrides in tests; WelcomeBulletPreview is used by preview tooling.

MatchingDeclarationName (36) is handled separately as a rule-configuration change.

Tests

No new tests. These are corrections to existing behaviour with no new logic; the full existing suite passes.

Verification

  • ./gradlew testall modules pass.
  • ./gradlew :app:compileDebugKotlin — passes.
  • ./gradlew detekt — passes.
  • All @SerialName values verified against the original snake_case names.

Baseline

Every module's baseline regenerated — 50 removed, 0 added, project total 357 → 307.

Two removals were side effects rather than direct targets, and both were checked:

  • ForbiddenImport:HubSectionHeader.kt — a stale entry for a file deleted in Share the section header composable #56.
  • ThrowsCount:downloadWithChecksum — converting its five explicit throws to check()/error() genuinely reduced the throw count.

@AhmadKharfan
AhmadKharfan merged commit 0d1158d into develop Jul 29, 2026
2 checks passed
@AhmadKharfan
AhmadKharfan deleted the refactor/baseline-triage-fixes branch July 29, 2026 17:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant