predictionHeatRisk.ts
Purpose
This module is the top-level prediction orchestrator. It gathers all required inputs from their respective services, selects the appropriate core temperature model variant, runs inference, persists the result to connected wearables, and returns a structured prediction payload.
Its responsibilities include:
- Fetching the current WBGT prediction via
makeWbgtPrediction - Loading the user profile and computing BMI
- Resolving the 40-minute average CPM from the activity service (platform-dependent)
- Accepting an optional heart rate result and extracting the 40-minute average BPM
- Selecting the appropriate model variant based on data availability
- Running core temperature inference via
runCoreTempInference(lazily required) - Sending the result to WearOS or WatchOS depending on platform
- Logging all model inputs and outputs for debugging
Invariants
WBGT Failure Short-Circuits
If makeWbgtPrediction throws, the function returns null immediately without attempting inference.
This is the only case where null is returned; all other failure paths throw.
Model Selection Logic
The model is selected by strict precedence based on data availability:
| Heart rate window full | CPM available | Model selected |
|---|---|---|
| Yes | Yes | "hybrid" |
| Yes | No | "watch-only" |
| No | Yes | "phone-only" |
| No | No | Throws ActivityCpmUnavailableError |
CPM Platform Routing
On iOS, CPM is read from getActivityCpm40Average unless cpmOverride is provided.
On Android, only getActivityCpm40Average is used; cpmOverride is ignored.
Lazy ONNX Require
runCoreTempInference is loaded via a lazy require() call at prediction time rather than at import time.
This keeps the native ONNX module out of app startup and ensures compatibility with Jest’s CommonJS runtime.
Wearable Result Dispatch
After successful inference, the core temperature is sent to the connected wearable:
- Android:
sendCBTToWearOS(core.coreTempC)— awaited - iOS:
sendCBTToWatchOS(core.coreTempC)— fire-and-forget
Exports
ActivityCpmUnavailableError
class ActivityCpmUnavailableError extends Error {
name: "ActivityCpmUnavailableError";
}
Thrown when neither heart rate nor CPM data is available to make a prediction.
makeHeatRiskPrediction(...)
async function makeHeatRiskPrediction(
hrResult: HeartRateResult | null,
cpmOverride?: number,
): Promise<{
wbgt: WbgtPredictionResult;
profile: UserProfile & { bmi: number };
cpm40: number | undefined;
core: CoreTempResult;
} | null>
Runs a full heat risk prediction. Returns null if WBGT data is unavailable. Throws ActivityCpmUnavailableError if insufficient motion data exists for any model variant.
Parameters
| Parameter | Description |
|---|---|
hrResult | Heart rate result from useHeartRate hook, or null |
cpmOverride | Optional CPM value to use instead of the activity service (iOS only) |