Skip to content

feat: SDK improvements for Meshtastic-Android hard cutover#1

Merged
jamesarich merged 36 commits into
mainfrom
feat/meshtastic-android-integration-gaps
May 9, 2026
Merged

feat: SDK improvements for Meshtastic-Android hard cutover#1
jamesarich merged 36 commits into
mainfrom
feat/meshtastic-android-integration-gaps

Conversation

@jamesarich
Copy link
Copy Markdown
Collaborator

Summary

Hard-cutover integration of meshtastic-sdk into Meshtastic-Android revealed SDK gaps, missing APIs, and documentation staleness. This PR addresses all findings across multiple audit rounds.

API additions (29 commits, 97 files, +13.5k lines)

Phase 1 — Core gaps:

  • RadioClient.textMessages flow, RadioClient.channels StateFlow
  • BleTransport(address) factory for Android
  • sendRaw(ToRadio) for MQTT proxy/XModem
  • Complete AdminApi — all 9 remaining operations for full proto coverage

Phase 2 — Feature APIs:

  • AdminApi.forNode(dest) — remote node admin
  • sendReaction() — emoji reactions
  • getDeviceMetadata(), requestNodeInfo()
  • editSettings {} batch support + AdminBatchScope
  • SFPP protocol handling + MeshTopology graph utility
  • Congestion metrics, presence timer, retry extension, Store-and-Forward impl
  • AdminResult.RateLimited, AdminResult.getOrThrow()
  • Config DSL builders (23 extension functions)
  • Admin batch getters

Quality:

  • Firmware compliance audit fixes (P0/P1 bug fixes)
  • Thread-safety, timeout, flow caching, error mapping improvements
  • KDoc on all public API symbols
  • Stale Phase-2 labels removed from implemented features

Documentation

  • api-reference.md fully synced: NodeChange.CameOnline/WentOffline, AdminResult.RateLimited, StoreForwardApi, 23 config builders, forNode(), sendReaction/sendRaw
  • error-taxonomy.md, integration-guide.md, consumer guides updated
  • Migration guide examples made exhaustive
  • Stale sample paths fixed in ADR-003

Tests (565 total, 0 failures)

  • AdminApi RPC coverage, engine integration, handshake FSM
  • Config DSL, admin batch, CommandDispatcher, TelemetryApi
  • StoreForward protocol, WireCodec edge cases
  • RadioClient send/sendText/sendReaction

Samples

  • Fixed 5 compilation errors (NodeChange + AdminResult exhaustiveness)
  • All 3 sample projects build clean

⚠️ Merge order: This PR should merge first. CI will publish a 0.1.0-SNAPSHOT to Sonatype Central. The companion Meshtastic-Android PR depends on these changes via includeBuild (composite build) during development, or via the published snapshot artifact in CI.

jamesarich and others added 29 commits May 2, 2026 19:04
Guard axionRelease plugin with gradle.parent == null so the SDK can be
included as a Gradle composite build (e.g. from Meshtastic-Android) without
the plugin erroring out trying to access the root project too early.
Resolves UnknownDomainObjectException when the build is consumed as a
composite dependency.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds a RadioClient extension property that filters the raw packets flow
by TEXT_MESSAGE_APP portnum, giving callers a typed stream of text messages
without hand-decoding portnum on every packet.

  RadioClient.textMessages: Flow<MeshPacket>
    = packets.filter { it.decoded?.portnum == PortNum.TEXT_MESSAGE_APP }

Filter is portnum-based (not asText() != null) so that empty-payload
TEXT_MESSAGE_APP packets are included — callers that care about delivery
receipts or zero-length pings can distinguish the packet from 'no message'.

Also adds FakeRadioTransport.injectPacket(MeshPacket) to the testing module
so integration tests can exercise packet flows without constructing raw frames.

Tests (PayloadAccessorsTest):
  - textMessagesEmitsTextPackets
  - textMessagesExcludesNonTextPackets
  - textMessagesIncludesEmptyPayloadTextPackets
  - rawPacketsFlowReceivesInjected (diagnostic)

Test note: use runCurrent() not advanceUntilIdle() in engine integration
tests — advanceUntilIdle() advances virtual time past the 60 s liveness
timeout, triggering handleDisconnect and silently dropping all subsequent
injected frames.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Exposes a reactive channel list on RadioClient so callers don't have to
issue 8 serial admin RPCs (admin.listChannels()) just to read channels.

  RadioClient.channels: StateFlow<List<Channel>?>

Seeding:
  - Populated in the SeedingSession commit from pendingChannels (the
    channel frames received during the Stage-1 handshake drain).
  - Falls back to storage (loadChannels()) on reconnect sessions where
    the device does not re-send channels (ifEmpty { null } so a known-
    empty storage slot stays null rather than an empty list).

Write-through:
  - AdminApiImpl.setChannel now calls engine.updateChannelAndPersist()
    on success: atomically patches the in-memory StateFlow (StateFlow.update)
    and enqueues a best-effort saveChannels() on engineScope.
  - Guards invalid channel indices (< 0 or > MAX_CHANNEL_INDEX).
  - Sparse gaps (idx > list.size) are silently skipped to avoid holes.

Lifecycle:
  - Cleared to null in cleanup() so stale channels never leak into a
    new session.
  - Preserved across auto-reconnect resets (aligns with existing engine
    comment: 'channels live across the cycle').

Imports: added ChannelIndex, kotlinx.coroutines.flow.update to MeshEngine.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…droid (Gap F)

Adds an androidMain-only factory function that creates a BleTransport from a
persisted MAC address string, eliminating the need for callers to manually
construct a Kable Peripheral before instantiating the transport.

On Android, Kable's Identifier is a String typealias. The factory calls
toIdentifier() on the address for forward-compatibility with Kable versioning,
then delegates to the primary BleTransport(peripheral, address) constructor.

Callers can supply a PeripheralBuilder action for GATT configuration:
    BleTransport("AA:BB:CC:DD:EE:FF") { autoConnectIf { true } }

The autoConnectIf { true } flag is required for bonded devices that connect
without a fresh BLE advertisement (avoids GATT error 133). iOS MAC addresses
are UUIDs (NSUUID), not strings, so this factory is Android-specific and lives
in androidMain.

Compile-verified: :transport-ble:compileAndroidMain + :transport-ble:jvmTest pass.

Gap F workaround (BlePeripheralFactory.kt in Meshtastic-Android core:ble) can
now be replaced with this SDK factory.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- NodeDiff: populate NodeChange.Updated with actual changed fields
- NodeStatus: isOnline(), ConnectionQuality, SignalQuality extensions
- MeshNode: unified consumer-friendly node model with computed status
- ConfigMerge: section-key-based merge for Gap G (configBundle refresh)
- AdminApiImpl: track written configs, call applyConfigEdits() after commit
- MeshEngine: flush dirty heartbeats on disconnect for presence restore
- MeshEngine: detect external config/channel changes (Gap C refinement)
- MeshEngine: telemetry→node update pipeline (maybeMergeDeviceMetrics)
- PayloadAccessors: asWaypoint(), asTraceroute(), asNeighborInfo()
- Node.kt: ExternalConfigChange event + ExternalChangeKind enum
- MeshEngine: updateChannelAndPersist handles null→init channel list
- Tests: ExternalConfigChangeTest, MeshNodeTest, PayloadAccessors additions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
BUG-01 (CRITICAL): get_channel_request now sends 1-based index per
admin.proto spec. Firmware expects index+1 to avoid proto3 zero-value
omission. Without this, all channel reads returned BAD_REQUEST.

BUG-02: Remove misleading preserveFavorites param from nodeDbReset().
Proto3 cannot encode false for the nodedb_reset field — firmware always
preserves favorites during reset. Simplified API with clear docs.

BUG-03: Replace fragile transport::class.simpleName check with
transport.identity.raw prefix check. simpleName is erased by R8
minification; identity is a stable runtime value.

PASSKEY-01: Reduce SESSION_PASSKEY_TTL from 24h to 4min. Firmware
regenerates passkeys every ~150s (valid for ~300s). The 24h TTL meant
every reconnect admin call failed once before re-seeding via retry.

ASSUMPTION-01: Detect is_managed mode from SecurityConfig in config
bundle. If device is managed, all admin commands from non-zero 'from'
addresses are silently dropped by firmware. SDK now returns
AdminResult.Unauthorized immediately instead of timing out.

GAP-H3: Send 4×0x94 wake bytes before first want_config_id on
stream-based transports (TCP/Serial). Required by protocol spec to
resync firmware's frame decoder after unclean disconnect.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- protocol.md §16: Fix heartbeat nonce description (SDK uses nonce=0,
  not incrementing counter starting at 2)
- protocol.md §13: Fix get_channel_request type annotation (uint32
  1-based, not bool)
- protocol.md §13: Correct session passkey TTL (~4min, not ~5min)
- protocol.md §13: Document managed mode (is_managed) behavior
- protocol.md §13: Document editSettings BLE disconnect side-effect
- protocol.md: Clarify wake bytes are now sent (not just recommended)
- SPEC.md + api-reference.md: Remove obsolete preserveFavorites param
  from nodeDbReset() signature

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
GAP-A1: Add 18 missing AdminApi operations:
  - toggleMuted(node)
  - setFixedPosition(position), removeFixedPosition()
  - getUIConfig(), storeUIConfig(config)
  - getCannedMessages(), setCannedMessages(messages)
  - getRingtone(), setRingtone(rtttl)
  - getDeviceConnectionStatus(), getRemoteHardwarePins()
  - setHamMode(params)
  - enterDfuMode(), deleteFile(path)
  - backupPreferences(location), restorePreferences(location),
    removeBackupPreferences(location)

GAP-H1: Capture DeviceUIConfig during handshake:
  - Add deviceUIConfig field to ConfigBundle
  - Process FromRadio.deviceuiConfig in Stage 1 envelope handler
  - Store in pendingDeviceUIConfig buffer, include in bundle assembly

GAP-T1: Add 3 missing telemetry request methods:
  - requestHealth(node) → HealthMetrics
  - requestHost(node) → HostMetrics
  - requestTrafficManagement(node) → TrafficManagementStats

Also adds 5 new ResponseKind variants for the new admin RPC responses
(CannedMessages, Ringtone, DeviceConnectionStatus, RemoteHardwarePins,
DeviceUIConfig).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds the remaining AdminMessage operations to achieve 100% coverage
of the admin.proto payload_variant oneOf:

- removeNode(node) — remove a node from device NodeDB
- setScale(scale) — e-ink display DPI calibration
- sendInputEvent(event) — synthetic button/touch input
- addContact(contact) — shared contact management
- keyVerification(verification) — key verification exchange
- rebootOta(after) — reboot into OTA update mode
- otaRequest(event) — firmware update control
- setSensorConfig(config) — attached sensor configuration
- exitSimulator() — exit firmware simulator (dev only)

The SDK AdminApi now exposes every admin operation defined in the
meshtastic protobufs spec.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Expose a public escape hatch on RadioClient for sending raw ToRadio
frames that aren't MeshPackets. This is needed by consumers that
manage MQTT client proxy messages and XModem file transfers — both
are non-packet ToRadio variants that the engine passes directly to
the transport without internal tracking.

The MeshEngine.sendToRadio() method visibility is changed from
private to internal so RadioClient can delegate to it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…d surface

SDK gap implementation for multi-client consumption:

Protocol Utilities (S1):
- DeviceCapabilities: firmware version parsing + capability gates
- NodeIds: toDefaultId()/fromDefaultId() conversions
- SfppHash: SFPP message deduplication hash
- ChannelUrls: channelNameHashDjb2() for channel identification
- PositionUtils: Haversine distance, bearing, coordinate validation

Missing APIs (S2):
- SharedContactUrl: contact URL encoding/decoding
- ConnectionState extensions: isUsable, isInProgress, statusMessage
- RouteDiscoveryResult: traceroute result model from proto
- NodeChange.WentOffline/CameOnline: presence event types
- NeighborInfo: parsed neighbor info model

Higher-Level Features (S3):
- ChannelHelpers: validation, findEmptySlot, createSettings
- RetryPolicy: None/Fixed/ExponentialBackoff strategies
- CongestionLevel + CongestionMetrics: mesh congestion awareness
- MeshEvent: CongestionWarning, MqttConnected, MqttDisconnected

Store-and-Forward (S4):
- StoreForwardApi interface + StoreForwardStats + StoreForwardEvent

All features are KMP commonMain with full test coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ion, Store-and-Forward impl

Engine Wiring:
- E1: CongestionMetrics emission on telemetry level transitions (MeshEvent.CongestionWarning)
- E2: Presence timer with configurable timeout (Builder.presenceTimeout), emits WentOffline/CameOnline
- E3: MessageHandle.retryWith(policy) suspend extension for structured retries
- E4: StoreForwardApiImpl — RPC dispatch, server discovery, event emission via RadioClient.storeForward

Integration Tests:
- CongestionEmissionTest: threshold transitions, zero suppression, per-node tracking
- PresenceTimerTest: stale→offline, recovery→online, self-exclusion
- MessageHandleRetryTest: retry/no-retry/exhaustion/exponential-backoff
- StoreForwardImplTest: instantiation, state, RPC smoke

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add SfppLinkProvided and SfppCanonAnnounced events to StoreForwardApi
- StoreForwardApiImpl: parse SFPP packets, compute hashes, emit events
- MeshTopology: incremental graph from NeighborInfo (BFS shortest path, SNR edges)
- Tests for SFPP event emission and topology graph operations

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- MeshTopology: usage example, Edge KDoc, shortestPath return docs
- RetryPolicy: document delayForAttempt null return
- MeshTopologyTest: clear(), self-loop, disconnected components
- StoreForwardApiImplSfppTest: malformed payloads, null hash, unknown type

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…opology doc

- SfppLinkProvided.to now emits normalized destination (broadcast 0 → NodeId.BROADCAST)
  so consumers can reliably correlate/recompute hashes from event data
- MeshTopology KDoc: remove false thread-safety claim (unsynchronized mutableMap)
- Update SFPP test to assert normalized broadcast destination

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- AdminApi.forNode(dest): returns a remote-targeting AdminApi instance
  that routes all admin calls to the specified mesh node
- AdminApi.getDeviceMetadata(): request DeviceMetadata from target node
- RadioClient.sendReaction(): convenience for emoji reactions with
  proper emoji indicator and reply_id

These additions eliminate the need for consumers to manually construct
AdminMessage + MeshPacket envelopes for remote admin operations.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- RadioClient.requestNodeInfo(node): sends NODEINFO_APP with
  want_response=true to request a remote node's identity
- Fix AdminEditImpl.enqueueOrThrow to route through localNode()
  (respects targetNode for remote editSettings)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add getOrNull, getOrElse, isSuccess, map, fold, onSuccess, onFailure
  extensions to AdminResult for ergonomic API usage
- Cache MeshTopology.nodes with invalidation on addNeighborInfo/removeNode/clear
  to avoid O(n) allocation on every access
- Document threading risk on RadioClient.close() (runBlocking can ANR on
  main thread — prefer suspend disconnect() from coroutines)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…, error mapping

Phase 1 critical fixes:

1. MeshTopology thread-safety: All methods are now suspend with
   internal Mutex synchronization. Safe for concurrent engine/UI access.
   Property 'nodes' → function nodes(), 'edgeCount' → edgeCount().

2. submitAdminAck timeout: Wrap stateFlow.first{} with
   withTimeoutOrNull(rpcTimeout) so ACK-based admin ops cannot block
   forever if transport dies without emitting a terminal state.

3. Flow caching: RadioClient's public flow properties (connection,
   ownNode, configBundle, channels, nodes, packets, events) are now
   initialized once at construction — no new flow/StateFlow wrapper
   created per property access.

4. Routing error mapping: Added AdminResult.RateLimited variant for
   RATE_LIMIT_EXCEEDED. Fixed ACK-path mapSendFailureToAdminResult to
   properly map ADMIN_BAD_SESSION_KEY → SessionKeyExpired and
   ADMIN_PUBLIC_KEY_UNAUTHORIZED → Unauthorized (previously fell through
   to generic Failed). CommandDispatcher also maps RateLimited.

5. Session passkey: Verified already fully implemented (engine stamps
   all outgoing admin msgs, seeds from handshake, retryOnSessionExpiry
   handles refresh).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rchy

- getOrThrow() maps failure variants to typed exceptions for callers
  preferring exception-based error handling
- AdminResultException sealed hierarchy with SessionKeyExpired, Unauthorized,
  Timeout, RateLimited, NodeUnreachable, RoutingFailed(error)
- Improved toggleMuted KDoc (documents toggle-not-set firmware semantics)
- Tests for all getOrThrow() failure paths, fold, and map

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- AdminApiImplComprehensiveTest: 75 tests covering all config/channel/device ops
- MeshEngineEdgeCasesTest: 28 tests for malformed packets, dedup, encryption
- HandshakeAndReconnectTest: handshake FSM, backoff, session key lifecycle
- StoreForwardProtocolTest: server discovery, history, SFPP, multi-chunk

Also hardens MeshEngine with frame validation and duplicate detection.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…PI surface

- Fix 5 sample compilation errors: add NodeChange.CameOnline/WentOffline
  branches (ConnectCmds.kt, TuiCmd.kt, MeshSampleController.kt) and
  AdminResult.RateLimited branches (Scenarios.kt x2)
- Update api-reference.md: add CameOnline/WentOffline to NodeChange,
  RateLimited to AdminResult, forNode() to AdminApi, sendReaction()/
  sendRaw() to Outbound table, StoreForwardApi full section, all 23
  config builder extensions, StoreForwardStats/Event/Api to package map
- Update error-taxonomy.md: add RateLimited to AdminResult listing,
  wire mapping table, and example when block
- Update integration-guide.md: add §6 admin operations and config
  builders with editSettings/forNode examples
- Update reactive-lifecycle-management.md: add WentOffline/CameOnline
  to NodeChange when example
- Update meshtastic-android-migration.md: add presence variants to
  scan() accumulator and make AdminResult when exhaustive

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add KDoc to ~15 public API symbols (AutoReconnectConfig, BatteryStatus,
  ChannelHelpers, ChannelUrls, CongestionLevel, Connect, DeviceCapabilities)
- Fix incomplete comment fragment in MeshEngine.kt
- Update KeyVerificationPrompt: remove stale Phase-1 marker, clarify as
  marker interface pending PKI verification UI
- Update RadioClient.Builder transport comment: Phase-2 → Future
- Fix stale sample paths in docs/decisions/003-tooling.md

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Phase 2 RPC dispatch, admin timeout, backpressure, and reconnect are all
implemented. Remove 'Phase 2' labels from EngineMessage, CommandDispatcher,
P2AdminRpcTest, and HandshakeFsmTest comments since they describe current
behavior, not future plans.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jamesarich jamesarich marked this pull request as draft May 6, 2026 22:47
jamesarich and others added 6 commits May 6, 2026 17:58
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Broadcast MessageHandle.await() would hang forever because the mesh
never sends a Routing ACK for broadcasts. The engine now transitions
broadcast sends to Acked immediately after dispatching to the transport.

- MeshEngine.dispatchSend: auto-resolve broadcast (to=BROADCAST, no
  want_response) to Acked and remove from pendingSends
- Scenarios: rename cs2 to 'broadcast text acceptance', add cs7 unicast
  DM scenario (requires --peer-node)
- ConformanceCmd: wire cs7 into the conformance sweep
- Tests: update 4 existing tests that assumed broadcast stays in Sent,
  add sendText_broadcastAutoResolvesToSuccess test

566 tests, 0 failures. Verified against real hardware (firmware 2.7.19):
cs1 ✓ cs2 ✓ cs3 ✓ cs5 ✓

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Align with Apple/Android client behavior: sendText() now sets
want_ack=true on all packets (including broadcasts). The firmware
generates an implicit ACK when it overhears a neighbor relay the
packet, providing relay confirmation.

Engine changes:
- Fire-and-forget broadcasts (want_ack=false) still auto-resolve
- Broadcasts with want_ack=true arm the ACK timeout and wait for
  the firmware's implicit ACK (or timeout to Failed)
- Removes the unconditional broadcast auto-resolve that previously
  reported success before the radio even transmitted

This gives consumers meaningful feedback: Success means at least one
mesh node relayed the message. Failure (AckTimeout) means no relay
was overheard within the timeout window.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace wildcard import in StoreForwardApiTest with explicit imports
- Apply spotless formatting across source and test files

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Regenerated via :core:updateKotlinAbi to reflect new public API surface.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR closes multiple SDK gaps discovered during a hard cutover integration into Meshtastic-Android by adding missing public APIs (notably Store-and-Forward, presence tracking, retry helpers, and various convenience builders), expanding test coverage, and syncing documentation/specs to the updated behavior and API surface.

Changes:

  • Add new public APIs and utilities (StoreForwardApi, presence NodeChange events, congestion helpers, retry policy, node status/mesh-node helpers, channel helpers, shared-contact URL support).
  • Expand protocol/engine behavior coverage with extensive new unit/integration tests (WireCodec, StoreForward/SFPP, presence timer, external config changes, etc.).
  • Refresh docs and samples for new sealed variants, updated semantics, and new CLI conformance scenario.

Reviewed changes

Copilot reviewed 103 out of 105 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
transport-ble/src/androidMain/kotlin/org/meshtastic/sdk/transport/ble/BleTransport.android.kt Adds Android factory for creating BleTransport from persisted MAC address.
testing/src/commonMain/kotlin/org/meshtastic/sdk/testing/FakeRadioTransport.kt Adds test injection helpers for arbitrary packets and Store-and-Forward responses.
testing/api/testing.klib.api Updates KLIB ABI surface for FakeRadioTransport injections.
testing/api/jvm/testing.api Updates JVM ABI surface for FakeRadioTransport injections.
samples/parity-app/src/commonMain/kotlin/org/meshtastic/sample/MeshSampleController.kt Updates sample to handle new NodeChange presence events.
samples/cli/src/main/kotlin/org/meshtastic/cli/conformance/Scenarios.kt Refines cs2 semantics and adds cs7 unicast-DM conformance scenario.
samples/cli/src/main/kotlin/org/meshtastic/cli/cmd/TuiCmd.kt Updates TUI node event logging for presence events.
samples/cli/src/main/kotlin/org/meshtastic/cli/cmd/ConnectCmds.kt Updates CLI JSON/human node events output for presence events.
samples/cli/src/main/kotlin/org/meshtastic/cli/cmd/ConformanceCmd.kt Exposes cs7 filtering and execution wiring.
gradle/libs.versions.toml Bumps Android Gradle Plugin version.
docs/SPEC.md Syncs AdminApi spec (nodeDbReset signature change).
docs/protocol.md Updates protocol notes (admin channel indexing, session-passkey timing, reconnect wake bytes, managed mode, heartbeat nonce behavior, BLE commit disconnect note).
docs/integration-guide.md Adds Admin/config builder usage section and renumbers subsequent sections.
docs/error-taxonomy.md Documents AdminResult.RateLimited and routing error interception mapping.
docs/decisions/003-tooling.md Updates sample app paths in tooling ADR.
docs/consumer-guides/reactive-lifecycle-management.md Updates guide examples for NodeChange presence events.
docs/architecture/meshtastic-android-migration.md Updates migration guide for presence events and new AdminResult variant handling.
docs/api-reference.md Expands API reference for StoreForwardApi, presence NodeChange events, new send APIs, AdminResult.RateLimited, config builders, forNode().
core/src/jvmTest/kotlin/org/meshtastic/sdk/MeshTopologyTest.kt Adds tests for MeshTopology graph operations.
core/src/jvmTest/kotlin/org/meshtastic/sdk/internal/StoreForwardApiImplSfppTest.kt Adds SFPP StoreForward event behavior tests.
core/src/commonTest/kotlin/org/meshtastic/sdk/WireCodecTest.kt Adds additional framing/boundary/resync test coverage.
core/src/commonTest/kotlin/org/meshtastic/sdk/P2RoutingRpcTest.kt Resolves NeighborInfo type ambiguity by aliasing proto type in tests.
core/src/commonTest/kotlin/org/meshtastic/sdk/P0ReliabilityTest.kt Updates broadcast ACK expectations and adds want_ack broadcast timeout test.
core/src/commonTest/kotlin/org/meshtastic/sdk/NodeStatusTest.kt Adds tests for online/connection/signal quality helpers on NodeInfo.
core/src/commonTest/kotlin/org/meshtastic/sdk/MeshNodeTest.kt Adds tests for MeshNode convenience wrapper/accessors.
core/src/commonTest/kotlin/org/meshtastic/sdk/internal/NodeDiffTest.kt Adds tests for diffNodeFields field categorization.
core/src/commonTest/kotlin/org/meshtastic/sdk/internal/ConfigMergeTest.kt Adds tests for config/module-config merge helpers.
core/src/commonTest/kotlin/org/meshtastic/sdk/HandshakeFsmTest.kt Renames/retitles audit section header.
core/src/commonTest/kotlin/org/meshtastic/sdk/ExternalConfigChangeTest.kt Adds tests for unsolicited admin updates applying to local state + event emission.
core/src/commonTest/kotlin/org/meshtastic/sdk/ext/StoreForwardImplTest.kt Adds StoreForward API integration tests using FakeRadioTransport.
core/src/commonTest/kotlin/org/meshtastic/sdk/ext/StoreForwardApiTest.kt Adds basic StoreForwardStats and StoreForwardEvent sealed-shape tests.
core/src/commonTest/kotlin/org/meshtastic/sdk/ext/SharedContactUrlTest.kt Adds tests for shared-contact URL encode/parse behavior.
core/src/commonTest/kotlin/org/meshtastic/sdk/ext/SfppHashTest.kt Adds tests for SFPP hash properties (size/determinism).
core/src/commonTest/kotlin/org/meshtastic/sdk/ext/RouteDiscoveryResultTest.kt Adds tests for RouteDiscoveryResult assembly and formatting.
core/src/commonTest/kotlin/org/meshtastic/sdk/ext/RetryPolicyTest.kt Adds tests for retry delay computation.
core/src/commonTest/kotlin/org/meshtastic/sdk/ext/PresenceTimerTest.kt Adds tests for presence timeout/offline-online transitions.
core/src/commonTest/kotlin/org/meshtastic/sdk/ext/PositionUtilsTest.kt Adds tests for position conversions/validation/distance/bearing.
core/src/commonTest/kotlin/org/meshtastic/sdk/ext/PayloadAccessorsTest.kt Adds tests for packets/textMessages flow and new payload accessors.
core/src/commonTest/kotlin/org/meshtastic/sdk/ext/NodeIdsTest.kt Adds tests for default-id formatting/parsing.
core/src/commonTest/kotlin/org/meshtastic/sdk/ext/NodeChangePresenceTest.kt Adds tests ensuring presence changes are pattern-matchable NodeChange variants.
core/src/commonTest/kotlin/org/meshtastic/sdk/ext/NeighborInfoTest.kt Adds tests for parsed NeighborInfo model.
core/src/commonTest/kotlin/org/meshtastic/sdk/ext/MqttEventsTest.kt Adds tests for MQTT MeshEvent variants.
core/src/commonTest/kotlin/org/meshtastic/sdk/ext/MessageHandleRetryTest.kt Adds tests for MessageHandle.retryWith behavior using a fake handle.
core/src/commonTest/kotlin/org/meshtastic/sdk/ext/DeviceCapabilitiesTest.kt Adds tests for firmware version parsing and capability gating.
core/src/commonTest/kotlin/org/meshtastic/sdk/ext/ConnectionStateTest.kt Adds tests for new ConnectionState convenience extensions.
core/src/commonTest/kotlin/org/meshtastic/sdk/ext/CongestionTest.kt Adds tests for congestion level derivation and backoff suggestions.
core/src/commonTest/kotlin/org/meshtastic/sdk/ext/CongestionEmissionTest.kt Adds tests for congestion warning emission behavior.
core/src/commonTest/kotlin/org/meshtastic/sdk/ext/ChannelUrlsTest.kt Adds test for DJB2 channel-name hash.
core/src/commonTest/kotlin/org/meshtastic/sdk/ext/ChannelHelpersTest.kt Adds tests for channel validation and empty-slot selection.
core/src/commonTest/kotlin/org/meshtastic/sdk/EngineTest.kt Adjusts engine tests to use unicast packets where broadcasts now auto-resolve.
core/src/commonTest/kotlin/org/meshtastic/sdk/EngineAuditFixesTest.kt Updates audit test to assert DeviceUIConfig is captured in ConfigBundle.
core/src/commonTest/kotlin/org/meshtastic/sdk/AdminResultExtensionsTest.kt Adds tests for AdminResult extension helpers and getOrThrow exceptions.
core/src/commonMain/kotlin/org/meshtastic/sdk/TelemetryApi.kt Adds telemetry RPCs for health/host/traffic-management metrics.
core/src/commonMain/kotlin/org/meshtastic/sdk/StoreForwardApi.kt Introduces StoreForwardApi, StoreForwardStats, and StoreForwardEvent public types.
core/src/commonMain/kotlin/org/meshtastic/sdk/Storage.kt Extends ConfigBundle to optionally include DeviceUIConfig.
core/src/commonMain/kotlin/org/meshtastic/sdk/SharedContactUrl.kt Adds shared-contact URL encoding/parsing helpers and extension.
core/src/commonMain/kotlin/org/meshtastic/sdk/SfppHash.kt Adds SFPP deduplication hash computation utility.
core/src/commonMain/kotlin/org/meshtastic/sdk/RoutingApi.kt Disambiguates proto NeighborInfo type via alias in public API.
core/src/commonMain/kotlin/org/meshtastic/sdk/RouteDiscoveryResult.kt Adds parsed traceroute result model + formatting helper.
core/src/commonMain/kotlin/org/meshtastic/sdk/RetryPolicy.kt Introduces retry policy types and delay computation.
core/src/commonMain/kotlin/org/meshtastic/sdk/Result.kt Adds ConnectionState helpers and AdminResult.RateLimited + AdminResult extensions/exceptions.
core/src/commonMain/kotlin/org/meshtastic/sdk/PositionUtils.kt Adds reusable geographic computations (validation, haversine distance, bearing).
core/src/commonMain/kotlin/org/meshtastic/sdk/PayloadAccessors.kt Adds RadioClient.textMessages flow and new payload decoding helpers.
core/src/commonMain/kotlin/org/meshtastic/sdk/NodeStatus.kt Adds online/connection/signal quality helpers for NodeInfo.
core/src/commonMain/kotlin/org/meshtastic/sdk/NodeIds.kt Adds default-id formatting/parsing helpers.
core/src/commonMain/kotlin/org/meshtastic/sdk/Node.kt Adds presence NodeChange variants + new MeshEvent variants and external-config change kinds.
core/src/commonMain/kotlin/org/meshtastic/sdk/NeighborInfo.kt Introduces parsed NeighborInfo model distinct from proto type.
core/src/commonMain/kotlin/org/meshtastic/sdk/MessageHandleRetry.kt Adds MessageHandle.retryWith and retryability classification.
core/src/commonMain/kotlin/org/meshtastic/sdk/MeshTopology.kt Introduces a topology graph utility built from NeighborInfo reports.
core/src/commonMain/kotlin/org/meshtastic/sdk/MeshNode.kt Adds MeshNode consumer-friendly wrapper with flattened accessors.
core/src/commonMain/kotlin/org/meshtastic/sdk/internal/TelemetryApiImpl.kt Implements new telemetry RPC variants and propagates RateLimited.
core/src/commonMain/kotlin/org/meshtastic/sdk/internal/RoutingApiImpl.kt Updates neighbor-info RPC to use proto alias consistently.
core/src/commonMain/kotlin/org/meshtastic/sdk/internal/NodeDiff.kt Adds internal node-diff helper used for changed-field reporting.
core/src/commonMain/kotlin/org/meshtastic/sdk/internal/EngineMessage.kt Adds presence tick message and removes stale “Phase 2” wording.
core/src/commonMain/kotlin/org/meshtastic/sdk/internal/ConfigMerge.kt Adds internal config merge utilities for section-based replacement.
core/src/commonMain/kotlin/org/meshtastic/sdk/internal/CommandDispatcher.kt Extends RPC response decoding (Admin/UI/status/etc.) and StoreForward decode paths; maps RateLimited.
core/src/commonMain/kotlin/org/meshtastic/sdk/internal/Base64Url.kt Centralizes base64url encode/decode for URL-based sharing features.
core/src/commonMain/kotlin/org/meshtastic/sdk/DeviceCapabilities.kt Adds firmware version parsing and capability flags.
core/src/commonMain/kotlin/org/meshtastic/sdk/Connect.kt Adds @since tag to connectAndAwaitReady documentation.
core/src/commonMain/kotlin/org/meshtastic/sdk/CongestionLevel.kt Adds congestion metrics model and derived levels/backoff guidance.
core/src/commonMain/kotlin/org/meshtastic/sdk/ConfigBuilders.kt Adds AdminApi config builder extensions for common writes and batching.
core/src/commonMain/kotlin/org/meshtastic/sdk/ChannelUrls.kt Reuses centralized base64url helpers and adds DJB2 channel-name hashing.
core/src/commonMain/kotlin/org/meshtastic/sdk/ChannelHelpers.kt Adds channel validation and slot selection helpers.
core/src/commonMain/kotlin/org/meshtastic/sdk/BatteryStatus.kt Improves KDoc and adds @since tags for battery status helpers.
core/src/commonMain/kotlin/org/meshtastic/sdk/AutoReconnectConfig.kt Minor KDoc wording update.
build.gradle.kts Applies axion-release conditionally for composite-build compatibility and sets a composite fallback version.

Comment thread core/src/commonMain/kotlin/org/meshtastic/sdk/MeshTopology.kt Outdated
Comment thread core/src/commonMain/kotlin/org/meshtastic/sdk/MeshTopology.kt Outdated
Comment thread core/src/commonMain/kotlin/org/meshtastic/sdk/RetryPolicy.kt Outdated
…olicy example

- MeshTopology: clarify KDoc that Mutex is for consumer-side concurrency,
  not engine-actor hot path (ADR-002 compliant)
- MeshTopology.nodes(): return immutable copy via toSet() to prevent
  cache corruption through external mutation
- RetryPolicy: fix KDoc example from policy.execute(handle) to
  handle.retryWith(policy) matching actual API

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: James Rich <james.a.rich@gmail.com>
@jamesarich jamesarich force-pushed the feat/meshtastic-android-integration-gaps branch from e545616 to ef0b432 Compare May 7, 2026 17:21
@jamesarich jamesarich marked this pull request as ready for review May 9, 2026 19:46
@jamesarich jamesarich merged commit e6b1b99 into main May 9, 2026
11 checks passed
@jamesarich jamesarich deleted the feat/meshtastic-android-integration-gaps branch May 9, 2026 19:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants