verify-android-build
Run the canonical verification pipeline (spotlessCheck → assembleStableDebug → lint → test), parse the results, and refuse success claims on a red build. The project's verification-procedure SSOT.
SKILL.md.claude/skills/verify-android-build/SKILL.md
GitHubVerifying an Android build
A change that compiles only in the editor still requires a real build before it ships. Use this skill before declaring a change "done", "ready", or "looks good" after any edit to the paths above. This skill is the verification-procedure SSOT; other skills cite it rather than describing the verification themselves.
When invoked manually, $ARGUMENTS overrides the default Gradle
task. Default is assembleStableDebug.
Procedure
Check format and code style.
./gradlew spotlessCheckOn failure, run
./gradlew spotlessApplyto auto-fix. ktlint findings that Spotless cannot auto-fix (e.g.compose:modifier-missing-check) need a manual edit; do not bypass withsuppressLintsFor.Build a debug APK.
./gradlew assembleStableDebugExpect
BUILD SUCCESSFUL. APK atapp/build/outputs/apk/stable/debug/app-stable-debug.apk.assembleStableDebugalso builds the LIVE map web payload (:app:buildWebMapruns pnpm + Vite overwebmap/), so webmap regressions surface here.Run lint for any change touching the manifest, themes, or resources:
./gradlew lintRead the report (
app/build/reports/lint-results-*.{xml,html}) and summarise: new errors (blocking), new warnings grouped by category, and any baseline regressions. Never suppress — fix at source (AGENTS.md#no-suppress) or surface the finding to the user for a decision.Run unit tests if you touched code that has corresponding tests:
./gradlew testIf you touched
app/src/test/.../catalog/ortestfixtures/Dashboard*, also run./gradlew :app:generateCatalog -Pfemto.catalog.filter=head-unit-853x512__medium__light__right__bottom— the generator is category-excluded fromtest, so nothing else exercises it locally.Check the docs site if you touched anything under
docs/:pnpm --dir docs run check && pnpm --dir docs run buildBoth must pass;
buildincludes the dist link check that fails on a link missing the Pages base. CI runs the same two commands in thedocs-sitejob.Report explicitly what was run and what passed:
- "Ran
./gradlew spotlessCheck— passed." - "Ran
./gradlew assembleStableDebug— BUILD SUCCESSFUL." - "Ran
./gradlew lint— no new findings."
Do not claim success generically; cite the commands.
- "Ran
On red, fix the root cause per
AGENTS.md#no-suppress, and do not skip hooks. If a Compose API is experimental, opt in at file level — never at module level.
CI parity: .github/workflows/ci.yml runs the same four tasks
(spotlessCheck, lint, test, assembleStableDebug), split across
three parallel jobs (static-checks, unit-tests, assemble) for
wall-clock speed, plus lintNightlyRelease alongside lint in CI only
(the bare lint task covers the default variant, so this is the one
check that compiles the nightly resource source set), plus
verifyRoborazziStableDebug alongside test in
CI only (screenshot verification against goldens recorded on the
CI runner OS), plus the docs-site job (pnpm run check + pnpm run build under docs/), plus a one-entry generateCatalog -Pfemto.catalog.filter=… smoke render in the unit-tests leg
(CI-only). If this step list changes, change ci.yml in the same
commit.
Common failure modes and fixes
| Failure | Likely cause | Fix |
|---|---|---|
This API is experimental and is likely to change |
Variable-font FontVariation use |
Add @file:OptIn(androidx.compose.ui.text.ExperimentalTextApi::class) at the top of the file (see .claude/rules/fonts.md) |
Unresolved reference: libs.<x> |
Forgot to add the alias in libs.versions.toml |
Add to [libraries] (and [plugins] for plugins), then re-sync. See .claude/rules/dependencies.md. |
Theme.Material3.DayNight.NoActionBar not found |
com.google.android.material:material removed |
Re-add it in libs.versions.toml and app/build.gradle.kts |
:app:buildWebMap fails |
TypeScript / Vite error under webmap/ |
Fix the webmap source; Gradle provisions Node and pnpm itself. Keep Vite's build.target at the WebView floor (AGENTS.md#tech-stack) |
| Compose Compiler version mismatch | The catalog was bypassed — kotlin-compose shares version.ref = "kotlin" in gradle/libs.versions.toml and cannot diverge through it (.claude/rules/dependencies.md) |
Restore the shared version.ref |