Add per-device truth for multi-computer dives (PRO-67, PRO-34) - #167
Conversation
Phase A — import correctness: - Extract shared GasMixMergeHelper (dedupe by composition, gasmixIndex remap, per-device device_id) used by both BLE and Shearwater Cloud import paths; Cloud merge previously never remapped sample indices - Filter imported gases to slots actually referenced by samples - Gate Cloud time-proximity merging on device ownership so buddy computers (ownership: other) no longer merge into owned dives - Dive-level GF/deco metadata now comes from the primary device instead of silent first-wins across computers Phase B — per-device settings and UI: - Migration 018: dive_device_settings (GF, deco model, salinity, surface pressure, is_primary per computer), populated on all import paths and backfilled on re-import - Device picker drives gas list, deco/GF display, and Replay prefill; defaults to primary device with subtle conflict footnote when computers disagree - splitDive moves the device's settings row and promotes a new primary on the original dive Co-authored-by: Cursor <cursoragent@cursor.com>
Self-review (project checklist)Validation run locally:
Correctness spot-checks:
Known gaps, deliberately deferred:
Manual QA still required (device-dependent): re-import Shearwater |
…ings - Cloud import grouping: buddy-owned rows now form singleton groups without breaking the current group, so two owned computers still merge when a buddy row falls between them chronologically - mergeDevices: reassign dive_device_settings rows from loser to winner, dropping the loser's row when the dive already has one for the winner (avoids PK violation) - Regression tests for both scenarios Co-authored-by: Cursor <cursoragent@cursor.com>
Second-opinion review (GPT-5.3 Codex) — findings addressed in f9b9996The independent review found two major issues, both real and both fixed: 1. Interleaved buddy row broke owned-computer merging. The ownership gate compared each row only to the previous one, so 2. 3 (minor). Test coverage gaps — covered by the three tests above. Full suite: 416 tests, 0 failures. Reviewer verdict was "request changes"; both changes are now in. |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
… detection Codecov flagged untested paths that no existing test reached: - DiveDeviceSettings.backfillIfMissing (import paths create rows directly, so the re-import backfill never fired in tests) - Legacy dives.fingerprint fallback in backfillMissingMetadata - DiveService.hasConflictingDeviceSettings (GF and deco model disagreement, agreement, and single-device cases) Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
Implements the multi-computer dive design: one dive record, per-device truth for samples, gases, and deco settings, with the device picker as the source of truth in the UI.
Phase A — import correctness (PRO-67):
GasMixMergeHelper(dedupe by composition,gasmixIndexremap, per-devicedevice_id) used by both BLE and Shearwater Cloud import paths — Cloud merge previously never remapped sample gas indicesownership: other) no longer merge into owned divesPhase B — per-device settings + UI (PRO-34):
dive_device_settingstable (GF low/high, deco model, salinity, surface pressure,is_primaryper computer); populated on all import paths, backfilled on re-import (extends the PRO-62 pattern)DiveDetailView: device picker drives gas list, deco/GF display, and Replay prefill; defaults to primary device on multi-computer dives; subtle footnote when computers disagree ("Varies by computer — showing Petrel")ReplayProfileSheet: GF/deco model prefill from the selected device's settingssplitDivemoves the device's settings row to the new dive and promotes a new primary on the originalDiveService.hasConflictingDeviceSettings()+getDeviceSettings()helpersRepair path: re-importing the Shearwater Cloud
.dbfixes existing merged dives (gas attribution, per-device settings rows) — same flow as PRO-62.Closes PRO-67, PRO-34.
Test plan
swift test), including newGasMixMergeHelperTests, Cloud ownership-gate/settings tests, and split settings testsmake lintclean (SwiftLint 0 violations)xcodebuild -scheme Profundum -destination 'platform=macOS').dbon a Petrel+Perdix dive; confirm gas list and GF follow the device picker; verify conflict footnote when GFs differMade with Cursor