svharness 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +531 -0
- package/bin/cli.js +3 -0
- package/dist/adapters/_frontmatter.js +24 -0
- package/dist/adapters/claude-code.js +12 -0
- package/dist/adapters/codechat.js +12 -0
- package/dist/adapters/cursor.js +19 -0
- package/dist/adapters/generic.js +19 -0
- package/dist/adapters/index.js +26 -0
- package/dist/adapters/qoder.js +12 -0
- package/dist/commands/apply.js +272 -0
- package/dist/commands/init.js +420 -0
- package/dist/core/agent-injector.js +192 -0
- package/dist/core/next-steps.js +91 -0
- package/dist/core/render-meta.js +81 -0
- package/dist/core/repomix-pack.js +54 -0
- package/dist/core/scaffold.js +93 -0
- package/dist/core/state.js +80 -0
- package/dist/index.js +239 -0
- package/dist/types.js +5 -0
- package/dist/utils/baseline-copy.js +591 -0
- package/dist/utils/baseline-defaults.js +106 -0
- package/dist/utils/logger.js +56 -0
- package/dist/utils/validate-args.js +132 -0
- package/dist/utils/version.js +23 -0
- package/dist/wiki/abort.js +30 -0
- package/dist/wiki/config.js +79 -0
- package/dist/wiki/defaults.js +16 -0
- package/dist/wiki/envLoader.js +78 -0
- package/dist/wiki/index.js +29 -0
- package/dist/wiki/openaiCompat.js +219 -0
- package/dist/wiki/repowikiCanonicalSections.js +67 -0
- package/dist/wiki/repowikiCheckpoint.js +106 -0
- package/dist/wiki/repowikiConfig.js +9 -0
- package/dist/wiki/repowikiGit.js +73 -0
- package/dist/wiki/repowikiIndexer.js +824 -0
- package/dist/wiki/repowikiMarkdownPost.js +123 -0
- package/dist/wiki/repowikiMetadataContent.js +64 -0
- package/dist/wiki/repowikiMetadataJson.js +15 -0
- package/dist/wiki/repowikiScanner.js +156 -0
- package/dist/wiki/repowikiStructureNav.js +286 -0
- package/dist/wiki/repowikiStructureNormalize.js +218 -0
- package/dist/wiki/wikiStructureXml.js +316 -0
- package/dist/wiki/wikiTasksWriter.js +127 -0
- package/package.json +57 -0
- package/templates/_shared/apply-skills/harness-apply-skills-main.md +91 -0
- package/templates/_shared/build-rules/harness-build-rule-agent-agnostic.md +35 -0
- package/templates/_shared/build-rules/harness-build-rule-chinese-only.md +49 -0
- package/templates/_shared/build-rules/harness-build-rule-memory-write.md +31 -0
- package/templates/_shared/build-rules/harness-build-rule-orchestrator-flow.md +25 -0
- package/templates/_shared/build-rules/harness-build-rule-skills-tasks-output.md +35 -0
- package/templates/_shared/build-rules/harness-build-rule-specs-schema.md +32 -0
- package/templates/_shared/build-rules/harness-build-rule-user-interaction.md +63 -0
- package/templates/_shared/build-skills/harness-build-skill-knowledge-builder.md +120 -0
- package/templates/_shared/build-skills/harness-build-skill-orchestrator.md +87 -0
- package/templates/_shared/build-skills/harness-build-skill-spec-builder.md +85 -0
- package/templates/_shared/build-skills/harness-build-skill-wiki-writer.md +77 -0
- package/templates/_shared/meta/AGENTS.md.ejs +53 -0
- package/templates/_shared/meta/CHANGELOG.md.ejs +15 -0
- package/templates/_shared/meta/README.md.ejs +51 -0
- package/templates/_shared/meta/VERSION.ejs +1 -0
- package/templates/_shared/meta/harness.yaml.ejs +52 -0
- package/templates/_shared/skeleton/agent-env/memory/categories/.gitkeep +1 -0
- package/templates/_shared/skeleton/agent-env/memory/inbox/.gitkeep +1 -0
- package/templates/_shared/skeleton/agent-env/skills/.gitkeep +1 -0
- package/templates/_shared/skeleton/agent-env/tools/.gitkeep +1 -0
- package/templates/_shared/skeleton/assets/baseline/code/.gitkeep +1 -0
- package/templates/_shared/skeleton/assets/baseline/repomix/.gitkeep +1 -0
- package/templates/_shared/skeleton/assets/baseline/wiki/.gitkeep +1 -0
- package/templates/_shared/skeleton/assets/raw/.gitkeep +1 -0
- package/templates/_shared/skeleton/assets/requirements/.gitkeep +1 -0
- package/templates/_shared/skeleton/commands/install/.gitkeep +1 -0
- package/templates/_shared/skeleton/commands/update/.gitkeep +1 -0
- package/templates/_shared/skeleton/specs/behavior/schema.json +39 -0
- package/templates/_shared/skeleton/specs/interfaces/schema.json +38 -0
- package/templates/_shared/skeleton/specs/signals/schema.json +37 -0
- package/templates/_shared/skeleton/specs/ui/schema.json +44 -0
- package/templates/_shared/skeleton/tasks/templates/.gitkeep +0 -0
- package/templates/android-compose/skeleton/agent-env/rules/harness-compose-mandatory.mdc +49 -0
- package/templates/android-compose/skeleton/agent-env/rules/harness-coroutines-scope.mdc +52 -0
- package/templates/android-compose/skeleton/agent-env/rules/harness-hilt-injection.mdc +47 -0
- package/templates/android-compose/skeleton/agent-env/rules/harness-mvi-layering.mdc +58 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-android-architecture/SKILL.md +260 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-android-architecture/references/gradle-module-patterns.md +66 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-android-architecture/references/implementation-checklist.md +45 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-android-architecture/references/udf-data-flow.md +80 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-android-cli/SKILL.md +79 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-android-cli/references/interact.md +83 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-android-cli/references/journeys.md +97 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/SKILL.md +162 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/references/canonical-sources.md +116 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/references/diagnostics.md +182 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/references/report-template.md +135 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/references/scoring.md +277 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/references/search-playbook.md +303 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-audit/scripts/compose-reports.init.gradle +58 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-state/SKILL.md +196 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-ui/SKILL.md +192 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-ui/references/composable-api-guide.md +123 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-ui/references/performance-recipes.md +97 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-compose-ui/references/state-patterns.md +93 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-kotlin-coroutines/SKILL.md +167 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/SKILL.md +45 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/CONFIGURATION.md +44 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/KEEP-RULES-IMPACT-HIERARCHY.md +83 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/REDUNDANT-RULES.md +222 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/REFLECTION-GUIDE.md +139 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/android/topic/performance/app-optimization/enable-app-optimization.md +176 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-r8-analyzer/references/android/training/testing/other-components/ui-automator.md +312 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/SKILL.md +87 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/references/analysis-of-the-project-and-layout.md +42 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/references/android/develop/ui/compose/designsystems/migrate-xml-theme-to-compose.md +168 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/references/android/develop/ui/compose/setup-compose-dependencies-and-compiler.md +183 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/references/identify-optimal-xml-candidate.md +31 -0
- package/templates/android-compose/skeleton/agent-env/skills/harness-xml-to-compose/references/xml-layout-migration.md +86 -0
- package/templates/android-xml/skeleton/agent-env/rules/seed-aidl-thread.md +29 -0
- package/templates/android-xml/skeleton/agent-env/rules/seed-lifecycle-awareness.md +32 -0
- package/templates/android-xml/skeleton/agent-env/rules/seed-mvc-layering.md +32 -0
- package/templates/android-xml/skeleton/agent-env/rules/seed-view-binding.md +33 -0
- package/templates/android-xml/skeleton/agent-env/rules/seed-xml-styling.md +27 -0
- package/templates/cpp/skeleton/agent-env/rules/seed-cmake-explicit-sources.md +31 -0
- package/templates/cpp/skeleton/agent-env/rules/seed-header-guards.md +34 -0
- package/templates/cpp/skeleton/agent-env/rules/seed-include-layering.md +39 -0
- package/templates/cpp/skeleton/agent-env/rules/seed-no-cyclic-deps.md +29 -0
- package/templates/cpp/skeleton/agent-env/rules/seed-raii.md +30 -0
- package/templates/python/skeleton/agent-env/rules/seed-context-managers.md +60 -0
- package/templates/python/skeleton/agent-env/rules/seed-docstrings.md +48 -0
- package/templates/python/skeleton/agent-env/rules/seed-import-order.md +49 -0
- package/templates/python/skeleton/agent-env/rules/seed-pep8-naming.md +45 -0
- package/templates/python/skeleton/agent-env/rules/seed-type-annotations.md +43 -0
- package/templates/web-react/skeleton/agent-env/rules/seed-controlled-component.md +43 -0
- package/templates/web-react/skeleton/agent-env/rules/seed-effect-cleanup.md +43 -0
- package/templates/web-react/skeleton/agent-env/rules/seed-hook-rules.md +42 -0
- package/templates/web-react/skeleton/agent-env/rules/seed-key-stability.md +39 -0
- package/templates/web-react/skeleton/agent-env/rules/seed-no-props-drilling.md +43 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Tools
|
|
2
|
+
Run `android layout --help` and `android screen --help`.
|
|
3
|
+
|
|
4
|
+
## UI Dump
|
|
5
|
+
`android layout` returns a flat JSON list of the UI elements on screen.
|
|
6
|
+
`android layout --diff` returns a flat JSON list of the UI elements that have changed since the last call to `layout` or `layout --diff`
|
|
7
|
+
|
|
8
|
+
Each JSON object represents a UI element in the Android app. The following properties may be present:
|
|
9
|
+
- `text` - any literal text the element contains
|
|
10
|
+
- `resourceId` - the Android resource id used to refer to the element
|
|
11
|
+
- `contentDesc` - a description of a UI element for use by accessibility tools
|
|
12
|
+
- `interactions` - the set of user interactions the element supports. May contain one or more of: `checkable`, `clickable`, `focusable`, `scrollable`, `long-clickable`, `password`
|
|
13
|
+
- `state` - the set of states the element is in. May contain one or more of `checked`, `focused`, `selected`
|
|
14
|
+
- `bounds` - the screen coordinates of the bounding rectangle of the element, in the format `[min X,min Y][max X, max Y]`
|
|
15
|
+
- `center` - the screen coordinates of the center of the element, in the format `[x,y]`
|
|
16
|
+
- `off-screen` - if true, the element is in the UI hierarchy but not visible; it may require scrolling to view.
|
|
17
|
+
|
|
18
|
+
Use `layout` as a primary means of examining an Android app. Use `layout --diff` to focus on changes and to keep your context small.
|
|
19
|
+
Example: When entering digits into a calculator, use `layout --diff` to output only the digit readout element.
|
|
20
|
+
|
|
21
|
+
`layout` may fail due to the app displaying a WebView or animation; in these cases, use `android screen --annotate` to inspect the app.
|
|
22
|
+
This failure will likely resolve after navigating away from the current screen.
|
|
23
|
+
|
|
24
|
+
## Screenshot
|
|
25
|
+
`android screen capture -o <file path>` saves a PNG of the current device screen to `<file path>`
|
|
26
|
+
|
|
27
|
+
Use `screen capture` as a secondary means of examining an Android app
|
|
28
|
+
Examples:
|
|
29
|
+
- Understanding the content of an on-screen image
|
|
30
|
+
- Looking at a `WebView` (web content does not always appear in the ui dump)
|
|
31
|
+
- Trying to find a UI element by its visual appearance
|
|
32
|
+
|
|
33
|
+
**IMPORTANT**: Always *VISUALLY* examine the PNG image returned from `android screen` BEFORE doing anything else.
|
|
34
|
+
|
|
35
|
+
## Annotated Screenshot
|
|
36
|
+
`android screen capture --annotate -o <file path>`
|
|
37
|
+
`android screen resolve --screen <path> --string <string>`
|
|
38
|
+
|
|
39
|
+
The `--annotate` command adds numerical labels and bounding boxes around UI elements. Use this command to locate UI elements that cannot
|
|
40
|
+
be located in the `layout` output.
|
|
41
|
+
|
|
42
|
+
**IMPORTANT**: When using `android screen --annotate`, always *VISUALLY* examine the resulting PNG file.
|
|
43
|
+
|
|
44
|
+
To refer to these labels in input commands, use `screen resolve` to convert labels into coordinates:
|
|
45
|
+
|
|
46
|
+
`android screen resolve --screen <file path> --string "#3"` returns `<x coord of region 3> <y coord of region 3>`
|
|
47
|
+
|
|
48
|
+
To save turns, you can combine shell commands:
|
|
49
|
+
|
|
50
|
+
`adb shell input $(android screen resolve --screen screen.png --string "tap #34")`
|
|
51
|
+
|
|
52
|
+
This command taps on region #34 from `screen.png`
|
|
53
|
+
|
|
54
|
+
## Input
|
|
55
|
+
Use `adb shell input` for interacting with Android devices.
|
|
56
|
+
Refer to the `"interactions"` property of an element for what interactions can be performed on a particular element.
|
|
57
|
+
|
|
58
|
+
Interact with UI elements with their `center` coordinate or their `bounds` coordinates:
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"key": -248568265,
|
|
62
|
+
"class": "android.widget.Button",
|
|
63
|
+
"bounds": "[138,9][167,38]",
|
|
64
|
+
"center": "[152,23]"
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
To tap on this button, you would execute `adb shell input tap 152 23`. This taps the center.
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"key": 12487234,
|
|
72
|
+
"class": "com.example.ui.ScrollableList",
|
|
73
|
+
"bounds": "[100,200][400,600]",
|
|
74
|
+
"center": "[250,400]"
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
To scroll down on this list, you would execute `adb shell input swipe 250 400 600 500`. This swipes from the center to the bottom over 500ms.
|
|
78
|
+
|
|
79
|
+
# Android Interaction Rules
|
|
80
|
+
1. Always ensure text input fields have `"focused"` in their `"state"` list before entering text
|
|
81
|
+
2. If an element has `"scrollable"` in its `"interactions"` list, try scrolling it when looking for missing UI elements
|
|
82
|
+
2. Always scroll slowly when executing scroll inputs. The 5th argument to `adb shell input swipe` controls scroll duration.
|
|
83
|
+
3. Content may take time to load; if a `layout` is missing information after you take an action, wait a few seconds, then perform `layout --diff` to see if anything changes.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
A journey is an XML-specified test of an Android app's behavior. It consists of a list of `<action>` elements. For example:
|
|
2
|
+
```xml
|
|
3
|
+
<journey name="My Journey">
|
|
4
|
+
<description>
|
|
5
|
+
A sample journey to illustrate the format
|
|
6
|
+
</description>
|
|
7
|
+
<actions>
|
|
8
|
+
<action>
|
|
9
|
+
Tap the "Home" icon
|
|
10
|
+
</action>
|
|
11
|
+
<action>
|
|
12
|
+
Verify that the app is on its Home screen
|
|
13
|
+
</action>
|
|
14
|
+
</actions>
|
|
15
|
+
</journey>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Evaluate a journey by proceeding through the `<actions>` list in sequential order. Evaluate each `<action>` block individually.
|
|
19
|
+
A journey succeeds if all elements in the `<actions>` list succeed.
|
|
20
|
+
|
|
21
|
+
A journey is a test case for an app. The journey XML is the source of truth; if the app disagrees with the journey, the app has failed.
|
|
22
|
+
Additionally, if the app exits, crashes, or freezes, journey evaluation stops and the journey fails.
|
|
23
|
+
|
|
24
|
+
**IMPORTANT** - Execute each step EXACTLY as written, and independently of other steps! If an action says to `"tap the first search result"`,
|
|
25
|
+
you MUST find the search results and tap the first one. Do this even if you believe you know the intent behind the action.
|
|
26
|
+
|
|
27
|
+
## Taking Actions
|
|
28
|
+
Some `<action>` elements specify UI interactions to perform on the running Android app. Perform the interaction and verify that the app does
|
|
29
|
+
not crash or behave in an unexpected manner. This is the *only* verification you should perform for an `<action>`.
|
|
30
|
+
|
|
31
|
+
If the interaction cannot be performed as specified, the journey fails.
|
|
32
|
+
Example:
|
|
33
|
+
```<action>Click the red button</action>```
|
|
34
|
+
If you determine a red button is not present in the UI, the journey fails.
|
|
35
|
+
|
|
36
|
+
If the text of an `<action>` specifies a list of actions, break it into sub-actions and evaluate them individually:
|
|
37
|
+
Example:
|
|
38
|
+
```<action>Search for soda and add the first result to the cart</action>```
|
|
39
|
+
This should be evaluated as:
|
|
40
|
+
```
|
|
41
|
+
<action>Search for soda</action>
|
|
42
|
+
<action>Add the first result to the cart</action>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
If an `<action>` contains something that is not a specification for a UI interaction, alert the user that the journey is malformed and exit
|
|
46
|
+
early, specifying the error in question.
|
|
47
|
+
|
|
48
|
+
## Verifying Expectations
|
|
49
|
+
`<action>` elements that begin with "check" or "verify" specify expectations for the current state of the Android app. Determine the current
|
|
50
|
+
state of the app and check if the expectations are met.
|
|
51
|
+
|
|
52
|
+
Determine the current state of the app by inspecting the current screen of the device without interacting with it.
|
|
53
|
+
Example:
|
|
54
|
+
```<action>Check if "Switch 2" is visible on the screen</action>```
|
|
55
|
+
This requires only inspecting the current screen, not scrolling or interacting. If "Switch 2" is not currently visible, the action fails.
|
|
56
|
+
|
|
57
|
+
If the expectations are not met, mark the `<action>` as a failure and the journey evaluation ends. A single `<action>` may contain
|
|
58
|
+
multiple expectations.
|
|
59
|
+
Example:
|
|
60
|
+
```<action>Verify that the app is on the Home screen, the Home icon is blue, and the temperature is displayed</action>```
|
|
61
|
+
This `<action>` fails if ANY of the following are false:
|
|
62
|
+
- The app is on the Home screen
|
|
63
|
+
- There is a Home icon, and it is blue
|
|
64
|
+
- A temperature is displayed
|
|
65
|
+
|
|
66
|
+
## Handling failure
|
|
67
|
+
When running a journey, evaluate it as a test. Failure is acceptable, and often expected. Proper reporting of failures is the priority.
|
|
68
|
+
|
|
69
|
+
Keep debugging and troubleshooting to a minimum; assume that tools are showing you the correct output every time. The goal is to determine
|
|
70
|
+
if the *current* Android app can correctly handle the *current* steps outlined in the journey. Suggestions for bug fixes, clarification, or
|
|
71
|
+
other improvements should be kept to journey evaluation summary at the end.
|
|
72
|
+
|
|
73
|
+
## Summarizing
|
|
74
|
+
For each `<action>` you evaluated, output JSON describing the results.
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
{
|
|
78
|
+
"journey:", The name of the journey
|
|
79
|
+
"results:" [
|
|
80
|
+
{
|
|
81
|
+
// A string containing the full text of the <action>
|
|
82
|
+
"action": "Click the blue button,
|
|
83
|
+
// "PASSED" if the instruction was evaluated, "FAILED" if the instruction could not be evaluated, or "SKIPPED" if journey evaluation ended early because an instruction failed
|
|
84
|
+
"status": "PASSED",
|
|
85
|
+
// A list of the ADB commands executed while evaluating the instruction,
|
|
86
|
+
"commands": [ "adb input swipe 490 200 500 500 500", "adb input tap 45 920" ],
|
|
87
|
+
// Failure reasons, feedback, or other useful information
|
|
88
|
+
"comment": "The journey step doesn't specify that the button requires scrolling to see",
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"action": "The home screen is shown",
|
|
92
|
+
"status": "FAILED",
|
|
93
|
+
"comment": "The settings page was shown",
|
|
94
|
+
},
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
```
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: harness-compose-audit
|
|
3
|
+
description: 审计 Android Jetpack Compose 仓库的性能、状态管理、副作用和可组合函数 API 质量。扫描源代码,对每个类别进行 0-10 评分,编写严格的 markdown 报告,并总结最重要的修复建议。在审查 Compose 代码库、评估仓库质量、检查重组/状态问题或运行 Compose 审计时使用。
|
|
4
|
+
allowed-tools: Read, Glob, Grep, Write, Bash, Agent
|
|
5
|
+
argument-hint: "[仓库路径或模块路径]"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Jetpack Compose 审计
|
|
9
|
+
|
|
10
|
+
本技能以严格的、基于证据的报告审计 Android Jetpack Compose 仓库。
|
|
11
|
+
|
|
12
|
+
**评分标准版本:** v1 — 当前版本日期 2026-04-13。Compose 版本:Kotlin 2.0.20+ / Compose Compiler 1.5.4+(强跳过模式默认开启)。
|
|
13
|
+
|
|
14
|
+
本技能专注于四个类别:
|
|
15
|
+
|
|
16
|
+
- 性能
|
|
17
|
+
- 状态管理
|
|
18
|
+
- 副作用
|
|
19
|
+
- 可组合函数 API 质量
|
|
20
|
+
|
|
21
|
+
本技能在 v1 版本中**不**对设计或 Material 3 合规性评分。如果审计发现可能的设计系统问题,建议使用 `material-3` 技能进行后续审计(参考实现:<https://github.com/hamen/material-3-skill>)。
|
|
22
|
+
|
|
23
|
+
## v1 版本不包含的内容
|
|
24
|
+
|
|
25
|
+
有意的范围选择 — 在报告中说明限制,而不是默默地提供薄弱的覆盖:
|
|
26
|
+
|
|
27
|
+
- Material 3 合规性、主题、颜色/排版标记 — 推迟到 `material-3` 技能处理。
|
|
28
|
+
- 无障碍评分(`semantics`、内容描述、触摸目标大小)— 将明显的差距作为注释标出,不评分。
|
|
29
|
+
- UI 测试覆盖率和 Compose 测试规则模式 — 注明存在/不存在,不评分。
|
|
30
|
+
- Compose Multiplatform 特定规则(`expect`/`actual`、目标特定代码路径)。
|
|
31
|
+
- Wear OS / TV / Auto / Glance 界面。
|
|
32
|
+
- 构建性能(增量编译、KSP/KAPT 选择)。
|
|
33
|
+
|
|
34
|
+
## 何时使用
|
|
35
|
+
|
|
36
|
+
当用户要求以下内容时使用此技能:
|
|
37
|
+
|
|
38
|
+
- 审计 Jetpack Compose 仓库
|
|
39
|
+
- 审查 Compose 架构或质量
|
|
40
|
+
- 对代码库进行评分
|
|
41
|
+
- 检查重组、状态或副作用问题
|
|
42
|
+
- 识别现有仓库中的 Compose 最佳实践违规
|
|
43
|
+
|
|
44
|
+
典型触发短语:
|
|
45
|
+
|
|
46
|
+
- "审计这个 Compose 仓库"
|
|
47
|
+
- "对这个 Jetpack Compose 代码库评分"
|
|
48
|
+
- "审查状态提升和副作用"
|
|
49
|
+
- "检查 Compose 性能"
|
|
50
|
+
- "评估这个仓库"
|
|
51
|
+
|
|
52
|
+
## 预期输出
|
|
53
|
+
|
|
54
|
+
同时生成:
|
|
55
|
+
|
|
56
|
+
- 一个名为 `COMPOSE-AUDIT-REPORT.md` 的仓库报告文件
|
|
57
|
+
- 一个简短的聊天摘要,包含总分、类别得分、最严重的问题和首要修复建议
|
|
58
|
+
|
|
59
|
+
## 审计原则
|
|
60
|
+
|
|
61
|
+
- 严格,但基于证据。
|
|
62
|
+
- 不要仅从搜索命中进行评分。在判断类别之前阅读代表性文件。
|
|
63
|
+
- 在报告中为每个重要的扣分引用具体的文件路径。
|
|
64
|
+
- **为每个扣分引用官方文档 URL。** 评分标准将每条规则映射到 `references/canonical-sources.md` 中的权威来源。报告模板要求每个发现都有 `References:` 行。
|
|
65
|
+
- 优先使用官方 Android 指导而非道听途说。
|
|
66
|
+
- 将性能视为重要,但不是唯一的角度。
|
|
67
|
+
- 不要因为应用代码未通过公共库纯度测试而惩罚它。主要对可复用的内部组件、设计系统片段和共享 UI 构建块应用 API 质量检查。
|
|
68
|
+
- 将 `0-3` 分保留给重复或系统性问题,而非孤立错误。
|
|
69
|
+
- 除非仓库在类别中持续表现强劲,否则不授予 `9-10` 分。
|
|
70
|
+
|
|
71
|
+
## 流程
|
|
72
|
+
|
|
73
|
+
### 1. 确认范围
|
|
74
|
+
|
|
75
|
+
识别目标路径,确认 Compose 确实存在(快速失败):在 `build.gradle*` 或 `libs.versions.toml` 中 grep `androidx.compose`,在 `src/` 下 grep `setContent {` 或 `@Composable`。
|
|
76
|
+
|
|
77
|
+
### 2. 映射仓库
|
|
78
|
+
|
|
79
|
+
在评分之前识别:Gradle 模块、Android 应用和功能模块、Compose 源根目录、共享 UI/组件包、主题或设计系统包、状态持有者或 ViewModel 区域、测试和预览位置。
|
|
80
|
+
|
|
81
|
+
### 3. 构建 Compose 表面映射
|
|
82
|
+
|
|
83
|
+
查找 `@Composable` 函数、可复用 UI 组件、屏幕和路由、`ViewModel` 使用、`remember`/`rememberSaveable`/`mutableStateOf`、`collectAsStateWithLifecycle`/`collectAsState`、`LaunchedEffect`/`DisposableEffect`/`SideEffect`、`LazyColumn`/`LazyRow`/`items`。
|
|
84
|
+
|
|
85
|
+
### 4. 生成 Compose 编译器报告(自动)
|
|
86
|
+
|
|
87
|
+
**不要**要求用户编辑 `build.gradle` 或自己运行命令。该技能使用捆绑的 Gradle 初始化脚本运行构建:
|
|
88
|
+
|
|
89
|
+
1. 定位 `scripts/compose-reports.init.gradle`
|
|
90
|
+
2. 检查目标中的 Gradle wrapper
|
|
91
|
+
3. 选择编译目标(优先 `compileReleaseKotlinAndroid`)
|
|
92
|
+
4. 运行构建:`./gradlew <task> --init-script <path> --no-daemon --quiet`(600 秒超时)
|
|
93
|
+
5. 收集报告:`find <target> -path '*/build/compose_audit/*'`
|
|
94
|
+
6. 如果构建失败,回退到源代码推断的稳定性发现,降低置信度
|
|
95
|
+
|
|
96
|
+
### 5. 审计四个类别
|
|
97
|
+
|
|
98
|
+
使用 `references/scoring.md` 中的评分标准和 `references/search-playbook.md` 中的启发式方法。
|
|
99
|
+
|
|
100
|
+
**性能**:组合中的昂贵工作、可避免的重组、懒列表键、错误的状态读取时机、不稳定或过于宽泛的读取、向后写入。
|
|
101
|
+
|
|
102
|
+
**状态管理**:提升正确性、单一数据源、可复用的无状态接缝、`remember` 与 `rememberSaveable` 的正确使用、生命周期感知的可观察收集。
|
|
103
|
+
|
|
104
|
+
**副作用**:在组合中错误执行的副作用、正确的副作用 API 选择、副作用键、过期的 lambda 捕获、清理正确性。
|
|
105
|
+
|
|
106
|
+
**可组合函数 API 质量**:`modifier` 存在性和位置、参数顺序、显式优于隐式配置、有意义的默认值、避免在可复用 API 中使用 `MutableState<T>` 参数。
|
|
107
|
+
|
|
108
|
+
### 6. 验证发现
|
|
109
|
+
|
|
110
|
+
在扣分之前阅读问题出现的文件,确保模式是真实的而非误报,区分一次性错误和系统性模式。
|
|
111
|
+
|
|
112
|
+
### 7. 评分
|
|
113
|
+
|
|
114
|
+
为每个类别分配 `0-10` 分(0-3 不合格、4-6 需要改进、7-8 良好、9-10 优秀)。
|
|
115
|
+
|
|
116
|
+
**测量上限是强制性的。** 基于 `skippable%` 和不稳定参数计数定义上限,在报告中显示计算过程。
|
|
117
|
+
|
|
118
|
+
### 8. 编写报告
|
|
119
|
+
|
|
120
|
+
使用 `references/report-template.md`。报告必须包含:总分、类别得分表、关键发现、逐类别推理、证据文件路径、优先修复列表。
|
|
121
|
+
|
|
122
|
+
### 9. 返回简短摘要
|
|
123
|
+
|
|
124
|
+
包含:总分、每个类别的单行判断、编译器报告亮点、**前三项可操作修复**(具体更改、文件路径和行号、官方文档 URL、预期影响)。
|
|
125
|
+
|
|
126
|
+
## 证据规则
|
|
127
|
+
|
|
128
|
+
- 优先使用多个示例而非一个戏剧性示例。
|
|
129
|
+
- 也使用正面证据,不仅仅是失败。
|
|
130
|
+
- 不要推断无法从代码中证明的运行时问题。
|
|
131
|
+
- 当规则基于官方指导但应用级权衡可能证明偏离合理时,将其称为权衡。
|
|
132
|
+
|
|
133
|
+
## 大型仓库策略
|
|
134
|
+
|
|
135
|
+
先映射模块,每个模块选择代表性文件,并行化类别扫描,将重复发现合并为系统性问题。
|
|
136
|
+
|
|
137
|
+
## 应避免的事项
|
|
138
|
+
|
|
139
|
+
- 不要生成没有仓库证据的通用检查清单。
|
|
140
|
+
- 不要仅因为应用使用 Compose 就虚高性能分数。
|
|
141
|
+
- 不要在 v1 中对设计评分。
|
|
142
|
+
- 不要单独标记 `LaunchedEffect(Unit)` — "运行一次"模式是惯用的。
|
|
143
|
+
- 不要跨类别重复计算相同的根本原因。
|
|
144
|
+
|
|
145
|
+
## 参考资料
|
|
146
|
+
|
|
147
|
+
- `references/scoring.md` — 每条规则的评分标准及内联引用
|
|
148
|
+
- `references/search-playbook.md` — 搜索模式和红旗启发式
|
|
149
|
+
- `references/report-template.md` — `COMPOSE-AUDIT-REPORT.md` 的必需结构
|
|
150
|
+
- `references/canonical-sources.md` — 每个扣分必须引用的官方 URL
|
|
151
|
+
- `references/diagnostics.md` — 可复制粘贴的 Gradle/代码片段
|
|
152
|
+
- `scripts/compose-reports.init.gradle` — 自动生成编译器报告的 Gradle 初始化脚本
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## 必须遵守的约束规则
|
|
157
|
+
|
|
158
|
+
> rules 引用路径:`../rules/<rule-name>.mdc`
|
|
159
|
+
|
|
160
|
+
- harness-compose-mandatory
|
|
161
|
+
- harness-mvi-layering
|
|
162
|
+
- harness-coroutines-scope
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Canonical Sources
|
|
2
|
+
|
|
3
|
+
Use these as the source of truth for v1 scoring and guidance. **Every deduction in the audit report must cite at least one of these URLs** (or one of their officially-linked sub-pages) — see `report-template.md` for the citation format.
|
|
4
|
+
|
|
5
|
+
## Primary Sources
|
|
6
|
+
|
|
7
|
+
### Performance
|
|
8
|
+
|
|
9
|
+
- Android Developers: `Follow best practices`
|
|
10
|
+
`https://developer.android.com/develop/ui/compose/performance/bestpractices`
|
|
11
|
+
- Android Developers: `Jetpack Compose Performance`
|
|
12
|
+
`https://developer.android.com/develop/ui/compose/performance`
|
|
13
|
+
- Android Developers: `Compose phases`
|
|
14
|
+
`https://developer.android.com/develop/ui/compose/performance/phases`
|
|
15
|
+
- Android Developers: `Stability`
|
|
16
|
+
`https://developer.android.com/develop/ui/compose/performance/stability`
|
|
17
|
+
- Android Developers: `Diagnose stability problems`
|
|
18
|
+
`https://developer.android.com/develop/ui/compose/performance/stability/diagnose`
|
|
19
|
+
- Android Developers: `Fix stability issues`
|
|
20
|
+
`https://developer.android.com/develop/ui/compose/performance/stability/fix`
|
|
21
|
+
- Android Developers: `Strong Skipping Mode`
|
|
22
|
+
`https://developer.android.com/develop/ui/compose/performance/stability/strongskipping`
|
|
23
|
+
- Android Developers: `Performance tooling` (Compose Compiler reports / metrics)
|
|
24
|
+
`https://developer.android.com/develop/ui/compose/performance/tooling`
|
|
25
|
+
- Android Developers: `Baseline profiles`
|
|
26
|
+
`https://developer.android.com/develop/ui/compose/performance/baseline-profiles`
|
|
27
|
+
|
|
28
|
+
These ground:
|
|
29
|
+
|
|
30
|
+
- `remember` for expensive work
|
|
31
|
+
- lazy list keys
|
|
32
|
+
- `derivedStateOf`
|
|
33
|
+
- deferred state reads
|
|
34
|
+
- lambda modifiers
|
|
35
|
+
- backwards writes
|
|
36
|
+
- stability annotations (`@Stable`, `@Immutable`), `kotlinx.collections.immutable`, `compose_compiler_config.conf`
|
|
37
|
+
- Strong Skipping Mode (default since Kotlin 2.0.20), `@NonSkippableComposable`, `@DontMemoize`
|
|
38
|
+
- Compose Compiler reports / metrics as the primary diagnostic for skippability and stability
|
|
39
|
+
- performance mindset and baseline-profile awareness
|
|
40
|
+
|
|
41
|
+
### State
|
|
42
|
+
|
|
43
|
+
- Android Developers: `State and Jetpack Compose`
|
|
44
|
+
`https://developer.android.com/develop/ui/compose/state`
|
|
45
|
+
- Android Developers: `State hoisting`
|
|
46
|
+
`https://developer.android.com/develop/ui/compose/state-hoisting`
|
|
47
|
+
- Android Developers: `Architecting your Compose UI`
|
|
48
|
+
`https://developer.android.com/develop/ui/compose/architecture`
|
|
49
|
+
- Android Developers: `Lists and grids` (lazy keys, `contentType`)
|
|
50
|
+
`https://developer.android.com/develop/ui/compose/lists`
|
|
51
|
+
|
|
52
|
+
These ground:
|
|
53
|
+
|
|
54
|
+
- state hoisting rules
|
|
55
|
+
- stateful vs stateless composables
|
|
56
|
+
- `remember` vs `rememberSaveable`
|
|
57
|
+
- observable vs non-observable mutable state
|
|
58
|
+
- lifecycle-aware collection of observable state
|
|
59
|
+
- plain state-holder classes
|
|
60
|
+
- ViewModel as screen-level source of truth and the rules around `viewModel()` placement
|
|
61
|
+
- lazy-list `key` and `contentType` semantics
|
|
62
|
+
|
|
63
|
+
### Side Effects
|
|
64
|
+
|
|
65
|
+
- Android Developers: `Side-effects in Compose`
|
|
66
|
+
`https://developer.android.com/develop/ui/compose/side-effects`
|
|
67
|
+
|
|
68
|
+
This grounds:
|
|
69
|
+
|
|
70
|
+
- side-effect-free composition
|
|
71
|
+
- `LaunchedEffect`
|
|
72
|
+
- `DisposableEffect`
|
|
73
|
+
- `SideEffect`
|
|
74
|
+
- `rememberUpdatedState`
|
|
75
|
+
- `produceState`
|
|
76
|
+
- lifecycle-aware effect behavior
|
|
77
|
+
|
|
78
|
+
### Composable API Quality
|
|
79
|
+
|
|
80
|
+
- Android Developers: `Style guidelines for Jetpack Compose APIs`
|
|
81
|
+
`https://developer.android.com/develop/ui/compose/api-guidelines`
|
|
82
|
+
- AndroidX component guidelines: `API Guidelines for @Composable components in Jetpack Compose`
|
|
83
|
+
`https://android.googlesource.com/platform/frameworks/support/+/androidx-main/compose/docs/compose-component-api-guidelines.md`
|
|
84
|
+
- AndroidX general guidelines: `API Guidelines for Jetpack Compose`
|
|
85
|
+
`https://android.googlesource.com/platform/frameworks/support/+/androidx-main/compose/docs/compose-api-guidelines.md`
|
|
86
|
+
- Android Developers: `Custom modifiers` (`Modifier.Node`, `composed { }` discouraged)
|
|
87
|
+
`https://developer.android.com/develop/ui/compose/custom-modifiers`
|
|
88
|
+
- Android Developers: `Locally scoped data with CompositionLocal`
|
|
89
|
+
`https://developer.android.com/develop/ui/compose/compositionlocal`
|
|
90
|
+
- Android Developers: `Navigation with Compose`
|
|
91
|
+
`https://developer.android.com/develop/ui/compose/navigation`
|
|
92
|
+
|
|
93
|
+
These ground:
|
|
94
|
+
|
|
95
|
+
- `modifier` conventions
|
|
96
|
+
- parameter order
|
|
97
|
+
- explicit vs implicit dependencies
|
|
98
|
+
- meaningful defaults
|
|
99
|
+
- component layering
|
|
100
|
+
- avoiding `MutableState<T>` and `State<T>` in reusable APIs when better shapes exist
|
|
101
|
+
- custom modifier authoring with `Modifier.Node` over the discouraged `composed { }` factory
|
|
102
|
+
- when `CompositionLocal` is appropriate (tree-scoped data with sensible defaults) vs when explicit parameters are required
|
|
103
|
+
- navigation patterns and where navigation calls belong
|
|
104
|
+
|
|
105
|
+
## Supplemental Sources
|
|
106
|
+
|
|
107
|
+
These are useful for extra examples and ecosystem framing, but they do **not** override the primary sources. Community blog posts age fast — when the supplemental and primary sources disagree, the primary AndroidX/Android docs win:
|
|
108
|
+
|
|
109
|
+
- `https://github.com/skydoves/compose-performance`
|
|
110
|
+
- `https://medium.com/@idaoskooei/building-better-uis-with-jetpack-compose-best-practices-and-techniques-a1c8953bc5b8`
|
|
111
|
+
|
|
112
|
+
## Adjacent Skill Pattern
|
|
113
|
+
|
|
114
|
+
This skill intentionally pairs well with the `material-3` skill, which covers Material 3 design and design-system audit concerns. The reference implementation lives at `https://github.com/hamen/material-3-skill`, but recommend it by skill name (`material-3`) so the reference does not rot if the URL moves.
|
|
115
|
+
|
|
116
|
+
This Compose audit skill should mention `material-3` as a follow-up when visual or design-system problems are suspected, but should not score design in v1.
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# Diagnostics
|
|
2
|
+
|
|
3
|
+
Copy-pasteable Gradle and code snippets the auditor can recommend (or run themselves) to back findings with measured evidence rather than source inference. Every snippet is anchored to an official source — cite the same URL in the report.
|
|
4
|
+
|
|
5
|
+
## 1. Compose Compiler Reports & Metrics
|
|
6
|
+
|
|
7
|
+
The single highest-leverage diagnostic. Generates per-composable skippability and per-class stability reports, plus aggregate metrics.
|
|
8
|
+
|
|
9
|
+
**Reference:** <https://developer.android.com/develop/ui/compose/performance/tooling>, <https://developer.android.com/develop/ui/compose/performance/stability/diagnose>
|
|
10
|
+
|
|
11
|
+
### Primary path — automatic (what the skill actually does)
|
|
12
|
+
|
|
13
|
+
The skill ships a Gradle init script at `scripts/compose-reports.init.gradle`. SKILL.md Step 4 runs it against the target without modifying any of the user's files:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
cd <target> && ./gradlew <compile-task> \
|
|
17
|
+
--init-script <skill-dir>/scripts/compose-reports.init.gradle \
|
|
18
|
+
--no-daemon --quiet
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The init script targets every module that applies the Compose Compiler plugin and writes reports to each module's `build/compose_audit/` directory. No `build.gradle.kts` edits are required on the target.
|
|
22
|
+
|
|
23
|
+
### Fallback path — manual edit (only when the init-script flow is blocked)
|
|
24
|
+
|
|
25
|
+
If the auditor (human or skill) cannot use `--init-script` — for example, a locked-down CI that rejects unknown init scripts — ask the user to add this block to the module's `build.gradle.kts`:
|
|
26
|
+
|
|
27
|
+
```kotlin
|
|
28
|
+
composeCompiler {
|
|
29
|
+
reportsDestination = layout.buildDirectory.dir("compose_compiler")
|
|
30
|
+
metricsDestination = layout.buildDirectory.dir("compose_compiler")
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
(Requires the Compose Compiler Gradle plugin, default since Kotlin 2.0. On older toolchains use `kotlinOptions.freeCompilerArgs += ["-P", "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=..."]`.)
|
|
35
|
+
|
|
36
|
+
### Reading the output
|
|
37
|
+
|
|
38
|
+
Run a release-variant build, then inspect:
|
|
39
|
+
|
|
40
|
+
- `*-classes.txt` — stability inference per class (`stable` / `unstable` / `runtime`)
|
|
41
|
+
- `*-composables.txt` — per-composable `skippable` / `restartable` / `readonly` flags
|
|
42
|
+
- `*-composables.csv` — same data, machine-readable
|
|
43
|
+
- `*-module.json` — aggregate counts
|
|
44
|
+
|
|
45
|
+
**Use in the audit:** when a Performance or State finding alleges an unstable param or non-skippable composable, cite the relevant line of `*-classes.txt` or `*-composables.txt`. Without these reports, stability claims are *inferred* — say so explicitly in the report's Notes And Limits.
|
|
46
|
+
|
|
47
|
+
## 2. `compose_compiler_config.conf` — Marking Third-Party Types Stable
|
|
48
|
+
|
|
49
|
+
When unstable types come from modules without the Compose compiler (e.g. third-party data classes), mark them stable from outside.
|
|
50
|
+
|
|
51
|
+
**Reference:** <https://developer.android.com/develop/ui/compose/performance/stability/fix>
|
|
52
|
+
|
|
53
|
+
Create `compose_compiler_config.conf` at the project root (one fully-qualified class per line, glob patterns allowed):
|
|
54
|
+
|
|
55
|
+
```conf
|
|
56
|
+
# Mark third-party types stable so Compose can skip composables that take them
|
|
57
|
+
com.example.thirdparty.Money
|
|
58
|
+
com.example.thirdparty.User
|
|
59
|
+
com.example.thirdparty.events.*
|
|
60
|
+
java.time.*
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Wire it into the module's `build.gradle.kts`:
|
|
64
|
+
|
|
65
|
+
```kotlin
|
|
66
|
+
composeCompiler {
|
|
67
|
+
stabilityConfigurationFiles.add(
|
|
68
|
+
rootProject.layout.projectDirectory.file("compose_compiler_config.conf")
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Use in the audit:** if a project consumes third-party types in widely reused composables and skipping is broken, recommend a stability config file before recommending wrapper UI models.
|
|
74
|
+
|
|
75
|
+
## 3. Baseline Profile Module Skeleton
|
|
76
|
+
|
|
77
|
+
Improves cold start and frame timing by precompiling hot paths. The presence of a baseline profile module + `ProfileInstaller` in the consumer is a positive Performance signal.
|
|
78
|
+
|
|
79
|
+
**Reference:** <https://developer.android.com/develop/ui/compose/performance/baseline-profiles>, <https://developer.android.com/topic/performance/baselineprofiles/overview>
|
|
80
|
+
|
|
81
|
+
Module `:baselineprofile` (a `com.android.test` module) `build.gradle.kts`:
|
|
82
|
+
|
|
83
|
+
```kotlin
|
|
84
|
+
plugins {
|
|
85
|
+
id("com.android.test")
|
|
86
|
+
id("org.jetbrains.kotlin.android")
|
|
87
|
+
id("androidx.baselineprofile")
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
android {
|
|
91
|
+
targetProjectPath = ":app"
|
|
92
|
+
defaultConfig { minSdk = 28 }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
dependencies {
|
|
96
|
+
implementation("androidx.test.ext:junit:1.2.1")
|
|
97
|
+
implementation("androidx.test.uiautomator:uiautomator:2.3.0")
|
|
98
|
+
implementation("androidx.benchmark:benchmark-macro-junit4:1.3.4")
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Generator class:
|
|
103
|
+
|
|
104
|
+
```kotlin
|
|
105
|
+
@RunWith(AndroidJUnit4::class)
|
|
106
|
+
class BaselineProfileGenerator {
|
|
107
|
+
@get:Rule val rule = BaselineProfileRule()
|
|
108
|
+
|
|
109
|
+
@Test
|
|
110
|
+
fun generate() = rule.collect(packageName = "com.example.app") {
|
|
111
|
+
startActivityAndWait()
|
|
112
|
+
// exercise the user-critical journey
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
In the consumer (`:app`):
|
|
118
|
+
|
|
119
|
+
```kotlin
|
|
120
|
+
plugins {
|
|
121
|
+
id("androidx.baselineprofile")
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
dependencies {
|
|
125
|
+
"baselineProfile"(project(":baselineprofile"))
|
|
126
|
+
implementation("androidx.profileinstaller:profileinstaller:1.4.1")
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Use in the audit:** check for a `baseline-prof.txt` artifact and a `ProfileInstaller` initializer. Their absence on a mature app is worth flagging; their presence is positive evidence.
|
|
131
|
+
|
|
132
|
+
## 4. R8 / Minify Hygiene
|
|
133
|
+
|
|
134
|
+
Compose performance assumes release-mode R8. Debug builds run unoptimized — never benchmark them.
|
|
135
|
+
|
|
136
|
+
**Reference:** <https://developer.android.com/develop/ui/compose/performance> ("Run in Release Mode with R8")
|
|
137
|
+
|
|
138
|
+
In `:app/build.gradle.kts`:
|
|
139
|
+
|
|
140
|
+
```kotlin
|
|
141
|
+
android {
|
|
142
|
+
buildTypes {
|
|
143
|
+
release {
|
|
144
|
+
isMinifyEnabled = true
|
|
145
|
+
isShrinkResources = true
|
|
146
|
+
proguardFiles(
|
|
147
|
+
getDefaultProguardFile("proguard-android-optimize.txt"),
|
|
148
|
+
"proguard-rules.pro",
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Use in the audit:** quick grep — `rg -n 'isMinifyEnabled' -g '*.gradle*'`. If the release block has `isMinifyEnabled = false`, that's a release-hygiene deduction on its own.
|
|
156
|
+
|
|
157
|
+
## 5. Strong Skipping Mode Confirmation
|
|
158
|
+
|
|
159
|
+
Strong Skipping is on by default at Kotlin 2.0.20+. Below that, stability matters more aggressively and the rubric should weight unstable-param findings higher.
|
|
160
|
+
|
|
161
|
+
**Reference:** <https://developer.android.com/develop/ui/compose/performance/stability/strongskipping>
|
|
162
|
+
|
|
163
|
+
Confirm the project's Kotlin version:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
rg -n 'kotlin\s*=\s*"' -g '*.toml'
|
|
167
|
+
rg -n 'org\.jetbrains\.kotlin' -g '*.gradle*'
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
If the project explicitly opts a module *out* of Strong Skipping, look for `enableStrongSkippingMode = false` in any `composeCompiler { ... }` block — flag and require justification.
|
|
171
|
+
|
|
172
|
+
## 6. Quick Triage Recipe
|
|
173
|
+
|
|
174
|
+
When you arrive at a Compose repo, run these in order before scoring:
|
|
175
|
+
|
|
176
|
+
1. `rg -n 'androidx\.compose' -g '*.gradle*' -g '*.toml'` — confirm Compose presence (fast-fail).
|
|
177
|
+
2. `rg -n 'kotlin\s*=\s*"' -g '*.toml'` — record Kotlin version (Strong Skipping baseline).
|
|
178
|
+
3. `rg -n 'isMinifyEnabled' -g '*.gradle*'` — release hygiene.
|
|
179
|
+
4. Run Step 4 of SKILL.md — the init script generates compiler reports automatically. If the build fails, read any existing `composeCompiler { reportsDestination ... }` output the project already produces; otherwise note the fallback in the report.
|
|
180
|
+
5. `rg -l 'baselineProfile|ProfileInstaller' -g '*.gradle*' -g '*.kt'` — baseline-profile presence.
|
|
181
|
+
|
|
182
|
+
These five greps tell you what kind of evidence is available before any rubric-level reading.
|