Skip to content

feat(spo2): nightly 5/MG SpO2 candidate as the mean of per-window medians (experimental) - #2825

Open
LeonardSEO wants to merge 1 commit into
ryanbr:mainfrom
LeonardSEO:feat/spo2-candidate-windowed-median
Open

LeonardSEO wants to merge 1 commit into
ryanbr:mainfrom
LeonardSEO:feat/spo2-candidate-windowed-median

Conversation

@LeonardSEO

Copy link
Copy Markdown

Experimental, like the candidate itself. The method follows one captured night; I do not expect it to be accepted as an improvement, and it is not described as one.

What this PR does

Changes how the nightly 5/MG SpO2 candidate (spo2_candidate_82) is aggregated. Display-only, behind the existing default-off toggle; it never writes spo2Pct and feeds nothing.

  • Before: the mean of every in-band (70-100) second inside the sleep sessions.
  • After: nonzero @82 seconds are grouped into measurement windows (a gap of more than 2 s ends one). A window with at least 5 in-band seconds yields its median, and the night is the mean of those medians. Status codes stay inside a window but never count as readings.
  • samples is now the in-band seconds of the windows that counted.
  • Swift and Kotlin twins changed together; the tests are rewritten with the same fixtures on both platforms.

Why: in an overnight iOS capture, byte 82 is 0 in every record except 15 windows of exactly 30 s starting exactly every 1,200 s, all during sleep. Several windows hold only 1-4 valid seconds (one a lone 78 % among status codes). A per-second mean weighs those thin windows like full ones, which may explain part of the split cross-device evidence noted at the candidate. That is a hypothesis until a captured night is compared with the official app's own SpO2.

Source: LeonardSEO/wearable5.0, FINDINGS §13 (spo2_windows).

Validation: none beyond that one night (7 windows of 93-99 %). No held-out number, so per docs/VALIDATION_PROTOCOL.md this is not claimed as an improvement.

Type of change

  • New feature

How it was tested

  • Spo2CandidateNightlyTests / Spo2CandidateNightlyTest, rewritten with the same fixtures on both platforms: window median, mean of medians, status codes and thin windows ignored, a gap splitting windows, session bounds, band edges.
  • swift test in Packages/StrandAnalytics: 2141 tests pass.
  • ./gradlew testFullDebugUnitTest: 6686 tests, all pass apart from the 2 RecoveryDriversTest half-tie cases that fail the same way on unmodified main.
  • Tools/i18n_audit.py --ci, Tools/doc_comment_lint.py, docs/protocol-examples checks and Tools/parity_ledger.py --refresh-derived (derived snapshots included): pass.
  • Tools unit tests, the parity acceptance suite and the R-R contract: pass apart from the 4 test_check_source_references cases (/var vs /private/var temp path on macOS) that fail the same way on unmodified main.
  • Apple: the macOS app (Strand) builds with this change on my development branch; StrandTests and the iOS target were not run locally for this branch. app-build.yml covers both.

Checklist

  • Swift package tests pass for any package I touched
  • Android unit tests pass if I touched android/ (apart from the 2 RecoveryDriversTest half-tie cases that fail the same way on unmodified main)
  • No new build warnings introduced (Android: none; Apple warnings not checked per branch)
  • UI changes use only StrandDesign / Palette / Metrics tokens
  • 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

Refs #103

🤖 Generated with Claude Code

…ians

Byte 82 is measured in 30 s windows every 1,200 s during sleep (LeonardSEO/wearable5.0 FINDINGS §13). Each window with at least 5 in-band seconds yields its median; the night is the mean of those medians. Display-only and still default-off; not claimed as an improvement.

Refs ryanbr#103
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