@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,450 @@
1
+ @prefix sh: <http://www.w3.org/ns/shacl#> .
2
+ @prefix cascade: <https://ns.cascadeprotocol.org/core/v1#> .
3
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
4
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
5
+
6
+ # ============================================================================
7
+ # Cascade Protocol -- Core Vocabulary SHACL Validation Shapes
8
+ # ============================================================================
9
+ # Version: 1.0 (Phase 4, 2026-02-18)
10
+ # Validates: cascade:PatientProfile, cascade:Address, cascade:EmergencyContact,
11
+ # cascade:PharmacyInfo, cascade:AdvanceDirectives
12
+ #
13
+ # Severity levels:
14
+ # sh:Violation -- Must fix (blocks operations)
15
+ # sh:Warning -- Should address (shown prominently)
16
+ # sh:Info -- Suggestion (nice to have)
17
+ #
18
+ # These shapes validate core patient demographics and identity structures
19
+ # defined in core.ttl v2.2. They are used by all Cascade Protocol applications
20
+ # that serialize PatientProfile data (e.g., Cascade Checkup intake forms,
21
+ # POTS Check patient context).
22
+ # ============================================================================
23
+
24
+ # ============================================================================
25
+ # Shape: Patient Profile
26
+ # ============================================================================
27
+
28
+ cascade:PatientProfileShape a sh:NodeShape ;
29
+ sh:targetClass cascade:PatientProfile ;
30
+ rdfs:label "Patient Profile Shape"@en ;
31
+ rdfs:comment "Validation constraints for patient demographics and identity extensions"@en ;
32
+
33
+ # VIOLATION: dateOfBirth required for age calculation and screening eligibility
34
+ sh:property [
35
+ sh:path cascade:dateOfBirth ;
36
+ sh:datatype xsd:date ;
37
+ sh:minCount 1 ;
38
+ sh:maxCount 1 ;
39
+ sh:severity sh:Violation ;
40
+ sh:name "Date of Birth"@en ;
41
+ sh:message "Patient profile must have a date of birth for age calculation and screening eligibility"@en
42
+ ] ;
43
+
44
+ # VIOLATION: biologicalSex required for clinical calculations
45
+ sh:property [
46
+ sh:path cascade:biologicalSex ;
47
+ sh:datatype xsd:string ;
48
+ sh:minCount 1 ;
49
+ sh:maxCount 1 ;
50
+ sh:in ( "male" "female" "intersex" ) ;
51
+ sh:severity sh:Violation ;
52
+ sh:name "Biological Sex"@en ;
53
+ sh:message "Patient profile must specify biological sex (male, female, or intersex) for clinical calculations"@en
54
+ ] ;
55
+
56
+ # VIOLATION: dataProvenance required for source tracking
57
+ sh:property [
58
+ sh:path cascade:dataProvenance ;
59
+ sh:minCount 1 ;
60
+ sh:severity sh:Violation ;
61
+ sh:name "Data Provenance"@en ;
62
+ sh:message "Patient profile must have at least one data provenance classification"@en
63
+ ] ;
64
+
65
+ # WARNING: genderIdentity recommended for patient-centered care
66
+ sh:property [
67
+ sh:path cascade:genderIdentity ;
68
+ sh:datatype xsd:string ;
69
+ sh:maxCount 1 ;
70
+ sh:in ( "woman" "man" "non_binary" "other" "prefer_not_to_say" ) ;
71
+ sh:severity sh:Warning ;
72
+ sh:name "Gender Identity"@en ;
73
+ sh:message "Gender identity is recommended for patient-centered care. Values: woman, man, non_binary, other, prefer_not_to_say"@en
74
+ ] ;
75
+
76
+ # WARNING: emergencyContact recommended for safety
77
+ sh:property [
78
+ sh:path cascade:emergencyContact ;
79
+ sh:class cascade:EmergencyContact ;
80
+ sh:severity sh:Warning ;
81
+ sh:name "Emergency Contact"@en ;
82
+ sh:message "An emergency contact is recommended for patient safety"@en
83
+ ] ;
84
+
85
+ # INFO: ageGroup for screening classification
86
+ sh:property [
87
+ sh:path cascade:ageGroup ;
88
+ sh:datatype xsd:string ;
89
+ sh:maxCount 1 ;
90
+ sh:in ( "pediatric" "young_adult" "adult" "senior" ) ;
91
+ sh:severity sh:Info ;
92
+ sh:name "Age Group"@en ;
93
+ sh:message "Age group helps classify patients for screening recommendations (pediatric, young_adult, adult, senior)"@en
94
+ ] ;
95
+
96
+ # INFO: computedAge for convenience
97
+ sh:property [
98
+ sh:path cascade:computedAge ;
99
+ sh:datatype xsd:integer ;
100
+ sh:maxCount 1 ;
101
+ sh:minInclusive 0 ;
102
+ sh:maxInclusive 150 ;
103
+ sh:severity sh:Info ;
104
+ sh:name "Computed Age"@en ;
105
+ sh:message "Computed age should be between 0 and 150 years"@en
106
+ ] ;
107
+
108
+ # INFO: maritalStatus for demographic context
109
+ sh:property [
110
+ sh:path cascade:maritalStatus ;
111
+ sh:datatype xsd:string ;
112
+ sh:maxCount 1 ;
113
+ sh:in ( "single" "married" "domestic_partnership" "divorced" "separated" "widowed" "prefer_not_to_say" ) ;
114
+ sh:severity sh:Info ;
115
+ sh:name "Marital Status"@en ;
116
+ sh:message "Marital status provides demographic context for care planning"@en
117
+ ] ;
118
+
119
+ # INFO: raceEthnicity for health disparity tracking
120
+ sh:property [
121
+ sh:path cascade:raceEthnicity ;
122
+ sh:datatype xsd:string ;
123
+ sh:in ( "american_indian_alaska_native" "asian" "black_african_american" "hispanic_latino" "native_hawaiian_pacific_islander" "white" "other" "prefer_not_to_say" ) ;
124
+ sh:severity sh:Info ;
125
+ sh:name "Race/Ethnicity"@en ;
126
+ sh:message "Race/ethnicity data supports health equity tracking and risk assessment"@en
127
+ ] ;
128
+
129
+ # INFO: address for contact information
130
+ sh:property [
131
+ sh:path cascade:address ;
132
+ sh:class cascade:Address ;
133
+ sh:maxCount 1 ;
134
+ sh:severity sh:Info ;
135
+ sh:name "Address"@en ;
136
+ sh:message "A postal address is helpful for care coordination and correspondence"@en
137
+ ] ;
138
+
139
+ # INFO: preferredPharmacy for prescription routing
140
+ sh:property [
141
+ sh:path cascade:preferredPharmacy ;
142
+ sh:class cascade:PharmacyInfo ;
143
+ sh:maxCount 1 ;
144
+ sh:severity sh:Info ;
145
+ sh:name "Preferred Pharmacy"@en ;
146
+ sh:message "A preferred pharmacy helps streamline prescription fulfillment"@en
147
+ ] ;
148
+
149
+ # INFO: advanceDirectives for care planning
150
+ sh:property [
151
+ sh:path cascade:advanceDirectives ;
152
+ sh:class cascade:AdvanceDirectives ;
153
+ sh:maxCount 1 ;
154
+ sh:severity sh:Info ;
155
+ sh:name "Advance Directives"@en ;
156
+ sh:message "Advance directives document patient wishes for end-of-life care"@en
157
+ ] ;
158
+
159
+ # INFO: profileId for traceability
160
+ sh:property [
161
+ sh:path cascade:profileId ;
162
+ sh:datatype xsd:string ;
163
+ sh:maxCount 1 ;
164
+ sh:severity sh:Info ;
165
+ sh:name "Profile ID"@en ;
166
+ sh:message "A profile ID (UUID) enables traceability and deduplication"@en
167
+ ] .
168
+
169
+ # ============================================================================
170
+ # Shape: Address
171
+ # ============================================================================
172
+
173
+ cascade:AddressShape a sh:NodeShape ;
174
+ sh:targetClass cascade:Address ;
175
+ rdfs:label "Address Shape"@en ;
176
+ rdfs:comment "Validation constraints for structured postal addresses. Accepts both simplified aliases (city, state) and FHIR-aligned properties (addressCity, addressState)."@en ;
177
+
178
+ # WARNING: city or addressCity recommended for location identification
179
+ sh:property [
180
+ sh:path cascade:city ;
181
+ sh:datatype xsd:string ;
182
+ sh:maxCount 1 ;
183
+ sh:severity sh:Warning ;
184
+ sh:name "City"@en ;
185
+ sh:message "City is recommended for meaningful address identification"@en
186
+ ] ;
187
+
188
+ sh:property [
189
+ sh:path cascade:addressCity ;
190
+ sh:datatype xsd:string ;
191
+ sh:maxCount 1 ;
192
+ sh:severity sh:Warning ;
193
+ sh:name "Address City (FHIR-aligned)"@en ;
194
+ sh:message "City (FHIR-aligned) is recommended for meaningful address identification"@en
195
+ ] ;
196
+
197
+ # WARNING: state or addressState recommended for location identification
198
+ sh:property [
199
+ sh:path cascade:state ;
200
+ sh:datatype xsd:string ;
201
+ sh:maxCount 1 ;
202
+ sh:severity sh:Warning ;
203
+ sh:name "State"@en ;
204
+ sh:message "State is recommended for meaningful address identification"@en
205
+ ] ;
206
+
207
+ sh:property [
208
+ sh:path cascade:addressState ;
209
+ sh:datatype xsd:string ;
210
+ sh:maxCount 1 ;
211
+ sh:severity sh:Warning ;
212
+ sh:name "Address State (FHIR-aligned)"@en ;
213
+ sh:message "State (FHIR-aligned) is recommended for meaningful address identification"@en
214
+ ] ;
215
+
216
+ # INFO: streetAddress or addressLine
217
+ sh:property [
218
+ sh:path cascade:streetAddress ;
219
+ sh:datatype xsd:string ;
220
+ sh:maxCount 1 ;
221
+ sh:severity sh:Info ;
222
+ sh:name "Street Address"@en ;
223
+ sh:message "Street address provides complete location details"@en
224
+ ] ;
225
+
226
+ sh:property [
227
+ sh:path cascade:addressLine ;
228
+ sh:datatype xsd:string ;
229
+ sh:severity sh:Info ;
230
+ sh:name "Address Line (FHIR-aligned)"@en ;
231
+ sh:message "Address line (FHIR-aligned) provides complete location details"@en
232
+ ] ;
233
+
234
+ # INFO: postalCode or addressPostalCode
235
+ sh:property [
236
+ sh:path cascade:postalCode ;
237
+ sh:datatype xsd:string ;
238
+ sh:maxCount 1 ;
239
+ sh:severity sh:Info ;
240
+ sh:name "Postal Code"@en ;
241
+ sh:message "Postal code helps with geographic identification"@en
242
+ ] ;
243
+
244
+ sh:property [
245
+ sh:path cascade:addressPostalCode ;
246
+ sh:datatype xsd:string ;
247
+ sh:maxCount 1 ;
248
+ sh:severity sh:Info ;
249
+ sh:name "Address Postal Code (FHIR-aligned)"@en ;
250
+ sh:message "Postal code (FHIR-aligned) helps with geographic identification"@en
251
+ ] ;
252
+
253
+ # INFO: country or addressCountry
254
+ sh:property [
255
+ sh:path cascade:country ;
256
+ sh:datatype xsd:string ;
257
+ sh:maxCount 1 ;
258
+ sh:severity sh:Info ;
259
+ sh:name "Country"@en ;
260
+ sh:message "Country is helpful for international patients"@en
261
+ ] ;
262
+
263
+ sh:property [
264
+ sh:path cascade:addressCountry ;
265
+ sh:datatype xsd:string ;
266
+ sh:maxCount 1 ;
267
+ sh:severity sh:Info ;
268
+ sh:name "Address Country (FHIR-aligned)"@en ;
269
+ sh:message "Country (FHIR-aligned) is helpful for international patients"@en
270
+ ] ;
271
+
272
+ # INFO: addressUse for address purpose
273
+ sh:property [
274
+ sh:path cascade:addressUse ;
275
+ sh:datatype xsd:string ;
276
+ sh:maxCount 1 ;
277
+ sh:in ( "home" "work" "temp" "old" ) ;
278
+ sh:severity sh:Info ;
279
+ sh:name "Address Use"@en ;
280
+ sh:message "Address use should be home, work, temp, or old"@en
281
+ ] ;
282
+
283
+ # INFO: addressType for address classification
284
+ sh:property [
285
+ sh:path cascade:addressType ;
286
+ sh:datatype xsd:string ;
287
+ sh:maxCount 1 ;
288
+ sh:in ( "postal" "physical" "both" ) ;
289
+ sh:severity sh:Info ;
290
+ sh:name "Address Type"@en ;
291
+ sh:message "Address type should be postal, physical, or both"@en
292
+ ] .
293
+
294
+ # ============================================================================
295
+ # Shape: Emergency Contact
296
+ # ============================================================================
297
+
298
+ cascade:EmergencyContactShape a sh:NodeShape ;
299
+ sh:targetClass cascade:EmergencyContact ;
300
+ rdfs:label "Emergency Contact Shape"@en ;
301
+ rdfs:comment "Validation constraints for patient emergency contact persons"@en ;
302
+
303
+ # VIOLATION: contactName required
304
+ sh:property [
305
+ sh:path cascade:contactName ;
306
+ sh:datatype xsd:string ;
307
+ sh:minCount 1 ;
308
+ sh:maxCount 1 ;
309
+ sh:minLength 1 ;
310
+ sh:severity sh:Violation ;
311
+ sh:name "Contact Name"@en ;
312
+ sh:message "Emergency contact must have a name"@en
313
+ ] ;
314
+
315
+ # VIOLATION: contactPhone required
316
+ sh:property [
317
+ sh:path cascade:contactPhone ;
318
+ sh:datatype xsd:string ;
319
+ sh:minCount 1 ;
320
+ sh:maxCount 1 ;
321
+ sh:minLength 1 ;
322
+ sh:severity sh:Violation ;
323
+ sh:name "Contact Phone"@en ;
324
+ sh:message "Emergency contact must have a phone number"@en
325
+ ] ;
326
+
327
+ # WARNING: contactRelationship recommended
328
+ sh:property [
329
+ sh:path cascade:contactRelationship ;
330
+ sh:datatype xsd:string ;
331
+ sh:maxCount 1 ;
332
+ sh:in ( "spouse" "parent" "child" "sibling" "partner" "friend" "caregiver" "other" ) ;
333
+ sh:severity sh:Warning ;
334
+ sh:name "Contact Relationship"@en ;
335
+ sh:message "Emergency contact relationship is recommended (spouse, parent, child, sibling, partner, friend, caregiver, other)"@en
336
+ ] .
337
+
338
+ # ============================================================================
339
+ # Shape: Pharmacy Info
340
+ # ============================================================================
341
+
342
+ cascade:PharmacyInfoShape a sh:NodeShape ;
343
+ sh:targetClass cascade:PharmacyInfo ;
344
+ rdfs:label "Pharmacy Info Shape"@en ;
345
+ rdfs:comment "Validation constraints for preferred pharmacy information"@en ;
346
+
347
+ # VIOLATION: pharmacyName required
348
+ sh:property [
349
+ sh:path cascade:pharmacyName ;
350
+ sh:datatype xsd:string ;
351
+ sh:minCount 1 ;
352
+ sh:maxCount 1 ;
353
+ sh:minLength 1 ;
354
+ sh:severity sh:Violation ;
355
+ sh:name "Pharmacy Name"@en ;
356
+ sh:message "Pharmacy must have a name"@en
357
+ ] ;
358
+
359
+ # INFO: pharmacyAddress for location
360
+ sh:property [
361
+ sh:path cascade:pharmacyAddress ;
362
+ sh:datatype xsd:string ;
363
+ sh:maxCount 1 ;
364
+ sh:severity sh:Info ;
365
+ sh:name "Pharmacy Address"@en ;
366
+ sh:message "Pharmacy address helps identify the correct location"@en
367
+ ] ;
368
+
369
+ # INFO: pharmacyPhone for contact
370
+ sh:property [
371
+ sh:path cascade:pharmacyPhone ;
372
+ sh:datatype xsd:string ;
373
+ sh:maxCount 1 ;
374
+ sh:severity sh:Info ;
375
+ sh:name "Pharmacy Phone"@en ;
376
+ sh:message "Pharmacy phone number is helpful for prescription coordination"@en
377
+ ] .
378
+
379
+ # ============================================================================
380
+ # Shape: Advance Directives
381
+ # ============================================================================
382
+
383
+ cascade:AdvanceDirectivesShape a sh:NodeShape ;
384
+ sh:targetClass cascade:AdvanceDirectives ;
385
+ rdfs:label "Advance Directives Shape"@en ;
386
+ rdfs:comment "Validation constraints for patient advance directive declarations. Elevated PHI sensitivity."@en ;
387
+
388
+ # VIOLATION: hasLivingWill required
389
+ sh:property [
390
+ sh:path cascade:hasLivingWill ;
391
+ sh:datatype xsd:boolean ;
392
+ sh:minCount 1 ;
393
+ sh:maxCount 1 ;
394
+ sh:severity sh:Violation ;
395
+ sh:name "Has Living Will"@en ;
396
+ sh:message "Advance directives must declare whether a living will is on file"@en
397
+ ] ;
398
+
399
+ # VIOLATION: hasPowerOfAttorney required
400
+ sh:property [
401
+ sh:path cascade:hasPowerOfAttorney ;
402
+ sh:datatype xsd:boolean ;
403
+ sh:minCount 1 ;
404
+ sh:maxCount 1 ;
405
+ sh:severity sh:Violation ;
406
+ sh:name "Has Power of Attorney"@en ;
407
+ sh:message "Advance directives must declare whether a healthcare power of attorney is on file"@en
408
+ ] ;
409
+
410
+ # VIOLATION: hasDNR required
411
+ sh:property [
412
+ sh:path cascade:hasDNR ;
413
+ sh:datatype xsd:boolean ;
414
+ sh:minCount 1 ;
415
+ sh:maxCount 1 ;
416
+ sh:severity sh:Violation ;
417
+ sh:name "Has DNR"@en ;
418
+ sh:message "Advance directives must declare whether a do-not-resuscitate order is on file"@en
419
+ ] ;
420
+
421
+ # INFO: advanceDirectiveNotes for additional context
422
+ sh:property [
423
+ sh:path cascade:advanceDirectiveNotes ;
424
+ sh:datatype xsd:string ;
425
+ sh:maxCount 1 ;
426
+ sh:severity sh:Info ;
427
+ sh:name "Advance Directive Notes"@en ;
428
+ sh:message "Notes can provide additional context about advance directive wishes"@en
429
+ ] .
430
+
431
+ # ============================================================================
432
+ # Changelog
433
+ # ============================================================================
434
+ #
435
+ # Version 1.0 (2026-02-18)
436
+ # - Initial release of core vocabulary SHACL shapes (Phase 4)
437
+ # - PatientProfileShape: VIOLATION for dateOfBirth, biologicalSex,
438
+ # dataProvenance; WARNING for genderIdentity, emergencyContact;
439
+ # INFO for ageGroup, computedAge, maritalStatus, raceEthnicity,
440
+ # address, preferredPharmacy, advanceDirectives, profileId
441
+ # - AddressShape: WARNING for city/addressCity, state/addressState;
442
+ # INFO for streetAddress/addressLine, postalCode/addressPostalCode,
443
+ # country/addressCountry, addressUse, addressType
444
+ # - EmergencyContactShape: VIOLATION for contactName, contactPhone;
445
+ # WARNING for contactRelationship
446
+ # - PharmacyInfoShape: VIOLATION for pharmacyName;
447
+ # INFO for pharmacyAddress, pharmacyPhone
448
+ # - AdvanceDirectivesShape: VIOLATION for hasLivingWill,
449
+ # hasPowerOfAttorney, hasDNR; INFO for advanceDirectiveNotes
450
+ #