eyeling 1.13.2 → 1.13.4
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.
- package/HANDBOOK.md +2 -0
- package/examples/allen-interval-calculus.n3 +180 -0
- package/examples/deck/odrl-dpv-risk-ranked.md +251 -0
- package/examples/dining-philosophers.n3 +383 -0
- package/examples/input/annotation.ttl +3 -1
- package/examples/input/reifies.ttl +2 -0
- package/examples/input/triple-term.ttl +3 -2
- package/examples/kaprekar.n3 +205 -0
- package/examples/odrl-dpv-ehds-risk-ranked.n3 +473 -0
- package/examples/odrl-dpv-healthcare-risk-ranked.n3 +575 -0
- package/examples/odrl-dpv-risk-ranked.n3 +30 -31
- package/examples/output/allen-interval-calculus.n3 +157 -0
- package/examples/output/dining-philosophers.n3 +808 -0
- package/examples/output/kaprekar.n3 +9992 -0
- package/examples/output/odrl-dpv-ehds-risk-ranked.n3 +144 -0
- package/examples/output/odrl-dpv-healthcare-risk-ranked.n3 +117 -0
- package/examples/output/odrl-dpv-risk-ranked.n3 +70 -6
- package/examples/output/wind-turbine.n3 +6 -0
- package/examples/reifies.n3 +1 -2
- package/examples/triple-term.n3 +3 -3
- package/examples/wind-turbine.n3 +63 -0
- package/eyeling.js +7 -2
- package/lib/cli.js +4 -1
- package/lib/engine.js +3 -1
- package/package.json +1 -1
- package/test/api.test.js +11 -0
- package/tools/n3gen.js +36 -7
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
# ========================================================================================
|
|
2
|
+
# ODRL + DPV risk assessment (Healthcare & Life Sciences) with ranked, explainable output.
|
|
3
|
+
#
|
|
4
|
+
# What this file demonstrates
|
|
5
|
+
# - Models a healthcare / life-sciences data use agreement as an ODRL policy (odrl:Policy)
|
|
6
|
+
# containing permissions, duties, constraints, and clause references.
|
|
7
|
+
# - Captures a patient’s expectations (needs/preferences) as a lightweight profile.
|
|
8
|
+
# - Uses N3 rules with log:includes / log:notIncludes to detect missing safeguards, e.g.:
|
|
9
|
+
# * secondary research use without explicit opt‑in consent
|
|
10
|
+
# * external genomic data sharing without de-identification/pseudonymisation
|
|
11
|
+
# * automated triage without human review/override (human‑in‑the‑loop)
|
|
12
|
+
# * retention exceeding the patient’s preferred limit
|
|
13
|
+
# - Generates DPV risks (dpv:Risk) and classifies them using DPV‑RISK concepts.
|
|
14
|
+
# - Proposes mitigations as dpv:RiskMitigationMeasure resources and links them to risks
|
|
15
|
+
# via dpv:isMitigatedByMeasure.
|
|
16
|
+
# - Computes a numeric score per risk and prints a ranked report where each risk is
|
|
17
|
+
# followed by its mitigation(s).
|
|
18
|
+
#
|
|
19
|
+
# How to run (Eyeling)
|
|
20
|
+
# - Deterministic ranked printing of log:outputString requires “strings mode”:
|
|
21
|
+
# eyeling -r odrl-dpv-healthcare-risk-ranked.n3
|
|
22
|
+
#
|
|
23
|
+
# How ranking works
|
|
24
|
+
# - Output lines are emitted as log:outputString triples.
|
|
25
|
+
# - With -r, Eyeling prints these strings in key order.
|
|
26
|
+
# - The key encodes an inverse score (1000 - score) so higher scores appear first.
|
|
27
|
+
# - Mitigation lines use a key that sorts immediately after their corresponding risk.
|
|
28
|
+
#
|
|
29
|
+
# Structure
|
|
30
|
+
# 1) Parties, data assets, and a processing context (dpv:Process)
|
|
31
|
+
# 2) Patient profile (needs/preferences)
|
|
32
|
+
# 3) Agreement with ODRL policy clauses (intentionally includes gaps)
|
|
33
|
+
# 4) Risk rules + mitigations (ODRL -> DPV/DPV‑RISK)
|
|
34
|
+
# 5) Score normalisation -> risk level/severity
|
|
35
|
+
# 6) Ranked report output (risks + mitigations)
|
|
36
|
+
#
|
|
37
|
+
# Disclaimer
|
|
38
|
+
# - This is an illustrative example, not legal advice or a compliance checklist.
|
|
39
|
+
#
|
|
40
|
+
# References
|
|
41
|
+
# - Eyeling handbook: https://eyereasoner.github.io/eyeling/HANDBOOK
|
|
42
|
+
# - ODRL vocab: https://www.w3.org/TR/odrl-vocab/
|
|
43
|
+
# - DPV core: https://w3id.org/dpv
|
|
44
|
+
# - DPV-PD: https://w3id.org/dpv/pd
|
|
45
|
+
# - DPV-RISK: https://w3id.org/dpv/risk
|
|
46
|
+
# ========================================================================================
|
|
47
|
+
|
|
48
|
+
@prefix : <https://example.org/odrl-dpv-healthcare-risk-ranked#> .
|
|
49
|
+
@prefix dct: <http://purl.org/dc/terms/> .
|
|
50
|
+
@prefix dpv: <https://w3id.org/dpv#> .
|
|
51
|
+
@prefix pd: <https://w3id.org/dpv/pd#> .
|
|
52
|
+
@prefix risk: <https://w3id.org/dpv/risk#> .
|
|
53
|
+
@prefix odrl: <http://www.w3.org/ns/odrl/2/> .
|
|
54
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#> .
|
|
55
|
+
@prefix math: <http://www.w3.org/2000/10/swap/math#> .
|
|
56
|
+
@prefix string:<http://www.w3.org/2000/10/swap/string#> .
|
|
57
|
+
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
|
|
58
|
+
@prefix duo: <http://purl.obolibrary.org/obo/DUO_> .
|
|
59
|
+
@prefix hl7ca: <http://terminology.hl7.org/CodeSystem/consentaction#> .
|
|
60
|
+
|
|
61
|
+
# ---------------------------------------------------
|
|
62
|
+
# Domain vocabularies used (healthcare/life-sciences)
|
|
63
|
+
# ---------------------------------------------------
|
|
64
|
+
# - GA4GH Data Use Ontology (DUO): https://obofoundry.org/ontology/duo.html
|
|
65
|
+
# We use DUO codes as values for odrl:purpose constraints (via odrl:rightOperandReference).
|
|
66
|
+
# * duo:0000006 (HMB) health/medical/biomedical research
|
|
67
|
+
# * duo:0000042 (GRU) general research use
|
|
68
|
+
# * duo:0000043 (CC) clinical care use
|
|
69
|
+
#
|
|
70
|
+
# - HL7 Consent Action Codes: http://terminology.hl7.org/CodeSystem/consentaction
|
|
71
|
+
# We mint code IRIs using a fragment (#code) purely for convenience in this example:
|
|
72
|
+
# * hl7ca:use, hl7ca:disclose, hl7ca:collect
|
|
73
|
+
#
|
|
74
|
+
|
|
75
|
+
:PurposeHMB a skos:Concept ;
|
|
76
|
+
skos:prefLabel "DUO HMB: Health/Medical/Biomedical Research" ;
|
|
77
|
+
skos:exactMatch duo:0000006 .
|
|
78
|
+
|
|
79
|
+
:PurposeGRU a skos:Concept ;
|
|
80
|
+
skos:prefLabel "DUO GRU: General Research Use" ;
|
|
81
|
+
skos:exactMatch duo:0000042 .
|
|
82
|
+
|
|
83
|
+
:PurposeCC a skos:Concept ;
|
|
84
|
+
skos:prefLabel "DUO CC: Clinical Care Use" ;
|
|
85
|
+
skos:exactMatch duo:0000043 .
|
|
86
|
+
|
|
87
|
+
# ----------------------------------------------
|
|
88
|
+
# 1) Parties, data assets, and "process context"
|
|
89
|
+
# ----------------------------------------------
|
|
90
|
+
|
|
91
|
+
:Hospital a odrl:Party ; dct:title "Example Hospital" .
|
|
92
|
+
:ResearchUnit a odrl:Party ; dct:title "Hospital Research Unit" .
|
|
93
|
+
:PharmaPartner a odrl:Party ; dct:title "Pharma Partner" .
|
|
94
|
+
:ClinicalAIService a odrl:Party ; dct:title "Clinical AI Service Provider" .
|
|
95
|
+
|
|
96
|
+
:HealthRecordData a pd:HealthRecord ; dct:title "Electronic Health Record (EHR) data" .
|
|
97
|
+
:GenomicData a pd:Genetic ; dct:title "Genomic sequencing data" .
|
|
98
|
+
|
|
99
|
+
:ProcessContextHC1 a dpv:Process ;
|
|
100
|
+
dct:title "Example healthcare processing context" .
|
|
101
|
+
|
|
102
|
+
# --------------------------------------
|
|
103
|
+
# 2) Patient profile (needs/preferences)
|
|
104
|
+
# --------------------------------------
|
|
105
|
+
|
|
106
|
+
:PatientExample a :PatientProfile, odrl:Party ;
|
|
107
|
+
dct:title "Example patient profile" ;
|
|
108
|
+
:hasNeed :Need_ConsentForResearch,
|
|
109
|
+
:Need_DeIdentifyBeforeSharing,
|
|
110
|
+
:Need_HumanReviewForAutomatedTriage,
|
|
111
|
+
:Need_RetentionLimit3y .
|
|
112
|
+
|
|
113
|
+
:Need_ConsentForResearch a :Need ;
|
|
114
|
+
dct:description "Explicit opt-in consent required before secondary use for research/publication." ;
|
|
115
|
+
:importance 35 .
|
|
116
|
+
|
|
117
|
+
:Need_DeIdentifyBeforeSharing a :Need ;
|
|
118
|
+
dct:description "De-identify or pseudonymise health/genetic data before sharing with external partners." ;
|
|
119
|
+
:importance 35 .
|
|
120
|
+
|
|
121
|
+
:Need_HumanReviewForAutomatedTriage a :Need ;
|
|
122
|
+
dct:description "Human review/override required for automated triage decisions." ;
|
|
123
|
+
:importance 25 .
|
|
124
|
+
|
|
125
|
+
:Need_RetentionLimit3y a :Need ;
|
|
126
|
+
dct:description "Retention limited to 3 years unless a specific legal obligation requires longer retention." ;
|
|
127
|
+
:importance 15 ;
|
|
128
|
+
:maxRetentionDays 1095 .
|
|
129
|
+
|
|
130
|
+
# ----------------------------------------------------------------
|
|
131
|
+
# 3) Agreement + ODRL policy clauses (intentionally contains gaps)
|
|
132
|
+
# ----------------------------------------------------------------
|
|
133
|
+
|
|
134
|
+
:ClauseH1 a :Clause ;
|
|
135
|
+
:clauseId "H1" ;
|
|
136
|
+
:text "Hospital may use EHR and genomic data for internal clinical research and publication." .
|
|
137
|
+
|
|
138
|
+
:ClauseH2 a :Clause ;
|
|
139
|
+
:clauseId "H2" ;
|
|
140
|
+
:text "Hospital may share genomic data with pharmaceutical partners for drug discovery and R&D." .
|
|
141
|
+
|
|
142
|
+
:ClauseH3 a :Clause ;
|
|
143
|
+
:clauseId "H3" ;
|
|
144
|
+
:text "Hospital may use automated triage and prioritisation systems using EHR data." .
|
|
145
|
+
|
|
146
|
+
:ClauseH4 a :Clause ;
|
|
147
|
+
:clauseId "H4" ;
|
|
148
|
+
:text "Hospital retains patient health records for 10 years." .
|
|
149
|
+
|
|
150
|
+
:AgreementHC1 a odrl:Agreement ;
|
|
151
|
+
dct:title "Example Healthcare & Life-Sciences Data Use Agreement" ;
|
|
152
|
+
:policyGraph {
|
|
153
|
+
|
|
154
|
+
:PolicyHC1 a odrl:Policy ;
|
|
155
|
+
odrl:permission
|
|
156
|
+
:PermResearchUse,
|
|
157
|
+
:PermShareWithPharma,
|
|
158
|
+
:PermAutomatedTriage,
|
|
159
|
+
:PermRetention10y .
|
|
160
|
+
|
|
161
|
+
# Permission: internal clinical research (NO explicit-consent constraint -> should trigger R1)
|
|
162
|
+
:PermResearchUse a odrl:Permission ;
|
|
163
|
+
odrl:assigner :Hospital ;
|
|
164
|
+
odrl:assignee :ResearchUnit ;
|
|
165
|
+
odrl:action hl7ca:use ;
|
|
166
|
+
odrl:target :HealthRecordData, :GenomicData ;
|
|
167
|
+
odrl:constraint [
|
|
168
|
+
a odrl:Constraint ;
|
|
169
|
+
odrl:leftOperand odrl:purpose ;
|
|
170
|
+
odrl:operator odrl:eq ;
|
|
171
|
+
odrl:rightOperandReference :PurposeHMB
|
|
172
|
+
] ;
|
|
173
|
+
|
|
174
|
+
:clause :ClauseH1 .
|
|
175
|
+
|
|
176
|
+
# Permission: share genomic data with pharma (NO de-identification constraint -> should trigger R2)
|
|
177
|
+
:PermShareWithPharma a odrl:Permission ;
|
|
178
|
+
odrl:assigner :Hospital ;
|
|
179
|
+
odrl:assignee :PharmaPartner ;
|
|
180
|
+
odrl:action hl7ca:disclose ;
|
|
181
|
+
odrl:target :GenomicData ;
|
|
182
|
+
odrl:constraint [
|
|
183
|
+
a odrl:Constraint ;
|
|
184
|
+
odrl:leftOperand odrl:purpose ;
|
|
185
|
+
odrl:operator odrl:eq ;
|
|
186
|
+
odrl:rightOperandReference :PurposeHMB
|
|
187
|
+
] ;
|
|
188
|
+
|
|
189
|
+
:clause :ClauseH2 .
|
|
190
|
+
|
|
191
|
+
# Permission: automated triage (NO human-review duty -> should trigger R3)
|
|
192
|
+
:PermAutomatedTriage a odrl:Permission ;
|
|
193
|
+
odrl:assigner :Hospital ;
|
|
194
|
+
odrl:assignee :ClinicalAIService ;
|
|
195
|
+
odrl:action hl7ca:use ;
|
|
196
|
+
odrl:target :HealthRecordData ;
|
|
197
|
+
odrl:constraint [
|
|
198
|
+
a odrl:Constraint ;
|
|
199
|
+
odrl:leftOperand odrl:purpose ;
|
|
200
|
+
odrl:operator odrl:eq ;
|
|
201
|
+
odrl:rightOperandReference :PurposeCC
|
|
202
|
+
] ;
|
|
203
|
+
|
|
204
|
+
:clause :ClauseH3 ;
|
|
205
|
+
odrl:duty [
|
|
206
|
+
a odrl:Duty ;
|
|
207
|
+
odrl:action :humanReview ;
|
|
208
|
+
odrl:constraint [
|
|
209
|
+
a odrl:Constraint ;
|
|
210
|
+
odrl:leftOperand :encryptionAtRest ;
|
|
211
|
+
odrl:operator odrl:eq ;
|
|
212
|
+
odrl:rightOperand true
|
|
213
|
+
]
|
|
214
|
+
] .
|
|
215
|
+
|
|
216
|
+
# Permission: retain for 10 years (should trigger R4 vs patient max 3 years)
|
|
217
|
+
:PermRetention10y a odrl:Permission ;
|
|
218
|
+
odrl:assigner :Hospital ;
|
|
219
|
+
odrl:assignee :Hospital ;
|
|
220
|
+
odrl:action hl7ca:collect ;
|
|
221
|
+
odrl:target :HealthRecordData ;
|
|
222
|
+
odrl:constraint [
|
|
223
|
+
a odrl:Constraint ;
|
|
224
|
+
odrl:leftOperand odrl:purpose ;
|
|
225
|
+
odrl:operator odrl:eq ;
|
|
226
|
+
odrl:rightOperandReference :PurposeCC
|
|
227
|
+
] ;
|
|
228
|
+
|
|
229
|
+
:clause :ClauseH4 ;
|
|
230
|
+
odrl:constraint [
|
|
231
|
+
a odrl:Constraint ;
|
|
232
|
+
odrl:leftOperand :retentionDays ;
|
|
233
|
+
odrl:operator odrl:eq ;
|
|
234
|
+
odrl:rightOperand 3650
|
|
235
|
+
] .
|
|
236
|
+
} .
|
|
237
|
+
|
|
238
|
+
# -----------------------------------------------------------------
|
|
239
|
+
# 4) Risk detection rules + mitigation suggestions (DPV + DPV-RISK)
|
|
240
|
+
# -----------------------------------------------------------------
|
|
241
|
+
|
|
242
|
+
# R1: Secondary research use WITHOUT explicit consent constraint
|
|
243
|
+
{
|
|
244
|
+
:AgreementHC1 :policyGraph ?G .
|
|
245
|
+
:PatientExample :hasNeed :Need_ConsentForResearch .
|
|
246
|
+
:Need_ConsentForResearch :importance ?w .
|
|
247
|
+
|
|
248
|
+
?G log:includes {
|
|
249
|
+
:PermResearchUse a odrl:Permission ;
|
|
250
|
+
:clause ?clause .
|
|
251
|
+
}.
|
|
252
|
+
|
|
253
|
+
?G log:notIncludes {
|
|
254
|
+
:PermResearchUse odrl:constraint [
|
|
255
|
+
a odrl:Constraint ;
|
|
256
|
+
odrl:leftOperand :explicitConsent ;
|
|
257
|
+
odrl:operator odrl:eq ;
|
|
258
|
+
odrl:rightOperand true
|
|
259
|
+
] .
|
|
260
|
+
}.
|
|
261
|
+
|
|
262
|
+
?clause :clauseId ?cid ; :text ?txt .
|
|
263
|
+
|
|
264
|
+
(85 ?w) math:sum ?raw .
|
|
265
|
+
( :AgreementHC1 :PatientExample :ResearchNoConsent ?cid ) log:skolem ?risk .
|
|
266
|
+
( :AgreementHC1 :PatientExample :ResearchNoConsentSource ?cid ) log:skolem ?src .
|
|
267
|
+
( ?risk :M1 ) log:skolem ?m1 .
|
|
268
|
+
|
|
269
|
+
( "Risk: health/genomic data may be used for research without explicit opt-in consent. Clause %s: %s"
|
|
270
|
+
?cid ?txt ) string:format ?why .
|
|
271
|
+
}
|
|
272
|
+
=>
|
|
273
|
+
{
|
|
274
|
+
?src a risk:RiskSource, risk:LegalComplianceRisk ;
|
|
275
|
+
dct:source :PermResearchUse ;
|
|
276
|
+
dct:description "Research use permitted without explicit consent constraint." .
|
|
277
|
+
|
|
278
|
+
?risk a dpv:Risk, risk:PolicyRisk, risk:CustomerConfidenceLoss ;
|
|
279
|
+
dct:source :PermResearchUse ;
|
|
280
|
+
risk:hasRiskSource ?src ;
|
|
281
|
+
dpv:hasConsequence risk:CustomerConfidenceLoss ;
|
|
282
|
+
dpv:hasImpact risk:NonMaterialDamage, risk:FinancialLoss ;
|
|
283
|
+
:aboutClause ?clause ;
|
|
284
|
+
:scoreRaw ?raw ;
|
|
285
|
+
:violatesNeed :Need_ConsentForResearch ;
|
|
286
|
+
dct:description ?why .
|
|
287
|
+
|
|
288
|
+
:ProcessContextHC1 dpv:hasRisk ?risk .
|
|
289
|
+
|
|
290
|
+
?m1 a dpv:RiskMitigationMeasure ;
|
|
291
|
+
dct:description "Add an explicit consent constraint for secondary research use." ;
|
|
292
|
+
dpv:mitigatesRisk ?risk ;
|
|
293
|
+
:suggestAdd {
|
|
294
|
+
:PermResearchUse odrl:constraint [
|
|
295
|
+
a odrl:Constraint ;
|
|
296
|
+
odrl:leftOperand :explicitConsent ;
|
|
297
|
+
odrl:operator odrl:eq ;
|
|
298
|
+
odrl:rightOperand true
|
|
299
|
+
] .
|
|
300
|
+
} .
|
|
301
|
+
|
|
302
|
+
?risk dpv:isMitigatedByMeasure ?m1 .
|
|
303
|
+
} .
|
|
304
|
+
|
|
305
|
+
# R2: Sharing genomic data WITHOUT de-identification/pseudonymisation requirement
|
|
306
|
+
{
|
|
307
|
+
:AgreementHC1 :policyGraph ?G .
|
|
308
|
+
:PatientExample :hasNeed :Need_DeIdentifyBeforeSharing .
|
|
309
|
+
:Need_DeIdentifyBeforeSharing :importance ?w .
|
|
310
|
+
|
|
311
|
+
?G log:includes {
|
|
312
|
+
:PermShareWithPharma a odrl:Permission ;
|
|
313
|
+
:clause ?clause .
|
|
314
|
+
}.
|
|
315
|
+
|
|
316
|
+
?G log:notIncludes {
|
|
317
|
+
:PermShareWithPharma odrl:constraint [
|
|
318
|
+
a odrl:Constraint ;
|
|
319
|
+
odrl:leftOperand :deIdentified ;
|
|
320
|
+
odrl:operator odrl:eq ;
|
|
321
|
+
odrl:rightOperand true
|
|
322
|
+
] .
|
|
323
|
+
}.
|
|
324
|
+
|
|
325
|
+
?clause :clauseId ?cid ; :text ?txt .
|
|
326
|
+
|
|
327
|
+
(90 ?w) math:sum ?raw .
|
|
328
|
+
( :AgreementHC1 :PatientExample :ShareNoDeId ?cid ) log:skolem ?risk .
|
|
329
|
+
( :AgreementHC1 :PatientExample :ShareNoDeIdSource ?cid ) log:skolem ?src .
|
|
330
|
+
( ?risk :M1 ) log:skolem ?m1 .
|
|
331
|
+
|
|
332
|
+
( "Risk: genomic data may be shared with external pharma partners without a de-identification/pseudonymisation requirement. Clause %s: %s"
|
|
333
|
+
?cid ?txt ) string:format ?why .
|
|
334
|
+
}
|
|
335
|
+
=>
|
|
336
|
+
{
|
|
337
|
+
?src a risk:RiskSource, risk:LegalComplianceRisk ;
|
|
338
|
+
dct:source :PermShareWithPharma ;
|
|
339
|
+
dct:description "External sharing permitted without de-identification/pseudonymisation requirement." .
|
|
340
|
+
|
|
341
|
+
?risk a dpv:Risk, risk:UnwantedDisclosureData, risk:ReputationalRisk ;
|
|
342
|
+
dct:source :PermShareWithPharma ;
|
|
343
|
+
risk:hasRiskSource ?src ;
|
|
344
|
+
dpv:hasConsequence risk:CustomerConfidenceLoss ;
|
|
345
|
+
dpv:hasImpact risk:NonMaterialDamage, risk:FinancialLoss, risk:Discrimination ;
|
|
346
|
+
:aboutClause ?clause ;
|
|
347
|
+
:scoreRaw ?raw ;
|
|
348
|
+
:violatesNeed :Need_DeIdentifyBeforeSharing ;
|
|
349
|
+
dct:description ?why .
|
|
350
|
+
|
|
351
|
+
:ProcessContextHC1 dpv:hasRisk ?risk .
|
|
352
|
+
|
|
353
|
+
?m1 a dpv:RiskMitigationMeasure ;
|
|
354
|
+
dct:description "Require de-identification/pseudonymisation before external sharing of genomic data." ;
|
|
355
|
+
dpv:mitigatesRisk ?risk ;
|
|
356
|
+
:suggestAdd {
|
|
357
|
+
:PermShareWithPharma odrl:constraint [
|
|
358
|
+
a odrl:Constraint ;
|
|
359
|
+
odrl:leftOperand :deIdentified ;
|
|
360
|
+
odrl:operator odrl:eq ;
|
|
361
|
+
odrl:rightOperand true
|
|
362
|
+
] ;
|
|
363
|
+
odrl:duty [
|
|
364
|
+
a odrl:Duty ;
|
|
365
|
+
odrl:action :deIdentify ;
|
|
366
|
+
odrl:constraint [
|
|
367
|
+
a odrl:Constraint ;
|
|
368
|
+
odrl:leftOperand :deIdentificationStandard ;
|
|
369
|
+
odrl:operator odrl:eq ;
|
|
370
|
+
odrl:rightOperand :StateOfTheArt
|
|
371
|
+
]
|
|
372
|
+
] .
|
|
373
|
+
} .
|
|
374
|
+
|
|
375
|
+
?risk dpv:isMitigatedByMeasure ?m1 .
|
|
376
|
+
} .
|
|
377
|
+
|
|
378
|
+
# R3: Automated triage WITHOUT human review/override duty
|
|
379
|
+
{
|
|
380
|
+
:AgreementHC1 :policyGraph ?G .
|
|
381
|
+
:PatientExample :hasNeed :Need_HumanReviewForAutomatedTriage .
|
|
382
|
+
:Need_HumanReviewForAutomatedTriage :importance ?w .
|
|
383
|
+
|
|
384
|
+
?G log:includes {
|
|
385
|
+
:PermAutomatedTriage a odrl:Permission ;
|
|
386
|
+
:clause ?clause .
|
|
387
|
+
}.
|
|
388
|
+
|
|
389
|
+
?G log:notIncludes {
|
|
390
|
+
:PermAutomatedTriage odrl:duty [
|
|
391
|
+
a odrl:Duty ;
|
|
392
|
+
odrl:action :humanReview
|
|
393
|
+
] .
|
|
394
|
+
}.
|
|
395
|
+
|
|
396
|
+
?clause :clauseId ?cid ; :text ?txt .
|
|
397
|
+
|
|
398
|
+
(80 ?w) math:sum ?raw .
|
|
399
|
+
( :AgreementHC1 :PatientExample :AutoTriageNoHuman ?cid ) log:skolem ?risk .
|
|
400
|
+
( :AgreementHC1 :PatientExample :AutoTriageNoHumanSource ?cid ) log:skolem ?src .
|
|
401
|
+
( ?risk :M1 ) log:skolem ?m1 .
|
|
402
|
+
|
|
403
|
+
( "Risk: automated triage may affect care pathways without a human review/override safeguard. Clause %s: %s"
|
|
404
|
+
?cid ?txt ) string:format ?why .
|
|
405
|
+
}
|
|
406
|
+
=>
|
|
407
|
+
{
|
|
408
|
+
?src a risk:RiskSource, risk:PolicyRisk ;
|
|
409
|
+
dct:source :PermAutomatedTriage ;
|
|
410
|
+
dct:description "Automated triage permitted without a human review/override duty." .
|
|
411
|
+
|
|
412
|
+
?risk a dpv:Risk, risk:QualityRisk, risk:InabilityToProvideHealthCare ;
|
|
413
|
+
dct:source :PermAutomatedTriage ;
|
|
414
|
+
risk:hasRiskSource ?src ;
|
|
415
|
+
dpv:hasConsequence risk:InabilityToProvideHealthCare ;
|
|
416
|
+
dpv:hasImpact risk:PhysicalHarm, risk:NonMaterialDamage ;
|
|
417
|
+
:aboutClause ?clause ;
|
|
418
|
+
:scoreRaw ?raw ;
|
|
419
|
+
:violatesNeed :Need_HumanReviewForAutomatedTriage ;
|
|
420
|
+
dct:description ?why .
|
|
421
|
+
|
|
422
|
+
:ProcessContextHC1 dpv:hasRisk ?risk .
|
|
423
|
+
|
|
424
|
+
?m1 a dpv:RiskMitigationMeasure ;
|
|
425
|
+
dct:description "Add a duty requiring human review/override for triage decisions (human-in-the-loop)." ;
|
|
426
|
+
dpv:mitigatesRisk ?risk ;
|
|
427
|
+
:suggestAdd {
|
|
428
|
+
:PermAutomatedTriage odrl:duty [
|
|
429
|
+
a odrl:Duty ;
|
|
430
|
+
odrl:action :humanReview ;
|
|
431
|
+
odrl:constraint [
|
|
432
|
+
a odrl:Constraint ;
|
|
433
|
+
odrl:leftOperand :reviewBeforeDecision ;
|
|
434
|
+
odrl:operator odrl:eq ;
|
|
435
|
+
odrl:rightOperand true
|
|
436
|
+
]
|
|
437
|
+
] .
|
|
438
|
+
} .
|
|
439
|
+
|
|
440
|
+
?risk dpv:isMitigatedByMeasure ?m1 .
|
|
441
|
+
} .
|
|
442
|
+
|
|
443
|
+
# R4: Retention exceeds patient max (3 years)
|
|
444
|
+
{
|
|
445
|
+
:AgreementHC1 :policyGraph ?G .
|
|
446
|
+
:PatientExample :hasNeed :Need_RetentionLimit3y .
|
|
447
|
+
:Need_RetentionLimit3y :importance ?w ; :maxRetentionDays ?max .
|
|
448
|
+
|
|
449
|
+
?G log:includes {
|
|
450
|
+
:PermRetention10y a odrl:Permission ;
|
|
451
|
+
odrl:constraint [
|
|
452
|
+
a odrl:Constraint ;
|
|
453
|
+
odrl:leftOperand :retentionDays ;
|
|
454
|
+
odrl:rightOperand ?days
|
|
455
|
+
] ;
|
|
456
|
+
:clause ?clause .
|
|
457
|
+
}.
|
|
458
|
+
|
|
459
|
+
?days math:greaterThan ?max .
|
|
460
|
+
?clause :clauseId ?cid ; :text ?txt .
|
|
461
|
+
|
|
462
|
+
(55 ?w) math:sum ?raw .
|
|
463
|
+
( :AgreementHC1 :PatientExample :RetentionTooLong ?cid ) log:skolem ?risk .
|
|
464
|
+
( :AgreementHC1 :PatientExample :RetentionTooLongSource ?cid ) log:skolem ?src .
|
|
465
|
+
( ?risk :M1 ) log:skolem ?m1 .
|
|
466
|
+
|
|
467
|
+
( "Risk: retention (%s days) exceeds patient preference (%s days). Clause %s: %s"
|
|
468
|
+
?days ?max ?cid ?txt ) string:format ?why .
|
|
469
|
+
}
|
|
470
|
+
=>
|
|
471
|
+
{
|
|
472
|
+
?src a risk:RiskSource, risk:PolicyRisk ;
|
|
473
|
+
dct:source :PermRetention10y ;
|
|
474
|
+
dct:description "Retention period exceeds patient preference." .
|
|
475
|
+
|
|
476
|
+
?risk a dpv:Risk, risk:PolicyRisk, risk:CustomerConfidenceLoss ;
|
|
477
|
+
dct:source :PermRetention10y ;
|
|
478
|
+
risk:hasRiskSource ?src ;
|
|
479
|
+
dpv:hasConsequence risk:CustomerConfidenceLoss ;
|
|
480
|
+
dpv:hasImpact risk:NonMaterialDamage ;
|
|
481
|
+
:aboutClause ?clause ;
|
|
482
|
+
:scoreRaw ?raw ;
|
|
483
|
+
:violatesNeed :Need_RetentionLimit3y ;
|
|
484
|
+
dct:description ?why .
|
|
485
|
+
|
|
486
|
+
:ProcessContextHC1 dpv:hasRisk ?risk .
|
|
487
|
+
|
|
488
|
+
?m1 a dpv:RiskMitigationMeasure ;
|
|
489
|
+
dct:description "Limit retention to 3 years (or document the legal obligation requiring longer retention)." ;
|
|
490
|
+
dpv:mitigatesRisk ?risk ;
|
|
491
|
+
:suggestAdd {
|
|
492
|
+
:PermRetention10y odrl:constraint [
|
|
493
|
+
a odrl:Constraint ;
|
|
494
|
+
odrl:leftOperand :retentionDays ;
|
|
495
|
+
odrl:operator odrl:lteq ;
|
|
496
|
+
odrl:rightOperand 1095
|
|
497
|
+
] .
|
|
498
|
+
} .
|
|
499
|
+
|
|
500
|
+
?risk dpv:isMitigatedByMeasure ?m1 .
|
|
501
|
+
} .
|
|
502
|
+
|
|
503
|
+
# ------------------------------------------------
|
|
504
|
+
# 5) Score normalization + DPV-RISK severity/level
|
|
505
|
+
# ------------------------------------------------
|
|
506
|
+
|
|
507
|
+
{ ?r a dpv:Risk ; :scoreRaw ?raw . ?raw math:greaterThan 100 . }
|
|
508
|
+
=> { ?r :score 100 . } .
|
|
509
|
+
|
|
510
|
+
{ ?r a dpv:Risk ; :scoreRaw ?raw . 100 math:notLessThan ?raw . }
|
|
511
|
+
=> { ?r :score ?raw . } .
|
|
512
|
+
|
|
513
|
+
{ ?r a dpv:Risk ; :score ?s . ?s math:greaterThan 79 . }
|
|
514
|
+
=> { ?r dpv:hasSeverity risk:HighSeverity ; dpv:hasRiskLevel risk:HighRisk . } .
|
|
515
|
+
|
|
516
|
+
{ ?r a dpv:Risk ; :score ?s . ?s math:lessThan 80 . ?s math:greaterThan 49 . }
|
|
517
|
+
=> { ?r dpv:hasSeverity risk:ModerateSeverity ; dpv:hasRiskLevel risk:ModerateRisk . } .
|
|
518
|
+
|
|
519
|
+
{ ?r a dpv:Risk ; :score ?s . ?s math:lessThan 50 . }
|
|
520
|
+
=> { ?r dpv:hasSeverity risk:LowSeverity ; dpv:hasRiskLevel risk:LowRisk . } .
|
|
521
|
+
|
|
522
|
+
# -------------------------------------------------------------------
|
|
523
|
+
# 6) Ranked explainable output (Eyeling -r prints these in key order)
|
|
524
|
+
# -------------------------------------------------------------------
|
|
525
|
+
|
|
526
|
+
# Header
|
|
527
|
+
{
|
|
528
|
+
:AgreementHC1 dct:title ?alabel .
|
|
529
|
+
:PatientExample dct:title ?plabel .
|
|
530
|
+
( "\n=== Ranked DPV Risk Report (Healthcare & Life Sciences) ===\nAgreement: %s\nProfile: %s\n\n"
|
|
531
|
+
?alabel ?plabel ) string:format ?hdr .
|
|
532
|
+
}
|
|
533
|
+
=>
|
|
534
|
+
{
|
|
535
|
+
( :AgreementHC1 :PatientExample 0 ) log:outputString ?hdr .
|
|
536
|
+
} .
|
|
537
|
+
|
|
538
|
+
# Risk lines (key includes inverse score = 1000 - score)
|
|
539
|
+
{
|
|
540
|
+
?r a dpv:Risk ;
|
|
541
|
+
:score ?score ;
|
|
542
|
+
dpv:hasRiskLevel ?lvl ;
|
|
543
|
+
dpv:hasSeverity ?sev ;
|
|
544
|
+
:aboutClause ?clause ;
|
|
545
|
+
dct:description ?why .
|
|
546
|
+
?clause :clauseId ?cid .
|
|
547
|
+
|
|
548
|
+
( 1000 ?score ) math:difference ?inv .
|
|
549
|
+
|
|
550
|
+
( "score=%s (%s, %s) clause %s\n %s\n\n"
|
|
551
|
+
?score ?lvl ?sev ?cid ?why ) string:format ?line .
|
|
552
|
+
}
|
|
553
|
+
=>
|
|
554
|
+
{
|
|
555
|
+
( :AgreementHC1 :PatientExample 1 ?inv ?cid 0 ?r ) log:outputString ?line .
|
|
556
|
+
} .
|
|
557
|
+
|
|
558
|
+
# Mitigation lines (same ordering as their risk)
|
|
559
|
+
{
|
|
560
|
+
?r a dpv:Risk ;
|
|
561
|
+
:score ?score ;
|
|
562
|
+
dpv:isMitigatedByMeasure ?m ;
|
|
563
|
+
:aboutClause ?clause .
|
|
564
|
+
?clause :clauseId ?cid .
|
|
565
|
+
?m dct:description ?md .
|
|
566
|
+
|
|
567
|
+
( 1000 ?score ) math:difference ?inv .
|
|
568
|
+
|
|
569
|
+
( " - mitigation for clause %s: %s\n"
|
|
570
|
+
?cid ?md ) string:format ?mline .
|
|
571
|
+
}
|
|
572
|
+
=>
|
|
573
|
+
{
|
|
574
|
+
( :AgreementHC1 :PatientExample 1 ?inv ?cid 1 ?r ?m ) log:outputString ?mline .
|
|
575
|
+
} .
|