Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions shapes/health_measurement.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix dct: <http://purl.org/dc/terms/> .
@prefix prov: <http://www.w3.org/ns/prov#> .
@prefix schema: <https://schema.org/> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix vs: <http://www.w3.org/2003/06/sw-vocab-status/ns#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

@prefix health_measurement_shape: <https://solidproject.org/shapes/health_measurement#> .

health_measurement_shape:HealthMeasurementShape
a sh:NodeShape ;
sh:targetClass schema:Observation ;
sh:name "Health Measurement Shape" ;
sh:description "SHACL shape for a single health or fitness measurement modelled as a Schema.org Observation. The intended representation for the common cases consumer health and fitness exports (Apple Health, Google Fit, Strava) describe — heart rate, steps, sleep duration, body weight, distance, exercise duration, and energy burned. Note: schema:Observation and the schema:observation* properties currently sit in the pending area of Schema.org (https://pending.schema.org/); native exporters typically emit proprietary formats and an importer is expected to map them to this shape." ;
Comment on lines +4 to +15
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shape uses only the https://schema.org/ namespace. A lot of RDF data (and some shapes in this repo) still use the legacy http://schema.org/ IRIs, so instances/properties like http://schema.org/Observation or http://schema.org/value would not be targeted/validated by this shape. Consider adding a schema_http: prefix and accepting both forms (e.g., dual sh:targetClass entries, and sh:path via sh:alternativePath or the “legacy predicate” pattern used in shapes/chat.ttl).

Copilot uses AI. Check for mistakes.
dct:created "2026-04-23"^^xsd:date ;
vs:term_status "testing" ;
dc:source <https://schema.org/Observation> ;
prov:wasDerivedFrom <https://schema.org/Observation> ;
dct:references <https://schema.org/Observation> ; # references the schema:Observation class (currently in https://pending.schema.org/) which the Schema.org Health-Lifesci extension and broader Schema.org community use to describe a single point measurement, together with schema:value, schema:unitCode, schema:observationDate, schema:observationAbout, and schema:measuredProperty.
dct:references <https://health-lifesci.schema.org/> ; # references the Schema.org Health-Lifesci hosted extension which defines health-specific vocabulary (e.g. schema:ExerciseAction usage, body-weight terms) reused alongside the core Observation pattern.
dct:references <https://www.hl7.org/fhir/observation.html> ; # references HL7 FHIR Observation as a heavier-duty alternative model used by clinical systems; this shape does not depend on FHIR but acknowledges the conceptual mapping.
sh:codeIdentifier "HealthMeasurement";

# Numeric value of the measurement. Accepts the common XSD numeric
# datatypes since SHACL sh:datatype matches exactly (no XSD subtype
# widening), and exporters emit any of decimal, integer, double, or
# float depending on the metric.
sh:property [
sh:path schema:value ;
sh:or (
[ sh:datatype xsd:decimal ]
[ sh:datatype xsd:integer ]
[ sh:datatype xsd:double ]
[ sh:datatype xsd:float ]
) ;
sh:maxCount 1 ;
sh:name "Value" ;
sh:description "Numeric value of the measurement (e.g., 72 for a heart-rate reading, 8500 for a step count, 5.2 for a kilometre distance). May be xsd:decimal, xsd:integer, xsd:double, or xsd:float." ;
sh:codeIdentifier "value";
] ;
Comment on lines +29 to +41
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Several properties described as core constraints in the PR (e.g., schema:value, schema:unitCode, schema:observationDate, schema:observationAbout) only have sh:maxCount here, so an Observation with none of these fields would still conform. If these are intended to be required for a “per-measurement” node, add appropriate sh:minCount 1 constraints (at least for value/date/about, and likely measuredProperty/unitCode depending on the metric).

Copilot uses AI. Check for mistakes.

# Unit of measurement. Per Schema.org, schema:unitCode is Text or URL,
# so accept any IRI or literal (including language-tagged strings).
sh:property [
sh:path schema:unitCode ;
sh:nodeKind sh:IRIOrLiteral ;
sh:maxCount 1 ;
sh:name "Unit Code" ;
sh:description "Unit of measurement, given as a UN/CEFACT Common Code 3-character string (e.g. \"BPM\" for beats per minute, \"KGM\" for kilograms, \"KMT\" for kilometres) or a URL such as a QUDT unit IRI." ;
sh:codeIdentifier "unitCode";
] ;

# Optional human-readable unit text (Schema.org provides schema:unitText).
sh:property [
sh:path schema:unitText ;
sh:datatype xsd:string ;
sh:maxCount 1 ;
sh:name "Unit Text" ;
sh:description "Optional human-readable string for the unit of measurement, used when no UN/CEFACT or URL code is available (e.g. \"steps\", \"hours\")." ;
sh:codeIdentifier "unitText";
] ;

# Date or date-time at which the observation was made. Schema.org's
# observationDate range is Date or DateTime; daily metrics (e.g. weight,
# daily step total) are typically stored at date granularity.
sh:property [
sh:path schema:observationDate ;
sh:or (
[ sh:datatype xsd:dateTime ]
[ sh:datatype xsd:date ]
) ;
sh:maxCount 1 ;
sh:name "Observation Date" ;
sh:description "Date or date-time at which the measurement was taken (Schema.org schema:observationDate). Use xsd:dateTime for instantaneous readings (heart rate, exercise samples) and xsd:date for daily aggregates." ;
sh:codeIdentifier "observationDate";
] ;

# The entity the observation is about. For self-reported health and
# fitness data this is the user's WebID.
sh:property [
sh:path schema:observationAbout ;
sh:nodeKind sh:IRI ;
sh:maxCount 1 ;
sh:name "Observation About" ;
sh:description "The entity the observation is about. For personal health and fitness data this is typically the user's WebID (Schema.org schema:observationAbout)." ;
sh:codeIdentifier "observationAbout";
Comment on lines +82 to +87
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description lists schema:about as the link to the WebID/agent, but this shape uses schema:observationAbout. If schema:about is what consumers/exporters will emit, the shape should accept it (or the PR description should be updated to match schema:observationAbout).

Copilot uses AI. Check for mistakes.
] ;

# What property is being measured. Left open to any IRI so that apps can
# use either Schema.org properties (e.g. schema:weight) or vocabulary from
# other systems (HL7 FHIR, LOINC, QUDT, Wikidata, Data Commons).
sh:property [
sh:path schema:measuredProperty ;
sh:nodeKind sh:IRI ;
sh:maxCount 1 ;
sh:name "Measured Property" ;
sh:description "The property being measured, identified by IRI. Apps may use Schema.org properties (e.g. schema:weight), Health-Lifesci terms, or external vocabularies such as HL7 FHIR, LOINC, or QUDT (Schema.org schema:measuredProperty)." ;
sh:codeIdentifier "measuredProperty";
] ;

# Optional method/device used to capture the measurement (e.g. a smart
# watch, a manual entry, an exercise activity). May be an IRI (device or
# enumeration value) or a literal label.
sh:property [
sh:path schema:measurementMethod ;
sh:nodeKind sh:IRIOrLiteral ;
sh:maxCount 1 ;
sh:name "Measurement Method" ;
sh:description "Method or device used to capture the measurement (Schema.org schema:measurementMethod). May be an IRI to a device or enumeration value, or a literal label." ;
sh:codeIdentifier "measurementMethod";
] .
Loading