Skip to content

Latest commit

 

History

History
192 lines (136 loc) · 18.7 KB

File metadata and controls

192 lines (136 loc) · 18.7 KB

Jetpack Compose Audit Report

Target: E:\GitHub\ComposeHooks Date: 2026-06-23 Scope: hooks, ai, app Compose/KMP source sets; Android release compiler diagnostics for hooks and ai. Excluded from scoring: tests, generated/build outputs, and demo-only issues where they do not affect the reusable library surface. Confidence: High Overall Score: 86/100

Scorecard

Category Score Weight Status Notes
Performance 9/10 35% excellent Strong Skipping is on, measured named skippability is 100%, and the remaining mutable/demo lazy lists now use stable keys.
State management 9/10 25% excellent Hooks mostly expose clear holder/state APIs; FormRef now uses private backing maps and explicit operations, app examples use FormItemWithState, and the deprecated legacy FormItem Triple API remains only for compatibility.
Side effects 8/10 20% solid useSse, useStateAsync, Fetch, and AI streaming paths now rethrow cancellation; polling no longer forces Dispatchers.Default.
Composable API quality 8/10 20% solid The audited extracted components now expose/root-apply modifier; a few demo-local private UI helpers remain lighter-weight than a full shared UI kit.

Critical Findings

No unresolved critical findings remain from the prioritized remediation pass. The remaining item is a compatibility cleanup opportunity for the deprecated form API.

Remediation Status

  1. Fixed: cancellation is propagated from SSE and async-state hooks

  2. Fixed: polling no longer overrides the caller/hook dispatcher with Dispatchers.Default

  3. Fixed: audited extracted components now expose/root-apply modifier

  4. Fixed: remaining mutable/demo lazy lists now use stable keys

  5. Fixed: FormRef internal mutation surfaces are now explicit operations

  6. Fixed: app form examples were migrated off the deprecated FormItem overload

Adjacent Findings

Android Launch UX

Category Details

Performance - 9/10

Ceiling check

  • Strong Skipping: on for measured modules (gradle/libs.versions.toml:3 uses Kotlin 2.3.21; module reports show featureFlags.StrongSkipping = true).
  • Ceiling table applied: SSM-on.
  • Module-wide skippable%: ai 4/4 = 100.0%; hooks 51/51 = 100.0%.
  • Named-only skippable%: ai 3/3 = 100.0%; hooks 46/46 = 100.0%.
  • Unstable shared types from compiler: ai 82 inferred unstable classes; hooks 38 inferred unstable classes. Under SSM-on this count is not a cap by itself.
  • SSM-on binding evidence: no widespread source churn in measured hooks / ai composable bodies; previously flagged mutable/demo lazy-list keys have been fixed.
  • Qualitative score: 9/10.
  • Ceiling: none. Remaining demo-level small allocations do not bind the SSM-on ceiling.
  • Applied score: 9/10.

What is working

  • The Android release compiler reports for hooks and ai are clean on named skippability.
  • Previously risky app examples now use stable keys in the chat/agent/table message lists, table rows, immutable-list demo, and selectable demo.
  • useTable now keeps a stable TableInstance and returns stable state wrappers, reducing holder churn in the reusable library surface.

What is hurting the score

  • A few composable bodies still allocate small option lists or perform string aggregation for display. They are sample-level, not systemic.

Animation performance signals

  • Status: clean in audited hotspots. No Animatable-without-remember or composition-phase animated modifier reads were found in the library surface. animateContentSize() usage in cards/messages is ordinary declarative animation.

Evidence

State Management - 9/10

What is working

  • Hook holders consistently expose observable State fields first and operations after them, matching the repository's own hook API standard.
  • useTable and useRequest keep table/request state in holder abstractions rather than scattering ownership through UI examples.
  • AI hooks use immutable message lists (ImmutableList / persistent collections) for chat-like state, which is a strong signal for observable state boundaries.
  • FormRef now keeps its mutable maps as private backing state and exposes named internal operations for registration, validation, errors, touched/dirty state, pending validation, and submit callbacks.
  • The app showcase now uses FormItemWithState in its form examples instead of demonstrating the deprecated Triple overload.

What is hurting the score

  • The legacy FormItem Triple API remains for external compatibility, although it now has a deprecation warning pointing callers to FormItemWithState. Removing it would be a breaking API change and should be handled as a planned migration.

Evidence

Side Effects - 8/10

What is working

  • Fetch, useSse, and useStateAsync now rethrow CancellationException from broad exception paths.
  • AI streaming hooks reviewed here (useAsr, useTts, useChat, AgentLoop) mostly rethrow cancellation before converting errors to UI state.
  • Long-lived async work generally starts from event callbacks or Compose-owned scopes rather than directly from composition bodies.
  • Polling delayed refresh now stays in the selected hook/plugin scope instead of unconditionally switching to Dispatchers.Default.

What is hurting the score

  • Some plugin and callback surfaces still use broad exception isolation by design, so future async additions should keep the CancellationException rethrow rule as a regression guard.

Animation side-effect signals

  • Status: clean. No target-driven Animatable.animateTo() launched directly from composition was found in audited library paths.

Evidence

Composable API Quality - 8/10

What is working

  • Core shared app components such as TButton, SimpleContainer, ExampleCard, LogCard, and ScrollColumn expose modifier: Modifier = Modifier.
  • Several selector/card/message components now pass the modifier to their root node.
  • The hook library intentionally returns non-UI holders from composable hook functions; that is a domain-specific API shape and was not treated as a generic UI-emitting composable violation.

What is hurting the score

  • Some private demo-only UI helpers remain intentionally compact and do not yet follow full shared-component API rigor.

Evidence

Remaining Non-Blocking Follow-Up

  1. Remove the deprecated legacy FormItem overload in a future breaking release after external consumers have had a migration window. References: https://developer.android.com/develop/ui/compose/state, https://android.googlesource.com/platform/frameworks/support/+/androidx-main/compose/docs/compose-component-api-guidelines.md
  2. Keep cancellation propagation as a regression rule for future hooks: any new broad catch (Exception) / catch (Throwable) around suspend work should rethrow CancellationException first. References: https://developer.android.com/kotlin/coroutines/coroutines-best-practices

Notes And Limits

  • COMPOSE-AUDIT-REPORT.md was deleted before this audit and recreated with current findings.
  • Prioritized remediation was applied after the audit: useSse, useStateAsync, polling, audited modifier APIs, mutable/demo lazy-list keys, FormRef internal mutation surfaces, and app FormItemWithState migration were fixed.
  • The Gradle build with the audit init script completed successfully for :hooks:compileReleaseKotlinAndroid, :ai:compileReleaseKotlinAndroid, and :app:compileReleaseKotlinAndroid after the final form refactor.
  • Latest compiler diagnostics: named restartable skippability remains hooks 46/46 and ai 3/3.
  • Post-remediation verification completed successfully: formatKotlin, lintKotlin, :hooks:compileReleaseKotlinAndroid, :app:compileReleaseKotlinAndroid, :hooks:compileTestKotlinDesktop, :hooks:desktopTest --tests xyz.junerver.compose.hooks.test.UseSseTest, and the targeted form tests (UseFormRefTest, UseFormInstanceTest, UseFormSubmitTest, UseFormTouchedDirtyTest, UseFormValidationTriggerTest).
  • A strict source search found no remaining direct assignments/removals through the old FormRef map properties in production or form tests, and no remaining actual FormItem calls under app/src or ai/src.
  • Compiler diagnostics used: yes, but only hooks and ai produced files under build/compose_audit; app was audited from source because no app/build/compose_audit report was generated.
  • Strong Skipping mode: on in measured modules (featureFlags.StrongSkipping = true).
  • Weight choice: default 35/25/20/20.
  • Renormalization: none.
  • Adjacent coverage notes: this is a Compose Multiplatform/KMP repository with commonMain, Android, Desktop, and iOS source sets. Focus/keyboard and UI-test coverage were noted but not scored in this skill.
  • Android Launch UX resources: no splash-screen theme item found; no static splash icon risk was scored or prioritized.

Suggested Follow-Up

  • material-3 audit is optional; this skill did not score visual design or Material 3 token quality.
  • Run compose-agent focus on kmp if platform-boundary quality is the next priority; this repo has significant CMP/KMP surface.
  • Run compose-agent focus on testing if UI test, preview, and screenshot coverage should be assessed beyond the source-level audit.
  • Run compose-agent focus on focus only if Desktop/keyboard behavior becomes a product requirement beyond the current demo coverage.