Stability Reality Check¶
The Stability Reality Check answers a question static analysis alone cannot: does the compiler's stability prediction actually hold up at runtime? Since Compose's strong skipping compares unstable parameters by instance identity (===) and stable ones by equals(), a parameter the compiler flags "unstable" frequently skips perfectly fine in practice — while another quietly recomposes on every frame. This feature joins the static prediction (from in-IDE analysis) with live recomposition data (from the heatmap stream) and grades each parameter accordingly.

Prerequisites¶
Reality Check reuses the heatmap's live data pipeline, so it shares the same requirements:
- The Compose Stability Analyzer Gradle plugin applied to your project.
- Composable functions annotated with
@TraceRecomposition. - Logging enabled via
ComposeStabilityAnalyzer.setEnabled(true)in yourApplicationclass. - A device or emulator connected via ADB, with the Recomposition Heatmap started.
The Grades¶
Each parameter of a traced composable is graded by reconciling its compile-time prediction with what actually happened at runtime:
| Grade | Meaning | What to do |
|---|---|---|
| 🟢 Confirmed | Predicted stable and it behaves stably — no wasteful recomposition. | Nothing. |
| 🟡 False alarm | Predicted unstable, but the instance stays referentially stable at runtime, so Compose skips it fine. | Safely ignore the "unstable" warning. |
| 🔴 Silent waste | The value is equals-equal but arrives as a new instance every recomposition, so strong skipping's === check fails and it recomposes when it could have skipped. |
Hoist the value into remember, or make the type stable. |
| ⚪ Justified | The value genuinely changes between recompositions, so recomposing is necessary. | Nothing — correct behavior. |
| ⚪ Observing | Not enough recompositions observed yet to grade. | Interact with your app a few more times. |
Why strong skipping makes this necessary
Before strong skipping, an unstable parameter always made a composable non-skippable. With strong skipping (Compose Compiler 2.0+), unstable parameters are compared by identity (===), so the same instance skips fine — the compiler's "unstable" label is often a false alarm. The real cost is a fresh-but-equals-equal instance every frame, which this feature surfaces as silent waste.
Where Grades Appear¶
- Editor inlay: the block above each composable shows the recomposition count plus a grade summary (e.g.
(!) silent waste: user). - Hover tooltip: hovering a composable adds a "predicted vs. actual" column to the stability table, with a per-parameter grade badge.
- Reality tab: the Reality tool-window tab is a module-wide scorecard listing each observed composable, its per-parameter grades, and a "wasted recompositions (recent)" tally. Double-click a row to jump to the source.
How to Use¶
- Annotate the composables you want to grade with
@TraceRecomposition. - Start the Recomposition Heatmap and interact with your app to drive recompositions.
- Hover a composable, watch its inlay, or open the Reality tab — grades appear once a parameter has been observed a few times (the observation threshold filters out early noise).
Grading needs observed recompositions
A grade is only assigned after a composable actually recomposes a few times. Because the recomposition tracker runs inside the composable body, a parameter that simply skips is confirmed as expected and is not re-tracked — that's the goal, not a problem.