kibi-core 0.23.0 → 0.26.1
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/package.json +1 -1
- package/schema/entities.pl +6 -0
- package/schema/validation.pl +7 -2
- package/src/certificate_check.pl +62 -1
- package/src/certificates.pl +17 -1
- package/src/checks.pl +4 -1
- package/src/claim_obligations.pl +706 -0
- package/src/code_certificates.pl +532 -0
- package/src/discovery.pl +160 -2
- package/src/intervals.pl +11 -0
- package/src/kb.pl +55 -1
- package/src/model_check.pl +728 -0
- package/src/requirement_proof.pl +561 -42
- package/src/rule_registry.pl +8 -0
- package/src/semantic_quality.pl +1 -1
package/package.json
CHANGED
package/schema/entities.pl
CHANGED
|
@@ -56,6 +56,9 @@ entity_property(req, exempts_claims, list).
|
|
|
56
56
|
% Absent reads as default.
|
|
57
57
|
entity_property(req, firmness, atom).
|
|
58
58
|
entity_property(adr, firmness, atom).
|
|
59
|
+
% The weakest evidence level a current requirement accepts: proved, tested,
|
|
60
|
+
% asserted or unverified. Absent: tested when firm, otherwise unverified.
|
|
61
|
+
entity_property(req, required_evidence, atom).
|
|
59
62
|
% Intended outcome of a scenario: success, rejection or error.
|
|
60
63
|
entity_property(scenario, expects, atom).
|
|
61
64
|
|
|
@@ -69,6 +72,8 @@ entity_property(fact, value_string, string).
|
|
|
69
72
|
entity_property(fact, value_int, integer).
|
|
70
73
|
entity_property(fact, value_number, number).
|
|
71
74
|
entity_property(fact, value_bool, boolean).
|
|
75
|
+
% The exact members of a set fact (value_type set).
|
|
76
|
+
entity_property(fact, value_set, list).
|
|
72
77
|
entity_property(fact, unit, string).
|
|
73
78
|
entity_property(fact, scope, string).
|
|
74
79
|
entity_property(fact, polarity, atom).
|
|
@@ -150,6 +155,7 @@ optional_property(req, rationale).
|
|
|
150
155
|
optional_property(req, exempts_claims).
|
|
151
156
|
optional_property(req, firmness).
|
|
152
157
|
optional_property(adr, firmness).
|
|
158
|
+
optional_property(req, required_evidence).
|
|
153
159
|
optional_property(test, verification_scope).
|
|
154
160
|
optional_property(test, verification_perspective).
|
|
155
161
|
optional_property(test, proof_contract).
|
package/schema/validation.pl
CHANGED
|
@@ -108,6 +108,7 @@ is_fact_only_field(value_string).
|
|
|
108
108
|
is_fact_only_field(value_int).
|
|
109
109
|
is_fact_only_field(value_number).
|
|
110
110
|
is_fact_only_field(value_bool).
|
|
111
|
+
is_fact_only_field(value_set).
|
|
111
112
|
is_fact_only_field(unit).
|
|
112
113
|
is_fact_only_field(scope).
|
|
113
114
|
is_fact_only_field(polarity).
|
|
@@ -156,6 +157,8 @@ validate_fact_shape(property_value, Props) :-
|
|
|
156
157
|
valid_operator(Op),
|
|
157
158
|
memberchk(value_type=VT, Props),
|
|
158
159
|
valid_value_type(VT),
|
|
160
|
+
( Op == matches -> VT == string ; true ),
|
|
161
|
+
( memberchk(Op, [includes, subset_of, excludes]) -> VT == set ; true ),
|
|
159
162
|
exactly_one_value_field(Props),
|
|
160
163
|
value_type_matches_field(VT, Props),
|
|
161
164
|
valid_optional_fact_enums(Props),
|
|
@@ -224,10 +227,10 @@ text_atom(Value, Atom) :- atom(Value), !, Atom = Value.
|
|
|
224
227
|
text_atom(Value, Atom) :- string(Value), atom_string(Atom, Value).
|
|
225
228
|
|
|
226
229
|
% valid_operator(+Op)
|
|
227
|
-
valid_operator(Op) :- memberchk(Op, [eq, neq, lt, lte, gt, gte]), !.
|
|
230
|
+
valid_operator(Op) :- memberchk(Op, [eq, neq, lt, lte, gt, gte, matches, includes, subset_of, excludes]), !.
|
|
228
231
|
|
|
229
232
|
% valid_value_type(+VT)
|
|
230
|
-
valid_value_type(ValueType) :- memberchk(ValueType, [string, int, number, bool]), !.
|
|
233
|
+
valid_value_type(ValueType) :- memberchk(ValueType, [string, int, number, bool, set]), !.
|
|
231
234
|
|
|
232
235
|
% valid_polarity_in_props(+Props)
|
|
233
236
|
% Validates polarity if present; succeeds if no polarity in props
|
|
@@ -299,6 +302,7 @@ is_value_field(value_string).
|
|
|
299
302
|
is_value_field(value_int).
|
|
300
303
|
is_value_field(value_number).
|
|
301
304
|
is_value_field(value_bool).
|
|
305
|
+
is_value_field(value_set).
|
|
302
306
|
|
|
303
307
|
% value_type_matches_field(+ValueType, +Props)
|
|
304
308
|
% Ensures that value_type matches the actual value field present
|
|
@@ -306,6 +310,7 @@ value_type_matches_field(string, Props) :- memberchk(value_string=_, Props), !.
|
|
|
306
310
|
value_type_matches_field(int, Props) :- memberchk(value_int=_, Props), !.
|
|
307
311
|
value_type_matches_field(number, Props) :- memberchk(value_number=_, Props), !.
|
|
308
312
|
value_type_matches_field(bool, Props) :- memberchk(value_bool=_, Props), !.
|
|
313
|
+
value_type_matches_field(set, Props) :- memberchk(value_set=_, Props), !.
|
|
309
314
|
|
|
310
315
|
% valid_origin_in_props(+Props)
|
|
311
316
|
% Entity provenance travels as a JSON object string (or a dict). When present
|
package/src/certificate_check.pl
CHANGED
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
certificate_rule_edges/1,
|
|
39
39
|
certificate_member_holds/3,
|
|
40
40
|
certificate_members_satisfiable/2,
|
|
41
|
+
set_texts/2,
|
|
41
42
|
verify_certificates/2,
|
|
42
43
|
kb_verify_certificates_file/2
|
|
43
44
|
]).
|
|
@@ -148,7 +149,7 @@ kind_is(Certificate, Kind) :-
|
|
|
148
149
|
% Every comparable context: context(Subject, Property, Scope, Domain, Members)
|
|
149
150
|
% or unresolved(Subject, Property, Scope, Reason). A member is
|
|
150
151
|
% m(FactId, Op, Value, ValidFrom, ValidTo) with the operator already negated
|
|
151
|
-
% for a forbid fact; Domain is int, number, bool or
|
|
152
|
+
% for a forbid fact; Domain is int, number, bool, string or set.
|
|
152
153
|
certificate_property_contexts(Contexts) :-
|
|
153
154
|
findall(Fact-tuple(Subject, Property, Op, Type, Value, Unit, Scope, Polarity, From, To),
|
|
154
155
|
( kb:current_req(Req),
|
|
@@ -202,6 +203,8 @@ context_domain(Members, Domain, Reason) :-
|
|
|
202
203
|
-> Domain = bool, context_scalar_reason(Members, Reason)
|
|
203
204
|
; Types == [string]
|
|
204
205
|
-> Domain = string, context_scalar_reason(Members, Reason)
|
|
206
|
+
; Types == [set]
|
|
207
|
+
-> Domain = set, context_set_reason(Members, Reason)
|
|
205
208
|
; Types = [_, _|_]
|
|
206
209
|
-> Domain = none, Reason = "the facts use different value types"
|
|
207
210
|
; Domain = none, Reason = "the value type is not supported"
|
|
@@ -225,6 +228,25 @@ context_scalar_reason(Members, Reason) :-
|
|
|
225
228
|
; Reason = none
|
|
226
229
|
).
|
|
227
230
|
|
|
231
|
+
% Sets also compare with includes (every member of the bound has the
|
|
232
|
+
% property), subset_of (every member with the property is in the bound) and
|
|
233
|
+
% excludes (no member of the bound has it), but only as requirements: a
|
|
234
|
+
% forbidden one has no single negation among the set operators. neq beside
|
|
235
|
+
% subset_of or excludes is left unresolved: the finite candidates below decide
|
|
236
|
+
% those only without neq.
|
|
237
|
+
context_set_reason(Members, Reason) :-
|
|
238
|
+
( member(_-tuple(_, _, Op, _, _, _, _, Polarity, _, _), Members),
|
|
239
|
+
( \+ memberchk(Op, [eq, neq, includes, subset_of, excludes])
|
|
240
|
+
; memberchk(Op, [includes, subset_of, excludes]), Polarity == forbid
|
|
241
|
+
)
|
|
242
|
+
-> Reason = "only eq, neq and a required includes, subset_of or excludes compare set values"
|
|
243
|
+
; member(_-tuple(_, _, neq, _, _, _, _, _, _, _), Members),
|
|
244
|
+
member(_-tuple(_, _, Bounding, _, _, _, _, _, _, _), Members),
|
|
245
|
+
memberchk(Bounding, [subset_of, excludes])
|
|
246
|
+
-> Reason = "neq beside subset_of or excludes on one set property is not compared"
|
|
247
|
+
; Reason = none
|
|
248
|
+
).
|
|
249
|
+
|
|
228
250
|
context_member(_Domain, Fact-tuple(_, _, Op0, _, Value, _, _, Polarity, From, To), m(Fact, Op, Value, From, To)) :-
|
|
229
251
|
( Polarity == forbid
|
|
230
252
|
-> numeric_constraint_negation(c(Op0, _, Value), c(Op, _, _))
|
|
@@ -247,6 +269,26 @@ certificate_member_holds(Domain, m(_, Op, Bound, _, _), Value) :-
|
|
|
247
269
|
; Op == neq -> ValueText \== BoundText
|
|
248
270
|
).
|
|
249
271
|
|
|
272
|
+
% A set value is the exact set of members with the property: eq holds for
|
|
273
|
+
% the same members in any order, neq for any other set, includes for any set
|
|
274
|
+
% that contains every member of the bound.
|
|
275
|
+
certificate_member_holds(set, m(_, Op, Bound, _, _), Value) :-
|
|
276
|
+
set_texts(Value, ValueTexts),
|
|
277
|
+
set_texts(Bound, BoundTexts),
|
|
278
|
+
( Op == eq -> ValueTexts == BoundTexts
|
|
279
|
+
; Op == neq -> ValueTexts \== BoundTexts
|
|
280
|
+
; Op == includes -> subtract(BoundTexts, ValueTexts, [])
|
|
281
|
+
; Op == subset_of -> subtract(ValueTexts, BoundTexts, [])
|
|
282
|
+
; Op == excludes -> \+ ( member(Text, ValueTexts), memberchk(Text, BoundTexts) )
|
|
283
|
+
).
|
|
284
|
+
|
|
285
|
+
%% set_texts(+Value, -Texts)
|
|
286
|
+
% The sorted, unique member texts of a set value.
|
|
287
|
+
set_texts(Value, Texts) :-
|
|
288
|
+
is_list(Value),
|
|
289
|
+
maplist(text_of, Value, Texts0),
|
|
290
|
+
sort(Texts0, Texts).
|
|
291
|
+
|
|
250
292
|
numeric_domain(int).
|
|
251
293
|
numeric_domain(number).
|
|
252
294
|
|
|
@@ -282,6 +324,25 @@ scalar_candidates(string, Members, Candidates) :-
|
|
|
282
324
|
atomic_list_concat(["kibi:fresh"|Texts], '|', FreshAtom),
|
|
283
325
|
atom_string(FreshAtom, Fresh),
|
|
284
326
|
append(Texts, [Fresh], Candidates).
|
|
327
|
+
scalar_candidates(set, Members, Candidates) :-
|
|
328
|
+
findall(Texts, (member(m(_, _, Bound, _, _), Members), set_texts(Bound, Texts)), Sets0),
|
|
329
|
+
sort(Sets0, Sets),
|
|
330
|
+
findall(Text, (member(Set, Sets), member(Text, Set)), Texts0),
|
|
331
|
+
sort(Texts0, Texts),
|
|
332
|
+
atomic_list_concat(["kibi:fresh"|Texts], '|', FreshAtom),
|
|
333
|
+
atom_string(FreshAtom, Fresh),
|
|
334
|
+
% The union of every bound satisfies any set of includes facts alone; the
|
|
335
|
+
% union of the includes bounds is the least set every includes fact
|
|
336
|
+
% allows, so with subset_of and excludes (and no eq or neq) it is
|
|
337
|
+
% satisfiable exactly when that union is.
|
|
338
|
+
includes_union(Members, Included),
|
|
339
|
+
append(Sets, [Texts, Included, [Fresh]], Candidates).
|
|
340
|
+
|
|
341
|
+
includes_union(Members, Union) :-
|
|
342
|
+
findall(Text,
|
|
343
|
+
(member(m(_, includes, Bound, _, _), Members), set_texts(Bound, Set), member(Text, Set)),
|
|
344
|
+
Texts),
|
|
345
|
+
sort(Texts, Union).
|
|
285
346
|
|
|
286
347
|
property_theorem(Contexts, Numbered, Theorem, Used, Rejected) :-
|
|
287
348
|
findall(Index-Certificate,
|
package/src/certificates.pl
CHANGED
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
certificate_decision_groups/1,
|
|
28
28
|
certificate_rule_edges/1,
|
|
29
29
|
certificate_member_holds/3,
|
|
30
|
-
certificate_members_satisfiable/2
|
|
30
|
+
certificate_members_satisfiable/2,
|
|
31
|
+
set_texts/2
|
|
31
32
|
]).
|
|
32
33
|
|
|
33
34
|
%% kb_write_certificates(+Path, -JsonString)
|
|
@@ -121,6 +122,21 @@ model_candidates(string, Members, Candidates) :-
|
|
|
121
122
|
fresh_text(Bounds, 0, Fresh),
|
|
122
123
|
append(Bounds, [Fresh], Candidates).
|
|
123
124
|
|
|
125
|
+
model_candidates(set, Members, Candidates) :-
|
|
126
|
+
findall(Set, (member(m(_, _, Bound, _, _), Members), set_texts(Bound, Set)), Sets0),
|
|
127
|
+
sort(Sets0, Sets),
|
|
128
|
+
findall(Text, (member(Set, Sets), member(Text, Set)), Texts0),
|
|
129
|
+
sort(Texts0, Texts),
|
|
130
|
+
fresh_text(Texts, 0, Fresh),
|
|
131
|
+
% The union of every bound satisfies any set of includes facts alone;
|
|
132
|
+
% the union of the includes bounds alone is the least set they allow,
|
|
133
|
+
% which subset_of and excludes facts accept when anything does.
|
|
134
|
+
findall(Text,
|
|
135
|
+
(member(m(_, includes, Bound, _, _), Members), set_texts(Bound, Set), member(Text, Set)),
|
|
136
|
+
Included0),
|
|
137
|
+
sort(Included0, Included),
|
|
138
|
+
append(Sets, [Texts, Included, [Fresh]], Candidates).
|
|
139
|
+
|
|
124
140
|
fresh_text(Bounds, Index, Fresh) :-
|
|
125
141
|
format(string(Candidate), "kibi:model:~w", [Index]),
|
|
126
142
|
( member(Bound, Bounds), text_value(Bound, Candidate)
|
package/src/checks.pl
CHANGED
|
@@ -2377,7 +2377,7 @@ property_value_shape_error(Props, "Property value fact missing required field: o
|
|
|
2377
2377
|
property_value_shape_error(Props, "Property value fact missing required field: value_type") :-
|
|
2378
2378
|
memberchk(operator=_, Props),
|
|
2379
2379
|
\+ memberchk(value_type=_, Props).
|
|
2380
|
-
property_value_shape_error(Props, "Property value fact missing value field (value_string, value_int, value_number, or
|
|
2380
|
+
property_value_shape_error(Props, "Property value fact missing value field (value_string, value_int, value_number, value_bool, or value_set)") :-
|
|
2381
2381
|
memberchk(value_type=_, Props),
|
|
2382
2382
|
\+ has_value_field(Props).
|
|
2383
2383
|
property_value_shape_error(Props, "Property value fact has multiple value fields (should have exactly one)") :-
|
|
@@ -2394,17 +2394,20 @@ is_value_field(value_string).
|
|
|
2394
2394
|
is_value_field(value_int).
|
|
2395
2395
|
is_value_field(value_number).
|
|
2396
2396
|
is_value_field(value_bool).
|
|
2397
|
+
is_value_field(value_set).
|
|
2397
2398
|
|
|
2398
2399
|
has_value_field(Props) :- memberchk(value_string=_, Props), !.
|
|
2399
2400
|
has_value_field(Props) :- memberchk(value_int=_, Props), !.
|
|
2400
2401
|
has_value_field(Props) :- memberchk(value_number=_, Props), !.
|
|
2401
2402
|
has_value_field(Props) :- memberchk(value_bool=_, Props), !.
|
|
2403
|
+
has_value_field(Props) :- memberchk(value_set=_, Props), !.
|
|
2402
2404
|
|
|
2403
2405
|
% value_type_matches_field(+ValueType, +Props)
|
|
2404
2406
|
value_type_matches_field(string, Props) :- memberchk(value_string=_, Props), !.
|
|
2405
2407
|
value_type_matches_field(int, Props) :- memberchk(value_int=_, Props), !.
|
|
2406
2408
|
value_type_matches_field(number, Props) :- memberchk(value_number=_, Props), !.
|
|
2407
2409
|
value_type_matches_field(bool, Props) :- memberchk(value_bool=_, Props), !.
|
|
2410
|
+
value_type_matches_field(set, Props) :- memberchk(value_set=_, Props), !.
|
|
2408
2411
|
|
|
2409
2412
|
predicate_schema_shape_error(Props, "Predicate schema fact missing required field: predicate_name") :-
|
|
2410
2413
|
\+ memberchk(predicate_name=_, Props).
|