@the-cascade-protocol/cli 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/.dockerignore +7 -0
  2. package/.eslintrc.json +23 -0
  3. package/.prettierrc +7 -0
  4. package/DOCKER.md +36 -0
  5. package/Dockerfile +18 -0
  6. package/README.md +69 -0
  7. package/dist/commands/capabilities.d.ts +9 -0
  8. package/dist/commands/capabilities.d.ts.map +1 -0
  9. package/dist/commands/capabilities.js +194 -0
  10. package/dist/commands/capabilities.js.map +1 -0
  11. package/dist/commands/conformance.d.ts +15 -0
  12. package/dist/commands/conformance.d.ts.map +1 -0
  13. package/dist/commands/conformance.js +348 -0
  14. package/dist/commands/conformance.js.map +1 -0
  15. package/dist/commands/convert.d.ts +21 -0
  16. package/dist/commands/convert.d.ts.map +1 -0
  17. package/dist/commands/convert.js +134 -0
  18. package/dist/commands/convert.js.map +1 -0
  19. package/dist/commands/pod/export.d.ts +8 -0
  20. package/dist/commands/pod/export.d.ts.map +1 -0
  21. package/dist/commands/pod/export.js +72 -0
  22. package/dist/commands/pod/export.js.map +1 -0
  23. package/dist/commands/pod/helpers.d.ts +79 -0
  24. package/dist/commands/pod/helpers.d.ts.map +1 -0
  25. package/dist/commands/pod/helpers.js +369 -0
  26. package/dist/commands/pod/helpers.js.map +1 -0
  27. package/dist/commands/pod/index.d.ts +20 -0
  28. package/dist/commands/pod/index.d.ts.map +1 -0
  29. package/dist/commands/pod/index.js +29 -0
  30. package/dist/commands/pod/index.js.map +1 -0
  31. package/dist/commands/pod/info.d.ts +9 -0
  32. package/dist/commands/pod/info.d.ts.map +1 -0
  33. package/dist/commands/pod/info.js +196 -0
  34. package/dist/commands/pod/info.js.map +1 -0
  35. package/dist/commands/pod/init.d.ts +9 -0
  36. package/dist/commands/pod/init.d.ts.map +1 -0
  37. package/dist/commands/pod/init.js +251 -0
  38. package/dist/commands/pod/init.js.map +1 -0
  39. package/dist/commands/pod/query.d.ts +9 -0
  40. package/dist/commands/pod/query.d.ts.map +1 -0
  41. package/dist/commands/pod/query.js +169 -0
  42. package/dist/commands/pod/query.js.map +1 -0
  43. package/dist/commands/pod 2.js +1017 -0
  44. package/dist/commands/pod.d.ts +28 -0
  45. package/dist/commands/pod.d.ts 2.map +1 -0
  46. package/dist/commands/pod.d.ts.map +1 -0
  47. package/dist/commands/pod.js +1031 -0
  48. package/dist/commands/pod.js 2.map +1 -0
  49. package/dist/commands/pod.js.map +1 -0
  50. package/dist/commands/serve.d.ts +33 -0
  51. package/dist/commands/serve.d.ts.map +1 -0
  52. package/dist/commands/serve.js +74 -0
  53. package/dist/commands/serve.js.map +1 -0
  54. package/dist/commands/validate.d.ts +18 -0
  55. package/dist/commands/validate.d.ts.map +1 -0
  56. package/dist/commands/validate.js +275 -0
  57. package/dist/commands/validate.js.map +1 -0
  58. package/dist/index.d.ts +19 -0
  59. package/dist/index.d.ts.map +1 -0
  60. package/dist/index.js +49 -0
  61. package/dist/index.js.map +1 -0
  62. package/dist/lib/fhir-converter/cascade-to-fhir.d.ts +17 -0
  63. package/dist/lib/fhir-converter/cascade-to-fhir.d.ts.map +1 -0
  64. package/dist/lib/fhir-converter/cascade-to-fhir.js +358 -0
  65. package/dist/lib/fhir-converter/cascade-to-fhir.js.map +1 -0
  66. package/dist/lib/fhir-converter/converters-clinical.d.ts +29 -0
  67. package/dist/lib/fhir-converter/converters-clinical.d.ts.map +1 -0
  68. package/dist/lib/fhir-converter/converters-clinical.js +391 -0
  69. package/dist/lib/fhir-converter/converters-clinical.js.map +1 -0
  70. package/dist/lib/fhir-converter/converters-demographics.d.ts +20 -0
  71. package/dist/lib/fhir-converter/converters-demographics.d.ts.map +1 -0
  72. package/dist/lib/fhir-converter/converters-demographics.js +242 -0
  73. package/dist/lib/fhir-converter/converters-demographics.js.map +1 -0
  74. package/dist/lib/fhir-converter/fhir-to-cascade.d.ts +17 -0
  75. package/dist/lib/fhir-converter/fhir-to-cascade.d.ts.map +1 -0
  76. package/dist/lib/fhir-converter/fhir-to-cascade.js +63 -0
  77. package/dist/lib/fhir-converter/fhir-to-cascade.js.map +1 -0
  78. package/dist/lib/fhir-converter/index.d.ts +36 -0
  79. package/dist/lib/fhir-converter/index.d.ts.map +1 -0
  80. package/dist/lib/fhir-converter/index.js +187 -0
  81. package/dist/lib/fhir-converter/index.js.map +1 -0
  82. package/dist/lib/fhir-converter/types.d.ts +77 -0
  83. package/dist/lib/fhir-converter/types.d.ts.map +1 -0
  84. package/dist/lib/fhir-converter/types.js +236 -0
  85. package/dist/lib/fhir-converter/types.js.map +1 -0
  86. package/dist/lib/fhir-converter.d.ts +62 -0
  87. package/dist/lib/fhir-converter.d.ts.map +1 -0
  88. package/dist/lib/fhir-converter.js +1474 -0
  89. package/dist/lib/fhir-converter.js.map +1 -0
  90. package/dist/lib/mcp/audit.d.ts +24 -0
  91. package/dist/lib/mcp/audit.d.ts.map +1 -0
  92. package/dist/lib/mcp/audit.js +85 -0
  93. package/dist/lib/mcp/audit.js.map +1 -0
  94. package/dist/lib/mcp/server.d.ts +38 -0
  95. package/dist/lib/mcp/server.d.ts.map +1 -0
  96. package/dist/lib/mcp/server.js +172 -0
  97. package/dist/lib/mcp/server.js.map +1 -0
  98. package/dist/lib/mcp/tools.d.ts +47 -0
  99. package/dist/lib/mcp/tools.d.ts.map +1 -0
  100. package/dist/lib/mcp/tools.js +547 -0
  101. package/dist/lib/mcp/tools.js.map +1 -0
  102. package/dist/lib/output.d.ts +26 -0
  103. package/dist/lib/output.d.ts.map +1 -0
  104. package/dist/lib/output.js +64 -0
  105. package/dist/lib/output.js.map +1 -0
  106. package/dist/lib/shacl-validator.d.ts +53 -0
  107. package/dist/lib/shacl-validator.d.ts.map +1 -0
  108. package/dist/lib/shacl-validator.js +245 -0
  109. package/dist/lib/shacl-validator.js.map +1 -0
  110. package/dist/lib/turtle-parser.d.ts +64 -0
  111. package/dist/lib/turtle-parser.d.ts.map +1 -0
  112. package/dist/lib/turtle-parser.js +236 -0
  113. package/dist/lib/turtle-parser.js.map +1 -0
  114. package/dist/shapes/checkup.shapes.ttl +1459 -0
  115. package/dist/shapes/clinical.shapes.ttl +1350 -0
  116. package/dist/shapes/clinical.ttl +1369 -0
  117. package/dist/shapes/core.shapes.ttl +450 -0
  118. package/dist/shapes/core.ttl +603 -0
  119. package/dist/shapes/coverage.shapes.ttl +214 -0
  120. package/dist/shapes/coverage.ttl +182 -0
  121. package/dist/shapes/health.shapes.ttl +697 -0
  122. package/dist/shapes/health.ttl +859 -0
  123. package/dist/shapes/pots.shapes.ttl +481 -0
  124. package/package.json +54 -0
  125. package/src/commands/capabilities.ts +235 -0
  126. package/src/commands/conformance.ts +447 -0
  127. package/src/commands/convert.ts +164 -0
  128. package/src/commands/pod/export.ts +85 -0
  129. package/src/commands/pod/helpers.ts +449 -0
  130. package/src/commands/pod/index.ts +32 -0
  131. package/src/commands/pod/info.ts +239 -0
  132. package/src/commands/pod/init.ts +273 -0
  133. package/src/commands/pod/query.ts +224 -0
  134. package/src/commands/serve.ts +92 -0
  135. package/src/commands/validate.ts +303 -0
  136. package/src/index.ts +58 -0
  137. package/src/lib/fhir-converter/cascade-to-fhir.ts +369 -0
  138. package/src/lib/fhir-converter/converters-clinical.ts +446 -0
  139. package/src/lib/fhir-converter/converters-demographics.ts +270 -0
  140. package/src/lib/fhir-converter/fhir-to-cascade.ts +82 -0
  141. package/src/lib/fhir-converter/index.ts +215 -0
  142. package/src/lib/fhir-converter/types.ts +318 -0
  143. package/src/lib/mcp/audit.ts +107 -0
  144. package/src/lib/mcp/server.ts +192 -0
  145. package/src/lib/mcp/tools.ts +668 -0
  146. package/src/lib/output.ts +76 -0
  147. package/src/lib/shacl-validator.ts +314 -0
  148. package/src/lib/turtle-parser.ts +277 -0
  149. package/src/shapes/checkup.shapes.ttl +1459 -0
  150. package/src/shapes/clinical.shapes.ttl +1350 -0
  151. package/src/shapes/clinical.ttl +1369 -0
  152. package/src/shapes/core.shapes.ttl +450 -0
  153. package/src/shapes/core.ttl +603 -0
  154. package/src/shapes/coverage.shapes.ttl +214 -0
  155. package/src/shapes/coverage.ttl +182 -0
  156. package/src/shapes/health.shapes.ttl +697 -0
  157. package/src/shapes/health.ttl +859 -0
  158. package/src/shapes/pots.shapes.ttl +481 -0
  159. package/test-fixtures/fhir-bundle-example.json +216 -0
  160. package/test-fixtures/fhir-medication-example.json +18 -0
  161. package/tests/cli.test.ts +126 -0
  162. package/tests/fhir-converter.test.ts +874 -0
  163. package/tests/mcp-server.test.ts +396 -0
  164. package/tests/pod.test.ts +400 -0
  165. package/tsconfig.json +24 -0
@@ -0,0 +1,1459 @@
1
+ @prefix sh: <http://www.w3.org/ns/shacl#> .
2
+ @prefix checkup: <https://ns.cascadeprotocol.org/checkup/v1#> .
3
+ @prefix cascade: <https://ns.cascadeprotocol.org/core/v1#> .
4
+ @prefix health: <https://ns.cascadeprotocol.org/health/v1#> .
5
+ @prefix clinical: <https://ns.cascadeprotocol.org/clinical/v1#> .
6
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
7
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
8
+
9
+ # ============================================================================
10
+ # CASCADE CHECKUP SHACL SHAPES - ADULT (Ages 18-64)
11
+ # ============================================================================
12
+ # Version: 2.0
13
+ # Created: 2026-01-03
14
+ # Modified: 2026-02-18 (v2.0: Shapes for v1.5-v2.0 ontology classes)
15
+ #
16
+ # SEVERITY LEVELS:
17
+ # - sh:Violation = Must fix (blocks export) - e.g., missing patient name
18
+ # - sh:Warning = Should address (shown prominently) - e.g., no allergies listed
19
+ # - sh:Info = Nice to have (suggestions) - e.g., incomplete family history
20
+ #
21
+ # PHASE 7 ADDITIONS:
22
+ # - Extended MedicationSummaryShape with episode linkage and patient meaning fields
23
+ # - Added SupplementSummaryShape with regulatory classification requirements
24
+ # - Added hasSupplement validation to IntakeFormData
25
+ #
26
+ # v1.6 ADDITIONS:
27
+ # - Added IntakeQuestionnaireResponseShape with LOINC panel code validation
28
+ # - Added ResponseItemShape with question text validation
29
+ # - Added hasQuestionnaireResponse validation to IntakeFormData
30
+ #
31
+ # v2.0 ADDITIONS (WS8 - Shapes for v1.5-v2.0 ontology classes):
32
+ # - Added DailyCheckInShape with SelfReport inheritance via sh:node
33
+ # - Added ImmunizationSummaryShape with vaccine validation
34
+ # - Added LabResultSummaryShape with mixed namespace (clinical:/checkup:)
35
+ # - Added ProcedureSummaryShape with mixed namespace (clinical:/checkup:)
36
+ # - Added DiscussionTopicShape with category and relevance validation
37
+ # - Added hasDailyCheckIn, hasDiscussionTopic, hasImmunization,
38
+ # hasLabResult, hasProcedure aggregate links to IntakeFormDataShape
39
+ # - Added health: and clinical: prefix declarations
40
+ # ============================================================================
41
+
42
+ # ============================================================================
43
+ # INTAKE FORM DATA SHAPE (Top-level validation)
44
+ # ============================================================================
45
+
46
+ checkup:IntakeFormDataShape a sh:NodeShape ;
47
+ sh:targetClass checkup:IntakeFormData ;
48
+ rdfs:label "Intake Form Data Validation" ;
49
+ rdfs:comment "Validates completeness of intake form data for adult patients (18-64)" ;
50
+
51
+ # Required: Patient Profile
52
+ sh:property [
53
+ sh:path checkup:hasPatientProfile ;
54
+ sh:minCount 1 ;
55
+ sh:maxCount 1 ;
56
+ sh:node checkup:PatientProfileShape ;
57
+ sh:severity sh:Violation ;
58
+ sh:message "Patient profile is required for intake forms"
59
+ ] ;
60
+
61
+ # Required: Schema version
62
+ sh:property [
63
+ sh:path checkup:schemaVersion ;
64
+ sh:minCount 1 ;
65
+ sh:datatype xsd:string ;
66
+ sh:severity sh:Violation ;
67
+ sh:message "Schema version is required"
68
+ ] ;
69
+
70
+ # Required: Generation timestamp
71
+ sh:property [
72
+ sh:path checkup:generatedAt ;
73
+ sh:minCount 1 ;
74
+ sh:datatype xsd:dateTime ;
75
+ sh:severity sh:Violation ;
76
+ sh:message "Generation timestamp is required"
77
+ ] ;
78
+
79
+ # Warning: Medications
80
+ sh:property [
81
+ sh:path checkup:hasMedication ;
82
+ sh:minCount 0 ;
83
+ sh:node checkup:MedicationSummaryShape ;
84
+ sh:severity sh:Warning ;
85
+ sh:message "Medication list helps providers avoid drug interactions. Add your current medications or confirm 'None'."
86
+ ] ;
87
+
88
+ # Info: Supplements (Phase 3 - separate from medications)
89
+ sh:property [
90
+ sh:path checkup:hasSupplement ;
91
+ sh:minCount 0 ;
92
+ sh:node checkup:SupplementSummaryShape ;
93
+ sh:severity sh:Info ;
94
+ sh:message "Supplements and OTC products can interact with medications. Consider listing supplements separately from prescription medications."
95
+ ] ;
96
+
97
+ # Warning: Allergies
98
+ sh:property [
99
+ sh:path checkup:hasAllergy ;
100
+ sh:minCount 0 ;
101
+ sh:node checkup:AllergySummaryShape ;
102
+ sh:severity sh:Warning ;
103
+ sh:message "Allergy information helps prevent adverse reactions. Add allergies or confirm 'No Known Drug Allergies (NKDA)'."
104
+ ] ;
105
+
106
+ # Warning: Insurance
107
+ sh:property [
108
+ sh:path checkup:hasInsurance ;
109
+ sh:minCount 0 ;
110
+ sh:maxCount 1 ;
111
+ sh:node checkup:InsuranceInfoShape ;
112
+ sh:severity sh:Warning ;
113
+ sh:message "Insurance information is usually required for office visits. Add insurance or select 'Self-Pay'."
114
+ ] ;
115
+
116
+ # Warning: Conditions
117
+ sh:property [
118
+ sh:path checkup:hasCondition ;
119
+ sh:minCount 0 ;
120
+ sh:node checkup:ConditionSummaryShape ;
121
+ sh:severity sh:Warning ;
122
+ sh:message "Active conditions help providers understand your health history. Add conditions or confirm 'None'."
123
+ ] ;
124
+
125
+ # Info: Family History
126
+ sh:property [
127
+ sh:path checkup:hasFamilyHistory ;
128
+ sh:minCount 0 ;
129
+ sh:node checkup:FamilyHistoryEntryShape ;
130
+ sh:severity sh:Info ;
131
+ sh:message "Family history helps assess risk for certain conditions. Consider adding health history for parents and siblings."
132
+ ] ;
133
+
134
+ # Info: Vital Signs Trends
135
+ sh:property [
136
+ sh:path checkup:hasVitalsTrend ;
137
+ sh:minCount 0 ;
138
+ sh:node checkup:VitalSignsTrendShape ;
139
+ sh:severity sh:Info ;
140
+ sh:message "Recent vital signs provide context for your current health status."
141
+ ] ;
142
+
143
+ # Info: Screening Status
144
+ sh:property [
145
+ sh:path checkup:hasScreening ;
146
+ sh:minCount 0 ;
147
+ sh:node checkup:ScreeningStatusShape ;
148
+ sh:severity sh:Info ;
149
+ sh:message "Tracking preventive screenings helps you stay current with recommended care."
150
+ ] ;
151
+
152
+ # Info: Visit Issues
153
+ sh:property [
154
+ sh:path checkup:hasVisitIssue ;
155
+ sh:minCount 0 ;
156
+ sh:node checkup:VisitIssueShape ;
157
+ sh:severity sh:Info ;
158
+ sh:message "Adding issues you want to discuss helps you make the most of your appointment."
159
+ ] ;
160
+
161
+ # Info: Diagnostic Results
162
+ sh:property [
163
+ sh:path checkup:hasDiagnosticResult ;
164
+ sh:minCount 0 ;
165
+ sh:node checkup:DiagnosticTestResultShape ;
166
+ sh:severity sh:Info ;
167
+ sh:message "Including recent diagnostic tests gives your provider valuable context."
168
+ ] ;
169
+
170
+ # Info: Intake Questionnaires (v1.6)
171
+ sh:property [
172
+ sh:path checkup:hasQuestionnaireResponse ;
173
+ sh:minCount 0 ;
174
+ sh:node checkup:IntakeQuestionnaireResponseShape ;
175
+ sh:severity sh:Info ;
176
+ sh:message "Consider completing intake questionnaires for a more complete health profile."
177
+ ] ;
178
+
179
+ # Info: Daily Check-ins (v2.0)
180
+ sh:property [
181
+ sh:path checkup:hasDailyCheckIn ;
182
+ sh:minCount 0 ;
183
+ sh:node checkup:DailyCheckInShape ;
184
+ sh:severity sh:Info ;
185
+ sh:message "Daily medication check-ins help track adherence patterns for your provider."
186
+ ] ;
187
+
188
+ # Info: Discussion Topics (v2.0)
189
+ sh:property [
190
+ sh:path checkup:hasDiscussionTopic ;
191
+ sh:minCount 0 ;
192
+ sh:node checkup:DiscussionTopicShape ;
193
+ sh:severity sh:Info ;
194
+ sh:message "Discussion topics help prioritize what to cover during your appointment."
195
+ ] ;
196
+
197
+ # Info: Immunizations (v2.0)
198
+ sh:property [
199
+ sh:path checkup:hasImmunization ;
200
+ sh:minCount 0 ;
201
+ sh:node checkup:ImmunizationSummaryShape ;
202
+ sh:severity sh:Info ;
203
+ sh:message "Including immunization records helps your provider review your vaccination status."
204
+ ] ;
205
+
206
+ # Info: Lab Results (v2.0)
207
+ sh:property [
208
+ sh:path checkup:hasLabResult ;
209
+ sh:minCount 0 ;
210
+ sh:node checkup:LabResultSummaryShape ;
211
+ sh:severity sh:Info ;
212
+ sh:message "Recent lab results give your provider context about your current health status."
213
+ ] ;
214
+
215
+ # Info: Procedures (v2.0)
216
+ sh:property [
217
+ sh:path checkup:hasProcedure ;
218
+ sh:minCount 0 ;
219
+ sh:node checkup:ProcedureSummaryShape ;
220
+ sh:severity sh:Info ;
221
+ sh:message "Procedure history helps your provider understand your surgical and diagnostic background."
222
+ ] .
223
+
224
+ # ============================================================================
225
+ # PATIENT PROFILE SHAPE (Critical - blocks export if invalid)
226
+ # ============================================================================
227
+
228
+ checkup:PatientProfileShape a sh:NodeShape ;
229
+ sh:targetClass checkup:PatientProfile ;
230
+ rdfs:label "Patient Profile Validation" ;
231
+ rdfs:comment "Validates required patient demographics" ;
232
+
233
+ # VIOLATION: Patient name required
234
+ sh:property [
235
+ sh:path checkup:patientName ;
236
+ sh:minCount 1 ;
237
+ sh:datatype xsd:string ;
238
+ sh:minLength 2 ;
239
+ sh:severity sh:Violation ;
240
+ sh:message "Patient name is required for intake forms"
241
+ ] ;
242
+
243
+ # VIOLATION: Date of birth required
244
+ sh:property [
245
+ sh:path checkup:dateOfBirth ;
246
+ sh:minCount 1 ;
247
+ sh:datatype xsd:date ;
248
+ sh:severity sh:Violation ;
249
+ sh:message "Date of birth is required for intake forms"
250
+ ] ;
251
+
252
+ # VIOLATION: Biological sex required (for screening recommendations)
253
+ sh:property [
254
+ sh:path checkup:biologicalSex ;
255
+ sh:minCount 1 ;
256
+ sh:datatype xsd:string ;
257
+ sh:in ( "male" "female" "intersex" ) ;
258
+ sh:severity sh:Violation ;
259
+ sh:message "Biological sex is required for medical screening recommendations"
260
+ ] ;
261
+
262
+ # WARNING: Contact phone recommended
263
+ sh:property [
264
+ sh:path checkup:contactPhone ;
265
+ sh:minCount 0 ;
266
+ sh:datatype xsd:string ;
267
+ sh:severity sh:Warning ;
268
+ sh:message "Contact phone number is typically required by healthcare providers"
269
+ ] ;
270
+
271
+ # INFO: Emergency contact suggested
272
+ sh:property [
273
+ sh:path checkup:emergencyContact ;
274
+ sh:minCount 0 ;
275
+ sh:datatype xsd:string ;
276
+ sh:severity sh:Info ;
277
+ sh:message "Consider adding an emergency contact"
278
+ ] ;
279
+
280
+ # Computed age must be valid integer
281
+ sh:property [
282
+ sh:path checkup:computedAge ;
283
+ sh:datatype xsd:integer ;
284
+ sh:minInclusive 18 ;
285
+ sh:maxInclusive 64 ;
286
+ sh:severity sh:Warning ;
287
+ sh:message "Age should be between 18-64 for adult shapes (use senior shapes for 65+)"
288
+ ] ;
289
+
290
+ # Age group must be valid
291
+ sh:property [
292
+ sh:path checkup:ageGroup ;
293
+ sh:in ( "young_adult" "adult" ) ;
294
+ sh:severity sh:Info ;
295
+ sh:message "Age group should be young_adult (18-39) or adult (40-64)"
296
+ ] ;
297
+
298
+ # Gender identity is optional but validated if present
299
+ sh:property [
300
+ sh:path checkup:genderIdentity ;
301
+ sh:in ( "woman" "man" "non_binary" "other" "prefer_not_to_say" ) ;
302
+ sh:severity sh:Info ;
303
+ sh:message "Gender identity must be a valid option if provided"
304
+ ] .
305
+
306
+ # ============================================================================
307
+ # INSURANCE INFO SHAPE
308
+ # ============================================================================
309
+
310
+ checkup:InsuranceInfoShape a sh:NodeShape ;
311
+ sh:targetClass checkup:InsuranceInfo ;
312
+ rdfs:label "Insurance Information Validation" ;
313
+ rdfs:comment "Validates insurance details for intake forms" ;
314
+
315
+ # WARNING: Provider name required if insurance section exists
316
+ sh:property [
317
+ sh:path checkup:insuranceProvider ;
318
+ sh:minCount 1 ;
319
+ sh:datatype xsd:string ;
320
+ sh:severity sh:Warning ;
321
+ sh:message "Insurance provider name is required"
322
+ ] ;
323
+
324
+ # WARNING: Member ID required
325
+ sh:property [
326
+ sh:path checkup:memberId ;
327
+ sh:minCount 1 ;
328
+ sh:datatype xsd:string ;
329
+ sh:severity sh:Warning ;
330
+ sh:message "Member ID / Policy number is required for insurance verification"
331
+ ] ;
332
+
333
+ # Coverage type must be valid
334
+ sh:property [
335
+ sh:path checkup:coverageType ;
336
+ sh:in ( "hmo" "ppo" "epo" "pos" "medicare" "medicaid" "tricare" "self_pay" "other" ) ;
337
+ sh:severity sh:Info ;
338
+ sh:message "Coverage type should be a recognized plan type"
339
+ ] ;
340
+
341
+ # INFO: PCP recommended
342
+ sh:property [
343
+ sh:path checkup:primaryCareProvider ;
344
+ sh:minCount 0 ;
345
+ sh:datatype xsd:string ;
346
+ sh:severity sh:Info ;
347
+ sh:message "Primary care provider name is helpful for care coordination"
348
+ ] .
349
+
350
+ # ============================================================================
351
+ # MEDICATION SUMMARY SHAPE (Extended v1.2 - Phase 3 Medication Ontology)
352
+ # ============================================================================
353
+
354
+ checkup:MedicationSummaryShape a sh:NodeShape ;
355
+ sh:targetClass checkup:MedicationSummary ;
356
+ rdfs:label "Medication Summary Validation" ;
357
+ rdfs:comment "Validates medication entries with adherence data and episode linkage (Phase 3 extended)" ;
358
+
359
+ # WARNING: Medication name required
360
+ sh:property [
361
+ sh:path checkup:medicationName ;
362
+ sh:minCount 1 ;
363
+ sh:datatype xsd:string ;
364
+ sh:minLength 2 ;
365
+ sh:severity sh:Warning ;
366
+ sh:message "Medication name is required"
367
+ ] ;
368
+
369
+ # INFO: Dose recommended
370
+ sh:property [
371
+ sh:path checkup:dose ;
372
+ sh:minCount 0 ;
373
+ sh:datatype xsd:string ;
374
+ sh:severity sh:Info ;
375
+ sh:message "Including the dose helps prevent medication errors"
376
+ ] ;
377
+
378
+ # INFO: Frequency recommended
379
+ sh:property [
380
+ sh:path checkup:frequency ;
381
+ sh:in ( "once_daily" "twice_daily" "three_times_daily" "four_times_daily" "as_needed" "weekly" "monthly" "other" ) ;
382
+ sh:severity sh:Info ;
383
+ sh:message "Frequency should be a recognized dosing schedule"
384
+ ] ;
385
+
386
+ # Adherence status must be valid if present
387
+ sh:property [
388
+ sh:path checkup:adherenceStatus ;
389
+ sh:in ( "taking_as_prescribed" "usually_take" "sometimes_miss" "often_miss" "stopped" ) ;
390
+ sh:severity sh:Info ;
391
+ sh:message "Adherence status must be a recognized value"
392
+ ] ;
393
+
394
+ # Adherence barrier must be valid if present
395
+ sh:property [
396
+ sh:path checkup:adherenceBarrier ;
397
+ sh:in ( "cost" "side_effects" "forgetfulness" "access" "complexity" "other" "none" ) ;
398
+ sh:severity sh:Info ;
399
+ sh:message "Adherence barrier must be a recognized value"
400
+ ] ;
401
+
402
+ # Effectiveness must be valid if present
403
+ sh:property [
404
+ sh:path checkup:perceivedEffectiveness ;
405
+ sh:in ( "very_effective" "somewhat_effective" "not_sure" "not_effective" ) ;
406
+ sh:severity sh:Info ;
407
+ sh:message "Perceived effectiveness must be a recognized value"
408
+ ] ;
409
+
410
+ # Phase 3: Episode linkage (recommended for traceability)
411
+ sh:property [
412
+ sh:path checkup:episodeId ;
413
+ sh:datatype xsd:string ;
414
+ sh:maxCount 1 ;
415
+ sh:severity sh:Info ;
416
+ sh:name "Episode ID" ;
417
+ sh:message "Linking to MedicationUseEpisode enables longitudinal tracking"
418
+ ] ;
419
+
420
+ # Phase 3: Start date
421
+ sh:property [
422
+ sh:path checkup:startDate ;
423
+ sh:datatype xsd:date ;
424
+ sh:maxCount 1 ;
425
+ sh:severity sh:Info ;
426
+ sh:name "Start Date" ;
427
+ sh:message "Start date helps track medication duration"
428
+ ] ;
429
+
430
+ # Phase 3: Indication (why patient takes it)
431
+ sh:property [
432
+ sh:path checkup:indication ;
433
+ sh:datatype xsd:string ;
434
+ sh:maxCount 1 ;
435
+ sh:severity sh:Info ;
436
+ sh:name "Indication" ;
437
+ sh:message "Understanding why patient takes medication improves clinical context"
438
+ ] ;
439
+
440
+ # Phase 3: Patient cost
441
+ sh:property [
442
+ sh:path checkup:patientCost ;
443
+ sh:datatype xsd:decimal ;
444
+ sh:maxCount 1 ;
445
+ sh:minInclusive 0 ;
446
+ sh:severity sh:Info ;
447
+ sh:name "Patient Cost" ;
448
+ sh:message "Cost tracking helps identify financial barriers"
449
+ ] ;
450
+
451
+ # Phase 3: Cost frequency
452
+ sh:property [
453
+ sh:path checkup:costFrequency ;
454
+ sh:in ( "per_month" "per_refill" "per_dose" "per_bottle" "annual" ) ;
455
+ sh:maxCount 1 ;
456
+ sh:severity sh:Info ;
457
+ sh:name "Cost Frequency" ;
458
+ sh:message "Cost frequency should be a recognized value"
459
+ ] ;
460
+
461
+ # Phase 3: Functional impact
462
+ sh:property [
463
+ sh:path checkup:functionalImpact ;
464
+ sh:datatype xsd:string ;
465
+ sh:maxCount 1 ;
466
+ sh:severity sh:Info ;
467
+ sh:name "Functional Impact" ;
468
+ sh:message "How medication helps patient functionally (e.g., 'helps me sleep')"
469
+ ] ;
470
+
471
+ # Phase 3: Concerns for doctor
472
+ sh:property [
473
+ sh:path checkup:concernsForDoctor ;
474
+ sh:datatype xsd:string ;
475
+ sh:maxCount 1 ;
476
+ sh:severity sh:Info ;
477
+ sh:name "Concerns For Doctor" ;
478
+ sh:message "Concerns patient wants to discuss with provider"
479
+ ] .
480
+
481
+ # ============================================================================
482
+ # SUPPLEMENT SUMMARY SHAPE (v1.1 - Phase 3 Medication Ontology)
483
+ # ============================================================================
484
+
485
+ checkup:SupplementSummaryShape a sh:NodeShape ;
486
+ sh:targetClass checkup:SupplementSummary ;
487
+ rdfs:label "Supplement Summary Validation" ;
488
+ rdfs:comment "Validates supplement entries with regulatory classification. Explicitly separate from medications per Cascade Protocol." ;
489
+
490
+ # WARNING: Supplement name required
491
+ sh:property [
492
+ sh:path checkup:supplementName ;
493
+ sh:minCount 1 ;
494
+ sh:datatype xsd:string ;
495
+ sh:minLength 2 ;
496
+ sh:severity sh:Warning ;
497
+ sh:message "Supplement name is required"
498
+ ] ;
499
+
500
+ # REQUIRED: Regulatory status (distinguishes from FDA-approved medications)
501
+ sh:property [
502
+ sh:path checkup:regulatoryStatus ;
503
+ sh:minCount 1 ;
504
+ sh:in ( "dietarySupplement" "otcDrug" "homeopathic" "herbalRemedy" "unknown" ) ;
505
+ sh:severity sh:Warning ;
506
+ sh:name "Regulatory Status" ;
507
+ sh:message "Regulatory status is required to distinguish supplements from FDA-approved medications"
508
+ ] ;
509
+
510
+ # INFO: Dose recommended
511
+ sh:property [
512
+ sh:path checkup:supplementDose ;
513
+ sh:minCount 0 ;
514
+ sh:datatype xsd:string ;
515
+ sh:severity sh:Info ;
516
+ sh:message "Including the dose helps track supplement intake"
517
+ ] ;
518
+
519
+ # INFO: Frequency recommended
520
+ sh:property [
521
+ sh:path checkup:supplementFrequency ;
522
+ sh:in ( "once_daily" "twice_daily" "three_times_daily" "four_times_daily" "as_needed" "weekly" "monthly" "other" ) ;
523
+ sh:severity sh:Info ;
524
+ sh:message "Frequency should be a recognized dosing schedule"
525
+ ] ;
526
+
527
+ # Optional: Brand
528
+ sh:property [
529
+ sh:path checkup:supplementBrand ;
530
+ sh:datatype xsd:string ;
531
+ sh:maxCount 1 ;
532
+ sh:severity sh:Info ;
533
+ sh:message "Brand helps identify specific products"
534
+ ] ;
535
+
536
+ # Optional: Form
537
+ sh:property [
538
+ sh:path checkup:supplementForm ;
539
+ sh:in ( "capsule" "tablet" "softgel" "liquid" "powder" "gummy" "spray" "patch" "tea" "tincture" "other" ) ;
540
+ sh:maxCount 1 ;
541
+ sh:severity sh:Info ;
542
+ sh:message "Physical form should be a recognized value"
543
+ ] ;
544
+
545
+ # Optional: Evidence strength
546
+ sh:property [
547
+ sh:path checkup:evidenceStrength ;
548
+ sh:in ( "strongEvidence" "moderateEvidence" "limitedEvidence" "traditionalUse" "noEvidence" "unknown" ) ;
549
+ sh:maxCount 1 ;
550
+ sh:severity sh:Info ;
551
+ sh:name "Evidence Strength" ;
552
+ sh:message "Evidence strength helps set expectations about supplement efficacy"
553
+ ] ;
554
+
555
+ # Optional: Reason for use
556
+ sh:property [
557
+ sh:path checkup:reasonForUse ;
558
+ sh:datatype xsd:string ;
559
+ sh:maxCount 1 ;
560
+ sh:severity sh:Info ;
561
+ sh:message "Reason for use helps providers understand patient goals"
562
+ ] ;
563
+
564
+ # Optional: Start date
565
+ sh:property [
566
+ sh:path checkup:supplementStartDate ;
567
+ sh:datatype xsd:date ;
568
+ sh:maxCount 1 ;
569
+ sh:severity sh:Info ;
570
+ sh:message "Start date helps track supplement duration"
571
+ ] ;
572
+
573
+ # Optional: Is active
574
+ sh:property [
575
+ sh:path checkup:supplementIsActive ;
576
+ sh:datatype xsd:boolean ;
577
+ sh:maxCount 1 ;
578
+ sh:severity sh:Info ;
579
+ sh:message "Active status indicates if currently taking"
580
+ ] ;
581
+
582
+ # Optional: DSLD ID (NIH identifier)
583
+ sh:property [
584
+ sh:path checkup:dsldId ;
585
+ sh:datatype xsd:string ;
586
+ sh:maxCount 1 ;
587
+ sh:severity sh:Info ;
588
+ sh:name "DSLD ID" ;
589
+ sh:message "NIH Dietary Supplement Label Database identifier for product lookup"
590
+ ] ;
591
+
592
+ # Optional: Doctor aware
593
+ sh:property [
594
+ sh:path checkup:doctorAware ;
595
+ sh:datatype xsd:boolean ;
596
+ sh:maxCount 1 ;
597
+ sh:severity sh:Info ;
598
+ sh:name "Doctor Aware" ;
599
+ sh:message "Indicates if healthcare provider knows about this supplement"
600
+ ] ;
601
+
602
+ # Optional: Patient cost
603
+ sh:property [
604
+ sh:path checkup:patientCost ;
605
+ sh:datatype xsd:decimal ;
606
+ sh:maxCount 1 ;
607
+ sh:minInclusive 0 ;
608
+ sh:severity sh:Info ;
609
+ sh:message "Cost tracking helps identify financial barriers"
610
+ ] ;
611
+
612
+ # Optional: Cost frequency
613
+ sh:property [
614
+ sh:path checkup:costFrequency ;
615
+ sh:in ( "per_month" "per_refill" "per_dose" "per_bottle" "annual" ) ;
616
+ sh:maxCount 1 ;
617
+ sh:severity sh:Info ;
618
+ sh:message "Cost frequency should be a recognized value"
619
+ ] .
620
+
621
+ # ============================================================================
622
+ # ALLERGY SUMMARY SHAPE
623
+ # ============================================================================
624
+
625
+ checkup:AllergySummaryShape a sh:NodeShape ;
626
+ sh:targetClass checkup:AllergySummary ;
627
+ rdfs:label "Allergy Summary Validation" ;
628
+ rdfs:comment "Validates allergy entries with reaction details" ;
629
+
630
+ # WARNING: Allergen name required
631
+ sh:property [
632
+ sh:path checkup:allergen ;
633
+ sh:minCount 1 ;
634
+ sh:datatype xsd:string ;
635
+ sh:minLength 2 ;
636
+ sh:severity sh:Warning ;
637
+ sh:message "Allergen name is required"
638
+ ] ;
639
+
640
+ # INFO: Reaction type recommended
641
+ sh:property [
642
+ sh:path checkup:reaction ;
643
+ sh:in ( "hives" "rash" "swelling" "difficulty_breathing" "anaphylaxis" "nausea" "diarrhea" "headache" "other" "unknown" ) ;
644
+ sh:severity sh:Info ;
645
+ sh:message "Reaction type should be a recognized value"
646
+ ] ;
647
+
648
+ # INFO: Severity recommended
649
+ sh:property [
650
+ sh:path checkup:allergySeverity ;
651
+ sh:in ( "mild" "moderate" "severe" "life_threatening" ) ;
652
+ sh:severity sh:Info ;
653
+ sh:message "Knowing allergy severity helps providers assess risk"
654
+ ] ;
655
+
656
+ # Category must be valid if present
657
+ sh:property [
658
+ sh:path checkup:allergyCategory ;
659
+ sh:in ( "medication" "food" "environmental" "latex" "contrast" "insect" "other" ) ;
660
+ sh:severity sh:Info ;
661
+ sh:message "Allergy category should be a recognized value"
662
+ ] .
663
+
664
+ # ============================================================================
665
+ # CONDITION SUMMARY SHAPE
666
+ # ============================================================================
667
+
668
+ checkup:ConditionSummaryShape a sh:NodeShape ;
669
+ sh:targetClass checkup:ConditionSummary ;
670
+ rdfs:label "Condition Summary Validation" ;
671
+ rdfs:comment "Validates health condition entries" ;
672
+
673
+ # WARNING: Condition name required
674
+ sh:property [
675
+ sh:path checkup:conditionName ;
676
+ sh:minCount 1 ;
677
+ sh:datatype xsd:string ;
678
+ sh:minLength 2 ;
679
+ sh:severity sh:Warning ;
680
+ sh:message "Condition name is required"
681
+ ] ;
682
+
683
+ # Status must be valid
684
+ sh:property [
685
+ sh:path checkup:conditionStatus ;
686
+ sh:in ( "active" "resolved" "remission" "recurrence" "inactive" ) ;
687
+ sh:severity sh:Info ;
688
+ sh:message "Condition status should be a recognized value"
689
+ ] ;
690
+
691
+ # ICD-10 code pattern if present
692
+ sh:property [
693
+ sh:path checkup:icd10Code ;
694
+ sh:datatype xsd:string ;
695
+ sh:pattern "^[A-Z][0-9]{2}(\\.[0-9A-Z]{1,4})?$" ;
696
+ sh:severity sh:Info ;
697
+ sh:message "ICD-10 code should follow standard format (e.g., I10, E11.9)"
698
+ ] .
699
+
700
+ # ============================================================================
701
+ # FAMILY HISTORY ENTRY SHAPE
702
+ # ============================================================================
703
+
704
+ checkup:FamilyHistoryEntryShape a sh:NodeShape ;
705
+ sh:targetClass checkup:FamilyHistoryEntry ;
706
+ rdfs:label "Family History Entry Validation" ;
707
+ rdfs:comment "Validates family health history entries" ;
708
+
709
+ # INFO: Relative type required
710
+ sh:property [
711
+ sh:path checkup:relativeType ;
712
+ sh:minCount 1 ;
713
+ sh:in ( "mother" "father" "sibling" "maternal_grandmother" "maternal_grandfather" "paternal_grandmother" "paternal_grandfather" "aunt" "uncle" "child" ) ;
714
+ sh:severity sh:Info ;
715
+ sh:message "Relative type is required for family history entries"
716
+ ] ;
717
+
718
+ # INFO: Condition required
719
+ sh:property [
720
+ sh:path checkup:familyCondition ;
721
+ sh:minCount 1 ;
722
+ sh:datatype xsd:string ;
723
+ sh:severity sh:Info ;
724
+ sh:message "Health condition is required for family history entries"
725
+ ] ;
726
+
727
+ # Age at diagnosis should be reasonable
728
+ sh:property [
729
+ sh:path checkup:ageAtDiagnosis ;
730
+ sh:datatype xsd:integer ;
731
+ sh:minInclusive 0 ;
732
+ sh:maxInclusive 120 ;
733
+ sh:severity sh:Info ;
734
+ sh:message "Age at diagnosis should be between 0 and 120"
735
+ ] ;
736
+
737
+ # Age at death should be reasonable
738
+ sh:property [
739
+ sh:path checkup:ageAtDeath ;
740
+ sh:datatype xsd:integer ;
741
+ sh:minInclusive 0 ;
742
+ sh:maxInclusive 120 ;
743
+ sh:severity sh:Info ;
744
+ sh:message "Age at death should be between 0 and 120"
745
+ ] .
746
+
747
+ # ============================================================================
748
+ # VITAL SIGNS TREND SHAPE
749
+ # ============================================================================
750
+
751
+ checkup:VitalSignsTrendShape a sh:NodeShape ;
752
+ sh:targetClass checkup:VitalSignsTrend ;
753
+ rdfs:label "Vital Signs Trend Validation" ;
754
+ rdfs:comment "Validates vital signs with trend analysis" ;
755
+
756
+ # Vital type must be valid
757
+ sh:property [
758
+ sh:path checkup:vitalType ;
759
+ sh:minCount 1 ;
760
+ sh:in ( "blood_pressure" "systolic_bp" "diastolic_bp" "heart_rate" "weight" "height" "bmi" "temperature" "respiratory_rate" "oxygen_saturation" ) ;
761
+ sh:severity sh:Info ;
762
+ sh:message "Vital type must be a recognized measurement type"
763
+ ] ;
764
+
765
+ # Current value required
766
+ sh:property [
767
+ sh:path checkup:currentValue ;
768
+ sh:minCount 1 ;
769
+ sh:severity sh:Info ;
770
+ sh:message "Current value is required for vital signs"
771
+ ] ;
772
+
773
+ # Trend direction must be valid
774
+ sh:property [
775
+ sh:path checkup:trendDirection ;
776
+ sh:in ( "increasing" "decreasing" "stable" ) ;
777
+ sh:severity sh:Info ;
778
+ sh:message "Trend direction should be increasing, decreasing, or stable"
779
+ ] ;
780
+
781
+ # Data source must be valid
782
+ sh:property [
783
+ sh:path checkup:dataSource ;
784
+ sh:in ( "apple_health" "ehr" "manual" "device" "imported" ) ;
785
+ sh:severity sh:Info ;
786
+ sh:message "Data source should be a recognized value"
787
+ ] .
788
+
789
+ # ============================================================================
790
+ # SCREENING STATUS SHAPE
791
+ # ============================================================================
792
+
793
+ checkup:ScreeningStatusShape a sh:NodeShape ;
794
+ sh:targetClass checkup:ScreeningStatus ;
795
+ rdfs:label "Screening Status Validation" ;
796
+ rdfs:comment "Validates preventive screening status" ;
797
+
798
+ # Screening type must be valid
799
+ sh:property [
800
+ sh:path checkup:screeningType ;
801
+ sh:minCount 1 ;
802
+ sh:in ( "mammogram" "colonoscopy" "colorectal" "pap_smear" "psa" "bone_density" "aaa_ultrasound" "lung_ct" "diabetes_a1c" "lipid_panel" "hepatitis_c" "hiv" "std" "skin_cancer" ) ;
803
+ sh:severity sh:Info ;
804
+ sh:message "Screening type must be a recognized preventive screening"
805
+ ] ;
806
+
807
+ # Status must be valid
808
+ sh:property [
809
+ sh:path checkup:screeningStatus ;
810
+ sh:in ( "not_due" "due" "overdue" "completed" "declined" "not_applicable" ) ;
811
+ sh:severity sh:Info ;
812
+ sh:message "Screening status must be a recognized value"
813
+ ] ;
814
+
815
+ # Guideline source should be recognized
816
+ sh:property [
817
+ sh:path checkup:guidelineSource ;
818
+ sh:in ( "USPSTF" "ACS" "AAP" "ACOG" "ADA" "ACC_AHA" "other" ) ;
819
+ sh:severity sh:Info ;
820
+ sh:message "Guideline source should be a recognized organization"
821
+ ] ;
822
+
823
+ # Grade level for USPSTF
824
+ sh:property [
825
+ sh:path checkup:gradeLevel ;
826
+ sh:in ( "A" "B" "C" "D" "I" ) ;
827
+ sh:severity sh:Info ;
828
+ sh:message "USPSTF grade should be A, B, C, D, or I"
829
+ ] .
830
+
831
+ # ============================================================================
832
+ # VISIT ISSUE SHAPE
833
+ # ============================================================================
834
+
835
+ checkup:VisitIssueShape a sh:NodeShape ;
836
+ sh:targetClass checkup:VisitIssue ;
837
+ rdfs:label "Visit Issue Validation" ;
838
+ rdfs:comment "Validates chief complaints / issues to discuss" ;
839
+
840
+ # Category must be valid
841
+ sh:property [
842
+ sh:path checkup:issueCategory ;
843
+ sh:minCount 1 ;
844
+ sh:in ( "pain" "skin" "digestive" "respiratory" "cardiovascular" "mental_health" "neurological" "musculoskeletal" "urinary" "reproductive" "endocrine" "medication" "screening" "general" "other" ) ;
845
+ sh:severity sh:Info ;
846
+ sh:message "Issue category must be a recognized value"
847
+ ] ;
848
+
849
+ # Description required
850
+ sh:property [
851
+ sh:path checkup:issueDescription ;
852
+ sh:minCount 1 ;
853
+ sh:datatype xsd:string ;
854
+ sh:minLength 5 ;
855
+ sh:severity sh:Info ;
856
+ sh:message "Issue description is required and should be at least 5 characters"
857
+ ] ;
858
+
859
+ # Duration must be valid
860
+ sh:property [
861
+ sh:path checkup:issueDuration ;
862
+ sh:in ( "hours" "days" "weeks" "months" "years" ) ;
863
+ sh:severity sh:Info ;
864
+ sh:message "Duration should be hours, days, weeks, months, or years"
865
+ ] ;
866
+
867
+ # Severity must be valid
868
+ sh:property [
869
+ sh:path checkup:issueSeverity ;
870
+ sh:in ( "mild" "moderate" "severe" ) ;
871
+ sh:severity sh:Info ;
872
+ sh:message "Severity should be mild, moderate, or severe"
873
+ ] ;
874
+
875
+ # Frequency must be valid
876
+ sh:property [
877
+ sh:path checkup:issueFrequency ;
878
+ sh:in ( "constant" "intermittent" "occasional" "rare" ) ;
879
+ sh:severity sh:Info ;
880
+ sh:message "Frequency should be constant, intermittent, occasional, or rare"
881
+ ] ;
882
+
883
+ # Priority must be 1-10
884
+ sh:property [
885
+ sh:path checkup:issuePriority ;
886
+ sh:datatype xsd:integer ;
887
+ sh:minInclusive 1 ;
888
+ sh:maxInclusive 10 ;
889
+ sh:severity sh:Info ;
890
+ sh:message "Priority should be between 1 (highest) and 10 (lowest)"
891
+ ] .
892
+
893
+ # ============================================================================
894
+ # DIAGNOSTIC TEST RESULT SHAPE
895
+ # ============================================================================
896
+
897
+ checkup:DiagnosticTestResultShape a sh:NodeShape ;
898
+ sh:targetClass checkup:DiagnosticTestResult ;
899
+ rdfs:label "Diagnostic Test Result Validation" ;
900
+ rdfs:comment "Validates external diagnostic test results" ;
901
+
902
+ # Test type must be valid
903
+ sh:property [
904
+ sh:path checkup:testType ;
905
+ sh:minCount 1 ;
906
+ sh:in ( "pots_check" "blood_pressure_series" "glucose_series" "ecg" "sleep_analysis" "hearing_test" "vision_test" "other" ) ;
907
+ sh:severity sh:Info ;
908
+ sh:message "Test type must be a recognized diagnostic test"
909
+ ] ;
910
+
911
+ # Test date required
912
+ sh:property [
913
+ sh:path checkup:testDate ;
914
+ sh:minCount 1 ;
915
+ sh:datatype xsd:dateTime ;
916
+ sh:severity sh:Info ;
917
+ sh:message "Test date is required for diagnostic results"
918
+ ] ;
919
+
920
+ # Source app required
921
+ sh:property [
922
+ sh:path checkup:sourceApp ;
923
+ sh:minCount 1 ;
924
+ sh:datatype xsd:string ;
925
+ sh:severity sh:Info ;
926
+ sh:message "Source app name is required for provenance"
927
+ ] ;
928
+
929
+ # Result summary required
930
+ sh:property [
931
+ sh:path checkup:resultSummary ;
932
+ sh:minCount 1 ;
933
+ sh:datatype xsd:string ;
934
+ sh:minLength 10 ;
935
+ sh:severity sh:Info ;
936
+ sh:message "Result summary is required and should be descriptive"
937
+ ] .
938
+
939
+ # ============================================================================
940
+ # SUGGESTED QUESTION SHAPE
941
+ # ============================================================================
942
+
943
+ checkup:SuggestedQuestionShape a sh:NodeShape ;
944
+ sh:targetClass checkup:SuggestedQuestion ;
945
+ rdfs:label "Suggested Question Validation" ;
946
+ rdfs:comment "Validates AI-generated or template questions" ;
947
+
948
+ # Question text required
949
+ sh:property [
950
+ sh:path checkup:questionText ;
951
+ sh:minCount 1 ;
952
+ sh:datatype xsd:string ;
953
+ sh:minLength 10 ;
954
+ sh:severity sh:Info ;
955
+ sh:message "Question text is required and should be meaningful"
956
+ ] ;
957
+
958
+ # Category must be valid
959
+ sh:property [
960
+ sh:path checkup:questionCategory ;
961
+ sh:in ( "treatment_options" "side_effects" "prevention" "lifestyle" "referral" "diagnosis" "prognosis" "medication" "screening" "general" ) ;
962
+ sh:severity sh:Info ;
963
+ sh:message "Question category must be a recognized value"
964
+ ] .
965
+
966
+ # ============================================================================
967
+ # INTAKE QUESTIONNAIRE RESPONSE SHAPE (v1.6)
968
+ # ============================================================================
969
+
970
+ checkup:IntakeQuestionnaireResponseShape a sh:NodeShape ;
971
+ sh:targetClass checkup:IntakeQuestionnaireResponse ;
972
+ rdfs:label "Intake Questionnaire Response Validation" ;
973
+ rdfs:comment "Validates intake questionnaire responses using LOINC panel codes" ;
974
+
975
+ # VIOLATION: Questionnaire ID (LOINC panel code) required
976
+ sh:property [
977
+ sh:path checkup:questionnaireId ;
978
+ sh:minCount 1 ;
979
+ sh:datatype xsd:string ;
980
+ sh:minLength 1 ;
981
+ sh:severity sh:Violation ;
982
+ sh:message "Questionnaire ID (LOINC panel code) is required"
983
+ ] ;
984
+
985
+ # VIOLATION: Questionnaire title required
986
+ sh:property [
987
+ sh:path checkup:questionnaireTitle ;
988
+ sh:minCount 1 ;
989
+ sh:datatype xsd:string ;
990
+ sh:severity sh:Violation ;
991
+ sh:message "Questionnaire title is required"
992
+ ] ;
993
+
994
+ # WARNING: At least one response item
995
+ sh:property [
996
+ sh:path checkup:responseItem ;
997
+ sh:minCount 1 ;
998
+ sh:node checkup:ResponseItemShape ;
999
+ sh:severity sh:Warning ;
1000
+ sh:message "Questionnaire should have at least one response item"
1001
+ ] ;
1002
+
1003
+ # INFO: Completion timestamp
1004
+ sh:property [
1005
+ sh:path checkup:completedAt ;
1006
+ sh:datatype xsd:dateTime ;
1007
+ sh:maxCount 1 ;
1008
+ sh:severity sh:Info ;
1009
+ sh:message "Consider adding completion timestamp"
1010
+ ] .
1011
+
1012
+ # ============================================================================
1013
+ # RESPONSE ITEM SHAPE (v1.6)
1014
+ # ============================================================================
1015
+
1016
+ checkup:ResponseItemShape a sh:NodeShape ;
1017
+ sh:targetClass checkup:ResponseItem ;
1018
+ rdfs:label "Response Item Validation" ;
1019
+ rdfs:comment "Validates individual question-answer pairs within a questionnaire response" ;
1020
+
1021
+ # VIOLATION: Question text required
1022
+ sh:property [
1023
+ sh:path checkup:itemText ;
1024
+ sh:minCount 1 ;
1025
+ sh:datatype xsd:string ;
1026
+ sh:minLength 1 ;
1027
+ sh:severity sh:Violation ;
1028
+ sh:message "Question text is required for each response item"
1029
+ ] ;
1030
+
1031
+ # INFO: Item link ID (LOINC code)
1032
+ sh:property [
1033
+ sh:path checkup:itemLinkId ;
1034
+ sh:datatype xsd:string ;
1035
+ sh:maxCount 1 ;
1036
+ sh:severity sh:Info ;
1037
+ sh:message "LOINC item code helps standardize questionnaire items"
1038
+ ] ;
1039
+
1040
+ # INFO: Answer text
1041
+ sh:property [
1042
+ sh:path checkup:itemAnswer ;
1043
+ sh:datatype xsd:string ;
1044
+ sh:severity sh:Info ;
1045
+ sh:message "Consider providing an answer for this item"
1046
+ ] ;
1047
+
1048
+ # INFO: Answer code (SNOMED CT or LOINC answer)
1049
+ sh:property [
1050
+ sh:path checkup:itemAnswerCode ;
1051
+ sh:datatype xsd:string ;
1052
+ sh:severity sh:Info ;
1053
+ sh:message "Coded answer enables interoperability with clinical systems"
1054
+ ] ;
1055
+
1056
+ # INFO: Answer code system URI
1057
+ sh:property [
1058
+ sh:path checkup:itemAnswerCodeSystem ;
1059
+ sh:datatype xsd:anyURI ;
1060
+ sh:severity sh:Info ;
1061
+ sh:message "Code system URI identifies the terminology (e.g., SNOMED CT, LOINC)"
1062
+ ] ;
1063
+
1064
+ # Nested child items (recursive structure)
1065
+ sh:property [
1066
+ sh:path checkup:childItem ;
1067
+ sh:node checkup:ResponseItemShape ;
1068
+ sh:severity sh:Info ;
1069
+ sh:message "Child items support hierarchical questionnaire structures"
1070
+ ] .
1071
+
1072
+ # ============================================================================
1073
+ # DAILY CHECK-IN SHAPE (v2.0 - SelfReport subclass)
1074
+ # ============================================================================
1075
+
1076
+ checkup:DailyCheckInShape a sh:NodeShape ;
1077
+ sh:targetClass checkup:DailyCheckIn ;
1078
+ rdfs:label "Daily Check-in Validation" ;
1079
+ rdfs:comment "Validates daily medication adherence check-ins. Inherits base SelfReport validation via sh:node." ;
1080
+
1081
+ # Inherit SelfReport base validation (reportDate, reportType, completionStatus)
1082
+ sh:node health:SelfReportShape ;
1083
+
1084
+ # VIOLATION: Check-in date required
1085
+ sh:property [
1086
+ sh:path checkup:checkInDate ;
1087
+ sh:minCount 1 ;
1088
+ sh:datatype xsd:dateTime ;
1089
+ sh:severity sh:Violation ;
1090
+ sh:message "Check-in date is required"
1091
+ ] ;
1092
+
1093
+ # VIOLATION: Adherence response required
1094
+ sh:property [
1095
+ sh:path checkup:checkInResponse ;
1096
+ sh:minCount 1 ;
1097
+ sh:in ( "allTaken" "missedSome" "skippedToday" ) ;
1098
+ sh:severity sh:Violation ;
1099
+ sh:message "Check-in response is required and must be allTaken, missedSome, or skippedToday"
1100
+ ] ;
1101
+
1102
+ # INFO: Missed medication IDs (relevant when response is missedSome)
1103
+ sh:property [
1104
+ sh:path checkup:missedMedicationIds ;
1105
+ sh:datatype xsd:string ;
1106
+ sh:severity sh:Info ;
1107
+ sh:message "Consider identifying which medications were missed for better adherence tracking"
1108
+ ] ;
1109
+
1110
+ # INFO: Notes
1111
+ sh:property [
1112
+ sh:path checkup:checkInNotes ;
1113
+ sh:datatype xsd:string ;
1114
+ sh:severity sh:Info ;
1115
+ sh:message "Notes can help explain adherence barriers or side effects"
1116
+ ] ;
1117
+
1118
+ # INFO: Submission timestamp
1119
+ sh:property [
1120
+ sh:path checkup:submittedAt ;
1121
+ sh:datatype xsd:dateTime ;
1122
+ sh:severity sh:Info ;
1123
+ sh:message "Submission timestamp helps track check-in timing patterns"
1124
+ ] .
1125
+
1126
+ # ============================================================================
1127
+ # IMMUNIZATION SUMMARY SHAPE (v2.0)
1128
+ # ============================================================================
1129
+
1130
+ checkup:ImmunizationSummaryShape a sh:NodeShape ;
1131
+ sh:targetClass checkup:ImmunizationSummary ;
1132
+ rdfs:label "Immunization Summary Validation" ;
1133
+ rdfs:comment "Validates immunization records for intake forms" ;
1134
+
1135
+ # VIOLATION: Vaccine name required
1136
+ sh:property [
1137
+ sh:path checkup:vaccineName ;
1138
+ sh:minCount 1 ;
1139
+ sh:datatype xsd:string ;
1140
+ sh:minLength 1 ;
1141
+ sh:severity sh:Violation ;
1142
+ sh:message "Vaccine name is required"
1143
+ ] ;
1144
+
1145
+ # VIOLATION: Administration date required
1146
+ sh:property [
1147
+ sh:path checkup:administrationDate ;
1148
+ sh:minCount 1 ;
1149
+ sh:datatype xsd:dateTime ;
1150
+ sh:severity sh:Violation ;
1151
+ sh:message "Vaccine administration date is required"
1152
+ ] ;
1153
+
1154
+ # WARNING: Immunization status
1155
+ sh:property [
1156
+ sh:path checkup:immunizationStatus ;
1157
+ sh:in ( "completed" "entered-in-error" "not-done" ) ;
1158
+ sh:severity sh:Warning ;
1159
+ sh:message "Immunization status should be completed, entered-in-error, or not-done"
1160
+ ] ;
1161
+
1162
+ # WARNING: Vaccine code (CVX)
1163
+ sh:property [
1164
+ sh:path checkup:vaccineCode ;
1165
+ sh:datatype xsd:string ;
1166
+ sh:severity sh:Warning ;
1167
+ sh:message "CVX vaccine code helps standardize immunization records"
1168
+ ] ;
1169
+
1170
+ # WARNING: Vaccine category
1171
+ sh:property [
1172
+ sh:path checkup:vaccineCategory ;
1173
+ sh:in ( "routine" "travel" "occupational" "other" ) ;
1174
+ sh:severity sh:Warning ;
1175
+ sh:message "Vaccine category should be routine, travel, occupational, or other"
1176
+ ] ;
1177
+
1178
+ # INFO: Manufacturer
1179
+ sh:property [
1180
+ sh:path checkup:manufacturer ;
1181
+ sh:datatype xsd:string ;
1182
+ sh:severity sh:Info ;
1183
+ sh:message "Vaccine manufacturer helps identify specific products"
1184
+ ] ;
1185
+
1186
+ # INFO: Lot number
1187
+ sh:property [
1188
+ sh:path checkup:lotNumber ;
1189
+ sh:datatype xsd:string ;
1190
+ sh:severity sh:Info ;
1191
+ sh:message "Lot number supports vaccine recall tracking"
1192
+ ] ;
1193
+
1194
+ # INFO: Dose number in series
1195
+ sh:property [
1196
+ sh:path checkup:doseNumber ;
1197
+ sh:datatype xsd:integer ;
1198
+ sh:minInclusive 1 ;
1199
+ sh:severity sh:Info ;
1200
+ sh:message "Dose number tracks progress in multi-dose vaccine series"
1201
+ ] ;
1202
+
1203
+ # INFO: Notes
1204
+ sh:property [
1205
+ sh:path checkup:immunizationNotes ;
1206
+ sh:datatype xsd:string ;
1207
+ sh:severity sh:Info ;
1208
+ sh:message "Additional notes about the immunization"
1209
+ ] .
1210
+
1211
+ # ============================================================================
1212
+ # LAB RESULT SUMMARY SHAPE (v2.0 - mixed namespace: clinical:/checkup:)
1213
+ # ============================================================================
1214
+
1215
+ checkup:LabResultSummaryShape a sh:NodeShape ;
1216
+ sh:targetClass checkup:LabResultSummary ;
1217
+ rdfs:label "Lab Result Summary Validation" ;
1218
+ rdfs:comment "Validates lab result records using mixed namespace pattern: clinical: for standardized data, checkup: for app-layer categorization" ;
1219
+
1220
+ # VIOLATION: Test name required (clinical: namespace)
1221
+ sh:property [
1222
+ sh:path clinical:testName ;
1223
+ sh:minCount 1 ;
1224
+ sh:datatype xsd:string ;
1225
+ sh:minLength 1 ;
1226
+ sh:severity sh:Violation ;
1227
+ sh:message "Lab test name is required"
1228
+ ] ;
1229
+
1230
+ # WARNING: Result value
1231
+ sh:property [
1232
+ sh:path clinical:resultValue ;
1233
+ sh:datatype xsd:string ;
1234
+ sh:severity sh:Warning ;
1235
+ sh:message "Lab result value helps providers interpret results"
1236
+ ] ;
1237
+
1238
+ # WARNING: Lab category for intake display
1239
+ sh:property [
1240
+ sh:path checkup:labCategory ;
1241
+ sh:in ( "metabolic" "hematology" "lipid" "thyroid" "vitamin" "other" ) ;
1242
+ sh:severity sh:Warning ;
1243
+ sh:message "Lab category should be metabolic, hematology, lipid, thyroid, vitamin, or other"
1244
+ ] ;
1245
+
1246
+ # INFO: Result unit
1247
+ sh:property [
1248
+ sh:path clinical:resultUnit ;
1249
+ sh:datatype xsd:string ;
1250
+ sh:severity sh:Info ;
1251
+ sh:message "Result unit helps interpret the lab value"
1252
+ ] ;
1253
+
1254
+ # INFO: Reference range
1255
+ sh:property [
1256
+ sh:path clinical:referenceRange ;
1257
+ sh:datatype xsd:string ;
1258
+ sh:severity sh:Info ;
1259
+ sh:message "Reference range provides context for the result"
1260
+ ] ;
1261
+
1262
+ # INFO: Result date
1263
+ sh:property [
1264
+ sh:path clinical:resultDate ;
1265
+ sh:datatype xsd:dateTime ;
1266
+ sh:severity sh:Info ;
1267
+ sh:message "Result date helps establish the timeline of lab work"
1268
+ ] ;
1269
+
1270
+ # INFO: Interpretation
1271
+ sh:property [
1272
+ sh:path clinical:interpretation ;
1273
+ sh:datatype xsd:string ;
1274
+ sh:severity sh:Info ;
1275
+ sh:message "Interpretation (normal, abnormal, critical) helps providers triage results"
1276
+ ] ;
1277
+
1278
+ # INFO: Notes
1279
+ sh:property [
1280
+ sh:path clinical:notes ;
1281
+ sh:datatype xsd:string ;
1282
+ sh:severity sh:Info ;
1283
+ sh:message "Additional clinical notes about the lab result"
1284
+ ] .
1285
+
1286
+ # ============================================================================
1287
+ # PROCEDURE SUMMARY SHAPE (v2.0 - mixed namespace: clinical:/checkup:)
1288
+ # ============================================================================
1289
+
1290
+ checkup:ProcedureSummaryShape a sh:NodeShape ;
1291
+ sh:targetClass checkup:ProcedureSummary ;
1292
+ rdfs:label "Procedure Summary Validation" ;
1293
+ rdfs:comment "Validates procedure records using mixed namespace pattern: checkup: for app-layer fields, clinical: for standardized clinical data" ;
1294
+
1295
+ # VIOLATION: Procedure name required
1296
+ sh:property [
1297
+ sh:path checkup:procedureName ;
1298
+ sh:minCount 1 ;
1299
+ sh:datatype xsd:string ;
1300
+ sh:minLength 1 ;
1301
+ sh:severity sh:Violation ;
1302
+ sh:message "Procedure name is required"
1303
+ ] ;
1304
+
1305
+ # WARNING: Procedure status (clinical: namespace)
1306
+ sh:property [
1307
+ sh:path clinical:procedureStatus ;
1308
+ sh:datatype xsd:string ;
1309
+ sh:severity sh:Warning ;
1310
+ sh:message "Procedure status helps providers know if the procedure was completed"
1311
+ ] ;
1312
+
1313
+ # WARNING: Performed date (clinical: namespace)
1314
+ sh:property [
1315
+ sh:path clinical:performedDate ;
1316
+ sh:datatype xsd:dateTime ;
1317
+ sh:severity sh:Warning ;
1318
+ sh:message "Performed date helps establish the timeline of procedures"
1319
+ ] ;
1320
+
1321
+ # INFO: Procedure category
1322
+ sh:property [
1323
+ sh:path checkup:procedureCategory ;
1324
+ sh:in ( "surgical" "diagnostic" "therapeutic" "other" ) ;
1325
+ sh:severity sh:Info ;
1326
+ sh:message "Procedure category should be surgical, diagnostic, therapeutic, or other"
1327
+ ] ;
1328
+
1329
+ # INFO: Procedure location
1330
+ sh:property [
1331
+ sh:path checkup:procedureLocation ;
1332
+ sh:datatype xsd:string ;
1333
+ sh:severity sh:Info ;
1334
+ sh:message "Facility or location where the procedure was performed"
1335
+ ] ;
1336
+
1337
+ # INFO: Body site
1338
+ sh:property [
1339
+ sh:path clinical:bodySite ;
1340
+ sh:datatype xsd:string ;
1341
+ sh:severity sh:Info ;
1342
+ sh:message "Body site provides specificity about where the procedure was performed"
1343
+ ] ;
1344
+
1345
+ # INFO: Performer
1346
+ sh:property [
1347
+ sh:path clinical:performer ;
1348
+ sh:datatype xsd:string ;
1349
+ sh:severity sh:Info ;
1350
+ sh:message "Performer name supports care coordination"
1351
+ ] ;
1352
+
1353
+ # INFO: Outcome
1354
+ sh:property [
1355
+ sh:path clinical:outcome ;
1356
+ sh:datatype xsd:string ;
1357
+ sh:severity sh:Info ;
1358
+ sh:message "Outcome description provides context about the procedure result"
1359
+ ] .
1360
+
1361
+ # ============================================================================
1362
+ # DISCUSSION TOPIC SHAPE (v2.0)
1363
+ # ============================================================================
1364
+
1365
+ checkup:DiscussionTopicShape a sh:NodeShape ;
1366
+ sh:targetClass checkup:DiscussionTopic ;
1367
+ rdfs:label "Discussion Topic Validation" ;
1368
+ rdfs:comment "Validates AI-generated or user-created visit discussion topics" ;
1369
+
1370
+ # VIOLATION: Topic text required
1371
+ sh:property [
1372
+ sh:path checkup:topicText ;
1373
+ sh:minCount 1 ;
1374
+ sh:datatype xsd:string ;
1375
+ sh:minLength 1 ;
1376
+ sh:severity sh:Violation ;
1377
+ sh:message "Discussion topic text is required"
1378
+ ] ;
1379
+
1380
+ # WARNING: Topic category
1381
+ sh:property [
1382
+ sh:path checkup:topicCategory ;
1383
+ sh:in ( "durationBased" "recentChange" "adherenceConcern" "sideEffectReport" "multipleForSame" "supplementDoctor" "interactionRisk" "refillDue" "effectivenessConcern" "costConcern" "custom" ) ;
1384
+ sh:severity sh:Warning ;
1385
+ sh:message "Topic category must be a recognized value"
1386
+ ] ;
1387
+
1388
+ # INFO: Topic source
1389
+ sh:property [
1390
+ sh:path checkup:topicSource ;
1391
+ sh:datatype xsd:string ;
1392
+ sh:severity sh:Info ;
1393
+ sh:message "Topic source indicates how the topic was generated (medication, supplement, adherencePattern, custom)"
1394
+ ] ;
1395
+
1396
+ # INFO: Relevance score
1397
+ sh:property [
1398
+ sh:path checkup:relevanceScore ;
1399
+ sh:datatype xsd:double ;
1400
+ sh:minInclusive 0.0 ;
1401
+ sh:maxInclusive 1.0 ;
1402
+ sh:severity sh:Info ;
1403
+ sh:message "Relevance score should be between 0.0 and 1.0"
1404
+ ] ;
1405
+
1406
+ # INFO: Is selected for next visit
1407
+ sh:property [
1408
+ sh:path checkup:isSelected ;
1409
+ sh:datatype xsd:boolean ;
1410
+ sh:severity sh:Info ;
1411
+ sh:message "Selection status indicates if topic is active for the next visit"
1412
+ ] .
1413
+
1414
+ # ============================================================================
1415
+ # CHANGELOG
1416
+ # ============================================================================
1417
+ #
1418
+ # v2.0 (2026-02-18): WS8 - Shapes for v1.5-v2.0 ontology classes
1419
+ # - Added health: and clinical: prefix declarations for cross-namespace shapes
1420
+ # - Added 5 new NodeShapes:
1421
+ # - DailyCheckInShape: SelfReport subclass with sh:node health:SelfReportShape
1422
+ # inheritance, checkInDate/checkInResponse required (Violation), missedMedicationIds/
1423
+ # checkInNotes/submittedAt optional (Info)
1424
+ # - ImmunizationSummaryShape: vaccineName/administrationDate required (Violation),
1425
+ # immunizationStatus/vaccineCode/vaccineCategory warnings, manufacturer/lotNumber/
1426
+ # doseNumber/immunizationNotes info
1427
+ # - LabResultSummaryShape: mixed namespace — clinical:testName required (Violation),
1428
+ # clinical:resultValue warning, checkup:labCategory warning, clinical info properties
1429
+ # - ProcedureSummaryShape: mixed namespace — checkup:procedureName required (Violation),
1430
+ # clinical:procedureStatus/performedDate warnings, checkup:procedureCategory/
1431
+ # procedureLocation and clinical:bodySite/performer/outcome info
1432
+ # - DiscussionTopicShape: topicText required (Violation), topicCategory warning,
1433
+ # topicSource/relevanceScore/isSelected info
1434
+ # - Added 5 new aggregate link properties to IntakeFormDataShape:
1435
+ # hasDailyCheckIn, hasDiscussionTopic, hasImmunization, hasLabResult, hasProcedure
1436
+ # - Total shapes: 20 (was 15)
1437
+ #
1438
+ # v1.6 (2026-02-09): Intake Questionnaire SHACL Shapes
1439
+ # - Added IntakeQuestionnaireResponseShape with LOINC panel code validation
1440
+ # - Added ResponseItemShape with question text validation and nested child items
1441
+ # - Added hasQuestionnaireResponse validation to IntakeFormDataShape
1442
+ # - Total shapes: 15 (was 13)
1443
+ #
1444
+ # v1.3 (2026-01-17): Phase 7 Medication Ontology Extensions
1445
+ # - Extended MedicationSummaryShape with episode linkage (episodeId, startDate,
1446
+ # indication) and patient meaning fields (patientCost, costFrequency,
1447
+ # functionalImpact, concernsForDoctor)
1448
+ # - Added SupplementSummaryShape with regulatoryStatus requirement
1449
+ # - Added hasSupplement validation to IntakeFormDataShape
1450
+ #
1451
+ # v1.0 (2026-01-03): Initial release
1452
+ # - 10 core shapes: IntakeFormData, PatientProfile, InsuranceInfo,
1453
+ # MedicationSummary, AllergySummary, ConditionSummary, FamilyHistoryEntry,
1454
+ # VitalSignsTrend, ScreeningStatus, VisitIssue, DiagnosticTestResult,
1455
+ # SuggestedQuestion
1456
+ #
1457
+ # ============================================================================
1458
+ # END OF ADULT SHAPES
1459
+ # ============================================================================