visualizing-recomposition-cascades — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited visualizing-recomposition-cascades (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Passive gutter icons answer "is this composable skippable" (covered by ../using-stability-analyzer-ide-plugin/SKILL.md). The active investigation tools answer two harder questions. The Cascade visualizer walks the static call graph from a root @Composable and shows what else might recompose if the root recomposes. The Live Heatmap subscribes to the device's logcat and renders the actual recomposition counts as block inlays above each instrumented composable in the editor. Together they close the loop between static analysis and runtime evidence.
Both features live inside the same IntelliJ plugin and surface through the right-anchored Compose Stability Analyzer tool window, which has three tabs: Explorer, Cascade, and Heatmap.
../../recomposition/debugging-recompositions/SKILL.md and needing the call-site context.UnstableComposable inspection from ../using-stability-analyzer-ide-plugin/SKILL.md are enough.../enforcing-stability-in-ci/SKILL.md.../../measurement/generating-baseline-profiles/SKILL.md. Toggle the heatmap off before such runs.../understanding-stability-inference/SKILL.md.../using-stability-analyzer-ide-plugin/SKILL.md already installed and the Compose Stability Analyzer tool window visible in the right rail.@TraceRecomposition (cross-link ../../measurement/tracing-recompositions-at-runtime/SKILL.md for the runtime setup).ComposeStabilityAnalyzer.setEnabled(true) called in Application.onCreate (gated on BuildConfig.DEBUG or a dedicated flag — see ../../measurement/tracing-recompositions-at-runtime/SKILL.md).@ComposableThe action Analyze Recomposition Cascade (id com.skydoves.compose.stability.idea.cascade.AnalyzeCascadeAction) is enabled only when the caret is inside a @Composable function. It is registered in the Editor popup; right-click anywhere inside the composable body to surface it.
Right-click → Analyze Recomposition Cascade. The right-anchored Compose Stability Analyzer tool window opens to the Cascade tab and renders a tree rooted at the selected function.
Internals to know when triaging the result:
KtCallExpression and descends into call targets resolved via resolveMainReference().../using-stability-analyzer-ide-plugin/SKILL.md.Walk depth-first. For each node:
../stabilizing-compose-types/SKILL.md) or by deferring state reads inside hot leaves (../../recomposition/deferring-state-reads/SKILL.md).The cascade is a static call-graph walk. Whether each downstream node actually recomposes at runtime depends on stability and skipping decisions made by the compiler and runtime. Confirm with the live heatmap (Workflow B) before drawing conclusions about real cost.
@TraceRecompositionThe heatmap is fed by logcat lines emitted by the @TraceRecomposition runtime. Without instrumented composables, no inlays appear. Use the Add @TraceRecomposition intention from ../using-stability-analyzer-ide-plugin/SKILL.md, or add the annotation manually. Full runtime setup (gating, state tracing, throttling) lives in ../../measurement/tracing-recompositions-at-runtime/SKILL.md.
Run a debug build on the connected device. Open the Logcat tool window and filter on tag Recomposition. Confirm D/Recomposition lines stream in when the instrumented composables recompose. The exact format the plugin's parser expects:
[Recomposition #3] UserProfile (tag: user-screen) (2.30ms)
├─ [param] user: User changed (User@abc123 → User@def456)
├─ [param] count: Int stable (42)
├─ [state] counter: Int changed (5 → 6)
└─ Unstable parameters: [user]If the log lines are not appearing, the runtime is misconfigured — go back to ../../measurement/tracing-recompositions-at-runtime/SKILL.md before continuing.
In the editor right-click → Toggle Recomposition Heatmap (action id com.skydoves.compose.stability.idea.heatmap.ToggleHeatmapAction). The action also lives under the Code menu.
The plugin's AdbLogcatService spawns this exact ADB command to subscribe:
adb logcat -s Recomposition:D -T 1-s Recomposition:D filters to the tag at debug level; -T 1 starts from the most recent line. If multiple devices are connected, a popup chooser appears.
HeatmapInlayManager places block inlays above each @Composable declaration that has streamed at least one event. Each inlay shows:
Click an inlay to switch the tool window to the Heatmap tab and focus that composable's event history. Hover an inlay for a 5-second tooltip with the latest data, served from AdbLogcatService.getHeatmapData(name).
Run Code → Clear Recomposition Data (action id com.skydoves.compose.stability.idea.heatmap.ClearHeatmapDataAction) to reset the counters between scenarios. Use this when comparing two interactions back-to-back (e.g. a list scroll vs. a search filter) without restarting the app.
Toggle the heatmap action again to stop the listener. The heatmap drives logcat I/O and PSI work on every recomposition; MUST toggle it off before running Macrobenchmark or Baseline Profile generation per ../../measurement/generating-baseline-profiles/SKILL.md, or the overhead will skew the timing results.
The right-anchored tool window with id Compose Stability Analyzer (icon /icons/stability.svg) ships with three tabs registered by StabilityToolWindowFactory:
| Tab | Backing class | Purpose |
|---|---|---|
| Explorer | StabilityToolWindow | Hierarchical tree by module → package → file → composable, with stability badges. Double-click navigates to the source. Use this as a survey view across a module before drilling into Cascade or Heatmap. |
| Cascade | CascadePanel | Populated when Analyze Recomposition Cascade runs. Shows the static call-graph tree from the selected root. |
| Heatmap | HeatmapPanel | Populated when the live heatmap is toggled on. Shows the live event log per composable. |
Use the Explorer tab as the entry point; drop into Cascade for a target; enable Heatmap to confirm.
@TraceRecomposition produces no inlays// WRONG
1. Toggle Recomposition Heatmap on.
2. ADB connects, logcat reader starts.
3. Scroll the screen aggressively.
4. No inlays appear above any composable.
5. Developer concludes "the heatmap is broken".// WRONG because: the heatmap is fed by logcat lines emitted by `@TraceRecomposition`.
// Without at least one instrumented composable there is nothing to render.
// Add `@TraceRecomposition` per `../../measurement/tracing-recompositions-at-runtime/SKILL.md`,
// rebuild, and toggle again.// RIGHT — instrument first, then toggle the heatmap
@TraceRecomposition(traceStates = true)
@Composable
fun PriceTicker(price: Price) {
Text(price.formatted)
}// WRONG
1. Open Macrobenchmark scroll journey.
2. Toggle Recomposition Heatmap on (forgot from earlier session).
3. Run the benchmark.
4. FrameTimingMetric numbers regress vs. baseline; team panics.// WRONG because: the heatmap drives logcat I/O and PSI updates on every recomposition.
// That overhead skews FrameTimingMetric and any release-grade measurement.
// Toggle the heatmap off before running `../../measurement/generating-baseline-profiles/SKILL.md`
// or any Macrobenchmark journey.// RIGHT
1. Toggle Recomposition Heatmap off (verify no inlays in editor).
2. Run the Macrobenchmark journey.
3. Compare FrameTimingMetric vs. the committed baseline.// WRONG
Cascade from PriceTicker shows 12 downstream composables.
Developer concludes "all 12 will recompose every tick" and refactors all 12.// WRONG because: the cascade is a static call-graph walk. Whether each downstream node
// actually recomposes depends on stability and skipping at runtime. Several of the 12
// may already be skipping today; refactoring them is wasted work.
// Confirm with the live heatmap before drawing conclusions.// RIGHT — the loop: cascade for blast radius, heatmap for confirmation, fix, re-measure
1. Analyze Recomposition Cascade from PriceTicker -> 12 nodes flagged.
2. Annotate the top 3 (by suspected hotness) with `@TraceRecomposition`.
3. Toggle Recomposition Heatmap on, run a representative scenario.
4. Inlays show 2 nodes with high counts; the other 10 stayed cold.
5. Fix the 2 hot nodes via `../stabilizing-compose-types/SKILL.md`.
6. Toggle the heatmap off, re-measure with `../../measurement/generating-baseline-profiles/SKILL.md`.// WRONG
Cascade shows a wide subtree; developer wraps every leaf in `key { ... }` to force isolation.// WRONG because: `key` does not make an unstable parameter stable. The leaves still
// receive unstable arguments; the parent still recomposes them. The fix is upstream:
// stabilize the type per `../stabilizing-compose-types/SKILL.md` so the existing
// skipping logic can do its job.// RIGHT
Identify the unstable parameter via the cascade node's badge.
Stabilize the type at its declaration site.
Re-run the cascade to confirm the badge flipped to stable.@TraceRecomposition before toggling the heatmap. Without it, the logcat stream is empty and no inlays render.../../measurement/generating-baseline-profiles/SKILL.md. Logcat overhead skews timing.ComposeStabilityAnalyzer.setEnabled(true) in production. Gate on BuildConfig.DEBUG or a dedicated flag per ../../measurement/tracing-recompositions-at-runtime/SKILL.md.@Composable shows Analyze Recomposition Cascade; right-clicking outside any composable does not.@TraceRecomposition applied, D/Recomposition lines appear in the Logcat window and block inlays appear above the matching composable declarations.D/Recomposition consumption from the plugin).compose-stability-analyzer-idea module within that repo — https://github.com/skydoves/compose-stability-analyzer/tree/main/compose-stability-analyzer-ideaFor the passive in-editor features (gutter icons, hover, inline hints, inspection) of the same plugin, see ../using-stability-analyzer-ide-plugin/SKILL.md. For the runtime instrumentation that emits the D/Recomposition lines the heatmap consumes, see ../../measurement/tracing-recompositions-at-runtime/SKILL.md. For CI-side gating against stability regressions, see ../enforcing-stability-in-ci/SKILL.md. For the upstream type fixes that prune cascade branches, see ../stabilizing-compose-types/SKILL.md. For deferring state reads inside hot leaves discovered via the heatmap, see ../../recomposition/deferring-state-reads/SKILL.md. For Macrobenchmark journeys that MUST run with the heatmap off, see ../../measurement/generating-baseline-profiles/SKILL.md.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.