kibi-core 0.24.0 → 0.27.0
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/validation.pl +3 -1
- package/src/certificate_check.pl +38 -4
- package/src/certificates.pl +10 -2
- package/src/checks.pl +178 -17
- package/src/claim_obligations.pl +371 -28
- package/src/code_certificates.pl +243 -4
- package/src/discovery.pl +65 -23
- package/src/intervals.pl +35 -14
- package/src/kb.pl +337 -38
- package/src/kb_consistency.pl +15 -0
- package/src/logic_ir.pl +130 -161
- package/src/model_check.pl +776 -0
- package/src/requirement_proof.pl +101 -13
- package/src/rule_registry.pl +1 -1
- package/src/status.pl +16 -0
- package/src/units.pl +1 -3
package/src/requirement_proof.pl
CHANGED
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
:- use_module('logic_ir.pl', [logic_rule_safety/2]).
|
|
28
28
|
:- use_module('code_certificates.pl', [code_certificate_check/2, code_certificate_digest/2]).
|
|
29
29
|
:- use_module('claim_obligations.pl', [claim_obligation/3, obligation_equal/2]).
|
|
30
|
+
:- use_module('model_check.pl', [model_check_obligation/4]).
|
|
30
31
|
|
|
31
32
|
proof_version('kibi.requirement-proof.v5').
|
|
32
33
|
|
|
@@ -53,7 +54,13 @@ requirement_proof_context(VerificationSnapshot, CheckedAt, MaxAgeSeconds,
|
|
|
53
54
|
(catch(parse_time(CheckedAtAtom, CheckedAtStamp), _, fail) -> true ; CheckedAtStamp = -1),
|
|
54
55
|
normalize_integer(MaxAgeSeconds, MaxAge),
|
|
55
56
|
normalize_atom(BindingMode, BindingModeAtom),
|
|
57
|
+
% Everything else in the context follows from the KB, so the proof memo
|
|
58
|
+
% key needs only the caller's parameters.
|
|
59
|
+
variant_sha1(params(Snapshot, CheckedAtAtom, MaxAge, BindingModeAtom, TestBindings), ParamsKey),
|
|
60
|
+
variant_sha1(findings(Contradictions, ContradictionWitnesses, UnsafeRules, UnverifiableRules), FindingsKey),
|
|
56
61
|
Context = _{
|
|
62
|
+
proofMemoKey: ParamsKey,
|
|
63
|
+
ladderMemoKey: FindingsKey,
|
|
57
64
|
contradictions: Contradictions,
|
|
58
65
|
contradictionWitnesses: ContradictionWitnesses,
|
|
59
66
|
unsafeRules: UnsafeRules,
|
|
@@ -67,28 +74,86 @@ requirement_proof_context(VerificationSnapshot, CheckedAt, MaxAgeSeconds,
|
|
|
67
74
|
}.
|
|
68
75
|
|
|
69
76
|
% implements REQ-kibi-conservative-requirement-proof
|
|
77
|
+
% A requirement's proof is kept per KB generation and proof parameters, so
|
|
78
|
+
% the evidence-floor rule, the coverage evidence and a coverage report in one
|
|
79
|
+
% check read each ladder once. Inside a transaction (what-if staging) the
|
|
80
|
+
% KB is not the generation's, so the proof is computed afresh.
|
|
81
|
+
requirement_proof(ReqId, ReqProps, Context, Proof) :-
|
|
82
|
+
( \+ rdf_db:rdf_active_transaction(_),
|
|
83
|
+
get_dict(proofMemoKey, Context, ParamsKey),
|
|
84
|
+
kb:index_verification_key(requirement_proof, IndexKey)
|
|
85
|
+
-> Key = key(IndexKey, ParamsKey),
|
|
86
|
+
( kb:kb_requirement_proof_memo(ReqId, Key, Proof0)
|
|
87
|
+
-> Proof = Proof0
|
|
88
|
+
; compute_requirement_proof(ReqId, ReqProps, Context, Proof),
|
|
89
|
+
( once(kb:kb_requirement_proof_memo(_, Stored, _)),
|
|
90
|
+
Stored \== Key
|
|
91
|
+
-> retractall(kb:kb_requirement_proof_memo(_, _, _))
|
|
92
|
+
; true
|
|
93
|
+
),
|
|
94
|
+
assertz(kb:kb_requirement_proof_memo(ReqId, Key, Proof))
|
|
95
|
+
)
|
|
96
|
+
; compute_requirement_proof(ReqId, ReqProps, Context, Proof)
|
|
97
|
+
).
|
|
98
|
+
|
|
99
|
+
% The stages before passing_e2e read the KB and the context's KB-derived
|
|
100
|
+
% findings (contradictions, unsafe and unverifiable rules) only, never the
|
|
101
|
+
% caller's snapshot, receipt bindings or checkedAt. A check passes a new
|
|
102
|
+
% checkedAt every run, so these stages are kept per KB generation and those
|
|
103
|
+
% findings apart from the full proof; inside a transaction they are computed
|
|
104
|
+
% afresh.
|
|
105
|
+
receipt_independent_stages(ReqId, ReqProps, Context, Ladder) :-
|
|
106
|
+
( \+ rdf_db:rdf_active_transaction(_),
|
|
107
|
+
get_dict(ladderMemoKey, Context, FindingsKey),
|
|
108
|
+
kb:index_verification_key(requirement_ladder, IndexKey)
|
|
109
|
+
-> variant_sha1(ReqProps, PropsKey),
|
|
110
|
+
Key = key(IndexKey, FindingsKey, PropsKey),
|
|
111
|
+
( kb:kb_requirement_ladder_memo(ReqId, Key, Ladder0)
|
|
112
|
+
-> Ladder = Ladder0
|
|
113
|
+
; compute_receipt_independent_stages(ReqId, ReqProps, Context, Ladder),
|
|
114
|
+
( once(kb:kb_requirement_ladder_memo(_, key(Stored, _, _), _)),
|
|
115
|
+
Stored \== IndexKey
|
|
116
|
+
-> retractall(kb:kb_requirement_ladder_memo(_, _, _))
|
|
117
|
+
; true
|
|
118
|
+
),
|
|
119
|
+
retractall(kb:kb_requirement_ladder_memo(ReqId, _, _)),
|
|
120
|
+
assertz(kb:kb_requirement_ladder_memo(ReqId, Key, Ladder))
|
|
121
|
+
)
|
|
122
|
+
; compute_receipt_independent_stages(ReqId, ReqProps, Context, Ladder)
|
|
123
|
+
).
|
|
124
|
+
|
|
125
|
+
compute_receipt_independent_stages(ReqId, ReqProps, Context,
|
|
126
|
+
ladder(SemanticStage, Inventory, LogicStage, ContradictionStage,
|
|
127
|
+
ScenarioStage, ScenarioTestStage, ScenarioTests, SymbolSets)) :-
|
|
128
|
+
semantic_inventory_stage(ReqProps, SemanticStage, Inventory),
|
|
129
|
+
logic_grounding_stage(ReqId, ReqProps, Inventory, Context, LogicStage),
|
|
130
|
+
contradiction_stage(ReqId, LogicStage.status, SemanticStage.status, Context, ContradictionStage),
|
|
131
|
+
scenario_stage(ReqId, ScenarioStage, ScenarioIds),
|
|
132
|
+
scenario_test_stage(ScenarioIds, ScenarioTestStage, ScenarioTests),
|
|
133
|
+
production_symbol_sets(ReqId, SymbolSets).
|
|
134
|
+
|
|
70
135
|
% Exemption first: a current requirement explicitly marked proof_exempt with a
|
|
71
136
|
% reason is intentionally outside E2E-proof scope and must never fall through
|
|
72
137
|
% to the ladder (which would report misleading receipt gaps).
|
|
73
|
-
|
|
138
|
+
compute_requirement_proof(ReqId, ReqProps, _Context, Proof) :-
|
|
74
139
|
kb:current_req(ReqId),
|
|
75
140
|
proof_exempt(ReqProps, Reason),
|
|
76
141
|
!,
|
|
77
142
|
exempt_requirement_proof(Reason, ReqProps, Proof).
|
|
78
|
-
|
|
143
|
+
compute_requirement_proof(ReqId, ReqProps, _Context, Proof) :-
|
|
79
144
|
\+ kb:current_req(ReqId),
|
|
80
145
|
!,
|
|
81
146
|
applicability_exclusion_reason(ReqId, Reason),
|
|
82
147
|
exempt_requirement_proof(Reason, ReqProps, Proof).
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
scenario_stage(ReqId, ScenarioStage, ScenarioIds),
|
|
88
|
-
scenario_test_stage(ScenarioIds, ScenarioTestStage, ScenarioTests),
|
|
148
|
+
compute_requirement_proof(ReqId, ReqProps, Context, Proof) :-
|
|
149
|
+
receipt_independent_stages(ReqId, ReqProps, Context,
|
|
150
|
+
ladder(SemanticStage, Inventory, LogicStage, ContradictionStage,
|
|
151
|
+
ScenarioStage, ScenarioTestStage, ScenarioTests, SymbolSets)),
|
|
89
152
|
passing_e2e_stage(ScenarioTestStage, Context, PassingE2eStage, PassingE2eTests),
|
|
90
153
|
executable_symbol_stage(PassingE2eTests, ExecutableStage, ExecutableSymbols),
|
|
91
|
-
|
|
154
|
+
production_symbol_stage_from_sets(ReqId, SymbolSets, PassingE2eTests, ScenarioTests,
|
|
155
|
+
PassingE2eStage.receiptEvidence, Context,
|
|
156
|
+
ProductionStage, ProductionSymbols),
|
|
92
157
|
source_coordinate_stage(ReqProps, ExecutableSymbols, ProductionSymbols, CoordinateStage),
|
|
93
158
|
Stages = _{
|
|
94
159
|
semanticInventory: SemanticStage,
|
|
@@ -1009,7 +1074,7 @@ valid_receipt_version_fields('kibi.proof-receipt.v1', _Receipt).
|
|
|
1009
1074
|
valid_receipt_version_fields('kibi.proof-receipt.v2', Receipt) :-
|
|
1010
1075
|
inventory_entry_field(Receipt, kind, RawKind),
|
|
1011
1076
|
normalize_receipt_atom(RawKind, Kind),
|
|
1012
|
-
memberchk(Kind, [e2e, example, property, exhaustive, typecheck, arithmetic, smt]),
|
|
1077
|
+
memberchk(Kind, [e2e, example, property, exhaustive, typecheck, arithmetic, smt, rule, state_machine, regex, source]),
|
|
1013
1078
|
inventory_entry_field(Receipt, evidence_level, RawLevel),
|
|
1014
1079
|
normalize_receipt_atom(RawLevel, Level),
|
|
1015
1080
|
memberchk(Level, [proved, tested]),
|
|
@@ -1019,7 +1084,7 @@ valid_receipt_version_fields('kibi.proof-receipt.v2', Receipt) :-
|
|
|
1019
1084
|
; true
|
|
1020
1085
|
),
|
|
1021
1086
|
( Level == proved
|
|
1022
|
-
-> memberchk(Kind, [exhaustive, typecheck, arithmetic, smt]),
|
|
1087
|
+
-> memberchk(Kind, [exhaustive, typecheck, arithmetic, smt, rule, state_machine, regex, source]),
|
|
1023
1088
|
inventory_entry_field(Receipt, outcome, RawOutcome),
|
|
1024
1089
|
normalize_receipt_atom(RawOutcome, passed),
|
|
1025
1090
|
inventory_entry_field(Receipt, certificate, _),
|
|
@@ -1210,6 +1275,11 @@ canonical_json_value(Value, Json) :-
|
|
|
1210
1275
|
maplist(canonical_json_value, Value, Parts),
|
|
1211
1276
|
atomics_to_string(Parts, ",", Body),
|
|
1212
1277
|
format(string(Json), "[~s]", [Body]).
|
|
1278
|
+
% JSON true, false and null read back as atoms; json_write would quote them,
|
|
1279
|
+
% so the hash would differ from the one the CLI recorded at ingest.
|
|
1280
|
+
canonical_json_value(Value, Json) :-
|
|
1281
|
+
memberchk(Value, [true, false, null]), !,
|
|
1282
|
+
atom_string(Value, Json).
|
|
1213
1283
|
canonical_json_value(Value, Json) :-
|
|
1214
1284
|
with_output_to(string(Json), json_write(current_output, Value, [width(0)])).
|
|
1215
1285
|
|
|
@@ -1374,6 +1444,14 @@ production_symbol_stage(ReqId, PassingE2eTests, Stage, ProductionSymbols) :-
|
|
|
1374
1444
|
production_symbol_stage(ReqId, PassingE2eTests, ScenarioTests, [], Context, Stage, ProductionSymbols).
|
|
1375
1445
|
|
|
1376
1446
|
production_symbol_stage(ReqId, PassingE2eTests, ScenarioTests, ReceiptEvidence, Context, Stage, ProductionSymbols) :-
|
|
1447
|
+
production_symbol_sets(ReqId, Sets),
|
|
1448
|
+
production_symbol_stage_from_sets(ReqId, Sets, PassingE2eTests, ScenarioTests,
|
|
1449
|
+
ReceiptEvidence, Context, Stage, ProductionSymbols).
|
|
1450
|
+
|
|
1451
|
+
% The implementing symbols of a requirement, split into structural
|
|
1452
|
+
% (type-shape with a unit-test contract) and production ones, with the
|
|
1453
|
+
% production symbols' coordinates: all read from the KB alone.
|
|
1454
|
+
production_symbol_sets(ReqId, symbol_sets(StructuralSymbols, ProductionSymbols, Coordinates)) :-
|
|
1377
1455
|
findall(SymbolId,
|
|
1378
1456
|
(kb_relationship(implements, SymbolId, ReqId),
|
|
1379
1457
|
kb_entity(SymbolId, symbol, _),
|
|
@@ -1382,13 +1460,17 @@ production_symbol_stage(ReqId, PassingE2eTests, ScenarioTests, ReceiptEvidence,
|
|
|
1382
1460
|
sort(Implementing0, ImplementingSymbols),
|
|
1383
1461
|
include(type_shape_symbol_with_structural_contract, ImplementingSymbols, StructuralSymbols),
|
|
1384
1462
|
exclude(type_shape_symbol_with_structural_contract, ImplementingSymbols, ProductionSymbols),
|
|
1463
|
+
maplist(symbol_coordinate_ref, ProductionSymbols, Coordinates).
|
|
1464
|
+
|
|
1465
|
+
production_symbol_stage_from_sets(ReqId, symbol_sets(StructuralSymbols, ProductionSymbols, Coordinates),
|
|
1466
|
+
PassingE2eTests, ScenarioTests, ReceiptEvidence, Context,
|
|
1467
|
+
Stage, ProductionSymbols) :-
|
|
1385
1468
|
include(symbol_not_covered_by_tests(PassingE2eTests), ProductionSymbols, UncoveredProduction),
|
|
1386
1469
|
structural_unit_receipts(StructuralSymbols, Context, UnitReceipts),
|
|
1387
1470
|
exclude(structural_symbol_covered(PassingE2eTests, UnitReceipts), StructuralSymbols, UncoveredStructural),
|
|
1388
1471
|
append(UncoveredProduction, UncoveredStructural, UncoveredSymbols),
|
|
1389
1472
|
production_stage_status(ProductionSymbols, StructuralSymbols, PassingE2eTests,
|
|
1390
1473
|
UncoveredProduction, UncoveredStructural, Status, StatusReason),
|
|
1391
|
-
maplist(symbol_coordinate_ref, ProductionSymbols, Coordinates),
|
|
1392
1474
|
production_coverage_explanations(
|
|
1393
1475
|
ReqId, ProductionSymbols, StructuralSymbols, UncoveredSymbols,
|
|
1394
1476
|
PassingE2eTests, ScenarioTests, ReceiptEvidence, UnitReceipts-Context, Explanations),
|
|
@@ -1996,7 +2078,7 @@ claim_entry(ReqId, ProofStatus, IntentLevel, BoundTests, InventoryEntry, Entry)
|
|
|
1996
2078
|
sort(Bindings0, Bindings),
|
|
1997
2079
|
include(binding_is(rejected), Bindings, RejectedBindings),
|
|
1998
2080
|
maplist(binding_rejection(Key), RejectedBindings, Rejections),
|
|
1999
|
-
( member(B, Bindings), get_dict(binding, B, derived), get_dict(scope, B,
|
|
2081
|
+
( member(B, Bindings), get_dict(binding, B, derived), \+ get_dict(scope, B, intent)
|
|
2000
2082
|
-> Level = proved
|
|
2001
2083
|
; Level = tested
|
|
2002
2084
|
),
|
|
@@ -2097,6 +2179,12 @@ certificate_obligation_problem(arithmetic, Evidence, Obligation, Problem) :-
|
|
|
2097
2179
|
; Problem = 'the certificate\'s claim is not the fact\'s constraint'
|
|
2098
2180
|
).
|
|
2099
2181
|
|
|
2182
|
+
certificate_obligation_problem(Kind, Evidence, Obligation, Problem) :-
|
|
2183
|
+
memberchk(Kind, [rule, state_machine, source]),
|
|
2184
|
+
get_dict(certificate, Evidence, Certificate),
|
|
2185
|
+
model_check_obligation(Kind, Obligation, Certificate, problem(Problem0)),
|
|
2186
|
+
atom_string(Problem, Problem0).
|
|
2187
|
+
|
|
2100
2188
|
%% claim_summary(+ClaimEvidence, -Summary, -UnprovedClaims)
|
|
2101
2189
|
claim_summary(ClaimEvidence, Summary, Unproved) :-
|
|
2102
2190
|
include(applicable_claim, ClaimEvidence, Applicable),
|
package/src/rule_registry.pl
CHANGED
|
@@ -318,4 +318,4 @@ rule_description('policy-markers', 'When a plugin activated for kibi.check-polic
|
|
|
318
318
|
rule_description('kb-consistency', 'The facts current requirements name must hold together, jointly and not only pairwise: every property context needs a value that satisfies all its facts, every atom and decision key one truth value, and stored rules a stratification. Each finding is a contradiction certificate (an irreducible core, two disagreeing facts or a negation cycle) re-verified by the independent checker, or a certificate that checker rejects').
|
|
319
319
|
rule_description('kb-consistency-unresolved', 'Advisory: a property context, atom or decision key whose facts the consistency checker cannot compare (mixed value types or units, an unsupported operator or polarity, or a contradiction whose validity windows never overlap); it never counts as consistent').
|
|
320
320
|
rule_description('evidence-floor', 'Every current requirement\'s computed evidence level (proved, tested, asserted, unverified) must reach its floor: required_evidence when set, otherwise tested for a firm requirement and no floor for any other. Receipts that are only older than the code count as pending re-proof and pass, unless kibi check runs with --fresh-evidence, which also needs a clean proof snapshot').
|
|
321
|
-
rule_description('proof-contract-claims', 'From schema 12, every certificate-kind proof contract (exhaustive, typecheck, arithmetic, smt) must name the claims it proves in proves, and each named claim must be a modeled claim of a current requirement the test reaches through its scenarios, grounded by a fact that proof kind can express or attest').
|
|
321
|
+
rule_description('proof-contract-claims', 'From schema 12, every certificate-kind proof contract (exhaustive, typecheck, arithmetic, smt, rule, state_machine, regex) must name the claims it proves in proves, and each named claim must be a modeled claim of a current requirement the test reaches through its scenarios, grounded by a fact that proof kind can express or attest').
|
package/src/status.pl
CHANGED
|
@@ -203,7 +203,23 @@ kb_snapshot_time(SnapshotTime) :-
|
|
|
203
203
|
% made kb_status_json quadratic (paths x entities) and could wedge large KBs
|
|
204
204
|
% for minutes whenever mtime churn (e.g. a git checkout) marked whole lanes
|
|
205
205
|
% newer than the snapshot.
|
|
206
|
+
% The source -> entity id index reads every entity, so it is kept per KB
|
|
207
|
+
% generation (whose key names the attached store's graph): status runs it on
|
|
208
|
+
% each freshness probe while the KB is unchanged. Inside a transaction it is
|
|
209
|
+
% built afresh.
|
|
206
210
|
entity_source_id_index(Index) :-
|
|
211
|
+
( \+ rdf_db:rdf_active_transaction(_),
|
|
212
|
+
kb:index_verification_key(status_source_index, Key)
|
|
213
|
+
-> ( kb:kb_status_source_index_memo(Key, Index0)
|
|
214
|
+
-> Index = Index0
|
|
215
|
+
; compute_entity_source_id_index(Index),
|
|
216
|
+
retractall(kb:kb_status_source_index_memo(_, _)),
|
|
217
|
+
assertz(kb:kb_status_source_index_memo(Key, Index))
|
|
218
|
+
)
|
|
219
|
+
; compute_entity_source_id_index(Index)
|
|
220
|
+
).
|
|
221
|
+
|
|
222
|
+
compute_entity_source_id_index(Index) :-
|
|
207
223
|
findall(RelativeSource-Id,
|
|
208
224
|
( kb_entity(Id, _Type, Props),
|
|
209
225
|
entity_source_property(Props, RawSource),
|
package/src/units.pl
CHANGED
|
@@ -120,13 +120,11 @@ numeric_value_type(number).
|
|
|
120
120
|
|
|
121
121
|
known_unit(Unit, BaseUnit, Factor) :-
|
|
122
122
|
atom(Unit),
|
|
123
|
-
Unit \== '',
|
|
124
123
|
( unit_symbol(Unit, BaseUnit, Factor)
|
|
125
124
|
-> true
|
|
126
125
|
; downcase_atom(Unit, Lower),
|
|
127
126
|
unit_word(Lower, BaseUnit, Factor)
|
|
128
|
-
)
|
|
129
|
-
!.
|
|
127
|
+
).
|
|
130
128
|
|
|
131
129
|
% Integers (including big integers) stay exact. Floats have binary noise
|
|
132
130
|
% rounded away (0.1 h * 3600 = 360.00000000000006) before deciding whether the
|