> ## 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.

# Health backfill

> Cold-start SRM seeding from Health Connect (Android) or HealthKit (iOS) historical sleep + overnight HR/HRV.

## Overview

Most users open a Synheart-powered app with months or years of existing wearable history sitting in the platform health store. The [longitudinal SRM](/synheart-core/srm) is a great fit for that data — but it needs to be **seeded** from history, not just streamed live.

The Health backfill sinks read historical sleep nights + overnight HR/HRV from the platform health store, aggregate per local wake-day, and push the SRM's [five primary dimensions](/synheart-core/srm#dimensions) per night via the runtime's `wearable_daily_values` ingest path (secondary dimensions are populated when the underlying samples are present). After a one-time backfill, the user's "your normal" baselines reflect their last N days of real sleep / recovery — instead of warming from zero over the first week of app use.

| Platform            | Source                    | SDK                                        | Time range                                                                 |
| ------------------- | ------------------------- | ------------------------------------------ | -------------------------------------------------------------------------- |
| **Android**         | Health Connect (live API) | `HealthConnectRuntimeSink`                 | Whatever Health Connect retained — typically \~30 days HR, 1–2 years sleep |
| **iOS**             | HealthKit (live API)      | `HealthKitRuntimeSink`                     | Whatever HealthKit retained — effectively user-owned, often years          |
| **iOS (alternate)** | `export.zip` import       | `AppleHealthRuntimeSink` (Flutter / Swift) | Years; full Apple Health archive                                           |

All three push the same five dimensions per wake-day at `confidence: 0.85`, `fidelity: 1`:

* `sleep_need` (total asleep minutes × 60, in seconds)
* `deep_sleep_min`
* `rem_sleep_min`
* `hrv_rmssd`
* `resting_hr`

## Android — Health Connect

```kotlin theme={null}
import ai.synheart.core.backfill.HealthConnectRuntimeSink
import ai.synheart.wear.adapters.HealthConnectAdapter

// The HealthHistoryReader contract lives in synheart-wear-kotlin;
// HealthConnectAdapter implements it.
val reader = HealthConnectAdapter(context)
val sink = HealthConnectRuntimeSink(
    reader = reader,
    bridge = coreRuntime,
)

// Call after the user has granted Health Connect read permissions
// (and ConsentType.BIOSIGNALS on the Synheart side). Heavy — first
// run can take 10+ seconds for a year of HR samples on cold cache.
val result = sink.backfill(daysBack = 365)
println("seeded ${result.daysIngested} days, ${result.dimensionsPushed} dimensions in ${result.durationMs}ms")
```

`HealthConnectBackfillResult` carries `daysIngested`, `dimensionsPushed`, `requestedDaysBack`, `skipped`, `skipReason`, `durationMs`. The `skipped: true` path covers "Health Connect not available on this device", "daysBack must be positive", etc.

## iOS — HealthKit

```swift theme={null}
import SynheartCore
import SynheartWear

// HealthKitHistoryReader implements HealthHistoryReader; owns its own HKHealthStore.
let reader = HealthKitHistoryReader()
let sink = HealthKitRuntimeSink(
    reader: reader,
    pushDaily: { dimension, dayIndex, value, confidence, fidelity in
        coreRuntime.pushWearableDailyValue(
            dimension: dimension,
            dayIndex: dayIndex,
            value: value,
            confidence: confidence,
            fidelity: fidelity
        )
    },
    triggerRecompute: {
        coreRuntime.triggerWearableRecompute(triggerType: 0, asOfDay: 0)
    }
)

// Call after HealthKit authorization + ConsentType.biosignals granted.
let result = try await sink.backfill(daysBack: 365)
print("seeded \(result.daysIngested) days, \(result.dimensionsPushed) dims in \(result.durationMs)ms")
```

## HealthHistoryReader contract

Both platforms consume the same wear-side reader contract — that's what lets the core sink stay HealthKit / HealthConnect agnostic. Two methods, bucketed by local wake-day:

```text theme={null}
fetchSleepNights(start, end, zone) → Map<LocalDate, SleepNightSummary>
fetchOvernightPhysiology(start, end, zone) → Map<LocalDate, OvernightPhysiologySummary>
```

`SleepNightSummary` carries `totalAsleepMinutes`, optional `deepMinutes` / `remMinutes`. `OvernightPhysiologySummary` carries optional `hrvRmssdMs` / `restingHrBpm` averaged over the sleep window. Both are nullable because real sources can lack stage breakdowns or in-sleep HRV samples — the runtime accepts nulls and degrades the SRM gracefully.

## When NOT to call it

* Before the user has granted the platform health permission (sink returns `skipped: true`)
* Before `ConsentType.BIOSIGNALS` is granted on the Synheart side — the runtime will accept the writes but the user hasn't consented to longitudinal storage of derived dimensions
* Periodically (don't poll) — the runtime ingest is idempotent per `(day_index, dimension)`, but pulling from the platform health store every app launch is wasteful. Run once on first launch + after a long backgrounded gap.

## Cross-language

* Flutter: `lib/src/backfill/{health_connect_runtime_sink,apple_health_runtime_sink,apple_xml_backfill_sink}.dart`
* Kotlin: `synheart-core/src/main/kotlin/ai/synheart/core/backfill/HealthConnectRuntimeSink.kt`
* Swift: `SynheartCore/Modules/Backfill/HealthKitRuntimeSink.swift`

**Apple Health XML backfill (`export.zip` import)** is iOS-only by design; Android users get Health Connect's live API instead. Kotlin intentionally has no equivalent — the native backfill symbols are unbound on Android.

## Related

* [Baselines](/synheart-core/baselines) — reads the SRM these sinks seed
* [Scoring models](/synheart-core/scoring) — what the runtime computes once baselines are warm
* [synheart-wear](/synheart-wear/overview) — owns the `HealthHistoryReader` contract + platform-specific adapter
