Skip to main content

pre-release-validation

Run local CI/CD checks before pushing code. Use before commits, releases, or when validating code quality. Catches issues before they reach remote.

Source facts

Repository
rommapp/argosy-launcher
Last source activity
August 4, 2026 at 05:32
Detected SKILL.md language
English
Stars
633
Forks
47

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
pre-release-validation
description
Run local CI/CD checks before pushing code. Use before commits, releases, or when validating code quality. Catches issues before they reach remote.
# Pre-Release Validation Run comprehensive local checks before pushing code to catch issues early. --- ## When to Use This Skill **Automatically invoke:** - Before creating a release (stable or beta) - Before pushing significant changes - After completing a feature implementation **Manual invocation when:** - User asks to "run checks" or "validate" - Debugging CI failures locally - Auditing code quality --- ## Validation Tiers Timing reality: a cold `:app:compileDebugKotlin` runs ~12 min with the Compose stability config (per the comment at `app/build.gradle.kts:140`; >42 min without it); a warm compile is ~4.5 min. Tier estimates assume a warm daemon and stretch accordingly when cold. Build in the background and wait for completion; do not kill slow builds mid-flight. ### Tier 1: Quick Check (warm ~5 min) Fast validation for small changes. ```bash # Lint check ./gradlew lintDebug 2>&1 | head -50 # Compile check ./gradlew compileDebugKotlin 2>&1 ``` ### Tier 2: Standard Check (warm ~10 min) Full validation before commits. ```bash # Lint ./gradlew lintDebug # Unit tests ./gradlew testDebugUnitTest # Compile release ./gradlew compileReleaseKotlin ``` ### Tier 3: Full Check (warm 15+ min; much longer cold) Complete validation before releases. ```bash # Full lint (both debug and release) ./gradlew lint # All unit tests ./gradlew testDebugUnitTest testReleaseUnitTest # Full release build ./gradlew assembleRelease ``` --- ## Coupling Sweep (release backstop) The git-commit hook (`scripts/ci/coupling-guard.py`, via PreToolUse) gates each agent commit against Argosy's coupling map. This sweep is the release-time backstop: it re-runs the same rules over the WHOLE changeset since the last tag, catching coupling gaps that slipped across many commits. ```bash # Sweep every change since the last release tag LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") python3 scripts/ci/coupling-guard.py --sweep "${LAST_TAG:+$LAST_TAG..}HEAD" ``` The sweep is advisory (never blocks the release on its own), but its output is a release blocker for judgment: - WALKTHROUGH-FORCED axes (save-sync, RomM) flagged -> confirm the live-data proof obligations were actually met for this release (`GET /api/saves`, negotiate returns no_op twice). Never ship these on code-reading alone. - platform / settings / UI flags -> confirm the lockstep set and consumption sites. Rules live in `scripts/ci/coupling-hotspots.json` (machine mirror of `coupling-map.md`). Update both when the architecture moves. The guard and its rules are tracked, not maintainer-local: CI runs the same sweep on every PR, so a rule added here takes effect for every contributor rather than only on this machine. --- ## Validation Checklist ### Code Quality ``` [ ] No lint errors (warnings acceptable) [ ] No compiler warnings in changed files [ ] Unit tests pass [ ] No TODO/FIXME in committed code (unless intentional) ``` ### Build Validation ``` [ ] Debug build succeeds [ ] Release build succeeds [ ] APK size reasonable (check for bloat) ``` ### Git Hygiene ``` [ ] No untracked files that should be committed [ ] No secrets/credentials in staged files [ ] Commit message follows conventions ``` ### Compose Stability Guard The stability config (`app/compose_stability_config.conf`) asserts covered packages are immutable; the compiler does not check it. Before release, verify no mutable constructor/body properties crept into covered state classes: ```bash grep -rEn --include="*.kt" "^ {4}var [a-zA-Z]+:" \ app/src/main/kotlin/com/nendo/argosy/data/model \ app/src/main/kotlin/com/nendo/argosy/data/local/entity \ app/src/main/kotlin/com/nendo/argosy/ui/screens \ app/src/main/kotlin/com/nendo/argosy/ui/components \ app/src/main/kotlin/com/nendo/argosy/ui/dualscreen ``` Triage hits: a `var` property on a data class used as UI state or a composable param is a BLOCKER (fix to `val` + copy-on-change, or move the class out of covered packages). `private var` internals of ViewModels/delegates are exempt, but confirm nothing reads them directly inside composition. ``` [ ] Stability guard grep is clean (or all hits triaged exempt) ``` --- ## Workflow ### Before Commit ```bash # Quick validation ./gradlew lintDebug compileDebugKotlin testDebugUnitTest ``` ### Before Push ```bash # Standard validation ./gradlew lint testDebugUnitTest compileReleaseKotlin ``` ### Before Release ```bash # Full validation (run these in sequence) ./gradlew lint ./gradlew testDebugUnitTest testReleaseUnitTest ./gradlew assembleRelease ``` --- ## Common Issues & Fixes ### Lint Errors **Unused imports/variables:** ```kotlin // Remove or use the import/variable // Android Studio: Optimize Imports (Cmd+Opt+O) ``` **Hardcoded strings:** ```kotlin // Move to strings.xml or suppress if intentional @Suppress("HardcodedText") ``` **Missing nullability:** ```kotlin // Add explicit null handling val value = nullable ?: default ``` ### Test Failures **Flaky tests:** ```bash # Run specific test multiple times ./gradlew testDebugUnitTest --tests "TestClass.testMethod" --rerun-tasks ``` **Missing mocks:** ```kotlin // Ensure all dependencies are mocked in test setup every { dependency.method() } returns expected ``` ### Build Failures **Dependency conflicts:** ```bash # Check dependency tree ./gradlew dependencies --configuration releaseRuntimeClasspath ``` **ProGuard issues:** ``` # Check proguard-rules.pro for missing keep rules -keep class com.nendo.argosy.** { *; } ``` --- ## Single Invocation, Never Parallel NEVER run concurrent gradle invocations against this project (no separate terminals, no `&`). Concurrent invocations corrupted the KSP caches here in a prior incident, and recovery meant scoped cache invalidation. Pass multiple tasks to ONE invocation and let Gradle schedule them: ```bash ./gradlew lintDebug testDebugUnitTest ``` --- ## Output Interpretation ### Lint Output ``` > Task :app:lintDebug Wrote HTML report to file:///path/app/build/reports/lint-results-debug.html 0 errors, 3 warnings # ACCEPTABLE - proceed 5 errors, 3 warnings # BLOCKING - fix errors first ``` `app/lint-baseline.xml` snapshots the warnings that existed at 2.6.1, so anything lint reports now is NEW and worth reading. Regenerate it only as a deliberate act after clearing real findings (delete the file and re-run `lintDebug`), never to silence a warning that just appeared. What the baseline is holding, so it is not mistaken for a backlog of bugs: the `Recycle` entries are false positives (cursors already closed via `?.use`, animators driven by a started `AnimatorSet`); `HardwareIds` is the device identity RomM device-sync and request signing depend on; `SdCardPath` entries are the upstream-exact emulator data paths the save resolvers need verbatim; `GetInstance` is AES-XTS, which is built from ECB primitives by definition; and the network config permits cleartext and user certificates because the server is self-hosted, frequently on a LAN with a self-signed cert. Genuinely worth doing later: `ApplySharedPref` outside `SessionStateStore` (where the synchronous write is deliberate), and the `ObsoleteSdkInt` dead branches. ### Test Output ``` > Task :app:testDebugUnitTest 85 tests completed, 0 failed # PASS 85 tests completed, 2 failed # BLOCKING - check failures ``` ### Build Output ``` BUILD SUCCESSFUL in 54s # PASS BUILD FAILED # BLOCKING - check error ``` --- ## Integration with Release Skill The release skill should invoke pre-release validation automatically: ```markdown ## Release Workflow (Updated) 1. Ask release type (stable/beta/rc) 2. **RUN PRE-RELEASE VALIDATION (Tier 3)** - ./gradlew lint - ./gradlew testDebugUnitTest testReleaseUnitTest - ./gradlew assembleRelease 3. **RUN COUPLING SWEEP** over changes since last tag (see Coupling Sweep above) - Resolve flagged axes; for save-sync/RomM confirm live-data proofs were met 4. If validation or sweep blockers remain, STOP and fix issues 5. If clean, proceed with version bump 6. ... (rest of release process) ``` --- ## CI/CD Parity CI (`.github/workflows/build.yml`) runs DEBUG variants only: | Local Command | CI Job | |---------------|--------| | `./gradlew assembleDebug -PallAbis` | build | | `./gradlew testDebugUnitTest -PallAbis` | test | | `./gradlew lintDebug -PallAbis` | lint | PRs additionally run the `rules` job (blocking agentic smell check + advisory coupling sweep; skippable via the maintainer-applied `rules-exempt` PR label). CI never builds, tests, or lints the RELEASE variant -- the release-variant checks in Tier 2/3 are local-only and still required before a release. Running the debug set locally first prevents CI failures. --- ## Quick Reference Commands ```bash # One-liner: Full pre-release validation ./gradlew lint testDebugUnitTest assembleRelease # Check specific area after changes ./gradlew testDebugUnitTest --tests "*DownloadManager*" ./gradlew testDebugUnitTest --tests "*Platform*" ./gradlew testDebugUnitTest --tests "*Emulator*" # Just build, skip tests (quick sanity check) ./gradlew assembleRelease -x test -x lint ``` Do NOT reach for `./gradlew clean` when a build misbehaves -- house rule. Invalidate the specific stale cache (scoped) instead; a clean forces the full cold-compile cost for no diagnostic gain. --- ## Validation Report Template After running checks, report: ```markdown ## Pre-Release Validation Report ### Lint - Status: PASS/FAIL - Errors: 0 - Warnings: 3 (acceptable) ### Tests - Status: PASS/FAIL - Passed: 85 - Failed: 0 - Skipped: 2 ### Build - Status: PASS/FAIL - APK Size: 12.3 MB - Build Time: 54s ### Verdict Ready for release: YES/NO Blockers: [list if any] ```
View on GitHub