kibi-core 0.12.0 → 0.14.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 +2 -5
- package/schema/entities.pl +3 -0
- package/schema/relationships.pl +8 -0
- package/schema/validation.pl +2 -0
- package/src/checks.pl +199 -36
- package/src/discovery.pl +97 -7
- package/src/kb.pl +322 -13
- package/src/requirement_proof.pl +337 -7
- package/src/rule_registry.pl +46 -0
- package/src/semantic_quality.pl +750 -0
- package/src/status.pl +41 -15
- package/src/units.pl +146 -0
package/src/requirement_proof.pl
CHANGED
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
requirement_proof/4
|
|
9
9
|
]).
|
|
10
10
|
|
|
11
|
+
% Source contains non-ASCII text; do not depend on the host locale.
|
|
12
|
+
:- encoding(utf8).
|
|
13
|
+
|
|
11
14
|
:- use_module(library(http/json)).
|
|
12
15
|
:- use_module(library(crypto)).
|
|
13
16
|
:- use_module(library(date)).
|
|
@@ -77,10 +80,10 @@ requirement_proof(ReqId, ReqProps, Context, Proof) :-
|
|
|
77
80
|
logic_grounding_stage(ReqId, ReqProps, Inventory, Context, LogicStage),
|
|
78
81
|
contradiction_stage(ReqId, LogicStage.status, Context, ContradictionStage),
|
|
79
82
|
scenario_stage(ReqId, ScenarioStage, ScenarioIds),
|
|
80
|
-
scenario_test_stage(ScenarioIds, ScenarioTestStage,
|
|
83
|
+
scenario_test_stage(ScenarioIds, ScenarioTestStage, ScenarioTests),
|
|
81
84
|
passing_e2e_stage(ScenarioTestStage, Context, PassingE2eStage, PassingE2eTests),
|
|
82
85
|
executable_symbol_stage(PassingE2eTests, ExecutableStage, ExecutableSymbols),
|
|
83
|
-
production_symbol_stage(ReqId, PassingE2eTests, ProductionStage, ProductionSymbols),
|
|
86
|
+
production_symbol_stage(ReqId, PassingE2eTests, ScenarioTests, PassingE2eStage.receiptEvidence, Context, ProductionStage, ProductionSymbols),
|
|
84
87
|
source_coordinate_stage(ReqProps, ExecutableSymbols, ProductionSymbols, CoordinateStage),
|
|
85
88
|
Stages = _{
|
|
86
89
|
semanticInventory: SemanticStage,
|
|
@@ -103,7 +106,8 @@ requirement_proof(ReqId, ReqProps, Context, Proof) :-
|
|
|
103
106
|
proofGaps: Gaps,
|
|
104
107
|
proofAdvisories: Advisories,
|
|
105
108
|
proofRepairs: Repairs,
|
|
106
|
-
proofStages: Stages
|
|
109
|
+
proofStages: Stages,
|
|
110
|
+
testResolutions: ScenarioTestStage.resolutions
|
|
107
111
|
}.
|
|
108
112
|
|
|
109
113
|
exempt_requirement_proof(Reason, Proof) :-
|
|
@@ -236,7 +240,47 @@ inventory_entry_field(List, Key, Value) :-
|
|
|
236
240
|
is_list(List),
|
|
237
241
|
memberchk(Key=Value, List).
|
|
238
242
|
|
|
243
|
+
% Pure-function memos, content-addressed by variant_sha1/2, so they need no
|
|
244
|
+
% invalidation: equal inputs always produce equal outputs. Proof evaluation
|
|
245
|
+
% re-parses the same receipt histories and re-validates the same receipts on
|
|
246
|
+
% every coverage run; both are bounded so a long-lived engine cannot grow them
|
|
247
|
+
% without limit.
|
|
248
|
+
:- dynamic pure_memo/3.
|
|
249
|
+
:- dynamic pure_memo_size/1.
|
|
250
|
+
|
|
251
|
+
pure_memo_limit(4096).
|
|
252
|
+
|
|
253
|
+
pure_memo(Kind, Input, Goal, Output) :-
|
|
254
|
+
variant_sha1(Kind-Input, Key),
|
|
255
|
+
( pure_memo(Key, Kind, Cached)
|
|
256
|
+
-> Output = Cached
|
|
257
|
+
; call(Goal, Input, Result),
|
|
258
|
+
pure_memo_remember(Key, Kind, Result),
|
|
259
|
+
Output = Result
|
|
260
|
+
).
|
|
261
|
+
|
|
262
|
+
pure_memo_remember(Key, Kind, Output) :-
|
|
263
|
+
( pure_memo_size(Size)
|
|
264
|
+
-> true
|
|
265
|
+
; Size = 0
|
|
266
|
+
),
|
|
267
|
+
pure_memo_limit(Limit),
|
|
268
|
+
( Size >= Limit
|
|
269
|
+
-> retractall(pure_memo(_, _, _)),
|
|
270
|
+
NextSize = 1
|
|
271
|
+
; NextSize is Size + 1
|
|
272
|
+
),
|
|
273
|
+
retractall(pure_memo_size(_)),
|
|
274
|
+
assertz(pure_memo_size(NextSize)),
|
|
275
|
+
assertz(pure_memo(Key, Kind, Output)).
|
|
276
|
+
|
|
239
277
|
inventory_entries(Raw, Entries) :-
|
|
278
|
+
( (atom(Raw) ; string(Raw))
|
|
279
|
+
-> pure_memo(inventory_entries, Raw, parse_inventory_entries, Entries)
|
|
280
|
+
; parse_inventory_entries(Raw, Entries)
|
|
281
|
+
).
|
|
282
|
+
|
|
283
|
+
parse_inventory_entries(Raw, Entries) :-
|
|
240
284
|
( is_list(Raw)
|
|
241
285
|
-> Entries = Raw
|
|
242
286
|
; Raw = ^^(Value, _)
|
|
@@ -532,6 +576,7 @@ scenario_test_stage(ScenarioIds, Stage, ScenarioTests) :-
|
|
|
532
576
|
; Status = passed
|
|
533
577
|
),
|
|
534
578
|
maplist(entity_source_ref, ScenarioTests, Sources),
|
|
579
|
+
maplist(test_resolution_record, ScenarioTests, Resolutions),
|
|
535
580
|
Stage = _{
|
|
536
581
|
status: Status,
|
|
537
582
|
scenarios: ScenarioIds,
|
|
@@ -539,7 +584,8 @@ scenario_test_stage(ScenarioIds, Stage, ScenarioTests) :-
|
|
|
539
584
|
scenarioTestTargets: ScenarioTestTargets,
|
|
540
585
|
invalidScenarioTestTargets: InvalidScenarioTestTargets,
|
|
541
586
|
sources: Sources,
|
|
542
|
-
obligations: Obligations
|
|
587
|
+
obligations: Obligations,
|
|
588
|
+
resolutions: Resolutions
|
|
543
589
|
}.
|
|
544
590
|
|
|
545
591
|
scenario_test_obligation(ScenarioId, Obligation) :-
|
|
@@ -724,8 +770,8 @@ receipt_evidence_state(TestId, Scope, Props, Receipts, _Present, _Context,
|
|
|
724
770
|
proof_contract_binding(Props, ContractBinding),
|
|
725
771
|
(ContractBinding == invalid
|
|
726
772
|
; Receipts == []
|
|
727
|
-
;
|
|
728
|
-
|
|
773
|
+
; pure_memo(receipt_history_well_formed, TestId-Receipts,
|
|
774
|
+
receipt_history_well_formed, false)),
|
|
729
775
|
!.
|
|
730
776
|
receipt_evidence_state(TestId, Scope, Props, Receipts, _Present, Context, Evidence) :-
|
|
731
777
|
receipt_for_current_mode(TestId, Context, Receipts, SnapshotReceipts),
|
|
@@ -742,6 +788,13 @@ receipt_evidence_state(TestId, Scope, Props, Receipts, _Present, Context, Eviden
|
|
|
742
788
|
)
|
|
743
789
|
).
|
|
744
790
|
|
|
791
|
+
receipt_history_well_formed(TestId-Receipts, WellFormed) :-
|
|
792
|
+
( forall(member(Receipt, Receipts), valid_receipt_shape(TestId, Receipt)),
|
|
793
|
+
chronological_receipt_history(Receipts)
|
|
794
|
+
-> WellFormed = true
|
|
795
|
+
; WellFormed = false
|
|
796
|
+
).
|
|
797
|
+
|
|
745
798
|
proof_receipt_entries(Props, Receipts, Present) :-
|
|
746
799
|
( memberchk(proof_receipts=Raw, Props)
|
|
747
800
|
-> Present = true,
|
|
@@ -1069,6 +1122,14 @@ test_missing_executable_symbol(TestId) :-
|
|
|
1069
1122
|
\+ (kb_relationship(executable_for, SymbolId, TestId), kb_entity(SymbolId, symbol, _)).
|
|
1070
1123
|
|
|
1071
1124
|
production_symbol_stage(ReqId, PassingE2eTests, Stage, ProductionSymbols) :-
|
|
1125
|
+
findall(TestId,
|
|
1126
|
+
(kb_relationship(specified_by, ReqId, ScenarioId),
|
|
1127
|
+
scenario_test(ScenarioId, TestId)),
|
|
1128
|
+
ScenarioTests0),
|
|
1129
|
+
sort(ScenarioTests0, ScenarioTests),
|
|
1130
|
+
production_symbol_stage(ReqId, PassingE2eTests, ScenarioTests, [], _{}, Stage, ProductionSymbols).
|
|
1131
|
+
|
|
1132
|
+
production_symbol_stage(ReqId, PassingE2eTests, ScenarioTests, ReceiptEvidence, Context, Stage, ProductionSymbols) :-
|
|
1072
1133
|
findall(SymbolId,
|
|
1073
1134
|
(kb_relationship(implements, SymbolId, ReqId),
|
|
1074
1135
|
kb_entity(SymbolId, symbol, _),
|
|
@@ -1080,12 +1141,16 @@ production_symbol_stage(ReqId, PassingE2eTests, Stage, ProductionSymbols) :-
|
|
|
1080
1141
|
include(symbol_not_covered_by_tests(PassingE2eTests), ProductionSymbols, UncoveredSymbols),
|
|
1081
1142
|
production_stage_status(ProductionSymbols, StructuralSymbols, PassingE2eTests, UncoveredSymbols, Status, StatusReason),
|
|
1082
1143
|
maplist(symbol_coordinate_ref, ProductionSymbols, Coordinates),
|
|
1144
|
+
production_coverage_explanations(
|
|
1145
|
+
ReqId, ProductionSymbols, StructuralSymbols, UncoveredSymbols,
|
|
1146
|
+
PassingE2eTests, ScenarioTests, ReceiptEvidence, Context, Explanations),
|
|
1083
1147
|
StageBase = _{
|
|
1084
1148
|
status: Status,
|
|
1085
1149
|
symbols: ProductionSymbols,
|
|
1086
1150
|
structuralSymbols: StructuralSymbols,
|
|
1087
1151
|
uncoveredSymbols: UncoveredSymbols,
|
|
1088
|
-
coordinates: Coordinates
|
|
1152
|
+
coordinates: Coordinates,
|
|
1153
|
+
explanations: Explanations
|
|
1089
1154
|
},
|
|
1090
1155
|
( Status == passed
|
|
1091
1156
|
-> Stage = StageBase
|
|
@@ -1127,6 +1192,271 @@ production_stage_status(ProductionSymbols, StructuralSymbols, PassingE2eTests, U
|
|
|
1127
1192
|
symbol_not_covered_by_tests(Tests, SymbolId) :-
|
|
1128
1193
|
\+ (member(TestId, Tests), kb_relationship(covered_by, SymbolId, TestId)).
|
|
1129
1194
|
|
|
1195
|
+
production_coverage_explanations(ReqId, ProductionSymbols, StructuralSymbols, UncoveredSymbols,
|
|
1196
|
+
PassingE2eTests, ScenarioTests, ReceiptEvidence, Context, Explanations) :-
|
|
1197
|
+
maplist(production_symbol_explanation(ReqId, UncoveredSymbols, PassingE2eTests, ScenarioTests, ReceiptEvidence, Context),
|
|
1198
|
+
ProductionSymbols, ProductionExplanations),
|
|
1199
|
+
maplist(structural_symbol_explanation(ReqId, PassingE2eTests, ScenarioTests, ReceiptEvidence, Context),
|
|
1200
|
+
StructuralSymbols, StructuralExplanations),
|
|
1201
|
+
append(ProductionExplanations, StructuralExplanations, Explanations).
|
|
1202
|
+
|
|
1203
|
+
structural_symbol_explanation(ReqId, PassingE2eTests, ScenarioTests, ReceiptEvidence, Context, SymbolId, Explanation) :-
|
|
1204
|
+
symbol_classification(SymbolId, Classification),
|
|
1205
|
+
symbol_coverage_candidates(structural, PassingE2eTests, ScenarioTests, ReceiptEvidence, Context, SymbolId, Candidates),
|
|
1206
|
+
explanation_reason_text(structural_unit_contract, ReasonText),
|
|
1207
|
+
Explanation = _{
|
|
1208
|
+
symbolId: SymbolId,
|
|
1209
|
+
requirementId: ReqId,
|
|
1210
|
+
classification: Classification,
|
|
1211
|
+
status: covered,
|
|
1212
|
+
reason: structural_unit_contract,
|
|
1213
|
+
reasonText: ReasonText,
|
|
1214
|
+
coverageCandidates: Candidates
|
|
1215
|
+
}.
|
|
1216
|
+
|
|
1217
|
+
production_symbol_explanation(ReqId, UncoveredSymbols, PassingE2eTests, ScenarioTests, ReceiptEvidence, Context, SymbolId, Explanation) :-
|
|
1218
|
+
symbol_classification(SymbolId, Classification),
|
|
1219
|
+
symbol_coverage_candidates(behavioral, PassingE2eTests, ScenarioTests, ReceiptEvidence, Context, SymbolId, Candidates),
|
|
1220
|
+
production_symbol_rollup(UncoveredSymbols, PassingE2eTests, SymbolId, Candidates, Status, Reason),
|
|
1221
|
+
explanation_reason_text(Reason, ReasonText),
|
|
1222
|
+
Explanation = _{
|
|
1223
|
+
symbolId: SymbolId,
|
|
1224
|
+
requirementId: ReqId,
|
|
1225
|
+
classification: Classification,
|
|
1226
|
+
status: Status,
|
|
1227
|
+
reason: Reason,
|
|
1228
|
+
reasonText: ReasonText,
|
|
1229
|
+
coverageCandidates: Candidates
|
|
1230
|
+
}.
|
|
1231
|
+
|
|
1232
|
+
production_symbol_rollup(_Uncovered, [], _SymbolId, _Candidates, uncovered, stage_blocked_no_passing_e2e) :-
|
|
1233
|
+
!.
|
|
1234
|
+
production_symbol_rollup(UncoveredSymbols, _Passing, SymbolId, Candidates, uncovered, Reason) :-
|
|
1235
|
+
memberchk(SymbolId, UncoveredSymbols),
|
|
1236
|
+
!,
|
|
1237
|
+
(Candidates == [] -> Reason = covered_by_missing ; Reason = no_qualifying_e2e_coverage).
|
|
1238
|
+
production_symbol_rollup(_Uncovered, _Passing, _SymbolId, _Candidates, covered, covered).
|
|
1239
|
+
|
|
1240
|
+
symbol_classification(SymbolId, Classification) :-
|
|
1241
|
+
kb_entity(SymbolId, symbol, Props),
|
|
1242
|
+
memberchk(symbol_role=RawRole, Props),
|
|
1243
|
+
normalize_atom(RawRole, Role),
|
|
1244
|
+
Role \= '',
|
|
1245
|
+
!,
|
|
1246
|
+
Classification = Role.
|
|
1247
|
+
symbol_classification(_SymbolId, unknown).
|
|
1248
|
+
|
|
1249
|
+
symbol_coverage_candidates(Mode, PassingE2eTests, ScenarioTests, ReceiptEvidence, Context, SymbolId, Candidates) :-
|
|
1250
|
+
findall(TestId, kb_relationship(covered_by, SymbolId, TestId), TestIds0),
|
|
1251
|
+
sort(TestIds0, TestIds),
|
|
1252
|
+
maplist(coverage_candidate_dict(Mode, PassingE2eTests, ScenarioTests, ReceiptEvidence, Context), TestIds, Candidates).
|
|
1253
|
+
|
|
1254
|
+
coverage_candidate_dict(Mode, PassingE2eTests, ScenarioTests, ReceiptEvidence, Context, TestId, Candidate) :-
|
|
1255
|
+
coverage_candidate_qualification(Mode, PassingE2eTests, ScenarioTests, ReceiptEvidence, Context, TestId, Qualifies, Primary, Secondaries),
|
|
1256
|
+
explanation_reason_text(Primary, ReasonText),
|
|
1257
|
+
cheap_candidate_scope(TestId, Scope),
|
|
1258
|
+
reused_receipt_state(ReceiptEvidence, TestId, ReceiptState),
|
|
1259
|
+
CandidateBase = _{
|
|
1260
|
+
testId: TestId,
|
|
1261
|
+
relationship: covered_by,
|
|
1262
|
+
qualifies: Qualifies,
|
|
1263
|
+
reason: Primary,
|
|
1264
|
+
reasonText: ReasonText,
|
|
1265
|
+
secondaryReasons: Secondaries,
|
|
1266
|
+
scope: Scope
|
|
1267
|
+
},
|
|
1268
|
+
( ReceiptState == none
|
|
1269
|
+
-> Candidate = CandidateBase
|
|
1270
|
+
; put_dict(receiptState, CandidateBase, ReceiptState, Candidate)
|
|
1271
|
+
).
|
|
1272
|
+
|
|
1273
|
+
% Shared candidate evaluator. Mode selects the coverage contract:
|
|
1274
|
+
% behavioral — production symbols require passing scenario-backed E2E
|
|
1275
|
+
% structural — type-shape symbols may also qualify via a unit contract
|
|
1276
|
+
coverage_candidate_qualification(_Mode, PassingE2eTests, _ScenarioTests, _ReceiptEvidence, _Context, TestId, true, covered, []) :-
|
|
1277
|
+
memberchk(TestId, PassingE2eTests),
|
|
1278
|
+
!.
|
|
1279
|
+
coverage_candidate_qualification(_Mode, _Passing, _Scenario, _Evidence, _Context, TestId, false, missing_test_entity, []) :-
|
|
1280
|
+
\+ kb_entity(TestId, test, _),
|
|
1281
|
+
!.
|
|
1282
|
+
coverage_candidate_qualification(structural, _Passing, _Scenario, _Evidence, _Context, TestId, true, structural_unit_contract, []) :-
|
|
1283
|
+
structural_unit_contract_test(TestId),
|
|
1284
|
+
!.
|
|
1285
|
+
coverage_candidate_qualification(_Mode, _Passing, ScenarioTests, ReceiptEvidence, Context, TestId, false, Primary, Secondaries) :-
|
|
1286
|
+
cheap_scope_reject_reason(TestId, ScopeReason),
|
|
1287
|
+
( \+ memberchk(TestId, ScenarioTests)
|
|
1288
|
+
-> Primary = test_not_in_requirement_scenario_chain,
|
|
1289
|
+
maybe_singleton(ScopeReason, ScopeSecondaries),
|
|
1290
|
+
reused_receipt_reject_reasons(ReceiptEvidence, TestId, ReceiptSecondaries),
|
|
1291
|
+
append(ScopeSecondaries, ReceiptSecondaries, Secondaries)
|
|
1292
|
+
; ScopeReason \= none
|
|
1293
|
+
-> Primary = ScopeReason,
|
|
1294
|
+
reused_receipt_reject_reasons(ReceiptEvidence, TestId, Secondaries)
|
|
1295
|
+
; receipt_reject_for_in_chain(ReceiptEvidence, Context, TestId, Primary, Secondaries)
|
|
1296
|
+
).
|
|
1297
|
+
|
|
1298
|
+
structural_unit_contract_test(TestId) :-
|
|
1299
|
+
kb_entity(TestId, test, TestProps),
|
|
1300
|
+
test_scope(TestProps, unit),
|
|
1301
|
+
memberchk(status=RawStatus, TestProps),
|
|
1302
|
+
normalize_atom(RawStatus, Status),
|
|
1303
|
+
memberchk(Status, [active, passing]).
|
|
1304
|
+
|
|
1305
|
+
cheap_candidate_scope(TestId, Scope) :-
|
|
1306
|
+
kb_entity(TestId, test, Props),
|
|
1307
|
+
!,
|
|
1308
|
+
test_scope(Props, Scope).
|
|
1309
|
+
cheap_candidate_scope(_TestId, unknown).
|
|
1310
|
+
|
|
1311
|
+
cheap_scope_reject_reason(TestId, Reason) :-
|
|
1312
|
+
cheap_candidate_scope(TestId, Scope),
|
|
1313
|
+
scope_reject_reason(Scope, Reason).
|
|
1314
|
+
|
|
1315
|
+
scope_reject_reason(unit, test_scope_is_unit) :- !.
|
|
1316
|
+
scope_reject_reason(end_to_end, none) :- !.
|
|
1317
|
+
scope_reject_reason(_Scope, test_scope_is_non_e2e).
|
|
1318
|
+
|
|
1319
|
+
maybe_singleton(none, []) :- !.
|
|
1320
|
+
maybe_singleton(Reason, [Reason]).
|
|
1321
|
+
|
|
1322
|
+
reused_receipt_state(Evidence, TestId, State) :-
|
|
1323
|
+
member(Item, Evidence),
|
|
1324
|
+
Item.testId == TestId,
|
|
1325
|
+
!,
|
|
1326
|
+
State = Item.state.
|
|
1327
|
+
reused_receipt_state(_Evidence, _TestId, none).
|
|
1328
|
+
|
|
1329
|
+
reused_receipt_item(Evidence, TestId, Item) :-
|
|
1330
|
+
member(Item, Evidence),
|
|
1331
|
+
Item.testId == TestId,
|
|
1332
|
+
!.
|
|
1333
|
+
|
|
1334
|
+
reused_receipt_reject_reasons(Evidence, TestId, Reasons) :-
|
|
1335
|
+
reused_receipt_item(Evidence, TestId, Item),
|
|
1336
|
+
!,
|
|
1337
|
+
receipt_item_reject_reason(Item, Reason),
|
|
1338
|
+
maybe_singleton(Reason, Reasons).
|
|
1339
|
+
reused_receipt_reject_reasons(_Evidence, _TestId, []).
|
|
1340
|
+
|
|
1341
|
+
receipt_reject_for_in_chain(Evidence, _Context, TestId, Primary, []) :-
|
|
1342
|
+
reused_receipt_item(Evidence, TestId, Item),
|
|
1343
|
+
!,
|
|
1344
|
+
receipt_item_reject_reason(Item, Reason),
|
|
1345
|
+
(Reason == none -> Primary = no_qualifying_e2e_coverage ; Primary = Reason).
|
|
1346
|
+
receipt_reject_for_in_chain(_Evidence, Context, TestId, Primary, []) :-
|
|
1347
|
+
is_dict(Context),
|
|
1348
|
+
Context \= _{},
|
|
1349
|
+
test_receipt_evidence(Context, TestId, Evidence),
|
|
1350
|
+
!,
|
|
1351
|
+
receipt_item_reject_reason(Evidence, Reason),
|
|
1352
|
+
(Reason == none -> Primary = no_qualifying_e2e_coverage ; Primary = Reason).
|
|
1353
|
+
receipt_reject_for_in_chain(_Evidence, _Context, _TestId, no_qualifying_e2e_coverage, []).
|
|
1354
|
+
|
|
1355
|
+
receipt_item_reject_reason(Item, stale_proof_receipt) :-
|
|
1356
|
+
Item.state == stale,
|
|
1357
|
+
get_dict(codeSnapshot, Item, _),
|
|
1358
|
+
!.
|
|
1359
|
+
receipt_item_reject_reason(Item, receipt_snapshot_mismatch) :-
|
|
1360
|
+
Item.state == stale,
|
|
1361
|
+
!.
|
|
1362
|
+
receipt_item_reject_reason(Item, Reason) :-
|
|
1363
|
+
receipt_state_reject_reason(Item.state, Reason).
|
|
1364
|
+
|
|
1365
|
+
receipt_state_reject_reason(missing, missing_proof_receipt) :- !.
|
|
1366
|
+
receipt_state_reject_reason(snapshot_unavailable, proof_snapshot_unavailable) :- !.
|
|
1367
|
+
receipt_state_reject_reason(contract_mismatch, receipt_contract_mismatch) :- !.
|
|
1368
|
+
receipt_state_reject_reason(invalid, invalid_proof_receipt) :- !.
|
|
1369
|
+
receipt_state_reject_reason(failed, failed_proof_receipt) :- !.
|
|
1370
|
+
receipt_state_reject_reason(not_end_to_end, none) :- !.
|
|
1371
|
+
receipt_state_reject_reason(stale, receipt_snapshot_mismatch) :- !.
|
|
1372
|
+
receipt_state_reject_reason(passed, none) :- !.
|
|
1373
|
+
receipt_state_reject_reason(none, none) :- !.
|
|
1374
|
+
receipt_state_reject_reason(_, none).
|
|
1375
|
+
|
|
1376
|
+
explanation_reason_text(Reason, Text) :-
|
|
1377
|
+
explanation_reason_text_def(Reason, Text),
|
|
1378
|
+
!.
|
|
1379
|
+
explanation_reason_text(Reason, Reason) :-
|
|
1380
|
+
atom(Reason).
|
|
1381
|
+
|
|
1382
|
+
explanation_reason_text_def(covered, "Qualifying covered_by to a passing scenario-backed E2E test").
|
|
1383
|
+
explanation_reason_text_def(covered_by_missing, "No covered_by relationship to any test").
|
|
1384
|
+
explanation_reason_text_def(no_qualifying_e2e_coverage, "covered_by relationships exist but none qualify as passing scenario-backed E2E coverage").
|
|
1385
|
+
explanation_reason_text_def(structural_unit_contract, "type-shape symbol is satisfied by a unit structural contract").
|
|
1386
|
+
explanation_reason_text_def(executable_test, "Symbol is executable test code linked with executable_for").
|
|
1387
|
+
explanation_reason_text_def(stage_blocked_no_passing_e2e, "Production coverage cannot be evaluated because no passing E2E evidence is available for the current snapshot").
|
|
1388
|
+
explanation_reason_text_def(missing_test_entity, "covered_by target is not a test entity").
|
|
1389
|
+
explanation_reason_text_def(test_not_in_requirement_scenario_chain, "Test is not in this requirement's scenario chain").
|
|
1390
|
+
explanation_reason_text_def(test_scope_is_unit, "Test verification_scope is unit, which cannot cover behavioral production symbols").
|
|
1391
|
+
explanation_reason_text_def(test_scope_is_non_e2e, "Test verification_scope is not end_to_end").
|
|
1392
|
+
explanation_reason_text_def(proof_snapshot_unavailable, "Workspace snapshot is unavailable so receipt currency cannot be proven").
|
|
1393
|
+
explanation_reason_text_def(missing_proof_receipt, "Scenario-backed E2E test has no kibi.proof-receipt.v1").
|
|
1394
|
+
explanation_reason_text_def(receipt_snapshot_mismatch, "Receipts exist but none match the current snapshot or binding").
|
|
1395
|
+
explanation_reason_text_def(stale_proof_receipt, "Current-snapshot receipt is older than the allowed proof age").
|
|
1396
|
+
explanation_reason_text_def(receipt_contract_mismatch, "Receipt does not match the current proof contract hash or fingerprint").
|
|
1397
|
+
explanation_reason_text_def(invalid_proof_receipt, "Receipt evidence is malformed or otherwise uncheckable").
|
|
1398
|
+
explanation_reason_text_def(failed_proof_receipt, "Latest current receipt outcome is not passed").
|
|
1399
|
+
|
|
1400
|
+
test_resolution_record(TestId, _{
|
|
1401
|
+
testId: TestId,
|
|
1402
|
+
requiredProofs: RequiredProofs,
|
|
1403
|
+
executableFor: ExecutableFor
|
|
1404
|
+
}) :-
|
|
1405
|
+
test_required_proof_refs(TestId, RequiredProofs),
|
|
1406
|
+
test_executable_for_refs(TestId, ExecutableFor).
|
|
1407
|
+
|
|
1408
|
+
test_required_proof_refs(TestId, Refs) :-
|
|
1409
|
+
kb_entity(TestId, test, Props),
|
|
1410
|
+
memberchk(proof_contract=RawContract, Props),
|
|
1411
|
+
proof_contract_dict(RawContract, Contract),
|
|
1412
|
+
contract_required_symbol_ids(Contract, SymbolIds),
|
|
1413
|
+
!,
|
|
1414
|
+
maplist(symbol_resolution_ref, SymbolIds, Refs).
|
|
1415
|
+
test_required_proof_refs(_TestId, []).
|
|
1416
|
+
|
|
1417
|
+
contract_required_symbol_ids(Contract, SymbolIds) :-
|
|
1418
|
+
( get_dict(required_proofs, Contract, Raw)
|
|
1419
|
+
; get_dict('required_proofs', Contract, Raw)
|
|
1420
|
+
),
|
|
1421
|
+
!,
|
|
1422
|
+
inventory_entries(Raw, Entries),
|
|
1423
|
+
findall(SymbolId,
|
|
1424
|
+
(member(Entry, Entries), required_proof_entry_symbol(Entry, SymbolId)),
|
|
1425
|
+
SymbolIds0),
|
|
1426
|
+
sort(SymbolIds0, SymbolIds).
|
|
1427
|
+
contract_required_symbol_ids(_, []).
|
|
1428
|
+
|
|
1429
|
+
required_proof_entry_symbol(Entry, SymbolId) :-
|
|
1430
|
+
( inventory_entry_field(Entry, symbol_id, Raw)
|
|
1431
|
+
; inventory_entry_field(Entry, symbolId, Raw)
|
|
1432
|
+
),
|
|
1433
|
+
normalize_atom(Raw, SymbolId),
|
|
1434
|
+
SymbolId \= ''.
|
|
1435
|
+
|
|
1436
|
+
test_executable_for_refs(TestId, Refs) :-
|
|
1437
|
+
findall(SymbolId,
|
|
1438
|
+
(kb_relationship(executable_for, SymbolId, TestId), kb_entity(SymbolId, symbol, _)),
|
|
1439
|
+
SymbolIds0),
|
|
1440
|
+
sort(SymbolIds0, SymbolIds),
|
|
1441
|
+
maplist(symbol_resolution_ref, SymbolIds, Refs).
|
|
1442
|
+
|
|
1443
|
+
symbol_resolution_ref(SymbolId, Ref) :-
|
|
1444
|
+
kb_entity(SymbolId, symbol, _),
|
|
1445
|
+
!,
|
|
1446
|
+
symbol_coordinate_ref(SymbolId, Coord),
|
|
1447
|
+
symbol_classification(SymbolId, Role),
|
|
1448
|
+
put_dict(_{role: Role, exists: true}, Coord, Ref).
|
|
1449
|
+
symbol_resolution_ref(SymbolId, _{
|
|
1450
|
+
id: SymbolId,
|
|
1451
|
+
sourceFile: '',
|
|
1452
|
+
sourceLine: 0,
|
|
1453
|
+
sourceColumn: 0,
|
|
1454
|
+
sourceEndLine: 0,
|
|
1455
|
+
sourceEndColumn: 0,
|
|
1456
|
+
role: unresolved,
|
|
1457
|
+
exists: false
|
|
1458
|
+
}).
|
|
1459
|
+
|
|
1130
1460
|
source_coordinate_stage(ReqProps, ExecutableSymbols, ProductionSymbols, Stage) :-
|
|
1131
1461
|
append(ExecutableSymbols, ProductionSymbols, Symbols0),
|
|
1132
1462
|
sort(Symbols0, Symbols),
|
package/src/rule_registry.pl
CHANGED
|
@@ -33,6 +33,14 @@ known_rule('strict-req-fact-pairing').
|
|
|
33
33
|
known_rule('predicate-verifiability').
|
|
34
34
|
known_rule('strict-readiness').
|
|
35
35
|
known_rule('semantic-completeness').
|
|
36
|
+
known_rule('proof-contract-symbols').
|
|
37
|
+
known_rule('entity-id-style').
|
|
38
|
+
known_rule('domain-redundancy').
|
|
39
|
+
known_rule('domain-implication').
|
|
40
|
+
known_rule('subject-key-identity').
|
|
41
|
+
known_rule('subject-key-shape').
|
|
42
|
+
known_rule('ontology-quality').
|
|
43
|
+
known_rule('predicate-schema-conformance').
|
|
36
44
|
|
|
37
45
|
rule_enforcement_class('must-priority-coverage', canonical).
|
|
38
46
|
rule_enforcement_class('symbol-coverage', canonical).
|
|
@@ -53,6 +61,14 @@ rule_enforcement_class('strict-req-fact-pairing', advisory).
|
|
|
53
61
|
rule_enforcement_class('predicate-verifiability', advisory).
|
|
54
62
|
rule_enforcement_class('strict-readiness', migration).
|
|
55
63
|
rule_enforcement_class('semantic-completeness', migration).
|
|
64
|
+
rule_enforcement_class('proof-contract-symbols', advisory).
|
|
65
|
+
rule_enforcement_class('entity-id-style', advisory).
|
|
66
|
+
rule_enforcement_class('domain-redundancy', advisory).
|
|
67
|
+
rule_enforcement_class('domain-implication', advisory).
|
|
68
|
+
rule_enforcement_class('subject-key-identity', advisory).
|
|
69
|
+
rule_enforcement_class('subject-key-shape', advisory).
|
|
70
|
+
rule_enforcement_class('ontology-quality', advisory).
|
|
71
|
+
rule_enforcement_class('predicate-schema-conformance', advisory).
|
|
56
72
|
|
|
57
73
|
rule_implementation('must-priority-coverage', prolog).
|
|
58
74
|
rule_implementation('symbol-coverage', prolog).
|
|
@@ -73,6 +89,14 @@ rule_implementation('strict-req-fact-pairing', prolog).
|
|
|
73
89
|
rule_implementation('predicate-verifiability', prolog).
|
|
74
90
|
rule_implementation('strict-readiness', prolog).
|
|
75
91
|
rule_implementation('semantic-completeness', prolog).
|
|
92
|
+
rule_implementation('proof-contract-symbols', prolog).
|
|
93
|
+
rule_implementation('entity-id-style', prolog).
|
|
94
|
+
rule_implementation('domain-redundancy', prolog).
|
|
95
|
+
rule_implementation('domain-implication', prolog).
|
|
96
|
+
rule_implementation('subject-key-identity', prolog).
|
|
97
|
+
rule_implementation('subject-key-shape', prolog).
|
|
98
|
+
rule_implementation('ontology-quality', prolog).
|
|
99
|
+
rule_implementation('predicate-schema-conformance', typescript).
|
|
76
100
|
|
|
77
101
|
rule_predicate('must-priority-coverage', check_must_priority_coverage).
|
|
78
102
|
rule_predicate('symbol-coverage', check_symbol_coverage).
|
|
@@ -91,6 +115,13 @@ rule_predicate('strict-req-fact-pairing', check_strict_req_fact_pairing).
|
|
|
91
115
|
rule_predicate('predicate-verifiability', check_predicate_verifiability).
|
|
92
116
|
rule_predicate('strict-readiness', check_strict_readiness).
|
|
93
117
|
rule_predicate('semantic-completeness', check_semantic_completeness).
|
|
118
|
+
rule_predicate('proof-contract-symbols', check_proof_contract_symbols).
|
|
119
|
+
rule_predicate('entity-id-style', check_entity_id_style).
|
|
120
|
+
rule_predicate('domain-redundancy', check_domain_redundancy).
|
|
121
|
+
rule_predicate('domain-implication', check_domain_implication).
|
|
122
|
+
rule_predicate('subject-key-identity', check_subject_key_identity).
|
|
123
|
+
rule_predicate('subject-key-shape', check_subject_key_shape).
|
|
124
|
+
rule_predicate('ontology-quality', check_ontology_quality).
|
|
94
125
|
|
|
95
126
|
rule_predicate_arity('must-priority-coverage', 1).
|
|
96
127
|
rule_predicate_arity('symbol-coverage', 1).
|
|
@@ -109,6 +140,13 @@ rule_predicate_arity('strict-req-fact-pairing', 1).
|
|
|
109
140
|
rule_predicate_arity('predicate-verifiability', 1).
|
|
110
141
|
rule_predicate_arity('strict-readiness', 1).
|
|
111
142
|
rule_predicate_arity('semantic-completeness', 1).
|
|
143
|
+
rule_predicate_arity('proof-contract-symbols', 1).
|
|
144
|
+
rule_predicate_arity('entity-id-style', 1).
|
|
145
|
+
rule_predicate_arity('domain-redundancy', 1).
|
|
146
|
+
rule_predicate_arity('domain-implication', 1).
|
|
147
|
+
rule_predicate_arity('subject-key-identity', 1).
|
|
148
|
+
rule_predicate_arity('subject-key-shape', 1).
|
|
149
|
+
rule_predicate_arity('ontology-quality', 1).
|
|
112
150
|
|
|
113
151
|
rule_description('must-priority-coverage', 'Every must-priority requirement must have a scenario and a test').
|
|
114
152
|
rule_description('symbol-coverage', 'Production symbols need qualifying coverage via covered_by plus a canonical requirement/scenario test path').
|
|
@@ -129,3 +167,11 @@ rule_description('strict-req-fact-pairing', 'Detect requirements with incomplete
|
|
|
129
167
|
rule_description('predicate-verifiability', 'Detect requires_predicate links that do not target ground fact_kind: predicate facts').
|
|
130
168
|
rule_description('strict-readiness', 'Report strict contradiction-readiness levels for requirements that are still prose-only or otherwise not contradiction-ready').
|
|
131
169
|
rule_description('semantic-completeness', 'Every inventoried assertive proposition is modeled or explicitly classified').
|
|
170
|
+
rule_description('proof-contract-symbols', 'Detect unresolved required_proofs.symbol_id values, type-shape required proofs, and proof_bindings.source_file disagreement with the named symbol sourceFile').
|
|
171
|
+
rule_description('entity-id-style', 'Entity IDs name the governed behavior and match their filename stem; new purely numeric IDs are reported at creation boundaries').
|
|
172
|
+
rule_description('domain-redundancy', 'Two current requirements must not ground the identical logical term or share a ground fact unless linked by supersedes or restates').
|
|
173
|
+
rule_description('domain-implication', 'Informational: one requirement\'s numeric bound strictly implies another requirement\'s bound on the same subject and property').
|
|
174
|
+
rule_description('subject-key-identity', 'Subject keys must name a shared component, not be derived from a requirement ID').
|
|
175
|
+
rule_description('subject-key-shape', 'Subject keys follow dotted component.aspect[.sub] with lowercase snake segments').
|
|
176
|
+
rule_description('ontology-quality', 'Informational: predicate schemas whose argument values mostly occur in only one fact are carrying prose instead of a shared vocabulary').
|
|
177
|
+
rule_description('predicate-schema-conformance', 'Predicate facts match a predicate_schema (project-local, or the built-in catalog in the default namespace) and use its declared argument constants').
|