eyeprolog 1.6.12 → 1.6.13

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 (129) hide show
  1. package/examples/proof/abstract-interpretation.pl +146 -0
  2. package/examples/proof/ackermann.pl +296 -0
  3. package/examples/proof/alignment-demo.pl +196 -0
  4. package/examples/proof/allen-interval-calculus.pl +1271 -0
  5. package/examples/proof/auroracare.pl +954 -0
  6. package/examples/proof/basic-monadic.pl +37176 -0
  7. package/examples/proof/bayes-therapy.pl +1349 -0
  8. package/examples/proof/bench.pl +2802 -0
  9. package/examples/proof/binomial-vandermonde.pl +983 -0
  10. package/examples/proof/blocks-world-planning.pl +471 -0
  11. package/examples/proof/bmi.pl +386 -0
  12. package/examples/proof/braking-safety-worlds.pl +508 -0
  13. package/examples/proof/buck-converter-design.pl +179 -0
  14. package/examples/proof/bulk-stream-write.pl +3 -0
  15. package/examples/proof/collatz-1000.pl +43784 -0
  16. package/examples/proof/competitive-enzyme-kinetics.pl +167 -0
  17. package/examples/proof/complex.pl +514 -0
  18. package/examples/proof/context-schema-audit.pl +374 -0
  19. package/examples/proof/continued-fraction-sqrt2.pl +476 -0
  20. package/examples/proof/control-system.pl +137 -0
  21. package/examples/proof/critical-path-schedule.pl +491 -0
  22. package/examples/proof/cross-organization-data-sharing.pl +732 -0
  23. package/examples/proof/cyclic-path.pl +44 -0
  24. package/examples/proof/dairy-energy-balance.pl +290 -0
  25. package/examples/proof/dcg-expression-language.pl +157 -0
  26. package/examples/proof/deep-taxonomy-10.pl +185 -0
  27. package/examples/proof/deep-taxonomy-100.pl +365 -0
  28. package/examples/proof/deep-taxonomy-1000.pl +163 -0
  29. package/examples/proof/deep-taxonomy-10000.pl +163 -0
  30. package/examples/proof/deep-taxonomy-100000.pl +163 -0
  31. package/examples/proof/delfour.pl +1615 -0
  32. package/examples/proof/dijkstra-findall-sort.pl +354 -0
  33. package/examples/proof/dijkstra-risk-path.pl +820 -0
  34. package/examples/proof/dijkstra.pl +753 -0
  35. package/examples/proof/dining-philosophers.pl +2663 -0
  36. package/examples/proof/donald-gerald-robert.pl +311 -0
  37. package/examples/proof/dpv-odrl-purpose-mapping.pl +1189 -0
  38. package/examples/proof/drone-corridor-planner.pl +2365 -0
  39. package/examples/proof/easter-computus.pl +1406 -0
  40. package/examples/proof/eulerian-path.pl +457 -0
  41. package/examples/proof/ev-range-worlds.pl +508 -0
  42. package/examples/proof/exoplanet-validation-worlds.pl +397 -0
  43. package/examples/proof/explainable-ev-depot-configuration.pl +313 -0
  44. package/examples/proof/family-cousins.pl +920 -0
  45. package/examples/proof/fast-fourier-transform.pl +5045 -0
  46. package/examples/proof/fastpow.pl +769 -0
  47. package/examples/proof/fft8-numeric.pl +685 -0
  48. package/examples/proof/fibonacci.pl +1425 -0
  49. package/examples/proof/field-nitrogen-balance.pl +320 -0
  50. package/examples/proof/flandor.pl +533 -0
  51. package/examples/proof/fundamental-theorem-arithmetic.pl +245 -0
  52. package/examples/proof/gd-step-certified.pl +1717 -0
  53. package/examples/proof/goldbach.pl +1135 -0
  54. package/examples/proof/gps.pl +627 -0
  55. package/examples/proof/graph.pl +105 -0
  56. package/examples/proof/gray-code-counter.pl +355 -0
  57. package/examples/proof/hamiltonian-path.pl +3373 -0
  58. package/examples/proof/hamming-code.pl +232 -0
  59. package/examples/proof/heron-theorem.pl +79 -0
  60. package/examples/proof/http-client.pl +0 -0
  61. package/examples/proof/illegitimate-reasoning.pl +220 -0
  62. package/examples/proof/integer-partitions.pl +1642 -0
  63. package/examples/proof/iso-atomic-conversion.pl +73 -0
  64. package/examples/proof/knowledge-engineering-alignment-flow.pl +200 -0
  65. package/examples/proof/knuth-bendix-completion.pl +290 -0
  66. package/examples/proof/law-of-cosines.pl +71 -0
  67. package/examples/proof/least-squares-regression.pl +342 -0
  68. package/examples/proof/lee.pl +637 -0
  69. package/examples/proof/lldm.pl +581 -0
  70. package/examples/proof/manufacturing-quality-control.pl +181 -0
  71. package/examples/proof/map-four-color-search.pl +796 -0
  72. package/examples/proof/markov-logic-network.pl +405 -0
  73. package/examples/proof/matrix-chain-order.pl +164 -0
  74. package/examples/proof/matrix-noncommutativity.pl +183 -0
  75. package/examples/proof/microgrid-dispatch.pl +164 -0
  76. package/examples/proof/missionaries-cannibals.pl +428 -0
  77. package/examples/proof/modular-exponentiation.pl +838 -0
  78. package/examples/proof/monkey-bananas.pl +278 -0
  79. package/examples/proof/network-sla.pl +100 -0
  80. package/examples/proof/newton-raphson.pl +520 -0
  81. package/examples/proof/observability-log-correlation.pl +1061 -0
  82. package/examples/proof/odrl-dpv-fpv-trust-flow.pl +1366 -0
  83. package/examples/proof/odrl-dpv-healthcare-risk-ranked.pl +488 -0
  84. package/examples/proof/odrl-dpv-risk-ranked.pl +637 -0
  85. package/examples/proof/odrl-policy-advanced.pl +705 -0
  86. package/examples/proof/odrl-policy-reasoning.pl +1423 -0
  87. package/examples/proof/odrl-policy.pl +103 -0
  88. package/examples/proof/operational-incident-response.pl +435 -0
  89. package/examples/proof/orbital-transfer-design.pl +288 -0
  90. package/examples/proof/path-discovery.pl +502 -0
  91. package/examples/proof/peano-arithmetic.pl +910 -0
  92. package/examples/proof/peano-calculus.pl +294 -0
  93. package/examples/proof/pell-equation.pl +295 -0
  94. package/examples/proof/pendulum-period.pl +97 -0
  95. package/examples/proof/pi.pl +3 -0
  96. package/examples/proof/pointer-analysis.pl +94 -0
  97. package/examples/proof/polynomial.pl +2487 -0
  98. package/examples/proof/portable-library-overlap.pl +6 -0
  99. package/examples/proof/quadratic-formula.pl +159 -0
  100. package/examples/proof/quine-mccluskey.pl +914 -0
  101. package/examples/proof/radioactive-decay.pl +104 -0
  102. package/examples/proof/rdf12-annotated-claims.pl +263 -0
  103. package/examples/proof/register-allocation.pl +120 -0
  104. package/examples/proof/relational-cube-lookup.pl +15867 -0
  105. package/examples/proof/riemann-hypothesis.pl +148 -0
  106. package/examples/proof/sat-solver-dpll.pl +226 -0
  107. package/examples/proof/scientific-evidence-graph.pl +681 -0
  108. package/examples/proof/send-more-money.pl +252 -0
  109. package/examples/proof/service-impact.pl +151 -0
  110. package/examples/proof/shoelace-polygon-area.pl +161 -0
  111. package/examples/proof/skolem-functions.pl +128 -0
  112. package/examples/proof/statistics-summary.pl +250 -0
  113. package/examples/proof/stirling-bell-numbers.pl +125 -0
  114. package/examples/proof/superdense-coding.pl +118 -0
  115. package/examples/proof/symbiotic-knowledge-graph.pl +1569 -0
  116. package/examples/proof/truth-maintenance-system.pl +466 -0
  117. package/examples/proof/turing.pl +1183 -0
  118. package/examples/proof/type-inference.pl +267 -0
  119. package/examples/proof/vector-similarity.pl +163 -0
  120. package/examples/proof/vulnerability-impact.pl +180 -0
  121. package/examples/proof/wolf-goat-cabbage.pl +339 -0
  122. package/examples/proof/zebra.pl +176 -0
  123. package/package.json +1 -1
  124. package/src/check-proof.js +159 -11
  125. package/test/conformance/NEUMERKEL-LATEST.md +3 -3
  126. package/test/regression/cases-white-box.mjs +38 -0
  127. package/test/run-examples.mjs +7 -111
  128. package/test/run-proof-checking.mjs +28 -5
  129. package/the-art-of-eyeprolog.md +4 -2
@@ -0,0 +1,954 @@
1
+ label(scenarioA, "A – Primary care visit").
2
+ label(scenarioB, "B – Quality improvement (in scope)").
3
+ label(scenarioC, "C – Quality improvement (out of scope)").
4
+ label(scenarioD, "D – Insurance management").
5
+ label(scenarioE, "E – GP checks labs").
6
+ label(scenarioF, "F – Research on anonymised dataset").
7
+ label(scenarioG, "G – AI training (opt-out)").
8
+ description(scenarioA, "Clinician in the patient's care team accessing the patient summary for primary care management.").
9
+ description(scenarioB, "QI analyst using lab results + summary in a secure environment.").
10
+ description(scenarioC, "QI analyst with only lab results; policy expects labs + summary.").
11
+ description(scenarioD, "Insurance bot attempting to use health data for insurance management (prohibited purpose).").
12
+ description(scenarioE, "GP for the same patient checking lab results via the API gateway.").
13
+ description(scenarioF, "Researcher using anonymised labs + summary in a secure environment, with opt-in.").
14
+ description(scenarioG, "Data user wants to train AI, but the subject opted out of AI training.").
15
+ careTeamLinked(scenarioA, true).
16
+ careTeamLinked(scenarioE, true).
17
+ subjectOptIn(scenarioF, true).
18
+ subjectOptOut(scenarioG, true).
19
+ decision(scenarioA, "PERMIT").
20
+ decision(scenarioE, "PERMIT").
21
+ decision(scenarioB, "PERMIT").
22
+ decision(scenarioF, "PERMIT").
23
+ decision(scenarioD, "DENY").
24
+ decision(scenarioG, "DENY").
25
+ decision(scenarioC, "DENY").
26
+ matchedPolicyUid(scenarioA, "urn:policy:primary-care-001").
27
+ matchedPolicyUid(scenarioE, "urn:policy:primary-care-001").
28
+ matchedPolicyUid(scenarioB, "urn:policy:qi-2025-aurora").
29
+ matchedPolicyUid(scenarioF, "urn:policy:research-aurora-diabetes").
30
+ matchedProhibition(scenarioD, policyDenyInsurance).
31
+ reason(scenarioA, "Permitted: clinician in the patient's care team, and the primary-care policy matched.").
32
+ reason(scenarioE, "Permitted: clinician in the patient's care team, and the primary-care policy matched.").
33
+ reason(scenarioB, "Permitted: ODRL/DPV policy matched for secondary use.").
34
+ reason(scenarioF, "Permitted: subject opted in and an ODRL/DPV policy matched (anonymised dataset in secure environment).").
35
+ reason(scenarioD, "Denied: the requested purpose (insurance management) is prohibited by policy.").
36
+ reason(scenarioG, "Denied: you opted out of your data being used to train AI systems.").
37
+ reason(scenarioC, "Denied: no policy matched (purpose, environment, TOMs, or categories out of scope).").
38
+ trace(scenarioA, "permit:primary_care_allowed").
39
+ trace(scenarioE, "permit:primary_care_allowed").
40
+ trace(scenarioA, "urn:policy:primary-care-001:permit:odrl:permission_matched").
41
+ trace(scenarioE, "urn:policy:primary-care-001:permit:odrl:permission_matched").
42
+ trace(scenarioB, "urn:policy:qi-2025-aurora:permit:odrl:permission_matched").
43
+ trace(scenarioF, "urn:policy:research-aurora-diabetes:permit:odrl:permission_matched").
44
+ trace(scenarioD, "deny:prohibited_purpose").
45
+ trace(scenarioD, "urn:policy:deny-insurance:deny:odrl:prohibition_matched").
46
+ trace(scenarioG, "deny:subject_opted_out_ai_training").
47
+ trace(scenarioC, "urn:policy:qi-2025-aurora:deny:odrl:no_permission_matched").
48
+ checkC1(scenarioA, "SKIPPED - not a prohibited purpose").
49
+ checkC1(scenarioB, "SKIPPED - not a prohibited purpose").
50
+ checkC1(scenarioC, "SKIPPED - not a prohibited purpose").
51
+ checkC1(scenarioD, "OK - denied prohibited purpose").
52
+ checkC1(scenarioE, "SKIPPED - not a prohibited purpose").
53
+ checkC1(scenarioF, "SKIPPED - not a prohibited purpose").
54
+ checkC1(scenarioG, "SKIPPED - not a prohibited purpose").
55
+ checkC2(scenarioA, "OK - clinician").
56
+ checkC2(scenarioB, "SKIPPED").
57
+ checkC2(scenarioC, "SKIPPED").
58
+ checkC2(scenarioD, "SKIPPED").
59
+ checkC2(scenarioE, "OK - clinician").
60
+ checkC2(scenarioF, "SKIPPED").
61
+ checkC2(scenarioG, "SKIPPED").
62
+ checkC3(scenarioA, "OK - care-team linked").
63
+ checkC3(scenarioB, "SKIPPED").
64
+ checkC3(scenarioC, "SKIPPED").
65
+ checkC3(scenarioD, "SKIPPED").
66
+ checkC3(scenarioE, "OK - care-team linked").
67
+ checkC3(scenarioF, "SKIPPED").
68
+ checkC3(scenarioG, "SKIPPED").
69
+ checkC4(scenarioA, "SKIPPED").
70
+ checkC4(scenarioB, "OK - opt-in present and policy matched").
71
+ checkC4(scenarioC, "OK - denied because opt-in missing or no policy match").
72
+ checkC4(scenarioD, "SKIPPED").
73
+ checkC4(scenarioE, "SKIPPED").
74
+ checkC4(scenarioF, "OK - opt-in present and policy matched").
75
+ checkC4(scenarioG, "OK - denied because opt-in missing or no policy match").
76
+ checkC5(scenarioA, "OK - operator=isAnyOf, allowed=[\"https://example.org/health#PATIENT_SUMMARY\", \"https://example.org/health#LAB_RESULTS\"], requested=[\"https://example.org/health#PATIENT_SUMMARY\"]").
77
+ checkC5(scenarioB, "OK - operator=isAllOf, allowed=[\"https://example.org/health#LAB_RESULTS\", \"https://example.org/health#PATIENT_SUMMARY\"], requested=[\"https://example.org/health#LAB_RESULTS\", \"https://example.org/health#PATIENT_SUMMARY\"]").
78
+ checkC5(scenarioC, "SKIPPED").
79
+ checkC5(scenarioD, "SKIPPED").
80
+ checkC5(scenarioE, "OK - operator=isAnyOf, allowed=[\"https://example.org/health#PATIENT_SUMMARY\", \"https://example.org/health#LAB_RESULTS\"], requested=[\"https://example.org/health#LAB_RESULTS\"]").
81
+ checkC5(scenarioF, "OK - operator=isAnyOf, allowed=[\"https://example.org/health#LAB_RESULTS\", \"https://example.org/health#PATIENT_SUMMARY\", \"https://example.org/health#IMAGING_REPORT\"], requested=[\"https://example.org/health#PATIENT_SUMMARY\", \"https://example.org/health#LAB_RESULTS\"]").
82
+ checkC5(scenarioG, "SKIPPED").
83
+ checkC6(scenarioA, "SKIPPED - no prohibition matched").
84
+ checkC6(scenarioB, "SKIPPED - no prohibition matched").
85
+ checkC6(scenarioC, "SKIPPED - no prohibition matched").
86
+ checkC6(scenarioD, "OK - denied due to prohibition").
87
+ checkC6(scenarioE, "SKIPPED - no prohibition matched").
88
+ checkC6(scenarioF, "SKIPPED - no prohibition matched").
89
+ checkC6(scenarioG, "SKIPPED - no prohibition matched").
90
+ checkC7(scenarioA, "OK - trace shows matching permission").
91
+ checkC7(scenarioB, "OK - trace shows matching permission").
92
+ checkC7(scenarioC, "SKIPPED").
93
+ checkC7(scenarioD, "SKIPPED").
94
+ checkC7(scenarioE, "OK - trace shows matching permission").
95
+ checkC7(scenarioF, "OK - trace shows matching permission").
96
+ checkC7(scenarioG, "SKIPPED").
97
+ checkC8(scenarioA, "SKIPPED - no matched policy or no duties").
98
+ checkC8(scenarioB, "INFO - duties attached: duty:https://w3id.org/dpv/legal/eu/ehds#requireConsent, duty:https://w3id.org/dpv/legal/eu/ehds#noExfiltration").
99
+ checkC8(scenarioC, "SKIPPED - no matched policy or no duties").
100
+ checkC8(scenarioD, "SKIPPED - no matched policy or no duties").
101
+ checkC8(scenarioE, "SKIPPED - no matched policy or no duties").
102
+ checkC8(scenarioF, "INFO - duties attached: duty:https://w3id.org/dpv/legal/eu/ehds#annualOutcomeReport, duty:https://w3id.org/dpv/legal/eu/ehds#noReidentification, duty:https://w3id.org/dpv/legal/eu/ehds#noExfiltration").
103
+ checkC8(scenarioG, "SKIPPED - no matched policy or no duties").
104
+ checkC9(scenarioA, "SKIPPED - policy has no environment constraint").
105
+ checkC9(scenarioB, "OK - operator=eq, allowed=\"secure_env\", requested=\"secure_env\"").
106
+ checkC9(scenarioC, "SKIPPED").
107
+ checkC9(scenarioD, "SKIPPED").
108
+ checkC9(scenarioE, "SKIPPED - policy has no environment constraint").
109
+ checkC9(scenarioF, "OK - operator=eq, allowed=\"secure_env\", requested=\"secure_env\"").
110
+ checkC9(scenarioG, "SKIPPED").
111
+ checkC10Text(scenarioA, "INFO - matched policy: urn:policy:primary-care-001").
112
+ checkC10Text(scenarioB, "INFO - matched policy: urn:policy:qi-2025-aurora").
113
+ checkC10Text(scenarioC, "SKIPPED - no matched policy").
114
+ checkC10Text(scenarioD, "SKIPPED - no matched policy").
115
+ checkC10Text(scenarioE, "INFO - matched policy: urn:policy:primary-care-001").
116
+ checkC10Text(scenarioF, "INFO - matched policy: urn:policy:research-aurora-diabetes").
117
+ checkC10Text(scenarioG, "SKIPPED - no matched policy").
118
+
119
+ clause(28, policyUid(policyPrimary, "urn:policy:primary-care-001"), true).
120
+ clause(32, allowAnyCategory(policyPrimary, patientSummary), true).
121
+ clause(33, allowAnyCategory(policyPrimary, labResults), true).
122
+ clause(34, policyUid(policyQi, "urn:policy:qi-2025-aurora"), true).
123
+ clause(41, policyUid(policyResearch, "urn:policy:research-aurora-diabetes"), true).
124
+ clause(52, prohibitPurpose(policyDenyInsurance, insuranceManagement), true).
125
+ clause(53, linkedTo(clinicianAlba, ruben), true).
126
+ clause(54, linkedTo(gpRuben, ruben), true).
127
+ clause(55, consentAllow(ruben, healthcareScientificResearch), true).
128
+ clause(56, consentDeny(ruben, trainTestAndEvaluateAiSystemsAlgorithms), true).
129
+ clause(62, scenario_label(scenarioA, "A – Primary care visit"), true).
130
+ clause(63,
131
+ scenario_description(scenarioA, "Clinician in the patient's care team accessing the patient summary for primary care management."),
132
+ true).
133
+ clause(64, requester(scenarioA, clinicianAlba), true).
134
+ clause(65, requesterRole(scenarioA, "clinician"), true).
135
+ clause(66, subject(scenarioA, ruben), true).
136
+ clause(67, purpose(scenarioA, primaryCareManagement), true).
137
+ clause(69, category(scenarioA, patientSummary), true).
138
+ clause(72, scenario_label(scenarioB, "B – Quality improvement (in scope)"), true).
139
+ clause(73,
140
+ scenario_description(scenarioB, "QI analyst using lab results + summary in a secure environment."),
141
+ true).
142
+ clause(77, purpose(scenarioB, ensureQualitySafetyHealthcare), true).
143
+ clause(78, environment(scenarioB, "secure_env"), true).
144
+ clause(79, category(scenarioB, labResults), true).
145
+ clause(80, category(scenarioB, patientSummary), true).
146
+ clause(83, scenario_label(scenarioC, "C – Quality improvement (out of scope)"), true).
147
+ clause(84,
148
+ scenario_description(scenarioC, "QI analyst with only lab results; policy expects labs + summary."),
149
+ true).
150
+ clause(88, purpose(scenarioC, ensureQualitySafetyHealthcare), true).
151
+ clause(93, scenario_label(scenarioD, "D – Insurance management"), true).
152
+ clause(94,
153
+ scenario_description(scenarioD, "Insurance bot attempting to use health data for insurance management (prohibited purpose)."),
154
+ true).
155
+ clause(98, purpose(scenarioD, insuranceManagement), true).
156
+ clause(103, scenario_label(scenarioE, "E – GP checks labs"), true).
157
+ clause(104,
158
+ scenario_description(scenarioE, "GP for the same patient checking lab results via the API gateway."),
159
+ true).
160
+ clause(105, requester(scenarioE, gpRuben), true).
161
+ clause(106, requesterRole(scenarioE, "clinician"), true).
162
+ clause(107, subject(scenarioE, ruben), true).
163
+ clause(108, purpose(scenarioE, primaryCareManagement), true).
164
+ clause(110, category(scenarioE, labResults), true).
165
+ clause(113, scenario_label(scenarioF, "F – Research on anonymised dataset"), true).
166
+ clause(114,
167
+ scenario_description(scenarioF, "Researcher using anonymised labs + summary in a secure environment, with opt-in."),
168
+ true).
169
+ clause(117, subject(scenarioF, ruben), true).
170
+ clause(118, purpose(scenarioF, healthcareScientificResearch), true).
171
+ clause(119, environment(scenarioF, "secure_env"), true).
172
+ clause(120, tom(scenarioF, anonymisation), true).
173
+ clause(122, category(scenarioF, labResults), true).
174
+ clause(125, scenario_label(scenarioG, "G – AI training (opt-out)"), true).
175
+ clause(126,
176
+ scenario_description(scenarioG, "Data user wants to train AI, but the subject opted out of AI training."),
177
+ true).
178
+ clause(129, subject(scenarioG, ruben), true).
179
+ clause(130, purpose(scenarioG, trainTestAndEvaluateAiSystemsAlgorithms), true).
180
+ clause(134, label(var('S'), var('Label')), scenario_label(var('S'), var('Label'))).
181
+ clause(135,
182
+ description(var('S'), var('Description')),
183
+ scenario_description(var('S'), var('Description'))).
184
+ clause(136,
185
+ care_team_linked(var('S')),
186
+ (requester(var('S'), var('Requester')),
187
+ subject(var('S'), var('Subject')),
188
+ linkedTo(var('Requester'), var('Subject')))).
189
+ clause(137,
190
+ subject_opt_in(var('S')),
191
+ (subject(var('S'), var('Subject')),
192
+ purpose(var('S'), var('Purpose')),
193
+ consentAllow(var('Subject'), var('Purpose')))).
194
+ clause(138,
195
+ subject_opt_out(var('S')),
196
+ (subject(var('S'), var('Subject')),
197
+ purpose(var('S'), var('Purpose')),
198
+ consentDeny(var('Subject'), var('Purpose')))).
199
+ clause(139,
200
+ primary_policy_match(var('S')),
201
+ (purpose(var('S'), primaryCareManagement),
202
+ requesterRole(var('S'), "clinician"),
203
+ care_team_linked(var('S')),
204
+ category(var('S'), var('Category')),
205
+ allowAnyCategory(policyPrimary, var('Category')))).
206
+ clause(140,
207
+ qi_policy_match(var('S')),
208
+ (purpose(var('S'), ensureQualitySafetyHealthcare),
209
+ environment(var('S'), "secure_env"),
210
+ category(var('S'), labResults),
211
+ category(var('S'), patientSummary))).
212
+ clause(141,
213
+ research_policy_match(var('S')),
214
+ (purpose(var('S'), healthcareScientificResearch),
215
+ environment(var('S'), "secure_env"),
216
+ tom(var('S'), anonymisation),
217
+ subject_opt_in(var('S')),
218
+ category(var('S'), labResults))).
219
+ clause(142,
220
+ insurance_prohibition_match(var('S')),
221
+ (purpose(var('S'), insuranceManagement),
222
+ prohibitPurpose(policyDenyInsurance, insuranceManagement))).
223
+ clause(143,
224
+ ai_training_opt_out_match(var('S')),
225
+ (purpose(var('S'), trainTestAndEvaluateAiSystemsAlgorithms), subject_opt_out(var('S')))).
226
+ clause(144, careTeamLinked(var('S'), true), care_team_linked(var('S'))).
227
+ clause(145, subjectOptIn(var('S'), true), subject_opt_in(var('S'))).
228
+ clause(146, subjectOptOut(var('S'), true), subject_opt_out(var('S'))).
229
+ clause(147, decision(var('S'), "PERMIT"), primary_policy_match(var('S'))).
230
+ clause(148, decision(var('S'), "PERMIT"), qi_policy_match(var('S'))).
231
+ clause(149, decision(var('S'), "PERMIT"), research_policy_match(var('S'))).
232
+ clause(150, decision(var('S'), "DENY"), insurance_prohibition_match(var('S'))).
233
+ clause(151, decision(var('S'), "DENY"), ai_training_opt_out_match(var('S'))).
234
+ clause(152, decision(scenarioC, "DENY"), purpose(scenarioC, ensureQualitySafetyHealthcare)).
235
+ clause(153,
236
+ matchedPolicyUid(var('S'), var('Uid')),
237
+ (primary_policy_match(var('S')), policyUid(policyPrimary, var('Uid')))).
238
+ clause(154,
239
+ matchedPolicyUid(var('S'), var('Uid')),
240
+ (qi_policy_match(var('S')), policyUid(policyQi, var('Uid')))).
241
+ clause(155,
242
+ matchedPolicyUid(var('S'), var('Uid')),
243
+ (research_policy_match(var('S')), policyUid(policyResearch, var('Uid')))).
244
+ clause(156,
245
+ matchedProhibition(var('S'), policyDenyInsurance),
246
+ insurance_prohibition_match(var('S'))).
247
+ clause(157,
248
+ reason(var('S'), "Permitted: clinician in the patient's care team, and the primary-care policy matched."),
249
+ primary_policy_match(var('S'))).
250
+ clause(158,
251
+ reason(var('S'), "Permitted: ODRL/DPV policy matched for secondary use."),
252
+ qi_policy_match(var('S'))).
253
+ clause(159,
254
+ reason(var('S'), "Permitted: subject opted in and an ODRL/DPV policy matched (anonymised dataset in secure environment)."),
255
+ research_policy_match(var('S'))).
256
+ clause(160,
257
+ reason(var('S'), "Denied: the requested purpose (insurance management) is prohibited by policy."),
258
+ insurance_prohibition_match(var('S'))).
259
+ clause(161,
260
+ reason(var('S'), "Denied: you opted out of your data being used to train AI systems."),
261
+ ai_training_opt_out_match(var('S'))).
262
+ clause(162,
263
+ reason(scenarioC, "Denied: no policy matched (purpose, environment, TOMs, or categories out of scope)."),
264
+ purpose(scenarioC, ensureQualitySafetyHealthcare)).
265
+ clause(163, trace(var('S'), "permit:primary_care_allowed"), primary_policy_match(var('S'))).
266
+ clause(164,
267
+ trace(var('S'), "urn:policy:primary-care-001:permit:odrl:permission_matched"),
268
+ primary_policy_match(var('S'))).
269
+ clause(165,
270
+ trace(var('S'), "urn:policy:qi-2025-aurora:permit:odrl:permission_matched"),
271
+ qi_policy_match(var('S'))).
272
+ clause(166,
273
+ trace(var('S'), "urn:policy:research-aurora-diabetes:permit:odrl:permission_matched"),
274
+ research_policy_match(var('S'))).
275
+ clause(167, trace(var('S'), "deny:prohibited_purpose"), insurance_prohibition_match(var('S'))).
276
+ clause(168,
277
+ trace(var('S'), "urn:policy:deny-insurance:deny:odrl:prohibition_matched"),
278
+ insurance_prohibition_match(var('S'))).
279
+ clause(169,
280
+ trace(var('S'), "deny:subject_opted_out_ai_training"),
281
+ ai_training_opt_out_match(var('S'))).
282
+ clause(170,
283
+ trace(scenarioC, "urn:policy:qi-2025-aurora:deny:odrl:no_permission_matched"),
284
+ purpose(scenarioC, ensureQualitySafetyHealthcare)).
285
+ clause(171,
286
+ checkC1(scenarioA, "SKIPPED - not a prohibited purpose"),
287
+ decision(scenarioA, "PERMIT")).
288
+ clause(172, checkC2(scenarioA, "OK - clinician"), decision(scenarioA, "PERMIT")).
289
+ clause(173, checkC3(scenarioA, "OK - care-team linked"), decision(scenarioA, "PERMIT")).
290
+ clause(174, checkC4(scenarioA, "SKIPPED"), decision(scenarioA, "PERMIT")).
291
+ clause(175,
292
+ checkC5(scenarioA, "OK - operator=isAnyOf, allowed=[\"https://example.org/health#PATIENT_SUMMARY\", \"https://example.org/health#LAB_RESULTS\"], requested=[\"https://example.org/health#PATIENT_SUMMARY\"]"),
293
+ decision(scenarioA, "PERMIT")).
294
+ clause(176,
295
+ checkC6(scenarioA, "SKIPPED - no prohibition matched"),
296
+ decision(scenarioA, "PERMIT")).
297
+ clause(177,
298
+ checkC7(scenarioA, "OK - trace shows matching permission"),
299
+ decision(scenarioA, "PERMIT")).
300
+ clause(178,
301
+ checkC8(scenarioA, "SKIPPED - no matched policy or no duties"),
302
+ decision(scenarioA, "PERMIT")).
303
+ clause(179,
304
+ checkC9(scenarioA, "SKIPPED - policy has no environment constraint"),
305
+ decision(scenarioA, "PERMIT")).
306
+ clause(180,
307
+ checkC10Text(scenarioA, "INFO - matched policy: urn:policy:primary-care-001"),
308
+ decision(scenarioA, "PERMIT")).
309
+ clause(181,
310
+ checkC1(scenarioB, "SKIPPED - not a prohibited purpose"),
311
+ decision(scenarioB, "PERMIT")).
312
+ clause(182, checkC2(scenarioB, "SKIPPED"), decision(scenarioB, "PERMIT")).
313
+ clause(183, checkC3(scenarioB, "SKIPPED"), decision(scenarioB, "PERMIT")).
314
+ clause(184,
315
+ checkC4(scenarioB, "OK - opt-in present and policy matched"),
316
+ decision(scenarioB, "PERMIT")).
317
+ clause(185,
318
+ checkC5(scenarioB, "OK - operator=isAllOf, allowed=[\"https://example.org/health#LAB_RESULTS\", \"https://example.org/health#PATIENT_SUMMARY\"], requested=[\"https://example.org/health#LAB_RESULTS\", \"https://example.org/health#PATIENT_SUMMARY\"]"),
319
+ decision(scenarioB, "PERMIT")).
320
+ clause(186,
321
+ checkC6(scenarioB, "SKIPPED - no prohibition matched"),
322
+ decision(scenarioB, "PERMIT")).
323
+ clause(187,
324
+ checkC7(scenarioB, "OK - trace shows matching permission"),
325
+ decision(scenarioB, "PERMIT")).
326
+ clause(188,
327
+ checkC8(scenarioB, "INFO - duties attached: duty:https://w3id.org/dpv/legal/eu/ehds#requireConsent, duty:https://w3id.org/dpv/legal/eu/ehds#noExfiltration"),
328
+ decision(scenarioB, "PERMIT")).
329
+ clause(189,
330
+ checkC9(scenarioB, "OK - operator=eq, allowed=\"secure_env\", requested=\"secure_env\""),
331
+ decision(scenarioB, "PERMIT")).
332
+ clause(190,
333
+ checkC10Text(scenarioB, "INFO - matched policy: urn:policy:qi-2025-aurora"),
334
+ decision(scenarioB, "PERMIT")).
335
+ clause(191,
336
+ checkC1(scenarioC, "SKIPPED - not a prohibited purpose"),
337
+ decision(scenarioC, "DENY")).
338
+ clause(192, checkC2(scenarioC, "SKIPPED"), decision(scenarioC, "DENY")).
339
+ clause(193, checkC3(scenarioC, "SKIPPED"), decision(scenarioC, "DENY")).
340
+ clause(194,
341
+ checkC4(scenarioC, "OK - denied because opt-in missing or no policy match"),
342
+ decision(scenarioC, "DENY")).
343
+ clause(195, checkC5(scenarioC, "SKIPPED"), decision(scenarioC, "DENY")).
344
+ clause(196, checkC6(scenarioC, "SKIPPED - no prohibition matched"), decision(scenarioC, "DENY")).
345
+ clause(197, checkC7(scenarioC, "SKIPPED"), decision(scenarioC, "DENY")).
346
+ clause(198,
347
+ checkC8(scenarioC, "SKIPPED - no matched policy or no duties"),
348
+ decision(scenarioC, "DENY")).
349
+ clause(199, checkC9(scenarioC, "SKIPPED"), decision(scenarioC, "DENY")).
350
+ clause(200, checkC10Text(scenarioC, "SKIPPED - no matched policy"), decision(scenarioC, "DENY")).
351
+ clause(201, checkC1(scenarioD, "OK - denied prohibited purpose"), decision(scenarioD, "DENY")).
352
+ clause(202, checkC2(scenarioD, "SKIPPED"), decision(scenarioD, "DENY")).
353
+ clause(203, checkC3(scenarioD, "SKIPPED"), decision(scenarioD, "DENY")).
354
+ clause(204, checkC4(scenarioD, "SKIPPED"), decision(scenarioD, "DENY")).
355
+ clause(205, checkC5(scenarioD, "SKIPPED"), decision(scenarioD, "DENY")).
356
+ clause(206, checkC6(scenarioD, "OK - denied due to prohibition"), decision(scenarioD, "DENY")).
357
+ clause(207, checkC7(scenarioD, "SKIPPED"), decision(scenarioD, "DENY")).
358
+ clause(208,
359
+ checkC8(scenarioD, "SKIPPED - no matched policy or no duties"),
360
+ decision(scenarioD, "DENY")).
361
+ clause(209, checkC9(scenarioD, "SKIPPED"), decision(scenarioD, "DENY")).
362
+ clause(210, checkC10Text(scenarioD, "SKIPPED - no matched policy"), decision(scenarioD, "DENY")).
363
+ clause(211,
364
+ checkC1(scenarioE, "SKIPPED - not a prohibited purpose"),
365
+ decision(scenarioE, "PERMIT")).
366
+ clause(212, checkC2(scenarioE, "OK - clinician"), decision(scenarioE, "PERMIT")).
367
+ clause(213, checkC3(scenarioE, "OK - care-team linked"), decision(scenarioE, "PERMIT")).
368
+ clause(214, checkC4(scenarioE, "SKIPPED"), decision(scenarioE, "PERMIT")).
369
+ clause(215,
370
+ checkC5(scenarioE, "OK - operator=isAnyOf, allowed=[\"https://example.org/health#PATIENT_SUMMARY\", \"https://example.org/health#LAB_RESULTS\"], requested=[\"https://example.org/health#LAB_RESULTS\"]"),
371
+ decision(scenarioE, "PERMIT")).
372
+ clause(216,
373
+ checkC6(scenarioE, "SKIPPED - no prohibition matched"),
374
+ decision(scenarioE, "PERMIT")).
375
+ clause(217,
376
+ checkC7(scenarioE, "OK - trace shows matching permission"),
377
+ decision(scenarioE, "PERMIT")).
378
+ clause(218,
379
+ checkC8(scenarioE, "SKIPPED - no matched policy or no duties"),
380
+ decision(scenarioE, "PERMIT")).
381
+ clause(219,
382
+ checkC9(scenarioE, "SKIPPED - policy has no environment constraint"),
383
+ decision(scenarioE, "PERMIT")).
384
+ clause(220,
385
+ checkC10Text(scenarioE, "INFO - matched policy: urn:policy:primary-care-001"),
386
+ decision(scenarioE, "PERMIT")).
387
+ clause(221,
388
+ checkC1(scenarioF, "SKIPPED - not a prohibited purpose"),
389
+ decision(scenarioF, "PERMIT")).
390
+ clause(222, checkC2(scenarioF, "SKIPPED"), decision(scenarioF, "PERMIT")).
391
+ clause(223, checkC3(scenarioF, "SKIPPED"), decision(scenarioF, "PERMIT")).
392
+ clause(224,
393
+ checkC4(scenarioF, "OK - opt-in present and policy matched"),
394
+ decision(scenarioF, "PERMIT")).
395
+ clause(225,
396
+ checkC5(scenarioF, "OK - operator=isAnyOf, allowed=[\"https://example.org/health#LAB_RESULTS\", \"https://example.org/health#PATIENT_SUMMARY\", \"https://example.org/health#IMAGING_REPORT\"], requested=[\"https://example.org/health#PATIENT_SUMMARY\", \"https://example.org/health#LAB_RESULTS\"]"),
397
+ decision(scenarioF, "PERMIT")).
398
+ clause(226,
399
+ checkC6(scenarioF, "SKIPPED - no prohibition matched"),
400
+ decision(scenarioF, "PERMIT")).
401
+ clause(227,
402
+ checkC7(scenarioF, "OK - trace shows matching permission"),
403
+ decision(scenarioF, "PERMIT")).
404
+ clause(228,
405
+ checkC8(scenarioF, "INFO - duties attached: duty:https://w3id.org/dpv/legal/eu/ehds#annualOutcomeReport, duty:https://w3id.org/dpv/legal/eu/ehds#noReidentification, duty:https://w3id.org/dpv/legal/eu/ehds#noExfiltration"),
406
+ decision(scenarioF, "PERMIT")).
407
+ clause(229,
408
+ checkC9(scenarioF, "OK - operator=eq, allowed=\"secure_env\", requested=\"secure_env\""),
409
+ decision(scenarioF, "PERMIT")).
410
+ clause(230,
411
+ checkC10Text(scenarioF, "INFO - matched policy: urn:policy:research-aurora-diabetes"),
412
+ decision(scenarioF, "PERMIT")).
413
+ clause(231,
414
+ checkC1(scenarioG, "SKIPPED - not a prohibited purpose"),
415
+ decision(scenarioG, "DENY")).
416
+ clause(232, checkC2(scenarioG, "SKIPPED"), decision(scenarioG, "DENY")).
417
+ clause(233, checkC3(scenarioG, "SKIPPED"), decision(scenarioG, "DENY")).
418
+ clause(234,
419
+ checkC4(scenarioG, "OK - denied because opt-in missing or no policy match"),
420
+ decision(scenarioG, "DENY")).
421
+ clause(235, checkC5(scenarioG, "SKIPPED"), decision(scenarioG, "DENY")).
422
+ clause(236, checkC6(scenarioG, "SKIPPED - no prohibition matched"), decision(scenarioG, "DENY")).
423
+ clause(237, checkC7(scenarioG, "SKIPPED"), decision(scenarioG, "DENY")).
424
+ clause(238,
425
+ checkC8(scenarioG, "SKIPPED - no matched policy or no duties"),
426
+ decision(scenarioG, "DENY")).
427
+ clause(239, checkC9(scenarioG, "SKIPPED"), decision(scenarioG, "DENY")).
428
+ clause(240, checkC10Text(scenarioG, "SKIPPED - no matched policy"), decision(scenarioG, "DENY")).
429
+
430
+ step(label(scenarioA, "A – Primary care visit"),
431
+ rule(134),
432
+ ['S' = scenarioA, 'Label' = "A – Primary care visit"],
433
+ [scenario_label(scenarioA, "A – Primary care visit")]).
434
+ step(scenario_label(scenarioA, "A – Primary care visit"), fact(62), [], []).
435
+ step(label(scenarioB, "B – Quality improvement (in scope)"),
436
+ rule(134),
437
+ ['S' = scenarioB, 'Label' = "B – Quality improvement (in scope)"],
438
+ [scenario_label(scenarioB, "B – Quality improvement (in scope)")]).
439
+ step(scenario_label(scenarioB, "B – Quality improvement (in scope)"), fact(72), [], []).
440
+ step(label(scenarioC, "C – Quality improvement (out of scope)"),
441
+ rule(134),
442
+ ['S' = scenarioC, 'Label' = "C – Quality improvement (out of scope)"],
443
+ [scenario_label(scenarioC, "C – Quality improvement (out of scope)")]).
444
+ step(scenario_label(scenarioC, "C – Quality improvement (out of scope)"), fact(83), [], []).
445
+ step(label(scenarioD, "D – Insurance management"),
446
+ rule(134),
447
+ ['S' = scenarioD, 'Label' = "D – Insurance management"],
448
+ [scenario_label(scenarioD, "D – Insurance management")]).
449
+ step(scenario_label(scenarioD, "D – Insurance management"), fact(93), [], []).
450
+ step(label(scenarioE, "E – GP checks labs"),
451
+ rule(134),
452
+ ['S' = scenarioE, 'Label' = "E – GP checks labs"],
453
+ [scenario_label(scenarioE, "E – GP checks labs")]).
454
+ step(scenario_label(scenarioE, "E – GP checks labs"), fact(103), [], []).
455
+ step(label(scenarioF, "F – Research on anonymised dataset"),
456
+ rule(134),
457
+ ['S' = scenarioF, 'Label' = "F – Research on anonymised dataset"],
458
+ [scenario_label(scenarioF, "F – Research on anonymised dataset")]).
459
+ step(scenario_label(scenarioF, "F – Research on anonymised dataset"), fact(113), [], []).
460
+ step(label(scenarioG, "G – AI training (opt-out)"),
461
+ rule(134),
462
+ ['S' = scenarioG, 'Label' = "G – AI training (opt-out)"],
463
+ [scenario_label(scenarioG, "G – AI training (opt-out)")]).
464
+ step(scenario_label(scenarioG, "G – AI training (opt-out)"), fact(125), [], []).
465
+ step(description(scenarioA, "Clinician in the patient's care team accessing the patient summary for primary care management."),
466
+ rule(135),
467
+ ['S' = scenarioA,
468
+ 'Description' = "Clinician in the patient's care team accessing the patient summary for primary care management."],
469
+ [scenario_description(scenarioA, "Clinician in the patient's care team accessing the patient summary for primary care management.")]).
470
+ step(scenario_description(scenarioA, "Clinician in the patient's care team accessing the patient summary for primary care management."),
471
+ fact(63),
472
+ [],
473
+ []).
474
+ step(description(scenarioB, "QI analyst using lab results + summary in a secure environment."),
475
+ rule(135),
476
+ ['S' = scenarioB,
477
+ 'Description' = "QI analyst using lab results + summary in a secure environment."],
478
+ [scenario_description(scenarioB, "QI analyst using lab results + summary in a secure environment.")]).
479
+ step(scenario_description(scenarioB, "QI analyst using lab results + summary in a secure environment."),
480
+ fact(73),
481
+ [],
482
+ []).
483
+ step(description(scenarioC, "QI analyst with only lab results; policy expects labs + summary."),
484
+ rule(135),
485
+ ['S' = scenarioC,
486
+ 'Description' = "QI analyst with only lab results; policy expects labs + summary."],
487
+ [scenario_description(scenarioC, "QI analyst with only lab results; policy expects labs + summary.")]).
488
+ step(scenario_description(scenarioC, "QI analyst with only lab results; policy expects labs + summary."),
489
+ fact(84),
490
+ [],
491
+ []).
492
+ step(description(scenarioD, "Insurance bot attempting to use health data for insurance management (prohibited purpose)."),
493
+ rule(135),
494
+ ['S' = scenarioD,
495
+ 'Description' = "Insurance bot attempting to use health data for insurance management (prohibited purpose)."],
496
+ [scenario_description(scenarioD, "Insurance bot attempting to use health data for insurance management (prohibited purpose).")]).
497
+ step(scenario_description(scenarioD, "Insurance bot attempting to use health data for insurance management (prohibited purpose)."),
498
+ fact(94),
499
+ [],
500
+ []).
501
+ step(description(scenarioE, "GP for the same patient checking lab results via the API gateway."),
502
+ rule(135),
503
+ ['S' = scenarioE,
504
+ 'Description' = "GP for the same patient checking lab results via the API gateway."],
505
+ [scenario_description(scenarioE, "GP for the same patient checking lab results via the API gateway.")]).
506
+ step(scenario_description(scenarioE, "GP for the same patient checking lab results via the API gateway."),
507
+ fact(104),
508
+ [],
509
+ []).
510
+ step(description(scenarioF, "Researcher using anonymised labs + summary in a secure environment, with opt-in."),
511
+ rule(135),
512
+ ['S' = scenarioF,
513
+ 'Description' = "Researcher using anonymised labs + summary in a secure environment, with opt-in."],
514
+ [scenario_description(scenarioF, "Researcher using anonymised labs + summary in a secure environment, with opt-in.")]).
515
+ step(scenario_description(scenarioF, "Researcher using anonymised labs + summary in a secure environment, with opt-in."),
516
+ fact(114),
517
+ [],
518
+ []).
519
+ step(description(scenarioG, "Data user wants to train AI, but the subject opted out of AI training."),
520
+ rule(135),
521
+ ['S' = scenarioG,
522
+ 'Description' = "Data user wants to train AI, but the subject opted out of AI training."],
523
+ [scenario_description(scenarioG, "Data user wants to train AI, but the subject opted out of AI training.")]).
524
+ step(scenario_description(scenarioG, "Data user wants to train AI, but the subject opted out of AI training."),
525
+ fact(126),
526
+ [],
527
+ []).
528
+ step(careTeamLinked(scenarioA, true),
529
+ rule(144),
530
+ ['S' = scenarioA],
531
+ [care_team_linked(scenarioA)]).
532
+ step(care_team_linked(scenarioA),
533
+ rule(136),
534
+ ['S' = scenarioA, 'Requester' = clinicianAlba, 'Subject' = ruben],
535
+ [requester(scenarioA, clinicianAlba),
536
+ subject(scenarioA, ruben),
537
+ linkedTo(clinicianAlba, ruben)]).
538
+ step(requester(scenarioA, clinicianAlba), fact(64), [], []).
539
+ step(subject(scenarioA, ruben), fact(66), [], []).
540
+ step(linkedTo(clinicianAlba, ruben), fact(53), [], []).
541
+ step(careTeamLinked(scenarioE, true),
542
+ rule(144),
543
+ ['S' = scenarioE],
544
+ [care_team_linked(scenarioE)]).
545
+ step(care_team_linked(scenarioE),
546
+ rule(136),
547
+ ['S' = scenarioE, 'Requester' = gpRuben, 'Subject' = ruben],
548
+ [requester(scenarioE, gpRuben), subject(scenarioE, ruben), linkedTo(gpRuben, ruben)]).
549
+ step(requester(scenarioE, gpRuben), fact(105), [], []).
550
+ step(subject(scenarioE, ruben), fact(107), [], []).
551
+ step(linkedTo(gpRuben, ruben), fact(54), [], []).
552
+ step(subjectOptIn(scenarioF, true), rule(145), ['S' = scenarioF], [subject_opt_in(scenarioF)]).
553
+ step(subject_opt_in(scenarioF),
554
+ rule(137),
555
+ ['S' = scenarioF, 'Subject' = ruben, 'Purpose' = healthcareScientificResearch],
556
+ [subject(scenarioF, ruben),
557
+ purpose(scenarioF, healthcareScientificResearch),
558
+ consentAllow(ruben, healthcareScientificResearch)]).
559
+ step(subject(scenarioF, ruben), fact(117), [], []).
560
+ step(purpose(scenarioF, healthcareScientificResearch), fact(118), [], []).
561
+ step(consentAllow(ruben, healthcareScientificResearch), fact(55), [], []).
562
+ step(subjectOptOut(scenarioG, true), rule(146), ['S' = scenarioG], [subject_opt_out(scenarioG)]).
563
+ step(subject_opt_out(scenarioG),
564
+ rule(138),
565
+ ['S' = scenarioG, 'Subject' = ruben, 'Purpose' = trainTestAndEvaluateAiSystemsAlgorithms],
566
+ [subject(scenarioG, ruben),
567
+ purpose(scenarioG, trainTestAndEvaluateAiSystemsAlgorithms),
568
+ consentDeny(ruben, trainTestAndEvaluateAiSystemsAlgorithms)]).
569
+ step(subject(scenarioG, ruben), fact(129), [], []).
570
+ step(purpose(scenarioG, trainTestAndEvaluateAiSystemsAlgorithms), fact(130), [], []).
571
+ step(consentDeny(ruben, trainTestAndEvaluateAiSystemsAlgorithms), fact(56), [], []).
572
+ step(decision(scenarioA, "PERMIT"),
573
+ rule(147),
574
+ ['S' = scenarioA],
575
+ [primary_policy_match(scenarioA)]).
576
+ step(primary_policy_match(scenarioA),
577
+ rule(139),
578
+ ['S' = scenarioA, 'Category' = patientSummary],
579
+ [purpose(scenarioA, primaryCareManagement),
580
+ requesterRole(scenarioA, "clinician"),
581
+ care_team_linked(scenarioA),
582
+ category(scenarioA, patientSummary),
583
+ allowAnyCategory(policyPrimary, patientSummary)]).
584
+ step(purpose(scenarioA, primaryCareManagement), fact(67), [], []).
585
+ step(requesterRole(scenarioA, "clinician"), fact(65), [], []).
586
+ step(category(scenarioA, patientSummary), fact(69), [], []).
587
+ step(allowAnyCategory(policyPrimary, patientSummary), fact(32), [], []).
588
+ step(decision(scenarioE, "PERMIT"),
589
+ rule(147),
590
+ ['S' = scenarioE],
591
+ [primary_policy_match(scenarioE)]).
592
+ step(primary_policy_match(scenarioE),
593
+ rule(139),
594
+ ['S' = scenarioE, 'Category' = labResults],
595
+ [purpose(scenarioE, primaryCareManagement),
596
+ requesterRole(scenarioE, "clinician"),
597
+ care_team_linked(scenarioE),
598
+ category(scenarioE, labResults),
599
+ allowAnyCategory(policyPrimary, labResults)]).
600
+ step(purpose(scenarioE, primaryCareManagement), fact(108), [], []).
601
+ step(requesterRole(scenarioE, "clinician"), fact(106), [], []).
602
+ step(category(scenarioE, labResults), fact(110), [], []).
603
+ step(allowAnyCategory(policyPrimary, labResults), fact(33), [], []).
604
+ step(decision(scenarioB, "PERMIT"), rule(148), ['S' = scenarioB], [qi_policy_match(scenarioB)]).
605
+ step(qi_policy_match(scenarioB),
606
+ rule(140),
607
+ ['S' = scenarioB],
608
+ [purpose(scenarioB, ensureQualitySafetyHealthcare),
609
+ environment(scenarioB, "secure_env"),
610
+ category(scenarioB, labResults),
611
+ category(scenarioB, patientSummary)]).
612
+ step(purpose(scenarioB, ensureQualitySafetyHealthcare), fact(77), [], []).
613
+ step(environment(scenarioB, "secure_env"), fact(78), [], []).
614
+ step(category(scenarioB, labResults), fact(79), [], []).
615
+ step(category(scenarioB, patientSummary), fact(80), [], []).
616
+ step(decision(scenarioF, "PERMIT"),
617
+ rule(149),
618
+ ['S' = scenarioF],
619
+ [research_policy_match(scenarioF)]).
620
+ step(research_policy_match(scenarioF),
621
+ rule(141),
622
+ ['S' = scenarioF],
623
+ [purpose(scenarioF, healthcareScientificResearch),
624
+ environment(scenarioF, "secure_env"),
625
+ tom(scenarioF, anonymisation),
626
+ subject_opt_in(scenarioF),
627
+ category(scenarioF, labResults)]).
628
+ step(environment(scenarioF, "secure_env"), fact(119), [], []).
629
+ step(tom(scenarioF, anonymisation), fact(120), [], []).
630
+ step(category(scenarioF, labResults), fact(122), [], []).
631
+ step(decision(scenarioD, "DENY"),
632
+ rule(150),
633
+ ['S' = scenarioD],
634
+ [insurance_prohibition_match(scenarioD)]).
635
+ step(insurance_prohibition_match(scenarioD),
636
+ rule(142),
637
+ ['S' = scenarioD],
638
+ [purpose(scenarioD, insuranceManagement),
639
+ prohibitPurpose(policyDenyInsurance, insuranceManagement)]).
640
+ step(purpose(scenarioD, insuranceManagement), fact(98), [], []).
641
+ step(prohibitPurpose(policyDenyInsurance, insuranceManagement), fact(52), [], []).
642
+ step(decision(scenarioG, "DENY"),
643
+ rule(151),
644
+ ['S' = scenarioG],
645
+ [ai_training_opt_out_match(scenarioG)]).
646
+ step(ai_training_opt_out_match(scenarioG),
647
+ rule(143),
648
+ ['S' = scenarioG],
649
+ [purpose(scenarioG, trainTestAndEvaluateAiSystemsAlgorithms), subject_opt_out(scenarioG)]).
650
+ step(decision(scenarioC, "DENY"),
651
+ rule(152),
652
+ [],
653
+ [purpose(scenarioC, ensureQualitySafetyHealthcare)]).
654
+ step(purpose(scenarioC, ensureQualitySafetyHealthcare), fact(88), [], []).
655
+ step(matchedPolicyUid(scenarioA, "urn:policy:primary-care-001"),
656
+ rule(153),
657
+ ['S' = scenarioA, 'Uid' = "urn:policy:primary-care-001"],
658
+ [primary_policy_match(scenarioA), policyUid(policyPrimary, "urn:policy:primary-care-001")]).
659
+ step(policyUid(policyPrimary, "urn:policy:primary-care-001"), fact(28), [], []).
660
+ step(matchedPolicyUid(scenarioE, "urn:policy:primary-care-001"),
661
+ rule(153),
662
+ ['S' = scenarioE, 'Uid' = "urn:policy:primary-care-001"],
663
+ [primary_policy_match(scenarioE), policyUid(policyPrimary, "urn:policy:primary-care-001")]).
664
+ step(matchedPolicyUid(scenarioB, "urn:policy:qi-2025-aurora"),
665
+ rule(154),
666
+ ['S' = scenarioB, 'Uid' = "urn:policy:qi-2025-aurora"],
667
+ [qi_policy_match(scenarioB), policyUid(policyQi, "urn:policy:qi-2025-aurora")]).
668
+ step(policyUid(policyQi, "urn:policy:qi-2025-aurora"), fact(34), [], []).
669
+ step(matchedPolicyUid(scenarioF, "urn:policy:research-aurora-diabetes"),
670
+ rule(155),
671
+ ['S' = scenarioF, 'Uid' = "urn:policy:research-aurora-diabetes"],
672
+ [research_policy_match(scenarioF),
673
+ policyUid(policyResearch, "urn:policy:research-aurora-diabetes")]).
674
+ step(policyUid(policyResearch, "urn:policy:research-aurora-diabetes"), fact(41), [], []).
675
+ step(matchedProhibition(scenarioD, policyDenyInsurance),
676
+ rule(156),
677
+ ['S' = scenarioD],
678
+ [insurance_prohibition_match(scenarioD)]).
679
+ step(reason(scenarioA, "Permitted: clinician in the patient's care team, and the primary-care policy matched."),
680
+ rule(157),
681
+ ['S' = scenarioA],
682
+ [primary_policy_match(scenarioA)]).
683
+ step(reason(scenarioE, "Permitted: clinician in the patient's care team, and the primary-care policy matched."),
684
+ rule(157),
685
+ ['S' = scenarioE],
686
+ [primary_policy_match(scenarioE)]).
687
+ step(reason(scenarioB, "Permitted: ODRL/DPV policy matched for secondary use."),
688
+ rule(158),
689
+ ['S' = scenarioB],
690
+ [qi_policy_match(scenarioB)]).
691
+ step(reason(scenarioF, "Permitted: subject opted in and an ODRL/DPV policy matched (anonymised dataset in secure environment)."),
692
+ rule(159),
693
+ ['S' = scenarioF],
694
+ [research_policy_match(scenarioF)]).
695
+ step(reason(scenarioD, "Denied: the requested purpose (insurance management) is prohibited by policy."),
696
+ rule(160),
697
+ ['S' = scenarioD],
698
+ [insurance_prohibition_match(scenarioD)]).
699
+ step(reason(scenarioG, "Denied: you opted out of your data being used to train AI systems."),
700
+ rule(161),
701
+ ['S' = scenarioG],
702
+ [ai_training_opt_out_match(scenarioG)]).
703
+ step(reason(scenarioC, "Denied: no policy matched (purpose, environment, TOMs, or categories out of scope)."),
704
+ rule(162),
705
+ [],
706
+ [purpose(scenarioC, ensureQualitySafetyHealthcare)]).
707
+ step(trace(scenarioA, "permit:primary_care_allowed"),
708
+ rule(163),
709
+ ['S' = scenarioA],
710
+ [primary_policy_match(scenarioA)]).
711
+ step(trace(scenarioE, "permit:primary_care_allowed"),
712
+ rule(163),
713
+ ['S' = scenarioE],
714
+ [primary_policy_match(scenarioE)]).
715
+ step(trace(scenarioA, "urn:policy:primary-care-001:permit:odrl:permission_matched"),
716
+ rule(164),
717
+ ['S' = scenarioA],
718
+ [primary_policy_match(scenarioA)]).
719
+ step(trace(scenarioE, "urn:policy:primary-care-001:permit:odrl:permission_matched"),
720
+ rule(164),
721
+ ['S' = scenarioE],
722
+ [primary_policy_match(scenarioE)]).
723
+ step(trace(scenarioB, "urn:policy:qi-2025-aurora:permit:odrl:permission_matched"),
724
+ rule(165),
725
+ ['S' = scenarioB],
726
+ [qi_policy_match(scenarioB)]).
727
+ step(trace(scenarioF, "urn:policy:research-aurora-diabetes:permit:odrl:permission_matched"),
728
+ rule(166),
729
+ ['S' = scenarioF],
730
+ [research_policy_match(scenarioF)]).
731
+ step(trace(scenarioD, "deny:prohibited_purpose"),
732
+ rule(167),
733
+ ['S' = scenarioD],
734
+ [insurance_prohibition_match(scenarioD)]).
735
+ step(trace(scenarioD, "urn:policy:deny-insurance:deny:odrl:prohibition_matched"),
736
+ rule(168),
737
+ ['S' = scenarioD],
738
+ [insurance_prohibition_match(scenarioD)]).
739
+ step(trace(scenarioG, "deny:subject_opted_out_ai_training"),
740
+ rule(169),
741
+ ['S' = scenarioG],
742
+ [ai_training_opt_out_match(scenarioG)]).
743
+ step(trace(scenarioC, "urn:policy:qi-2025-aurora:deny:odrl:no_permission_matched"),
744
+ rule(170),
745
+ [],
746
+ [purpose(scenarioC, ensureQualitySafetyHealthcare)]).
747
+ step(checkC1(scenarioA, "SKIPPED - not a prohibited purpose"),
748
+ rule(171),
749
+ [],
750
+ [decision(scenarioA, "PERMIT")]).
751
+ step(checkC1(scenarioB, "SKIPPED - not a prohibited purpose"),
752
+ rule(181),
753
+ [],
754
+ [decision(scenarioB, "PERMIT")]).
755
+ step(checkC1(scenarioC, "SKIPPED - not a prohibited purpose"),
756
+ rule(191),
757
+ [],
758
+ [decision(scenarioC, "DENY")]).
759
+ step(checkC1(scenarioD, "OK - denied prohibited purpose"),
760
+ rule(201),
761
+ [],
762
+ [decision(scenarioD, "DENY")]).
763
+ step(checkC1(scenarioE, "SKIPPED - not a prohibited purpose"),
764
+ rule(211),
765
+ [],
766
+ [decision(scenarioE, "PERMIT")]).
767
+ step(checkC1(scenarioF, "SKIPPED - not a prohibited purpose"),
768
+ rule(221),
769
+ [],
770
+ [decision(scenarioF, "PERMIT")]).
771
+ step(checkC1(scenarioG, "SKIPPED - not a prohibited purpose"),
772
+ rule(231),
773
+ [],
774
+ [decision(scenarioG, "DENY")]).
775
+ step(checkC2(scenarioA, "OK - clinician"), rule(172), [], [decision(scenarioA, "PERMIT")]).
776
+ step(checkC2(scenarioB, "SKIPPED"), rule(182), [], [decision(scenarioB, "PERMIT")]).
777
+ step(checkC2(scenarioC, "SKIPPED"), rule(192), [], [decision(scenarioC, "DENY")]).
778
+ step(checkC2(scenarioD, "SKIPPED"), rule(202), [], [decision(scenarioD, "DENY")]).
779
+ step(checkC2(scenarioE, "OK - clinician"), rule(212), [], [decision(scenarioE, "PERMIT")]).
780
+ step(checkC2(scenarioF, "SKIPPED"), rule(222), [], [decision(scenarioF, "PERMIT")]).
781
+ step(checkC2(scenarioG, "SKIPPED"), rule(232), [], [decision(scenarioG, "DENY")]).
782
+ step(checkC3(scenarioA, "OK - care-team linked"),
783
+ rule(173),
784
+ [],
785
+ [decision(scenarioA, "PERMIT")]).
786
+ step(checkC3(scenarioB, "SKIPPED"), rule(183), [], [decision(scenarioB, "PERMIT")]).
787
+ step(checkC3(scenarioC, "SKIPPED"), rule(193), [], [decision(scenarioC, "DENY")]).
788
+ step(checkC3(scenarioD, "SKIPPED"), rule(203), [], [decision(scenarioD, "DENY")]).
789
+ step(checkC3(scenarioE, "OK - care-team linked"),
790
+ rule(213),
791
+ [],
792
+ [decision(scenarioE, "PERMIT")]).
793
+ step(checkC3(scenarioF, "SKIPPED"), rule(223), [], [decision(scenarioF, "PERMIT")]).
794
+ step(checkC3(scenarioG, "SKIPPED"), rule(233), [], [decision(scenarioG, "DENY")]).
795
+ step(checkC4(scenarioA, "SKIPPED"), rule(174), [], [decision(scenarioA, "PERMIT")]).
796
+ step(checkC4(scenarioB, "OK - opt-in present and policy matched"),
797
+ rule(184),
798
+ [],
799
+ [decision(scenarioB, "PERMIT")]).
800
+ step(checkC4(scenarioC, "OK - denied because opt-in missing or no policy match"),
801
+ rule(194),
802
+ [],
803
+ [decision(scenarioC, "DENY")]).
804
+ step(checkC4(scenarioD, "SKIPPED"), rule(204), [], [decision(scenarioD, "DENY")]).
805
+ step(checkC4(scenarioE, "SKIPPED"), rule(214), [], [decision(scenarioE, "PERMIT")]).
806
+ step(checkC4(scenarioF, "OK - opt-in present and policy matched"),
807
+ rule(224),
808
+ [],
809
+ [decision(scenarioF, "PERMIT")]).
810
+ step(checkC4(scenarioG, "OK - denied because opt-in missing or no policy match"),
811
+ rule(234),
812
+ [],
813
+ [decision(scenarioG, "DENY")]).
814
+ step(checkC5(scenarioA, "OK - operator=isAnyOf, allowed=[\"https://example.org/health#PATIENT_SUMMARY\", \"https://example.org/health#LAB_RESULTS\"], requested=[\"https://example.org/health#PATIENT_SUMMARY\"]"),
815
+ rule(175),
816
+ [],
817
+ [decision(scenarioA, "PERMIT")]).
818
+ step(checkC5(scenarioB, "OK - operator=isAllOf, allowed=[\"https://example.org/health#LAB_RESULTS\", \"https://example.org/health#PATIENT_SUMMARY\"], requested=[\"https://example.org/health#LAB_RESULTS\", \"https://example.org/health#PATIENT_SUMMARY\"]"),
819
+ rule(185),
820
+ [],
821
+ [decision(scenarioB, "PERMIT")]).
822
+ step(checkC5(scenarioC, "SKIPPED"), rule(195), [], [decision(scenarioC, "DENY")]).
823
+ step(checkC5(scenarioD, "SKIPPED"), rule(205), [], [decision(scenarioD, "DENY")]).
824
+ step(checkC5(scenarioE, "OK - operator=isAnyOf, allowed=[\"https://example.org/health#PATIENT_SUMMARY\", \"https://example.org/health#LAB_RESULTS\"], requested=[\"https://example.org/health#LAB_RESULTS\"]"),
825
+ rule(215),
826
+ [],
827
+ [decision(scenarioE, "PERMIT")]).
828
+ step(checkC5(scenarioF, "OK - operator=isAnyOf, allowed=[\"https://example.org/health#LAB_RESULTS\", \"https://example.org/health#PATIENT_SUMMARY\", \"https://example.org/health#IMAGING_REPORT\"], requested=[\"https://example.org/health#PATIENT_SUMMARY\", \"https://example.org/health#LAB_RESULTS\"]"),
829
+ rule(225),
830
+ [],
831
+ [decision(scenarioF, "PERMIT")]).
832
+ step(checkC5(scenarioG, "SKIPPED"), rule(235), [], [decision(scenarioG, "DENY")]).
833
+ step(checkC6(scenarioA, "SKIPPED - no prohibition matched"),
834
+ rule(176),
835
+ [],
836
+ [decision(scenarioA, "PERMIT")]).
837
+ step(checkC6(scenarioB, "SKIPPED - no prohibition matched"),
838
+ rule(186),
839
+ [],
840
+ [decision(scenarioB, "PERMIT")]).
841
+ step(checkC6(scenarioC, "SKIPPED - no prohibition matched"),
842
+ rule(196),
843
+ [],
844
+ [decision(scenarioC, "DENY")]).
845
+ step(checkC6(scenarioD, "OK - denied due to prohibition"),
846
+ rule(206),
847
+ [],
848
+ [decision(scenarioD, "DENY")]).
849
+ step(checkC6(scenarioE, "SKIPPED - no prohibition matched"),
850
+ rule(216),
851
+ [],
852
+ [decision(scenarioE, "PERMIT")]).
853
+ step(checkC6(scenarioF, "SKIPPED - no prohibition matched"),
854
+ rule(226),
855
+ [],
856
+ [decision(scenarioF, "PERMIT")]).
857
+ step(checkC6(scenarioG, "SKIPPED - no prohibition matched"),
858
+ rule(236),
859
+ [],
860
+ [decision(scenarioG, "DENY")]).
861
+ step(checkC7(scenarioA, "OK - trace shows matching permission"),
862
+ rule(177),
863
+ [],
864
+ [decision(scenarioA, "PERMIT")]).
865
+ step(checkC7(scenarioB, "OK - trace shows matching permission"),
866
+ rule(187),
867
+ [],
868
+ [decision(scenarioB, "PERMIT")]).
869
+ step(checkC7(scenarioC, "SKIPPED"), rule(197), [], [decision(scenarioC, "DENY")]).
870
+ step(checkC7(scenarioD, "SKIPPED"), rule(207), [], [decision(scenarioD, "DENY")]).
871
+ step(checkC7(scenarioE, "OK - trace shows matching permission"),
872
+ rule(217),
873
+ [],
874
+ [decision(scenarioE, "PERMIT")]).
875
+ step(checkC7(scenarioF, "OK - trace shows matching permission"),
876
+ rule(227),
877
+ [],
878
+ [decision(scenarioF, "PERMIT")]).
879
+ step(checkC7(scenarioG, "SKIPPED"), rule(237), [], [decision(scenarioG, "DENY")]).
880
+ step(checkC8(scenarioA, "SKIPPED - no matched policy or no duties"),
881
+ rule(178),
882
+ [],
883
+ [decision(scenarioA, "PERMIT")]).
884
+ step(checkC8(scenarioB, "INFO - duties attached: duty:https://w3id.org/dpv/legal/eu/ehds#requireConsent, duty:https://w3id.org/dpv/legal/eu/ehds#noExfiltration"),
885
+ rule(188),
886
+ [],
887
+ [decision(scenarioB, "PERMIT")]).
888
+ step(checkC8(scenarioC, "SKIPPED - no matched policy or no duties"),
889
+ rule(198),
890
+ [],
891
+ [decision(scenarioC, "DENY")]).
892
+ step(checkC8(scenarioD, "SKIPPED - no matched policy or no duties"),
893
+ rule(208),
894
+ [],
895
+ [decision(scenarioD, "DENY")]).
896
+ step(checkC8(scenarioE, "SKIPPED - no matched policy or no duties"),
897
+ rule(218),
898
+ [],
899
+ [decision(scenarioE, "PERMIT")]).
900
+ step(checkC8(scenarioF, "INFO - duties attached: duty:https://w3id.org/dpv/legal/eu/ehds#annualOutcomeReport, duty:https://w3id.org/dpv/legal/eu/ehds#noReidentification, duty:https://w3id.org/dpv/legal/eu/ehds#noExfiltration"),
901
+ rule(228),
902
+ [],
903
+ [decision(scenarioF, "PERMIT")]).
904
+ step(checkC8(scenarioG, "SKIPPED - no matched policy or no duties"),
905
+ rule(238),
906
+ [],
907
+ [decision(scenarioG, "DENY")]).
908
+ step(checkC9(scenarioA, "SKIPPED - policy has no environment constraint"),
909
+ rule(179),
910
+ [],
911
+ [decision(scenarioA, "PERMIT")]).
912
+ step(checkC9(scenarioB, "OK - operator=eq, allowed=\"secure_env\", requested=\"secure_env\""),
913
+ rule(189),
914
+ [],
915
+ [decision(scenarioB, "PERMIT")]).
916
+ step(checkC9(scenarioC, "SKIPPED"), rule(199), [], [decision(scenarioC, "DENY")]).
917
+ step(checkC9(scenarioD, "SKIPPED"), rule(209), [], [decision(scenarioD, "DENY")]).
918
+ step(checkC9(scenarioE, "SKIPPED - policy has no environment constraint"),
919
+ rule(219),
920
+ [],
921
+ [decision(scenarioE, "PERMIT")]).
922
+ step(checkC9(scenarioF, "OK - operator=eq, allowed=\"secure_env\", requested=\"secure_env\""),
923
+ rule(229),
924
+ [],
925
+ [decision(scenarioF, "PERMIT")]).
926
+ step(checkC9(scenarioG, "SKIPPED"), rule(239), [], [decision(scenarioG, "DENY")]).
927
+ step(checkC10Text(scenarioA, "INFO - matched policy: urn:policy:primary-care-001"),
928
+ rule(180),
929
+ [],
930
+ [decision(scenarioA, "PERMIT")]).
931
+ step(checkC10Text(scenarioB, "INFO - matched policy: urn:policy:qi-2025-aurora"),
932
+ rule(190),
933
+ [],
934
+ [decision(scenarioB, "PERMIT")]).
935
+ step(checkC10Text(scenarioC, "SKIPPED - no matched policy"),
936
+ rule(200),
937
+ [],
938
+ [decision(scenarioC, "DENY")]).
939
+ step(checkC10Text(scenarioD, "SKIPPED - no matched policy"),
940
+ rule(210),
941
+ [],
942
+ [decision(scenarioD, "DENY")]).
943
+ step(checkC10Text(scenarioE, "INFO - matched policy: urn:policy:primary-care-001"),
944
+ rule(220),
945
+ [],
946
+ [decision(scenarioE, "PERMIT")]).
947
+ step(checkC10Text(scenarioF, "INFO - matched policy: urn:policy:research-aurora-diabetes"),
948
+ rule(230),
949
+ [],
950
+ [decision(scenarioF, "PERMIT")]).
951
+ step(checkC10Text(scenarioG, "SKIPPED - no matched policy"),
952
+ rule(240),
953
+ [],
954
+ [decision(scenarioG, "DENY")]).