kibi-core 0.22.5 → 0.23.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.
@@ -25,7 +25,7 @@
25
25
  ]).
26
26
  :- use_module('logic_ir.pl', [logic_rule_safety/2]).
27
27
 
28
- proof_version('kibi.requirement-proof.v3').
28
+ proof_version('kibi.requirement-proof.v4').
29
29
 
30
30
  requirement_proof_context(Context) :-
31
31
  requirement_proof_context(unknown, '1970-01-01T00:00:00Z', 604800, Context).
@@ -71,12 +71,12 @@ requirement_proof(ReqId, ReqProps, _Context, Proof) :-
71
71
  kb:current_req(ReqId),
72
72
  proof_exempt(ReqProps, Reason),
73
73
  !,
74
- exempt_requirement_proof(Reason, Proof).
75
- requirement_proof(ReqId, _ReqProps, _Context, Proof) :-
74
+ exempt_requirement_proof(Reason, ReqProps, Proof).
75
+ requirement_proof(ReqId, ReqProps, _Context, Proof) :-
76
76
  \+ kb:current_req(ReqId),
77
77
  !,
78
78
  applicability_exclusion_reason(ReqId, Reason),
79
- exempt_requirement_proof(Reason, Proof).
79
+ exempt_requirement_proof(Reason, ReqProps, Proof).
80
80
  requirement_proof(ReqId, ReqProps, Context, Proof) :-
81
81
  semantic_inventory_stage(ReqProps, SemanticStage, Inventory),
82
82
  logic_grounding_stage(ReqId, ReqProps, Inventory, Context, LogicStage),
@@ -101,10 +101,13 @@ requirement_proof(ReqId, ReqProps, Context, Proof) :-
101
101
  proof_issues(Stages, Gaps, Advisories),
102
102
  proof_repairs(Gaps, Repairs),
103
103
  proof_status(Stages, Status),
104
+ requirement_evidence(ReqProps, Status, PassingE2eTests, EvidenceLevel, Evidence),
104
105
  proof_version(Version),
105
106
  Proof = _{
106
107
  proofVersion: Version,
107
108
  proofStatus: Status,
109
+ evidenceLevel: EvidenceLevel,
110
+ evidence: Evidence,
108
111
  proofGaps: Gaps,
109
112
  proofAdvisories: Advisories,
110
113
  proofRepairs: Repairs,
@@ -112,11 +115,14 @@ requirement_proof(ReqId, ReqProps, Context, Proof) :-
112
115
  testResolutions: ScenarioTestStage.resolutions
113
116
  }.
114
117
 
115
- exempt_requirement_proof(Reason, Proof) :-
118
+ exempt_requirement_proof(Reason, ReqProps, Proof) :-
119
+ requirement_evidence(ReqProps, not_applicable, [], EvidenceLevel, Evidence),
116
120
  proof_version(Version),
117
121
  Proof = _{
118
122
  proofVersion: Version,
119
123
  proofStatus: not_applicable,
124
+ evidenceLevel: EvidenceLevel,
125
+ evidence: Evidence,
120
126
  proofGaps: [],
121
127
  proofAdvisories: [],
122
128
  proofRepairs: [],
@@ -1674,7 +1680,84 @@ proof_status(Stages, unresolved) :-
1674
1680
  stage_dict(Stages, Stage),
1675
1681
  memberchk(Stage.status, [unresolved, blocked]),
1676
1682
  !.
1677
- proof_status(_, proven).
1683
+ proof_status(_, tested).
1684
+
1685
+ % implements REQ-kibi-evidence-levels
1686
+ %% requirement_evidence(+Props, +ProofStatus, +PassingE2eTests, -Level, -Evidence)
1687
+ % How strong the evidence behind a requirement is, never stronger than what
1688
+ % backs it. Levels, strongest first: proved (a re-checkable certificate
1689
+ % covers every case), tested (passing E2E receipts cover every linked
1690
+ % scenario: proofStatus tested), asserted (a person stands behind the
1691
+ % statement but nothing current checks it), unverified (an agent wrote it and
1692
+ % no person approved it). No proof kind issues certificates yet, so proved
1693
+ % is never reached here. Evidence lists what earned the level and anything
1694
+ % weaker that also holds, each entry naming its kind and scope.
1695
+ requirement_evidence(Props, ProofStatus, PassingE2eTests, Level, Evidence) :-
1696
+ findall(Entry, evidence_entry(Props, ProofStatus, PassingE2eTests, Entry), Evidence),
1697
+ evidence_level(Evidence, Level).
1698
+
1699
+ evidence_entry(_Props, tested, PassingE2eTests, _{kind: e2e, scope: code, level: tested, tests: PassingE2eTests}).
1700
+ evidence_entry(Props, _ProofStatus, _PassingE2eTests, Entry) :-
1701
+ human_intent(Props, Basis, Ref),
1702
+ ( Ref == ''
1703
+ -> Entry = _{kind: human_intent, scope: intent, level: asserted, basis: Basis}
1704
+ ; Entry = _{kind: human_intent, scope: intent, level: asserted, basis: Basis, ref: Ref}
1705
+ ).
1706
+
1707
+ evidence_level(Evidence, Level) :-
1708
+ ( member(Level0, [proved, tested, asserted]),
1709
+ member(Entry, Evidence),
1710
+ get_dict(level, Entry, Level0)
1711
+ -> Level = Level0
1712
+ ; Level = unverified
1713
+ ).
1714
+
1715
+ %% human_intent(+Props, -Basis, -Ref)
1716
+ % A person stands behind the requirement: someone approved it
1717
+ % (origin.approved_by, the field agent-requirement-unapproved reads), or it
1718
+ % reads as firm (firmness: firm, or no firmness and an origin other than
1719
+ % agent, as for decision firmness). The top-level approved_by approves an
1720
+ % exception; an agent can write it, so on its own it approves nothing here.
1721
+ human_intent(Props, approved, Ref) :-
1722
+ origin_field(Props, approved_by, _),
1723
+ !,
1724
+ intent_ref(Props, Ref).
1725
+ human_intent(Props, firm, Ref) :-
1726
+ effective_firmness(Props, firm),
1727
+ !,
1728
+ intent_ref(Props, Ref).
1729
+
1730
+ effective_firmness(Props, Firmness) :-
1731
+ ( memberchk(firmness=Raw, Props),
1732
+ normalize_atom(Raw, Explicit),
1733
+ memberchk(Explicit, [firm, default, exploratory])
1734
+ -> Firmness = Explicit
1735
+ ; origin_field(Props, kind, agent)
1736
+ -> Firmness = default
1737
+ ; Firmness = firm
1738
+ ).
1739
+
1740
+ intent_ref(Props, Ref) :-
1741
+ ( origin_field(Props, ref, Ref0)
1742
+ -> Ref = Ref0
1743
+ ; prop_text(Props, approval_ref, Ref0)
1744
+ -> Ref = Ref0
1745
+ ; Ref = ''
1746
+ ).
1747
+
1748
+ prop_text(Props, Key, Text) :-
1749
+ Prop =.. [=, Key, Raw],
1750
+ memberchk(Prop, Props),
1751
+ normalize_atom(Raw, Text),
1752
+ Text \== ''.
1753
+
1754
+ origin_field(Props, Key, Value) :-
1755
+ memberchk(origin=Raw, Props),
1756
+ normalize_atom(Raw, Json),
1757
+ catch(atom_json_dict(Json, Origin, [value_string_as(atom)]), _, fail),
1758
+ get_dict(Key, Origin, Value0),
1759
+ normalize_atom(Value0, Value),
1760
+ Value \== ''.
1678
1761
 
1679
1762
  stage_dict(Stages, Stage) :-
1680
1763
  dict_pairs(Stages, _, Pairs),
@@ -1690,7 +1773,7 @@ proof_advisories(Stages, Advisories) :-
1690
1773
  % Every linked scenario is a mandatory proof obligation. Receipt-completeness
1691
1774
  % failures therefore remain blocking even when another scenario has a passing
1692
1775
  % receipt; unit/integration-only evidence stays nonblocking in the E2E lane.
1693
- % Invariant: proofStatus == proven implies proofGaps == [].
1776
+ % Invariant: proofStatus == tested implies proofGaps == [].
1694
1777
  proof_issues(Stages, Gaps, Advisories) :-
1695
1778
  findall(Gap,
1696
1779
  (gap_definition(Gap, _, _, _),
@@ -67,6 +67,8 @@ known_rule('supersedes-reason-missing').
67
67
  known_rule('supersedes-reason-acknowledged').
68
68
  known_rule('policy-ownership').
69
69
  known_rule('policy-markers').
70
+ known_rule('kb-consistency').
71
+ known_rule('kb-consistency-unresolved').
70
72
 
71
73
  rule_enforcement_class('must-priority-coverage', canonical).
72
74
  rule_enforcement_class('symbol-coverage', canonical).
@@ -121,6 +123,8 @@ rule_enforcement_class('supersedes-reason-missing', canonical).
121
123
  rule_enforcement_class('supersedes-reason-acknowledged', advisory).
122
124
  rule_enforcement_class('policy-ownership', canonical).
123
125
  rule_enforcement_class('policy-markers', canonical).
126
+ rule_enforcement_class('kb-consistency', canonical).
127
+ rule_enforcement_class('kb-consistency-unresolved', advisory).
124
128
 
125
129
  rule_implementation('must-priority-coverage', prolog).
126
130
  rule_implementation('symbol-coverage', prolog).
@@ -175,6 +179,8 @@ rule_implementation('supersedes-reason-missing', typescript).
175
179
  rule_implementation('supersedes-reason-acknowledged', typescript).
176
180
  rule_implementation('policy-ownership', typescript).
177
181
  rule_implementation('policy-markers', typescript).
182
+ rule_implementation('kb-consistency', prolog).
183
+ rule_implementation('kb-consistency-unresolved', prolog).
178
184
 
179
185
  rule_predicate('must-priority-coverage', check_must_priority_coverage).
180
186
  rule_predicate('symbol-coverage', check_symbol_coverage).
@@ -210,6 +216,8 @@ rule_predicate('ontology-quality', check_ontology_quality).
210
216
  rule_predicate('symbol-owner-superseded', check_symbol_owner_superseded).
211
217
  rule_predicate('adr-unlinked', check_adr_unlinked).
212
218
  rule_predicate('adr-proposed', check_adr_proposed).
219
+ rule_predicate('kb-consistency', check_kb_consistency).
220
+ rule_predicate('kb-consistency-unresolved', check_kb_consistency_unresolved).
213
221
 
214
222
  rule_predicate_arity('must-priority-coverage', 1).
215
223
  rule_predicate_arity('symbol-coverage', 1).
@@ -245,6 +253,8 @@ rule_predicate_arity('ontology-quality', 1).
245
253
  rule_predicate_arity('symbol-owner-superseded', 1).
246
254
  rule_predicate_arity('adr-unlinked', 1).
247
255
  rule_predicate_arity('adr-proposed', 1).
256
+ rule_predicate_arity('kb-consistency', 1).
257
+ rule_predicate_arity('kb-consistency-unresolved', 1).
248
258
 
249
259
  rule_description('must-priority-coverage', 'Every current must-priority requirement (not superseded, retired, or closed without the implemented tag) must have a scenario and a test').
250
260
  rule_description('symbol-coverage', 'Production symbols need qualifying coverage via covered_by plus a canonical requirement/scenario test path').
@@ -299,3 +309,5 @@ rule_description('supersedes-reason-missing', 'A current requirement or ADR that
299
309
  rule_description('supersedes-reason-acknowledged', 'Informational: how many current superseding requirements and ADRs have only supersede edges the schema 9 migration acknowledged without a \'Why this changed\' section; one summary finding per check').
300
310
  rule_description('policy-ownership', 'When a plugin activated for kibi.check-policy.v1 declares ownership rules, every production symbol in a rule\'s file set must implement a current requirement grounded (requires_predicate) in one of the rule\'s predicates; projects without an activated check policy are unaffected').
301
311
  rule_description('policy-markers', 'When a plugin activated for kibi.check-policy.v1 declares marker rules, every file implementing a requirement grounded in the rule\'s pattern predicate (with its declared sibling files) must contain each marker the KB declares for that pattern').
312
+ 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').
313
+ 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').