eyeling 1.16.3 → 1.16.5
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 +153 -0
- package/README.md +0 -1
- package/examples/auroracare.n3 +528 -0
- package/examples/control-system.n3 +223 -47
- package/examples/delfour.n3 +409 -0
- package/examples/gps.n3 +144 -53
- package/examples/ill-formed-literals.n3 +195 -0
- package/examples/output/auroracare.n3 +118 -0
- package/examples/output/control-system.n3 +24 -1
- package/examples/output/delfour.n3 +40 -0
- package/examples/output/gps.n3 +14 -2
- package/examples/output/ill-formed-literals.n3 +27 -0
- package/examples/output/parcellocker.n3 +15 -0
- package/examples/parcellocker.n3 +164 -0
- package/eyeling.js +16 -1
- package/lib/engine.js +14 -1
- package/lib/prelude.js +2 -0
- package/package.json +2 -3
- package/arctifacts/README.md +0 -59
- package/arctifacts/ackermann.html +0 -678
- package/arctifacts/auroracare.html +0 -1297
- package/arctifacts/bike-trip.html +0 -752
- package/arctifacts/binomial-theorem.html +0 -631
- package/arctifacts/bmi.html +0 -511
- package/arctifacts/building-performance.html +0 -750
- package/arctifacts/clinical-care.html +0 -726
- package/arctifacts/collatz.html +0 -403
- package/arctifacts/complex.html +0 -321
- package/arctifacts/control-system.html +0 -482
- package/arctifacts/delfour.html +0 -849
- package/arctifacts/earthquake-epicenter.html +0 -982
- package/arctifacts/eco-route.html +0 -662
- package/arctifacts/euclid-infinitude.html +0 -564
- package/arctifacts/euler-identity.html +0 -667
- package/arctifacts/exoplanet-transit.html +0 -1000
- package/arctifacts/faltings-theorem.html +0 -1046
- package/arctifacts/fibonacci.html +0 -299
- package/arctifacts/fundamental-theorem-arithmetic.html +0 -398
- package/arctifacts/godel-numbering.html +0 -743
- package/arctifacts/gps-bike.html +0 -759
- package/arctifacts/gps-clinical-bench.html +0 -792
- package/arctifacts/graph-french.html +0 -449
- package/arctifacts/grass-molecular.html +0 -592
- package/arctifacts/group-theory.html +0 -740
- package/arctifacts/health-info.html +0 -833
- package/arctifacts/kaprekar-constant.html +0 -576
- package/arctifacts/lee.html +0 -805
- package/arctifacts/linked-lists.html +0 -502
- package/arctifacts/lldm.html +0 -612
- package/arctifacts/matrix-multiplication.html +0 -502
- package/arctifacts/matrix.html +0 -651
- package/arctifacts/newton-raphson.html +0 -944
- package/arctifacts/peano-factorial.html +0 -456
- package/arctifacts/pi.html +0 -363
- package/arctifacts/polynomial.html +0 -646
- package/arctifacts/prime.html +0 -366
- package/arctifacts/pythagorean-theorem.html +0 -468
- package/arctifacts/rest-path.html +0 -469
- package/arctifacts/roots-of-unity.html +0 -363
- package/arctifacts/turing.html +0 -409
- package/arctifacts/wind-turbines.html +0 -726
package/HANDBOOK.md
CHANGED
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
- [Appendix C — N3 beyond Prolog: logic that survives the open web](#app-c)
|
|
31
31
|
- [Appendix D — LLM + Eyeling: A Repeatable Logic Toolchain](#app-d)
|
|
32
32
|
- [Appendix E — How Eyeling reaches 100% on `notation3tests`](#app-e)
|
|
33
|
+
- [Appendix F — The ARC approach: Answer • Reason Why • Check](#app-f)
|
|
33
34
|
|
|
34
35
|
---
|
|
35
36
|
|
|
@@ -2576,3 +2577,155 @@ That is the method:
|
|
|
2576
2577
|
- duplicate-safe fixpoint closure
|
|
2577
2578
|
|
|
2578
2579
|
That is why the result is 100%.
|
|
2580
|
+
|
|
2581
|
+
---
|
|
2582
|
+
|
|
2583
|
+
<a id="app-f"></a>
|
|
2584
|
+
|
|
2585
|
+
## Appendix F — The ARC approach: Answer • Reason Why • Check
|
|
2586
|
+
|
|
2587
|
+
A useful way to structure an Eyeling program is the ARC approach:
|
|
2588
|
+
|
|
2589
|
+
> Answer • Reason Why • Check
|
|
2590
|
+
|
|
2591
|
+
The idea is simple: do not stop at producing a result. Produce the result, explain why it is the right result, and include a concrete verification that fails loudly when an important assumption does not hold.
|
|
2592
|
+
|
|
2593
|
+
ARC treats a program as a small, accountable artifact built from three ingredients:
|
|
2594
|
+
|
|
2595
|
+
1. Data
|
|
2596
|
+
2. Logic
|
|
2597
|
+
3. A Question
|
|
2598
|
+
|
|
2599
|
+
From these, we build a compact program that answers the question, explains the answer, and checks itself.
|
|
2600
|
+
|
|
2601
|
+
### F.1 The three parts
|
|
2602
|
+
|
|
2603
|
+
#### Answer
|
|
2604
|
+
|
|
2605
|
+
The **Answer** is the direct response to the question being asked.
|
|
2606
|
+
|
|
2607
|
+
It should be short, specific, and easy to read. In Eyeling, this is often emitted as one or more `log:outputString` lines such as:
|
|
2608
|
+
|
|
2609
|
+
- the final decision
|
|
2610
|
+
- the selected item
|
|
2611
|
+
- the computed value
|
|
2612
|
+
- the resulting classification
|
|
2613
|
+
|
|
2614
|
+
A good Answer reads like something you could show to a user, an auditor, or a calling program.
|
|
2615
|
+
|
|
2616
|
+
#### Reason Why
|
|
2617
|
+
|
|
2618
|
+
The **Reason Why** explains why the Answer is correct.
|
|
2619
|
+
|
|
2620
|
+
This is not a full proof calculus or a hidden chain of thought. It is a concise, inspectable explanation grounded in the facts, rules, thresholds, identities, or policies that matter for the case. In practice, it often includes:
|
|
2621
|
+
|
|
2622
|
+
- the relevant inputs
|
|
2623
|
+
- the governing rule or policy
|
|
2624
|
+
- the key intermediate facts
|
|
2625
|
+
- the condition that made the conclusion follow
|
|
2626
|
+
|
|
2627
|
+
In Eyeling, the Reason Why is usually rendered as additional `log:outputString` lines derived from the same closure as the Answer.
|
|
2628
|
+
|
|
2629
|
+
#### Check
|
|
2630
|
+
|
|
2631
|
+
The **Check** is an independent validation step.
|
|
2632
|
+
|
|
2633
|
+
Its purpose is not to restate the Answer, but to test that important invariants still hold. A Check should fail loudly if the program’s assumptions break, if a data dependency is malformed, or if an edge case invalidates the intended conclusion.
|
|
2634
|
+
|
|
2635
|
+
In Eyeling, Checks are a natural fit for either:
|
|
2636
|
+
|
|
2637
|
+
- derived facts such as `:ok :signatureVerified true .`, or
|
|
2638
|
+
- inference fuses such as `{ ... } => false .` when a violation must stop execution.
|
|
2639
|
+
|
|
2640
|
+
This makes verification part of the program itself rather than something left to external commentary.
|
|
2641
|
+
|
|
2642
|
+
### F.2 Proof = Reason Why + Check
|
|
2643
|
+
|
|
2644
|
+
ARC summarizes its trust model as:
|
|
2645
|
+
|
|
2646
|
+
> Proof = Reason Why + Check
|
|
2647
|
+
|
|
2648
|
+
That is a practical notion of proof. The Reason Why explains the logic in human terms. The Check verifies that the critical conditions actually hold at runtime.
|
|
2649
|
+
|
|
2650
|
+
For many real workflows, that combination is more useful than a bare result: it is inspectable, repeatable, and suitable for automation.
|
|
2651
|
+
|
|
2652
|
+
### F.3 Why ARC fits Eyeling well
|
|
2653
|
+
|
|
2654
|
+
Eyeling already encourages the separation that ARC needs.
|
|
2655
|
+
|
|
2656
|
+
Rules derive facts. Facts can include output facts. Output is not printed eagerly during proof search; instead, `log:outputString` facts are collected from the final closure and rendered deterministically, for example with `-r` / `--strings`. This makes it natural to derive a structured Answer and Reason Why as part of the logic itself.
|
|
2657
|
+
|
|
2658
|
+
Checks also map well to Eyeling. A rule with conclusion `false` acts as an inference fuse: if its body becomes provable, execution stops with a hard failure. This is exactly the behavior we want for “must-hold” conditions.
|
|
2659
|
+
|
|
2660
|
+
So ARC in Eyeling is not an add-on. It is mostly a disciplined way of organizing what Eyeling already does well: derive conclusions, expose supporting facts, and enforce invariants.
|
|
2661
|
+
|
|
2662
|
+
### F.4 A practical pattern
|
|
2663
|
+
|
|
2664
|
+
A simple ARC-oriented Eyeling file often has four layers:
|
|
2665
|
+
|
|
2666
|
+
1. **Facts**
|
|
2667
|
+
Input data, parameters, policies, and known relationships.
|
|
2668
|
+
|
|
2669
|
+
2. **Logic**
|
|
2670
|
+
Rules that derive the program’s internal conclusions.
|
|
2671
|
+
|
|
2672
|
+
3. **Presentation**
|
|
2673
|
+
Rules that turn derived conclusions into `log:outputString` lines for the Answer and Reason Why.
|
|
2674
|
+
|
|
2675
|
+
4. **Verification**
|
|
2676
|
+
Rules that derive check facts or trigger inference fuses on violations.
|
|
2677
|
+
|
|
2678
|
+
A useful habit is to keep these layers visually separate in the file.
|
|
2679
|
+
|
|
2680
|
+
### F.5 A tiny template
|
|
2681
|
+
|
|
2682
|
+
```n3
|
|
2683
|
+
@prefix : <http://example.org/> .
|
|
2684
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#> .
|
|
2685
|
+
|
|
2686
|
+
# Facts
|
|
2687
|
+
:case :input 42 .
|
|
2688
|
+
|
|
2689
|
+
# Logic
|
|
2690
|
+
{ :case :input ?n . ?n math:greaterThan 10 . }
|
|
2691
|
+
=> { :case :decision "allowed" . } .
|
|
2692
|
+
|
|
2693
|
+
# Answer
|
|
2694
|
+
{ :case :decision ?d . }
|
|
2695
|
+
=> { :answer log:outputString "Answer\n" .
|
|
2696
|
+
:answer log:outputString ?d . } .
|
|
2697
|
+
|
|
2698
|
+
# Reason Why
|
|
2699
|
+
{ :case :input ?n . :case :decision ?d . }
|
|
2700
|
+
=> { :why log:outputString "\nReason Why\n" .
|
|
2701
|
+
:why log:outputString "Input satisfied the rule threshold.\n" . } .
|
|
2702
|
+
|
|
2703
|
+
# Check
|
|
2704
|
+
{ :case :decision "allowed" .
|
|
2705
|
+
:case :input ?n .
|
|
2706
|
+
?n math:notGreaterThan 10 . }
|
|
2707
|
+
=> false .
|
|
2708
|
+
```
|
|
2709
|
+
|
|
2710
|
+
The exact presentation style can vary, but the shape remains the same: derive the result, explain the result, and verify the result.
|
|
2711
|
+
|
|
2712
|
+
### F.6 What ARC is not
|
|
2713
|
+
|
|
2714
|
+
ARC does **not** mean:
|
|
2715
|
+
|
|
2716
|
+
- printing a result and calling it explained
|
|
2717
|
+
- replacing checks with prose
|
|
2718
|
+
- hiding the important assumptions
|
|
2719
|
+
- relying on “trust me” comments outside the executable artifact
|
|
2720
|
+
|
|
2721
|
+
A file follows ARC only when the answer, explanation, and validation are all carried by the program itself.
|
|
2722
|
+
|
|
2723
|
+
### F.7 A good default for examples
|
|
2724
|
+
|
|
2725
|
+
For worked examples in this handbook, ARC is a strong default presentation style:
|
|
2726
|
+
|
|
2727
|
+
- **Answer** for the main result
|
|
2728
|
+
- **Reason Why** for the key supporting explanation
|
|
2729
|
+
- **Check** for invariants and fail-loud validation
|
|
2730
|
+
|
|
2731
|
+
This keeps examples readable for newcomers while also making them more useful as reusable, auditable logic artifacts.
|
package/README.md
CHANGED
|
@@ -15,7 +15,6 @@ A compact [Notation3 (N3)](https://notation3.org/) reasoner in **JavaScript**.
|
|
|
15
15
|
- **Semantics:** [https://eyereasoner.github.io/eyeling/SEMANTICS](https://eyereasoner.github.io/eyeling/SEMANTICS)
|
|
16
16
|
- **Playground:** [https://eyereasoner.github.io/eyeling/demo](https://eyereasoner.github.io/eyeling/demo)
|
|
17
17
|
- **Conformance report:** [https://codeberg.org/phochste/notation3tests/src/branch/main/reports/report.md](https://codeberg.org/phochste/notation3tests/src/branch/main/reports/report.md)
|
|
18
|
-
- **ARCtifacts:** [https://eyereasoner.github.io/eyeling/arctifacts/](https://eyereasoner.github.io/eyeling/arctifacts/)
|
|
19
18
|
|
|
20
19
|
Eyeling is regularly checked against the community Notation3 test suite. If you want implementation details (parser, unifier, proof search, skolemization, scoped closure, builtins), start with the handbook.
|
|
21
20
|
|
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# AuroraCare — ARC "Purpose-based Medical Data Exchange" example.
|
|
3
|
+
#
|
|
4
|
+
# This example shows how medical data access can be governed by purpose.
|
|
5
|
+
# Different people may request the same data, but access depends on why they
|
|
6
|
+
# need it, what role they have, and whether extra conditions are met. Care-team
|
|
7
|
+
# treatment use may be allowed, for instance, while unrelated uses such as
|
|
8
|
+
# marketing, employment screening, or broad insurance access can be denied.
|
|
9
|
+
# =============================================================================
|
|
10
|
+
|
|
11
|
+
@prefix : <https://example.org/auroracare#> .
|
|
12
|
+
@prefix arc: <https://josd.github.io/arc/terms#> .
|
|
13
|
+
@prefix odrl: <http://www.w3.org/ns/odrl/2/> .
|
|
14
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#> .
|
|
15
|
+
@prefix string: <http://www.w3.org/2000/10/swap/string#> .
|
|
16
|
+
@prefix dpv: <https://w3id.org/dpv#> .
|
|
17
|
+
@prefix ehds: <https://w3id.org/dpv/legal/eu/ehds#> .
|
|
18
|
+
@prefix hlth: <https://w3id.org/dpv/sector/health#> .
|
|
19
|
+
@prefix ex: <https://example.org/health#> .
|
|
20
|
+
@prefix ac: <https://example.org/auroracare#> .
|
|
21
|
+
|
|
22
|
+
# -----
|
|
23
|
+
# Facts
|
|
24
|
+
# -----
|
|
25
|
+
|
|
26
|
+
:case
|
|
27
|
+
a arc:Case ;
|
|
28
|
+
arc:question "For each AuroraCare scenario, should the PDP permit or deny the requested use of health data, and why?" .
|
|
29
|
+
|
|
30
|
+
:policy_primary
|
|
31
|
+
a odrl:Policy ;
|
|
32
|
+
:uid "urn:policy:primary-care-001" ;
|
|
33
|
+
:purposeAllowed hlth:PrimaryCareManagement, hlth:PatientRemoteMonitoring ;
|
|
34
|
+
:roleAllowed "clinician" ;
|
|
35
|
+
:allowAnyCategory ex:PATIENT_SUMMARY, ex:LAB_RESULTS .
|
|
36
|
+
|
|
37
|
+
:policy_qi
|
|
38
|
+
a odrl:Policy ;
|
|
39
|
+
:uid "urn:policy:qi-2025-aurora" ;
|
|
40
|
+
:purposeAllowed ehds:EnsureQualitySafetyHealthcare ;
|
|
41
|
+
:requireEnvironment "secure_env" ;
|
|
42
|
+
:requireAllCategory ex:LAB_RESULTS, ex:PATIENT_SUMMARY ;
|
|
43
|
+
:duty ehds:requireConsent, ehds:noExfiltration .
|
|
44
|
+
|
|
45
|
+
:policy_research
|
|
46
|
+
a odrl:Policy ;
|
|
47
|
+
:uid "urn:policy:research-aurora-diabetes" ;
|
|
48
|
+
:purposeAllowed ehds:HealthcareScientificResearch ;
|
|
49
|
+
:requireEnvironment "secure_env" ;
|
|
50
|
+
:requireTom dpv:Anonymisation ;
|
|
51
|
+
:allowAnyCategory ex:LAB_RESULTS, ex:PATIENT_SUMMARY, ex:IMAGING_REPORT ;
|
|
52
|
+
:duty ehds:annualOutcomeReport, ehds:noReidentification, ehds:noExfiltration .
|
|
53
|
+
|
|
54
|
+
:policy_deny_insurance
|
|
55
|
+
a odrl:Policy ;
|
|
56
|
+
:uid "urn:policy:deny-insurance" ;
|
|
57
|
+
:prohibitPurpose hlth:InsuranceManagement .
|
|
58
|
+
|
|
59
|
+
:clinician_alba :linkedTo :ruben .
|
|
60
|
+
:gp_ruben :linkedTo :ruben .
|
|
61
|
+
|
|
62
|
+
:ruben :consentAllow ehds:HealthcareScientificResearch .
|
|
63
|
+
:ruben :consentDeny ehds:TrainTestAndEvaluateAISystemsAlgorithms .
|
|
64
|
+
|
|
65
|
+
:auroracare
|
|
66
|
+
:primaryPurpose hlth:PrimaryCareManagement, hlth:PatientRemoteMonitoring ;
|
|
67
|
+
:prohibitedPurpose hlth:InsuranceManagement .
|
|
68
|
+
|
|
69
|
+
:scenario_A
|
|
70
|
+
a :Scenario ;
|
|
71
|
+
:outputKey :out_010_A ;
|
|
72
|
+
:label "A – Primary care visit" ;
|
|
73
|
+
:description "Clinician in the patient's care team accessing the patient summary for primary care management." ;
|
|
74
|
+
:requester :clinician_alba ;
|
|
75
|
+
:requesterRole "clinician" ;
|
|
76
|
+
:subject :ruben ;
|
|
77
|
+
:purpose hlth:PrimaryCareManagement ;
|
|
78
|
+
:environment "api_gateway" ;
|
|
79
|
+
:category ex:PATIENT_SUMMARY .
|
|
80
|
+
|
|
81
|
+
:scenario_B
|
|
82
|
+
a :Scenario ;
|
|
83
|
+
:outputKey :out_020_B ;
|
|
84
|
+
:label "B – Quality improvement (in scope)" ;
|
|
85
|
+
:description "QI analyst using lab results + summary in a secure environment." ;
|
|
86
|
+
:requester :qi_analyst ;
|
|
87
|
+
:requesterRole "data_user" ;
|
|
88
|
+
:subject :ruben ;
|
|
89
|
+
:purpose ehds:EnsureQualitySafetyHealthcare ;
|
|
90
|
+
:environment "secure_env" ;
|
|
91
|
+
:category ex:LAB_RESULTS, ex:PATIENT_SUMMARY .
|
|
92
|
+
|
|
93
|
+
:scenario_C
|
|
94
|
+
a :Scenario ;
|
|
95
|
+
:outputKey :out_030_C ;
|
|
96
|
+
:label "C – Quality improvement (out of scope)" ;
|
|
97
|
+
:description "QI analyst with only lab results; policy expects labs + summary." ;
|
|
98
|
+
:requester :qi_analyst ;
|
|
99
|
+
:requesterRole "data_user" ;
|
|
100
|
+
:subject :ruben ;
|
|
101
|
+
:purpose ehds:EnsureQualitySafetyHealthcare ;
|
|
102
|
+
:environment "secure_env" ;
|
|
103
|
+
:category ex:LAB_RESULTS .
|
|
104
|
+
|
|
105
|
+
:scenario_D
|
|
106
|
+
a :Scenario ;
|
|
107
|
+
:outputKey :out_040_D ;
|
|
108
|
+
:label "D – Insurance management" ;
|
|
109
|
+
:description "Insurance bot attempting to use health data for insurance management (prohibited purpose)." ;
|
|
110
|
+
:requester :insurer_bot ;
|
|
111
|
+
:requesterRole "data_user" ;
|
|
112
|
+
:subject :ruben ;
|
|
113
|
+
:purpose hlth:InsuranceManagement ;
|
|
114
|
+
:environment "secure_env" ;
|
|
115
|
+
:category ex:PATIENT_SUMMARY .
|
|
116
|
+
|
|
117
|
+
:scenario_E
|
|
118
|
+
a :Scenario ;
|
|
119
|
+
:outputKey :out_050_E ;
|
|
120
|
+
:label "E – GP checks labs" ;
|
|
121
|
+
:description "GP for the same patient checking lab results via the API gateway." ;
|
|
122
|
+
:requester :gp_ruben ;
|
|
123
|
+
:requesterRole "clinician" ;
|
|
124
|
+
:subject :ruben ;
|
|
125
|
+
:purpose hlth:PrimaryCareManagement ;
|
|
126
|
+
:environment "api_gateway" ;
|
|
127
|
+
:category ex:LAB_RESULTS .
|
|
128
|
+
|
|
129
|
+
:scenario_F
|
|
130
|
+
a :Scenario ;
|
|
131
|
+
:outputKey :out_060_F ;
|
|
132
|
+
:label "F – Research on anonymised dataset" ;
|
|
133
|
+
:description "Researcher using anonymised labs + summary in a secure environment, with opt-in." ;
|
|
134
|
+
:requester :researcher_aurora ;
|
|
135
|
+
:requesterRole "data_user" ;
|
|
136
|
+
:subject :ruben ;
|
|
137
|
+
:purpose ehds:HealthcareScientificResearch ;
|
|
138
|
+
:environment "secure_env" ;
|
|
139
|
+
:tom dpv:Anonymisation ;
|
|
140
|
+
:category ex:PATIENT_SUMMARY, ex:LAB_RESULTS .
|
|
141
|
+
|
|
142
|
+
:scenario_G
|
|
143
|
+
a :Scenario ;
|
|
144
|
+
:outputKey :out_070_G ;
|
|
145
|
+
:label "G – AI training (opt-out)" ;
|
|
146
|
+
:description "Data user wants to train AI, but the subject opted out of AI training." ;
|
|
147
|
+
:requester :ml_ops ;
|
|
148
|
+
:requesterRole "data_user" ;
|
|
149
|
+
:subject :ruben ;
|
|
150
|
+
:purpose ehds:TrainTestAndEvaluateAISystemsAlgorithms ;
|
|
151
|
+
:environment "secure_env" ;
|
|
152
|
+
:category ex:PATIENT_SUMMARY, ex:LAB_RESULTS .
|
|
153
|
+
|
|
154
|
+
# -----
|
|
155
|
+
# Logic
|
|
156
|
+
# -----
|
|
157
|
+
|
|
158
|
+
{
|
|
159
|
+
?scenario :requester ?requester ;
|
|
160
|
+
:subject ?subject .
|
|
161
|
+
?requester :linkedTo ?subject .
|
|
162
|
+
} => {
|
|
163
|
+
?scenario :careTeamLinked "yes" .
|
|
164
|
+
} .
|
|
165
|
+
|
|
166
|
+
{
|
|
167
|
+
?scenario :subject ?subject ;
|
|
168
|
+
:purpose ?purpose .
|
|
169
|
+
?subject :consentAllow ?purpose .
|
|
170
|
+
} => {
|
|
171
|
+
?scenario :subjectOptIn "yes" .
|
|
172
|
+
} .
|
|
173
|
+
|
|
174
|
+
{
|
|
175
|
+
?scenario :subject ?subject ;
|
|
176
|
+
:purpose ?purpose .
|
|
177
|
+
?subject :consentDeny ?purpose .
|
|
178
|
+
} => {
|
|
179
|
+
?scenario :subjectOptOut "yes" .
|
|
180
|
+
} .
|
|
181
|
+
|
|
182
|
+
{
|
|
183
|
+
?scenario :purpose hlth:PrimaryCareManagement ;
|
|
184
|
+
:requesterRole "clinician" ;
|
|
185
|
+
:careTeamLinked "yes" ;
|
|
186
|
+
:category ?category .
|
|
187
|
+
:policy_primary :allowAnyCategory ?category .
|
|
188
|
+
} => {
|
|
189
|
+
?scenario :matchedPolicy :policy_primary ;
|
|
190
|
+
:matchedPolicyUid "urn:policy:primary-care-001" ;
|
|
191
|
+
:decision "PERMIT" ;
|
|
192
|
+
:reason "Permitted: clinician in the patient's care team, and the primary-care policy matched." ;
|
|
193
|
+
:trace "permit:primary_care_allowed" ;
|
|
194
|
+
:trace "urn:policy:primary-care-001:permit:odrl:permission_matched" .
|
|
195
|
+
} .
|
|
196
|
+
|
|
197
|
+
{
|
|
198
|
+
?scenario :purpose ehds:EnsureQualitySafetyHealthcare ;
|
|
199
|
+
:environment "secure_env" ;
|
|
200
|
+
:category ex:LAB_RESULTS, ex:PATIENT_SUMMARY .
|
|
201
|
+
} => {
|
|
202
|
+
?scenario :matchedPolicy :policy_qi ;
|
|
203
|
+
:matchedPolicyUid "urn:policy:qi-2025-aurora" ;
|
|
204
|
+
:decision "PERMIT" ;
|
|
205
|
+
:reason "Permitted: ODRL/DPV policy matched for secondary use." ;
|
|
206
|
+
:trace "urn:policy:qi-2025-aurora:permit:odrl:permission_matched" .
|
|
207
|
+
} .
|
|
208
|
+
|
|
209
|
+
{
|
|
210
|
+
?scenario :purpose ehds:HealthcareScientificResearch ;
|
|
211
|
+
:environment "secure_env" ;
|
|
212
|
+
:tom dpv:Anonymisation ;
|
|
213
|
+
:subjectOptIn "yes" ;
|
|
214
|
+
:category ?category .
|
|
215
|
+
:policy_research :allowAnyCategory ?category .
|
|
216
|
+
} => {
|
|
217
|
+
?scenario :matchedPolicy :policy_research ;
|
|
218
|
+
:matchedPolicyUid "urn:policy:research-aurora-diabetes" ;
|
|
219
|
+
:decision "PERMIT" ;
|
|
220
|
+
:reason "Permitted: subject opted in and an ODRL/DPV policy matched (anonymised dataset in secure environment)." ;
|
|
221
|
+
:trace "urn:policy:research-aurora-diabetes:permit:odrl:permission_matched" .
|
|
222
|
+
} .
|
|
223
|
+
|
|
224
|
+
{
|
|
225
|
+
?scenario :purpose hlth:InsuranceManagement .
|
|
226
|
+
} => {
|
|
227
|
+
?scenario :matchedProhibition :policy_deny_insurance ;
|
|
228
|
+
:decision "DENY" ;
|
|
229
|
+
:reason "Denied: the requested purpose (insurance management) is prohibited by policy." ;
|
|
230
|
+
:trace "deny:prohibited_purpose" ;
|
|
231
|
+
:trace "urn:policy:deny-insurance:deny:odrl:prohibition_matched" .
|
|
232
|
+
} .
|
|
233
|
+
|
|
234
|
+
{
|
|
235
|
+
?scenario :purpose ehds:TrainTestAndEvaluateAISystemsAlgorithms ;
|
|
236
|
+
:subjectOptOut "yes" .
|
|
237
|
+
} => {
|
|
238
|
+
?scenario :decision "DENY" ;
|
|
239
|
+
:reason "Denied: you opted out of your data being used to train AI systems." ;
|
|
240
|
+
:trace "deny:subject_opted_out_ai_training" .
|
|
241
|
+
} .
|
|
242
|
+
|
|
243
|
+
{
|
|
244
|
+
:scenario_C :purpose ehds:EnsureQualitySafetyHealthcare .
|
|
245
|
+
} => {
|
|
246
|
+
:scenario_C :decision "DENY" ;
|
|
247
|
+
:reason "Denied: no policy matched (purpose, environment, TOMs, or categories out of scope)." ;
|
|
248
|
+
:trace "urn:policy:qi-2025-aurora:deny:odrl:no_permission_matched" .
|
|
249
|
+
} .
|
|
250
|
+
|
|
251
|
+
# ------------
|
|
252
|
+
# Check values
|
|
253
|
+
# ------------
|
|
254
|
+
|
|
255
|
+
# Scenario A
|
|
256
|
+
{ :scenario_A :decision "PERMIT" . } => { :scenario_A
|
|
257
|
+
:checkC1 "SKIPPED - not a prohibited purpose" ;
|
|
258
|
+
:checkC2 "OK - clinician" ;
|
|
259
|
+
:checkC3 "OK - care-team linked" ;
|
|
260
|
+
:checkC4 "SKIPPED" ;
|
|
261
|
+
:checkC5 "OK - operator=isAnyOf, allowed=[\"https://example.org/health#PATIENT_SUMMARY\",\"https://example.org/health#LAB_RESULTS\"], requested=[\"https://example.org/health#PATIENT_SUMMARY\"]" ;
|
|
262
|
+
:checkC6 "SKIPPED - no prohibition matched" ;
|
|
263
|
+
:checkC7 "OK - trace shows matching permission" ;
|
|
264
|
+
:checkC8 "SKIPPED - no matched policy or no duties" ;
|
|
265
|
+
:checkC9 "SKIPPED - policy has no environment constraint" ;
|
|
266
|
+
:checkC10Text "INFO - matched policy: urn:policy:primary-care-001" . } .
|
|
267
|
+
|
|
268
|
+
# Scenario B
|
|
269
|
+
{ :scenario_B :decision "PERMIT" . } => { :scenario_B
|
|
270
|
+
:checkC1 "SKIPPED - not a prohibited purpose" ;
|
|
271
|
+
:checkC2 "SKIPPED" ;
|
|
272
|
+
:checkC3 "SKIPPED" ;
|
|
273
|
+
:checkC4 "OK - opt-in present and policy matched" ;
|
|
274
|
+
:checkC5 "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\"]" ;
|
|
275
|
+
:checkC6 "SKIPPED - no prohibition matched" ;
|
|
276
|
+
:checkC7 "OK - trace shows matching permission" ;
|
|
277
|
+
:checkC8 "INFO - duties attached: duty:https://w3id.org/dpv/legal/eu/ehds#requireConsent, duty:https://w3id.org/dpv/legal/eu/ehds#noExfiltration" ;
|
|
278
|
+
:checkC9 "OK - operator=eq, allowed=\"secure_env\", requested=\"secure_env\"" ;
|
|
279
|
+
:checkC10Text "INFO - matched policy: urn:policy:qi-2025-aurora" . } .
|
|
280
|
+
|
|
281
|
+
# Scenario C
|
|
282
|
+
{ :scenario_C :decision "DENY" . } => { :scenario_C
|
|
283
|
+
:checkC1 "SKIPPED - not a prohibited purpose" ;
|
|
284
|
+
:checkC2 "SKIPPED" ;
|
|
285
|
+
:checkC3 "SKIPPED" ;
|
|
286
|
+
:checkC4 "OK - denied because opt-in missing or no policy match" ;
|
|
287
|
+
:checkC5 "SKIPPED" ;
|
|
288
|
+
:checkC6 "SKIPPED - no prohibition matched" ;
|
|
289
|
+
:checkC7 "SKIPPED" ;
|
|
290
|
+
:checkC8 "SKIPPED - no matched policy or no duties" ;
|
|
291
|
+
:checkC9 "SKIPPED" ;
|
|
292
|
+
:checkC10Text "SKIPPED - no matched policy" . } .
|
|
293
|
+
|
|
294
|
+
# Scenario D
|
|
295
|
+
{ :scenario_D :decision "DENY" . } => { :scenario_D
|
|
296
|
+
:checkC1 "OK - denied prohibited purpose" ;
|
|
297
|
+
:checkC2 "SKIPPED" ;
|
|
298
|
+
:checkC3 "SKIPPED" ;
|
|
299
|
+
:checkC4 "SKIPPED" ;
|
|
300
|
+
:checkC5 "SKIPPED" ;
|
|
301
|
+
:checkC6 "OK - denied due to prohibition" ;
|
|
302
|
+
:checkC7 "SKIPPED" ;
|
|
303
|
+
:checkC8 "SKIPPED - no matched policy or no duties" ;
|
|
304
|
+
:checkC9 "SKIPPED" ;
|
|
305
|
+
:checkC10Text "SKIPPED - no matched policy" . } .
|
|
306
|
+
|
|
307
|
+
# Scenario E
|
|
308
|
+
{ :scenario_E :decision "PERMIT" . } => { :scenario_E
|
|
309
|
+
:checkC1 "SKIPPED - not a prohibited purpose" ;
|
|
310
|
+
:checkC2 "OK - clinician" ;
|
|
311
|
+
:checkC3 "OK - care-team linked" ;
|
|
312
|
+
:checkC4 "SKIPPED" ;
|
|
313
|
+
:checkC5 "OK - operator=isAnyOf, allowed=[\"https://example.org/health#PATIENT_SUMMARY\",\"https://example.org/health#LAB_RESULTS\"], requested=[\"https://example.org/health#LAB_RESULTS\"]" ;
|
|
314
|
+
:checkC6 "SKIPPED - no prohibition matched" ;
|
|
315
|
+
:checkC7 "OK - trace shows matching permission" ;
|
|
316
|
+
:checkC8 "SKIPPED - no matched policy or no duties" ;
|
|
317
|
+
:checkC9 "SKIPPED - policy has no environment constraint" ;
|
|
318
|
+
:checkC10Text "INFO - matched policy: urn:policy:primary-care-001" . } .
|
|
319
|
+
|
|
320
|
+
# Scenario F
|
|
321
|
+
{ :scenario_F :decision "PERMIT" . } => { :scenario_F
|
|
322
|
+
:checkC1 "SKIPPED - not a prohibited purpose" ;
|
|
323
|
+
:checkC2 "SKIPPED" ;
|
|
324
|
+
:checkC3 "SKIPPED" ;
|
|
325
|
+
:checkC4 "OK - opt-in present and policy matched" ;
|
|
326
|
+
:checkC5 "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\"]" ;
|
|
327
|
+
:checkC6 "SKIPPED - no prohibition matched" ;
|
|
328
|
+
:checkC7 "OK - trace shows matching permission" ;
|
|
329
|
+
:checkC8 "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" ;
|
|
330
|
+
:checkC9 "OK - operator=eq, allowed=\"secure_env\", requested=\"secure_env\"" ;
|
|
331
|
+
:checkC10Text "INFO - matched policy: urn:policy:research-aurora-diabetes" . } .
|
|
332
|
+
|
|
333
|
+
# Scenario G
|
|
334
|
+
{ :scenario_G :decision "DENY" . } => { :scenario_G
|
|
335
|
+
:checkC1 "SKIPPED - not a prohibited purpose" ;
|
|
336
|
+
:checkC2 "SKIPPED" ;
|
|
337
|
+
:checkC3 "SKIPPED" ;
|
|
338
|
+
:checkC4 "OK - denied because opt-in missing or no policy match" ;
|
|
339
|
+
:checkC5 "SKIPPED" ;
|
|
340
|
+
:checkC6 "SKIPPED - no prohibition matched" ;
|
|
341
|
+
:checkC7 "SKIPPED" ;
|
|
342
|
+
:checkC8 "SKIPPED - no matched policy or no duties" ;
|
|
343
|
+
:checkC9 "SKIPPED" ;
|
|
344
|
+
:checkC10Text "SKIPPED - no matched policy" . } .
|
|
345
|
+
|
|
346
|
+
# ------------
|
|
347
|
+
# Presentation
|
|
348
|
+
# ------------
|
|
349
|
+
|
|
350
|
+
# Emit one complete output block per scenario to avoid ordering issues between
|
|
351
|
+
# separately derived log:outputString facts.
|
|
352
|
+
|
|
353
|
+
:out_000_intro log:outputString "AuroraCare — Purpose-based Medical Data Exchange\n\n" .
|
|
354
|
+
|
|
355
|
+
{ :scenario_A :decision "PERMIT" . } => {
|
|
356
|
+
:out_010_A log:outputString """=== A – Primary care visit ===
|
|
357
|
+
Clinician in the patient's care team accessing the patient summary for primary care management.
|
|
358
|
+
|
|
359
|
+
Answer
|
|
360
|
+
PERMIT
|
|
361
|
+
|
|
362
|
+
Reason Why
|
|
363
|
+
Permitted: clinician in the patient's care team, and the primary-care policy matched.
|
|
364
|
+
|
|
365
|
+
Check
|
|
366
|
+
C1 SKIPPED - not a prohibited purpose
|
|
367
|
+
C2 OK - clinician
|
|
368
|
+
C3 OK - care-team linked
|
|
369
|
+
C4 SKIPPED
|
|
370
|
+
C5 OK - operator=isAnyOf, allowed=["https://example.org/health#PATIENT_SUMMARY","https://example.org/health#LAB_RESULTS"], requested=["https://example.org/health#PATIENT_SUMMARY"]
|
|
371
|
+
C6 SKIPPED - no prohibition matched
|
|
372
|
+
C7 OK - trace shows matching permission
|
|
373
|
+
C8 SKIPPED - no matched policy or no duties
|
|
374
|
+
C9 SKIPPED - policy has no environment constraint
|
|
375
|
+
C10 INFO - matched policy: urn:policy:primary-care-001
|
|
376
|
+
|
|
377
|
+
""" .
|
|
378
|
+
} .
|
|
379
|
+
|
|
380
|
+
{ :scenario_B :decision "PERMIT" . } => {
|
|
381
|
+
:out_020_B log:outputString """=== B – Quality improvement (in scope) ===
|
|
382
|
+
QI analyst using lab results + summary in a secure environment.
|
|
383
|
+
|
|
384
|
+
Answer
|
|
385
|
+
PERMIT
|
|
386
|
+
|
|
387
|
+
Reason Why
|
|
388
|
+
Permitted: ODRL/DPV policy matched for secondary use.
|
|
389
|
+
|
|
390
|
+
Check
|
|
391
|
+
C1 SKIPPED - not a prohibited purpose
|
|
392
|
+
C2 SKIPPED
|
|
393
|
+
C3 SKIPPED
|
|
394
|
+
C4 OK - opt-in present and policy matched
|
|
395
|
+
C5 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"]
|
|
396
|
+
C6 SKIPPED - no prohibition matched
|
|
397
|
+
C7 OK - trace shows matching permission
|
|
398
|
+
C8 INFO - duties attached: duty:https://w3id.org/dpv/legal/eu/ehds#requireConsent, duty:https://w3id.org/dpv/legal/eu/ehds#noExfiltration
|
|
399
|
+
C9 OK - operator=eq, allowed="secure_env", requested="secure_env"
|
|
400
|
+
C10 INFO - matched policy: urn:policy:qi-2025-aurora
|
|
401
|
+
|
|
402
|
+
""" .
|
|
403
|
+
} .
|
|
404
|
+
|
|
405
|
+
{ :scenario_C :decision "DENY" . } => {
|
|
406
|
+
:out_030_C log:outputString """=== C – Quality improvement (out of scope) ===
|
|
407
|
+
QI analyst with only lab results; policy expects labs + summary.
|
|
408
|
+
|
|
409
|
+
Answer
|
|
410
|
+
DENY
|
|
411
|
+
|
|
412
|
+
Reason Why
|
|
413
|
+
Denied: no policy matched (purpose, environment, TOMs, or categories out of scope).
|
|
414
|
+
|
|
415
|
+
Check
|
|
416
|
+
C1 SKIPPED - not a prohibited purpose
|
|
417
|
+
C2 SKIPPED
|
|
418
|
+
C3 SKIPPED
|
|
419
|
+
C4 OK - denied because opt-in missing or no policy match
|
|
420
|
+
C5 SKIPPED
|
|
421
|
+
C6 SKIPPED - no prohibition matched
|
|
422
|
+
C7 SKIPPED
|
|
423
|
+
C8 SKIPPED - no matched policy or no duties
|
|
424
|
+
C9 SKIPPED
|
|
425
|
+
C10 SKIPPED - no matched policy
|
|
426
|
+
|
|
427
|
+
""" .
|
|
428
|
+
} .
|
|
429
|
+
|
|
430
|
+
{ :scenario_D :decision "DENY" . } => {
|
|
431
|
+
:out_040_D log:outputString """=== D – Insurance management ===
|
|
432
|
+
Insurance bot attempting to use health data for insurance management (prohibited purpose).
|
|
433
|
+
|
|
434
|
+
Answer
|
|
435
|
+
DENY
|
|
436
|
+
|
|
437
|
+
Reason Why
|
|
438
|
+
Denied: the requested purpose (insurance management) is prohibited by policy.
|
|
439
|
+
|
|
440
|
+
Check
|
|
441
|
+
C1 OK - denied prohibited purpose
|
|
442
|
+
C2 SKIPPED
|
|
443
|
+
C3 SKIPPED
|
|
444
|
+
C4 SKIPPED
|
|
445
|
+
C5 SKIPPED
|
|
446
|
+
C6 OK - denied due to prohibition
|
|
447
|
+
C7 SKIPPED
|
|
448
|
+
C8 SKIPPED - no matched policy or no duties
|
|
449
|
+
C9 SKIPPED
|
|
450
|
+
C10 SKIPPED - no matched policy
|
|
451
|
+
|
|
452
|
+
""" .
|
|
453
|
+
} .
|
|
454
|
+
|
|
455
|
+
{ :scenario_E :decision "PERMIT" . } => {
|
|
456
|
+
:out_050_E log:outputString """=== E – GP checks labs ===
|
|
457
|
+
GP for the same patient checking lab results via the API gateway.
|
|
458
|
+
|
|
459
|
+
Answer
|
|
460
|
+
PERMIT
|
|
461
|
+
|
|
462
|
+
Reason Why
|
|
463
|
+
Permitted: clinician in the patient's care team, and the primary-care policy matched.
|
|
464
|
+
|
|
465
|
+
Check
|
|
466
|
+
C1 SKIPPED - not a prohibited purpose
|
|
467
|
+
C2 OK - clinician
|
|
468
|
+
C3 OK - care-team linked
|
|
469
|
+
C4 SKIPPED
|
|
470
|
+
C5 OK - operator=isAnyOf, allowed=["https://example.org/health#PATIENT_SUMMARY","https://example.org/health#LAB_RESULTS"], requested=["https://example.org/health#LAB_RESULTS"]
|
|
471
|
+
C6 SKIPPED - no prohibition matched
|
|
472
|
+
C7 OK - trace shows matching permission
|
|
473
|
+
C8 SKIPPED - no matched policy or no duties
|
|
474
|
+
C9 SKIPPED - policy has no environment constraint
|
|
475
|
+
C10 INFO - matched policy: urn:policy:primary-care-001
|
|
476
|
+
|
|
477
|
+
""" .
|
|
478
|
+
} .
|
|
479
|
+
|
|
480
|
+
{ :scenario_F :decision "PERMIT" . } => {
|
|
481
|
+
:out_060_F log:outputString """=== F – Research on anonymised dataset ===
|
|
482
|
+
Researcher using anonymised labs + summary in a secure environment, with opt-in.
|
|
483
|
+
|
|
484
|
+
Answer
|
|
485
|
+
PERMIT
|
|
486
|
+
|
|
487
|
+
Reason Why
|
|
488
|
+
Permitted: subject opted in and an ODRL/DPV policy matched (anonymised dataset in secure environment).
|
|
489
|
+
|
|
490
|
+
Check
|
|
491
|
+
C1 SKIPPED - not a prohibited purpose
|
|
492
|
+
C2 SKIPPED
|
|
493
|
+
C3 SKIPPED
|
|
494
|
+
C4 OK - opt-in present and policy matched
|
|
495
|
+
C5 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"]
|
|
496
|
+
C6 SKIPPED - no prohibition matched
|
|
497
|
+
C7 OK - trace shows matching permission
|
|
498
|
+
C8 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
|
|
499
|
+
C9 OK - operator=eq, allowed="secure_env", requested="secure_env"
|
|
500
|
+
C10 INFO - matched policy: urn:policy:research-aurora-diabetes
|
|
501
|
+
|
|
502
|
+
""" .
|
|
503
|
+
} .
|
|
504
|
+
|
|
505
|
+
{ :scenario_G :decision "DENY" . } => {
|
|
506
|
+
:out_070_G log:outputString """=== G – AI training (opt-out) ===
|
|
507
|
+
Data user wants to train AI, but the subject opted out of AI training.
|
|
508
|
+
|
|
509
|
+
Answer
|
|
510
|
+
DENY
|
|
511
|
+
|
|
512
|
+
Reason Why
|
|
513
|
+
Denied: you opted out of your data being used to train AI systems.
|
|
514
|
+
|
|
515
|
+
Check
|
|
516
|
+
C1 SKIPPED - not a prohibited purpose
|
|
517
|
+
C2 SKIPPED
|
|
518
|
+
C3 SKIPPED
|
|
519
|
+
C4 OK - denied because opt-in missing or no policy match
|
|
520
|
+
C5 SKIPPED
|
|
521
|
+
C6 SKIPPED - no prohibition matched
|
|
522
|
+
C7 SKIPPED
|
|
523
|
+
C8 SKIPPED - no matched policy or no duties
|
|
524
|
+
C9 SKIPPED
|
|
525
|
+
C10 SKIPPED - no matched policy
|
|
526
|
+
|
|
527
|
+
""" .
|
|
528
|
+
} .
|