Skip to content

Detect Oura the same way on both platforms - #1585

Merged
ryanbr merged 1 commit into
mainfrom
fix/oura-detect-parity
Aug 24, 2026
Merged

ryanbr merged 1 commit into
mainfrom
fix/oura-detect-parity

Conversation

@ryanbr

@ryanbr ryanbr commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Post-merge parity fix for #1584 (@pipiche38's #1568). Found while re-reviewing the merged state.

The divergence

The Oura SpO2 candidate branch resolved "is this owner an Oura device" differently on each platform:

Kotlin   DeviceBrandCatalog.isOura(owner)                        -> device-id PREFIX
Swift    regDevices.first { $0.id == owner }?.brand == "Oura"    -> registry BRAND string

Not stylistic. The two keys can disagree, and when they do it is an analytics split: a device with
an oura- id but no registry row — or a row whose brand text differs — was Oura on Android and not on
iOS, so Android computed the ceiling@100 candidate for that night and iOS did not. That is precisely
what the parity contract forbids.

A byte-identical Swift twin already existed:

public static func isOura(_ deviceId: String) -> Bool {
    all.first { deviceId.hasPrefix($0.idPrefix + "-") }?.sourceKind == .oura
}

Repository.activeDeviceIsOura already uses it, with a comment saying it is there "rather than an
ad-hoc 'oura' literal"
. Swift now uses it too.

The id-prefix key is also the safer one

Not just more consistent — more robust. Repository.swift:178 records that the registry mints every
non-WHOOP id as "<idPrefix>-<uuid>", so the prefix IS the brand key and is always present, while
the brand compare needs a registry row to exist and its text to match.

I verified Oura ids really are minted that way before changing anything —
SourceCoordinator.swift:453 builds "\(ExperimentalBrand.oura.idPrefix)-\(serial)" → "oura-<serial>"
— because if they weren't, this "fix" would have silently disabled the Oura path it exists to protect.

WHOOP owners are unaffected: my-whoop and my-whoop-noop fail the prefix test exactly as they failed
the brand test, so they still take the v18 aux branch.

Checked and deliberately left alone

skinTempWornToleranceSec keys on the brand string on both platforms (Swift :2363, Kotlin :77),
so that pair is symmetric — a different convention from the catalog, but not a divergence. It predates
#1568 (from #1467) and is out of scope here.

Verification

  • Kotlin untouched — it already used the catalog.
  • doc_comment_lint.py clean. No strings, no schema, no behaviour change for WHOOP owners.
  • app-build required — app-target Swift, nothing else compiles it. Not dispatched.
  • Not seen on a device. Neither was the original: @pipiche38's device capture with the toggle flipped
    on is still owed, and it now also exercises this resolver.

Post-merge parity fix for #1584. The Oura SpO2 candidate branch resolved "is this owner an
Oura device" differently on each platform:

    Kotlin  DeviceBrandCatalog.isOura(owner)                     -> device-id PREFIX
    Swift   regDevices.first { $0.id == owner }?.brand == "Oura"  -> registry BRAND string

Not stylistic. The two keys can disagree, and when they do it is an analytics split: a
device with an `oura-` id but no registry row, or a row whose brand text differs, was Oura
on Android and not on iOS — so Android computed the ceiling@100 candidate for that night and
iOS did not.

A byte-identical Swift twin already existed and is what `Repository.activeDeviceIsOura`
uses, with a comment saying it is there "rather than an ad-hoc 'oura' literal". Swift now
uses it too.

The id-prefix key is also the more robust of the two, not merely the more consistent:
Repository.swift:178 records that the registry mints every non-WHOOP id as
"<idPrefix>-<uuid>", so the prefix IS the brand key and is always present, while the brand
compare needs a registry row to exist AND its text to match. Verified Oura ids really are
minted that way — SourceCoordinator.swift:453 builds "\(ExperimentalBrand.oura.idPrefix)-
\(serial)" — so this cannot silently disable the Oura path it is meant to fix.

WHOOP owners are unaffected: "my-whoop" and "my-whoop-noop" fail the prefix test exactly as
they failed the brand test, so they still take the v18 aux branch.

Checked the sibling site while here: skinTempWornToleranceSec keys on the brand string on
BOTH platforms (Swift :2363, Kotlin :77), so that pair is symmetric — a different convention
from the catalog, but not a divergence. Left alone.
@ryanbr
ryanbr merged commit 7ee0572 into main Aug 24, 2026
4 checks passed
@ryanbr
ryanbr deleted the fix/oura-detect-parity branch August 24, 2026 05:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant