kibi-core 0.10.0 → 0.12.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.
@@ -0,0 +1,131 @@
1
+ % Module: rule_registry
2
+ % GENERATED by scripts/generate-rule-registry.mjs from
3
+ % packages/core/schema/rule-registry.json. Do not edit directly.
4
+ %
5
+ % Registry facts shared by TS and Prolog so unknown rule names fail loudly
6
+ % instead of silently returning empty results.
7
+
8
+ :- module(rule_registry, [
9
+ known_rule/1,
10
+ rule_enforcement_class/2,
11
+ rule_implementation/2,
12
+ rule_predicate/2,
13
+ rule_predicate_arity/2,
14
+ rule_description/2
15
+ ]).
16
+
17
+ known_rule('must-priority-coverage').
18
+ known_rule('symbol-coverage').
19
+ known_rule('symbol-traceability').
20
+ known_rule('no-dangling-refs').
21
+ known_rule('source-relationship-parity').
22
+ known_rule('no-cycles').
23
+ known_rule('required-fields').
24
+ known_rule('deprecated-adr-no-successor').
25
+ known_rule('domain-contradictions').
26
+ known_rule('logic-coverage').
27
+ known_rule('rule-safety').
28
+ known_rule('rule-verifiability').
29
+ known_rule('query-plan-safety').
30
+ known_rule('req-status-vocabulary').
31
+ known_rule('strict-fact-shape').
32
+ known_rule('strict-req-fact-pairing').
33
+ known_rule('predicate-verifiability').
34
+ known_rule('strict-readiness').
35
+ known_rule('semantic-completeness').
36
+
37
+ rule_enforcement_class('must-priority-coverage', canonical).
38
+ rule_enforcement_class('symbol-coverage', canonical).
39
+ rule_enforcement_class('symbol-traceability', canonical).
40
+ rule_enforcement_class('no-dangling-refs', canonical).
41
+ rule_enforcement_class('source-relationship-parity', canonical).
42
+ rule_enforcement_class('no-cycles', canonical).
43
+ rule_enforcement_class('required-fields', canonical).
44
+ rule_enforcement_class('deprecated-adr-no-successor', canonical).
45
+ rule_enforcement_class('domain-contradictions', canonical).
46
+ rule_enforcement_class('logic-coverage', canonical).
47
+ rule_enforcement_class('rule-safety', canonical).
48
+ rule_enforcement_class('rule-verifiability', canonical).
49
+ rule_enforcement_class('query-plan-safety', canonical).
50
+ rule_enforcement_class('req-status-vocabulary', canonical).
51
+ rule_enforcement_class('strict-fact-shape', advisory).
52
+ rule_enforcement_class('strict-req-fact-pairing', advisory).
53
+ rule_enforcement_class('predicate-verifiability', advisory).
54
+ rule_enforcement_class('strict-readiness', migration).
55
+ rule_enforcement_class('semantic-completeness', migration).
56
+
57
+ rule_implementation('must-priority-coverage', prolog).
58
+ rule_implementation('symbol-coverage', prolog).
59
+ rule_implementation('symbol-traceability', prolog).
60
+ rule_implementation('no-dangling-refs', prolog).
61
+ rule_implementation('source-relationship-parity', typescript).
62
+ rule_implementation('no-cycles', prolog).
63
+ rule_implementation('required-fields', prolog).
64
+ rule_implementation('deprecated-adr-no-successor', prolog).
65
+ rule_implementation('domain-contradictions', prolog).
66
+ rule_implementation('logic-coverage', prolog).
67
+ rule_implementation('rule-safety', prolog).
68
+ rule_implementation('rule-verifiability', prolog).
69
+ rule_implementation('query-plan-safety', typescript).
70
+ rule_implementation('req-status-vocabulary', prolog).
71
+ rule_implementation('strict-fact-shape', prolog).
72
+ rule_implementation('strict-req-fact-pairing', prolog).
73
+ rule_implementation('predicate-verifiability', prolog).
74
+ rule_implementation('strict-readiness', prolog).
75
+ rule_implementation('semantic-completeness', prolog).
76
+
77
+ rule_predicate('must-priority-coverage', check_must_priority_coverage).
78
+ rule_predicate('symbol-coverage', check_symbol_coverage).
79
+ rule_predicate('symbol-traceability', check_symbol_traceability).
80
+ rule_predicate('no-dangling-refs', check_no_dangling_refs).
81
+ rule_predicate('no-cycles', check_no_cycles).
82
+ rule_predicate('required-fields', check_required_fields).
83
+ rule_predicate('deprecated-adr-no-successor', check_deprecated_adrs).
84
+ rule_predicate('domain-contradictions', check_domain_contradictions).
85
+ rule_predicate('logic-coverage', check_logic_coverage).
86
+ rule_predicate('rule-safety', check_rule_safety).
87
+ rule_predicate('rule-verifiability', check_rule_verifiability).
88
+ rule_predicate('req-status-vocabulary', check_req_status_vocabulary).
89
+ rule_predicate('strict-fact-shape', check_strict_fact_shape).
90
+ rule_predicate('strict-req-fact-pairing', check_strict_req_fact_pairing).
91
+ rule_predicate('predicate-verifiability', check_predicate_verifiability).
92
+ rule_predicate('strict-readiness', check_strict_readiness).
93
+ rule_predicate('semantic-completeness', check_semantic_completeness).
94
+
95
+ rule_predicate_arity('must-priority-coverage', 1).
96
+ rule_predicate_arity('symbol-coverage', 1).
97
+ rule_predicate_arity('symbol-traceability', 2).
98
+ rule_predicate_arity('no-dangling-refs', 1).
99
+ rule_predicate_arity('no-cycles', 1).
100
+ rule_predicate_arity('required-fields', 1).
101
+ rule_predicate_arity('deprecated-adr-no-successor', 1).
102
+ rule_predicate_arity('domain-contradictions', 1).
103
+ rule_predicate_arity('logic-coverage', 1).
104
+ rule_predicate_arity('rule-safety', 1).
105
+ rule_predicate_arity('rule-verifiability', 1).
106
+ rule_predicate_arity('req-status-vocabulary', 1).
107
+ rule_predicate_arity('strict-fact-shape', 1).
108
+ rule_predicate_arity('strict-req-fact-pairing', 1).
109
+ rule_predicate_arity('predicate-verifiability', 1).
110
+ rule_predicate_arity('strict-readiness', 1).
111
+ rule_predicate_arity('semantic-completeness', 1).
112
+
113
+ rule_description('must-priority-coverage', 'Every must-priority requirement must have a scenario and a test').
114
+ rule_description('symbol-coverage', 'Production symbols need qualifying coverage via covered_by plus a canonical requirement/scenario test path').
115
+ rule_description('symbol-traceability', 'Production symbols must directly implement requirements for ownership; covered_by is coverage only and executable_for is test identity only').
116
+ rule_description('no-dangling-refs', 'All relationship targets must exist in the KB').
117
+ rule_description('source-relationship-parity', 'Authored Markdown and relationship-shard edges must exactly match the compiled KB').
118
+ rule_description('no-cycles', 'No circular dependency chains in requirements').
119
+ rule_description('required-fields', 'All entities must have required fields').
120
+ rule_description('deprecated-adr-no-successor', 'Deprecated ADRs must have a successor ADR that supersedes them').
121
+ rule_description('domain-contradictions', 'Detect contradictions between requirements constraining the same fact').
122
+ rule_description('logic-coverage', 'Require every explicitly declared atomic requirement claim to be grounded by a linked strict-property or predicate fact').
123
+ rule_description('rule-safety', 'Stored Logic IR rules use only the typed, bounded, stratified vocabulary').
124
+ rule_description('rule-verifiability', 'Requirement rule links resolve to safe rules and registered rule schemas').
125
+ rule_description('query-plan-safety', 'Detect Prolog validation clauses that place negation before generator calls').
126
+ rule_description('req-status-vocabulary', 'Requirement statuses must use the canonical vocabulary (open, in_progress, closed; legacy: active, approved); ADR statuses such as accepted silently fall out of the proof ladder').
127
+ rule_description('strict-fact-shape', 'Detect malformed strict facts (facts with fact_kind that are missing required fields)').
128
+ rule_description('strict-req-fact-pairing', 'Detect requirements with incomplete strict subject/property fact pairing for contradiction-safe semantics').
129
+ rule_description('predicate-verifiability', 'Detect requires_predicate links that do not target ground fact_kind: predicate facts').
130
+ rule_description('strict-readiness', 'Report strict contradiction-readiness levels for requirements that are still prose-only or otherwise not contradiction-ready').
131
+ rule_description('semantic-completeness', 'Every inventoried assertive proposition is modeled or explicitly classified').
package/src/status.pl CHANGED
@@ -19,12 +19,16 @@ status_meta_dict(StatusDict) :-
19
19
  snapshot_id(SnapshotId),
20
20
  synced_at(DataFile, SyncedAt),
21
21
  freshness_state(DataFile, Dirty, SyncState),
22
+ stale_reasons(StaleReasons, StaleReasonCount, StaleReasonsTruncated),
22
23
  StatusDict = _{
23
24
  branch: Branch,
24
25
  snapshotId: SnapshotId,
25
26
  syncedAt: SyncedAt,
26
27
  dirty: Dirty,
27
28
  syncState: SyncState,
29
+ staleReasons: StaleReasons,
30
+ staleReasonCount: StaleReasonCount,
31
+ staleReasonsTruncated: StaleReasonsTruncated,
28
32
  kbPath: KbPath,
29
33
  lastSyncSource: persisted
30
34
  }.
@@ -37,6 +41,9 @@ status_meta_dict(StatusDict) :-
37
41
  syncedAt: null,
38
42
  dirty: false,
39
43
  syncState: unknown,
44
+ staleReasons: [],
45
+ staleReasonCount: 0,
46
+ staleReasonsTruncated: false,
40
47
  kbPath: KbPath,
41
48
  lastSyncSource: unknown
42
49
  }.
@@ -104,9 +111,109 @@ freshness_state(DataFile, false, fresh) :-
104
111
  !.
105
112
  freshness_state(_, true, unknown).
106
113
 
114
+ stale_reasons(Reasons, Count, Truncated) :-
115
+ entity_source_id_index(Index),
116
+ findall(Reason, stale_indexed_source_reason(Index, Reason), IndexedReasons),
117
+ findall(Reason, stale_knowledge_lane_reason(Index, Reason), KnowledgeReasons),
118
+ findall(Reason, stale_documentation_reason(Index, Reason), DocumentationReasons),
119
+ append(IndexedReasons, KnowledgeReasons, IndexedAndKnowledge),
120
+ append(IndexedAndKnowledge, DocumentationReasons, Reasons0),
121
+ sort(Reasons0, Sorted),
122
+ length(Sorted, Count),
123
+ ( Count > 200
124
+ -> length(Reasons, 200), append(Reasons, _, Sorted), Truncated = true
125
+ ; Reasons = Sorted, Truncated = false
126
+ ).
127
+
128
+ stale_indexed_source_reason(Index, Reason) :-
129
+ attached_workspace_root(WorkspaceRoot),
130
+ kb:kb_indexed_sources(Sources),
131
+ kb_snapshot_time(SnapshotTime),
132
+ member(SourceAtom, Sources),
133
+ repo_relative_source(SourceAtom, RelativeSource),
134
+ directory_file_path(WorkspaceRoot, RelativeSource, SourcePath),
135
+ ( exists_file(SourcePath)
136
+ -> time_file(SourcePath, FileTime),
137
+ FileTime > SnapshotTime,
138
+ Code = indexed_source_newer
139
+ ; exists_directory(SourcePath)
140
+ -> fail
141
+ ; Code = indexed_source_missing
142
+ ),
143
+ entity_ids_for_source(Index, RelativeSource, EntityIds),
144
+ Reason = _{code: Code, path: RelativeSource, entityIds: EntityIds}.
145
+
146
+ stale_knowledge_lane_reason(Index, Reason) :-
147
+ attached_workspace_root(WorkspaceRoot),
148
+ knowledge_lane(Lane),
149
+ directory_file_path(WorkspaceRoot, '.kb', KbRoot),
150
+ directory_file_path(KbRoot, Lane, LaneRoot),
151
+ exists_directory(LaneRoot),
152
+ kb_snapshot_time(SnapshotTime),
153
+ directory_tree_newer_path(LaneRoot, SnapshotTime, Path),
154
+ workspace_relative_path(WorkspaceRoot, Path, RelativePath),
155
+ entity_ids_for_source(Index, RelativePath, EntityIds),
156
+ Reason = _{code: knowledge_source_newer, path: RelativePath, entityIds: EntityIds}.
157
+
158
+ stale_documentation_reason(Index, Reason) :-
159
+ attached_workspace_root(WorkspaceRoot),
160
+ directory_file_path(WorkspaceRoot, 'documentation', DocumentationRoot),
161
+ exists_directory(DocumentationRoot),
162
+ kb_snapshot_time(SnapshotTime),
163
+ directory_tree_newer_path(DocumentationRoot, SnapshotTime, Path),
164
+ workspace_relative_path(WorkspaceRoot, Path, RelativePath),
165
+ entity_ids_for_source(Index, RelativePath, EntityIds),
166
+ Reason = _{code: documentation_source_newer, path: RelativePath, entityIds: EntityIds}.
167
+
168
+ kb_snapshot_time(SnapshotTime) :-
169
+ kb:kb_attached(KbPath),
170
+ ( directory_file_path(KbPath, 'CURRENT', DataFile), exists_file(DataFile)
171
+ -> time_file(DataFile, SnapshotTime)
172
+ ; directory_file_path(KbPath, 'kb.rdf', DataFile), exists_file(DataFile)
173
+ -> time_file(DataFile, SnapshotTime)
174
+ ; SnapshotTime = 0
175
+ ).
176
+
177
+ % One pass over all entities builds the repo-relative source -> entity-id
178
+ % lookup used by every stale reason. The previous per-path full enumeration
179
+ % made kb_status_json quadratic (paths x entities) and could wedge large KBs
180
+ % for minutes whenever mtime churn (e.g. a git checkout) marked whole lanes
181
+ % newer than the snapshot.
182
+ entity_source_id_index(Index) :-
183
+ findall(RelativeSource-Id,
184
+ ( kb_entity(Id, _Type, Props),
185
+ entity_source_property(Props, RawSource),
186
+ source_value_atom(RawSource, SourceAtom),
187
+ repo_relative_source(SourceAtom, RelativeSource),
188
+ Id \= ''
189
+ ),
190
+ Pairs),
191
+ sort(Pairs, Sorted),
192
+ group_pairs_by_key(Sorted, Grouped),
193
+ maplist(sorted_id_values, Grouped, GroupedEntries),
194
+ dict_create(Index, source_index, GroupedEntries).
195
+
196
+ sorted_id_values(RelativeSource-Ids0, RelativeSource-Ids) :-
197
+ sort(Ids0, Ids).
198
+
199
+ entity_ids_for_source(Index, RelativeSource, EntityIds) :-
200
+ ( get_dict(RelativeSource, Index, Ids)
201
+ -> EntityIds = Ids
202
+ ; EntityIds = []
203
+ ).
204
+
205
+ entity_source_property(Props, RawSource) :-
206
+ memberchk(sourceFile=RawSource, Props),
207
+ !.
208
+ entity_source_property(Props, RawSource) :-
209
+ memberchk(source=RawSource, Props).
210
+
107
211
  workspace_state_changed(SnapshotTime) :-
108
212
  workspace_source_changed(SnapshotTime),
109
213
  !.
214
+ workspace_state_changed(SnapshotTime) :-
215
+ knowledge_lane_tree_changed(SnapshotTime),
216
+ !.
110
217
  workspace_state_changed(SnapshotTime) :-
111
218
  documentation_tree_changed(SnapshotTime),
112
219
  !.
@@ -126,6 +233,15 @@ workspace_source_changed(SnapshotTime) :-
126
233
  ),
127
234
  !.
128
235
 
236
+ knowledge_lane_tree_changed(SnapshotTime) :-
237
+ attached_workspace_root(WorkspaceRoot),
238
+ knowledge_lane(Lane),
239
+ directory_file_path(WorkspaceRoot, '.kb', KbRoot),
240
+ directory_file_path(KbRoot, Lane, LaneRoot),
241
+ exists_directory(LaneRoot),
242
+ directory_tree_newer(LaneRoot, SnapshotTime),
243
+ !.
244
+
129
245
  documentation_tree_changed(SnapshotTime) :-
130
246
  attached_workspace_root(WorkspaceRoot),
131
247
  directory_file_path(WorkspaceRoot, 'documentation', DocumentationRoot),
@@ -140,6 +256,7 @@ directory_tree_newer(Path, SnapshotTime) :-
140
256
  time_file(Path, EntryTime),
141
257
  EntryTime > SnapshotTime,
142
258
  !.
259
+
143
260
  directory_tree_newer(Path, SnapshotTime) :-
144
261
  exists_directory(Path),
145
262
  directory_files(Path, Entries),
@@ -150,6 +267,21 @@ directory_tree_newer(Path, SnapshotTime) :-
150
267
  directory_tree_newer(ChildPath, SnapshotTime),
151
268
  !.
152
269
 
270
+ directory_tree_newer_path(Path, SnapshotTime, Path) :-
271
+ exists_file(Path),
272
+ entity_documentation_file(Path),
273
+ \+ ignored_documentation_file(Path),
274
+ time_file(Path, EntryTime),
275
+ EntryTime > SnapshotTime.
276
+ directory_tree_newer_path(Path, SnapshotTime, ChildPath) :-
277
+ exists_directory(Path),
278
+ directory_files(Path, Entries),
279
+ member(Entry, Entries),
280
+ Entry \= '.',
281
+ Entry \= '..',
282
+ directory_file_path(Path, Entry, Candidate),
283
+ directory_tree_newer_path(Candidate, SnapshotTime, ChildPath).
284
+
153
285
  attached_workspace_root(WorkspaceRoot) :-
154
286
  kb:kb_attached(KbPath),
155
287
  branch_workspace_from_kb_path(KbPath, _Branch, WorkspaceRoot).
@@ -219,8 +351,20 @@ source_value_atom(Val, Atom) :-
219
351
  term_string(Val, Str),
220
352
  atom_string(Atom, Str).
221
353
 
354
+ knowledge_lane(requirements).
355
+ knowledge_lane(scenarios).
356
+ knowledge_lane(tests).
357
+ knowledge_lane(facts).
358
+ knowledge_lane(adr).
359
+ knowledge_lane(flags).
360
+ knowledge_lane(events).
361
+
222
362
  ignored_documentation_file(Path) :-
223
363
  file_base_name(Path, 'README.md').
364
+ ignored_documentation_file(Path) :-
365
+ sub_atom(Path, _, _, _, '/tests/e2e/').
366
+ ignored_documentation_file(Path) :-
367
+ sub_atom(Path, _, _, _, '/tests/benchmarks/').
224
368
 
225
369
  entity_documentation_file(Path) :-
226
370
  read_file_to_string(Path, Content, []),
@@ -0,0 +1,47 @@
1
+ % Module: symbol_classification
2
+ % GENERATED by scripts/generate-symbol-classification.mjs from
3
+ % packages/core/schema/symbol-classification.json. Do not edit directly.
4
+ %
5
+ % Vocabulary facts shared by TS and Prolog so symbol classification cannot
6
+ % drift between the extractors, the manifest gate, and validation.
7
+
8
+ :- module(symbol_classification, [
9
+ allowed_granularity_reason/1,
10
+ coarse_granularity_reason/1,
11
+ symbol_role/1,
12
+ inferred_role/2,
13
+ traceability_relationship_type/1
14
+ ]).
15
+
16
+ allowed_granularity_reason('config-artifact').
17
+ allowed_granularity_reason('module-level-behavior').
18
+ allowed_granularity_reason('extractor-miss').
19
+ allowed_granularity_reason('legacy-link').
20
+ allowed_granularity_reason('test-suite').
21
+
22
+ coarse_granularity_reason('config-artifact').
23
+ coarse_granularity_reason('module-level-behavior').
24
+ coarse_granularity_reason('extractor-miss').
25
+ coarse_granularity_reason('test-suite').
26
+
27
+ symbol_role('behavioral').
28
+ symbol_role('structural').
29
+ symbol_role('type-shape').
30
+ symbol_role('config').
31
+ symbol_role('module').
32
+ symbol_role('unknown').
33
+
34
+ inferred_role('function', 'behavioral').
35
+ inferred_role('class', 'behavioral').
36
+ inferred_role('method', 'behavioral').
37
+ inferred_role('property', 'behavioral').
38
+ inferred_role('accessor', 'behavioral').
39
+ inferred_role('interface', 'type-shape').
40
+ inferred_role('type', 'type-shape').
41
+ inferred_role('enum', 'type-shape').
42
+ inferred_role('variable', 'unknown').
43
+ inferred_role('unknown', 'unknown').
44
+
45
+ traceability_relationship_type('implements').
46
+ traceability_relationship_type('covered_by').
47
+ traceability_relationship_type('executable_for').