fix(specs): remove 23 stale map/POI references after deferral

Clean up references to MapScreen, PlaceListMapTemplate, POI category,
and related models across all spec artifacts following the map strategy
deferral decision. All map-related items are now properly marked as
DEFERRED or N/A.

Affected artifacts:
- contracts/car-app-service.md: screen hierarchy, tabs, template section
- contracts/manifest-declarations.md: POI category removed
- plan.md: file tree cleaned
- spec.md: component table, assumptions, clarification Q2
- data-model.md: MapUiState/NodePlace/LatLngWrapper commented out
- research.md: R6 marked UNDER REVIEW with options table
- tasks.md: T005, T014, delivery strategy
- checklists/car-integration.md: CHK020/030/038/043 marked N/A

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
James Rich
2026-05-21 17:04:46 -05:00
parent 38d29ee6cb
commit a82808d1ca
8 changed files with 44 additions and 59 deletions

View File

@@ -31,7 +31,7 @@
## Requirement Consistency
- [ ] CHK020 — Do FR-009 (PlaceListMapTemplate under POI) and Non-Goals (NAVIGATION deferred to v2) consistently align with map update latency requirement SC-009 (< 5s)? [Consistency, Spec §FR-009, §SC-009]
- [x] CHK020 — ~~Do FR-009 (PlaceListMapTemplate under POI) and Non-Goals (NAVIGATION deferred to v2) consistently align with map update latency requirement SC-009 (< 5s)?~~ N/A — FR-009 and SC-009 deferred with map feature [Consistency]
- [ ] CHK021 — Are voice input requirements consistent between US-1 (reply), US-7 (in-context), and FR-003 (primary method)? [Consistency]
- [ ] CHK022 — Does "no parked-mode differentiation" (Clarifications) conflict with any acceptance scenario implying driving-only behavior? [Consistency, Spec §Edge Cases]
- [ ] CHK023 — Are emergency handling requirements consistent between FR-005 (banner), FR-006 (spotlight), and US-2 (all scenarios)? [Consistency]
@@ -44,7 +44,7 @@
- [ ] CHK027 — Is SC-010 ("zero crashes in 2-hour session") sufficient as a release gate — what about ANRs, OOM, or session drops? [Measurability, Spec §SC-010]
- [ ] CHK028 — Is SC-007 ("passes Android Auto App Quality review") measurable before actual store submission? [Measurability, Spec §SC-007]
- [ ] CHK029 — Is SC-001 ("15 seconds total interaction time") measured from notification appearance or screen wake? [Measurability, Spec §SC-001]
- [ ] CHK030 — Are acceptance scenarios for US-5 (map) testable on DHU given DHU's limited map rendering capabilities? [Measurability, Spec §US-5]
- [x] CHK030 — ~~Are acceptance scenarios for US-5 (map) testable on DHU?~~ N/A — US-5 deferred [Measurability]
## Scenario Coverage
@@ -58,12 +58,12 @@
## Edge Case Coverage
- [ ] CHK038 — Is behavior defined when PlaceListMapTemplate's item limit is reached (max 6 items per CAL docs)? [Edge Case, Spec §FR-009]
- [x] CHK038 — ~~Is behavior defined when PlaceListMapTemplate's item limit is reached?~~ N/A — map deferred [Edge Case]
- [ ] CHK039 — Is behavior defined when a channel has zero messages (empty state for messaging screen per channel)? [Edge Case, Gap]
- [ ] CHK040 — Are requirements defined for handling very long node names that exceed Condensed Item text bounds? [Edge Case, Spec §FR-007]
- [ ] CHK041 — Is behavior defined when voice recognition returns empty/null result or times out? [Edge Case, Spec §FR-003]
- [ ] CHK042 — Is behavior defined for rapid consecutive emergency alerts from multiple nodes? [Edge Case, Spec §Edge Cases]
- [ ] CHK043 — Are requirements defined for handling GPS-less nodes on the map screen (nodes without position data)? [Edge Case, Spec §FR-009]
- [x] CHK043 — ~~Are requirements defined for handling GPS-less nodes on the map screen?~~ N/A — map deferred [Edge Case]
- [ ] CHK044 — Is behavior defined when the message being composed via voice exceeds mesh packet size limit (228 bytes)? [Edge Case, Gap]
- [ ] CHK045 — Is behavior defined when Minimized Control Panel data sources become stale (BLE connected but no mesh traffic)? [Edge Case, Spec §FR-010]

View File

@@ -16,7 +16,7 @@ The `MeshtasticCarAppService` is the entry point for Android Auto and AAOS hosts
<intent-filter>
<action android:name="androidx.car.app.CarAppService" />
<category android:name="androidx.car.app.category.MESSAGING" />
<category android:name="androidx.car.app.category.POI" />
<!-- Secondary category (POI or NAVIGATION) deferred pending map strategy decision -->
</intent-filter>
</service>
```
@@ -26,7 +26,7 @@ The `MeshtasticCarAppService` is the entry point for Android Auto and AAOS hosts
| Category | Purpose | Justification |
|----------|---------|---------------|
| `MESSAGING` | Primary — enables ConversationItem, voice reply | Core use case: read/reply to mesh messages |
| `POI` | Secondary — enables PlaceListMapTemplate | Node map with static pins (not navigation) |
| ~~`POI`~~ | ~~Secondary — enables PlaceListMapTemplate~~ | **DEFERRED** — pending NAVIGATION vs POI decision |
### Car API Level
@@ -75,10 +75,8 @@ class MeshtasticCarSession(private val sessionInfo: SessionInfo) : Session() {
HomeScreen (root, never popped)
├── MessagingScreen (tab 1)
│ └── ConversationScreen (push on conversation tap)
── NodeDashboardScreen (tab 2)
└── NodeDetailScreen (push on node tap)
└── MapScreen (tab 3)
└── NodeDetailScreen (push on map item tap)
── NodeDashboardScreen (tab 2)
└── NodeDetailScreen (push on node tap)
```
Maximum screen depth: 3 (compliant with CAL template depth limits).
@@ -92,7 +90,6 @@ TabTemplate {
tabs: [
Tab("Messages", messagingIcon),
Tab("Nodes", nodeIcon),
Tab("Map", mapIcon),
]
headerAction: Action.APP_ICON
}
@@ -170,25 +167,9 @@ PaneTemplate {
}
```
### MapScreen → PlaceListMapTemplate
### ~~MapScreen → PlaceListMapTemplate~~ (DEFERRED)
```
PlaceListMapTemplate {
title: "Node Map"
itemList: ItemList {
items: [
Row(
title: node.name,
text: "Updated {timeAgo} • {distanceFormatted}",
metadata: Place(LatLng(lat, lng)),
onClickListener: → push NodeDetailScreen
) for each node with position
]
}
anchor: LatLng(ownLat, ownLng) // if own position available
isCurrentLocationEnabled: true
}
```
> Map implementation deferred pending NAVIGATION vs POI category decision. Template contract will be defined when map strategy is resolved.
### MeshStatusPanel → Minimized Control Panel
@@ -224,7 +205,7 @@ AppManager.showAlert(
| BLE disconnected | Banner shown; screens degrade to cached data (read-only) |
| No channels configured | Show onboarding PaneTemplate directing to phone app |
| No nodes in range | Empty state in NodeDashboard: "No nodes heard" |
| No positions available | MapScreen shows empty map with "No positions reported" |
| No positions available | ~~MapScreen shows empty map~~ (DEFERRED with map feature) |
| Template item limit exceeded | Paginate with "Load more" action row |
| Voice input fails | Fall back to quick-reply template list |
| Session crash | Crashlytics captures with `car_session` tag; session restarts cleanly |

View File

@@ -17,7 +17,7 @@
<intent-filter>
<action android:name="androidx.car.app.CarAppService" />
<category android:name="androidx.car.app.category.MESSAGING" />
<category android:name="androidx.car.app.category.POI" />
<!-- POI or NAVIGATION category deferred pending map strategy decision -->
</intent-filter>
</service>

View File

@@ -139,10 +139,11 @@ data class TopologyHeader(
**Source**: `NodeRepository.nodeDBbyNum`, `NodeRepository.onlineNodeCount`
### MapUiState
### ~~MapUiState~~ (DEFERRED)
State for the PlaceListMapTemplate.
> Map models deferred pending NAVIGATION vs POI category decision. These models will be defined when map strategy is resolved.
<!--
```kotlin
data class MapUiState(
val places: List<NodePlace>,
@@ -165,6 +166,7 @@ data class LatLngWrapper(
```
**Source**: `NodeRepository.nodeDBbyNum` filtered to nodes with valid positions
-->
### EmergencyAlert

View File

@@ -85,12 +85,11 @@ feature/car/
│ │ │ │ ├── MeshtasticCarAppService.kt # CarAppService entry point
│ │ │ │ └── MeshtasticCarSession.kt # Session lifecycle, screen manager
│ │ │ ├── screens/
│ │ │ │ ├── HomeScreen.kt # Tab-based entry (messaging, nodes, map)
│ │ │ │ ├── HomeScreen.kt # Tab-based entry (messaging, nodes)
│ │ │ │ ├── MessagingScreen.kt # ConversationItem list, channel chips
│ │ │ │ ├── ConversationScreen.kt # Single conversation with voice reply
│ │ │ │ ├── NodeDashboardScreen.kt # Condensed Items node grid
│ │ │ │ ├── NodeDetailScreen.kt # Expanded node info
│ │ │ │ ├── MapScreen.kt # PlaceListMapTemplate
│ │ │ │ └── ChannelManagementScreen.kt # Channel selection/switching
│ │ │ ├── alerts/
│ │ │ │ └── EmergencyHandler.kt # Banner management for emergencies
@@ -110,8 +109,7 @@ feature/car/
│ │ └── MeshtasticCarSessionTest.kt
│ ├── screens/
│ │ ├── MessagingScreenTest.kt
│ │ ── NodeDashboardScreenTest.kt
│ │ └── MapScreenTest.kt
│ │ ── NodeDashboardScreenTest.kt
│ └── alerts/
│ └── EmergencyHandlerTest.kt

View File

@@ -90,24 +90,28 @@ The existing `SendMessageUseCase` in `core/repository` accepts `(text, contactKe
- Custom speech recognition → Rejected: CAL handles this automatically; would duplicate system capabilities
- Google Assistant App Actions → Rejected: Separate concern handled by AppFunctions feature
## R6: PlaceListMapTemplate for Node Map (POI Category)
## R6: Map Template Strategy (UNDER REVIEW)
**Decision**: Use `PlaceListMapTemplate` under POI category for static node position display
**Status**: ⚠️ **Decision deferred** — pending further research on NAVIGATION vs POI implications.
**Rationale**: POI category avoids NAVIGATION category requirements (turn-by-turn guidance, active routing), which would trigger additional Play Store review burden and potential conflicts with navigation apps. `PlaceListMapTemplate` renders a map with place items (pins) + a scrollable list — perfect for showing node positions.
**Options under consideration**:
**Implementation approach**:
- Each node with known GPS position becomes a `Place` item with `LatLng`
- List items show node name + distance + last update time
- Map auto-zooms to fit all visible pins
- Tap a list item → NodeDetailScreen with message option
- Refresh interval: 5 seconds (matches NFR map update latency requirement)
| Option | Template | Pros | Cons |
|--------|----------|------|------|
| POI | `PlaceListMapTemplate` | Simple, no nav conflicts, static pins | 6-item cap, limited interactivity |
| NAVIGATION | `MapWithContentTemplate` | Full map control, live tracking | Exclusive with Google Maps/Waze, stricter review |
**Limitation**: No live tracking line or animated position updates (NAVIGATION category feature, deferred to v2)
**Previous analysis** (preserved for reference):
- POI category avoids NAVIGATION requirements (turn-by-turn guidance, active routing), which would trigger additional Play Store review burden and conflicts with navigation apps
- `PlaceListMapTemplate` renders a map with place items (pins) + a scrollable list — suitable for showing node positions
- MapWithContentTemplate offers richer UX but requires NAVIGATION category declaration
**Alternatives considered**:
- MapWithContentTemplate + NAVIGATION category → Rejected by spec decision; deferred to v2
- No map at all → Rejected: Location awareness is core Meshtastic differentiator
**Open questions**:
1. Does NAVIGATION category preclude simultaneous Google Maps use on car display?
2. Would Google Maps SDK for AAOS (announced I/O 2026) change the calculus?
3. Is 6-item cap on PlaceListMapTemplate acceptable for typical mesh networks?
**Implementation approach**: TBD after decision is made
## R7: Koin DI Integration for Car Module

View File

@@ -15,7 +15,7 @@ Integrate the Android Car App Library 1.9.0-alpha01 into Meshtastic-Android to d
### Session 2026-05-21
- Q: How should voice commands be implemented — CAL built-in voice input, full Assistant App Actions, or both? → A: CAL built-in voice input only (tap reply → dictate → send). System-level "Hey Google" commands are handled separately by the AppFunctions feature (`specs/20260521-091500-app-functions/`), which exposes `sendMessage`, `getMeshStatus`, `listNodes`, `getRecentMessages`, and `getNodePosition` to Android system AI (Gemini) automatically — including on car displays.
- Q: Should the app declare NAVIGATION category for MapWithContentTemplate, or use PlaceListMapTemplate under POI? → A: Stay with POI category, use PlaceListMapTemplate (static pin list, refreshable). Avoids nav app conflicts and Play Store review burden. Live position tracking under NAVIGATION category deferred to v2.
- Q: Should the app declare NAVIGATION category for MapWithContentTemplate, or use PlaceListMapTemplate under POI? → A: **DECISION DEFERRED** — originally selected POI/PlaceListMapTemplate but reopened for further research. See US-5 deferral note for open questions on NAVIGATION vs POI implications.
- Q: Should the CarAppService maintain an independent BLE connection or share the phone app's existing connection? → A: Shared connection — single Application-scoped BleConnectionManager instance via Koin. CarAppService keeps the process alive via Android Auto host; BLE connection persists at the Service/Application level, not Activity level.
- Q: What observability approach should the car module use? → A: Reuse existing Crashlytics with `car_session` custom key tagging for car-specific filtering. No new observability infrastructure; tag existing analytics paths.
- Q: Should the car app unlock additional features when the vehicle is parked? → A: No parked-mode differentiation. Templated messaging apps provide a uniform experience regardless of driving state. Voice reply is built into ConversationItem. The Android Auto host enforces its own driving restrictions; the app just provides templates.
@@ -225,7 +225,7 @@ A driver uses CAL's built-in voice input to compose messages and perform actions
| MeshtasticCarAppService | `feature/car/service/` | CAL Session host, entry point for Android Auto/AAOS |
| MessagingScreen | `feature/car/screens/` | Message list with channel chips, voice reply, quick-reply |
| NodeDashboardScreen | `feature/car/screens/` | Condensed Items grid of all mesh nodes |
| MapScreen | `feature/car/screens/` | PlaceListMapTemplate showing node positions as place items |
| ~~MapScreen~~ | ~~`feature/car/screens/`~~ | ~~PlaceListMapTemplate showing node positions~~**DEFERRED** |
| EmergencyHandler | `feature/car/alerts/` | Banner management for emergency messages |
| MeshStatusPanel | `feature/car/panels/` | Minimized Control Panel with mesh health |
| CarMessageRepository | `core/data/` | Existing message repository (reused) |
@@ -313,7 +313,7 @@ A driver uses CAL's built-in voice input to compose messages and perform actions
- The `google` build flavor is the distribution target; F-Droid/GitHub flavors do not include car support
- Quick-reply templates are configurable via the phone app's settings; the car app consumes them read-only
- Voice input quality depends on the car's microphone hardware; the app delegates to Android's speech recognition system
- MapWithContentTemplate availability depends on NAVIGATION category declaration (deferred to v2); v1 uses PlaceListMapTemplate under POI which is widely supported
- Map template strategy (POI vs NAVIGATION category) is deferred; no map screen in initial implementation
- Minimum Car API Level 8 is required; older Android Auto hosts will not show the app (graceful absence, not crash)
- Koin dependency injection is used consistently with Koin Annotations for the new module
- TTS (text-to-speech) for reading messages aloud uses Android's built-in TTS engine
@@ -453,7 +453,7 @@ ConversationItem.Builder()
**Android-exclusive features (exceeding Apple):**
- Node dashboard with Condensed Items (Apple has no node visibility)
- Emergency Banner overlays with audio alerts (Apple shows emergencies as regular messages)
- Map integration via PlaceListMapTemplate (Apple has no map)
- ~~Map integration~~ (DEFERRED pending NAVIGATION vs POI decision)
- Channel Chips for instant switching (Apple requires tab navigation)
- Quick-reply templates (Apple only offers Siri voice)
- Visual hierarchy via Spotlight/Section Headers/Expanded Headers

View File

@@ -24,7 +24,7 @@
- [ ] T002 Add `include(":feature:car")` to settings.gradle.kts
- [ ] T003 Create module build file at feature/car/build.gradle.kts with android-library, flavors, koin plugins, and all dependencies per contracts/manifest-declarations.md
- [ ] T004 [P] Add `"googleImplementation"(projects.feature.car)` dependency in androidApp/build.gradle.kts
- [ ] T005 [P] Create AndroidManifest.xml at feature/car/src/main/AndroidManifest.xml with CarAppService, MESSAGING+POI categories, and minCarApiLevel 8 meta-data
- [ ] T005 [P] Create AndroidManifest.xml at feature/car/src/main/AndroidManifest.xml with CarAppService, MESSAGING category, and minCarApiLevel 8 meta-data
- [ ] T006 [P] Create AAOS descriptor at feature/car/src/main/res/xml/automotive_app_desc.xml
- [ ] T007 [P] Create car-specific strings file at feature/car/src/main/res/values/strings.xml with initial string resources
@@ -42,7 +42,7 @@
- [ ] T011 [P] Create TemplateBuilders helper extensions at feature/car/src/main/kotlin/org/meshtastic/feature/car/util/TemplateBuilders.kt with reusable CAL template construction helpers
- [ ] T012 Create MeshtasticCarAppService at feature/car/src/main/kotlin/org/meshtastic/feature/car/service/MeshtasticCarAppService.kt extending CarAppService, creating sessions via Koin
- [ ] T013 Create MeshtasticCarSession at feature/car/src/main/kotlin/org/meshtastic/feature/car/service/MeshtasticCarSession.kt with onCreateScreen (returns HomeScreen), onNewIntent, onCarConfigurationChanged, Crashlytics tagging, 300ms invalidation debouncing
- [ ] T014 Create presentation state models (CarSessionState, ConnectionStatus, MessagingUiState, ChannelUi, ConversationUi, NodeDashboardUiState, NodeUi, SignalQuality, TopologyHeader, MapUiState, NodePlace, LatLngWrapper, EmergencyAlert) at feature/car/src/main/kotlin/org/meshtastic/feature/car/model/CarUiModels.kt
- [ ] T014 Create presentation state models (CarSessionState, ConnectionStatus, MessagingUiState, ChannelUi, ConversationUi, NodeDashboardUiState, NodeUi, SignalQuality, TopologyHeader, EmergencyAlert) at feature/car/src/main/kotlin/org/meshtastic/feature/car/model/CarUiModels.kt
- [ ] T015 Create HomeScreen (TabTemplate with Messages/Nodes tabs; Map tab placeholder deferred) at feature/car/src/main/kotlin/org/meshtastic/feature/car/screens/HomeScreen.kt
**Checkpoint**: Foundation ready — CarAppService binds, session creates, HomeScreen renders tabs. User story implementation can now begin in parallel.
@@ -245,7 +245,7 @@ Task: T031 "Register panel in session"
1. Setup + Foundational → Module compiles and binds to Android Auto
2. Add US1 (Messaging) → Core value delivered (MVP!)
3. Add US2 (Emergency) → Safety-critical alerts operational
4. Add US3 + US5 (Nodes + Map) → Location awareness complete
4. Add US3 (Nodes) → Node awareness complete
5. Add US4 (Channels) → Multi-channel workflows enabled
6. Add US6 + US7 (Panel + Voice) → Polish and hands-free refinement
7. Each increment is independently testable with the Desktop Head Unit (DHU)
@@ -254,8 +254,8 @@ Task: T031 "Register panel in session"
With multiple developers after Phase 2:
- Developer A: US1 (Messaging) → US4 (Channels) → US7 (Voice)
- Developer B: US3 (Nodes) US5 (Map)
- Developer C: US2 (Emergency) + US6 (Status Panel)
- Developer B: US3 (Nodes) + US6 (Status Panel)
- Developer C: US2 (Emergency)
---