This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
mobilecritical PriorityID: android-15-predictive-back-gesture-state-transition-guardrail

Android 15 Predictive Back Deterministic Dual-State Rollback Guardrail

Enforces strict dual-state rollback synchronization and lifecycle-bounded callback isolation across Android 15 Predictive Back transitions in hybrid Jetpack Compose and Fragment architectures. Prevents premature state commitment, orphaned transient animations, and UI desynchronization when gesture invocations are canceled mid-swipe by the user. Mandates isolated preview state channels that commit to the canonical navigation stack only upon confirmed gesture completion.

Prohibited Anti-Pattern: Eager State Mutation in OnBackInvokedCallback / PredictiveBackHandler Corrupting Navigation Stacks on Gesture Cancellation

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Android 15 Predictive Back Deterministic Dual-State Rollback Guardrail - Enforces strict dual-state rollback synchronization and lifecycle-bounded callback isolation across Android 15 Predictive Back transitions in hybrid Jetpack Compose and Fragment architectures. Prevents premature state commitment, orphaned transient animations, and UI desynchronization when gesture invocations are canceled mid-swipe by the user. Mandates isolated preview state channels that commit to the canonical navigation stack only upon confirmed gesture completion.
globs: **/*Screen.kt, **/*Fragment.kt, **/*Navigation.kt, **/*NavHost.kt, **/*ViewModel.kt
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/android-15-predictive-back-gesture-state-transition-guardrail"
---

# Android 15 Predictive Back Deterministic Dual-State Rollback Guardrail

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Eager State Mutation in OnBackInvokedCallback / PredictiveBackHandler Corrupting Navigation Stacks on Gesture Cancellation

## System Constraints
You are a Principal Android Architect enforcing rigid state transition invariants for Android 15 (API level 35) Predictive Back gestures across Jetpack Compose and AndroidX Fragment navigation hierarchies. You must guarantee that no observable application state (ViewModel, Flow, Navigation BackStack, or DataStore) mutates during the progress phase of a gesture. Any transient UI transformations must reside exclusively within gesture-scoped preview states that automatically roll back to baseline when a gesture is canceled or fails.

## Strict Guidelines
- Engineers MUST ALWAYS isolate gesture progression states from canonical ViewModel state, using compose `PredictiveBackHandler` coroutine blocks or `OnBackAnimationCallback` gesture progress listeners strictly for transient visuals.
- Engineers MUST NOT execute canonical business logic, emit events to SharedFlows, mutate ViewModel properties, or invoke `NavController.popBackStack()` until the predictive back gesture successfully completes (after the `progress` Flow collection terminates without cancellation).
- Code MUST explicitly implement deterministic rollback handlers in `try ... finally` or `onBackCancelled` blocks to reset custom view transformations, animatable offsets, and alpha levels to their resting state.
- Services and ViewModels MUST NEVER register `OnBackInvokedCallback` or hold references to back-dispatch primitives, preserving single-direction lifecycle scoping exclusively inside UI components.
- Components NEVER bind `OnBackInvokedDispatcher.PRIORITY_OVERLAY` or `PRIORITY_DEFAULT` callbacks without unregistering them across lifecycle boundary events (`ON_PAUSE` or `ON_STOP`), preventing dangling system back dispatcher memory leaks and hijacked gestures.

## Bad vs Good Implementations
### Jetpack Compose PredictiveBackHandler State Isolation vs. Eager State Corruption

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Mutating business logic (cancelActiveTransaction) before or during the gesture collection corrupts the transaction if the user aborts the swipe. When a predictive back gesture is canceled, the coroutine is simply canceled; eager state mutations will not roll back automatically.
```kotlin
@Composable
fun CheckoutScreen(navController: NavController, viewModel: CheckoutViewModel) {
    // ANTI-PATTERN: Mutating canonical state and popping backstack prematurely
    // or treating gesture start as confirmed navigation
    PredictiveBackHandler(enabled = true) { progress: Flow<BackEventCompat> ->
        // Mutating canonical state on gesture initiation
        viewModel.cancelActiveTransaction() 
        progress.collect { backEvent ->
            // Directly modifying persistent viewmodel properties during gesture
            viewModel.updateSwipeProgress(backEvent.progress)
        }
        // If user drags back and cancels, cancelActiveTransaction already ran,
        // leaving the transaction aborted and UI corrupted
        navController.popBackStack()
    }
}
```

#### Production Standard (Correct)
> **Standard**: The good pattern keeps progress state strictly transient and encapsulated within Compose Animatable. If the user cancels the gesture mid-flight, a CancellationException is thrown, triggering the catch block where visual offsets roll back to zero without touching canonical ViewModel or Navigation state.
```kotlin
@Composable
fun CheckoutScreen(navController: NavController, viewModel: CheckoutViewModel) {
    val animatedProgress = remember { Animatable(0f) }
    val isGestureActive = remember { mutableStateOf(false) }

    PredictiveBackHandler(enabled = true) { progress: Flow<BackEventCompat> ->
        isGestureActive.value = true
        try {
            progress.collect { backEvent ->
                // Transient local presentation state ONLY
                animatedProgress.snapTo(backEvent.progress)
            }
            // Gesture completed successfully: Commit canonical state mutation
            viewModel.cancelActiveTransaction()
            navController.popBackStack()
        } catch (e: CancellationException) {
            // Gesture was canceled by user: Deterministic rollback
            animatedProgress.animateTo(0f, spring(stiffness = Spring.StiffnessHigh))
        } finally {
            isGestureActive.value = false
        }
    }
}
```

### Fragment OnBackAnimationCallback Deterministic Rollback in Android 15

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Registering a raw OnBackInvokedCallback without utilizing OnBackAnimationCallback prevents the app from participating in predictive back gesture animations, causes lifecycle leaks if not unregistered, and fails to handle cancellation rollbacks across fragment boundaries.
```kotlin
class DetailFragment : Fragment() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
            // ANTI-PATTERN: Using OnBackInvokedCallback without animation/cancellation hooks,
            // or eagerly triggering navigation logic inside onBackStarted
            requireActivity().onBackInvokedDispatcher.registerOnBackInvokedCallback(
                OnBackInvokedDispatcher.PRIORITY_DEFAULT
            ) {
                // Does not handle progress or cancel states; triggers full pop
                findNavController().popBackStack()
            }
        }
    }
}
```

#### Production Standard (Correct)
> **Standard**: Implements full OnBackAnimationCallback with dedicated onBackCancelled rollback logic to ensure views restore resting scales upon canceled gestures, and cleanly unregisters in onDestroyView to eliminate memory leaks.
```kotlin
class DetailFragment : Fragment() {
    private var backCallback: OnBackAnimationCallback? = null

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
            backCallback = object : OnBackAnimationCallback {
                override fun onBackStarted(backEvent: BackEvent) {
                    view.pivotX = 0f
                }
                override fun onBackProgressed(backEvent: BackEvent) {
                    // Bound transient visual scale; no business logic mutation
                    val scale = 1f - (backEvent.progress * 0.1f)
                    view.scaleX = scale
                    view.scaleY = scale
                }
                override fun onBackInvoked() {
                    // Confirmed execution
                    findNavController().popBackStack()
                }
                override fun onBackCancelled() {
                    // Explicit deterministic visual rollback
                    view.animate().scaleX(1f).scaleY(1f).setDuration(150).start()
                }
            }
            requireActivity().onBackInvokedDispatcher.registerOnBackInvokedCallback(
                OnBackInvokedDispatcher.PRIORITY_DEFAULT,
                backCallback!!
            )
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
            backCallback?.let { requireActivity().onBackInvokedDispatcher.unregisterOnBackInvokedCallback(it) }
            backCallback = null
        }
    }
}
```

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Android 15 Predictive Back Deterministic Dual-State Rollback Guardrail

Android 15 Predictive Back Deterministic Dual-State Rollback Guardrail defines an industrial-grade behavioral standard for mobile engineering. Enforces strict dual-state rollback synchronization and lifecycle-bounded callback isolation across Android 15 Predictive Back transitions in hybrid Jetpack Compose and Fragment architectures. Prevents premature state commitment, orphaned transient animations, and UI desynchronization when gesture invocations are canceled mid-swipe by the user. Mandates isolated preview state channels that commit to the canonical navigation stack only upon confirmed gesture completion. 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: Eager State Mutation in OnBackInvokedCallback / PredictiveBackHandler Corrupting Navigation Stacks on Gesture Cancellation 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 DriftEager State Mutation in OnBackInvokedCallback / PredictiveBackHandler Corrupting Navigation Stacks on Gesture CancellationCritical
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 isolate gesture progression states from canonical ViewModel state, using compose `PredictiveBackHandler` coroutine blocks or `OnBackAnimationCallback` gesture progress listeners strictly for transient visuals.

Engineers MUST ALWAYS isolate gesture progression states from canonical ViewModel state, using compose `PredictiveBackHandler` coroutine blocks or `OnBackAnimationCallback` gesture progress listeners strictly for transient visuals.

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 execute canonical business logic, emit events to SharedFlows, mutate ViewModel properties, or invoke `NavController.popBackStack()` until the predictive back gesture successfully completes (after the `progress` Flow collection terminates without cancellation).

Engineers MUST NOT execute canonical business logic, emit events to SharedFlows, mutate ViewModel properties, or invoke `NavController.popBackStack()` until the predictive back gesture successfully completes (after the `progress` Flow collection terminates without cancellation).

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

Code MUST explicitly implement deterministic rollback handlers in `try ... finally` or `onBackCancelled` blocks to reset custom view transformations, animatable offsets, and alpha levels to their resting state.

Code MUST explicitly implement deterministic rollback handlers in `try ... finally` or `onBackCancelled` blocks to reset custom view transformations, animatable offsets, and alpha levels to their resting 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

Services and ViewModels MUST NEVER register `OnBackInvokedCallback` or hold references to back-dispatch primitives, preserving single-direction lifecycle scoping exclusively inside UI components.

Services and ViewModels MUST NEVER register `OnBackInvokedCallback` or hold references to back-dispatch primitives, preserving single-direction lifecycle scoping exclusively inside UI components.

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 bind `OnBackInvokedDispatcher.PRIORITY_OVERLAY` or `PRIORITY_DEFAULT` callbacks without unregistering them across lifecycle boundary events (`ON_PAUSE` or `ON_STOP`), preventing dangling system back dispatcher memory leaks and hijacked gestures.

Components NEVER bind `OnBackInvokedDispatcher.PRIORITY_OVERLAY` or `PRIORITY_DEFAULT` callbacks without unregistering them across lifecycle boundary events (`ON_PAUSE` or `ON_STOP`), preventing dangling system back dispatcher memory leaks and hijacked gestures.

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 Android 15 Predictive Back Deterministic Dual-State Rollback Guardrail critical for AI coding assistants?

Enforces strict dual-state rollback synchronization and lifecycle-bounded callback isolation across Android 15 Predictive Back transitions in hybrid Jetpack Compose and Fragment architectures. Prevents premature state commitment, orphaned transient animations, and UI desynchronization when gesture invocations are canceled mid-swipe by the user. Mandates isolated preview state channels that commit to the canonical navigation stack only upon confirmed gesture completion. 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 (Eager State Mutation in OnBackInvokedCallback / PredictiveBackHandler Corrupting Navigation Stacks on Gesture Cancellation) 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

Android