docs: Update specs and governance for Android M3 accessibility (#5392)

This commit is contained in:
James Rich
2026-05-09 15:13:51 -05:00
committed by GitHub
parent c0d95d6ac4
commit 0d195ead53
110 changed files with 16687 additions and 646 deletions

View File

@@ -1,5 +1,7 @@
# Meshtastic Android — Copilot Instructions
> **Full rules**: `AGENTS.md` is the source of truth. This file is a compact quick-reference for build commands and task naming. For architecture, conventions, and workflow details, consult `AGENTS.md` and the `.skills/` playbooks listed at the bottom.
## Build, Test & Lint
**Requires:** JDK 21, `ANDROID_HOME` set, proto submodule initialized.
@@ -42,118 +44,20 @@ KMP modules have different task names than pure-Android modules. Using the wrong
-`:feature:connections:testDebugUnitTest` — ambiguous in KMP modules. Use `:feature:connections:allTests`.
-`:feature:connections:compileFdroidDebugKotlin` — wrong for KMP. Use `:feature:connections:compileKotlinJvm` or `kmpSmokeCompile`.
## Architecture
## Quick Reference
**Kotlin Multiplatform** project targeting Android, Desktop (JVM), and iOS. Business logic lives in `commonMain`; platform shells (`app/`, `desktop/`) wire DI and host UI.
- **Architecture**: KMP project (Android, Desktop, iOS). Business logic in `commonMain`; platform shells (`app/`, `desktop/`) wire DI and host UI. See `AGENTS.md` and `.skills/kmp-architecture/`.
- **Flavors**: `fdroid` (OSS) / `google` (Maps + DataDog). Only one installable at a time (different signing keys).
- **Verify before push**: Run `./gradlew spotlessApply detekt assembleDebug test allTests`, then confirm CI with `gh pr checks <PR>`.
- **Strings**: `stringResource(Res.string.key)` — run `python3 scripts/sort-strings.py` after adding strings.
- **Icons**: `MeshtasticIcons` (from `core/ui/icon/`), not `material.icons.Icons`.
- **Error handling**: `safeCatching {}` (not `runCatching {}`) in coroutine code.
- **Dispatchers**: `org.meshtastic.core.common.util.ioDispatcher`, not `Dispatchers.IO`.
- **Navigation**: `MeshtasticNavDisplay` + `NavigationBackHandler` (not Android `BackHandler`).
- **Protos**: `core/proto/` is a read-only git submodule. Never modify proto files.
- **Branches**: Must start with `feat/`, `fix/`, `chore/`, `docs/`, `build/`, `ci/`, `refactor/`, `test/`, `deps/`, or a numeric spec prefix. Always branch off `origin/main`.
### Module layers
| Layer | Modules | Role |
|-------|---------|------|
| Host | `app`, `desktop` | Platform shell, Koin root, theme |
| Feature | `feature/*` | Self-contained screens (KMP, `meshtastic.kmp.feature` plugin) |
| Core | `core/*` | Shared logic, data, networking, UI components |
### Key technologies
- **UI:** Compose Multiplatform + Material 3 Adaptive
- **Navigation:** JetBrains Navigation 3 (`@Serializable sealed interface` routes in `core:navigation`)
- **DI:** Koin 4.2+ with K2 Compiler Plugin (`@Module`, `@KoinViewModel`, `startKoin<AndroidKoinApp>`)
- **Networking:** Ktor (no OkHttp)
- **BLE:** Kable (via `core:ble`)
- **Database:** Room KMP
- **I/O:** Okio
- **Build:** Gradle Kotlin DSL with convention plugins in `build-logic/`
- **Flavors:** `fdroid` (OSS) / `google` (Maps + DataDog)
### Navigation pattern
Feature navigation graphs are extension functions on `EntryProviderScope<NavKey>` in `commonMain`. The host shell renders via `MeshtasticNavDisplay`. Use `NavigationBackHandler` (not Android's `BackHandler`).
## Key Conventions
### Source-set boundaries
- **`commonMain`** — All business logic, ViewModels, UI. No `java.*` or `android.*` imports.
- **`androidMain`** — Android framework integration only. No business logic.
- **`jvmMain` / `jvmAndroidMain`** — Shared JVM code (Android + Desktop).
- Platform capabilities: prefer interface + DI over `expect`/`actual`.
### Strings & formatting
- All strings in `core/resources/src/commonMain/composeResources/values/strings.xml`
- Use `stringResource(Res.string.key)` — never hardcoded strings.
- CMP only supports `%N$s` (string) and `%N$d` (int) — pre-format floats with `NumberFormatter.format()`.
- Run `python3 scripts/sort-strings.py` after adding strings.
### Error handling
- Use `safeCatching {}` (from `core:common`) instead of `runCatching {}` in suspend/coroutine code — `runCatching` swallows `CancellationException`.
### Dispatchers
- Use `org.meshtastic.core.common.util.ioDispatcher` — never `Dispatchers.IO` directly.
- Inject `CoroutineDispatchers` from `core:di`.
### Build-logic
- Convention plugins: `meshtastic.kmp.feature`, `meshtastic.kmp.library`, `meshtastic.kmp.jvm.android`, `meshtastic.koin`
- Use `libs.library("alias-name")` string-based lookups (not type-safe accessors) in convention plugins.
- Prefer lazy Gradle configuration (`configureEach`, `withPlugin`, provider APIs).
### Icons
- Use `MeshtasticIcons` (from `core/ui/icon/`) instead of `material.icons.Icons`.
### Protos
- `core/proto/` is a **read-only git submodule** from `meshtastic/protobufs`. Never modify proto files.
### Design standards
- All UI must conform to the [Meshtastic Client Design Standards](https://raw.githubusercontent.com/meshtastic/design/refs/heads/master/standards/meshtastic_design_standards_latest.md).
- Review new screens/significant UI changes against the standards before merge.
### Branch naming
Branches must start with: `bugfix/`, `enhancement/`, `dependencies/`, or `repo/`.
### Branching workflow
- `origin` = `meshtastic/Meshtastic-Android` (upstream, source of truth). Personal forks are typically behind.
- Always create branches off fetched upstream: `git fetch origin && git checkout -b <name> origin/main`
- Never branch from a personal fork's `main` — it may be stale.
### Push workflow (verify-then-push)
**Before push:**
```bash
./gradlew spotlessApply detekt assembleDebug test allTests # or targeted module tasks
```
Only push when the above passes locally.
**After push:**
```bash
gh pr checks <PR_NUMBER> # or: gh run list --branch <branch> --limit 3
```
Report CI status only after fetching actual results. Never say "CI should be green now" — check and confirm.
### Scope discipline
When a working branch grows beyond ~5 logical commits or starts spanning unrelated concerns, proactively propose:
1. A fresh branch off `origin/main`
2. Cherry-pick only the high-impact, low-blast-radius changes
3. Defer tangential work to follow-up PRs
Don't pile unrelated changes onto an existing branch. Squash fixup commits before pushing.
### Multi-flavor device installs
Two app flavors exist: `com.geeksville.mesh` (fdroid) and `com.geeksville.mesh.google` (google). Only one can be installed at a time (different signing keys). When switching flavors on a device:
- Uninstall the other flavor first, or the install will fail silently.
- Be aware that uninstalling loses onboarding state, permissions, and bonded-device data. Ask before uninstalling if the user has an active session.
## Deeper guidance
## Deeper Guidance
Consult `.skills/` for detailed playbooks:
- `.skills/project-overview/` — Full codebase map and bootstrap