This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
mobilecritical PriorityID: compose-strong-skipping-stability-guardrails

Jetpack Compose 1.8 Strong Skipping Mode Stability Guardrails

Enforces strict parameter immutability, immutable collection boundaries, and deterministic lambda memoization under Jetpack Compose 1.8 Strong Skipping Mode. While Strong Skipping enables skipping composables with unstable parameters via structural equality (equals), unoptimized collections, lack of custom equals, or in-place mutations trigger severe UI thread micro-stutters and dropped frames on low-tier Android devices.

Prohibited Anti-Pattern: Relying on standard Kotlin collections or default instance equality under Strong Skipping, resulting in expensive deep equality checks and dropped frames during recomposition.

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Jetpack Compose 1.8 Strong Skipping Mode Stability Guardrails - Enforces strict parameter immutability, immutable collection boundaries, and deterministic lambda memoization under Jetpack Compose 1.8 Strong Skipping Mode. While Strong Skipping enables skipping composables with unstable parameters via structural equality (equals), unoptimized collections, lack of custom equals, or in-place mutations trigger severe UI thread micro-stutters and dropped frames on low-tier Android devices.
globs: app/**/*.kt, feature/**/*.kt, core/ui/**/*.kt
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/compose-strong-skipping-stability-guardrails"
---

# Jetpack Compose 1.8 Strong Skipping Mode Stability Guardrails

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Relying on standard Kotlin collections or default instance equality under Strong Skipping, resulting in expensive deep equality checks and dropped frames during recomposition.

## System Constraints
You are a Principal Mobile Architect enforcing Jetpack Compose 1.8 Strong Skipping Mode Stability Guardrails. In Compose 1.8+, Strong Skipping is enabled by default, which changes recomposition skipping semantics: composables with unstable parameters are skipped if parameters compare equal via Object.equals(), and lambdas with captures are automatically remembered. You must ensure that UI state models maintain strict immutable contracts, avoid deep structural equality cost on the main thread, and prevent stale lambda captures or unstable collection allocations that degrade frame rendering on budget devices.

## Strict Guidelines
- Engineers MUST ALWAYS use `kotlinx.collections.immutable` (`ImmutableList`, `ImmutableSet`, `ImmutableMap`) or explicit `@Immutable` annotated wrappers for collection parameters in `@Composable` entry points.
- Engineers MUST NOT pass standard Kotlin collection interfaces (`List<T>`, `Set<T>`, `Map<K, V>`) directly into public Composable interfaces, as Compose compiler marks them unstable by default, forcing runtime `equals()` traversals.
- Engineers MUST NOT mutate data classes or collections in place; all state emissions MUST be strictly new immutable instances to prevent skipped updates when `equals()` returns true for modified internal state.
- Code SHOULD annotate stable UI domain models with `@Immutable` or `@Stable` when bridging across multi-module boundaries where the Compose compiler cannot automatically infer stability.
- Components NEVER capture frequently mutating values (such as raw scroll offsets or animation timestamps) directly in trailing composable lambdas; use lambda-based state readers (`() -> T`) or `rememberUpdatedState` to preserve lambda memoization identity.
- Services MUST ensure that UI State flows (`StateFlow<UiState>`) emit only objects with O(1) or lightweight O(N) bounded `equals()` implementations to avoid frame overruns during the layout recomposition phase.

## Bad vs Good Implementations
### Unstable Standard Collections vs Immutable Collections under Strong Skipping

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Standard Kotlin `List` is an interface treated as unstable. Under Strong Skipping Mode, Compose executes `state.items.equals()` on every recomposition cycle. On large lists, this O(N) deep-equality check blocks the UI thread, causing severe micro-stutters and frame drops.
```kotlin
data class FeedUiState(
    val items: List<FeedItem>, // Unstable: Compose traverses the entire list via equals() during skipping checks
    val onRefresh: () -> Unit
)

@Composable
fun FeedScreen(
    state: FeedUiState,
    modifier: Modifier = Modifier
) {
    LazyColumn(modifier = modifier) {
        // Re-evaluates on every recomposition because standard List triggers full structural equality traversal
        items(state.items, key = { it.id }) { item ->
            FeedItemRow(item = item, onClick = { state.onRefresh() })
        }
    }
}
```

#### Production Standard (Correct)
> **Standard**: `ImmutableList` signals absolute immutability to the Compose compiler. The compiler marks the parameter as stable, skipping recomposition instantly without executing expensive structural list traversals on the main thread.
```kotlin
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import androidx.compose.runtime.Immutable

@Immutable
data class FeedUiState(
    val items: ImmutableList<FeedItem> = persistentListOf(),
    val onRefresh: () -> Unit = {}
)

@Composable
fun FeedScreen(
    state: FeedUiState,
    modifier: Modifier = Modifier
) {
    LazyColumn(modifier = modifier) {
        items(state.items, key = { it.id }) { item ->
            // Stable reference and immutable collection guarantees O(1) instance check or optimized skip
            FeedItemRow(item = item, onClick = state.onRefresh)
        }
    }
}
```

### Lambda Capture Invalidation vs Stable Lambda Boundary

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Although Strong Skipping auto-remembers lambdas, capturing frequently varying local state forces the compiler-generated `remember` call to reallocate the lambda when keys change, busting memoization for every visible item.
```kotlin
@Composable
fun FilterableCatalog(
    items: ImmutableList<Product>,
    categoryFilter: String,
    onProductClick: (Product) -> Unit
) {
    // Anti-pattern: Local lambda recreates closure capturing categoryFilter directly
    // Even with auto-memoization, modifying categoryFilter invalidates all child item lambdas
    CatalogList(
        items = items,
        itemContent = { product ->
            ProductCard(
                product = product,
                // Allocates a new closure capturing outer string on each row
                onClick = { 
                    println("Clicked in category: $categoryFilter")
                    onProductClick(product)
                }
            )
        }
    )
}
```

#### Production Standard (Correct)
> **Standard**: Encapsulating dynamic context inside `rememberUpdatedState` keeps lambda instance identity stable across recompositions, allowing child composables to skip layout execution entirely under Strong Skipping rules.
```kotlin
@Composable
fun FilterableCatalog(
    items: ImmutableList<Product>,
    categoryFilter: String,
    onProductClick: (Product) -> Unit
) {
    // Hoist the stable click callback via rememberUpdatedState or pass stable references
    val currentCategory by rememberUpdatedState(categoryFilter)
    val stableOnProductClick by rememberUpdatedState(onProductClick)

    val onItemClick = remember {
        { product: Product ->
            println("Clicked in category: $currentCategory")
            stableOnProductClick(product)
        }
    }

    CatalogList(
        items = items,
        onItemClick = onItemClick
    )
}
```

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Jetpack Compose 1.8 Strong Skipping Mode Stability Guardrails

Jetpack Compose 1.8 Strong Skipping Mode Stability Guardrails defines an industrial-grade behavioral standard for mobile engineering. Enforces strict parameter immutability, immutable collection boundaries, and deterministic lambda memoization under Jetpack Compose 1.8 Strong Skipping Mode. While Strong Skipping enables skipping composables with unstable parameters via structural equality (equals), unoptimized collections, lack of custom equals, or in-place mutations trigger severe UI thread micro-stutters and dropped frames on low-tier Android devices. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Relying on standard Kotlin collections or default instance equality under Strong Skipping, resulting in expensive deep equality checks and dropped frames during recomposition. Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftRelying on standard Kotlin collections or default instance equality under Strong Skipping, resulting in expensive deep equality checks and dropped frames during recomposition.Critical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST ALWAYS use `kotlinx.collections.immutable` (`ImmutableList`, `ImmutableSet`, `ImmutableMap`) or explicit `@Immutable` annotated wrappers for collection parameters in `@Composable` entry points.

Engineers MUST ALWAYS use `kotlinx.collections.immutable` (`ImmutableList`, `ImmutableSet`, `ImmutableMap`) or explicit `@Immutable` annotated wrappers for collection parameters in `@Composable` entry points.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NOT pass standard Kotlin collection interfaces (`List<T>`, `Set<T>`, `Map<K, V>`) directly into public Composable interfaces, as Compose compiler marks them unstable by default, forcing runtime `equals()` traversals.

Engineers MUST NOT pass standard Kotlin collection interfaces (`List<T>`, `Set<T>`, `Map<K, V>`) directly into public Composable interfaces, as Compose compiler marks them unstable by default, forcing runtime `equals()` traversals.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Engineers MUST NOT mutate data classes or collections in place

Engineers MUST NOT mutate data classes or collections in place; all state emissions MUST be strictly new immutable instances to prevent skipped updates when `equals()` returns true for modified internal state.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Code SHOULD annotate stable UI domain models with `@Immutable` or `@Stable` when bridging across multi-module boundaries where the Compose compiler cannot automatically infer stability.

Code SHOULD annotate stable UI domain models with `@Immutable` or `@Stable` when bridging across multi-module boundaries where the Compose compiler cannot automatically infer stability.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Components NEVER capture frequently mutating values (such as raw scroll offsets or animation timestamps) directly in trailing composable lambdas

Components NEVER capture frequently mutating values (such as raw scroll offsets or animation timestamps) directly in trailing composable lambdas; use lambda-based state readers (`() -> T`) or `rememberUpdatedState` to preserve lambda memoization identity.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
6

Services MUST ensure that UI State flows (`StateFlow<UiState>`) emit only objects with O(1) or lightweight O(N) bounded `equals()` implementations to avoid frame overruns during the layout recomposition phase.

Services MUST ensure that UI State flows (`StateFlow<UiState>`) emit only objects with O(1) or lightweight O(N) bounded `equals()` implementations to avoid frame overruns during the layout recomposition phase.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is Jetpack Compose 1.8 Strong Skipping Mode Stability Guardrails critical for AI coding assistants?

Enforces strict parameter immutability, immutable collection boundaries, and deterministic lambda memoization under Jetpack Compose 1.8 Strong Skipping Mode. While Strong Skipping enables skipping composables with unstable parameters via structural equality (equals), unoptimized collections, lack of custom equals, or in-place mutations trigger severe UI thread micro-stutters and dropped frames on low-tier Android devices. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Relying on standard Kotlin collections or default instance equality under Strong Skipping, resulting in expensive deep equality checks and dropped frames during recomposition.) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

Related MOBILE Rules

View all rules →
1 Rule in Stack

Jetpack