kibi-core 0.1.7 → 0.1.9

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.
Files changed (3) hide show
  1. package/package.json +1 -1
  2. package/src/checks.pl +86 -0
  3. package/src/kb.pl +15 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kibi-core",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "private": false,
5
5
  "description": "Core Prolog modules and RDF graph logic for Kibi",
6
6
  "type": "module",
package/src/checks.pl CHANGED
@@ -8,6 +8,7 @@
8
8
  check_all_json/1, % Returns all violations as JSON string
9
9
  check_must_priority_coverage/1, % Returns list of must-priority violations
10
10
  check_symbol_coverage/1, % Returns list of uncovered symbols
11
+ check_symbol_traceability/2, % Returns list of symbols lacking direct traceability (ReqAdr option)
11
12
  check_no_dangling_refs/1, % Returns list of dangling ref violations
12
13
  check_no_cycles/1, % Returns list of cycle violations
13
14
  check_required_fields/1, % Returns list of missing required field violations
@@ -34,9 +35,11 @@ all_relationship_types([
34
35
  %% check_all(-ViolationsDict)
35
36
  % Returns a dict with all violations grouped by rule type.
36
37
  % Each value is a list of violation terms: violation(Rule, EntityId, Description, Suggestion, Source)
38
+ % For symbol-traceability, uses RequireAdr=false as default.
37
39
  check_all(ViolationsDict) :-
38
40
  check_must_priority_coverage(MustPriority),
39
41
  check_symbol_coverage(SymbolCoverage),
42
+ check_symbol_traceability(false, SymbolTraceability),
40
43
  check_no_dangling_refs(DanglingRefs),
41
44
  check_no_cycles(Cycles),
42
45
  check_required_fields(RequiredFields),
@@ -45,6 +48,7 @@ check_all(ViolationsDict) :-
45
48
  ViolationsDict = _{
46
49
  must_priority_coverage: MustPriority,
47
50
  symbol_coverage: SymbolCoverage,
51
+ symbol_traceability: SymbolTraceability,
48
52
  no_dangling_refs: DanglingRefs,
49
53
  no_cycles: Cycles,
50
54
  required_fields: RequiredFields,
@@ -98,6 +102,55 @@ symbol_coverage_violation(SymbolId, violation(
98
102
  )) :-
99
103
  violation_source(SymbolId, symbol, Source).
100
104
 
105
+ %% check_symbol_traceability(+RequireAdr, -Violations)
106
+ % Finds all symbols lacking direct traceability:
107
+ % - Every symbol must have at least one direct 'implements' relationship to a requirement
108
+ % - If RequireAdr=true, the symbol must also have at least one 'constrained_by' relationship to an ADR
109
+ check_symbol_traceability(RequireAdr, Violations) :-
110
+ findall(
111
+ Violation,
112
+ symbol_traceability_violation(RequireAdr, Violation),
113
+ Violations0
114
+ ),
115
+ sort(Violations0, Violations).
116
+
117
+ symbol_traceability_violation(RequireAdr, violation(
118
+ 'symbol-traceability',
119
+ SymbolId,
120
+ Description,
121
+ Suggestion,
122
+ Source
123
+ )) :-
124
+ kb_entity(SymbolId, symbol, _),
125
+ % Check if symbol has direct implements to a requirement
126
+ ( kb_relationship(implements, SymbolId, ReqId),
127
+ kb_entity(ReqId, req, _)
128
+ -> HasReq = true
129
+ ; HasReq = false
130
+ ),
131
+ % Check if symbol has constrained_by to ADR (only if required)
132
+ ( RequireAdr = true ->
133
+ ( kb_relationship(constrained_by, SymbolId, AdrId),
134
+ kb_entity(AdrId, adr, _)
135
+ -> HasAdr = true
136
+ ; HasAdr = false
137
+ )
138
+ ; HasAdr = true % Not required, so pass this check
139
+ ),
140
+ % Determine what is missing
141
+ ( HasReq = false, HasAdr = false, RequireAdr = true ->
142
+ Description = "Symbol has no direct requirement link and no ADR constraint.",
143
+ Suggestion = "Add 'implements: REQ-xxx' and 'constrained_by: ADR-xxx' in symbols.yaml."
144
+ ; HasReq = false ->
145
+ Description = "Symbol has no direct requirement link.",
146
+ Suggestion = "Add 'implements: REQ-xxx' in symbols.yaml."
147
+ ; HasAdr = false ->
148
+ Description = "Symbol has no ADR constraint.",
149
+ Suggestion = "Add 'constrained_by: ADR-xxx' in symbols.yaml."
150
+ ; fail % No violation
151
+ ),
152
+ violation_source(SymbolId, symbol, Source).
153
+
101
154
  %% check_no_dangling_refs(-Violations)
102
155
  % Finds all relationships referencing non-existent entities.
103
156
  check_no_dangling_refs(Violations) :-
@@ -323,6 +376,39 @@ check_all_json(JsonString) :-
323
376
  JsonString
324
377
  ).
325
378
 
379
+ %% check_all_json_with_options(-JsonString, +RequireAdr)
380
+ % Returns all violations as JSON string with options.
381
+ % RequireAdr: if true, symbol-traceability also requires ADR constraints.
382
+ check_all_json_with_options(JsonString, RequireAdr) :-
383
+ check_all_with_options(ViolationsDict, RequireAdr),
384
+ violations_dict_to_json(ViolationsDict, JsonDict),
385
+ with_output_to_string(
386
+ json_write_dict(current_output, JsonDict, [width(0)]),
387
+ JsonString
388
+ ).
389
+
390
+ %% check_all_with_options(-ViolationsDict, +RequireAdr)
391
+ % Returns a dict with all violations, respecting options.
392
+ check_all_with_options(ViolationsDict, RequireAdr) :-
393
+ check_must_priority_coverage(MustPriority),
394
+ check_symbol_coverage(SymbolCoverage),
395
+ check_symbol_traceability(RequireAdr, SymbolTraceability),
396
+ check_no_dangling_refs(DanglingRefs),
397
+ check_no_cycles(Cycles),
398
+ check_required_fields(RequiredFields),
399
+ check_deprecated_adrs(DeprecatedADRs),
400
+ check_domain_contradictions(Contradictions),
401
+ ViolationsDict = _{
402
+ must_priority_coverage: MustPriority,
403
+ symbol_coverage: SymbolCoverage,
404
+ symbol_traceability: SymbolTraceability,
405
+ no_dangling_refs: DanglingRefs,
406
+ no_cycles: Cycles,
407
+ required_fields: RequiredFields,
408
+ deprecated_adr_no_successor: DeprecatedADRs,
409
+ domain_contradictions: Contradictions
410
+ }.
411
+
326
412
  %% violations_dict_to_json(+ViolationsDict, -JsonDict)
327
413
  % Converts a dict of violation/5 term lists to a dict of JSON-compatible dicts.
328
414
  violations_dict_to_json(Dict, JsonDict) :-
package/src/kb.pl CHANGED
@@ -270,9 +270,21 @@ convert_legacy_prop(Prop, Prop, true).
270
270
  kb_entities_by_source(SourcePath, Ids) :-
271
271
  findall(Id,
272
272
  (kb_entity(Id, _Type, Props),
273
- memberchk(source-S, Props),
274
- sub_atom(S, _, _, _, SourcePath)),
275
- Ids).
273
+ memberchk(source=RawSource, Props),
274
+ source_value_atom(RawSource, SourceAtom),
275
+ sub_atom(SourceAtom, _, _, _, SourcePath)),
276
+ RawIds),
277
+ sort(RawIds, Ids).
278
+
279
+ source_value_atom(Value, Atom) :-
280
+ ( atom(Value)
281
+ -> Atom = Value
282
+ ; string(Value)
283
+ -> atom_string(Atom, Value)
284
+ ; Value = ^^(Inner, _)
285
+ -> source_value_atom(Inner, Atom)
286
+ ; term_string(Value, Atom)
287
+ ).
276
288
 
277
289
  %% kb_assert_relationship(+Type, +From, +To, +Metadata)
278
290
  % Assert a relationship between two entities with validation.