@mmerterden/multi-agent-pipeline 20.0.0 → 20.2.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/CHANGELOG.md +55 -0
- package/README.md +5 -5
- package/README.tr.md +5 -5
- package/SECURITY.md +3 -3
- package/docs/adr/0011-dormant-ci.md +10 -1
- package/docs/architecture.md +2 -2
- package/docs/ecosystem.md +5 -5
- package/docs/facts.json +8 -7
- package/install/_codex-agents.mjs +1 -1
- package/manifest.json +92 -64
- package/package.json +1 -1
- package/pipeline/agents/code-reviewer.md +2 -2
- package/pipeline/agents/dev-critic.md +5 -5
- package/pipeline/agents/security-auditor.md +80 -72
- package/pipeline/commands/figma-to-swiftui.md +1 -1
- package/pipeline/commands/multi-agent/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/channels/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/diff-explain/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/help/SKILL.md +2 -0
- package/pipeline/commands/multi-agent/scan/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/security-review/SKILL.md +52 -0
- package/pipeline/commands/multi-agent/sync/SKILL.md +3 -3
- package/pipeline/multi-agent-refs/component-dispatch.md +5 -5
- package/pipeline/multi-agent-refs/cross-cli-contract.md +6 -6
- package/pipeline/multi-agent-refs/features/security-audit.md +55 -0
- package/pipeline/multi-agent-refs/phases/modes.md +1 -1
- package/pipeline/multi-agent-refs/phases/phase-3-review.md +9 -15
- package/pipeline/multi-agent-refs/phases/phase-5-report.md +1 -1
- package/pipeline/multi-agent-refs/threat-model.md +39 -0
- package/pipeline/schemas/agent-state.schema.json +23 -0
- package/pipeline/schemas/phases.json +1 -2
- package/pipeline/schemas/prefs.schema.json +0 -4
- package/pipeline/schemas/reviewer-output.schema.json +99 -2
- package/pipeline/schemas/security-finding.schema.json +144 -0
- package/pipeline/scripts/_stack-routing.mjs +1 -0
- package/pipeline/scripts/gc-abandoned.sh +16 -9
- package/pipeline/scripts/render-work-summary.sh +7 -4
- package/pipeline/skills/.skill-manifest.json +47 -23
- package/pipeline/skills/.skills-index.json +75 -9
- package/pipeline/skills/shared/README.md +13 -7
- package/pipeline/skills/shared/core/multi-agent/SKILL.md +3 -4
- package/pipeline/skills/shared/core/multi-agent-scan/SKILL.md +2 -2
- package/pipeline/skills/shared/core/multi-agent-security-review/SKILL.md +29 -0
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +3 -3
- package/pipeline/skills/shared/external/android-architecture/SKILL.md +71 -0
- package/pipeline/skills/shared/external/android-architecture/references/patterns.md +142 -0
- package/pipeline/skills/shared/external/android-build-quality-gates/SKILL.md +314 -0
- package/pipeline/skills/shared/external/android-build-quality-gates/references/patterns.md +432 -0
- package/pipeline/skills/shared/external/android-datastore/SKILL.md +236 -0
- package/pipeline/skills/shared/external/android-datastore/references/patterns.md +297 -0
- package/pipeline/skills/shared/external/android-design-tokens-codegen/SKILL.md +249 -0
- package/pipeline/skills/shared/external/android-design-tokens-codegen/references/patterns.md +270 -0
- package/pipeline/skills/shared/external/android-jetpack-compose-expert/SKILL.md +62 -0
- package/pipeline/skills/shared/external/android-mvi-viewmodel/SKILL.md +255 -0
- package/pipeline/skills/shared/external/android-mvi-viewmodel/references/patterns.md +257 -0
- package/pipeline/skills/shared/external/android-performance/SKILL.md +86 -602
- package/pipeline/skills/shared/external/android-performance/references/patterns.md +659 -0
- package/pipeline/skills/shared/external/android-security/SKILL.md +117 -430
- package/pipeline/skills/shared/external/android-security/references/patterns.md +690 -0
- package/pipeline/skills/shared/external/{android_ui_verification → android-ui-verification}/SKILL.md +1 -1
- package/pipeline/skills/shared/external/api-security-best-practices/SKILL.md +35 -733
- package/pipeline/skills/shared/external/api-security-best-practices/references/auth.md +299 -0
- package/pipeline/skills/shared/external/api-security-best-practices/references/input-validation.md +255 -0
- package/pipeline/skills/shared/external/api-security-best-practices/references/rate-limiting.md +167 -0
- package/pipeline/skills/shared/external/app-intents/SKILL.md +39 -174
- package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +178 -0
- package/pipeline/skills/shared/external/compose-components/SKILL.md +48 -0
- package/pipeline/skills/shared/external/compose-components/references/patterns.md +200 -0
- package/pipeline/skills/shared/external/compose-navigation/SKILL.md +66 -3
- package/pipeline/skills/shared/external/compose-navigation/references/patterns.md +191 -0
- package/pipeline/skills/shared/external/compose-testing/SKILL.md +107 -397
- package/pipeline/skills/shared/external/compose-testing/references/patterns.md +631 -0
- package/pipeline/skills/shared/external/gradle-kotlin-dsl/SKILL.md +121 -449
- package/pipeline/skills/shared/external/gradle-kotlin-dsl/references/patterns.md +715 -0
- package/pipeline/skills/shared/external/kotlin-coroutines-expert/SKILL.md +143 -0
- package/pipeline/skills/shared/external/mapkit-location/SKILL.md +27 -102
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +42 -0
- package/pipeline/skills/shared/external/retrofit-networking/SKILL.md +94 -383
- package/pipeline/skills/shared/external/retrofit-networking/references/patterns.md +640 -0
- package/pipeline/skills/shared/external/room-database/SKILL.md +101 -440
- package/pipeline/skills/shared/external/room-database/references/patterns.md +614 -0
- package/pipeline/skills/shared/external/security-review/SKILL.md +64 -0
- package/pipeline/skills/shared/external/security-review/references/owasp-mobile-top10-2024.md +53 -0
- package/pipeline/skills/shared/external/security-review/references/owasp-web-api-top10-2021.md +56 -0
- package/pipeline/skills/shared/external/storekit/SKILL.md +69 -343
- package/pipeline/skills/shared/external/storekit/references/core-patterns.md +371 -0
- package/pipeline/skills/shared/external/widgetkit/SKILL.md +25 -101
- package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +107 -0
- package/pipeline/skills/skills-index.md +8 -2
- package/pipeline/commands/security-review.md +0 -6
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: android-build-quality-gates
|
|
3
|
+
description: "Encode Android module and quality rules as build-failing Gradle tasks: layer-dependency checks, coverage floors, a Compose-stability gate, lint-on-diff and screenshot validation. Use when a multi-module app needs enforceable boundaries and quality gates in the build, not in review."
|
|
4
|
+
risk: safe
|
|
5
|
+
source: multi-agent-pipeline
|
|
6
|
+
date_added: "2026-09-21"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Android Build Quality Gates
|
|
10
|
+
|
|
11
|
+
A convention holds only while everyone remembers it. A gate holds because the
|
|
12
|
+
build turns red without it. This skill covers the quality rules worth promoting
|
|
13
|
+
from review comments into Gradle tasks that fail: layer boundaries, coverage
|
|
14
|
+
floors, Compose stability, lint on changed files, and screenshot validation.
|
|
15
|
+
|
|
16
|
+
Targets AGP 8.x, Gradle 8.x with the configuration cache, Kover 0.8+, and the
|
|
17
|
+
Compose compiler Gradle plugin (Kotlin 2.0+). Copy-ready, full-length code for
|
|
18
|
+
every gate lives in [references/patterns.md](references/patterns.md); this file
|
|
19
|
+
carries the decisions and short snippets.
|
|
20
|
+
|
|
21
|
+
## Contents
|
|
22
|
+
|
|
23
|
+
- [Where gates live](#where-gates-live)
|
|
24
|
+
- [Layer-dependency gate](#layer-dependency-gate)
|
|
25
|
+
- [Coverage floor with Kover](#coverage-floor-with-kover)
|
|
26
|
+
- [Compose-stability gate](#compose-stability-gate)
|
|
27
|
+
- [Lint on diff](#lint-on-diff)
|
|
28
|
+
- [Screenshot validation task](#screenshot-validation-task)
|
|
29
|
+
- [Ratchet, do not wall](#ratchet-do-not-wall)
|
|
30
|
+
- [Wiring gates into check](#wiring-gates-into-check)
|
|
31
|
+
- [Do's and Don'ts](#dos-and-donts)
|
|
32
|
+
- [Review Checklist](#review-checklist)
|
|
33
|
+
|
|
34
|
+
## Where gates live
|
|
35
|
+
|
|
36
|
+
Author gates once in a convention plugin under `build-logic`, then apply that
|
|
37
|
+
plugin from each module. A gate copied into twenty `build.gradle.kts` files
|
|
38
|
+
drifts; a gate in one convention plugin is a single source of truth. See
|
|
39
|
+
`gradle-kotlin-dsl` for how the `build-logic` module and version catalog are
|
|
40
|
+
set up; this skill only adds tasks inside it.
|
|
41
|
+
|
|
42
|
+
Every gate follows the same three-part shape:
|
|
43
|
+
|
|
44
|
+
1. A task (or a `verify`/`check`-typed configuration) that computes a fact about
|
|
45
|
+
the module: its dependency set, its coverage ratio, its unskippable
|
|
46
|
+
composables.
|
|
47
|
+
2. An assertion that throws `GradleException` when the fact violates the rule.
|
|
48
|
+
3. A wire into the `check` lifecycle (or a `finalizedBy` on an existing task) so
|
|
49
|
+
it runs without anyone remembering to call it.
|
|
50
|
+
|
|
51
|
+
Keep the assertion message actionable: name the offending dependency, the
|
|
52
|
+
current versus required number, the exact composable. A gate that fails with
|
|
53
|
+
"verification failed" gets suppressed; one that says "module `feature-x` depends
|
|
54
|
+
on `data-y`, which is not in its allowed set" gets fixed.
|
|
55
|
+
|
|
56
|
+
## Layer-dependency gate
|
|
57
|
+
|
|
58
|
+
Clean layering (feature -> domain -> data, never feature -> data directly, never
|
|
59
|
+
domain -> feature) is the rule most often stated and least often enforced. Encode
|
|
60
|
+
it by walking a module's resolved project dependencies and asserting each is in
|
|
61
|
+
an allowed set for that module's layer.
|
|
62
|
+
|
|
63
|
+
Register a task that reads the `implementation`/`api` configurations, keeps only
|
|
64
|
+
`ProjectDependency` entries, and compares their paths against an allowlist:
|
|
65
|
+
|
|
66
|
+
```kotlin
|
|
67
|
+
val checkLayerDependencies by tasks.registering {
|
|
68
|
+
group = "verification"
|
|
69
|
+
val layer = project.moduleLayer()
|
|
70
|
+
val projectDeps = configurations
|
|
71
|
+
.matching { it.name in setOf("implementation", "api") }
|
|
72
|
+
.flatMap { it.dependencies.withType<ProjectDependency>() }
|
|
73
|
+
.map { it.path }
|
|
74
|
+
doLast {
|
|
75
|
+
val forbidden = projectDeps.filterNot { layer.allows(it) }
|
|
76
|
+
if (forbidden.isNotEmpty()) {
|
|
77
|
+
throw GradleException(
|
|
78
|
+
"$path ($layer) declares forbidden dependencies: $forbidden"
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
tasks.named("check").configure { dependsOn(checkLayerDependencies) }
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Derive the layer from the module path or a convention (`feature-*`, `domain-*`,
|
|
87
|
+
`data-*`) rather than a hand-maintained map, so a new module is governed the day
|
|
88
|
+
it is created. The full version, including the layer enum, its `allows` matrix,
|
|
89
|
+
and configuration-cache-safe capture of dependency paths, is in
|
|
90
|
+
[references/patterns.md#layer-dependency-gate](references/patterns.md#layer-dependency-gate).
|
|
91
|
+
|
|
92
|
+
Read dependency paths at configuration time into a local (as above), not inside
|
|
93
|
+
`doLast` off the live `configurations` object, so the task stays compatible with
|
|
94
|
+
the configuration cache.
|
|
95
|
+
|
|
96
|
+
## Coverage floor with Kover
|
|
97
|
+
|
|
98
|
+
A coverage number nobody enforces only decorates a report. Kover's verification
|
|
99
|
+
rule turns it into a gate: below the floor, the build fails.
|
|
100
|
+
|
|
101
|
+
Apply `org.jetbrains.kotlinx.kover` and declare a bound:
|
|
102
|
+
|
|
103
|
+
```kotlin
|
|
104
|
+
kover {
|
|
105
|
+
reports {
|
|
106
|
+
verify {
|
|
107
|
+
rule("Line coverage floor") {
|
|
108
|
+
minBound(60)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Split instrumentation from aggregation. Each module applies the Kover plugin so
|
|
116
|
+
its own classes are instrumented; a single aggregation module (or the root)
|
|
117
|
+
depends on every measured module and owns the `verify` rule over the merged
|
|
118
|
+
report. Verifying per module produces noisy, uneven thresholds; verifying the
|
|
119
|
+
aggregate gives one honest project number. The aggregation wiring and per-module
|
|
120
|
+
exclusion of generated code (`*_Factory`, `*Args`, `BuildConfig`, Hilt
|
|
121
|
+
components) are in
|
|
122
|
+
[references/patterns.md#coverage-floor-with-kover](references/patterns.md#coverage-floor-with-kover).
|
|
123
|
+
|
|
124
|
+
Gate the floor behind a property so local `assembleDebug` stays fast and only CI
|
|
125
|
+
(or an explicit run) pays for instrumented coverage:
|
|
126
|
+
|
|
127
|
+
```kotlin
|
|
128
|
+
tasks.named("check").configure {
|
|
129
|
+
if (providers.gradleProperty("enableCoverageVerification").isPresent) {
|
|
130
|
+
dependsOn("koverVerify")
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Run it in CI with `-PenableCoverageVerification`. Set the floor to the current
|
|
136
|
+
measured value, not an aspirational one; see [Ratchet, do not wall](#ratchet-do-not-wall).
|
|
137
|
+
|
|
138
|
+
## Compose-stability gate
|
|
139
|
+
|
|
140
|
+
Unstable parameters silently defeat recomposition skipping and cause jank that
|
|
141
|
+
no unit test catches. The Compose compiler can emit a stability report; parse it
|
|
142
|
+
and fail when a composable that should skip cannot.
|
|
143
|
+
|
|
144
|
+
First point the compiler's metrics and reports at a build directory via the
|
|
145
|
+
Compose compiler Gradle plugin:
|
|
146
|
+
|
|
147
|
+
```kotlin
|
|
148
|
+
composeCompiler {
|
|
149
|
+
val dir = layout.buildDirectory.dir("compose-metrics")
|
|
150
|
+
metricsDestination.set(dir)
|
|
151
|
+
reportsDestination.set(dir)
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
This produces `*-composables.txt` per module. Register a task that parses those
|
|
156
|
+
files, collects every `restartable` composable marked `skippable` as its
|
|
157
|
+
negation (i.e. the `restartable` but NOT `skippable` ones), and fails on any that
|
|
158
|
+
is not in a per-module ignore-list. Finalize each Kotlin compile with it so the
|
|
159
|
+
report is always fresh:
|
|
160
|
+
|
|
161
|
+
```kotlin
|
|
162
|
+
val checkComposeStability by tasks.registering(ComposeStabilityCheck::class) {
|
|
163
|
+
reportDir.set(layout.buildDirectory.dir("compose-metrics"))
|
|
164
|
+
ignoreFile.set(layout.projectDirectory.file("compose-stability-ignore.txt"))
|
|
165
|
+
}
|
|
166
|
+
tasks.withType<KotlinCompile>().configureEach {
|
|
167
|
+
finalizedBy(checkComposeStability)
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The ignore-list file holds fully-qualified composable names that are accepted
|
|
172
|
+
exceptions (a composable that takes a third-party unstable type you cannot
|
|
173
|
+
annotate). Each line is one accepted composable; anything unskippable and not
|
|
174
|
+
listed fails the build. The full `ComposeStabilityCheck` task with the report
|
|
175
|
+
parser and ignore-list matching is in
|
|
176
|
+
[references/patterns.md#compose-stability-gate](references/patterns.md#compose-stability-gate).
|
|
177
|
+
|
|
178
|
+
The report is only emitted when the compiler runs, which is why the check is
|
|
179
|
+
`finalizedBy` the compile rather than a standalone task: a cached compile with no
|
|
180
|
+
report means nothing changed, and the check reads the last report.
|
|
181
|
+
|
|
182
|
+
## Lint on diff
|
|
183
|
+
|
|
184
|
+
Full lint across a large multi-module project is minutes of wall time; running it
|
|
185
|
+
on every commit trains people to skip the hook. Split it: a fast pre-commit gate
|
|
186
|
+
over only the changed files, and full analysis in CI.
|
|
187
|
+
|
|
188
|
+
At commit time, feed the static analyzer (detekt or Android Lint) the diff:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
CHANGED=$(git diff --cached --name-only --diff-filter=d -- '*.kt' '*.kts')
|
|
192
|
+
[ -z "$CHANGED" ] && exit 0
|
|
193
|
+
./gradlew detektDiff -PdetektInput="$CHANGED"
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Wire `detektDiff` to accept a file list and set the detekt `source` to just those
|
|
197
|
+
paths, so the analyzer never walks the whole tree at commit time. In CI, run the
|
|
198
|
+
full `detekt` / `lint` task with the baseline so nothing escapes. The pre-commit
|
|
199
|
+
hook and the `detektDiff` task definition are in
|
|
200
|
+
[references/patterns.md#lint-on-diff](references/patterns.md#lint-on-diff).
|
|
201
|
+
|
|
202
|
+
Keep the two consistent: the same ruleset and the same baseline file drive both
|
|
203
|
+
the diff run and the full run, so a commit that passes the hook does not surprise
|
|
204
|
+
the author in CI.
|
|
205
|
+
|
|
206
|
+
## Screenshot validation task
|
|
207
|
+
|
|
208
|
+
Screenshot tests are only a gate when a mismatch fails the build. Author the
|
|
209
|
+
tests with the mechanics in `compose-testing`; here, register the verification
|
|
210
|
+
task and put it on the `check` path.
|
|
211
|
+
|
|
212
|
+
Expose a single umbrella task so CI and local calls agree:
|
|
213
|
+
|
|
214
|
+
```kotlin
|
|
215
|
+
tasks.register("verifyScreenshots") {
|
|
216
|
+
group = "verification"
|
|
217
|
+
dependsOn(tasks.matching { it.name == "verifyRoborazziDebug" })
|
|
218
|
+
}
|
|
219
|
+
tasks.named("check").configure { dependsOn("verifyScreenshots") }
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Record and verify are separate entry points: `recordScreenshots` regenerates
|
|
223
|
+
golden images (run deliberately, reviewed in the diff), `verifyScreenshots`
|
|
224
|
+
compares and fails. Never let `verify` fall back to recording on a missing
|
|
225
|
+
golden, or the gate passes on the very case it exists to catch. The record/verify
|
|
226
|
+
task pair and the CI upload of diff images on failure are in
|
|
227
|
+
[references/patterns.md#screenshot-validation-task](references/patterns.md#screenshot-validation-task).
|
|
228
|
+
|
|
229
|
+
## Ratchet, do not wall
|
|
230
|
+
|
|
231
|
+
The failure mode of every gate above is the same: set the bar higher than the
|
|
232
|
+
codebase currently clears, and the team disables the gate instead of meeting it.
|
|
233
|
+
A gate that is always red is worse than no gate, because it also hides the
|
|
234
|
+
regressions it was meant to catch.
|
|
235
|
+
|
|
236
|
+
Seed each gate at the current state and let it only tighten:
|
|
237
|
+
|
|
238
|
+
- Coverage: set `minBound` to the value measured today, then raise it in small
|
|
239
|
+
steps as tests land. Never open at a round aspirational number.
|
|
240
|
+
- Compose stability: seed the ignore-list with every composable currently
|
|
241
|
+
unskippable, so the gate passes on day one and only new offenders fail. Shrink
|
|
242
|
+
the list over time; adding to it needs review.
|
|
243
|
+
- Lint: generate a baseline of existing findings; the gate fails only on new
|
|
244
|
+
ones. Regenerating the baseline to bury a fresh finding is a review smell.
|
|
245
|
+
- Layers: if a forbidden edge exists today, either fix it before turning the gate
|
|
246
|
+
on, or record it as a temporary allowed exception with a tracking reference,
|
|
247
|
+
never widen the whole allow-matrix.
|
|
248
|
+
|
|
249
|
+
A ceiling that only moves down (ignore-lists, baselines) and a floor that only
|
|
250
|
+
moves up (coverage) is the shape that survives contact with a real team.
|
|
251
|
+
|
|
252
|
+
## Wiring gates into check
|
|
253
|
+
|
|
254
|
+
Gates that are not on a lifecycle path do not run. Attach each to `check` (or a
|
|
255
|
+
custom `qualityGates` aggregate task that `check` depends on) so a single
|
|
256
|
+
`./gradlew check` runs every gate, and CI needs no bespoke task list.
|
|
257
|
+
|
|
258
|
+
```kotlin
|
|
259
|
+
val qualityGates by tasks.registering {
|
|
260
|
+
group = "verification"
|
|
261
|
+
dependsOn(
|
|
262
|
+
"checkLayerDependencies",
|
|
263
|
+
"checkComposeStability",
|
|
264
|
+
"verifyScreenshots",
|
|
265
|
+
)
|
|
266
|
+
}
|
|
267
|
+
tasks.named("check").configure { dependsOn(qualityGates) }
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Keep the expensive, environment-dependent gates (instrumented coverage, full
|
|
271
|
+
lint) behind properties so `check` stays usable locally, and turn them on in CI
|
|
272
|
+
via `-P` flags. The full convention-plugin assembly that registers all gates is
|
|
273
|
+
in [references/patterns.md#wiring-gates-into-check](references/patterns.md#wiring-gates-into-check).
|
|
274
|
+
|
|
275
|
+
## Do's and Don'ts
|
|
276
|
+
|
|
277
|
+
- Do author every gate in a `build-logic` convention plugin, applied per module.
|
|
278
|
+
- Do make failure messages name the offender, the actual value, and the required
|
|
279
|
+
value.
|
|
280
|
+
- Do capture configuration values (dependency paths, file lists) into locals at
|
|
281
|
+
configuration time for configuration-cache compatibility.
|
|
282
|
+
- Do seed ignore-lists and baselines from the current state so the gate opens
|
|
283
|
+
green.
|
|
284
|
+
- Don't verify coverage per module; aggregate, then verify once.
|
|
285
|
+
- Don't let a screenshot `verify` task record missing goldens.
|
|
286
|
+
- Don't set a floor above what the code clears today; a permanently red gate gets
|
|
287
|
+
switched off.
|
|
288
|
+
- Don't duplicate the gate logic across module build files.
|
|
289
|
+
- Don't run full lint at commit time; run it on the diff, full in CI.
|
|
290
|
+
|
|
291
|
+
## Ownership Map
|
|
292
|
+
|
|
293
|
+
This skill owns build-failing quality-gate tasks. It does not re-explain:
|
|
294
|
+
|
|
295
|
+
- Typed `BuildConfig`, convention-plugin composition, version catalog, and
|
|
296
|
+
general build setup -> `gradle-kotlin-dsl`.
|
|
297
|
+
- Authoring Compose screenshot tests, semantic matchers, and ViewModel tests ->
|
|
298
|
+
`compose-testing` (this skill only registers the verification task).
|
|
299
|
+
- Codegen `--check` CI verification of generated design-token sources ->
|
|
300
|
+
`android-design-tokens-codegen`.
|
|
301
|
+
|
|
302
|
+
## Review Checklist
|
|
303
|
+
|
|
304
|
+
- [ ] Each gate lives in a convention plugin, not copied per module.
|
|
305
|
+
- [ ] Layer gate derives layer from convention, governs new modules automatically.
|
|
306
|
+
- [ ] Coverage uses a single aggregation report with one `verify` bound, gated by
|
|
307
|
+
a property.
|
|
308
|
+
- [ ] Compose stability report points at a build dir, check is `finalizedBy` the
|
|
309
|
+
compile, ignore-list holds accepted exceptions only.
|
|
310
|
+
- [ ] Lint runs on the diff at commit time, full with baseline in CI.
|
|
311
|
+
- [ ] Screenshot `verify` fails on missing/changed goldens, never records.
|
|
312
|
+
- [ ] Every gate is reachable from `check`; expensive ones sit behind `-P` flags.
|
|
313
|
+
- [ ] Floors seeded at current state; ignore-lists/baselines only ratchet down.
|
|
314
|
+
- [ ] Failure messages are actionable (offender + actual + required).
|