package com.gnx.earsling.contract /** * GNX Earsling Android/Kotlin SDK Contract. * * This contract transports candidate-status decisions only. * It must not be presented as body-temperature, heart-rate, rhythm, or blood-pressure measurement output. */ import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable enum class EarslingMetric { @SerialName("body_temperature") BODY_TEMPERATURE, @SerialName("heart_rhythm") HEART_RHYTHM, @SerialName("blood_pressure_range") BLOOD_PRESSURE_RANGE } @Serializable enum class EarslingDecision { GREEN_NORMAL, AMBER_CHECK, ORANGE_OUT_OF_RANGE, RED_SEVERE_RECHECK, GRAY_CONTEXT_INVALID } @Serializable enum class EarslingSeverity { green, amber, orange, red, gray } @Serializable data class EarslingProfileInput( val age: Int, val sex: String, val heightCm: Double, val weightKg: Double, val diabetesYn: String = "unknown", val consentScope: String = "demo" ) @Serializable data class EarslingCandidateState( val metric: String, val thermalBand: String? = null, val ambientThermalBand: String? = null, val heartRateBand: String? = null, val rhythmIrregularityBand: String? = null, val bloodPressureBand: String? = null, val candidateSource: String = "sdk_adapter" ) @Serializable data class EarslingContextState( val contactQuality: String, val frameStable: Boolean, val baselineReady: Boolean, val motionNoise: String, val adapterIntegrity: String, val sourceIntegrity: String ) @Serializable data class EarslingEvaluateRequest( val profile: EarslingProfileInput, val candidateState: EarslingCandidateState, val contextState: EarslingContextState, val persistEvidence: Boolean = false ) @Serializable data class EarslingTriggeredRule( val id: String, val group: String, val result: String, val severity: String, val reason: String ) @Serializable data class EarslingUiDirectives( val graphColor: String, val crossBoundary: String, val earslingTipGlow: String, val haptic: String, val messageTone: String ) @Serializable data class EarslingAndroidDirective( val hapticPattern: String, val displayMessage: String ) @Serializable data class EarslingIosDirective( val feedback: String, val displayMessage: String ) @Serializable data class EarslingAdapterPayload( val metric: String, val status: String, val severity: String, val message: String, val uiColor: String, val hapticPattern: String, val graphDirective: String, val evidencePacketId: String? = null, val policyVersion: String, val timestamp: String, val android: EarslingAndroidDirective, val ios: EarslingIosDirective ) @Serializable data class EarslingEvaluationResponse( val ok: Boolean, val engine: String, val engineVersion: String, val policyVersion: String, val ruleGraphVersion: String, val metric: String, val decision: String, val message: String, val triggeredRules: List, val uiDirectives: EarslingUiDirectives, val adapterPayload: EarslingAdapterPayload, val evidencePacketId: String? = null, val auditReceipt: String? = null, val disclaimers: List = emptyList(), val nonClaims: List = emptyList() ) /** * Android UI handling rule: * - OUT_OF_RANGE and NON_VALUE style responses are normal safety responses, not SDK failures. * - hapticPattern must be throttled and must not be repeated as medical-alarm behavior. */