Skip to content

Fix/oura live console trusted stream#56

Merged
ryanbr merged 2 commits into
ryanbr:mainfrom
pipiche38:fix/oura-live-console-trusted-stream
Jul 8, 2026
Merged

Fix/oura live console trusted stream#56
ryanbr merged 2 commits into
ryanbr:mainfrom
pipiche38:fix/oura-live-console-trusted-stream

Conversation

@pipiche38

@pipiche38 pipiche38 commented Jul 7, 2026

Copy link
Copy Markdown

What this PR does

The fix

In Strand/Screens/LiveView.swift I added a display-only predicate:

private var ringStreaming: Bool { live.connected && live.streamingLiveHR }

and taught the status layer to treat it as a trusted live stream, across all the places that were WHOOP-only:

  • Detail caption → "Heart rate stream is active." (instead of "not yet trusted")
  • Connection pill → green "Streaming" (instead of amber "Connected")
  • Mode badge → "STREAMING" (instead of "CONNECTING")
  • Mode color → accent/green (instead of amber)
  • Signal-trust tiles → Heart rate "Streaming now", Connection "Streaming / Authenticated ring stream"

Crucially, I left activeConnection itself untouched, so the actual bond-only feature gates (buzz, alarm, HRV snapshot, encrypted control) still correctly key off the
WHOOP bond — the ring shouldn't claim those.

One caveat I intentionally left alone

The Wear state / Worn stats still gate on activeConnection, so they'll read "Unknown" for the ring. I didn't route those through ringStreaming because I couldn't
confirm the Oura path drives live.worn (WRIST_ON/OFF) — showing a false "On wrist" would be worse than "Unknown". If the ring does report wear, say the word and I'll
wire those up too.

Type of change

  • Bug fix
  • New feature
  • Refactor / cleanup
  • Documentation
  • CI / tooling

How it was tested

Checklist

  • Swift package tests pass for any package I touched (swift test in Packages/<name>)
  • Android unit tests pass if I touched android/ (./gradlew testFullDebugUnitTest)
  • No new build warnings introduced
  • UI changes use only StrandDesign tokens — no hardcoded colors, fonts, or spacing
  • No hardcoded hex frame bytes; protocol facts live in the schema / decoders
  • Follows the conventions in docs/CONTRIBUTING.md
  • I did not commit generated output (Strand.xcodeproj/) or any secrets/keystores

Related issues

pipiche38 and others added 2 commits July 7, 2026 21:50
The Live Body Console derives every status from activeConnection
(= live.connected && live.bonded). `bonded` carries WHOOP encrypted-bond
semantics and is deliberately never set by the Oura path (ryanbr#69), so a
connected, authenticated, streaming ring fell through every WHOOP branch
to "Radio connected, stream not yet trusted." — even while HR was live.

Add a display-only `ringStreaming` predicate (live.connected &&
live.streamingLiveHR) and route the status layer through it: mode detail,
connection pill, mode badge, mode color, and the Heart rate / Connection
signal-trust tiles now read a ring stream as an active, trusted stream.

activeConnection itself is untouched, so bond-only feature gates (buzz,
alarm, HRV snapshot, encrypted control) still correctly key off the WHOOP
bond. Wear/Worn stats stay gated on activeConnection to avoid a false
"On wrist" until the ring's wear signal is confirmed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@pipiche38 pipiche38 marked this pull request as draft July 7, 2026 20:07
@pipiche38

Copy link
Copy Markdown
Author

I need to test it, but having issues to build, as the built application do not use the same environment as the new built 8.3.4 (for instance it is using now the Containers folder).

I'll see how to redo the build in a proper way

ryanbr added a commit that referenced this pull request Jul 8, 2026
Android: recognize the Oura ring's live stream as trusted in the Live console (#56 parity)
@ryanbr ryanbr marked this pull request as ready for review July 8, 2026 01:41
@ryanbr ryanbr merged commit 1034f22 into ryanbr:main Jul 8, 2026
tanarchytan pushed a commit to tanarchytan/noop that referenced this pull request Jul 8, 2026
… console (ryanbr#56 parity)

iOS PR ryanbr#56 makes the Live view treat an actively-streaming non-WHOOP source (the Oura
ring) as a trusted stream instead of "connecting / not yet trusted". Android had the
identical WHOOP-only status logic, but couldn't be fixed the same way because
LiveState.streamingLiveHR was an unfilled stub (hardcoded false) that nothing drove —
the ring's HR reaches the UI via publishExternalLiveHr, which set connected=true but
never streamingLiveHR. So the parity here is two parts:

1. Plumb the signal. publishExternalLiveHr (the non-WHOOP live-HR seam, invoked ONLY
   while WHOOP's own BLE is paused) now sets streamingLiveHR=true, and clearedBiometrics
   + the two remaining connected=false transitions clear it, keeping the invariant
   streamingLiveHR ⟹ connected. bonded stays false, so the buzz/alarm/HRV feature gates
   keep keying off the WHOOP bond — the ring never claims those.

2. Status copy (LiveScreen), mirroring iOS: a `ringStreaming = connected && streamingLiveHR`
   predicate feeds the mode badge ("STREAMING"), the pill ("Streaming", green), the mode
   colour (accent), the detail ("Heart rate stream is active."), and the signal-trust
   tiles (Heart rate "Streaming now", Connection "Streaming / Live stream, no WHOOP bond").
   Every ringStreaming branch sits AFTER the WHOOP activeConnection checks, so a bonded
   WHOOP is unaffected.

On Android the signal is driven for any external live source (ring, FTMS machine, generic
HR strap) — a superset of iOS's Oura-only, and correct for all of them.

Compiles (compileFullReleaseKotlin) and the BLE unit tests pass.
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.

2 participants