Skip to content

[Sync] 2 - Key telemetry on board_id #280

Description

@KacperKozak

Parent

What to build

telemetry_frames and telemetry_minute_buckets key on board_id and stop carrying device_id (the BLE identifier) and device_name (the Board name copied onto every row at capture time). Board names on Ride History are resolved by looking the Board up by id.

The reasoning, including why the denormalized name existed and why it stops earning its keep once Boards are tombstoned, is in docs/adr/0028-telemetry-is-keyed-on-board-id.md. This closes #274.

The Board id is already known at capture — the session config carries it next to the BLE identifier — it simply is not written down.

Migration, Room 30 -> 31 and the GRDB peer:

  • add board_id, backfilled by matching boards.ble_id to device_id
  • mint one tombstoned Board per device_id that matches nothing, named from that row's historical device_name, so telemetry from Boards deleted before [Sync] 1 - Tombstone deleted Boards #279 or re-linked to a different peripheral keeps a label, stays joinable, and can still be backed up
  • move the minute bucket primary key from (bucket_start_ms, device_id) to (bucket_start_ms, board_id), which is what the server already uses
  • drop device_id and device_name from both tables

telemetry_markers, diagnostic_events and metric_exclusion_ranges are not touched. They keep both columns, because that is what crosses the wire for them and they are low-cardinality display rows rather than a per-sample cost.

Three read paths stop reading the name off the sample row and resolve it by lookup instead. This is permitted by docs/adr/0005-ride-history-read-paths-stay-precomputed.md, whose Scope section now says explicitly that the no-reconstruction rule is about replaying Telemetry Samples, not about bounded configuration lookups.

Renaming a Board now retroactively relabels its Ride History. That is intended — it is the same Board — but it is a visible behaviour change.

Likely files

  • modules/vescape-core/android/src/main/java/expo/modules/vescapecore/telemetry/TelemetryEntities.kt - the two entities, their indices and the bucket primary key
  • modules/vescape-core/android/src/main/java/expo/modules/vescapecore/telemetry/TelemetryDao.kt - upsertBuckets, getBucket, insertBatch and the frame range reads
  • modules/vescape-core/android/src/main/java/expo/modules/vescapecore/telemetry/TelemetryDatabase.kt - Room version, the migration and the orphan-Board mint
  • modules/vescape-core/ios/telemetry/TelemetryDatabase.swift - the GRDB peer migration
  • modules/vescape-core/ios/telemetry/TelemetryDao.swift - the GRDB peer writes and reads
  • modules/vescape-core/android/src/main/java/expo/modules/vescapecore/connection/SessionConfigBuilder.kt - where the Board id and the BLE id are both already in hand
  • src/modules/history/lib/sessions.ts - HistorySession, the main read shape carrying the name
  • src/screens/main/history/HistoryTelemetryPanel.tsx, src/modules/history/components/HistorySessionSheet.tsx, src/modules/history/lib/historyMapMarkerInfo.ts - the three display consumers that switch to a lookup

Implementation hints

buildSessionConfig already produces appBoardId alongside deviceId = bleId and deviceName = boardName. The Board id reaches the recording path in the session config; it is not missing, just unused by the telemetry writes.

src/app/settings/eventLog.tsx also renders a device name, but from diagnostic_events, which keeps its columns. Do not change it.

The minute bucket primary key change means a table rebuild on both platforms, not an ALTER. The updated_at and sync_seq columns added earlier on the branch have to survive that rebuild — check them explicitly in the migration test rather than assuming the copy carried them.

Orphan minting is the only migration in this sequence that creates rows the Rider never made. Give it its own test: a frame whose device_id matches no Board must end up pointing at a Board that exists, is tombstoned, and carries the historical name.

Acceptance criteria

  • Frames and minute buckets carry board_id and no longer carry device_id or device_name
  • New frames and buckets are stamped with the Board id at capture time
  • Existing rows backfill by matching boards.ble_id, on both platforms
  • Rows matching no Board get a minted tombstoned Board named from their historical device_name
  • A minted Board never appears in the Rider's Board list
  • Minute bucket primary key is (bucket_start_ms, board_id), and the rebuild preserves updated_at and sync_seq
  • Markers, diagnostic events and metric exclusion ranges are unchanged
  • Ride History, the session sheet and map marker callouts show the Board name, including for a tombstoned Board
  • Renaming a Board changes the name shown on its existing history
  • Migration tests cover backfill, orphan minting and the bucket rebuild on both platforms
  • [Telemetry] Reconsider device_name denormalization on telemetry tables #274 is closed

Blocked by

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:dbTouches database / persistent storagearea:historyRide history, sessions, buckets, graphsarea:nativeTouches native side (modules/vesc-ble, Swift/Kotlin)area:syncBackup sync — native uploader, Sync Cursors, Sync Actions, Device Tokenarea:telemetryLive telemetry ingest and displaycomplexity:highCritical paths, subtle correctness, native pipelines. Use opus.ready-for-agentFully specified, ready for an AFK agent

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions