From b0ca5421b68011f1d778db3e13dad8e24106c3c6 Mon Sep 17 00:00:00 2001 From: Jason Ross Date: Mon, 6 Jul 2026 14:18:40 -0500 Subject: [PATCH] chore(preflight): run jacocoTestCoverageVerification in the fast gate Co-Authored-By: Claude Opus 4.8 --- .claude/skills/preflight/SKILL.md | 9 +++++++-- CLAUDE.md | 13 ++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.claude/skills/preflight/SKILL.md b/.claude/skills/preflight/SKILL.md index f7e637d..de1ca7f 100644 --- a/.claude/skills/preflight/SKILL.md +++ b/.claude/skills/preflight/SKILL.md @@ -1,6 +1,6 @@ --- name: preflight -description: Run LibreMail's fast CI gate locally (assembleDebug + testDebugUnitTest + compileDebugAndroidTestKotlin + lintDebug + ktlintCheck + detekt) plus the local emulator E2E — the instrumented test class(es) you changed via local_instrumented.py (cold-boot, no Gradle Managed Devices), then the API 37 preview via api37_e2e.py — before pushing or opening a PR. Mirrors the merge gate; CI runs the full multi-API matrix. Use before treating a change as done. +description: Run LibreMail's fast CI gate locally (assembleDebug + testDebugUnitTest + jacocoTestCoverageVerification + compileDebugAndroidTestKotlin + lintDebug + ktlintCheck + detekt) plus the local emulator E2E — the instrumented test class(es) you changed via local_instrumented.py (cold-boot, no Gradle Managed Devices), then the API 37 preview via api37_e2e.py — before pushing or opening a PR. Mirrors the merge gate; CI runs the full multi-API matrix. Use before treating a change as done. --- # /preflight @@ -38,7 +38,7 @@ Run these, stopping at the first failure: ```bash ./gradlew :app:assembleDebug -./gradlew :app:testDebugUnitTest +./gradlew :app:testDebugUnitTest :app:jacocoTestCoverageVerification ./gradlew :app:compileDebugAndroidTestKotlin ./gradlew :app:lintDebug ./gradlew :app:ktlintCheck :app:detekt @@ -46,6 +46,11 @@ python3 .claude/skills/preflight/local_instrumented.py [ python3 .claude/skills/preflight/api37_e2e.py # api37 preview E2E (hand-provisioned; on Windows: py or python) ``` +`jacocoTestCoverageVerification` runs right after `testDebugUnitTest` because it reads that +task's JVM exec data — it enforces the whole-app **no-regression line-coverage floor (currently +0.79)**, so a coverage regression is caught locally instead of only in CI (the exact class of +failure that reached CI on #367). + `compileDebugAndroidTestKotlin` compiles the `androidTest` source set — the E2E/instrumented tests — without needing an emulator. `assembleDebug`, `testDebugUnitTest`, and `lintDebug` never compile that source set, so a change that breaks it (e.g. an instrumented test calling a UI API diff --git a/CLAUDE.md b/CLAUDE.md index e3d7776..ebf1eb2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -27,11 +27,14 @@ or via Gradle Managed Devices `./gradlew e2eGroupDebugAndroidTest` (whole matrix `app/build.gradle.kts` must stay in lockstep with the E2E matrix in `.github/workflows/ci.yml`. **Before treating a change as done**, run the fast CI gate: `assembleDebug` + -`testDebugUnitTest` + `compileDebugAndroidTestKotlin` + `lintDebug` + `ktlintCheck` + -`detekt` + the local emulator E2E — the instrumented test class(es) you changed via -`python3 .claude/skills/preflight/local_instrumented.py ` + the API 37 preview E2E via -`python3 .claude/skills/preflight/api37_e2e.py` (the `/preflight` skill does all of this). -`compileDebugAndroidTestKotlin` compiles the `androidTest` source set +`testDebugUnitTest` + `jacocoTestCoverageVerification` + `compileDebugAndroidTestKotlin` + +`lintDebug` + `ktlintCheck` + `detekt` + the local emulator E2E — the instrumented test class(es) +you changed via `python3 .claude/skills/preflight/local_instrumented.py ` + the API 37 +preview E2E via `python3 .claude/skills/preflight/api37_e2e.py` (the `/preflight` skill does all +of this). `jacocoTestCoverageVerification` runs right after `testDebugUnitTest` (it reads that +task's JVM exec data) and enforces the whole-app **no-regression line-coverage floor (currently +0.79)**, catching coverage regressions locally instead of only in CI (the exact class of failure +that reached CI on #367). `compileDebugAndroidTestKotlin` compiles the `androidTest` source set that the static part of the gate skips, catching E2E/instrumented-test compile errors before they surface only in CI. `ktlintCheck`/`detekt` cover the `test`/`androidTest` source sets that `lintDebug` skips, so they catch style violations that would otherwise fail CI's Static analysis