Adding Android Lint to CI immediately caught two real crash bugs invisible to
all emulator QA (the fixture emulators run API 34+):
- SettingsViewModel + YourProgressViewModel called LocalDate.ofInstant, which
was only added in API 34 — but minSdk is 26. On every device running Android
8-13 (the bulk of the install base) these throw NoSuchMethodError and crash
the Settings and Your Progress screens. Fixed with the API-26-safe equivalent
Instant.atZone(zone).toLocalDate() (same result).
The other two Lint errors were false positives (ProduceStateDoesNotAssignValue
on two EncryptedChatImage composables that DO assign value inside the producer —
the check misfires on a suspend/?.let RHS) — explicitly @Suppress'd with a note,
so Lint reaches 0 errors legitimately rather than via a blanket baseline.
CI (android-ci.yml) gains two jobs:
- android-lint: ./gradlew :app:lintDebug (fails on error-severity; 113 existing
warnings are non-fatal and left for a separate burndown).
- release-build: first-ever R8 gate — builds :app:bundleRelease with a throwaway
keystore + dummy RC_API_KEY (satisfies the release guards; AAB not distributed),
so the minify/shrink/sign toolchain can never silently rot. Verified locally:
bundleRelease SUCCEEDS today (95MB AAB). A green build proves the toolchain,
not runtime survival of reflectively-loaded classes (Tink) — that stays a
release-APK QA item.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Node 20 was deprecated 2026-04-30 and deploys are blocked after 2026-10-30. nodejs22 is GA
for BOTH gens (deprecation 2027-04-30) — required because the runtime is codebase-wide and
onUserDelete stays gen1. nodejs24 was checked per plan and rejected: 2nd-gen only.
- functions/package.json engines.node 20 → 22 (the deploy-facing change; dist unaffected)
- .github/workflows/backend-ci.yml: both setup-node pins 20 → 22 so CI matches prod
Verified pre-deploy: tsc clean, 70 tests green, emulator discovery loads all 35 / 0 errors.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>