Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.synheart.ai/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Baselines is the host-facing read facade for wearable baselines. Apps subscribe to a reactive snapshot stream and get a fully-typed view of the user’s most recent sleep / recovery / readiness scores plus the current WearableReferenceView; no JSON parsing, no FFI. It does NOT compute scores or own ingest pipelines — it caches whatever the host SDK feeds in. The full Flutter Baselines.ingestVendorSleep orchestration (Whoop / Garmin / Apple Health / Health Connect → score → snapshot) lives only on the Flutter SDK at this time. On Kotlin / Swift, hosts wire vendor ingest themselves and call the cache* setters.

Surface

Process-wide singleton (Baselines.shared) with:
SurfaceDescription
updatesObservable stream of BaselinesSnapshot — emits after every cache* call. Replays the current snapshot to late subscribers.
latestSleepScore / latestRecoveryScore / latestReadinessScoreSync getters for the most recent score in each pipeline.
referenceThe most recent WearableReferenceView from the SRM (see Self-Reference Model).
lastSourceProvider id of whoever produced the latest sleep score (whoop, garmin, apple_health, health_connect, self_report, …).
cacheSleepScore(result, source)Push a new sleep score, roll into the recent-scores ring (cap 7), emit.
cacheRecoveryScore(result)Push a new recovery score, emit.
cacheReadinessScore(result)Push a new readiness score, emit.
cacheReference(view)Push a new wearable reference, emit.
reset()Forget everything (logout / user switch).
current()Synchronous snapshot read.

BaselinesSnapshot

reference: WearableReferenceView?
latestSleepScore: SleepScoreResult?
latestRecoveryScore: RecoveryScoreResult?
latestReadinessScore: ReadinessScoreResult?
recentSleepScores: [Int]      // recent-scores ring; oldest → newest; cap 7
capturedAtMs: Int64
Derived properties (computed without storage):
  • isEmpty — nothing has been ingested and the engine hasn’t produced a reference yet
  • isReady — true when the reference reports READY status, i.e. all five primary SRM dimensions are mature enough for personalized scoring (see SRM maturity states).
  • priorNightCount — what the scorer saw (nil if no score)
  • nightsLoggedCount — items in the recent-scores ring (capped at 7)
  • recentMedian — median of the ring when populated; falls back to reference.recentSleepScoreMedian

Kotlin

import ai.synheart.core.modules.baselines.Baselines
import ai.synheart.core.modules.baselines.BaselinesSnapshot

// Subscribe (Flow<BaselinesSnapshot>)
viewModelScope.launch {
    Baselines.shared.updates.collect { snap ->
        snap.latestSleepScore?.let { render(it.score) }
        snap.latestRecoveryScore?.let { render(it.score) }
        snap.latestReadinessScore?.let { render(it.score) }
    }
}

// Push (from your vendor-ingest code)
Baselines.shared.cacheSleepScore(result = sleepScore, source = "whoop")
Baselines.shared.cacheReference(reference = wearableRefView)

Swift

import SynheartCore

var cancellables = Set<AnyCancellable>()

// Subscribe (Combine — CurrentValueSubject, late subs get current snapshot)
Baselines.shared.updates
    .sink { snap in
        if let s = snap.latestSleepScore { render(s.score) }
        if let r = snap.latestRecoveryScore { render(r.score) }
        if let rd = snap.latestReadinessScore { render(rd.score) }
    }
    .store(in: &cancellables)

// Push
Baselines.shared.cacheSleepScore(sleepScore, source: "whoop")
Baselines.shared.cacheReference(wearableRefView)

Recent-scores ring semantics

cacheSleepScore pushes the score (if non-nil) onto a FIFO ring capped at 7. This is the “nights logged” surface for the user — it reflects cumulative ingests in the current session, not what the scorer saw (priorNightCount gives you that). The median of the ring is available after the 3rd attach, regardless of HSI window state.

Cross-language parity

The shape is identical across Flutter / Kotlin / Swift. The stream type differs by platform idiom (Dart Stream, Kotlin Flow, Swift AnyPublisher) but the snapshot content is byte-equivalent.
  • Flutter: lib/src/modules/baselines/baselines_snapshot.dart + (full ingest) baselines.dart
  • Kotlin: synheart-core/src/main/kotlin/ai/synheart/core/modules/baselines/{Baselines,BaselinesSnapshot}.kt
  • Swift: SynheartCore/Modules/Baselines/{Baselines,BaselinesSnapshot}.swift