[Board] Boards are tombstoned, never deleted - #435
Closed
KacperKozak wants to merge 1 commit into
Closed
Conversation
KacperKozak
added a commit
that referenced
this pull request
Aug 31, 2026
* Tombstone deleted Boards, never remove the row Deleting a Board now stamps boards.deleted_at instead of removing the row, so Ride History keeps a resolvable Board identity (ADR 0027). Board-owned configuration is still hard-deleted; telemetry and Tune Profiles are not. getBoards() filters tombstones, getBoard(id) deliberately resolves them, and connect paths refuse a tombstoned Board. An ordinary upsert carries an existing tombstone forward, so deletion is terminal. Ported from #276 (#279) and the closed #435 (#428), renumbered onto schema 40 -> 41. * Key telemetry on the Board id, not the BLE identifier Every telemetry table — frames, minute buckets, markers, diagnostic events and metric exclusion ranges — now keys on board_id and drops both device_id (the mutable BLE identifier) and device_name (the Board name denormalized at capture time). Ride History resolves Board names by lookup, so a rename relabels history (ADR 0028, closes #274). Migration 41 -> 42 rebuilds all five tables, resolving each BLE identifier to a Board exactly once through a shared scratch map so no two tables can pick different claimants of a duplicated identifier. Rows that resolve to no Board mint a tombstoned Board named from their historical device_name, so orphaned history keeps a label and stays joinable. The boardId -> bleId translation used by markers, events and ranges is deleted. RideHistoryRepository (added on dev after #276 branched) is rekeyed the same way. Ported from #276 (#280) with the follow-up dedup and marker/event/range rekey. * Align the iOS schema stamp and the docs with board-id keying The iOS backup stamp still claimed schema 41, so a current backup left the board-id migration unstamped and replayed it on restore — caught by TelemetryMigrationTests. Also rekeys the native API and history docs, adds both ADRs to the docs index, and records the Board Tombstone rules in CONTEXT.md. * Record Board-id keying as a whole-schema rule, not a telemetry one Every durable Board-owned table now keys on board_id; boards.ble_id is the only BLE identifier left and is a Board Link attribute, not a join key. * Fix nested GRDB read crash in Ride History page boardNamesById() opens its own pool read; calling it inside getPage's read tripped GRDBPrecondition and killed the reader queue. Hoist it out, like every other call site already does.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Deleting a Board now stamps
deleted_atinstead of removing its row, so the rides it produced keep a Board identity that still resolves. Board-owned configuration is still hard-deleted, and Ride History is untouched, exactly as before.Note
Risk: Medium — changes deletion semantics and the Board read paths on both platforms.
Complexity: Medium — small surface, but the list/lookup split and the no-resurrect rule have to hold identically in Room and GRDB.
DB: Migration — additive nullable
boards.deleted_at(Room 36 → 37, GRDBv37_board_deleted_at); existing rows upgrade as live.Tasks
Description
Ride History outlives the Board that produced it. The app has always kept telemetry after a Board delete, but the
boardsrow vanishing left those rides pointing at an id that resolved to nothing, so history could only fall back to thedevice_namesnapshotted on each row — a frozen label, not an identity. A tombstone keeps the row resolvable.The rule is a deliberate split:
getBoards()filtersdeleted_at IS NULL, so a tombstone is gone from every rider-facing list, whilegetBoard(id)resolves tombstones on purpose, because history still has to name a deleted Board. Anything that acts on a Board rather than describing one — building a session config for a connect — checks the stamp and refuses. Deletion is terminal: an ordinary upsert from the bridge carries an existing tombstone forward rather than clearing it, and deleting an already-tombstoned Board is a no-op, so the stamp never moves.The decision, its rejected alternatives and its consequences are in
docs/adr/0027-boards-are-tombstoned-never-deleted.md.This slice was specified in #279 and implemented on the unmerged sync branch behind #276, which left
devstill hard-deleting. It is extracted here without the sync half — nosync_seq, no delete-action log, no server contract; those stay with #276 and will need reconciling when it merges, since it carries its owndeleted_atat a different migration number.Making Board identity resolvable is the prerequisite for the identity half of #274 — putting
board_idon the telemetry tables so history stops relying on the denormalizeddevice_name. That remains a separate slice, anddevice_nameis deliberately untouched here: telemetry keys on the BLE id, not the Board id, and boards hard-deleted by earlier versions are already gone, so that label is still the only one some existing rides have.Closes #428
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.