kibi-core 0.4.0 → 0.5.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 +7 -0
- package/schema/relationships.pl +4 -0
- package/schema/validation.pl +27 -2
- package/src/checks.pl +14 -13
- package/src/kb.pl +145 -21
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kibi-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Core Prolog modules and RDF graph logic for Kibi",
|
|
6
6
|
"type": "module",
|
|
@@ -9,10 +9,7 @@
|
|
|
9
9
|
"bun": ">=1.0"
|
|
10
10
|
},
|
|
11
11
|
"main": "./src/kb.pl",
|
|
12
|
-
"files": [
|
|
13
|
-
"src/**/*.pl",
|
|
14
|
-
"schema/**/*.pl"
|
|
15
|
-
],
|
|
12
|
+
"files": ["src/**/*.pl", "schema/**/*.pl"],
|
|
16
13
|
"license": "AGPL-3.0-or-later",
|
|
17
14
|
"author": "Piotr Franczyk",
|
|
18
15
|
"repository": {
|
package/schema/entities.pl
CHANGED
|
@@ -28,6 +28,7 @@ entity_property(_, priority, atom).
|
|
|
28
28
|
entity_property(_, severity, atom).
|
|
29
29
|
entity_property(_, links, list).
|
|
30
30
|
entity_property(_, text_ref, uri).
|
|
31
|
+
entity_property(_, sourceFile, uri).
|
|
31
32
|
|
|
32
33
|
% Typed fact fields - only valid for fact entities
|
|
33
34
|
entity_property(fact, fact_kind, atom).
|
|
@@ -47,6 +48,10 @@ entity_property(fact, valid_from, datetime).
|
|
|
47
48
|
entity_property(fact, valid_to, datetime).
|
|
48
49
|
entity_property(fact, canonical_key, string).
|
|
49
50
|
|
|
51
|
+
% Typed test verification fields - only valid for test entities
|
|
52
|
+
entity_property(test, verification_scope, atom).
|
|
53
|
+
entity_property(test, verification_perspective, atom).
|
|
54
|
+
|
|
50
55
|
% Required properties for all entity types
|
|
51
56
|
required_property(Type, id) :- entity_type(Type).
|
|
52
57
|
required_property(Type, title) :- entity_type(Type).
|
|
@@ -62,6 +67,8 @@ optional_property(Type, priority) :- entity_type(Type).
|
|
|
62
67
|
optional_property(Type, severity) :- entity_type(Type).
|
|
63
68
|
optional_property(Type, links) :- entity_type(Type).
|
|
64
69
|
optional_property(Type, text_ref) :- entity_type(Type).
|
|
70
|
+
optional_property(test, verification_scope).
|
|
71
|
+
optional_property(test, verification_perspective).
|
|
65
72
|
|
|
66
73
|
% Documentation helpers
|
|
67
74
|
% list all entity types
|
package/schema/relationships.pl
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
% Relationship types
|
|
6
6
|
relationship_type(depends_on).
|
|
7
|
+
relationship_type(executable_for).
|
|
7
8
|
relationship_type(specified_by).
|
|
8
9
|
relationship_type(verified_by).
|
|
9
10
|
relationship_type(validates).
|
|
@@ -20,9 +21,12 @@ relationship_type(requires_property).
|
|
|
20
21
|
|
|
21
22
|
% valid_relationship(RelType, FromType, ToType).
|
|
22
23
|
valid_relationship(depends_on, req, req).
|
|
24
|
+
valid_relationship(executable_for, symbol, test).
|
|
23
25
|
valid_relationship(specified_by, req, scenario).
|
|
24
26
|
valid_relationship(verified_by, req, test).
|
|
27
|
+
valid_relationship(verified_by, scenario, test).
|
|
25
28
|
valid_relationship(validates, test, req).
|
|
29
|
+
valid_relationship(validates, test, scenario).
|
|
26
30
|
valid_relationship(implements, symbol, req).
|
|
27
31
|
valid_relationship(covered_by, symbol, test).
|
|
28
32
|
valid_relationship(constrained_by, symbol, adr).
|
package/schema/validation.pl
CHANGED
|
@@ -60,10 +60,16 @@ validate_entity_shape(fact, Props) :-
|
|
|
60
60
|
valid_optional_fact_enums(Props),
|
|
61
61
|
valid_polarity_in_props(Props),
|
|
62
62
|
( memberchk(fact_kind=RawKind, Props) -> validate_fact_shape(RawKind, Props) ; true ).
|
|
63
|
+
validate_entity_shape(test, Props) :-
|
|
64
|
+
!,
|
|
65
|
+
valid_optional_test_enums(Props),
|
|
66
|
+
forall(member(Key=_, Props), \+ is_fact_only_field(Key)).
|
|
63
67
|
validate_entity_shape(Type, Props) :-
|
|
64
68
|
Type \= fact,
|
|
65
|
-
|
|
66
|
-
|
|
69
|
+
Type \= test,
|
|
70
|
+
% Non-fact/non-test entities cannot have type-specific fields
|
|
71
|
+
forall(member(Key=_, Props), \+ is_fact_only_field(Key)),
|
|
72
|
+
forall(member(Key=_, Props), \+ is_test_only_field(Key)).
|
|
67
73
|
|
|
68
74
|
% is_fact_only_field(+Key) - true if Key is a fact-specific field
|
|
69
75
|
is_fact_only_field(fact_kind).
|
|
@@ -83,6 +89,10 @@ is_fact_only_field(valid_from).
|
|
|
83
89
|
is_fact_only_field(valid_to).
|
|
84
90
|
is_fact_only_field(canonical_key).
|
|
85
91
|
|
|
92
|
+
% is_test_only_field(+Key) - true if Key is a test-specific field
|
|
93
|
+
is_test_only_field(verification_scope).
|
|
94
|
+
is_test_only_field(verification_perspective).
|
|
95
|
+
|
|
86
96
|
% validate_fact_shape(+Kind, +Props)
|
|
87
97
|
validate_fact_shape(subject, Props) :-
|
|
88
98
|
memberchk(subject_key=_Val, Props),
|
|
@@ -136,10 +146,25 @@ valid_optional_fact_enums(Props) :-
|
|
|
136
146
|
( memberchk(operator=Op, Props) -> valid_operator(Op) ; true ),
|
|
137
147
|
( memberchk(value_type=VT, Props) -> valid_value_type(VT) ; true ).
|
|
138
148
|
|
|
149
|
+
% valid_optional_test_enums(+Props)
|
|
150
|
+
% Validates enum-typed test fields whenever they are present
|
|
151
|
+
valid_optional_test_enums(Props) :-
|
|
152
|
+
( memberchk(verification_scope=Scope, Props) -> valid_verification_scope(Scope) ; true ),
|
|
153
|
+
( memberchk(verification_perspective=Perspective, Props) -> valid_verification_perspective(Perspective) ; true ).
|
|
154
|
+
|
|
139
155
|
% valid_polarity(+P)
|
|
140
156
|
valid_polarity(require).
|
|
141
157
|
valid_polarity(forbid).
|
|
142
158
|
|
|
159
|
+
% valid_verification_scope(+Scope)
|
|
160
|
+
valid_verification_scope(unit).
|
|
161
|
+
valid_verification_scope(integration).
|
|
162
|
+
valid_verification_scope(end_to_end).
|
|
163
|
+
|
|
164
|
+
% valid_verification_perspective(+Perspective)
|
|
165
|
+
valid_verification_perspective(internal).
|
|
166
|
+
valid_verification_perspective(consumer).
|
|
167
|
+
|
|
143
168
|
% exactly_one_value_field(+Props)
|
|
144
169
|
exactly_one_value_field(Props) :-
|
|
145
170
|
findall(F, (member(F=_, Props), is_value_field(F)), Fields),
|
package/src/checks.pl
CHANGED
|
@@ -90,7 +90,7 @@ coverage_gap_suggestion(missing_scenario, "Create scenario that specifies this r
|
|
|
90
90
|
coverage_gap_suggestion(missing_scenario_and_test, "Create scenario that specifies and test that validates this requirement").
|
|
91
91
|
|
|
92
92
|
%% check_symbol_coverage(-Violations)
|
|
93
|
-
% Finds all symbols
|
|
93
|
+
% Finds all production symbols lacking qualifying production coverage.
|
|
94
94
|
check_symbol_coverage(Violations) :-
|
|
95
95
|
findall(SymbolId, symbol_no_req_coverage(SymbolId, _), SymbolIds0),
|
|
96
96
|
sort(SymbolIds0, SymbolIds),
|
|
@@ -99,15 +99,15 @@ check_symbol_coverage(Violations) :-
|
|
|
99
99
|
symbol_coverage_violation(SymbolId, violation(
|
|
100
100
|
'symbol-coverage',
|
|
101
101
|
SymbolId,
|
|
102
|
-
"
|
|
103
|
-
"
|
|
102
|
+
"Production symbol lacks qualifying requirement coverage.",
|
|
103
|
+
"Add 'covered_by: TEST-xxx' for production coverage, and ensure that test reaches the requirement through a scenario->test path or direct req->test fallback when no scenario exists.",
|
|
104
104
|
Source
|
|
105
105
|
)) :-
|
|
106
106
|
violation_source(SymbolId, symbol, Source).
|
|
107
107
|
|
|
108
108
|
%% check_symbol_traceability(+RequireAdr, -Violations)
|
|
109
|
-
% Finds all symbols lacking
|
|
110
|
-
% - Every symbol must have at least one
|
|
109
|
+
% Finds all symbols lacking direct requirement ownership:
|
|
110
|
+
% - Every symbol must have at least one direct implements ownership path
|
|
111
111
|
% - If RequireAdr=true, the symbol must also have at least one 'constrained_by' relationship to an ADR
|
|
112
112
|
check_symbol_traceability(RequireAdr, Violations) :-
|
|
113
113
|
findall(
|
|
@@ -125,8 +125,9 @@ symbol_traceability_violation(RequireAdr, violation(
|
|
|
125
125
|
Source
|
|
126
126
|
)) :-
|
|
127
127
|
kb_entity(SymbolId, symbol, _),
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
\+ executable_test_symbol(SymbolId),
|
|
129
|
+
% Check if symbol has direct requirement ownership
|
|
130
|
+
( symbol_owns_requirement(SymbolId, ReqId),
|
|
130
131
|
kb_entity(ReqId, req, _)
|
|
131
132
|
-> HasReq = true
|
|
132
133
|
; HasReq = false
|
|
@@ -142,11 +143,11 @@ symbol_traceability_violation(RequireAdr, violation(
|
|
|
142
143
|
),
|
|
143
144
|
% Determine what is missing
|
|
144
145
|
( HasReq = false, HasAdr = false, RequireAdr = true ->
|
|
145
|
-
Description = "Symbol has no
|
|
146
|
-
Suggestion = "Add a direct 'implements: REQ-xxx' link
|
|
146
|
+
Description = "Symbol has no direct requirement ownership and no ADR constraint.",
|
|
147
|
+
Suggestion = "Add a direct 'implements: REQ-xxx' link for ownership, use 'covered_by' only for production coverage, use 'executable_for' only for executable test code, and add 'constrained_by: ADR-xxx' in symbols.yaml."
|
|
147
148
|
; HasReq = false ->
|
|
148
|
-
Description = "Symbol has no
|
|
149
|
-
Suggestion = "Add a direct 'implements: REQ-xxx' link
|
|
149
|
+
Description = "Symbol has no direct requirement ownership.",
|
|
150
|
+
Suggestion = "Add a direct 'implements: REQ-xxx' link for ownership. Use 'covered_by' for production coverage and 'executable_for' for executable test code identity."
|
|
150
151
|
; HasAdr = false ->
|
|
151
152
|
Description = "Symbol has no ADR constraint.",
|
|
152
153
|
Suggestion = "Add 'constrained_by: ADR-xxx' in symbols.yaml."
|
|
@@ -177,7 +178,7 @@ dangling_ref_violation(Type, violation(
|
|
|
177
178
|
"Remove relationship or create missing entity",
|
|
178
179
|
""
|
|
179
180
|
)) :-
|
|
180
|
-
kb_relationship(Type, FromId,
|
|
181
|
+
kb_relationship(Type, FromId, _ToId),
|
|
181
182
|
\+ kb_entity(FromId, _, _), % From doesn't exist
|
|
182
183
|
format(string(Description), "Relationship references non-existent entity: ~w", [FromId]).
|
|
183
184
|
|
|
@@ -297,7 +298,7 @@ missing_required_field(Required, violation(
|
|
|
297
298
|
Suggestion,
|
|
298
299
|
Source
|
|
299
300
|
)) :-
|
|
300
|
-
kb_entity(EntityId,
|
|
301
|
+
kb_entity(EntityId, _Type, Props),
|
|
301
302
|
member(Field, Required),
|
|
302
303
|
\+ memberchk(Field=_, Props),
|
|
303
304
|
|
package/src/kb.pl
CHANGED
|
@@ -15,6 +15,14 @@
|
|
|
15
15
|
kb_assert_relationship_no_audit/4,
|
|
16
16
|
kb_log_relationship_upsert/4,
|
|
17
17
|
kb_relationship/3,
|
|
18
|
+
symbol_owns_requirement/2,
|
|
19
|
+
scenario_verified_by_test/2,
|
|
20
|
+
requirement_test_fallback_allowed/1,
|
|
21
|
+
test_satisfies_requirement_semantics/2,
|
|
22
|
+
production_symbol_covered_for_requirement/2,
|
|
23
|
+
production_symbol_untested/1,
|
|
24
|
+
executable_test_symbol/1,
|
|
25
|
+
mixed_role_symbol/1,
|
|
18
26
|
transitively_implements/2,
|
|
19
27
|
transitively_depends/2,
|
|
20
28
|
impacted_by_change/2,
|
|
@@ -382,6 +390,7 @@ kb_assert_relationship_no_audit(RelType, FromId, ToId, _Metadata) :-
|
|
|
382
390
|
once(kb_entity(FromId, FromType, _)),
|
|
383
391
|
once(kb_entity(ToId, ToType, _)),
|
|
384
392
|
validate_relationship(RelType, FromType, ToType),
|
|
393
|
+
validate_symbol_role_compatibility(RelType, FromId, ToId),
|
|
385
394
|
% NOTE: Strict-lane fact_kind pairing is validated at the MCP layer
|
|
386
395
|
% via validateStrictLanePairing() before the transaction begins.
|
|
387
396
|
% Prolog-level validation is deferred to avoid potential issues with
|
|
@@ -400,6 +409,25 @@ kb_assert_relationship_no_audit(RelType, FromId, ToId, _Metadata) :-
|
|
|
400
409
|
rdf_assert(FromURI, RelURI, ToURI, Graph)
|
|
401
410
|
)).
|
|
402
411
|
|
|
412
|
+
validate_symbol_role_compatibility(RelType, FromId, _ToId) :-
|
|
413
|
+
memberchk(RelType, [implements, covered_by, executable_for]),
|
|
414
|
+
!,
|
|
415
|
+
( mixed_symbol_role(RelType, FromId)
|
|
416
|
+
-> format(atom(Msg), 'symbol ~w cannot mix executable_for with production ownership/coverage relationships', [FromId]),
|
|
417
|
+
throw(error(validation_error(Msg), Msg))
|
|
418
|
+
; true
|
|
419
|
+
).
|
|
420
|
+
validate_symbol_role_compatibility(_, _, _).
|
|
421
|
+
|
|
422
|
+
mixed_symbol_role(executable_for, SymbolId) :-
|
|
423
|
+
( kb_relationship(implements, SymbolId, _)
|
|
424
|
+
; kb_relationship(covered_by, SymbolId, _)
|
|
425
|
+
).
|
|
426
|
+
mixed_symbol_role(implements, SymbolId) :-
|
|
427
|
+
kb_relationship(executable_for, SymbolId, _).
|
|
428
|
+
mixed_symbol_role(covered_by, SymbolId) :-
|
|
429
|
+
kb_relationship(executable_for, SymbolId, _).
|
|
430
|
+
|
|
403
431
|
%% kb_log_relationship_upsert(+Type, +From, +To, +Metadata)
|
|
404
432
|
% Append the audit entry for a successfully committed relationship upsert.
|
|
405
433
|
kb_log_relationship_upsert(RelType, FromId, ToId, _Metadata) :-
|
|
@@ -567,18 +595,85 @@ uri_to_key(URI, Key) :-
|
|
|
567
595
|
%% Inference predicates (Phase 1)
|
|
568
596
|
%% ------------------------------------------------------------------
|
|
569
597
|
|
|
570
|
-
%%
|
|
571
|
-
%
|
|
572
|
-
|
|
573
|
-
transitively_implements(Symbol, Req) :-
|
|
598
|
+
%% symbol_owns_requirement(+Symbol, +Req)
|
|
599
|
+
% Direct requirement ownership for production code.
|
|
600
|
+
symbol_owns_requirement(Symbol, Req) :-
|
|
574
601
|
kb_relationship(implements, Symbol, Req).
|
|
602
|
+
|
|
603
|
+
%% transitively_implements(+Symbol, +Req)
|
|
604
|
+
% Ownership is direct only; coverage/test traceability is handled separately.
|
|
575
605
|
transitively_implements(Symbol, Req) :-
|
|
576
|
-
|
|
606
|
+
symbol_owns_requirement(Symbol, Req).
|
|
607
|
+
|
|
608
|
+
%% scenario_verified_by_test(+Scenario, +Test)
|
|
609
|
+
% Canonical scenario-to-test verification path.
|
|
610
|
+
scenario_verified_by_test(Scenario, Test) :-
|
|
611
|
+
kb_relationship(validates, Test, Scenario).
|
|
612
|
+
scenario_verified_by_test(Scenario, Test) :-
|
|
613
|
+
kb_relationship(verified_by, Scenario, Test).
|
|
614
|
+
|
|
615
|
+
%% requirement_test_fallback_allowed(+Req)
|
|
616
|
+
% Direct requirement-to-test fallback is only allowed when no scenario exists.
|
|
617
|
+
requirement_test_fallback_allowed(Req) :-
|
|
618
|
+
\+ has_scenario(Req).
|
|
619
|
+
|
|
620
|
+
%% executable_test_symbol(+Symbol)
|
|
621
|
+
% Symbol represents executable test code rather than production code.
|
|
622
|
+
executable_test_symbol(Symbol) :-
|
|
623
|
+
kb_relationship(executable_for, Symbol, _).
|
|
624
|
+
|
|
625
|
+
%% mixed_role_symbol(+Symbol)
|
|
626
|
+
% Invalid symbol carrying both executable test identity and production semantics.
|
|
627
|
+
mixed_role_symbol(Symbol) :-
|
|
628
|
+
executable_test_symbol(Symbol),
|
|
629
|
+
( kb_relationship(implements, Symbol, _)
|
|
630
|
+
; kb_relationship(covered_by, Symbol, _)
|
|
631
|
+
).
|
|
632
|
+
|
|
633
|
+
%% production_symbol(+Symbol)
|
|
634
|
+
% Internal helper for production-only symbol checks.
|
|
635
|
+
production_symbol(Symbol) :-
|
|
636
|
+
kb_entity(Symbol, symbol, _),
|
|
637
|
+
\+ executable_test_symbol(Symbol).
|
|
638
|
+
|
|
639
|
+
%% requirement_verified_by_test(+Req, +Test)
|
|
640
|
+
% Direct req<->test compatibility path.
|
|
641
|
+
requirement_verified_by_test(Req, Test) :-
|
|
577
642
|
kb_relationship(validates, Test, Req).
|
|
578
|
-
|
|
579
|
-
kb_relationship(covered_by, Symbol, Test),
|
|
643
|
+
requirement_verified_by_test(Req, Test) :-
|
|
580
644
|
kb_relationship(verified_by, Req, Test).
|
|
581
645
|
|
|
646
|
+
%% test_satisfies_requirement_semantics(+Test, +Req)
|
|
647
|
+
% Matches requirement verification facts against typed test fields when present.
|
|
648
|
+
% If the requirement declares no verification semantics, compatibility passes.
|
|
649
|
+
test_satisfies_requirement_semantics(Test, Req) :-
|
|
650
|
+
findall(Key-Expected,
|
|
651
|
+
required_test_semantic(Req, Key, Expected),
|
|
652
|
+
RequiredPairs0),
|
|
653
|
+
sort(RequiredPairs0, RequiredPairs),
|
|
654
|
+
( RequiredPairs = []
|
|
655
|
+
-> true
|
|
656
|
+
; kb_entity(Test, test, TestProps),
|
|
657
|
+
forall(member(Key-Expected, RequiredPairs),
|
|
658
|
+
test_matches_required_semantic(TestProps, Key, Expected))
|
|
659
|
+
).
|
|
660
|
+
|
|
661
|
+
required_test_semantic(Req, Key, Expected) :-
|
|
662
|
+
memberchk(Key, [verification_scope, verification_perspective]),
|
|
663
|
+
verification_subject_key(Req, SubjectKey),
|
|
664
|
+
effective_req_property(Req, SubjectKey, Key, Operator, _ValueType, Value, _Unit, _Scope, Polarity),
|
|
665
|
+
Operator == eq,
|
|
666
|
+
Polarity == require,
|
|
667
|
+
normalize_term_atom(Value, Expected).
|
|
668
|
+
|
|
669
|
+
verification_subject_key(Req, SubjectKey) :-
|
|
670
|
+
format(atom(SubjectKey), 'requirement.~w.verification', [Req]).
|
|
671
|
+
|
|
672
|
+
test_matches_required_semantic(TestProps, Key, Expected) :-
|
|
673
|
+
memberchk(Key=ActualRaw, TestProps),
|
|
674
|
+
normalize_term_atom(ActualRaw, Actual),
|
|
675
|
+
Actual == Expected.
|
|
676
|
+
|
|
582
677
|
%% transitively_depends(+Req1, +Req2)
|
|
583
678
|
% Req1 transitively depends on Req2 through depends_on chains.
|
|
584
679
|
transitively_depends(Req1, Req2) :-
|
|
@@ -658,14 +753,17 @@ has_test(Req) :-
|
|
|
658
753
|
once(kb_relationship(validates, _, Req)).
|
|
659
754
|
has_test(Req) :-
|
|
660
755
|
once(kb_relationship(verified_by, Req, _)).
|
|
756
|
+
has_test(Req) :-
|
|
757
|
+
kb_relationship(specified_by, Req, Scenario),
|
|
758
|
+
once(kb_relationship(validates, _, Scenario)).
|
|
759
|
+
has_test(Req) :-
|
|
760
|
+
kb_relationship(specified_by, Req, Scenario),
|
|
761
|
+
once(kb_relationship(verified_by, Scenario, _)).
|
|
661
762
|
|
|
662
763
|
%% untested_symbols(-Symbols)
|
|
663
|
-
% Returns symbols with no test coverage relationship.
|
|
764
|
+
% Returns production symbols with no test coverage relationship.
|
|
664
765
|
untested_symbols(Symbols) :-
|
|
665
|
-
setof(Symbol,
|
|
666
|
-
(kb_entity(Symbol, symbol, _),
|
|
667
|
-
\+ kb_relationship(covered_by, Symbol, _)),
|
|
668
|
-
Symbols),
|
|
766
|
+
setof(Symbol, production_symbol_untested(Symbol), Symbols),
|
|
669
767
|
!.
|
|
670
768
|
untested_symbols([]).
|
|
671
769
|
|
|
@@ -683,9 +781,9 @@ stale(Entity, MaxAgeDays) :-
|
|
|
683
781
|
AgeDays > MaxAgeDays.
|
|
684
782
|
|
|
685
783
|
%% orphaned(+Symbol)
|
|
686
|
-
%
|
|
784
|
+
% Production symbol is orphaned if it has no core traceability links.
|
|
687
785
|
orphaned(Symbol) :-
|
|
688
|
-
|
|
786
|
+
production_symbol(Symbol),
|
|
689
787
|
\+ kb_relationship(implements, Symbol, _),
|
|
690
788
|
\+ kb_relationship(covered_by, Symbol, _),
|
|
691
789
|
\+ kb_relationship(constrained_by, Symbol, _).
|
|
@@ -1001,15 +1099,40 @@ normalize_uri_atom(Value, Atom) :-
|
|
|
1001
1099
|
).
|
|
1002
1100
|
|
|
1003
1101
|
%% symbol_no_req_coverage(+Symbol, -Reason)
|
|
1004
|
-
% Find symbols that
|
|
1005
|
-
symbol_no_req_coverage(Symbol,
|
|
1006
|
-
|
|
1007
|
-
\+
|
|
1102
|
+
% Find symbols that lack canonical production requirement coverage.
|
|
1103
|
+
symbol_no_req_coverage(Symbol, no_qualifying_production_coverage) :-
|
|
1104
|
+
production_symbol(Symbol),
|
|
1105
|
+
\+ production_symbol_covered_for_requirement(Symbol, _).
|
|
1106
|
+
|
|
1107
|
+
%% production_symbol_covered_for_requirement(+Symbol, +Req)
|
|
1108
|
+
% Production coverage requires a covered_by edge and a canonical requirement/test path.
|
|
1109
|
+
production_symbol_covered_for_requirement(Symbol, Req) :-
|
|
1110
|
+
production_symbol(Symbol),
|
|
1111
|
+
kb_relationship(covered_by, Symbol, Test),
|
|
1112
|
+
test_covers_requirement(Test, Req).
|
|
1113
|
+
|
|
1114
|
+
symbol_has_req_coverage(Symbol, Req) :-
|
|
1115
|
+
production_symbol_covered_for_requirement(Symbol, Req).
|
|
1116
|
+
|
|
1117
|
+
test_covers_requirement(Test, Req) :-
|
|
1118
|
+
requirement_test_fallback_allowed(Req),
|
|
1119
|
+
requirement_verified_by_test(Req, Test),
|
|
1120
|
+
test_satisfies_requirement_semantics(Test, Req).
|
|
1121
|
+
test_covers_requirement(Test, Req) :-
|
|
1122
|
+
kb_relationship(specified_by, Req, Scenario),
|
|
1123
|
+
scenario_verified_by_test(Scenario, Test),
|
|
1124
|
+
test_satisfies_requirement_semantics(Test, Req).
|
|
1125
|
+
|
|
1126
|
+
%% production_symbol_untested(+Symbol)
|
|
1127
|
+
% Production symbol with no covered_by test evidence at all.
|
|
1128
|
+
production_symbol_untested(Symbol) :-
|
|
1129
|
+
production_symbol(Symbol),
|
|
1130
|
+
\+ kb_relationship(covered_by, Symbol, _).
|
|
1008
1131
|
|
|
1009
1132
|
% Helper predicate for readability - symbols with no traceability
|
|
1010
1133
|
symbol_uncovered(Symbol) :-
|
|
1011
|
-
|
|
1012
|
-
\+
|
|
1134
|
+
production_symbol(Symbol),
|
|
1135
|
+
\+ production_symbol_covered_for_requirement(Symbol, _).
|
|
1013
1136
|
|
|
1014
1137
|
|
|
1015
1138
|
coerce_timestamp_atom(Val^^_Type, Atom) :-
|
|
@@ -1045,7 +1168,8 @@ coerce_timestamp_atom(Val, Atom) :-
|
|
|
1045
1168
|
% counted so that `// implements: REQ-001` can satisfy the gate.
|
|
1046
1169
|
changed_symbol_missing_req(Symbol, MinLinks, Count) :-
|
|
1047
1170
|
changed_symbol(Symbol),
|
|
1048
|
-
|
|
1171
|
+
\+ executable_test_symbol(Symbol),
|
|
1172
|
+
( setof(Req, symbol_owns_requirement(Symbol, Req), KbReqs)
|
|
1049
1173
|
-> true
|
|
1050
1174
|
; KbReqs = []
|
|
1051
1175
|
),
|