Compose Stability Analyzer 0.8.0: Stability Reality Check and Recomposition Blame
Compose Stability Analyzer 0.8.0: Stability Reality Check and Recomposition Blame
Jetpack Compose's strong skipping mode changed how stability affects recomposition. Before strong skipping, a single unstable parameter made a composable non-skippable. With strong skipping, unstable parameters are compared by instance identity (===) while stable ones are compared with equals(), so a composable can skip even when it has unstable parameters, as long as the same instances come back. The result is that the compiler's "unstable" label no longer maps cleanly to "will recompose," and the gap between what static analysis predicts and what actually happens at runtime has grown.
Compose Stability Analyzer has been surfacing stability information directly in Android Studio through gutter icons, hover tooltips, inline hints, the Stability Explorer, the Recomposition Cascade, and the Live Recomposition Heatmap. Those features answer "is this composable stable?" and "how often does it recompose?" Version 0.8.0 answers two questions that sit between prediction and reality: "did the stability prediction actually hold up at runtime?" and "what caused this recomposition in the first place?"
In this article, you'll explore the two new features introduced in version 0.8.0: the Stability Reality Check and Recomposition Blame.
Stability Reality Check
The compiler predicts stability at compile time, but strong skipping decides skipping at runtime using instance identity. A parameter the compiler marks unstable often skips fine because the same instance keeps coming back, while another quietly recomposes on every frame because a new instance arrives each time even though its contents are equal. The Stability Reality Check joins the static prediction with live recomposition data from the heatmap stream and grades each parameter by what actually happens on a real device.

Each parameter receives one of four grades:
- Confirmed: the prediction held. The parameter is stable and not recomposing wastefully.
- False alarm: the compiler flagged it unstable, but the instance stays referentially stable at runtime, so Compose skips it. You can ignore the warning.
- Silent waste: the value is
equalsequal but arrives as a new instance every recomposition, so strong skipping's===check fails and the composable recomposes when it could have skipped. - Justified: the value genuinely changes between recompositions, so recomposing is necessary.
Grades appear in three places: the editor inlay above each composable, the hover tooltip as a predicted versus actual column, and a dedicated Reality tab in the tool window that lists every observed composable with a wasted recomposition tally. To see them, annotate the composables you want to grade with @TraceRecomposition, start the heatmap, and interact with your app. Because grading depends on observed recompositions, a parameter is graded only after its composable recomposes a few times. A stable parameter that simply skips is confirmed as expected and needs no attention.
The silent waste grade is the one worth acting on. It points to a parameter that defeats strong skipping by changing identity without changing value, usually a list, lambda, or object created inline on each recomposition. Hoisting the value into remember or making the type stable removes the waste. The Reality Check documentation covers each grade in more depth.
Recomposition Blame
Knowing that a composable recomposes too often is only half the story. The other half is why. Recomposition Blame traces a recomposition back to its cause in two ways.
The first is the state write site, captured at runtime. When you annotate a composable with @TraceRecomposition(traceStates = true), the plugin installs a Compose Snapshot write observer that records where each internal state was mutated and appends it to the log:
[state] counter: Int changed (0 → 1) ← onClick (MainActivity.kt:97)
The ← method (File.kt:line) suffix tells you exactly which line wrote the state that triggered the recomposition, turning a guess into a precise pointer. Write site capture works for delegated scalar state declared as var x by remember { mutableStateOf(...) } on Android and JVM, and the same suffix also appears in the heatmap inlay's tooltip.
The second is parameter provenance, traced statically. Right-click any @Composable in the editor and choose "Blame this Recomposition":

A Blame tab opens showing the reverse of the cascade: which composables call this one, and where each argument's value originates.

Each caller node lists the arguments it passes, annotated with the static origin of each value: a val or var property, a forwarded parameter, a function call, or a dynamic expression. This view needs no running app, so you can trace where an unstable input comes from while reading code. Double-clicking a node navigates to its source. The Recomposition Blame documentation describes both layers and their limits.
Putting them together
The two features close a loop with the rest of the plugin. Static analysis and the cascade tell you which composables could recompose and what they would affect. The heatmap tells you which ones actually recompose and how often. The Stability Reality Check tells you whether each recomposition is justified or wasteful, and Recomposition Blame tells you what caused it.
A practical workflow looks like this. Start the heatmap and interact with your app. When a composable shows a silent waste grade, open Blame to find which caller passes the offending argument and where that value comes from, or read the state write site to find which line mutated the triggering state. Fix the root cause by hoisting the value into remember, making the type stable, or moving the state write. Then watch the grade flip from silent waste to confirmed. The prediction, the runtime behavior, and the cause now agree.
Both features are available in version 0.8.0 of the Compose Stability Analyzer, which you can install from the JetBrains Marketplace or build from
the repository. The
documentation covers every feature in detail.
As always, happy coding!

