eyeprolog 1.3.20 → 1.3.21

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.
@@ -0,0 +1,411 @@
1
+ % ODRL-style policy reasoning in plain EyeProlog.
2
+ %
3
+ % This executable example models the reasoning layer rather than JSON-LD
4
+ % parsing. It covers ODRL 2.2 permissions, prohibitions, constraints, duties,
5
+ % the perm/prohibit/invalid conflict strategies, action dependencies, and
6
+ % subsumption questions. The final section shows how an ODRL profile with
7
+ % recursive defaults can use tnot/1: WFS keeps a negative cycle undefined
8
+ % instead of choosing an arbitrary permission or prohibition.
9
+ %
10
+ % References: https://www.w3.org/TR/odrl-model/#conflict
11
+ % https://w3c.github.io/odrl/formal-semantics/
12
+
13
+ %% goal: actionQuestion(X0, X1, X2, X3)
14
+ %% goal: ruleQuestion(X0, X1, X2, X3)
15
+ %% goal: enforcementQuestion(X0, X1, X2, X3, X4, X5)
16
+ %% goal: conflictQuestion(X0, X1, X2, X3, X4)
17
+ %% goal: subsumptionQuestion(X0, X1, X2, X3)
18
+ %% goal: wfsQuestion(X0, X1)
19
+
20
+ % --- ODRL action vocabulary -----------------------------------------------
21
+
22
+ % A small excerpt of the ODRL action hierarchy. broader(A, B) means that A
23
+ % is the more general action. For example, a rule about use can affect print.
24
+ action(use).
25
+ action(present).
26
+ action(display).
27
+ action(play).
28
+ action(print).
29
+ action(distribute).
30
+ action(reproduce).
31
+ action(aggregate).
32
+ action(extract).
33
+ action(read).
34
+ action(delete).
35
+
36
+ broader(use, present).
37
+ broader(present, display).
38
+ broader(present, play).
39
+ broader(use, print).
40
+ broader(use, distribute).
41
+ broader(use, reproduce).
42
+
43
+ % Implicit action dependencies are kept separate from explicit subsumption.
44
+ requires(aggregate, read).
45
+ requires(extract, read).
46
+
47
+ action_subsumes(Action, Action) :- action(Action).
48
+ action_subsumes(Broader, Narrower) :- broader(Broader, Narrower).
49
+ action_subsumes(Broader, Narrower) :-
50
+ broader(Broader, Middle),
51
+ action_subsumes(Middle, Narrower).
52
+
53
+ action_requires(Action, Required) :- requires(Action, Required).
54
+ action_requires(Action, Required) :-
55
+ requires(Action, Middle),
56
+ action_requires(Middle, Required).
57
+
58
+ % The six useful answers to "how does this rule action relate to the requested
59
+ % action?": exact, broader, narrower, required, requiring, or no_match.
60
+ positive_action_match(Action, Action, exact) :- action(Action).
61
+ positive_action_match(RuleAction, RequestAction, broader) :-
62
+ RuleAction \= RequestAction,
63
+ action_subsumes(RuleAction, RequestAction).
64
+ positive_action_match(RuleAction, RequestAction, narrower) :-
65
+ RuleAction \= RequestAction,
66
+ action_subsumes(RequestAction, RuleAction).
67
+ positive_action_match(RuleAction, RequestAction, required) :-
68
+ action_requires(RequestAction, RuleAction).
69
+ positive_action_match(RuleAction, RequestAction, requiring) :-
70
+ action_requires(RuleAction, RequestAction).
71
+
72
+ action_match(RuleAction, RequestAction, Kind) :-
73
+ positive_action_match(RuleAction, RequestAction, Kind).
74
+ action_match(RuleAction, RequestAction, no_match) :-
75
+ action(RuleAction),
76
+ action(RequestAction),
77
+ \+ positive_action_match(RuleAction, RequestAction, _).
78
+
79
+ % --- Parties and assets ----------------------------------------------------
80
+
81
+ party(alice).
82
+ party(bob).
83
+ party(analysts).
84
+ party(anyone).
85
+ member_of(alice, analysts).
86
+ member_of(bob, analysts).
87
+
88
+ party_subsumes(Party, Party) :- party(Party).
89
+ party_subsumes(Group, Person) :- member_of(Person, Group).
90
+ party_subsumes(anyone, Party) :- party(Party), Party \= anyone.
91
+
92
+ asset(report_q1).
93
+ asset(report_q2).
94
+ asset(reports).
95
+ asset(dataset_a).
96
+ asset(dataset_b).
97
+ asset(dataset_c).
98
+
99
+ asset_member(report_q1, reports).
100
+ asset_member(report_q2, reports).
101
+
102
+ asset_subsumes(Asset, Asset) :- asset(Asset).
103
+ asset_subsumes(Collection, Item) :- asset_member(Item, Collection).
104
+
105
+ % --- Policies, rules, requests, and evidence ------------------------------
106
+
107
+ % policy(Policy, ConflictStrategy).
108
+ policy(open_printing, perm).
109
+ policy(strict_printing, prohibit).
110
+ policy(invalid_printing, invalid).
111
+ policy(duty_policy, invalid).
112
+ policy(context_policy, invalid).
113
+ policy(analysis_policy, invalid).
114
+ policy(general_policy, invalid).
115
+ policy(specific_policy, invalid).
116
+
117
+ % permission/prohibition(Policy, Rule, Assignee, Action, Target).
118
+ permission(open_printing, open_use, analysts, use, reports).
119
+ prohibition(open_printing, open_no_print, alice, print, report_q1).
120
+
121
+ permission(strict_printing, strict_use, analysts, use, reports).
122
+ prohibition(strict_printing, strict_no_print, alice, print, report_q1).
123
+
124
+ permission(invalid_printing, invalid_use, analysts, use, reports).
125
+ prohibition(invalid_printing, invalid_no_print, alice, print, report_q1).
126
+
127
+ permission(duty_policy, share_report, alice, distribute, report_q1).
128
+ duty(share_report, attribute_source).
129
+
130
+ permission(context_policy, research_use, analysts, use, reports).
131
+ constraint(research_use, purpose, research).
132
+
133
+ % Three independent static conflicts: exact action, explicit action
134
+ % subsumption, and an implicit requires dependency.
135
+ permission(analysis_policy, exact_permit, alice, display, dataset_a).
136
+ prohibition(analysis_policy, exact_prohibit, alice, display, dataset_a).
137
+ permission(analysis_policy, broad_permit, alice, use, dataset_b).
138
+ prohibition(analysis_policy, narrow_prohibit, alice, print, dataset_b).
139
+ permission(analysis_policy, aggregate_permit, alice, aggregate, dataset_c).
140
+ prohibition(analysis_policy, read_prohibit, alice, read, dataset_c).
141
+
142
+ % A broad policy and a narrower policy for rule/policy subsumption questions.
143
+ permission(general_policy, general_use, analysts, use, reports).
144
+ permission(specific_policy, specific_display, alice, display, report_q1).
145
+ constraint(specific_display, purpose, research).
146
+
147
+ % request(Request, Assignee, Action, Target).
148
+ request(q_print, alice, print, report_q1).
149
+ request(q_share_done, alice, distribute, report_q1).
150
+ request(q_share_missing, alice, distribute, report_q1).
151
+ request(q_research, alice, display, report_q1).
152
+ request(q_commercial, alice, display, report_q1).
153
+ request(q_unrelated, alice, delete, report_q1).
154
+
155
+ evidence(q_research, purpose, research).
156
+ evidence(q_commercial, purpose, commercial).
157
+ duty_done(q_share_done, attribute_source).
158
+
159
+ rule(Rule, Policy, permission, Party, Action, Target) :-
160
+ permission(Policy, Rule, Party, Action, Target).
161
+ rule(Rule, Policy, prohibition, Party, Action, Target) :-
162
+ prohibition(Policy, Rule, Party, Action, Target).
163
+
164
+ % --- Rule evaluation -------------------------------------------------------
165
+
166
+ rule_scope_matches(Rule, Request) :-
167
+ rule(Rule, _, _, RuleParty, RuleAction, RuleTarget),
168
+ request(Request, Party, Action, Target),
169
+ party_subsumes(RuleParty, Party),
170
+ asset_subsumes(RuleTarget, Target),
171
+ positive_action_match(RuleAction, Action, _).
172
+
173
+ constraints_hold(Rule, Request) :-
174
+ \+ (constraint(Rule, Key, Value), \+ evidence(Request, Key, Value)).
175
+
176
+ duties_hold(Rule, Request) :-
177
+ \+ (duty(Rule, Duty), \+ duty_done(Request, Duty)).
178
+
179
+ permission_result(Rule, Request, permission) :-
180
+ permission(_, Rule, _, _, _),
181
+ rule_scope_matches(Rule, Request),
182
+ constraints_hold(Rule, Request),
183
+ duties_hold(Rule, Request).
184
+ permission_result(Rule, Request, inactive(constraint(Key))) :-
185
+ permission(_, Rule, _, _, _),
186
+ rule_scope_matches(Rule, Request),
187
+ constraint(Rule, Key, Value),
188
+ \+ evidence(Request, Key, Value).
189
+ permission_result(Rule, Request, inactive(duty(Duty))) :-
190
+ permission(_, Rule, _, _, _),
191
+ rule_scope_matches(Rule, Request),
192
+ constraints_hold(Rule, Request),
193
+ duty(Rule, Duty),
194
+ \+ duty_done(Request, Duty).
195
+ permission_result(Rule, Request, not_applicable) :-
196
+ permission(_, Rule, _, _, _),
197
+ \+ rule_scope_matches(Rule, Request).
198
+
199
+ prohibition_result(Rule, Request, prohibition) :-
200
+ prohibition(_, Rule, _, _, _),
201
+ rule_scope_matches(Rule, Request),
202
+ constraints_hold(Rule, Request).
203
+ prohibition_result(Rule, Request, inactive(constraint(Key))) :-
204
+ prohibition(_, Rule, _, _, _),
205
+ rule_scope_matches(Rule, Request),
206
+ constraint(Rule, Key, Value),
207
+ \+ evidence(Request, Key, Value).
208
+ prohibition_result(Rule, Request, not_applicable) :-
209
+ prohibition(_, Rule, _, _, _),
210
+ \+ rule_scope_matches(Rule, Request).
211
+
212
+ rule_result(Rule, Request, Result) :- permission_result(Rule, Request, Result).
213
+ rule_result(Rule, Request, Result) :- prohibition_result(Rule, Request, Result).
214
+
215
+ % --- Enforcement -----------------------------------------------------------
216
+
217
+ policy_permission(Policy, Request) :-
218
+ permission(Policy, Rule, _, _, _),
219
+ permission_result(Rule, Request, permission).
220
+ policy_prohibition(Policy, Request) :-
221
+ prohibition(Policy, Rule, _, _, _),
222
+ prohibition_result(Rule, Request, prohibition).
223
+ policy_inactive(Policy, Request) :-
224
+ rule(Rule, Policy, _, _, _, _),
225
+ rule_result(Rule, Request, inactive(_)).
226
+ policy_applicable(Policy, Request) :-
227
+ rule(Rule, Policy, _, _, _, _),
228
+ rule_scope_matches(Rule, Request).
229
+
230
+ % Conflicting permission/prohibition answers use the ODRL conflict strategy.
231
+ policy_result(Policy, Request, permission) :-
232
+ policy_permission(Policy, Request),
233
+ policy_prohibition(Policy, Request),
234
+ policy(Policy, perm).
235
+ policy_result(Policy, Request, prohibition) :-
236
+ policy_permission(Policy, Request),
237
+ policy_prohibition(Policy, Request),
238
+ policy(Policy, prohibit).
239
+ policy_result(Policy, Request, invalid) :-
240
+ policy_permission(Policy, Request),
241
+ policy_prohibition(Policy, Request),
242
+ policy(Policy, invalid).
243
+
244
+ % Non-conflicting active rules retain their deontic result.
245
+ policy_result(Policy, Request, permission) :-
246
+ policy_permission(Policy, Request),
247
+ \+ policy_prohibition(Policy, Request).
248
+ policy_result(Policy, Request, prohibition) :-
249
+ policy_prohibition(Policy, Request),
250
+ \+ policy_permission(Policy, Request).
251
+ policy_result(Policy, Request, inactive) :-
252
+ \+ policy_permission(Policy, Request),
253
+ \+ policy_prohibition(Policy, Request),
254
+ policy_inactive(Policy, Request).
255
+ policy_result(Policy, Request, not_applicable) :-
256
+ policy(Policy, _),
257
+ \+ policy_applicable(Policy, Request).
258
+
259
+ % Access-control enforcement adds the evaluator behaviour for the case where
260
+ % no rule applies. "default" is the ODRL evaluator's closed behaviour.
261
+ access_decision(Policy, Request, _Behaviour, permit) :-
262
+ policy_result(Policy, Request, permission).
263
+ access_decision(Policy, Request, _Behaviour, deny) :-
264
+ policy_result(Policy, Request, prohibition).
265
+ access_decision(Policy, Request, _Behaviour, invalid) :-
266
+ policy_result(Policy, Request, invalid).
267
+ access_decision(Policy, Request, _Behaviour, deny) :-
268
+ policy_result(Policy, Request, inactive).
269
+ access_decision(Policy, Request, open, permit) :-
270
+ policy_result(Policy, Request, not_applicable).
271
+ access_decision(Policy, Request, closed, deny) :-
272
+ policy_result(Policy, Request, not_applicable).
273
+ access_decision(Policy, Request, default, deny) :-
274
+ policy_result(Policy, Request, not_applicable).
275
+
276
+ % --- Static conflict detection --------------------------------------------
277
+
278
+ opposite(permission, prohibition).
279
+ opposite(prohibition, permission).
280
+
281
+ parties_overlap(A, B) :- party_subsumes(A, B).
282
+ parties_overlap(A, B) :- party_subsumes(B, A).
283
+ assets_overlap(A, B) :- asset_subsumes(A, B).
284
+ assets_overlap(A, B) :- asset_subsumes(B, A).
285
+ constraints_compatible(RuleA, RuleB) :-
286
+ \+ (constraint(RuleA, Key, A), constraint(RuleB, Key, B), A \= B).
287
+
288
+ conflicting_action(Action, Action, exact) :- action(Action).
289
+ conflicting_action(ActionA, ActionB, subsumption) :-
290
+ ActionA \= ActionB,
291
+ (action_subsumes(ActionA, ActionB); action_subsumes(ActionB, ActionA)).
292
+ conflicting_action(ActionA, ActionB, dependency) :-
293
+ \+ action_subsumes(ActionA, ActionB),
294
+ \+ action_subsumes(ActionB, ActionA),
295
+ (action_requires(ActionA, ActionB); action_requires(ActionB, ActionA)).
296
+
297
+ rule_conflict(RuleA, RuleB, Kind) :-
298
+ rule(RuleA, _, EffectA, PartyA, ActionA, TargetA),
299
+ rule(RuleB, _, EffectB, PartyB, ActionB, TargetB),
300
+ opposite(EffectA, EffectB),
301
+ parties_overlap(PartyA, PartyB),
302
+ assets_overlap(TargetA, TargetB),
303
+ constraints_compatible(RuleA, RuleB),
304
+ conflicting_action(ActionA, ActionB, Kind).
305
+
306
+ % --- Rule and policy subsumption ------------------------------------------
307
+
308
+ constraints_subsume(General, Specific) :-
309
+ \+ (constraint(General, Key, Value), \+ constraint(Specific, Key, Value)).
310
+ duties_subsume(General, Specific) :-
311
+ \+ (duty(General, Duty), \+ duty(Specific, Duty)).
312
+
313
+ rule_subsumes(General, Specific) :-
314
+ rule(General, _, Effect, GeneralParty, GeneralAction, GeneralTarget),
315
+ rule(Specific, _, Effect, SpecificParty, SpecificAction, SpecificTarget),
316
+ party_subsumes(GeneralParty, SpecificParty),
317
+ action_subsumes(GeneralAction, SpecificAction),
318
+ asset_subsumes(GeneralTarget, SpecificTarget),
319
+ constraints_subsume(General, Specific),
320
+ duties_subsume(General, Specific).
321
+
322
+ policy_subsumes(General, Specific) :-
323
+ policy(General, _),
324
+ policy(Specific, _),
325
+ \+ (rule(SpecificRule, Specific, _, _, _, _),
326
+ \+ (rule(GeneralRule, General, _, _, _, _),
327
+ rule_subsumes(GeneralRule, SpecificRule))).
328
+
329
+ % --- WFS: true, false, and undefined --------------------------------------
330
+
331
+ % A profile can add recursive default rules. clear is unconditionally allowed,
332
+ % denied has no permission, and cycle has mutually defaulted permission and
333
+ % prohibition. The last case is intentionally undefined under WFS.
334
+ profile_request(clear).
335
+ profile_request(denied).
336
+ profile_request(cycle).
337
+ cycle_request(cycle).
338
+
339
+ profile_permission(clear).
340
+ profile_permission(Request) :-
341
+ cycle_request(Request),
342
+ tnot(profile_prohibition(Request)).
343
+ profile_prohibition(denied).
344
+ profile_prohibition(Request) :-
345
+ cycle_request(Request),
346
+ tnot(profile_permission(Request)).
347
+
348
+ % For a ground WFS claim, both Claim and tnot(Claim) conditionally succeed when
349
+ % the truth value is undefined. That lets this example expose all three states.
350
+ wfs_truth(Claim, true) :- call(Claim), \+ tnot(Claim).
351
+ wfs_truth(Claim, false) :- tnot(Claim), \+ call(Claim).
352
+ wfs_truth(Claim, undefined) :- call(Claim), tnot(Claim).
353
+
354
+ % --- Curated questions -----------------------------------------------------
355
+
356
+ % All six action relationship outcomes used by the evaluator.
357
+ actionQuestion(exact, use, use, Kind) :- action_match(use, use, Kind).
358
+ actionQuestion(broader, use, print, Kind) :- action_match(use, print, Kind).
359
+ actionQuestion(narrower, print, use, Kind) :- action_match(print, use, Kind).
360
+ actionQuestion(required, read, aggregate, Kind) :- action_match(read, aggregate, Kind).
361
+ actionQuestion(requiring, aggregate, read, Kind) :- action_match(aggregate, read, Kind).
362
+ actionQuestion(unrelated, display, delete, Kind) :- action_match(display, delete, Kind).
363
+
364
+ % Rule-level evaluation shows active permission/prohibition, inactive rules
365
+ % caused by a failed condition or constraint, and non-applicability.
366
+ ruleQuestion(unconditional, open_use, q_print, Result) :- rule_result(open_use, q_print, Result).
367
+ ruleQuestion(duty_satisfied, share_report, q_share_done, Result) :- rule_result(share_report, q_share_done, Result).
368
+ ruleQuestion(duty_missing, share_report, q_share_missing, Result) :- rule_result(share_report, q_share_missing, Result).
369
+ ruleQuestion(constraint_true, research_use, q_research, Result) :- rule_result(research_use, q_research, Result).
370
+ ruleQuestion(constraint_false, research_use, q_commercial, Result) :- rule_result(research_use, q_commercial, Result).
371
+ ruleQuestion(scope_miss, research_use, q_unrelated, Result) :- rule_result(research_use, q_unrelated, Result).
372
+ ruleQuestion(prohibition, open_no_print, q_print, Result) :- rule_result(open_no_print, q_print, Result).
373
+
374
+ % The same conflicting request under all three ODRL conflict strategies, then
375
+ % duty/constraint failures and open-vs-closed handling when no rule applies.
376
+ enforcementQuestion(permission_overrides, open_printing, q_print, closed, Result, Decision) :-
377
+ policy_result(open_printing, q_print, Result), access_decision(open_printing, q_print, closed, Decision).
378
+ enforcementQuestion(prohibition_overrides, strict_printing, q_print, closed, Result, Decision) :-
379
+ policy_result(strict_printing, q_print, Result), access_decision(strict_printing, q_print, closed, Decision).
380
+ enforcementQuestion(conflict_invalidates, invalid_printing, q_print, closed, Result, Decision) :-
381
+ policy_result(invalid_printing, q_print, Result), access_decision(invalid_printing, q_print, closed, Decision).
382
+ enforcementQuestion(duty_satisfied, duty_policy, q_share_done, closed, Result, Decision) :-
383
+ policy_result(duty_policy, q_share_done, Result), access_decision(duty_policy, q_share_done, closed, Decision).
384
+ enforcementQuestion(duty_missing, duty_policy, q_share_missing, closed, Result, Decision) :-
385
+ policy_result(duty_policy, q_share_missing, Result), access_decision(duty_policy, q_share_missing, closed, Decision).
386
+ enforcementQuestion(constraint_false, context_policy, q_commercial, closed, Result, Decision) :-
387
+ policy_result(context_policy, q_commercial, Result), access_decision(context_policy, q_commercial, closed, Decision).
388
+ enforcementQuestion(no_match_closed, context_policy, q_unrelated, closed, Result, Decision) :-
389
+ policy_result(context_policy, q_unrelated, Result), access_decision(context_policy, q_unrelated, closed, Decision).
390
+ enforcementQuestion(no_match_open, context_policy, q_unrelated, open, Result, Decision) :-
391
+ policy_result(context_policy, q_unrelated, Result), access_decision(context_policy, q_unrelated, open, Decision).
392
+ enforcementQuestion(no_match_default, context_policy, q_unrelated, default, Result, Decision) :-
393
+ policy_result(context_policy, q_unrelated, Result), access_decision(context_policy, q_unrelated, default, Decision).
394
+
395
+ % Conflict analysis distinguishes equality, explicit action subsumption, and
396
+ % implicit requires dependencies.
397
+ conflictQuestion(exact, analysis_policy, exact_permit, exact_prohibit, Kind) :- rule_conflict(exact_permit, exact_prohibit, Kind).
398
+ conflictQuestion(subsumption, analysis_policy, broad_permit, narrow_prohibit, Kind) :- rule_conflict(broad_permit, narrow_prohibit, Kind).
399
+ conflictQuestion(dependency, analysis_policy, aggregate_permit, read_prohibit, Kind) :- rule_conflict(aggregate_permit, read_prohibit, Kind).
400
+
401
+ % Positive and negative action, rule, and whole-policy subsumption questions.
402
+ subsumptionQuestion(action_yes, use, display, yes) :- action_subsumes(use, display).
403
+ subsumptionQuestion(action_no, display, use, no) :- \+ action_subsumes(display, use).
404
+ subsumptionQuestion(rule_yes, general_use, specific_display, yes) :- rule_subsumes(general_use, specific_display).
405
+ subsumptionQuestion(rule_no, specific_display, general_use, no) :- \+ rule_subsumes(specific_display, general_use).
406
+ subsumptionQuestion(policy_yes, general_policy, specific_policy, yes) :- policy_subsumes(general_policy, specific_policy).
407
+ subsumptionQuestion(policy_no, specific_policy, general_policy, no) :- \+ policy_subsumes(specific_policy, general_policy).
408
+
409
+ wfsQuestion(clear_permission, State) :- wfs_truth(profile_permission(clear), State).
410
+ wfsQuestion(absent_permission, State) :- wfs_truth(profile_permission(denied), State).
411
+ wfsQuestion(negative_cycle, State) :- wfs_truth(profile_permission(cycle), State).
@@ -0,0 +1,34 @@
1
+ actionQuestion(exact, use, use, exact).
2
+ actionQuestion(broader, use, print, broader).
3
+ actionQuestion(narrower, print, use, narrower).
4
+ actionQuestion(required, read, aggregate, required).
5
+ actionQuestion(requiring, aggregate, read, requiring).
6
+ actionQuestion(unrelated, display, delete, no_match).
7
+ ruleQuestion(unconditional, open_use, q_print, permission).
8
+ ruleQuestion(duty_satisfied, share_report, q_share_done, permission).
9
+ ruleQuestion(duty_missing, share_report, q_share_missing, inactive(duty(attribute_source))).
10
+ ruleQuestion(constraint_true, research_use, q_research, permission).
11
+ ruleQuestion(constraint_false, research_use, q_commercial, inactive(constraint(purpose))).
12
+ ruleQuestion(scope_miss, research_use, q_unrelated, not_applicable).
13
+ ruleQuestion(prohibition, open_no_print, q_print, prohibition).
14
+ enforcementQuestion(permission_overrides, open_printing, q_print, closed, permission, permit).
15
+ enforcementQuestion(prohibition_overrides, strict_printing, q_print, closed, prohibition, deny).
16
+ enforcementQuestion(conflict_invalidates, invalid_printing, q_print, closed, invalid, invalid).
17
+ enforcementQuestion(duty_satisfied, duty_policy, q_share_done, closed, permission, permit).
18
+ enforcementQuestion(duty_missing, duty_policy, q_share_missing, closed, inactive, deny).
19
+ enforcementQuestion(constraint_false, context_policy, q_commercial, closed, inactive, deny).
20
+ enforcementQuestion(no_match_closed, context_policy, q_unrelated, closed, not_applicable, deny).
21
+ enforcementQuestion(no_match_open, context_policy, q_unrelated, open, not_applicable, permit).
22
+ enforcementQuestion(no_match_default, context_policy, q_unrelated, default, not_applicable, deny).
23
+ conflictQuestion(exact, analysis_policy, exact_permit, exact_prohibit, exact).
24
+ conflictQuestion(subsumption, analysis_policy, broad_permit, narrow_prohibit, subsumption).
25
+ conflictQuestion(dependency, analysis_policy, aggregate_permit, read_prohibit, dependency).
26
+ subsumptionQuestion(action_yes, use, display, yes).
27
+ subsumptionQuestion(action_no, display, use, no).
28
+ subsumptionQuestion(rule_yes, general_use, specific_display, yes).
29
+ subsumptionQuestion(rule_no, specific_display, general_use, no).
30
+ subsumptionQuestion(policy_yes, general_policy, specific_policy, yes).
31
+ subsumptionQuestion(policy_no, specific_policy, general_policy, no).
32
+ wfsQuestion(clear_permission, true).
33
+ wfsQuestion(absent_permission, false).
34
+ wfsQuestion(negative_cycle, undefined).
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.3.20",
6
+ "version": "1.3.21",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
package/playground.html CHANGED
@@ -586,6 +586,7 @@
586
586
  "odrl-dpv-risk-ranked",
587
587
  "odrl-policy",
588
588
  "odrl-policy-advanced",
589
+ "odrl-policy-reasoning",
589
590
  "orbital-transfer-design",
590
591
  "partial-evaluator",
591
592
  "path-discovery",
@@ -6951,7 +6951,7 @@ Review questions:
6951
6951
  </figure>
6952
6952
 
6953
6953
  The [examples directory](https://github.com/eyereasoner/eyeprolog/tree/main/examples/) is the book's executable companion. The
6954
- top-level directory contains **210 self-contained runnable programs**. Every
6954
+ top-level directory contains **211 self-contained runnable programs**. Every
6955
6955
  source program has an exact answer file under
6956
6956
  [examples/output](https://github.com/eyereasoner/eyeprolog/tree/main/examples/output/), and **61 selected programs** have a checked
6957
6957
  explanation under [examples/proof](https://github.com/eyereasoner/eyeprolog/tree/main/examples/proof/). The thematic tables below link every top-level program and open the program
@@ -7281,6 +7281,7 @@ ground RDF-shaped results that can be serialized back to RDF.
7281
7281
  | [ODRL–DPV consumer risk ranking](https://github.com/eyereasoner/eyeprolog/blob/main/examples/odrl-dpv-risk-ranked.pl) | Score consumer-policy conflicts and return a deterministic risk ranking. | [answers](https://github.com/eyereasoner/eyeprolog/blob/main/examples/output/odrl-dpv-risk-ranked.pl) |
7282
7282
  | [ODRL policy](https://github.com/eyereasoner/eyeprolog/blob/main/examples/odrl-policy.pl) | Read one purpose-constrained permission from an ODRL policy graph. | [answers](https://github.com/eyereasoner/eyeprolog/blob/main/examples/output/odrl-policy.pl) |
7283
7283
  | [Advanced ODRL policy](https://github.com/eyereasoner/eyeprolog/blob/main/examples/odrl-policy-advanced.pl) | Evaluate permission, duty, constraint failure, and prohibition outcomes. | [answers](https://github.com/eyereasoner/eyeprolog/blob/main/examples/output/odrl-policy-advanced.pl) |
7284
+ | [ODRL policy reasoning](https://github.com/eyereasoner/eyeprolog/blob/main/examples/odrl-policy-reasoning.pl) | Query action relationships, rule and enforcement outcomes, conflict strategies and kinds, action/rule/policy subsumption, and three-valued WFS defaults. | [answers](https://github.com/eyereasoner/eyeprolog/blob/main/examples/output/odrl-policy-reasoning.pl) |
7284
7285
  | [RDF 1.2 annotated claims](https://github.com/eyereasoner/eyeprolog/blob/main/examples/rdf12-annotated-claims.pl) | Rank conflicting annotated claims by confidence and source trust. | [answers](https://github.com/eyereasoner/eyeprolog/blob/main/examples/output/rdf12-annotated-claims.pl) |
7285
7286
  | [RDF 1.2 annotation](https://github.com/eyereasoner/eyeprolog/blob/main/examples/rdf12-annotation.pl) | Recover an asserted triple together with its reifier and annotations. | [answers](https://github.com/eyereasoner/eyeprolog/blob/main/examples/output/rdf12-annotation.pl) |
7286
7287
  | [RDF 1.2 directional language](https://github.com/eyereasoner/eyeprolog/blob/main/examples/rdf12-directional-language.pl) | Preserve language and base-direction metadata in derived labels. | [answers](https://github.com/eyereasoner/eyeprolog/blob/main/examples/output/rdf12-directional-language.pl) |