kibi-core 0.9.1 → 0.11.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 CHANGED
@@ -1,15 +1,17 @@
1
1
  {
2
2
  "name": "kibi-core",
3
- "version": "0.9.1",
3
+ "version": "0.11.0",
4
4
  "private": false,
5
5
  "description": "Core Prolog modules and RDF graph logic for Kibi",
6
6
  "type": "module",
7
7
  "engines": {
8
- "node": ">=18",
9
- "bun": ">=1.0"
8
+ "node": ">=18"
10
9
  },
11
10
  "main": "./src/kb.pl",
12
- "files": ["src/**/*.pl", "schema/**/*.pl"],
11
+ "files": [
12
+ "src/**/*.pl",
13
+ "schema/**/*.pl"
14
+ ],
13
15
  "license": "AGPL-3.0-or-later",
14
16
  "author": "Piotr Franczyk",
15
17
  "repository": {
@@ -3,6 +3,7 @@
3
3
  :- module(kibi_entities, [entity_type/1, entity_property/3, required_property/2, optional_property/2]).
4
4
 
5
5
  % Entity types
6
+ % implements REQ-004
6
7
  entity_type(req).
7
8
  entity_type(scenario).
8
9
  entity_type(test).
@@ -87,6 +88,7 @@ entity_property(symbol, sourceEndColumn, integer).
87
88
  % Typed test verification fields - only valid for test entities
88
89
  entity_property(test, verification_scope, atom).
89
90
  entity_property(test, verification_perspective, atom).
91
+ entity_property(test, verification_contract, list_or_json).
90
92
  entity_property(test, verification_receipts, string).
91
93
 
92
94
  % Required properties for all entity types
@@ -113,6 +115,7 @@ optional_property(req, semantic_source_hash).
113
115
  optional_property(req, semantic_inventory).
114
116
  optional_property(test, verification_scope).
115
117
  optional_property(test, verification_perspective).
118
+ optional_property(test, verification_contract).
116
119
  optional_property(test, verification_receipts).
117
120
 
118
121
  % Documentation helpers
@@ -3,6 +3,7 @@
3
3
  :- module(kibi_relationships, [relationship_type/1, valid_relationship/3, relationship_metadata/1]).
4
4
 
5
5
  % Relationship types
6
+ % implements REQ-005
6
7
  relationship_type(depends_on).
7
8
  relationship_type(executable_for).
8
9
  relationship_type(specified_by).
@@ -119,6 +119,7 @@ is_fact_only_field(claim_span_end).
119
119
  % is_test_only_field(+Key) - true if Key is a test-specific field
120
120
  is_test_only_field(verification_scope).
121
121
  is_test_only_field(verification_perspective).
122
+ is_test_only_field(verification_contract).
122
123
  is_test_only_field(verification_receipts).
123
124
 
124
125
  % validate_fact_shape(+Kind, +Props)
package/src/checks.pl CHANGED
@@ -6,6 +6,7 @@
6
6
  :- module(checks, [
7
7
  check_all/1, % Returns all violations as a dict
8
8
  check_all_json/1, % Returns all violations as JSON string
9
+ check_selected_json/2, % Returns only selected rule violations as JSON
9
10
  check_must_priority_coverage/1, % Returns list of must-priority violations
10
11
  check_symbol_coverage/1, % Returns list of uncovered symbols
11
12
  check_symbol_traceability/2, % Returns list of symbols lacking requirement traceability (ReqAdr option)
@@ -14,6 +15,7 @@
14
15
  check_required_fields/1, % Returns list of missing required field violations
15
16
  check_deprecated_adrs/1, % Returns list of deprecated ADR violations
16
17
  check_domain_contradictions/1, % Returns list of contradiction violations
18
+ check_domain_contradictions_and_witnesses/2,
17
19
  check_domain_contradiction_witnesses/1,
18
20
  check_strict_fact_shape/1, % Returns list of malformed strict fact violations
19
21
  check_strict_req_fact_pairing/1,% Returns list of malformed strict req/fact pairing violations
@@ -591,6 +593,15 @@ check_domain_contradictions(Violations) :-
591
593
  check_domain_contradiction_witnesses(Witnesses),
592
594
  maplist(contradiction_witness_violation, Witnesses, Violations).
593
595
 
596
+ %% check_domain_contradictions_and_witnesses(-Violations, -Witnesses)
597
+ % Compute the contradiction witness graph once when a caller needs both the
598
+ % report violations and their exact evidence. The existing one-result
599
+ % predicates remain unchanged; this paired form avoids duplicate work in
600
+ % proof contexts without weakening any contradiction checks.
601
+ check_domain_contradictions_and_witnesses(Violations, Witnesses) :-
602
+ check_domain_contradiction_witnesses(Witnesses),
603
+ maplist(contradiction_witness_violation, Witnesses, Violations).
604
+
594
605
  %% check_domain_contradiction_witnesses(-Witnesses)
595
606
  % Exact, JSON-safe evidence for every strict-property, ground-predicate, and
596
607
  % safe-rule contradiction result. Rule overlap that cannot be proven or
@@ -989,9 +1000,11 @@ predicate_verifiability_kind_label(Kind, Label) :-
989
1000
 
990
1001
  %% check_logic_coverage(-Violations)
991
1002
  % Validates explicitly declared atomic requirement claim manifests. Legacy
992
- % requirements without logic_claims remain eligible for gradual backfill; once
993
- % a manifest exists, every key must be grounded by a linked strict-property or
994
- % predicate fact carrying the same claim_key.
1003
+ % requirements without logic_claims remain eligible for gradual backfill. A
1004
+ % modeled proposition must be grounded exactly once; ambiguous, ontology-gap,
1005
+ % and missing propositions remain explicit unresolved inventory states and are
1006
+ % not required to have a ground fact (missing is reported by semantic
1007
+ % completeness).
995
1008
  check_logic_coverage(Violations) :-
996
1009
  findall(Violation, logic_coverage_violation(Violation), Violations0),
997
1010
  sort(Violations0, Violations).
@@ -1006,6 +1019,7 @@ logic_coverage_violation(violation(
1006
1019
  kb:current_req(ReqId),
1007
1020
  requirement_logic_claims(ReqId, ClaimKeys),
1008
1021
  member(ClaimKey, ClaimKeys),
1022
+ claim_requires_grounding(ReqId, ClaimKey),
1009
1023
  \+ grounded_requirement_claim(ReqId, ClaimKey),
1010
1024
  format(
1011
1025
  string(Description),
@@ -1014,6 +1028,24 @@ logic_coverage_violation(violation(
1014
1028
  ),
1015
1029
  violation_source(ReqId, req, Source).
1016
1030
 
1031
+ logic_coverage_violation(violation(
1032
+ 'logic-coverage',
1033
+ ReqId,
1034
+ Description,
1035
+ "Keep ontology gaps, ambiguities, and missing interpretations unresolved; only modeled propositions may have logical ground facts",
1036
+ Source
1037
+ )) :-
1038
+ kb:current_req(ReqId),
1039
+ requirement_inventory_status(ReqId, ClaimKey, Status),
1040
+ memberchk(Status, [ambiguous, ontology_gap, missing]),
1041
+ grounded_requirement_claim(ReqId, ClaimKey),
1042
+ format(
1043
+ string(Description),
1044
+ "Requirement grounds unresolved ~w proposition ~w",
1045
+ [Status, ClaimKey]
1046
+ ),
1047
+ violation_source(ReqId, req, Source).
1048
+
1017
1049
  logic_coverage_violation(violation(
1018
1050
  'logic-coverage',
1019
1051
  ReqId,
@@ -1076,6 +1108,28 @@ requirement_logic_claims(ReqId, ClaimKeys) :-
1076
1108
  memberchk(logic_claims=RawClaimKeys, Props),
1077
1109
  kb:normalize_term_atom_list(RawClaimKeys, ClaimKeys).
1078
1110
 
1111
+ claim_requires_grounding(ReqId, ClaimKey) :-
1112
+ requirement_inventory_status(ReqId, ClaimKey, modeled),
1113
+ !.
1114
+ claim_requires_grounding(ReqId, ClaimKey) :-
1115
+ \+ requirement_inventory_status(ReqId, ClaimKey, _).
1116
+
1117
+ requirement_inventory_status(ReqId, ClaimKey, Status) :-
1118
+ kb_entity(ReqId, req, Props),
1119
+ memberchk(semantic_inventory=RawInventory, Props),
1120
+ inventory_entries(RawInventory, Entries),
1121
+ member(Entry, Entries),
1122
+ checks_inventory_entry_field(Entry, claim_key, RawClaimKey),
1123
+ kb:normalize_term_atom(RawClaimKey, ClaimKey),
1124
+ inventory_entry_status(Entry, Status).
1125
+
1126
+ checks_inventory_entry_field(Entry, Key, Value) :-
1127
+ is_dict(Entry),
1128
+ get_dict(Key, Entry, Value).
1129
+ checks_inventory_entry_field(Entry, Key, Value) :-
1130
+ is_list(Entry),
1131
+ memberchk(Key=Value, Entry).
1132
+
1079
1133
  grounded_requirement_claim(ReqId, ClaimKey) :-
1080
1134
  grounded_requirement_claim_fact(ReqId, ClaimKey, _FactId).
1081
1135
 
@@ -1222,13 +1276,15 @@ rule_verifiability_description(Props, FactId, Description) :-
1222
1276
  rule_verifiability_description(Props, FactId, Description) :-
1223
1277
  memberchk(fact_kind=RawKind, Props),
1224
1278
  normalize_term_atom(RawKind, rule),
1225
- memberchk(rule_schema_id=SchemaId, Props),
1279
+ memberchk(rule_schema_id=RawSchemaId, Props),
1280
+ normalize_term_atom(RawSchemaId, SchemaId),
1226
1281
  \+ kb_entity(SchemaId, fact, _),
1227
1282
  format(string(Description), "Rule fact ~w references missing rule schema ~w", [FactId, SchemaId]).
1228
1283
  rule_verifiability_description(Props, FactId, Description) :-
1229
1284
  memberchk(fact_kind=RawKind, Props),
1230
1285
  normalize_term_atom(RawKind, rule),
1231
- memberchk(rule_schema_id=SchemaId, Props),
1286
+ memberchk(rule_schema_id=RawSchemaId, Props),
1287
+ normalize_term_atom(RawSchemaId, SchemaId),
1232
1288
  kb_entity(SchemaId, fact, SchemaProps),
1233
1289
  \+ valid_rule_schema_props(SchemaProps),
1234
1290
  format(string(Description), "Rule fact ~w references ~w, which is not a rule_schema fact", [FactId, SchemaId]).
@@ -1286,6 +1342,10 @@ inventory_entries(Raw, Entries) :-
1286
1342
  catch(atom_json_dict(Raw, JsonEntries, [value_string_as(string)]), _, fail),
1287
1343
  is_list(JsonEntries)
1288
1344
  -> Entries = JsonEntries
1345
+ ; (atom(Raw) ; string(Raw)),
1346
+ catch(term_string(PrologEntries, Raw), _, fail),
1347
+ is_list(PrologEntries)
1348
+ -> Entries = PrologEntries
1289
1349
  ; Entries = []
1290
1350
  ).
1291
1351
 
@@ -1341,6 +1401,64 @@ check_all_json(JsonString) :-
1341
1401
  JsonString
1342
1402
  ).
1343
1403
 
1404
+ %% check_selected_json(+Rules, -JsonString)
1405
+ % Run only the named aggregated checks. This is intentionally separate from
1406
+ % check_all/1 so focused diagnostics cannot evaluate unrelated rule queries.
1407
+ check_selected_json(Rules, JsonString) :-
1408
+ check_selected(Rules, ViolationsDict),
1409
+ violations_dict_to_json(ViolationsDict, JsonDict),
1410
+ with_output_to_string(
1411
+ json_write_dict(current_output, JsonDict, [width(0)]),
1412
+ JsonString
1413
+ ).
1414
+
1415
+ check_selected(Rules, _{
1416
+ must_priority_coverage: MustPriority,
1417
+ symbol_coverage: SymbolCoverage,
1418
+ symbol_traceability: SymbolTraceability,
1419
+ no_dangling_refs: DanglingRefs,
1420
+ no_cycles: Cycles,
1421
+ required_fields: RequiredFields,
1422
+ deprecated_adr_no_successor: DeprecatedADRs,
1423
+ domain_contradictions: Contradictions,
1424
+ strict_fact_shape: StrictFactShape,
1425
+ strict_req_fact_pairing: StrictReqFactPairing,
1426
+ strict_readiness: StrictReadiness,
1427
+ predicate_verifiability: PredicateVerifiability,
1428
+ logic_coverage: LogicCoverage,
1429
+ rule_safety: RuleSafety,
1430
+ rule_verifiability: RuleVerifiability,
1431
+ semantic_completeness: SemanticCompleteness
1432
+ }) :-
1433
+ selected_rule(Rules, 'must-priority-coverage', check_must_priority_coverage, MustPriority),
1434
+ selected_rule(Rules, 'symbol-coverage', check_symbol_coverage, SymbolCoverage),
1435
+ selected_rule_with_options(Rules, 'symbol-traceability', check_symbol_traceability, SymbolTraceability),
1436
+ selected_rule(Rules, 'no-dangling-refs', check_no_dangling_refs, DanglingRefs),
1437
+ selected_rule(Rules, 'no-cycles', check_no_cycles, Cycles),
1438
+ selected_rule(Rules, 'required-fields', check_required_fields, RequiredFields),
1439
+ selected_rule(Rules, 'deprecated-adr-no-successor', check_deprecated_adrs, DeprecatedADRs),
1440
+ selected_rule(Rules, 'domain-contradictions', check_domain_contradictions, Contradictions),
1441
+ selected_rule(Rules, 'strict-fact-shape', check_strict_fact_shape, StrictFactShape),
1442
+ selected_rule(Rules, 'strict-req-fact-pairing', check_strict_req_fact_pairing, StrictReqFactPairing),
1443
+ selected_rule(Rules, 'strict-readiness', check_strict_readiness, StrictReadiness),
1444
+ selected_rule(Rules, 'predicate-verifiability', check_predicate_verifiability, PredicateVerifiability),
1445
+ selected_rule(Rules, 'logic-coverage', check_logic_coverage, LogicCoverage),
1446
+ selected_rule(Rules, 'rule-safety', check_rule_safety, RuleSafety),
1447
+ selected_rule(Rules, 'rule-verifiability', check_rule_verifiability, RuleVerifiability),
1448
+ selected_rule(Rules, 'semantic-completeness', check_semantic_completeness, SemanticCompleteness).
1449
+
1450
+ selected_rule(Rules, Name, Goal, Violations) :-
1451
+ ( memberchk(Name, Rules)
1452
+ -> call(Goal, Violations)
1453
+ ; Violations = []
1454
+ ).
1455
+
1456
+ selected_rule_with_options(Rules, Name, Goal, Violations) :-
1457
+ ( memberchk(Name, Rules)
1458
+ -> call(Goal, false, Violations)
1459
+ ; Violations = []
1460
+ ).
1461
+
1344
1462
  %% check_all_json_with_options(-JsonString, +RequireAdr)
1345
1463
  % Returns all violations as JSON string with options.
1346
1464
  % RequireAdr: if true, symbol-traceability also requires ADR constraints.
package/src/discovery.pl CHANGED
@@ -143,7 +143,7 @@ coverage_rows(type, _Tags, _IncludePassing, _IncludeTransitive, _VerificationSna
143
143
  requirement_coverage_row(Tags, IncludeTransitive, ProofContext, Row) :-
144
144
  kb_entity(Id, req, Props),
145
145
  matches_tags(Tags, Props),
146
- entity_title_status_source(Props, Title, Status, _Source),
146
+ entity_title_status_source(Props, Title, Status, Source),
147
147
  entity_priority(Props, Priority),
148
148
  count_distinct_targets(specified_by, Id, source, ScenarioCount),
149
149
  requirement_test_count(Id, TestCount),
@@ -156,6 +156,7 @@ requirement_coverage_row(Tags, IncludeTransitive, ProofContext, Row) :-
156
156
  type: req,
157
157
  title: Title,
158
158
  status: Status,
159
+ source: Source,
159
160
  priority: Priority,
160
161
  scenarioCount: ScenarioCount,
161
162
  testCount: TestCount,