Skip to content

fix: resolve release/2.8.0 branch-review findings (car hosts, AI node IDs, discovery abort, AQ zeros)#5813

Merged
jamesarich merged 2 commits into
release/2.8.0from
fix/release-280-review-fixes
Jun 16, 2026
Merged

fix: resolve release/2.8.0 branch-review findings (car hosts, AI node IDs, discovery abort, AQ zeros)#5813
jamesarich merged 2 commits into
release/2.8.0from
fix/release-280-review-fixes

Conversation

@jamesarich

@jamesarich jamesarich commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Repairs six defects found while reviewing the full release/2.8.0 branch against main. Three would have shipped a feature broken or unsafe in production in a way CI cannot catch; the rest fix a silently-dead search backfill, restore suppressed clean-air telemetry, and add the regression coverage that was missing for these paths.

🐛 Bug Fixes

  • Car App could not connect to Android Auto in any release build (feat(car): Android Car App Library integration #5633). MeshtasticCarAppService.createHostValidator() built the HostValidator from a car_hosts_allowlist of bare package names, but androidx.car.app's addAllowedHosts() requires digest,packageName entries and threw IllegalArgumentException on the first one during the host handshake (masked locally by the debug ALLOW_ALL_HOSTS_VALIDATOR). Replaced with Google's official entries, copied verbatim from androidx.car.app:1.9.0-alpha01's bundled hosts_allowlist_sample (3 Android Auto gearhead keys + 3 AAOS templates.host keys). ⚠️ Security-sensitive — worth a sanity check before merge.
  • AppFunctions emitted malformed node IDs for ~half the node-num space (feat(ai): Add App Functions for system AI integration #5585). AiFunctionProviderImpl used "!${node.num.toString(16)}"; for high-bit (negative Int) node nums this produced !-1 instead of the canonical !ffffffff, and the reverse toInt(16) lookup threw for canonical IDs greater than Int.MAX. Switched to the existing NodeAddress.numToDefaultId / idToNum helpers.
  • Discovery scan abort stranded the radio on the scan preset (feat(discovery): mesh network discovery #5275). pauseAndAbort() cancelled its own scanScope before restoring the home LoRa preset, so the restore/finalize threw CancellationException and never ran — leaving the radio on the scan modem preset with the UI stuck on Failed. Reordered to finalize and reach the terminal state, restore on applicationScope, then cancelScanInternal() last (mirroring stopScan()).
  • FTS5 historical-message backfill was dead code (feat: FTS5 full-text message search #5373). It keyed on json_extract(data, '$.text'), but DataPacket.text is a computed property never serialized into the stored JSON (the body is persisted as bytes), so the backfill silently no-opped and every message received before the v39 upgrade stayed permanently unsearchable. Replaced with a Kotlin-side decode that writes message_text via the previously-unused updateMessageText.
  • Air-quality summary cards hid legitimate 0 readings (feat: add air quality telemetry display (PM1.0, PM2.5, PM10, CO2) #5701). Dropped the != 0 guards on the node-detail cards (kept the ?.let null/presence check), consistent with the fix(node): chart local-node air-quality telemetry (orphaning + zero-suppression) #5793 chart/CSV zero-suppression fix.

🧹 Chores

  • Removed the now-unused HEX_RADIX constant from AiFunctionProviderImpl.

🧪 Testing Performed

  • AiFunctionProviderImplTest — added getNodeDetails_round_trips_high_bit_node_num (canonical ID round-trip for high-bit nums).
  • PacketFtsSearchTest (new, core:database androidHostTest) — search match/non-match, conversation scoping, and the backfill regression (the new test fails against the old json_extract implementation).
  • DiscoveryScanEngineTest (feature:discovery commonTest) — reconnect-timeout abort reaches Complete(Failed), finalizes the session as failed, and restores the home preset, plus stopScan and normal-completion restore. FakeRadioController now records setLocalConfig calls so the restore can be asserted.
  • Full local baseline: spotlessCheck detekt assembleDebug test allTests kmpSmokeCompile → BUILD SUCCESSFUL (includes the KoinVerificationTest typed-bootstrap graph).

🤖 Generated with Claude Code

Fixes four defects found reviewing the full release/2.8.0 branch; three would
have shipped a feature broken/unsafe in production, invisible to CI.

- car: HostValidator allowlist now uses Google's official "digest,packageName"
  entries (copied from androidx.car.app:1.9.0-alpha01's hosts_allowlist_sample).
  Bare package names made addAllowedHosts() throw IllegalArgumentException on the
  first entry, so the car app never connected to Android Auto in any release build
  (masked locally by the debug ALLOW_ALL_HOSTS_VALIDATOR).
- ai(appfunctions): format/parse node IDs via NodeAddress.numToDefaultId/idToNum.
  The old Int.toString(16) emitted "!-1" instead of "!ffffffff" and the reverse
  toInt(16) failed for canonical 8-hex IDs > Int.MAX, so AI agents got malformed
  IDs and broken lookups for ~half the node-num space. Drops the dead HEX_RADIX
  const; adds a high-bit round-trip regression test.
- discovery: pauseAndAbort() now finalizes the session, reaches the terminal state,
  and restores the home preset on applicationScope before cancelScanInternal() runs
  last. Previously it cancelled its own scanScope first, so the next suspend threw
  CancellationException and skipped restore/finalize — stranding the radio on the
  scan modem preset with the UI stuck on Failed. Mirrors stopScan()'s ordering.
- node(air-quality): show present-zero readings in the summary cards (drop the
  != 0 guards, keep the null/presence check), consistent with the #5793 chart fix.

Verified: spotlessCheck detekt assembleDebug test allTests kmpSmokeCompile -> BUILD SUCCESSFUL.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the bugfix PR tag label Jun 16, 2026
…rage

Resolves the two MEDIUM test-coverage findings from the release/2.8.0 review.

- database(fts5): the historical-message backfill was dead code. It keyed on
  json_extract(data, '$.text'), but DataPacket.text is a computed property that is
  never serialized into the stored JSON (the body is persisted as `bytes`), so the
  predicate was always NULL — every message received before the v39 upgrade stayed
  permanently unsearchable. Replace it with a Kotlin-side decode that reads each
  packet's payload and writes message_text via updateMessageText (previously
  unused). countPacketsNeedingBackfill no longer depends on json_extract. Adds
  PacketFtsSearchTest covering search match/non-match, conversation scoping, and the
  backfill regression (the new test fails against the old json_extract code).

- discovery: add tests for the home-preset restoration path — a reconnect-timeout
  abort now reaches Complete(Failed), finalizes the session as "failed", and
  restores the home LoRa preset (the behavior the pauseAndAbort ordering fix
  enables), plus stopScan and normal-completion restore. FakeRadioController now
  records setLocalConfig calls so the restore can be asserted.

Verified: spotlessCheck detekt assembleDebug test allTests kmpSmokeCompile -> BUILD SUCCESSFUL.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jamesarich jamesarich merged commit d49670a into release/2.8.0 Jun 16, 2026
17 checks passed
@jamesarich jamesarich deleted the fix/release-280-review-fixes branch June 16, 2026 20:32
jamesarich added a commit that referenced this pull request Jun 16, 2026
… IDs, discovery abort, AQ zeros) (#5813)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jamesarich added a commit that referenced this pull request Jun 16, 2026
… IDs, discovery abort, AQ zeros) (#5813)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jamesarich jamesarich mentioned this pull request Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix PR tag

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant