kibi-core 0.13.0 → 0.14.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 +1 -1
- package/schema/entities.pl +3 -0
- package/schema/relationships.pl +8 -0
- package/schema/validation.pl +2 -0
- package/src/checks.pl +69 -36
- package/src/discovery.pl +42 -7
- package/src/kb.pl +322 -13
- package/src/requirement_proof.pl +52 -2
- package/src/rule_registry.pl +40 -0
- package/src/semantic_quality.pl +750 -0
- package/src/status.pl +41 -15
- package/src/units.pl +146 -0
package/src/status.pl
CHANGED
|
@@ -19,7 +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
|
-
|
|
22
|
+
( SyncState == fresh
|
|
23
|
+
-> % fresh means no indexed source is newer or missing and no knowledge
|
|
24
|
+
% lane or documentation file is newer than the snapshot: exactly the
|
|
25
|
+
% conditions stale_reasons enumerates. Skip its full entity scan,
|
|
26
|
+
% which dominates status latency on large KBs.
|
|
27
|
+
StaleReasons = [],
|
|
28
|
+
StaleReasonCount = 0,
|
|
29
|
+
StaleReasonsTruncated = false
|
|
30
|
+
; stale_reasons(StaleReasons, StaleReasonCount, StaleReasonsTruncated)
|
|
31
|
+
),
|
|
23
32
|
StatusDict = _{
|
|
24
33
|
branch: Branch,
|
|
25
34
|
snapshotId: SnapshotId,
|
|
@@ -250,11 +259,7 @@ documentation_tree_changed(SnapshotTime) :-
|
|
|
250
259
|
!.
|
|
251
260
|
|
|
252
261
|
directory_tree_newer(Path, SnapshotTime) :-
|
|
253
|
-
|
|
254
|
-
entity_documentation_file(Path),
|
|
255
|
-
\+ ignored_documentation_file(Path),
|
|
256
|
-
time_file(Path, EntryTime),
|
|
257
|
-
EntryTime > SnapshotTime,
|
|
262
|
+
newer_entity_documentation_file(Path, SnapshotTime),
|
|
258
263
|
!.
|
|
259
264
|
|
|
260
265
|
directory_tree_newer(Path, SnapshotTime) :-
|
|
@@ -268,11 +273,7 @@ directory_tree_newer(Path, SnapshotTime) :-
|
|
|
268
273
|
!.
|
|
269
274
|
|
|
270
275
|
directory_tree_newer_path(Path, SnapshotTime, Path) :-
|
|
271
|
-
|
|
272
|
-
entity_documentation_file(Path),
|
|
273
|
-
\+ ignored_documentation_file(Path),
|
|
274
|
-
time_file(Path, EntryTime),
|
|
275
|
-
EntryTime > SnapshotTime.
|
|
276
|
+
newer_entity_documentation_file(Path, SnapshotTime).
|
|
276
277
|
directory_tree_newer_path(Path, SnapshotTime, ChildPath) :-
|
|
277
278
|
exists_directory(Path),
|
|
278
279
|
directory_files(Path, Entries),
|
|
@@ -282,9 +283,22 @@ directory_tree_newer_path(Path, SnapshotTime, ChildPath) :-
|
|
|
282
283
|
directory_file_path(Path, Entry, Candidate),
|
|
283
284
|
directory_tree_newer_path(Candidate, SnapshotTime, ChildPath).
|
|
284
285
|
|
|
286
|
+
:- dynamic workspace_root_memo/2.
|
|
287
|
+
|
|
288
|
+
% Resolved once per attached KB path: status maps every entity source to a
|
|
289
|
+
% workspace-relative path, and re-deriving the root per entity dominated it.
|
|
285
290
|
attached_workspace_root(WorkspaceRoot) :-
|
|
286
291
|
kb:kb_attached(KbPath),
|
|
287
|
-
|
|
292
|
+
( workspace_root_memo(KbPath, Memo)
|
|
293
|
+
-> Memo = found(WorkspaceRoot)
|
|
294
|
+
; ( once(branch_workspace_from_kb_path(KbPath, _Branch, Root))
|
|
295
|
+
-> Memo = found(Root)
|
|
296
|
+
; Memo = none
|
|
297
|
+
),
|
|
298
|
+
retractall(workspace_root_memo(_, _)),
|
|
299
|
+
assertz(workspace_root_memo(KbPath, Memo)),
|
|
300
|
+
Memo = found(WorkspaceRoot)
|
|
301
|
+
).
|
|
288
302
|
|
|
289
303
|
branch_workspace_from_kb_path(KbPath, Branch, WorkspaceRoot) :-
|
|
290
304
|
branch_path_segments(KbPath, BranchesDir, Segments),
|
|
@@ -366,12 +380,24 @@ ignored_documentation_file(Path) :-
|
|
|
366
380
|
ignored_documentation_file(Path) :-
|
|
367
381
|
sub_atom(Path, _, _, _, '/tests/benchmarks/').
|
|
368
382
|
|
|
383
|
+
%% newer_entity_documentation_file(+Path, +SnapshotTime) is semidet.
|
|
384
|
+
% Cheap path and mtime tests run before the file is read, and the content
|
|
385
|
+
% test is deterministic. Previously each sub_string/5 left a choicepoint per
|
|
386
|
+
% occurrence, so a failing mtime test backtracked through every combination
|
|
387
|
+
% of id:/title:/status: positions (millions of redos on large trees).
|
|
388
|
+
newer_entity_documentation_file(Path, SnapshotTime) :-
|
|
389
|
+
exists_file(Path),
|
|
390
|
+
\+ ignored_documentation_file(Path),
|
|
391
|
+
time_file(Path, EntryTime),
|
|
392
|
+
EntryTime > SnapshotTime,
|
|
393
|
+
entity_documentation_file(Path).
|
|
394
|
+
|
|
369
395
|
entity_documentation_file(Path) :-
|
|
370
396
|
read_file_to_string(Path, Content, []),
|
|
371
397
|
sub_string(Content, 0, 3, _, "---"),
|
|
372
|
-
sub_string(Content, _, _, _, "id:"),
|
|
373
|
-
sub_string(Content, _, _, _, "title:"),
|
|
374
|
-
sub_string(Content, _, _, _, "status:").
|
|
398
|
+
once(sub_string(Content, _, _, _, "id:")),
|
|
399
|
+
once(sub_string(Content, _, _, _, "title:")),
|
|
400
|
+
once(sub_string(Content, _, _, _, "status:")).
|
|
375
401
|
|
|
376
402
|
dict_json_string(Dict, JsonString) :-
|
|
377
403
|
with_output_to(string(JsonString), json_write_dict(current_output, Dict, [])).
|
package/src/units.pl
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
% Module: units
|
|
2
|
+
% Deterministic unit canonicalization for property_value comparison.
|
|
3
|
+
%
|
|
4
|
+
% Authored values are stored unchanged. Checks canonicalize a numeric value to
|
|
5
|
+
% the base unit of its family before computing logical ground signatures and
|
|
6
|
+
% before contradiction, redundancy, or implication comparison, so "30 min" and
|
|
7
|
+
% "1800 s" share one comparable term. Only exact, fixed-ratio conversions are
|
|
8
|
+
% listed: calendar units (month, year) have no fixed length and stay as-is.
|
|
9
|
+
% Unknown units are never equated with anything but themselves.
|
|
10
|
+
%
|
|
11
|
+
% implements REQ-kibi-unit-canonicalization
|
|
12
|
+
|
|
13
|
+
:- module(units, [
|
|
14
|
+
canonical_quantity/6, % +ValueType, +Value, +Unit, -CanonType, -CanonValue, -CanonUnit
|
|
15
|
+
unit_base/3 % ?Unit, -BaseUnit, -Factor
|
|
16
|
+
]).
|
|
17
|
+
|
|
18
|
+
% Aliases are grouped by unit family rather than by predicate.
|
|
19
|
+
:- discontiguous unit_symbol/3, unit_word/3.
|
|
20
|
+
|
|
21
|
+
%% unit_base(?Unit, -BaseUnit, -Factor)
|
|
22
|
+
% Factor converts one Unit into BaseUnit (Value * Factor). Symbols match
|
|
23
|
+
% exactly (case matters: MB is a megabyte, Mb is not listed); spelled-out words
|
|
24
|
+
% match case-insensitively. Ambiguous spellings (KB, Mb, bps, month, year) are
|
|
25
|
+
% deliberately absent so they are never silently equated.
|
|
26
|
+
unit_base(Unit, BaseUnit, Factor) :-
|
|
27
|
+
unit_symbol(Unit, BaseUnit, Factor).
|
|
28
|
+
unit_base(Unit, BaseUnit, Factor) :-
|
|
29
|
+
unit_word(Unit, BaseUnit, Factor).
|
|
30
|
+
|
|
31
|
+
% Duration family, base unit: s (second).
|
|
32
|
+
unit_symbol(ns, s, 1.0e-9).
|
|
33
|
+
unit_symbol(us, s, 1.0e-6).
|
|
34
|
+
unit_symbol(ms, s, 1.0e-3).
|
|
35
|
+
unit_symbol(s, s, 1).
|
|
36
|
+
unit_symbol(sec, s, 1).
|
|
37
|
+
unit_symbol(secs, s, 1).
|
|
38
|
+
unit_symbol(min, s, 60).
|
|
39
|
+
unit_symbol(mins, s, 60).
|
|
40
|
+
unit_symbol(h, s, 3600).
|
|
41
|
+
unit_symbol(hr, s, 3600).
|
|
42
|
+
unit_symbol(hrs, s, 3600).
|
|
43
|
+
unit_symbol(d, s, 86400).
|
|
44
|
+
unit_symbol(wk, s, 604800).
|
|
45
|
+
unit_word(nanosecond, s, 1.0e-9).
|
|
46
|
+
unit_word(nanoseconds, s, 1.0e-9).
|
|
47
|
+
unit_word(microsecond, s, 1.0e-6).
|
|
48
|
+
unit_word(microseconds, s, 1.0e-6).
|
|
49
|
+
unit_word(millisecond, s, 1.0e-3).
|
|
50
|
+
unit_word(milliseconds, s, 1.0e-3).
|
|
51
|
+
unit_word(second, s, 1).
|
|
52
|
+
unit_word(seconds, s, 1).
|
|
53
|
+
unit_word(minute, s, 60).
|
|
54
|
+
unit_word(minutes, s, 60).
|
|
55
|
+
unit_word(hour, s, 3600).
|
|
56
|
+
unit_word(hours, s, 3600).
|
|
57
|
+
unit_word(day, s, 86400).
|
|
58
|
+
unit_word(days, s, 86400).
|
|
59
|
+
unit_word(week, s, 604800).
|
|
60
|
+
unit_word(weeks, s, 604800).
|
|
61
|
+
|
|
62
|
+
% Data size family, base unit: byte. SI prefixes are decimal (kB = 1000 B);
|
|
63
|
+
% IEC prefixes are binary (KiB = 1024 B).
|
|
64
|
+
unit_symbol('B', byte, 1).
|
|
65
|
+
unit_symbol(kB, byte, 1000).
|
|
66
|
+
unit_symbol('MB', byte, 1000000).
|
|
67
|
+
unit_symbol('GB', byte, 1000000000).
|
|
68
|
+
unit_symbol('TB', byte, 1000000000000).
|
|
69
|
+
unit_symbol('KiB', byte, 1024).
|
|
70
|
+
unit_symbol('MiB', byte, 1048576).
|
|
71
|
+
unit_symbol('GiB', byte, 1073741824).
|
|
72
|
+
unit_symbol('TiB', byte, 1099511627776).
|
|
73
|
+
unit_word(byte, byte, 1).
|
|
74
|
+
unit_word(bytes, byte, 1).
|
|
75
|
+
unit_word(kilobyte, byte, 1000).
|
|
76
|
+
unit_word(kilobytes, byte, 1000).
|
|
77
|
+
unit_word(megabyte, byte, 1000000).
|
|
78
|
+
unit_word(megabytes, byte, 1000000).
|
|
79
|
+
unit_word(gigabyte, byte, 1000000000).
|
|
80
|
+
unit_word(gigabytes, byte, 1000000000).
|
|
81
|
+
unit_word(terabyte, byte, 1000000000000).
|
|
82
|
+
unit_word(terabytes, byte, 1000000000000).
|
|
83
|
+
unit_word(kibibyte, byte, 1024).
|
|
84
|
+
unit_word(kibibytes, byte, 1024).
|
|
85
|
+
unit_word(mebibyte, byte, 1048576).
|
|
86
|
+
unit_word(mebibytes, byte, 1048576).
|
|
87
|
+
unit_word(gibibyte, byte, 1073741824).
|
|
88
|
+
unit_word(gibibytes, byte, 1073741824).
|
|
89
|
+
unit_word(tebibyte, byte, 1099511627776).
|
|
90
|
+
unit_word(tebibytes, byte, 1099511627776).
|
|
91
|
+
|
|
92
|
+
% Percentage family, base unit: percent.
|
|
93
|
+
unit_symbol('%', percent, 1).
|
|
94
|
+
unit_word(percent, percent, 1).
|
|
95
|
+
unit_word(percentage, percent, 1).
|
|
96
|
+
unit_word(pct, percent, 1).
|
|
97
|
+
unit_word(basis_point, percent, 0.01).
|
|
98
|
+
unit_word(basis_points, percent, 0.01).
|
|
99
|
+
|
|
100
|
+
%% canonical_quantity(+ValueType, +Value, +Unit, -CanonType, -CanonValue, -CanonUnit)
|
|
101
|
+
% Numeric values with a known unit are converted to the family base unit.
|
|
102
|
+
% Integral numeric results are represented as int so int/number spellings of
|
|
103
|
+
% the same quantity compare equal. Non-numeric values and unknown units pass
|
|
104
|
+
% through unchanged.
|
|
105
|
+
canonical_quantity(ValueType, Value, Unit, CanonType, CanonValue, CanonUnit) :-
|
|
106
|
+
numeric_value_type(ValueType),
|
|
107
|
+
number(Value),
|
|
108
|
+
!,
|
|
109
|
+
( known_unit(Unit, BaseUnit, Factor)
|
|
110
|
+
-> Scaled is Value * Factor,
|
|
111
|
+
CanonUnit = BaseUnit
|
|
112
|
+
; Scaled = Value,
|
|
113
|
+
CanonUnit = Unit
|
|
114
|
+
),
|
|
115
|
+
canonical_number(Scaled, CanonType, CanonValue).
|
|
116
|
+
canonical_quantity(ValueType, Value, Unit, ValueType, Value, Unit).
|
|
117
|
+
|
|
118
|
+
numeric_value_type(int).
|
|
119
|
+
numeric_value_type(number).
|
|
120
|
+
|
|
121
|
+
known_unit(Unit, BaseUnit, Factor) :-
|
|
122
|
+
atom(Unit),
|
|
123
|
+
Unit \== '',
|
|
124
|
+
( unit_symbol(Unit, BaseUnit, Factor)
|
|
125
|
+
-> true
|
|
126
|
+
; downcase_atom(Unit, Lower),
|
|
127
|
+
unit_word(Lower, BaseUnit, Factor)
|
|
128
|
+
),
|
|
129
|
+
!.
|
|
130
|
+
|
|
131
|
+
% Integers (including big integers) stay exact. Floats have binary noise
|
|
132
|
+
% rounded away (0.1 h * 3600 = 360.00000000000006) before deciding whether the
|
|
133
|
+
% canonical value is integral; floats too large to round stay as they are.
|
|
134
|
+
canonical_number(Value, int, Value) :-
|
|
135
|
+
integer(Value),
|
|
136
|
+
!.
|
|
137
|
+
canonical_number(Value, Type, Canonical) :-
|
|
138
|
+
catch(Rounded is round(Value * 1.0e9) / 1.0e9, _, fail),
|
|
139
|
+
!,
|
|
140
|
+
( Rounded =:= round(Rounded)
|
|
141
|
+
-> Type = int,
|
|
142
|
+
Canonical is integer(round(Rounded))
|
|
143
|
+
; Type = number,
|
|
144
|
+
Canonical is float(Rounded)
|
|
145
|
+
).
|
|
146
|
+
canonical_number(Value, number, Value).
|