Question
Should device_name be dropped from the telemetry tables, keeping only a device/board identifier?
Raised while adding updated_at sync cursors (PR #273 on KacperKozak/vescape). Not actioned — needs a decision on history semantics first.
Findings from the codebase
The naming is misleading. There is no board_name or board_id on telemetry. The columns are:
device_id = BLE id (SessionConfigBuilder.kt:36 deviceId = bleId)
device_name = board nickname ( deviceName = boardName)
CONTEXT.md:378 already flags this: "device" is ambiguous, resolved term is Board. These columns predate that resolution.
Four tables carry device_name: telemetry_frames, telemetry_minute_buckets, telemetry_markers, diagnostic_events.
It is live, not dead code. Four display consumers:
| where |
renders |
src/screens/main/history/HistoryTelemetryPanel.tsx:512 |
ride title meta via formatRideMeta |
src/modules/history/components/HistorySessionSheet.tsx:129 |
session list row |
src/modules/history/lib/historyMapMarkerInfo.ts:81 |
Board: <name> in marker callout |
src/app/settings/eventLog.tsx:101 |
diagnostic event meta line |
Never filtered, grouped, or ordered on — pure display payload. device_id is a query key (bucket composite PK, marker/frame WHERE clauses).
Why it is not a clean delete
Deriving the name at read time means joining boards.ble_id = telemetry.device_id. ble_id is not a stable identity:
- nullable (unlinked boards)
- mutable — re-linking a board to a different peripheral orphans its old telemetry
- deleting a board wipes the label from past rides; today they keep the name the board had at ride time
- renaming a board retroactively relabels history
docs/adr/0005-ride-history-read-paths-stay-precomputed.md also states history reads stay precomputed and must not reconstruct on read.
So the current denormalization may be deliberate: a durable historical label that survives rename and delete.
Options
- Drop from
telemetry_frames only. That is where the cost actually is — one row per sample at up to 20 Hz, each repeating the name string. Buckets/markers/diagnostic_events are low-cardinality and the column is nearly free there, and they are the actual display sources. Needs confirming that the frames value at TelemetryRepository.kt:938 (frame.deviceName ?: base?.deviceName) is always overridden downstream and never surfaces.
- Add a real
board_id FK to telemetry, backfilled by matching ble_id -> boards, and keep device_name as the historical label. Gives sync a stable board identity instead of a BLE id. Bigger migration, with unresolvable rows for deleted or re-linked boards.
- Leave it. The column earns its keep as a durable label; rename to
board_name/board_id for glossary alignment if anything.
Option 2 interacts with the incremental-sync work: syncing telemetry keyed on a mutable BLE id is likely wrong for the server regardless of the device_name question.
Likely files
modules/vescape-core/android/src/main/java/expo/modules/vescapecore/telemetry/TelemetryEntities.kt - the four Room entities carrying device_name
modules/vescape-core/android/src/main/java/expo/modules/vescapecore/telemetry/TelemetryRepository.kt - write + reconstruction paths, incl. line 938
modules/vescape-core/android/src/main/java/expo/modules/vescapecore/connection/SessionConfigBuilder.kt - where deviceId = bleId / deviceName = boardName originate
modules/vescape-core/ios/telemetry/TelemetryDatabase.swift - iOS DDL for the same four tables
modules/vescape-core/ios/telemetry/TelemetryDao.swift - iOS frame/bucket/marker writes
src/modules/history/lib/sessions.ts - HistorySession.deviceName, the main read shape
docs/adr/0005-ride-history-read-paths-stay-precomputed.md - constraint on history read paths
Question
Should
device_namebe dropped from the telemetry tables, keeping only a device/board identifier?Raised while adding
updated_atsync cursors (PR #273 onKacperKozak/vescape). Not actioned — needs a decision on history semantics first.Findings from the codebase
The naming is misleading. There is no
board_nameorboard_idon telemetry. The columns are:CONTEXT.md:378already flags this: "device" is ambiguous, resolved term is Board. These columns predate that resolution.Four tables carry
device_name:telemetry_frames,telemetry_minute_buckets,telemetry_markers,diagnostic_events.It is live, not dead code. Four display consumers:
src/screens/main/history/HistoryTelemetryPanel.tsx:512formatRideMetasrc/modules/history/components/HistorySessionSheet.tsx:129src/modules/history/lib/historyMapMarkerInfo.ts:81Board: <name>in marker calloutsrc/app/settings/eventLog.tsx:101Never filtered, grouped, or ordered on — pure display payload.
device_idis a query key (bucket composite PK, marker/frameWHEREclauses).Why it is not a clean delete
Deriving the name at read time means joining
boards.ble_id = telemetry.device_id.ble_idis not a stable identity:docs/adr/0005-ride-history-read-paths-stay-precomputed.mdalso states history reads stay precomputed and must not reconstruct on read.So the current denormalization may be deliberate: a durable historical label that survives rename and delete.
Options
telemetry_framesonly. That is where the cost actually is — one row per sample at up to 20 Hz, each repeating the name string. Buckets/markers/diagnostic_events are low-cardinality and the column is nearly free there, and they are the actual display sources. Needs confirming that the frames value atTelemetryRepository.kt:938(frame.deviceName ?: base?.deviceName) is always overridden downstream and never surfaces.board_idFK to telemetry, backfilled by matchingble_id->boards, and keepdevice_nameas the historical label. Gives sync a stable board identity instead of a BLE id. Bigger migration, with unresolvable rows for deleted or re-linked boards.board_name/board_idfor glossary alignment if anything.Option 2 interacts with the incremental-sync work: syncing telemetry keyed on a mutable BLE id is likely wrong for the server regardless of the
device_namequestion.Likely files
modules/vescape-core/android/src/main/java/expo/modules/vescapecore/telemetry/TelemetryEntities.kt- the four Room entities carryingdevice_namemodules/vescape-core/android/src/main/java/expo/modules/vescapecore/telemetry/TelemetryRepository.kt- write + reconstruction paths, incl. line 938modules/vescape-core/android/src/main/java/expo/modules/vescapecore/connection/SessionConfigBuilder.kt- wheredeviceId = bleId/deviceName = boardNameoriginatemodules/vescape-core/ios/telemetry/TelemetryDatabase.swift- iOS DDL for the same four tablesmodules/vescape-core/ios/telemetry/TelemetryDao.swift- iOS frame/bucket/marker writessrc/modules/history/lib/sessions.ts-HistorySession.deviceName, the main read shapedocs/adr/0005-ride-history-read-paths-stay-precomputed.md- constraint on history read paths