Skip to content

Commit 4bf8aaf

Browse files
jamesarichCopilot
andcommitted
docs(spec): update discovery spec to reflect implementation state
- Update status from 'Not Started' to 'Implementation Complete' - Add Implementation Status section documenting per-user-story completion - Add data model divergences (simplified schema, RF health fields, neighborType) - Add Cross-Platform Alignment section comparing with meshtastic-apple - Document intentional differences (2-level state machine, production nav location) - Document known divergences and their priority (radar sweep, icon classification) - Reference design repo audit confirmation (50/51 tasks, D048 remaining) - Add implementation note to data-model.md about actual vs proposed schema Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 728678d commit 4bf8aaf

2 files changed

Lines changed: 124 additions & 3 deletions

File tree

specs/20260507-161658-local-mesh-discovery/data-model.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Data Model — Local Mesh Discovery
22

3+
> **⚠️ Implementation Note (2026-05-18):** The actual Room entities diverge from this original proposal.
4+
> The implemented schema is simpler (auto-generated Long PKs, fewer indices, unified DAO) and adds
5+
> RF health fields (`numPacketsTx`, `numPacketsRx`, `numPacketsRxBad`, `numRxDupe`, `avgChannelUtilization`,
6+
> `avgAirtimeRate`, `packetSuccessRate`, `packetFailureRate`, `numTxRelay`, `numTxRelayCanceled`,
7+
> `numOnlineNodes`, `numTotalNodes`, `uptimeSeconds`), `neighborType` on DiscoveredNode, `userLatitude`/
8+
> `userLongitude` on Session, and per-preset `aiSummary`. See the actual entity files in
9+
> `core/database/src/commonMain/kotlin/org/meshtastic/core/database/entity/` for the source of truth.
10+
311
This document defines the Room KMP persistence model for Local Mesh Discovery. The model is intentionally normalized around **session**, **per-preset result**, and **per-node discovery observation** so that history, summary, map, and export views can be rebuilt from persisted state without a live radio connection.
412

513
## Design Goals

specs/20260507-161658-local-mesh-discovery/spec.md

Lines changed: 116 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
# Feature Specification: Local Mesh Discovery
22

3-
**Feature Branch**: `001-local-mesh-discovery`
3+
**Feature Branch**: `feat/discovery`
44
**Created**: 2026-05-07
5-
**Status**: Not Started
6-
**Input**: User description: "Local Mesh Discovery — a high-fidelity diagnostic and community-mapping tool that cycles through modem presets to audit the local RF environment"
5+
**Updated**: 2026-05-18
6+
**Status**: Implementation Complete (pending final verification D048)
7+
**Input**: User description: "Local Mesh Discovery — a high-fidelity diagnostic and community-mapping tool that cycles through modem presets to audit the local RF environment"
8+
**Cross-Platform Pair**: `meshtastic/Meshtastic-Apple:specs/001-local-mesh-discovery/` (Status: ✅ Merged to main)
79

810
## Summary
911

@@ -359,3 +361,114 @@ If two presets still tie after all heuristics, the UI labels them as tied and av
359361
- `core/navigation/src/commonMain/kotlin/org/meshtastic/core/navigation/Routes.kt`
360362
- `core/navigation/src/commonMain/kotlin/org/meshtastic/core/navigation/DeepLinkRouter.kt`
361363
- `core/database/src/commonMain/kotlin/org/meshtastic/core/database/MeshtasticDatabase.kt`
364+
365+
---
366+
367+
## Implementation Status (2026-05-18)
368+
369+
### User Story Completion
370+
371+
| User Story | Status | Notes |
372+
|---|---|---|
373+
| US1 — Multi-Preset Scan | ✅ Complete | Full state machine, reconnect, dwell, advancement |
374+
| US2 — Map Visualization | ✅ Complete | CompositionLocal map, preset filter, topology overlay, direct/mesh color-coding |
375+
| US3 — Summary + AI | ✅ Complete (AI fallback only) | Deterministic 6-level ranking, per-preset AI summaries field, Gemini Nano provider stubbed (delegates to algorithmic) |
376+
| US4 — Persistence & History | ✅ Complete | Room KMP, cascade delete, history list, detail view |
377+
| US5 — 2.4 GHz Gating | ⚠️ Logic only | `Check24GhzCapability` implemented + tested; not wired to PresetPickerCard UI gates |
378+
| Export/Share | ⚠️ Partial | `PdfDiscoveryExporter` + `TextDiscoveryExporter` implemented; UI hookup pending |
379+
380+
### Implementation Divergences from Original Spec
381+
382+
The implementation evolved beyond the original spec in several areas. This section documents the actual state:
383+
384+
#### Data Model — Simplified Entity Structure
385+
386+
The actual Room entities use a simpler schema than `data-model.md` proposed:
387+
388+
- **`DiscoverySessionEntity`** uses auto-generated `Long` PK (not String UUID), fewer fields, and includes `userLatitude`/`userLongitude` (not in original spec).
389+
- **`DiscoveryPresetResultEntity`** uses `presetName: String` (not `presetKey` + `presetIndex`), and adds full RF health fields: `numPacketsTx`, `numPacketsRx`, `numPacketsRxBad`, `numRxDupe`, `numTxRelay`, `numTxRelayCanceled`, `numOnlineNodes`, `numTotalNodes`, `uptimeSeconds`, `avgChannelUtilization`, `avgAirtimeRate`, `packetSuccessRate`, `packetFailureRate`, `aiSummary`.
390+
- **`DiscoveredNodeEntity`** adds `neighborType: String` ("direct"/"mesh") and `messageCount`/`sensorPacketCount` — not in original spec but aligning with Apple implementation.
391+
- A unified `DiscoveryDao` serves all queries (rather than 3 separate DAOs as proposed).
392+
393+
#### RF Health & LocalStats — Fully Implemented
394+
395+
The implementation captures full `LocalStats` proto fields per-preset (Apple FR-008/FR-012/FR-024 equivalent):
396+
- `numPacketsTx`, `numPacketsRx`, `numPacketsRxBad`, `numRxDupe`
397+
- `packetSuccessRate`, `packetFailureRate`
398+
- `avgChannelUtilization` (from `DeviceMetrics.channel_utilization`)
399+
- `avgAirtimeRate` (from delta `air_util_tx` via 2-Packet Rule)
400+
401+
UI: `RfHealthSection.kt` renders these in the preset result cards.
402+
403+
#### Direct vs. Mesh Node Classification — Implemented
404+
405+
Nodes are classified as `"direct"` (seen via their own packets) or `"mesh"` (discovered only through `NeighborInfo` from another node). Map visualization uses `DiscoveryNeighborType.DIRECT`/`MESH` for color differentiation — aligning with Apple's green/blue color-coding.
406+
407+
#### Per-Preset AI Summaries — Field Present
408+
409+
`DiscoveryPresetResultEntity.aiSummary` stores per-preset summaries (Apple FR-021 equivalent). The summary generator populates these with algorithmic descriptions; the field is ready for Gemini Nano output when integrated.
410+
411+
#### State Machine Implementation Names
412+
413+
| Spec Name | Implementation Name | Notes |
414+
|---|---|---|
415+
| WaitingForReconnect | Reconnecting | Semantic equivalent |
416+
| SwitchingPreset | Shifting | Matches "Shifting to [preset]" UX text |
417+
| Completed (terminal) | Complete | Differentiated by `completionStatus` on session entity |
418+
419+
---
420+
421+
## Cross-Platform Alignment with Meshtastic-Apple
422+
423+
The Apple implementation (`meshtastic/Meshtastic-Apple`) is merged to `main` and provides the cross-platform reference. This section documents alignment and intentional differences.
424+
425+
### Fully Aligned Areas
426+
427+
| Feature | Android | Apple | Status |
428+
|---|---|---|---|
429+
| Core scan concept | Cycle presets → dwell → collect → summarize | Same | ✅ Aligned |
430+
| Entity triad | Session / PresetResult / DiscoveredNode | Same | ✅ Aligned |
431+
| Minimum dwell | 15 minutes | 15 minutes | ✅ Aligned |
432+
| 2.4 GHz gating approach | DeviceHardwareRepository tag check | DeviceHardwareEntity tags | ✅ Aligned |
433+
| Home preset snapshot + restore | Before first switch, restore on end | Same | ✅ Aligned |
434+
| NeighborInfo pipeline reuse | Existing handler | Same | ✅ Aligned |
435+
| BLE reconnect reuse | BleReconnectPolicy | Existing BLE actor | ✅ Aligned |
436+
| Deep link slug | `localMeshDiscovery` | `localMeshDiscovery` | ✅ Aligned |
437+
| RF Health metrics | All LocalStats fields | Same | ✅ Aligned |
438+
| Direct/mesh node classification | `neighborType` field | Same | ✅ Aligned |
439+
| User position on session | `userLatitude`/`userLongitude` | Same | ✅ Aligned |
440+
| Channel utilization + airtime | 2-Packet Rule computation | Same | ✅ Aligned |
441+
| Per-preset AI summary field | `aiSummary` on PresetResult | Same | ✅ Aligned |
442+
| Export | PDF primary, text fallback | PDF via UIGraphicsPDFRenderer | ✅ Aligned |
443+
444+
### Intentional Differences (Android Advantages)
445+
446+
| Feature | Android | Apple | Rationale |
447+
|---|---|---|---|
448+
| Navigation location | Settings > Advanced (production) | Settings > Developers (DEBUG only) | Android treats this as a power-user feature, not debug-only |
449+
| Two-level state machine | Session + Preset-level states | Single-level | Better partial-session tracking, per-preset SKIPPED state |
450+
| `isPartial` flag | Explicit bool on session | `completionStatus` string only | Clearer query semantics |
451+
| `medianSnr` | On PresetResult | Not stored | Richer ranking input |
452+
| `reconnectCount` | Per-preset | Not tracked | Useful for reliability analysis |
453+
| `actualDwellSeconds` | Separate from planned | Not stored | Shows reconnect-time loss |
454+
| KMP + Desktop | Full commonMain logic + JVM Desktop shell | iOS-only | Architectural requirement |
455+
| `bestPresetKey` + `recommendationSource` | Stored on session | Computed at render time | Faster history list rendering |
456+
457+
### Known Divergences (Potential Future Alignment)
458+
459+
| Feature | Apple Has | Android Status | Priority |
460+
|---|---|---|---|
461+
| Radar sweep animation | `RadarSweepView` at 60fps | Not planned | 🟡 Low — cosmetic, high battery cost |
462+
| Node social/sensor icon classification | `person.2.fill` vs `thermometer` | Data available (`messageCount`/`sensorPacketCount`) but no icon rule defined | 🟡 Medium — could add |
463+
| Map auto-zoom (1.6×, 0.005° min, 0.8s ease) | Specified | Uses platform map default auto-fit | 🟡 Low — platform maps handle this differently |
464+
| Dwell picker specific values | `[1, 5, 15, 30, 45, 60, 90, 120, 180]` min | Slider with 15-min minimum | 🟡 Low — UX preference |
465+
| Historical sessions fed to AI | Trend/cross-session analysis | Session-level only currently | 🟡 Medium — future enhancement |
466+
| Reconnect timeout default | 60 seconds explicit | Configurable, no spec'd default | 🟢 Low — uses BleReconnectPolicy defaults |
467+
468+
### Design Repo Status
469+
470+
The `meshtastic/design` repo (`standards/audits/cross-platform-spec-audit.md`) confirms:
471+
- Android: 50/51 tasks complete on `feat/discovery` — remaining: D048 full verification
472+
- Apple: ✅ Implemented on main
473+
- No feature-level design spec exists (design repo is visual standards only)
474+
- Design standard color palette (Success green `#3FB86D`, Info blue `#5C6BC0`) should be used for direct/mesh node map colors

0 commit comments

Comments
 (0)