predictionHeatRisk.ts

Orchestrates a full heat risk prediction by composing WBGT, CPM, heart rate, and profile inputs

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 fullCPM availableModel selected
YesYes"hybrid"
YesNo"watch-only"
NoYes"phone-only"
NoNoThrows 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

ParameterDescription
hrResultHeart rate result from useHeartRate hook, or null
cpmOverrideOptional CPM value to use instead of the activity service (iOS only)