@prefix health: <https://ns.cascadeprotocol.org/health/v1#> .
@prefix cascade: <https://ns.cascadeprotocol.org/core/v1#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix dct: <http://purl.org/dc/terms/> .
@prefix fhir: <http://hl7.org/fhir/> .
@prefix sct: <http://snomed.info/sct/> .
@prefix loinc: <http://loinc.org/rdf#> .
@prefix prov: <http://www.w3.org/ns/prov#> .
@prefix ucum: <http://unitsofmeasure.org/> .

# ============================================================================
# Ontology Metadata
# ============================================================================

<https://ns.cascadeprotocol.org/health/v1#> a owl:Ontology ;
    owl:imports <https://ns.cascadeprotocol.org/core/v1#> ;
    dct:title "Cascade Protocol Health & Wellness Ontology"@en ;
    dct:description "Vocabulary for consumer-generated wellness observations from wearable devices and HealthKit. Maps Cascade wellness properties to established SNOMED CT and LOINC codes following the three-layer ontology architecture."@en ;
    dct:creator "Cascade Agentic Labs" ;
    dct:created "2026-01-29"^^xsd:date ;
    dct:modified "2026-08-14"^^xsd:date ;
    owl:versionInfo "2.7" ;
    rdfs:comment """Three-layer ontology for wellness data:
        Layer 1 (Established standards): SNOMED CT concept IDs + LOINC observation codes
        Layer 2 (Cascade health vocabulary): health: namespace properties linking to Layer 1
        Layer 3 (Checkup summary): checkup: namespace patient-facing aggregations"""@en ;
    rdfs:seeAlso <https://cascadeprotocol.org/docs/health/v1/> .

# Changelog:
# v2.7 (2026-08-14): Let a source's absence and a source's unrecognised code
#     both survive import. Additive: one new property, one widened value set,
#     and nothing that validated under v2.6 stops validating.
#
#     1. health:interpretation's value set is widened from the single
#        data-absent-reason code "unknown" to all 15 codes of
#        http://terminology.hl7.org/CodeSystem/data-absent-reason (value set
#        http://hl7.org/fhir/ValueSet/data-absent-reason). v2.6 already
#        accepted one code from that system for the case of a source that
#        carried no interpretation; accepting only one of the fifteen made
#        every reason for the absence identical. FHIR's own pattern for a
#        CodeableConcept element that is absent for a stated reason is a
#        data-absent-reason coding in that element, so this is the ratified
#        spelling rather than a Cascade convention. It is what lets a C-CDA
#        <interpretationCode nullFlavor="NASK"/> ("nobody asked") arrive
#        distinguishable from nullFlavor="ASKU" ("asked, did not know") and
#        nullFlavor="NAV" ("known later"); the nullFlavor mapping table is
#        stated once, on cascade:dataAbsentReason in core v3.6.
#     2. NEW health:interpretationSourceCode: the source's verbatim
#        interpretation code, written ONLY when that code is a member of
#        neither bound value set. The alternative considered and rejected was
#        accepting the loss with a warning. A closed value set plus a lossy
#        importer means a laboratory's local flag is either dropped on the
#        floor or written into a field that then fails validation, and in both
#        cases the Pod can no longer answer what the source actually said.
#        Unconstrained by design: it is a verbatim carbon copy, not a code.
#     3. NOT changed, and stated here so its absence is not read as an
#        oversight: no interpretation constraint was added to
#        health:DailyVitalReadingShape. health:interpretation's rdfs:domain is
#        health:LabResultRecord and health's only vital class,
#        health:DailyVitalReading, carries no interpretation predicate at all,
#        so a shape there would constrain a triple no conforming record can
#        write. The vital-sign interpretation binding this release adds lives
#        in clinical v1.15 on clinical:VitalSignShape, which is the vital
#        shape that actually exists.
#
# v2.6 (2026-08-08): Align the lab-result constraints to the ratified standards
#     they claim to follow. Shapes-only; no class or property is added, removed
#     or renamed, and nothing that validated under v2.5 stops validating.
#
#     Motivation: real-world Epic FHIR exports fail validation on records that
#     are correct FHIR. Four constraints on health:LabResultRecordShape and
#     health:ConditionRecordShape were narrower than the resource definitions
#     the data is converted from.
#
#     1. health:interpretation was constrained to a five-member set Cascade
#        invented (normal/high/low/abnormal/critical). It is now the 49
#        selectable codes of the HL7 v3 ObservationInterpretation code system,
#        http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation
#        (version 3.0.0) — the code system FHIR R4 binds
#        Observation.interpretation to — plus the data-absent-reason code
#        "unknown" (http://terminology.hl7.org/CodeSystem/data-absent-reason)
#        for the very common case of a source Observation that carried no
#        interpretation at all. The ten v2.5 words are retained so existing
#        data keeps validating; they are not recommended for new writes.
#        The eight abstract (notSelectable) concepts of the code system are
#        excluded: they are hierarchy nodes, not values.
#     2. health:labCategory is now multi-valued. FHIR R4 Observation.category
#        is 0..* (https://hl7.org/fhir/R4/observation-definitions.html#Observation.category)
#        and real exports categorise one result several ways at once.
#     3. health:testCode is now multi-valued, and
#     4. health:icd10Code and health:snomedCode are now multi-valued, all three
#        because FHIR R4 CodeableConcept.coding is 0..*
#        (https://hl7.org/fhir/R4/datatypes.html#CodeableConcept). Dual coding
#        of a problem-list entry, and multiple LOINC codings of one test, are
#        the normal shape of EHR output.
#
#     Deliberately NOT changed: no sh:pattern is introduced on any code
#     property. ICD-10-CM permits a letter in any character position (per the
#     ICD-10-CM Official Guidelines for Coding and Reporting, Section I.A.2:
#     "Characters for categories, subcategories and codes may be either a letter
#     or a number"), and SNOMED CT identifiers are 6-18 digit integers, so a
#     pattern would reject valid codes for no gain. Format stays with the code
#     system that defines it.
#
# v2.5 (2026-08-03): Clinical record classes. Five classes that serializers have
#     emitted since v1.3 but that this ontology never defined are now defined:
#     health:LabResultRecord, health:ConditionRecord, health:AllergyRecord,
#     health:ImmunizationRecord, health:FamilyHistoryRecord. Adds the 40
#     properties they use (previously undefined vocabulary), 4 sleep-quality
#     named individuals, and 6 wellness container classes
#     (health:ActivityData, SleepData, HeartRateData, BloodPressureData,
#     HRVData, BodyMeasurements) as rdfs:subClassOf health:HealthProfile.
#     The subclass declarations make the existing rdfs:domain health:HealthProfile
#     on the eight history container properties true rather than contradicted,
#     and bring those containers under health:HealthProfileShape through
#     SHACL subclass-aware sh:targetClass. Adds a namespace-boundary note
#     explaining that health: vs clinical: is historical, not a provenance
#     signal. No serializer changes; every term here was already being emitted.
#
# v2.4 (2026-03-27): EHR Import Reconciliation (P1-C) — Added health:SocialHistoryRecord
#     class for social history observations (smoking, alcohol, exercise, occupation).
#     Added 4 properties: health:smokingStatus, health:alcoholUse,
#     health:exerciseFrequency, health:occupationalExposure.
#
# v2.3 (2026-02-28): BUG-006 — Added 6 Pattern A flat-property vocabulary terms
#     for VitalSignReading blank nodes: health:value (generic numeric value),
#     health:date (observation timestamp), health:sdnn (HRV SDNN measurement),
#     health:systolic and health:diastolic (blood pressure components),
#     health:walkingSteadinessLevel (enum ObjectProperty). Also added
#     health:WalkingSteadinessUnknown individual. These replace the Pattern B
#     fhir:Observation nesting in HealthProfileSerializer.
#
# v2.2 (2026-02-17): Added 2 container linking ObjectProperties:
#     health:hasHRVStatistics, health:hasBPStatistics. These link a wellness
#     profile or intake form to its statistical summary nodes. Previously dark
#     vocabulary emitted by CheckupSerializer. Part of Schema Refactoring
#     Plan Phase 3 (PF1-R).
#
# v2.1 (2026-02-17): Added health:SelfReport base class and 5 base properties
#     (reportDate, reportType, completionStatus, reportContext, reportNotes)
#     for patient-reported daily check-ins. (Phase 3, WS7)
#
# v2.0 (2026-02-18): Schema Refactoring WS3b — Migrated HealthProfileSerializer
#     from cascade: to health: namespace. Added 8 history container properties
#     (restingHeartRateHistory, walkingHeartRateHistory, hrvHistory,
#     bloodPressureHistory, vo2MaxHistory, bodyMassHistory, dailyActivityHistory,
#     dailySleepHistory) and 7 supporting classes (HealthProfile, DailyVitalReading,
#     HRVReading, BloodPressureReading, VitalSignReading, DailyActivitySnapshot,
#     DailySleepSnapshot). These properties capture time-series data emitted by
#     HealthProfileSerializer for 90-day, 30-day, and 7-day lookback windows.
#
# v1.9 (2026-02-17): Added health:bloodType property for ABO blood group and
#     Rh factor. Values: aPositive, aNegative, bPositive, bNegative, abPositive,
#     abNegative, oPositive, oNegative. Sourced from HealthKit
#     (HKCharacteristicType.bloodType) or manual entry. Previously dark vocabulary
#     emitted in QR payload. Part of Schema Refactoring Plan Phase 2.5 (PF4).
#
# v1.8 (2026-02-10): Added 6 body measurement properties with SNOMED/LOINC
#     annotations (bodyMass, bodyHeight, bodyMassIndex, bodyTemperature,
#     oxygenSaturation, bloodGlucose). Added health:BPStatistics class with
#     10 properties for blood pressure statistical summaries. Added shared
#     temporal properties (periodStart, periodEnd). Completed HRVStatistics
#     property definitions (hrvSampleCount, hrvDaysCovered, hrvMean, hrvMedian,
#     hrvStdDev, hrvMin, hrvMax, hrvPercentile25, hrvPercentile75,
#     hrvTrendDirection).
#
# v1.7 (2026-02-03): Added health:VO2MaxStatistics and health:HRVStatistics
#   composite classes for statistical trend analysis. Added 9 new properties
#   for VO2 Max statistics: vo2Mean, vo2Min, vo2MaxValue, vo2SampleCount,
#   vo2DaysCovered, vo2TrendDirection, vo2PercentageChange, fitnessClassification,
#   and isSparseData. These support the dual-path UI pattern where rich statistics
#   are preferred when available, with fallback to single values. Part of the
#   VO2 Max Statistics Implementation Plan Phase 5 (Documentation).
#
# v1.6 (2026-02-02): Added health:trendPolarity annotation property to all
#   measurable wellness metrics. Defines whether an increase is generally
#   favorable (higher_is_better), unfavorable (lower_is_better), or
#   context-dependent (neutral). Used by presentation layers for trend arrow
#   color semantics. Part of Visit Prep Feature Plan Phase 1.5.
#
# v1.5 (2026-02-01): Added health:MetricTrend class for time-bounded wellness
#   trends with direction, magnitude, confidence, and baseline/current values.
#   Follows the pattern established by clinical:LabTestSeries but designed for
#   continuous daily observations from consumer devices (vs discrete clinical samples).
#   Shares trendDirection/trendConfidence vocabulary with clinical: for cross-domain
#   consistency. Added as part of Ontology Improvement Plan (Work Stream 2, Task 2.1).
#
# v1.4 (2026-01-29): Initial release. Wellness vital signs, activity, and sleep
#   properties with SNOMED CT and LOINC standard code mappings for all metrics.
#   Created as part of the Wellness Data Pipeline implementation (Tasks 1-7).

# ============================================================================
# Layer 2: Wellness Observation Properties
# ============================================================================
# Each property maps a cascade: wellness term to its SNOMED CT and LOINC equivalents.
# These properties are used by HealthProfileSerializer to produce interoperable TTL.

# ----------------------------------------------------------------------------
# Vital Signs — Cardiac
# ----------------------------------------------------------------------------

health:restingHeartRate a owl:DatatypeProperty ;
    rdfs:label "Resting Heart Rate"@en ;
    rdfs:comment "Average resting heart rate from wearable device"@en ;
    rdfs:domain fhir:Observation ;
    rdfs:range xsd:double ;
    health:snomedCode sct:364075005 ;  # Heart rate
    health:loincCode loinc:40443-4 ;   # Heart rate --resting
    health:unit "beats/min" ;
    health:ucumCode "/min" ;
    health:trendPolarity "lower_is_better" .

health:walkingHeartRate a owl:DatatypeProperty ;
    rdfs:label "Walking Heart Rate"@en ;
    rdfs:comment "Average heart rate during walking from wearable device"@en ;
    rdfs:domain fhir:Observation ;
    rdfs:range xsd:double ;
    health:snomedCode sct:364075005 ;  # Heart rate
    health:loincCode loinc:89270-3 ;   # Heart rate --W exercise
    health:unit "beats/min" ;
    health:ucumCode "/min" ;
    health:trendPolarity "lower_is_better" .

health:heartRateVariability a owl:DatatypeProperty ;
    rdfs:label "Heart Rate Variability (SDNN)"@en ;
    rdfs:comment "Standard deviation of normal-to-normal R-R intervals (SDNN) from wearable device"@en ;
    rdfs:domain fhir:Observation ;
    rdfs:range xsd:double ;
    health:snomedCode sct:80404004 ;   # Heart rate variability
    health:loincCode loinc:80404-7 ;   # R-R interval.standard deviation
    health:unit "ms" ;
    health:ucumCode "ms" ;
    health:trendPolarity "higher_is_better" .

# ----------------------------------------------------------------------------
# Vital Signs — Cardiovascular
# ----------------------------------------------------------------------------

health:bloodPressure a owl:ObjectProperty ;
    rdfs:label "Blood Pressure"@en ;
    rdfs:comment "Blood pressure panel observation with systolic and diastolic components"@en ;
    rdfs:domain fhir:Observation ;
    health:snomedCode sct:75367002 ;   # Blood pressure
    health:loincCode loinc:85354-9 .   # Blood pressure panel

health:systolicBP a owl:DatatypeProperty ;
    rdfs:label "Systolic Blood Pressure"@en ;
    rdfs:domain fhir:Observation ;
    rdfs:range xsd:double ;
    health:snomedCode sct:271649006 ;  # Systolic blood pressure
    health:loincCode loinc:8480-6 ;    # Systolic blood pressure
    health:unit "mmHg" ;
    health:ucumCode "mm[Hg]" ;
    health:trendPolarity "lower_is_better" .

health:diastolicBP a owl:DatatypeProperty ;
    rdfs:label "Diastolic Blood Pressure"@en ;
    rdfs:domain fhir:Observation ;
    rdfs:range xsd:double ;
    health:snomedCode sct:271650006 ;  # Diastolic blood pressure
    health:loincCode loinc:8462-4 ;    # Diastolic blood pressure
    health:unit "mmHg" ;
    health:ucumCode "mm[Hg]" ;
    health:trendPolarity "lower_is_better" .

# ----------------------------------------------------------------------------
# Vital Signs — Respiratory & Fitness
# ----------------------------------------------------------------------------

health:respiratoryRate a owl:DatatypeProperty ;
    rdfs:label "Respiratory Rate"@en ;
    rdfs:comment "Average respiratory rate from wearable device"@en ;
    rdfs:domain fhir:Observation ;
    rdfs:range xsd:double ;
    health:snomedCode sct:86290005 ;   # Respiratory rate
    health:loincCode loinc:9279-1 ;    # Respiratory rate
    health:unit "breaths/min" ;
    health:ucumCode "/min" ;
    health:trendPolarity "neutral" .

health:vo2Max a owl:DatatypeProperty ;
    rdfs:label "VO2 Max"@en ;
    rdfs:comment "Estimated maximal oxygen consumption (cardiorespiratory fitness)"@en ;
    rdfs:domain fhir:Observation ;
    rdfs:range xsd:double ;
    health:snomedCode sct:251880009 ;  # Aerobic capacity
    health:loincCode loinc:60842-2 ;   # VO2 max
    health:unit "mL/kg/min" ;
    health:ucumCode "mL/kg/min" ;
    health:trendPolarity "higher_is_better" .

# ----------------------------------------------------------------------------
# Walking Steadiness
# ----------------------------------------------------------------------------

health:walkingSteadiness a owl:DatatypeProperty ;
    rdfs:label "Walking Steadiness"@en ;
    rdfs:comment "Apple Health walking steadiness classification (OK / Low / Very Low). Maps to nearest SNOMED balance concept. No LOINC equivalent exists for this consumer-device metric."@en ;
    rdfs:domain fhir:Observation ;
    rdfs:range xsd:string ;
    health:snomedCode sct:364832000 ;  # Balance finding
    rdfs:comment "SNOMED mapping note: 364832000 (Balance finding) is the closest available concept. Alternatives considered: 250043000 (Gait finding), 282097004 (Ability to walk). Apple's OK/Low/Very Low classification is proprietary."@en .

# Valid values for walkingSteadiness (legacy named individuals)
# health:WalkingSteadinessUnknown also defined in Pattern A section (v2.3)
health:WalkingSteadinessOK a health:WalkingSteadinessLevel ;
    rdfs:label "OK" .
health:WalkingSteadinessLow a health:WalkingSteadinessLevel ;
    rdfs:label "Low" .
health:WalkingSteadinessVeryLow a health:WalkingSteadinessLevel ;
    rdfs:label "Very Low" .

# ----------------------------------------------------------------------------
# Body Measurements (v1.8)
# ----------------------------------------------------------------------------

health:bodyMass a owl:DatatypeProperty ;
    rdfs:label "Body Mass"@en ;
    rdfs:comment "Body weight measurement."@en ;
    rdfs:domain fhir:Observation ;
    rdfs:range xsd:double ;
    health:snomedCode sct:27113001 ;
    health:loincCode loinc:29463-7 ;
    health:unit "kg" ;
    health:ucumCode "kg" ;
    health:trendPolarity "neutral" .

health:bodyHeight a owl:DatatypeProperty ;
    rdfs:label "Body Height"@en ;
    rdfs:comment "Body height measurement."@en ;
    rdfs:domain fhir:Observation ;
    rdfs:range xsd:double ;
    health:snomedCode sct:50373000 ;
    health:loincCode loinc:8302-2 ;
    health:unit "cm" ;
    health:ucumCode "cm" ;
    health:trendPolarity "neutral" .

health:bodyMassIndex a owl:DatatypeProperty ;
    rdfs:label "Body Mass Index"@en ;
    rdfs:comment "Computed body mass index (weight/height squared)."@en ;
    rdfs:domain fhir:Observation ;
    rdfs:range xsd:double ;
    health:snomedCode sct:60621009 ;
    health:loincCode loinc:39156-5 ;
    health:unit "kg/m2" ;
    health:ucumCode "kg/m2" ;
    health:trendPolarity "neutral" .

health:bodyTemperature a owl:DatatypeProperty ;
    rdfs:label "Body Temperature"@en ;
    rdfs:comment "Body temperature measurement."@en ;
    rdfs:domain fhir:Observation ;
    rdfs:range xsd:double ;
    health:snomedCode sct:386725007 ;
    health:loincCode loinc:8310-5 ;
    health:unit "degC" ;
    health:ucumCode "Cel" ;
    health:trendPolarity "neutral" .

health:oxygenSaturation a owl:DatatypeProperty ;
    rdfs:label "Oxygen Saturation"@en ;
    rdfs:comment "Blood oxygen saturation (SpO2) from pulse oximeter."@en ;
    rdfs:domain fhir:Observation ;
    rdfs:range xsd:double ;
    health:snomedCode sct:431314004 ;
    health:loincCode loinc:2708-6 ;
    health:unit "%" ;
    health:ucumCode "%" ;
    health:trendPolarity "higher_is_better" .

health:bloodGlucose a owl:DatatypeProperty ;
    rdfs:label "Blood Glucose"@en ;
    rdfs:comment "Blood glucose measurement."@en ;
    rdfs:domain fhir:Observation ;
    rdfs:range xsd:double ;
    health:snomedCode sct:33747003 ;
    health:loincCode loinc:2339-0 ;
    health:unit "mg/dL" ;
    health:ucumCode "mg/dL" ;
    health:trendPolarity "neutral" .

# ----------------------------------------------------------------------------
# Blood Type (v1.9)
# ----------------------------------------------------------------------------

health:bloodType a owl:DatatypeProperty ;
    rdfs:label "Blood Type"@en ;
    rdfs:comment "ABO blood group and Rh factor. Values: aPositive, aNegative, bPositive, bNegative, abPositive, abNegative, oPositive, oNegative. Sourced from HealthKit (HKCharacteristicType.bloodType) or manual entry."@en ;
    rdfs:domain health:HealthProfile ;
    rdfs:range xsd:string ;
    health:snomedCode sct:365637002 ;
    health:loincCode loinc:882-1 .

# Note: health:HealthProfile is not formally defined in this ontology file
# but refers to the SDK's HealthProfile model stored at /wellness/. The
# bloodType property is a characteristic (not a time-series observation)
# so it does not use fhir:Observation as its domain.

# ----------------------------------------------------------------------------
# Activity Metrics
# ----------------------------------------------------------------------------

health:averageDailySteps a owl:DatatypeProperty ;
    rdfs:label "Average Daily Steps"@en ;
    rdfs:comment "Average number of steps per day over measurement period"@en ;
    rdfs:domain health:ActivitySnapshot ;
    rdfs:range xsd:integer ;
    health:snomedCode sct:68130003 ;   # Physical activity
    health:loincCode loinc:41950-7 ;   # Number of steps in 24 hour Measured
    health:unit "steps" ;
    health:trendPolarity "higher_is_better" .

health:activeEnergyBurnedKcal a owl:DatatypeProperty ;
    rdfs:label "Active Energy Burned"@en ;
    rdfs:comment "Active energy expenditure in kilocalories (excludes basal metabolic rate)"@en ;
    rdfs:domain health:ActivitySnapshot ;
    rdfs:range xsd:decimal ;
    health:snomedCode sct:251833007 ;  # Energy expenditure
    health:loincCode loinc:41981-2 ;   # Calories burned
    health:unit "kcal" ;
    health:ucumCode "kcal" .

health:exerciseMinutesWeekly a owl:DatatypeProperty ;
    rdfs:label "Exercise Minutes (Weekly)"@en ;
    rdfs:comment "Total minutes of exercise activity per week"@en ;
    rdfs:domain health:ActivitySnapshot ;
    rdfs:range xsd:integer ;
    health:snomedCode sct:68130003 ;   # Physical activity
    health:loincCode loinc:73985-4 ;   # Exercise activity
    health:unit "min" ;
    health:ucumCode "min" ;
    health:trendPolarity "higher_is_better" .

health:standHoursDaily a owl:DatatypeProperty ;
    rdfs:label "Stand Hours (Daily)"@en ;
    rdfs:comment "Number of hours per day with at least one minute of standing. Cascade-proprietary metric — no SNOMED CT or LOINC equivalent exists. Apple Health-specific activity ring metric."@en ;
    rdfs:domain health:ActivitySnapshot ;
    rdfs:range xsd:integer ;
    health:unit "hours" .

# ----------------------------------------------------------------------------
# Sleep Metrics
# ----------------------------------------------------------------------------

health:averageDurationHours a owl:DatatypeProperty ;
    rdfs:label "Average Sleep Duration"@en ;
    rdfs:comment "Average sleep duration in hours over measurement period"@en ;
    rdfs:domain health:SleepSnapshot ;
    rdfs:range xsd:decimal ;
    health:snomedCode sct:248263006 ;  # Duration of sleep
    health:loincCode loinc:93832-4 ;   # Sleep duration
    health:unit "hours" ;
    health:ucumCode "h" ;
    health:trendPolarity "neutral" .

health:sleepQuality a owl:DatatypeProperty ;
    rdfs:label "Sleep Quality"@en ;
    rdfs:comment "Qualitative sleep quality assessment derived from wearable sleep analysis"@en ;
    rdfs:domain health:SleepSnapshot ;
    rdfs:range xsd:string .

# ============================================================================
# Composite Classes
# ============================================================================

health:ActivitySnapshot a owl:Class ;
    rdfs:label "Activity Snapshot"@en ;
    rdfs:comment "Aggregated activity metrics over a measurement period (typically 7 days)"@en ;
    rdfs:subClassOf prov:Entity .

health:SleepSnapshot a owl:Class ;
    rdfs:label "Sleep Snapshot"@en ;
    rdfs:comment "Aggregated sleep metrics over a measurement period (typically 7 days)"@en ;
    rdfs:subClassOf prov:Entity .

health:VO2MaxStatistics a owl:Class ;
    rdfs:label "VO2 Max Statistics"@en ;
    rdfs:comment "Statistical summary of VO2 Max readings over a measurement period (typically 180 days). Provides trend analysis, fitness classification, and min/max/mean calculations. Designed for dual-path UI display: rich statistics view when available, fallback to single VO2 Max value otherwise."@en ;
    rdfs:subClassOf prov:Entity .

health:HRVStatistics a owl:Class ;
    rdfs:label "HRV Statistics"@en ;
    rdfs:comment "Statistical summary of Heart Rate Variability (SDNN) readings over a measurement period. Provides trend analysis and min/max/mean calculations."@en ;
    rdfs:subClassOf prov:Entity .

health:BPStatistics a owl:Class ;
    rdfs:label "Blood Pressure Statistics"@en ;
    rdfs:comment "Statistical summary of blood pressure readings over a measurement period. Provides mean, min, max for systolic and diastolic values, plus AHA category classification."@en ;
    rdfs:subClassOf prov:Entity .

health:HealthProfile a owl:Class ;
    rdfs:label "Health Profile"@en ;
    rdfs:comment "Top-level wellness profile aggregating vital signs, body measurements, activity, and sleep data from consumer devices. Stored at /wellness/ in the Cascade Pod."@en ;
    rdfs:subClassOf prov:Entity .

health:DailyVitalReading a owl:Class ;
    rdfs:label "Daily Vital Reading"@en ;
    rdfs:comment "A single day's aggregated vital sign reading with value, unit, date, and sample count. Used in 90-day and 30-day history containers."@en ;
    rdfs:subClassOf fhir:Observation .

health:HRVReading a owl:Class ;
    rdfs:label "HRV Reading"@en ;
    rdfs:comment "A single heart rate variability (SDNN) observation with timestamp and optional source."@en ;
    rdfs:subClassOf fhir:Observation .

health:BloodPressureReading a owl:Class ;
    rdfs:label "Blood Pressure Reading"@en ;
    rdfs:comment "A single blood pressure observation with systolic and diastolic components, timestamp, and optional source."@en ;
    rdfs:subClassOf fhir:Observation .

health:VitalSignReading a owl:Class ;
    rdfs:label "Vital Sign Reading"@en ;
    rdfs:comment "A single vital sign observation with value, unit, measurement period, timestamp, and source. Used for baseline readings and VO2 Max history entries."@en ;
    rdfs:subClassOf fhir:Observation .

health:DailyActivitySnapshot a owl:Class ;
    rdfs:label "Daily Activity Snapshot"@en ;
    rdfs:comment "A single day's activity data: steps, active energy, exercise minutes, and stand hours."@en ;
    rdfs:subClassOf prov:Entity .

health:DailySleepSnapshot a owl:Class ;
    rdfs:label "Daily Sleep Snapshot"@en ;
    rdfs:comment "A single night's sleep data: duration in hours and quality classification."@en ;
    rdfs:subClassOf prov:Entity .

# ============================================================================
# History Container Properties (v2.0)
# ============================================================================
# Time-series containers emitted by HealthProfileSerializer for trend analysis.
# Each property links a HealthProfile to an ordered list of readings.

health:restingHeartRateHistory a owl:ObjectProperty ;
    rdfs:label "Resting Heart Rate History"@en ;
    rdfs:comment "Time series of daily resting heart rate readings (90-day lookback). Each entry is a DailyVitalReading with date and value."@en ;
    rdfs:domain health:HealthProfile ;
    rdfs:range health:DailyVitalReading .

health:walkingHeartRateHistory a owl:ObjectProperty ;
    rdfs:label "Walking Heart Rate History"@en ;
    rdfs:comment "Time series of daily walking heart rate readings (90-day lookback)."@en ;
    rdfs:domain health:HealthProfile ;
    rdfs:range health:DailyVitalReading .

health:hrvHistory a owl:ObjectProperty ;
    rdfs:label "HRV History"@en ;
    rdfs:comment "Time series of heart rate variability (SDNN) readings (7-day lookback)."@en ;
    rdfs:domain health:HealthProfile ;
    rdfs:range health:HRVReading .

health:bloodPressureHistory a owl:ObjectProperty ;
    rdfs:label "Blood Pressure History"@en ;
    rdfs:comment "Time series of blood pressure readings (30-day lookback). Each entry has systolic and diastolic values."@en ;
    rdfs:domain health:HealthProfile ;
    rdfs:range health:BloodPressureReading .

health:vo2MaxHistory a owl:ObjectProperty ;
    rdfs:label "VO2 Max History"@en ;
    rdfs:comment "Time series of VO2 Max readings (180-day lookback)."@en ;
    rdfs:domain health:HealthProfile ;
    rdfs:range health:VitalSignReading .

health:bodyMassHistory a owl:ObjectProperty ;
    rdfs:label "Body Mass History"@en ;
    rdfs:comment "Time series of daily body mass readings (30-day lookback)."@en ;
    rdfs:domain health:HealthProfile ;
    rdfs:range health:DailyVitalReading .

health:dailyActivityHistory a owl:ObjectProperty ;
    rdfs:label "Daily Activity History"@en ;
    rdfs:comment "Time series of daily activity snapshots (90-day lookback). Steps, exercise, calories, stand hours per day."@en ;
    rdfs:domain health:HealthProfile ;
    rdfs:range health:DailyActivitySnapshot .

health:dailySleepHistory a owl:ObjectProperty ;
    rdfs:label "Daily Sleep History"@en ;
    rdfs:comment "Time series of daily sleep snapshots (90-day lookback). Duration and quality per night."@en ;
    rdfs:domain health:HealthProfile ;
    rdfs:range health:DailySleepSnapshot .

# ============================================================================
# Self-Report Base Class (v2.1)
# ============================================================================
#
# Base class for patient-reported daily check-ins and self-assessments.
# Apps extend this with domain-specific response data.

health:SelfReport a owl:Class ;
    rdfs:label "Self Report"@en ;
    rdfs:comment "Base class for patient-reported daily check-ins and self-assessments. Provides common structure for timestamped self-reports across health domains. Apps extend this with domain-specific response data. Examples: medication adherence, symptom tracking, mood logging, sleep records."@en ;
    rdfs:subClassOf prov:Entity .

health:reportDate a owl:DatatypeProperty ;
    rdfs:label "Report Date"@en ;
    rdfs:comment "When the self-report was recorded."@en ;
    rdfs:domain health:SelfReport ;
    rdfs:range xsd:dateTime .

health:reportType a owl:DatatypeProperty ;
    rdfs:label "Report Type"@en ;
    rdfs:comment "Category of self-report (e.g., medication_adherence, symptom_tracking, mood, sleep)."@en ;
    rdfs:domain health:SelfReport ;
    rdfs:range xsd:string .

health:completionStatus a owl:DatatypeProperty ;
    rdfs:label "Completion Status"@en ;
    rdfs:comment "Whether the report is complete, partial, or skipped."@en ;
    rdfs:domain health:SelfReport ;
    rdfs:range xsd:string .

health:reportContext a owl:DatatypeProperty ;
    rdfs:label "Report Context"@en ;
    rdfs:comment "What tracking plan or list this report relates to (free-form reference)."@en ;
    rdfs:domain health:SelfReport ;
    rdfs:range xsd:string .

health:reportNotes a owl:DatatypeProperty ;
    rdfs:label "Report Notes"@en ;
    rdfs:comment "Optional free-text notes from the patient."@en ;
    rdfs:domain health:SelfReport ;
    rdfs:range xsd:string .

# ============================================================================
# Annotation Properties
# ============================================================================

health:snomedCode a owl:AnnotationProperty ;
    rdfs:label "SNOMED CT Code"@en ;
    rdfs:comment "Links a wellness property to its SNOMED CT concept"@en .

health:loincCode a owl:AnnotationProperty ;
    rdfs:label "LOINC Code"@en ;
    rdfs:comment "Links a wellness property to its LOINC observation code"@en .

health:unit a owl:AnnotationProperty ;
    rdfs:label "Display Unit"@en ;
    rdfs:comment "Human-readable unit of measurement"@en .

health:ucumCode a owl:AnnotationProperty ;
    rdfs:label "UCUM Code"@en ;
    rdfs:comment "Unified Code for Units of Measure code"@en .

health:trendPolarity a owl:AnnotationProperty ;
    rdfs:label "Trend Polarity"@en ;
    rdfs:comment "Whether an increase in this metric is generally favorable ('higher_is_better'), unfavorable ('lower_is_better'), or context-dependent ('neutral'). Used by presentation layers to determine trend arrow color semantics. This is a general heuristic — individual clinical context may differ."@en .

# ============================================================================
# Pattern A Flat Observation Properties (v2.3 — BUG-006)
# ============================================================================
# These properties are used in Pattern A flat blank nodes emitted by
# HealthProfileSerializer. They replace the fhir:Observation nesting
# (Pattern B) for all wellness vital sign readings.

health:value a owl:DatatypeProperty ;
    rdfs:label "Observation Value"@en ;
    rdfs:comment "Generic numeric value for a wellness observation blank node. Used in Pattern A flat serialization where the observation type is identified by the enclosing property (e.g., health:restingHeartRate). The unit is carried by health:unit on the same blank node."@en ;
    rdfs:range xsd:double .

health:date a owl:DatatypeProperty ;
    rdfs:label "Observation Date"@en ;
    rdfs:comment "Timestamp of a wellness observation in Pattern A flat serialization. Equivalent in role to fhir:effectiveDateTime but scoped to health: namespace blank nodes."@en ;
    rdfs:range xsd:dateTime .

health:sdnn a owl:DatatypeProperty ;
    rdfs:label "SDNN (HRV)"@en ;
    rdfs:comment "Standard deviation of normal-to-normal R-R intervals. The primary HRV scalar emitted in Pattern A HRVReading blank nodes."@en ;
    rdfs:range xsd:double ;
    health:snomedCode sct:80404004 ;
    health:loincCode loinc:80404-7 ;
    health:unit "ms" .

health:systolic a owl:DatatypeProperty ;
    rdfs:label "Systolic Blood Pressure (reading)"@en ;
    rdfs:comment "Systolic component value in a Pattern A BloodPressureReading blank node. Distinct from health:systolicBP which is a domain-level property on fhir:Observation."@en ;
    rdfs:range xsd:double ;
    health:snomedCode sct:271649006 ;
    health:loincCode loinc:8480-6 ;
    health:unit "mmHg" .

health:diastolic a owl:DatatypeProperty ;
    rdfs:label "Diastolic Blood Pressure (reading)"@en ;
    rdfs:comment "Diastolic component value in a Pattern A BloodPressureReading blank node. Distinct from health:diastolicBP which is a domain-level property on fhir:Observation."@en ;
    rdfs:range xsd:double ;
    health:snomedCode sct:271650006 ;
    health:loincCode loinc:8462-4 ;
    health:unit "mmHg" .

health:walkingSteadinessLevel a owl:ObjectProperty ;
    rdfs:label "Walking Steadiness Level"@en ;
    rdfs:comment "Links a Pattern A WalkingSteadiness blank node to its level individual (health:WalkingSteadinessOK, health:WalkingSteadinessLow, health:WalkingSteadinessVeryLow, health:WalkingSteadinessUnknown)."@en ;
    rdfs:range health:WalkingSteadinessLevel .

# health:WalkingSteadinessUnknown added v2.3 (previously only OK/Low/VeryLow defined)
health:WalkingSteadinessUnknown a health:WalkingSteadinessLevel ;
    rdfs:label "Unknown" .

# ============================================================================
# VO2 Max Statistics Properties (v1.7)
# ============================================================================
# Statistical analysis of VO2 Max readings with trend detection and fitness
# classification. Part of the dual-path wellness data pattern where rich
# statistics are preferred when available, with fallback to single values.

health:vo2Mean a owl:DatatypeProperty ;
    rdfs:label "Mean VO2 Max"@en ;
    rdfs:comment "Average VO2 Max over measurement period (mL/kg/min)"@en ;
    rdfs:domain health:VO2MaxStatistics ;
    rdfs:range xsd:double ;
    health:unit "mL/kg/min" ;
    health:ucumCode "mL/kg/min" .

health:vo2Min a owl:DatatypeProperty ;
    rdfs:label "Minimum VO2 Max"@en ;
    rdfs:comment "Lowest VO2 Max reading in measurement period"@en ;
    rdfs:domain health:VO2MaxStatistics ;
    rdfs:range xsd:double ;
    health:unit "mL/kg/min" .

health:vo2MaxValue a owl:DatatypeProperty ;
    rdfs:label "Maximum VO2 Max"@en ;
    rdfs:comment "Highest VO2 Max reading in measurement period"@en ;
    rdfs:domain health:VO2MaxStatistics ;
    rdfs:range xsd:double ;
    health:unit "mL/kg/min" .

health:vo2SampleCount a owl:DatatypeProperty ;
    rdfs:label "Sample Count"@en ;
    rdfs:comment "Number of VO2 Max measurements in the period"@en ;
    rdfs:domain health:VO2MaxStatistics ;
    rdfs:range xsd:integer .

health:vo2DaysCovered a owl:DatatypeProperty ;
    rdfs:label "Days Covered"@en ;
    rdfs:comment "Number of unique days with VO2 Max measurements"@en ;
    rdfs:domain health:VO2MaxStatistics ;
    rdfs:range xsd:integer .

health:vo2TrendDirection a owl:DatatypeProperty ;
    rdfs:label "VO2 Trend Direction"@en ;
    rdfs:comment "Trend direction based on comparison of first half vs second half of readings: 'improving', 'declining', 'stable', or 'unknown'. Uses 3% threshold (1 MET ≈ 3.5 mL/kg/min is clinically meaningful)."@en ;
    rdfs:domain health:VO2MaxStatistics ;
    rdfs:range xsd:string .

health:vo2PercentageChange a owl:DatatypeProperty ;
    rdfs:label "Percentage Change"@en ;
    rdfs:comment "Percentage change from oldest to newest reading period"@en ;
    rdfs:domain health:VO2MaxStatistics ;
    rdfs:range xsd:double .

health:fitnessClassification a owl:DatatypeProperty ;
    rdfs:label "Fitness Classification"@en ;
    rdfs:comment "Cardiorespiratory fitness level based on mean VO2 Max: 'veryPoor' (<20), 'poor' (20-29), 'fair' (30-34), 'good' (35-44), 'excellent' (45-54), 'superior' (≥55). Currently age/sex agnostic; future versions may use demographics for personalized classification."@en ;
    rdfs:domain health:VO2MaxStatistics ;
    rdfs:range xsd:string .

health:isSparseData a owl:DatatypeProperty ;
    rdfs:label "Sparse Data Indicator"@en ;
    rdfs:comment "True when measurements are limited (< 3 samples or < 30 days covered). Used to trigger messaging about VO2 Max measurement requirements."@en ;
    rdfs:domain health:VO2MaxStatistics ;
    rdfs:range xsd:boolean .

# ============================================================================
# Shared Statistics Temporal Properties (v1.8)
# ============================================================================

health:periodStart a owl:DatatypeProperty ;
    rdfs:label "Period Start"@en ;
    rdfs:comment "Start date of the statistical measurement period."@en ;
    rdfs:range xsd:dateTime .

health:periodEnd a owl:DatatypeProperty ;
    rdfs:label "Period End"@en ;
    rdfs:comment "End date of the statistical measurement period."@en ;
    rdfs:range xsd:dateTime .

# ============================================================================
# HRV Statistics Properties (v1.8)
# ============================================================================

health:hrvSampleCount a owl:DatatypeProperty ;
    rdfs:label "HRV Sample Count"@en ;
    rdfs:comment "Number of HRV readings in the period."@en ;
    rdfs:domain health:HRVStatistics ;
    rdfs:range xsd:integer .

health:hrvDaysCovered a owl:DatatypeProperty ;
    rdfs:label "HRV Days Covered"@en ;
    rdfs:comment "Number of unique days with HRV measurements."@en ;
    rdfs:domain health:HRVStatistics ;
    rdfs:range xsd:integer .

health:hrvMean a owl:DatatypeProperty ;
    rdfs:label "Mean HRV"@en ;
    rdfs:comment "Average HRV (SDNN) over the measurement period (ms)."@en ;
    rdfs:domain health:HRVStatistics ;
    rdfs:range xsd:double ;
    health:unit "ms" .

health:hrvMedian a owl:DatatypeProperty ;
    rdfs:label "Median HRV"@en ;
    rdfs:comment "Median HRV (SDNN) over the measurement period (ms)."@en ;
    rdfs:domain health:HRVStatistics ;
    rdfs:range xsd:double ;
    health:unit "ms" .

health:hrvStdDev a owl:DatatypeProperty ;
    rdfs:label "HRV Standard Deviation"@en ;
    rdfs:comment "Standard deviation of HRV readings over the measurement period (ms)."@en ;
    rdfs:domain health:HRVStatistics ;
    rdfs:range xsd:double ;
    health:unit "ms" .

health:hrvMin a owl:DatatypeProperty ;
    rdfs:label "Minimum HRV"@en ;
    rdfs:comment "Lowest HRV reading in the period (ms)."@en ;
    rdfs:domain health:HRVStatistics ;
    rdfs:range xsd:double ;
    health:unit "ms" .

health:hrvMax a owl:DatatypeProperty ;
    rdfs:label "Maximum HRV"@en ;
    rdfs:comment "Highest HRV reading in the period (ms)."@en ;
    rdfs:domain health:HRVStatistics ;
    rdfs:range xsd:double ;
    health:unit "ms" .

health:hrvPercentile25 a owl:DatatypeProperty ;
    rdfs:label "HRV 25th Percentile"@en ;
    rdfs:comment "25th percentile of HRV readings over the measurement period (ms)."@en ;
    rdfs:domain health:HRVStatistics ;
    rdfs:range xsd:double ;
    health:unit "ms" .

health:hrvPercentile75 a owl:DatatypeProperty ;
    rdfs:label "HRV 75th Percentile"@en ;
    rdfs:comment "75th percentile of HRV readings over the measurement period (ms)."@en ;
    rdfs:domain health:HRVStatistics ;
    rdfs:range xsd:double ;
    health:unit "ms" .

health:hrvTrendDirection a owl:DatatypeProperty ;
    rdfs:label "HRV Trend Direction"@en ;
    rdfs:comment "Trend direction for HRV: improving, declining, stable, or unknown."@en ;
    rdfs:domain health:HRVStatistics ;
    rdfs:range xsd:string .

# ============================================================================
# Blood Pressure Statistics Properties (v1.8)
# ============================================================================

health:bpSampleCount a owl:DatatypeProperty ;
    rdfs:label "BP Sample Count"@en ;
    rdfs:comment "Number of blood pressure readings in the period."@en ;
    rdfs:domain health:BPStatistics ;
    rdfs:range xsd:integer .

health:bpMeanSystolic a owl:DatatypeProperty ;
    rdfs:label "Mean Systolic BP"@en ;
    rdfs:comment "Average systolic blood pressure over the measurement period (mmHg)."@en ;
    rdfs:domain health:BPStatistics ;
    rdfs:range xsd:double ;
    health:unit "mmHg" .

health:bpMeanDiastolic a owl:DatatypeProperty ;
    rdfs:label "Mean Diastolic BP"@en ;
    rdfs:comment "Average diastolic blood pressure over the measurement period (mmHg)."@en ;
    rdfs:domain health:BPStatistics ;
    rdfs:range xsd:double ;
    health:unit "mmHg" .

health:bpMinSystolic a owl:DatatypeProperty ;
    rdfs:label "Minimum Systolic BP"@en ;
    rdfs:comment "Lowest systolic blood pressure reading in the period (mmHg)."@en ;
    rdfs:domain health:BPStatistics ;
    rdfs:range xsd:double ;
    health:unit "mmHg" .

health:bpMaxSystolic a owl:DatatypeProperty ;
    rdfs:label "Maximum Systolic BP"@en ;
    rdfs:comment "Highest systolic blood pressure reading in the period (mmHg)."@en ;
    rdfs:domain health:BPStatistics ;
    rdfs:range xsd:double ;
    health:unit "mmHg" .

health:bpMinDiastolic a owl:DatatypeProperty ;
    rdfs:label "Minimum Diastolic BP"@en ;
    rdfs:comment "Lowest diastolic blood pressure reading in the period (mmHg)."@en ;
    rdfs:domain health:BPStatistics ;
    rdfs:range xsd:double ;
    health:unit "mmHg" .

health:bpMaxDiastolic a owl:DatatypeProperty ;
    rdfs:label "Maximum Diastolic BP"@en ;
    rdfs:comment "Highest diastolic blood pressure reading in the period (mmHg)."@en ;
    rdfs:domain health:BPStatistics ;
    rdfs:range xsd:double ;
    health:unit "mmHg" .

health:bpCategory a owl:DatatypeProperty ;
    rdfs:label "BP Category"@en ;
    rdfs:comment "AHA blood pressure category based on mean values: normal, elevated, hypertension_stage1, hypertension_stage2, hypertensive_crisis."@en ;
    rdfs:domain health:BPStatistics ;
    rdfs:range xsd:string .

# ============================================================================
# Temporal Trend Classes (v1.5)
# ============================================================================
# Design rationale: clinical:LabTestSeries captures discrete lab samples over
# clinical visits as a long-lived container. health:MetricTrend is a computed
# observation over a bounded time window from continuous daily device data —
# more like a derived fact than a container. They share trendDirection and
# trendConfidence vocabulary intentionally for cross-domain consistency.
# Values use objective direction (increasing/decreasing) rather than
# value-laden terms (improving/declining) — the ontology describes *what*
# happened; the presentation layer interprets whether it's good or bad.

health:MetricTrend a owl:Class ;
    rdfs:label "Metric Trend" ;
    rdfs:comment "A time-bounded trend for a single wellness metric, computed from a series of observations. Captures direction, magnitude, and comparison period." ;
    rdfs:subClassOf prov:Entity .

# --- MetricTrend Properties ---

health:trendMetric a owl:ObjectProperty ;
    rdfs:label "Trend Metric" ;
    rdfs:comment "The wellness property this trend describes (e.g., health:restingHeartRate)" ;
    rdfs:domain health:MetricTrend .

health:trendDirection a owl:DatatypeProperty ;
    rdfs:label "Trend Direction" ;
    rdfs:comment "Direction of change: increasing, decreasing, stable, or insufficient_data. Matches clinical:trendDirection values for cross-domain consistency. Semantic interpretation (whether 'increasing' is good or bad) is metric-specific and handled at the presentation layer, not the ontology layer." ;
    rdfs:domain health:MetricTrend ;
    rdfs:range xsd:string .

health:trendMagnitude a owl:DatatypeProperty ;
    rdfs:label "Trend Magnitude" ;
    rdfs:comment "Percentage change between comparison periods (e.g., -5.6 means a 5.6% decrease)" ;
    rdfs:domain health:MetricTrend ;
    rdfs:range xsd:decimal .

health:trendPeriodStart a owl:DatatypeProperty ;
    rdfs:label "Trend Period Start" ;
    rdfs:domain health:MetricTrend ;
    rdfs:range xsd:dateTime .

health:trendPeriodEnd a owl:DatatypeProperty ;
    rdfs:label "Trend Period End" ;
    rdfs:domain health:MetricTrend ;
    rdfs:range xsd:dateTime .

health:trendBaselineValue a owl:DatatypeProperty ;
    rdfs:label "Baseline Value" ;
    rdfs:comment "The reference value (e.g., 90-day average) this trend is compared against" ;
    rdfs:domain health:MetricTrend ;
    rdfs:range xsd:decimal .

health:trendCurrentValue a owl:DatatypeProperty ;
    rdfs:label "Current Value" ;
    rdfs:comment "The current period average (e.g., 7-day average)" ;
    rdfs:domain health:MetricTrend ;
    rdfs:range xsd:decimal .

health:trendConfidence a owl:DatatypeProperty ;
    rdfs:label "Trend Confidence" ;
    rdfs:comment "Confidence in the trend: high (>30 days data), medium (14-30 days), low (<14 days)" ;
    rdfs:domain health:MetricTrend ;
    rdfs:range xsd:string .

health:trendSource a owl:ObjectProperty ;
    rdfs:label "Trend Data Source" ;
    rdfs:comment "The data source (device, app, or system) that produced the underlying observations. Links to cascade:DataSource when available; for inline use, a blank node with cascade:sourceName is acceptable." ;
    rdfs:domain health:MetricTrend ;
    rdfs:range cascade:DataSource .

# ============================================================================
# Statistics Container Linking Properties (v2.2)
# ============================================================================
# ObjectProperties used by CheckupSerializer to link an intake form or
# wellness profile to its statistical summary nodes.

health:hasHRVStatistics a owl:ObjectProperty ;
    rdfs:label "has HRV statistics"@en ;
    rdfs:comment "Links a wellness profile to its HRV statistical summary."@en ;
    rdfs:range health:HRVStatistics .

health:hasBPStatistics a owl:ObjectProperty ;
    rdfs:label "has BP statistics"@en ;
    rdfs:comment "Links a wellness profile to its blood pressure statistical summary."@en ;
    rdfs:range health:BPStatistics .

# Named individuals for walkingSteadinessLevel (Pattern A short-form, v2.3)
health:OK a health:WalkingSteadinessLevel ;
    rdfs:label "OK" .
health:Low a health:WalkingSteadinessLevel ;
    rdfs:label "Low" .
health:VeryLow a health:WalkingSteadinessLevel ;
    rdfs:label "Very Low" .
health:Unknown a health:WalkingSteadinessLevel ;
    rdfs:label "Unknown" .

# ============================================================================
# Standard Code Reference Table (for documentation)
# ============================================================================
#
# | Metric                | Health Property              | SNOMED CT   | LOINC    |
# |-----------------------|------------------------------|-------------|----------|
# | Resting Heart Rate    | health:restingHeartRate      | 364075005   | 40443-4  |
# | Walking Heart Rate    | health:walkingHeartRate      | 364075005   | 89270-3  |
# | HRV (SDNN)            | health:heartRateVariability  | 80404004    | 80404-7  |
# | Blood Pressure        | health:bloodPressure         | 75367002    | 85354-9  |
# | Systolic BP           | (component)                  | 271649006   | 8480-6   |
# | Diastolic BP          | (component)                  | 271650006   | 8462-4   |
# | Respiratory Rate      | health:respiratoryRate       | 86290005    | 9279-1   |
# | VO2 Max               | health:vo2Max                | 251880009   | 60842-2  |
# | Walking Steadiness    | health:walkingSteadiness     | 364832000   | ---      |
# | Average Daily Steps   | health:averageDailySteps     | 68130003    | 41950-7  |
# | Active Energy Burned  | health:activeEnergyBurnedKcal| 251833007   | 41981-2  |
# | Exercise Minutes      | health:exerciseMinutesWeekly | 68130003    | 73985-4  |
# | Stand Hours           | health:standHoursDaily       | ---         | ---      |
# | Sleep Duration        | health:averageDurationHours  | 248263006   | 93832-4  |

# ============================================================================
# Social History (v2.4)
# ============================================================================

###  Social History Record
health:SocialHistoryRecord a owl:Class ;
    rdfs:label "Social History Record"@en ;
    rdfs:comment "A social history observation about a patient, including smoking status, alcohol use, exercise, occupation, and other lifestyle factors."@en ;
    owl:versionInfo "Added in health v2.4" .

health:smokingStatus a owl:DatatypeProperty ;
    rdfs:label "Smoking Status"@en ;
    rdfs:comment "Patient's smoking status (e.g., current-smoker, former-smoker, never-smoker)."@en ;
    rdfs:domain health:SocialHistoryRecord ;
    rdfs:range xsd:string .

health:alcoholUse a owl:DatatypeProperty ;
    rdfs:label "Alcohol Use"@en ;
    rdfs:comment "Patient's alcohol consumption description."@en ;
    rdfs:domain health:SocialHistoryRecord ;
    rdfs:range xsd:string .

health:exerciseFrequency a owl:DatatypeProperty ;
    rdfs:label "Exercise Frequency"@en ;
    rdfs:comment "Patient's reported exercise frequency."@en ;
    rdfs:domain health:SocialHistoryRecord ;
    rdfs:range xsd:string .

health:occupationalExposure a owl:DatatypeProperty ;
    rdfs:label "Occupational Exposure"@en ;
    rdfs:comment "Occupational exposures relevant to patient health."@en ;
    rdfs:domain health:SocialHistoryRecord ;
    rdfs:range xsd:string .

# ============================================================================
# Namespace Boundary Note (v2.5)
# ============================================================================
#
# The split between the health: and clinical: namespaces is HISTORICAL, not
# semantic. It is not a provenance signal and must not be read as one.
#
# health: was introduced for consumer- and device-generated wellness data and
# clinical: for EHR-sourced records, but serializers have never honoured that
# division. Records typed health:LabResultRecord, health:ConditionRecord,
# health:AllergyRecord and health:ImmunizationRecord carry EHR-sourced data,
# and clinical:VitalSign records carry consumer-device data.
#
# PROVENANCE IS CARRIED BY cascade:dataProvenance, AND ONLY BY IT.
# Consumers deciding whether a record came from an EHR, a device, or the
# patient MUST key on cascade:dataProvenance (ClinicalGenerated, EHRVerified,
# DeviceGenerated, PatientReported, SelfReported, AIExtracted). Keying on the
# namespace of the rdf:type will give the wrong answer on real pods.
#
# Both namespaces are ratified and neither is being migrated. The clinical:
# classes that duplicate the five classes defined below are deprecated in
# clinical v1.13 (owl:deprecated true, rdfs:seeAlso pointing here) but are NOT
# removed: an existing export path still emits them and existing pods contain
# them. Readers must accept both spellings; writers should prefer these.
#
# ---------------------------------------------------------------------------
# SocialHistoryRecord: two classes, deliberately kept
# ---------------------------------------------------------------------------
#
# health:SocialHistoryRecord (v2.4, above) and clinical:SocialHistoryRecord
# (clinical v1.9) both exist and both are retained. The asserted
# consumer-versus-EHR division does not describe what is emitted:
#
#   - clinical:SocialHistoryRecord is emitted, by the free-text LLM extraction
#     path only.
#   - health:SocialHistoryRecord is emitted by nothing. The structured C-CDA
#     Social History path that appears to write it reports the entries it read
#     but writes no records at all, so the class is defined and shaped but
#     never instantiated.
#
# Neither class is therefore a reliable indicator of how a social-history
# observation was obtained. Consumers should accept both types and read
# cascade:dataProvenance for the actual source. Reconciling the two is
# deferred rather than guessed at.

# ============================================================================
# Clinical Record Classes (v2.5)
# ============================================================================
#
# These five classes have been emitted by Cascade serializers since schema
# version 1.3 but were never defined in this ontology. Defining them is purely
# additive: no serializer changes, no rdf:type changes, no pod migration. It
# makes existing data describable and, with health.shapes.ttl v1.2, checkable.
#
# Layer 1 alignment: each class states the FHIR R4 resource it corresponds to.
# Layer 2: the properties below. Layer 3: checkup:/pots: aggregations.

health:LabResultRecord a owl:Class ;
    rdfs:label "Lab Result Record"@en ;
    rdfs:comment "A laboratory test result: the test performed, its value and unit, the reference range it is read against, and the specimen it came from. Emitted for both EHR-imported and patient-entered results; read cascade:dataProvenance to tell them apart."@en ;
    rdfs:subClassOf fhir:Observation ;
    rdfs:seeAlso <https://hl7.org/fhir/R4/observation.html> ;
    owl:versionInfo "Added in health v2.5; emitted since schema 1.3" .

health:ConditionRecord a owl:Class ;
    rdfs:label "Condition Record"@en ;
    rdfs:comment "A diagnosed condition or problem-list entry, with its clinical status, onset, and coding. Emitted for both EHR-imported and self-reported conditions; read cascade:dataProvenance to tell them apart."@en ;
    rdfs:seeAlso <https://hl7.org/fhir/R4/condition.html> ;
    owl:versionInfo "Added in health v2.5; emitted since schema 1.3" .

health:AllergyRecord a owl:Class ;
    rdfs:label "Allergy Record"@en ;
    rdfs:comment "An allergy or intolerance: the allergen, the reaction it provokes, and the severity of that reaction. Emitted for both EHR-imported and self-reported allergies; read cascade:dataProvenance to tell them apart."@en ;
    rdfs:seeAlso <https://hl7.org/fhir/R4/allergyintolerance.html> ;
    owl:versionInfo "Added in health v2.5; emitted since schema 1.3" .

health:ImmunizationRecord a owl:Class ;
    rdfs:label "Immunization Record"@en ;
    rdfs:comment "An administered vaccine dose, with product identification, lot, route, site and administering party."@en ;
    rdfs:seeAlso <https://hl7.org/fhir/R4/immunization.html> ;
    owl:versionInfo "Added in health v2.5; emitted since schema 1.3" .

health:FamilyHistoryRecord a owl:Class ;
    rdfs:label "Family History Record"@en ;
    rdfs:comment "A condition recorded for a relative of the patient, with the relationship and the relative's age at onset. The relationship is expressed with clinical:relationship, which is shared with coverage records."@en ;
    rdfs:seeAlso <https://hl7.org/fhir/R4/familymemberhistory.html> ;
    owl:versionInfo "Added in health v2.5; emitted since schema 1.3" .

# ----------------------------------------------------------------------------
# Properties shared across the record classes
# ----------------------------------------------------------------------------
# Domains are unions rather than a single class. A single-class rdfs:domain on
# a property that several classes use is an assertion the data falsifies, which
# is the defect this release is correcting elsewhere; do not reintroduce it.

health:notes a owl:DatatypeProperty ;
    rdfs:label "Notes"@en ;
    rdfs:comment "Free-text clinical or patient commentary attached to a record."@en ;
    rdfs:domain [ a owl:Class ; owl:unionOf (
        health:LabResultRecord health:ConditionRecord health:AllergyRecord
        health:ImmunizationRecord health:FamilyHistoryRecord ) ] ;
    rdfs:range xsd:string ;
    owl:versionInfo "Added in health v2.5" .

health:sourceRecordId a owl:DatatypeProperty ;
    rdfs:label "Source Record Identifier"@en ;
    rdfs:comment "Identifier of this record in the system it was imported from. Opaque to Cascade; used for reconciliation against the source system, not as a Cascade identity."@en ;
    rdfs:domain [ a owl:Class ; owl:unionOf (
        health:LabResultRecord health:ConditionRecord health:AllergyRecord
        health:ImmunizationRecord health:FamilyHistoryRecord ) ] ;
    rdfs:range xsd:string ;
    owl:versionInfo "Added in health v2.5" .

health:status a owl:DatatypeProperty ;
    rdfs:label "Status"@en ;
    rdfs:comment "Lifecycle status of the record. The permitted values differ by class and are constrained per-shape, not here: condition records use the FHIR R4 ConditionClinicalStatusCodes value set, immunization records use ImmunizationStatusCodes."@en ;
    rdfs:domain [ a owl:Class ; owl:unionOf ( health:ConditionRecord health:ImmunizationRecord ) ] ;
    rdfs:range xsd:string ;
    owl:versionInfo "Added in health v2.5" .

health:onsetDate a owl:DatatypeProperty ;
    rdfs:label "Onset Date"@en ;
    rdfs:comment "When the condition or allergy began, or was first recorded as beginning."@en ;
    rdfs:domain [ a owl:Class ; owl:unionOf ( health:ConditionRecord health:AllergyRecord ) ] ;
    rdfs:range xsd:dateTime ;
    owl:versionInfo "Added in health v2.5" .

health:conditionName a owl:DatatypeProperty ;
    rdfs:label "Condition Name"@en ;
    rdfs:comment "Human-readable name of the condition. Used both for the patient's own conditions and for conditions recorded against a relative."@en ;
    rdfs:domain [ a owl:Class ; owl:unionOf ( health:ConditionRecord health:FamilyHistoryRecord ) ] ;
    rdfs:range xsd:string ;
    owl:versionInfo "Added in health v2.5" .

# ----------------------------------------------------------------------------
# Lab result properties
# ----------------------------------------------------------------------------

health:testName a owl:DatatypeProperty ;
    rdfs:label "Test Name"@en ;
    rdfs:comment "Human-readable name of the laboratory test performed."@en ;
    rdfs:domain health:LabResultRecord ;
    rdfs:range xsd:string ;
    owl:versionInfo "Added in health v2.5" .

health:resultValue a owl:DatatypeProperty ;
    rdfs:label "Result Value"@en ;
    rdfs:comment "The measured value. Carried as a string because lab results are not uniformly numeric: ratios, titres, qualitative results ('Negative'), and bounded values ('<0.01') all occur. Exactly one value per record."@en ;
    rdfs:domain health:LabResultRecord ;
    rdfs:range xsd:string ;
    owl:versionInfo "Added in health v2.5" .

health:resultUnit a owl:DatatypeProperty ;
    rdfs:label "Result Unit"@en ;
    rdfs:comment "Unit of measure for health:resultValue, as reported by the performing laboratory."@en ;
    rdfs:domain health:LabResultRecord ;
    rdfs:range xsd:string ;
    rdfs:seeAlso <http://unitsofmeasure.org/> ;
    owl:versionInfo "Added in health v2.5" .

health:interpretation a owl:DatatypeProperty ;
    rdfs:label "Interpretation"@en ;
    rdfs:comment "Categorical reading of the result, as a code from the HL7 v3 ObservationInterpretation code system: normality (N, A, H, L, HH, LL, ...), susceptibility (S, I, R, SDD, ...), detection (POS, NEG, DET, ND, IND), reactivity (RR, WR, NR), change (B, D, U, W) and the exception codes. Any of the 15 data-absent-reason codes is also accepted, for a source observation whose interpretation element was absent or null-flavoured; that is FHIR's own spelling for a CodeableConcept that is missing for a stated reason, and it is what keeps 'nobody asked' distinguishable from 'asked, did not know'. A source code that is a member of neither value set is carried verbatim on health:interpretationSourceCode instead of being forced into this one. At most one value per record."@en ;
    rdfs:domain health:LabResultRecord ;
    rdfs:range xsd:string ;
    rdfs:seeAlso <http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation> ;
    rdfs:seeAlso <http://terminology.hl7.org/CodeSystem/data-absent-reason> ;
    rdfs:seeAlso <https://hl7.org/fhir/R4/valueset-observation-interpretation.html> ;
    owl:versionInfo "Added in health v2.5; bound to HL7 v3 ObservationInterpretation in health v2.6; data-absent-reason codes admitted in health v2.7" .

health:interpretationSourceCode a owl:DatatypeProperty ;
    rdfs:label "Interpretation Source Code"@en ;
    rdfs:comment """The interpretation code the SOURCE wrote, copied verbatim, for the case where that code is a member of neither value set health:interpretation is bound to (HL7 v3 ObservationInterpretation, and data-absent-reason). A laboratory's local abnormality flag is the ordinary case.

WRITE IT ONLY THEN. A code that IS in one of the bound value sets belongs on health:interpretation and must not be duplicated here; this property is the escape hatch for the residue, not a parallel spelling.

It is deliberately unconstrained: no value set, no pattern, no case folding. The whole point is that the value is whatever the source said, so a reader can recover the original assertion and a later mapping can be built from real observed codes rather than guesses. Constraining it would recreate the loss it exists to prevent.

A producer that recognises the source code's INTENT should also write its best ratified equivalent on health:interpretation, so that a consumer reading only the bound property still gets a usable reading. The pair 'interpretation A, interpretationSourceCode elevated' says: the source said "elevated", and the nearest ratified code is A (Abnormal)."""@en ;
    rdfs:domain health:LabResultRecord ;
    rdfs:range xsd:string ;
    rdfs:seeAlso health:interpretation ;
    owl:versionInfo "Added in health v2.7" .

health:performedDate a owl:DatatypeProperty ;
    rdfs:label "Performed Date"@en ;
    rdfs:comment "When the specimen was collected or the test performed. Distinct from health:reportedDate."@en ;
    rdfs:domain health:LabResultRecord ;
    rdfs:range xsd:dateTime ;
    owl:versionInfo "Added in health v2.5" .

health:reportedDate a owl:DatatypeProperty ;
    rdfs:label "Reported Date"@en ;
    rdfs:comment "When the laboratory released the result. Later than health:performedDate."@en ;
    rdfs:domain health:LabResultRecord ;
    rdfs:range xsd:dateTime ;
    owl:versionInfo "Added in health v2.5" .

health:testCode a owl:ObjectProperty ;
    rdfs:label "Test Code"@en ;
    rdfs:comment "LOINC reference for the test performed, as an IRI. Repeatable: FHIR R4 CodeableConcept.coding is 0..*, and one test is often carried under more than one LOINC coding."@en ;
    rdfs:domain health:LabResultRecord ;
    rdfs:seeAlso <http://loinc.org/> ;
    rdfs:seeAlso <https://hl7.org/fhir/R4/datatypes.html#CodeableConcept> ;
    owl:versionInfo "Added in health v2.5; made repeatable in health v2.6" .

health:labCategory a owl:DatatypeProperty ;
    rdfs:label "Lab Category"@en ;
    rdfs:comment "Laboratory department or panel grouping (for example Chemistry, Hematology). Free text: laboratories do not agree on a common set. Repeatable, mirroring FHIR R4 Observation.category, which is 0..*."@en ;
    rdfs:domain health:LabResultRecord ;
    rdfs:range xsd:string ;
    rdfs:seeAlso <https://hl7.org/fhir/R4/observation-definitions.html#Observation.category> ;
    owl:versionInfo "Added in health v2.5; made repeatable in health v2.6" .

health:referenceRange a owl:DatatypeProperty ;
    rdfs:label "Reference Range"@en ;
    rdfs:comment "The normal range this result is read against, as printed by the performing laboratory (for example '70 - 100'). Not parsed."@en ;
    rdfs:domain health:LabResultRecord ;
    rdfs:range xsd:string ;
    owl:versionInfo "Added in health v2.5" .

health:specimenType a owl:DatatypeProperty ;
    rdfs:label "Specimen Type"@en ;
    rdfs:comment "The specimen the test was run on (for example Serum, Whole Blood, Urine)."@en ;
    rdfs:domain health:LabResultRecord ;
    rdfs:range xsd:string ;
    owl:versionInfo "Added in health v2.5" .

health:orderingProvider a owl:DatatypeProperty ;
    rdfs:label "Ordering Provider"@en ;
    rdfs:comment "Name of the clinician who ordered the test."@en ;
    rdfs:domain health:LabResultRecord ;
    rdfs:range xsd:string ;
    owl:versionInfo "Added in health v2.5" .

health:performingLab a owl:DatatypeProperty ;
    rdfs:label "Performing Laboratory"@en ;
    rdfs:comment "Name of the laboratory that ran the test."@en ;
    rdfs:domain health:LabResultRecord ;
    rdfs:range xsd:string ;
    owl:versionInfo "Added in health v2.5" .

# ----------------------------------------------------------------------------
# Condition properties
# ----------------------------------------------------------------------------

health:icd10Code a owl:ObjectProperty ;
    rdfs:label "ICD-10-CM Code"@en ;
    rdfs:comment "ICD-10-CM reference for the condition, as an IRI. Repeatable: FHIR R4 CodeableConcept.coding is 0..*, and problem-list entries are routinely dual coded. Note that ICD-10-CM permits a letter in any character position (C4A, D3A and M1A are ordinary categories), so no lexical pattern is imposed here."@en ;
    rdfs:domain health:ConditionRecord ;
    rdfs:seeAlso <https://hl7.org/fhir/R4/codesystem-icd10.html> ;
    rdfs:seeAlso <https://hl7.org/fhir/R4/datatypes.html#CodeableConcept> ;
    owl:versionInfo "Added in health v2.5; made repeatable in health v2.6" .

health:conditionClass a owl:DatatypeProperty ;
    rdfs:label "Condition Class"@en ;
    rdfs:comment "Body-system grouping used for patient-facing organisation (for example cardiovascular, endocrine, respiratory). A presentation aid, not a clinical classification; do not use it for decision support."@en ;
    rdfs:domain health:ConditionRecord ;
    rdfs:range xsd:string ;
    owl:versionInfo "Added in health v2.5" .

health:monitoredVitalSigns a owl:ObjectProperty ;
    rdfs:label "Monitored Vital Signs"@en ;
    rdfs:comment "Ordered list of vital-sign names a patient or app tracks because of this condition (for example bloodPressure, heartRate). An rdf:List of string literals."@en ;
    rdfs:domain health:ConditionRecord ;
    rdfs:range rdf:List ;
    owl:versionInfo "Added in health v2.5" .

# ----------------------------------------------------------------------------
# Allergy properties
# ----------------------------------------------------------------------------

health:allergen a owl:DatatypeProperty ;
    rdfs:label "Allergen"@en ;
    rdfs:comment "The substance the patient reacts to. Required: an allergy record without an allergen carries no safety information."@en ;
    rdfs:domain health:AllergyRecord ;
    rdfs:range xsd:string ;
    owl:versionInfo "Added in health v2.5" .

health:allergyCategory a owl:DatatypeProperty ;
    rdfs:label "Allergy Category"@en ;
    rdfs:comment "Category of the allergen, using the FHIR R4 AllergyIntoleranceCategory value set: food, medication, environment, biologic."@en ;
    rdfs:domain health:AllergyRecord ;
    rdfs:range xsd:string ;
    rdfs:seeAlso <https://hl7.org/fhir/R4/valueset-allergy-intolerance-category.html> ;
    owl:versionInfo "Added in health v2.5" .

health:reaction a owl:DatatypeProperty ;
    rdfs:label "Reaction"@en ;
    rdfs:comment "Description of the manifestation the allergen produces (for example 'Hives (urticaria)')."@en ;
    rdfs:domain health:AllergyRecord ;
    rdfs:range xsd:string ;
    owl:versionInfo "Added in health v2.5" .

health:allergySeverity a owl:DatatypeProperty ;
    rdfs:label "Allergy Severity"@en ;
    rdfs:comment "Severity of the reaction as a whole, using the FHIR R4 AllergyIntoleranceSeverity value set: mild, moderate, severe."@en ;
    rdfs:domain health:AllergyRecord ;
    rdfs:range xsd:string ;
    rdfs:seeAlso <https://hl7.org/fhir/R4/valueset-reaction-event-severity.html> ;
    owl:versionInfo "Added in health v2.5" .

# ----------------------------------------------------------------------------
# Immunization properties
# ----------------------------------------------------------------------------

health:vaccineName a owl:DatatypeProperty ;
    rdfs:label "Vaccine Name"@en ;
    rdfs:comment "Human-readable name of the vaccine product administered."@en ;
    rdfs:domain health:ImmunizationRecord ;
    rdfs:range xsd:string ;
    owl:versionInfo "Added in health v2.5" .

health:administrationDate a owl:DatatypeProperty ;
    rdfs:label "Administration Date"@en ;
    rdfs:comment "When the dose was administered. Corresponds to FHIR R4 Immunization.occurrence, which is 1..1."@en ;
    rdfs:domain health:ImmunizationRecord ;
    rdfs:range xsd:dateTime ;
    owl:versionInfo "Added in health v2.5" .

health:vaccineCode a owl:DatatypeProperty ;
    rdfs:label "Vaccine Code"@en ;
    rdfs:comment "Coded identifier for the vaccine product, typically a CVX code."@en ;
    rdfs:domain health:ImmunizationRecord ;
    rdfs:range xsd:string ;
    rdfs:seeAlso <https://hl7.org/fhir/R4/valueset-vaccine-code.html> ;
    owl:versionInfo "Added in health v2.5" .

health:manufacturer a owl:DatatypeProperty ;
    rdfs:label "Manufacturer"@en ;
    rdfs:comment "Manufacturer of the administered vaccine product."@en ;
    rdfs:domain health:ImmunizationRecord ;
    rdfs:range xsd:string ;
    owl:versionInfo "Added in health v2.5" .

health:lotNumber a owl:DatatypeProperty ;
    rdfs:label "Lot Number"@en ;
    rdfs:comment "Manufacturer lot number of the administered dose. Required for recall tracing."@en ;
    rdfs:domain health:ImmunizationRecord ;
    rdfs:range xsd:string ;
    owl:versionInfo "Added in health v2.5" .

health:doseQuantity a owl:DatatypeProperty ;
    rdfs:label "Dose Quantity"@en ;
    rdfs:comment "Amount administered, value and unit together as printed (for example '0.5 mL')."@en ;
    rdfs:domain health:ImmunizationRecord ;
    rdfs:range xsd:string ;
    owl:versionInfo "Added in health v2.5" .

health:route a owl:DatatypeProperty ;
    rdfs:label "Route"@en ;
    rdfs:comment "Route of administration (for example intramuscular, oral, intranasal)."@en ;
    rdfs:domain health:ImmunizationRecord ;
    rdfs:range xsd:string ;
    rdfs:seeAlso <https://hl7.org/fhir/R4/valueset-immunization-route.html> ;
    owl:versionInfo "Added in health v2.5" .

health:site a owl:DatatypeProperty ;
    rdfs:label "Administration Site"@en ;
    rdfs:comment "Body site the dose was administered at (for example 'Left deltoid')."@en ;
    rdfs:domain health:ImmunizationRecord ;
    rdfs:range xsd:string ;
    owl:versionInfo "Added in health v2.5" .

health:administeringProvider a owl:DatatypeProperty ;
    rdfs:label "Administering Provider"@en ;
    rdfs:comment "Name of the person who administered the dose."@en ;
    rdfs:domain health:ImmunizationRecord ;
    rdfs:range xsd:string ;
    owl:versionInfo "Added in health v2.5" .

health:administeringLocation a owl:DatatypeProperty ;
    rdfs:label "Administering Location"@en ;
    rdfs:comment "Facility where the dose was administered."@en ;
    rdfs:domain health:ImmunizationRecord ;
    rdfs:range xsd:string ;
    owl:versionInfo "Added in health v2.5" .

# ----------------------------------------------------------------------------
# Family history properties
# ----------------------------------------------------------------------------

health:onsetAge a owl:DatatypeProperty ;
    rdfs:label "Onset Age"@en ;
    rdfs:comment "Age in years at which the relative's condition began. Corresponds to FHIR R4 FamilyMemberHistory.condition.onsetAge."@en ;
    rdfs:domain health:FamilyHistoryRecord ;
    rdfs:range xsd:integer ;
    owl:versionInfo "Added in health v2.5" .

# ============================================================================
# Wellness Container Classes (v2.5)
# ============================================================================
#
# Six containers that HealthProfileSerializer has always emitted at /wellness/.
# Each is a partition of a health profile carrying one family of history
# containers. Declaring them subclasses of health:HealthProfile does two things:
#
#   1. It makes the rdfs:domain health:HealthProfile already asserted on the
#      eight history container properties above TRUE. Before this release those
#      domain statements were contradicted by every pod ever written, because
#      health:dailyActivityHistory is emitted on a health:ActivityData subject,
#      never on a health:HealthProfile subject.
#   2. It brings these subjects under health:HealthProfileShape, whose
#      sh:targetClass is subclass-aware per SHACL 2.1.3.1.
#
# No serializer changes. No rdf:type changes. These subjects were already
# being written with exactly these types.

health:ActivityData a owl:Class ;
    rdfs:label "Activity Data"@en ;
    rdfs:comment "Wellness container for daily activity history: steps, active energy, exercise minutes and stand hours."@en ;
    rdfs:subClassOf health:HealthProfile ;
    owl:versionInfo "Added in health v2.5; emitted since health v2.0" .

health:SleepData a owl:Class ;
    rdfs:label "Sleep Data"@en ;
    rdfs:comment "Wellness container for nightly sleep history: duration and quality."@en ;
    rdfs:subClassOf health:HealthProfile ;
    owl:versionInfo "Added in health v2.5; emitted since health v2.0" .

health:HeartRateData a owl:Class ;
    rdfs:label "Heart Rate Data"@en ;
    rdfs:comment "Wellness container for resting and walking heart rate history."@en ;
    rdfs:subClassOf health:HealthProfile ;
    owl:versionInfo "Added in health v2.5; emitted since health v2.0" .

health:BloodPressureData a owl:Class ;
    rdfs:label "Blood Pressure Data"@en ;
    rdfs:comment "Wellness container for blood pressure history from home monitors."@en ;
    rdfs:subClassOf health:HealthProfile ;
    owl:versionInfo "Added in health v2.5; emitted since health v2.0" .

health:HRVData a owl:Class ;
    rdfs:label "HRV Data"@en ;
    rdfs:comment "Wellness container for heart rate variability (SDNN) history."@en ;
    rdfs:subClassOf health:HealthProfile ;
    owl:versionInfo "Added in health v2.5; emitted since health v2.0" .

health:BodyMeasurements a owl:Class ;
    rdfs:label "Body Measurements"@en ;
    rdfs:comment "Wellness container for body mass and related anthropometric history."@en ;
    rdfs:subClassOf health:HealthProfile ;
    owl:versionInfo "Added in health v2.5; emitted since health v2.0" .

# ============================================================================
# Daily Snapshot Properties (v2.5)
# ============================================================================
#
# Emitted on health:DailyActivitySnapshot and health:DailySleepSnapshot entries
# inside the history containers. These are the single-day forms. The similarly
# named health:activeEnergyBurnedKcal, health:exerciseMinutesWeekly and
# health:standHoursDaily above are the 7-day aggregate forms carried on
# health:ActivitySnapshot; the two sets are distinct and both are emitted.

health:steps a owl:DatatypeProperty ;
    rdfs:label "Steps"@en ;
    rdfs:comment "Step count for a single day."@en ;
    rdfs:domain health:DailyActivitySnapshot ;
    rdfs:range xsd:integer ;
    owl:versionInfo "Added in health v2.5" .

health:activeEnergyKcal a owl:DatatypeProperty ;
    rdfs:label "Active Energy (kcal)"@en ;
    rdfs:comment "Active energy burned in kilocalories for a single day."@en ;
    rdfs:domain health:DailyActivitySnapshot ;
    rdfs:range xsd:decimal ;
    owl:versionInfo "Added in health v2.5" .

health:exerciseMinutes a owl:DatatypeProperty ;
    rdfs:label "Exercise Minutes"@en ;
    rdfs:comment "Minutes of exercise recorded for a single day."@en ;
    rdfs:domain health:DailyActivitySnapshot ;
    rdfs:range xsd:integer ;
    owl:versionInfo "Added in health v2.5" .

health:standHours a owl:DatatypeProperty ;
    rdfs:label "Stand Hours"@en ;
    rdfs:comment "Hours in which standing was recorded for a single day. Bounded 0-24."@en ;
    rdfs:domain health:DailyActivitySnapshot ;
    rdfs:range xsd:integer ;
    owl:versionInfo "Added in health v2.5" .

health:durationHours a owl:DatatypeProperty ;
    rdfs:label "Sleep Duration (hours)"@en ;
    rdfs:comment "Total sleep duration in hours for a single night."@en ;
    rdfs:domain health:DailySleepSnapshot ;
    rdfs:range xsd:decimal ;
    owl:versionInfo "Added in health v2.5" .

# ----------------------------------------------------------------------------
# Sleep quality individuals (v2.5)
# ----------------------------------------------------------------------------
#
# health:sleepQuality is emitted with an IRI object, not a string literal:
# HealthProfileSerializer writes `health:sleepQuality health:Good` and
# HealthProfileDeserializer parses exactly that form. The four individuals it
# ranges over were never defined. They are defined here.
#
# health:sleepQuality itself is left declared as it was (see above). Its
# rdfs:range xsd:string does not describe what is emitted, and no known emitter
# produces the string form, but correcting the declaration is a separate change
# with its own compatibility question and is deferred rather than bundled here.
# health:DailySleepSnapshotShape therefore constrains this property's
# cardinality and permitted values but asserts no datatype.

health:SleepQuality a owl:Class ;
    rdfs:label "Sleep Quality"@en ;
    rdfs:comment "Qualitative classification of a night's sleep, as derived by the recording device."@en ;
    owl:versionInfo "Added in health v2.5" .

health:Excellent a owl:NamedIndividual, health:SleepQuality ;
    rdfs:label "Excellent"@en ;
    rdfs:comment "Sleep quality classified as excellent."@en .

health:Good a owl:NamedIndividual, health:SleepQuality ;
    rdfs:label "Good"@en ;
    rdfs:comment "Sleep quality classified as good."@en .

health:Fair a owl:NamedIndividual, health:SleepQuality ;
    rdfs:label "Fair"@en ;
    rdfs:comment "Sleep quality classified as fair."@en .

health:Poor a owl:NamedIndividual, health:SleepQuality ;
    rdfs:label "Poor"@en ;
    rdfs:comment "Sleep quality classified as poor."@en .
