一键导入
investigate-compose-metrics
Investigate per-module Compose compiler metrics in this repo to find low-skippability hotspots and the underlying unstable classes.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Investigate per-module Compose compiler metrics in this repo to find low-skippability hotspots and the underlying unstable classes.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Shared review criteria and output format for code review agents
Generate a Roborazzi visual-regression test (VRT) class for a Jetpack Compose composable in the sunsetscrob project, with all three required annotations — @RunWith(AndroidJUnit4::class), @GraphicsMode(GraphicsMode.Mode.NATIVE), and @Category(VRT::class) — plus the captureScreenshot wiring from :test_helper:integration. Use this skill whenever the user asks to add or create a VRT, a Roborazzi test, a screenshot test, a visual regression test, スクリーンショットテスト, スクショテスト, or VRT 追加 / VRT 作って — or points at a composable and asks for a visual regression test. The skill exists specifically to prevent forgetting @Category(VRT::class), which silently drops the test into the wrong CI bucket without failing compilation.
基于 SOC 职业分类
| name | investigate-compose-metrics |
| description | Investigate per-module Compose compiler metrics in this repo to find low-skippability hotspots and the underlying unstable classes. |
| disable-model-invocation | true |
| allowed-tools | ["Read","Glob","Grep","Bash(./gradlew:*)","Bash(find:*)","Bash(awk:*)","Bash(grep:*)","Bash(sed:*)","Bash(jq:*)","Bash(sort:*)","Bash(column:*)"] |
Drill into the Compose compiler metrics that the build emits when
-PcomposeCompilerReports=true is passed. The goal is to find specific
Composables and parameter types whose stability or skippability should be
improved — not to produce a roll-up summary across modules.
This skill is investigation-only. Do not change code unless the user explicitly asks for a fix in a follow-up turn.
find . -path '*/build/compose_metrics/*-module.json'
Each module that applies the sunsetscrob.android.compose convention
plugin produces:
<mod>/build/compose_metrics/debug/<mod>-module.json<mod>/build/compose_reports/<mod>-classes.txt<mod>/build/compose_reports/<mod>-composables.csv<mod>/build/compose_reports/<mod>-composables.txtModules expected to appear: :app, :core, :ui_common,
:feature:account, :feature:album, :feature:artist,
:feature:auth, :feature:discover, :feature:home,
:feature:scrobble, :test_helper:integration.
If only a subset is present, the previous build restored
compileDebugKotlin from the build cache and the Compose compiler
plugin did not run for the missing modules. Regenerate (step 2).
If metrics are missing or stale, ask the user before regenerating — this rebuilds every Kotlin module from cold and takes several minutes.
./gradlew clean assembleDebug -PcomposeCompilerReports=true --no-build-cache
Why each flag matters:
-PcomposeCompilerReports=true — wires metricsDestination and
reportsDestination for the Compose compiler plugin
(build-logic/.../ext/ComposeConfiguration.kt). Without it, no
reports are written.--no-build-cache — without this, Gradle may restore
compileDebugKotlin outputs from the build cache and the Compose
plugin never runs, so most modules end up with no reports.clean — needed at least once after enabling the flag, to evict
prior compile output.<mod>-module.json reports effectivelyStableClasses / totalClasses,
but this ratio looks worse than reality because the denominator
includes classes that never appear as a Composable parameter and
therefore cannot affect skippability. Treat the following as noise
when scanning <mod>-classes.txt:
MetroFactory, the
MetroContributionToAppScope.BindsMirror inner class, the assisted
Factory.Impl.kotlinx.serialization — names
ending in .$serializer.MusicNotificationListenerService).UiState data class is
passed into Compose.MutableStateFlow, Job, CoroutineScope, Repository-typed
fields.The signal lives in classes that actually appear as a parameter type
of an @Composable function.
Read the <mod>-module.json files (Glob + Read, or jq) and choose a
module with a low skippableComposables / totalComposables ratio. A
fast scan:
jq -r '
"\(input_filename | sub(".*/(.+)/build.*"; "\\1")): " +
"skippable=\(.skippableComposables)/\(.totalComposables), " +
"stableCls=\(.effectivelyStableClasses)/\(.totalClasses), " +
"stableArg=\(.knownStableArguments)/\(.totalArguments)"
' */build/compose_metrics/debug/*-module.json **/*/build/compose_metrics/debug/*-module.json 2>/dev/null
If the glob expansion is awkward in the user's shell, fall back to
find ... | xargs jq ....
The CSV header is:
package,name,composable,skippable,restartable,readonly,inline,isLambda,hasDefaults,defaultsGroup,groups,calls
Filter rows that are real Composables (composable=1) and not
skippable (skippable=0):
awk -F, 'NR>1 && $3=="1" && $4=="0" {print $1"."$2}' \
<mod>/build/compose_reports/<mod>-composables.csv
For each suspect Composable, read its declaration in the source tree
(usually under feature/<mod>/src/main/kotlin/.../ui/) and note every
non-primitive parameter type, plus the receiver if any.
grep -B 1 -A 20 -E '(stable|unstable) class .*\.<TypeName> \{' \
<mod>/build/compose_reports/<mod>-classes.txt
The block ends with <runtime stability> = .... Each field line
states whether that field is stable, unstable, or runtime. The
unstable fields are the actual cause.
Common patterns in this codebase (see
.claude/rules/coding-conventions.md → "Data Class"):
@Immutable to a data class whose fields are all stable but
that the compiler conservatively marks unstable (e.g. deep generics,
inferred uncertainty across module boundaries).List<T> with kotlinx.collections.immutable.ImmutableList<T>.Present the candidates and the suggested direction to the user. Do not edit code in this turn unless asked.
Makefile or .github/workflows/compose_metrics.yml.