kibi-cli 2.39.0 → 2.40.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.
Files changed (163) hide show
  1. package/dist/cli-register-foundation.js +2 -2
  2. package/dist/commands/check.d.ts.map +1 -1
  3. package/dist/commands/check.js +33 -9
  4. package/dist/commands/doctor.d.ts.map +1 -1
  5. package/dist/commands/doctor.js +15 -0
  6. package/dist/commands/init.d.ts.map +1 -1
  7. package/dist/commands/init.js +4 -0
  8. package/dist/commands/migrate-plan-record.d.ts +18 -0
  9. package/dist/commands/migrate-plan-record.d.ts.map +1 -0
  10. package/dist/commands/migrate-plan-record.js +112 -0
  11. package/dist/commands/migrate.d.ts +11 -2
  12. package/dist/commands/migrate.d.ts.map +1 -1
  13. package/dist/commands/migrate.js +53 -7
  14. package/dist/commands/prove.d.ts.map +1 -1
  15. package/dist/commands/prove.js +18 -3
  16. package/dist/commands/sync/manifest.d.ts.map +1 -1
  17. package/dist/commands/sync/manifest.js +17 -4
  18. package/dist/commands/sync.d.ts.map +1 -1
  19. package/dist/commands/sync.js +8 -0
  20. package/dist/commands/telemetry.d.ts.map +1 -1
  21. package/dist/commands/telemetry.js +12 -2
  22. package/dist/extractors/symbol-title-match.d.ts +31 -0
  23. package/dist/extractors/symbol-title-match.d.ts.map +1 -0
  24. package/dist/extractors/symbol-title-match.js +133 -0
  25. package/dist/extractors/symbols-coordinator.d.ts.map +1 -1
  26. package/dist/extractors/symbols-coordinator.js +81 -12
  27. package/dist/operations/bootstrap/discovery-evidence.js +2 -2
  28. package/dist/operations/bootstrap/guidance-actions.d.ts.map +1 -1
  29. package/dist/operations/bootstrap/guidance-actions.js +12 -1
  30. package/dist/operations/bootstrap/plugin-offers.d.ts +7 -1
  31. package/dist/operations/bootstrap/plugin-offers.d.ts.map +1 -1
  32. package/dist/operations/bootstrap/plugin-offers.js +73 -3
  33. package/dist/operations/modeling/logic-modeling.d.ts.map +1 -1
  34. package/dist/operations/modeling/logic-modeling.js +2 -1
  35. package/dist/operations/modeling/model-requirement.d.ts.map +1 -1
  36. package/dist/operations/modeling/model-requirement.js +2 -1
  37. package/dist/operations/mutation/symbol-refresh.d.ts +2 -0
  38. package/dist/operations/mutation/symbol-refresh.d.ts.map +1 -1
  39. package/dist/operations/mutation/symbol-refresh.js +6 -1
  40. package/dist/operations/mutation/upsert.d.ts.map +1 -1
  41. package/dist/operations/mutation/upsert.js +7 -0
  42. package/dist/operations/planning/compile-intent.d.ts.map +1 -1
  43. package/dist/operations/planning/compile-intent.js +2 -1
  44. package/dist/operations/proof/claim-bindings.d.ts +11 -0
  45. package/dist/operations/proof/claim-bindings.d.ts.map +1 -1
  46. package/dist/operations/proof/claim-bindings.js +144 -1
  47. package/dist/operations/proof/code-certificates.d.ts +10 -3
  48. package/dist/operations/proof/code-certificates.d.ts.map +1 -1
  49. package/dist/operations/proof/code-certificates.js +65 -13
  50. package/dist/operations/proof/code-languages.d.ts +104 -0
  51. package/dist/operations/proof/code-languages.d.ts.map +1 -0
  52. package/dist/operations/proof/code-languages.js +119 -0
  53. package/dist/operations/proof/code-models.d.ts +2 -0
  54. package/dist/operations/proof/code-models.d.ts.map +1 -1
  55. package/dist/operations/proof/code-models.js +11 -5
  56. package/dist/operations/proof/code-runner.d.ts +12 -9
  57. package/dist/operations/proof/code-runner.d.ts.map +1 -1
  58. package/dist/operations/proof/code-runner.js +81 -38
  59. package/dist/operations/proof/code-scope.d.ts +8 -0
  60. package/dist/operations/proof/code-scope.d.ts.map +1 -1
  61. package/dist/operations/proof/code-scope.js +30 -1
  62. package/dist/operations/proof/explain.d.ts +13 -0
  63. package/dist/operations/proof/explain.d.ts.map +1 -1
  64. package/dist/operations/proof/explain.js +66 -0
  65. package/dist/operations/proof/ingest-proof.d.ts +2 -0
  66. package/dist/operations/proof/ingest-proof.d.ts.map +1 -1
  67. package/dist/operations/proof/ingest-proof.js +1 -0
  68. package/dist/operations/proof/java-package-shadow.d.ts +14 -0
  69. package/dist/operations/proof/java-package-shadow.d.ts.map +1 -0
  70. package/dist/operations/proof/java-package-shadow.js +389 -0
  71. package/dist/operations/proof/prolog-evaluator.d.ts +14 -0
  72. package/dist/operations/proof/prolog-evaluator.d.ts.map +1 -0
  73. package/dist/operations/proof/prolog-evaluator.js +247 -0
  74. package/dist/operations/proof/prolog-source-reader.d.ts +20 -0
  75. package/dist/operations/proof/prolog-source-reader.d.ts.map +1 -0
  76. package/dist/operations/proof/prolog-source-reader.js +1123 -0
  77. package/dist/operations/proof/source-code-readers.d.ts +6 -0
  78. package/dist/operations/proof/source-code-readers.d.ts.map +1 -1
  79. package/dist/operations/proof/source-code-readers.js +879 -75
  80. package/dist/plugins/approved-source-analyzers.generated.d.ts +13 -35
  81. package/dist/plugins/approved-source-analyzers.generated.d.ts.map +1 -1
  82. package/dist/plugins/approved-source-analyzers.generated.js +13 -35
  83. package/dist/plugins/plugin-install-check.d.ts +21 -0
  84. package/dist/plugins/plugin-install-check.d.ts.map +1 -0
  85. package/dist/plugins/plugin-install-check.js +62 -0
  86. package/dist/plugins/proof-reference-extractors.d.ts +20 -0
  87. package/dist/plugins/proof-reference-extractors.d.ts.map +1 -0
  88. package/dist/plugins/proof-reference-extractors.js +104 -0
  89. package/dist/plugins/reference-language-suggestion.d.ts +51 -0
  90. package/dist/plugins/reference-language-suggestion.d.ts.map +1 -0
  91. package/dist/plugins/reference-language-suggestion.js +277 -0
  92. package/dist/plugins/registry.d.ts.map +1 -1
  93. package/dist/plugins/registry.js +3 -1
  94. package/dist/plugins/source-analysis-service.d.ts.map +1 -1
  95. package/dist/plugins/source-analysis-service.js +4 -0
  96. package/dist/plugins/source-change-analysis.d.ts +26 -1
  97. package/dist/plugins/source-change-analysis.d.ts.map +1 -1
  98. package/dist/plugins/source-change-analysis.js +77 -5
  99. package/dist/plugins/source-classification.d.ts.map +1 -1
  100. package/dist/plugins/source-classification.js +23 -3
  101. package/dist/public/operations/catalog.d.ts +32 -7
  102. package/dist/public/operations/catalog.d.ts.map +1 -1
  103. package/dist/public/operations/check-executor.d.ts.map +1 -1
  104. package/dist/public/operations/check-executor.js +3 -0
  105. package/dist/public/operations/evidence-floor.d.ts +8 -0
  106. package/dist/public/operations/evidence-floor.d.ts.map +1 -1
  107. package/dist/public/operations/evidence-floor.js +19 -1
  108. package/dist/public/operations/specs/check-rules.generated.d.ts +1 -1
  109. package/dist/public/operations/specs/check-rules.generated.d.ts.map +1 -1
  110. package/dist/public/operations/specs/check-rules.generated.js +2 -1
  111. package/dist/public/operations/specs/check.d.ts +1 -1
  112. package/dist/public/operations/specs/mutation-schemas.d.ts +31 -6
  113. package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
  114. package/dist/public/operations/specs/reporting.d.ts +8 -0
  115. package/dist/public/operations/specs/reporting.d.ts.map +1 -1
  116. package/dist/public/operations/specs/reporting.js +26 -3
  117. package/dist/public/operations/specs/semantic.d.ts.map +1 -1
  118. package/dist/public/operations/specs/semantic.js +2 -1
  119. package/dist/public/operations/specs/upsert.d.ts +31 -6
  120. package/dist/public/operations/specs/upsert.d.ts.map +1 -1
  121. package/dist/public/operations/symbol-coordinates-check.d.ts +11 -0
  122. package/dist/public/operations/symbol-coordinates-check.d.ts.map +1 -0
  123. package/dist/public/operations/symbol-coordinates-check.js +66 -0
  124. package/dist/public/proof-protocol.d.ts +31 -6
  125. package/dist/public/proof-protocol.d.ts.map +1 -1
  126. package/dist/public/proof-protocol.js +45 -15
  127. package/dist/public/proof-sources.d.ts +4 -2
  128. package/dist/public/proof-sources.d.ts.map +1 -1
  129. package/dist/public/proof-sources.js +43 -4
  130. package/dist/public/skills/kibi-usage/SKILL.md +6 -3
  131. package/dist/public/skills/kibi-usage/resources/prolog-proofs.md +207 -0
  132. package/dist/public/skills/kibi-usage/resources/proof.md +44 -3
  133. package/dist/schemas/entity.schema.json +34 -6
  134. package/dist/traceability/analysis-gate.d.ts +3 -1
  135. package/dist/traceability/analysis-gate.d.ts.map +1 -1
  136. package/dist/traceability/analysis-gate.js +9 -1
  137. package/dist/traceability/staged-file-coverage.d.ts.map +1 -1
  138. package/dist/traceability/staged-file-coverage.js +7 -2
  139. package/dist/traceability/symbol-extract.d.ts +17 -0
  140. package/dist/traceability/symbol-extract.d.ts.map +1 -1
  141. package/dist/traceability/symbol-extract.js +69 -15
  142. package/dist/traceability/validate.d.ts.map +1 -1
  143. package/dist/traceability/validate.js +5 -7
  144. package/dist/utils/first-sentence.d.ts +9 -0
  145. package/dist/utils/first-sentence.d.ts.map +1 -0
  146. package/dist/utils/first-sentence.js +52 -0
  147. package/dist/utils/rule-registry.generated.d.ts +6 -0
  148. package/dist/utils/rule-registry.generated.d.ts.map +1 -1
  149. package/dist/utils/rule-registry.generated.js +7 -0
  150. package/package.json +5 -5
  151. package/src/public/operations/check-executor.ts +8 -0
  152. package/src/public/operations/evidence-floor.ts +29 -1
  153. package/src/public/operations/specs/check-rules.generated.ts +2 -1
  154. package/src/public/operations/specs/reporting.ts +38 -3
  155. package/src/public/operations/specs/semantic.ts +2 -1
  156. package/src/public/operations/symbol-coordinates-check.ts +79 -0
  157. package/src/public/proof-protocol-types.d.ts +22 -5
  158. package/src/public/proof-protocol.ts +78 -19
  159. package/src/public/proof-sources.ts +51 -3
  160. package/src/public/skills/kibi-usage/SKILL.md +6 -3
  161. package/src/public/skills/kibi-usage/resources/prolog-proofs.md +207 -0
  162. package/src/public/skills/kibi-usage/resources/proof.md +44 -3
  163. package/src/schemas/entity.schema.json +34 -6
@@ -21,8 +21,9 @@
21
21
  * JSON or YAML file, the files a glob matches, an OpenAPI document, the
22
22
  * references the code makes (environment variables, imports, calls, string
23
23
  * arguments, thrown error codes, property values), a data schema (drizzle,
24
- * Prisma or SQL migrations), a web app's route table (Hono, Express) and a
25
- * validator object (zod and anything with safeParse).
24
+ * Prisma or SQL migrations), a web app's route table (Hono, Express), a
25
+ * validator object (zod and anything with safeParse) and the facts of a
26
+ * SWI-Prolog file (a pack's requires/1).
26
27
  *
27
28
  * Every reader is exact or refuses: a member Kibi cannot read statically (a
28
29
  * computed environment variable name, a dynamic import, an ALTER TABLE form
@@ -44,6 +45,7 @@ export const SOURCE_READERS = [
44
45
  "schema",
45
46
  "routes",
46
47
  "validator",
48
+ "prolog",
47
49
  ];
48
50
  const SELECTS = {
49
51
  json: ["keys", "values", "items"],
@@ -89,6 +91,7 @@ const KEYS = {
89
91
  "select",
90
92
  ],
91
93
  validator: ["reader", "file", "export", "select"],
94
+ prolog: ["reader", "file", "functor", "arg"],
92
95
  };
93
96
  function record(value) {
94
97
  return value !== null && typeof value === "object" && !Array.isArray(value)
@@ -221,6 +224,15 @@ export function sourceSpecErrors(value, label) {
221
224
  if (!nonEmpty(row.export))
222
225
  errors.push(`${label}.export is required for reader validator: name the object schema`);
223
226
  break;
227
+ case "prolog":
228
+ file("file", true);
229
+ if (typeof row.functor !== "string" ||
230
+ !/^[a-z][A-Za-z0-9_]*\/(?:0|[1-9][0-9]*)$/.test(row.functor))
231
+ errors.push(`${label}.functor is required for reader prolog: name the facts read as Name/Arity (requires/1)`);
232
+ if (row.arg !== undefined &&
233
+ !(Number.isInteger(row.arg) && row.arg >= 1))
234
+ errors.push(`${label}.arg must be the 1-based argument of each fact that holds the member`);
235
+ break;
224
236
  }
225
237
  return errors;
226
238
  }
@@ -245,14 +257,28 @@ function globList(value) {
245
257
  const DEFAULT_IGNORE = ["**/node_modules/**", "**/.git/**", "**/.kb/**"];
246
258
  /** Workspace-relative files a glob list matches, sorted. */
247
259
  // implements REQ-kibi-source-proof-kinds
248
- export function matchWorkspaceFiles(workspaceRoot, patterns, ignore = []) {
260
+ export function matchWorkspaceFiles(workspaceRoot, patterns, ignore = [], caseSensitive = true) {
261
+ // A symbolic link to a file is read as that file (git and compilers read
262
+ // it so); links to folders are not walked.
249
263
  return fg
250
264
  .sync([...patterns], {
251
265
  cwd: workspaceRoot,
252
266
  ignore: [...DEFAULT_IGNORE, ...ignore],
267
+ caseSensitiveMatch: caseSensitive,
253
268
  dot: true,
254
- onlyFiles: true,
269
+ onlyFiles: false,
270
+ markDirectories: true,
255
271
  followSymbolicLinks: false,
272
+ })
273
+ .filter((file) => {
274
+ if (file.endsWith("/"))
275
+ return false;
276
+ try {
277
+ return statSync(path.join(workspaceRoot, file)).isFile();
278
+ }
279
+ catch {
280
+ return false;
281
+ }
256
282
  })
257
283
  .map((file) => file.split(path.sep).join("/"))
258
284
  .sort();
@@ -323,6 +349,9 @@ export function sourceDependencies(workspaceRoot, spec) {
323
349
  for (const file of globList(spec.names_from))
324
350
  addFile(file);
325
351
  break;
352
+ case "prolog":
353
+ addFile(String(spec.file));
354
+ break;
326
355
  }
327
356
  if (spec.reader === "routes" ||
328
357
  spec.reader === "validator" ||
@@ -1275,6 +1304,14 @@ export async function readSource(workspaceRoot, spec, evaluate) {
1275
1304
  ok: true,
1276
1305
  model: { members: sortedUnique(evaluated.members ?? []) },
1277
1306
  };
1307
+ if (spec.reader === "prolog")
1308
+ return {
1309
+ ok: true,
1310
+ model: {
1311
+ members: sortedUnique(evaluated.members ?? []),
1312
+ sequence: evaluated.sequence ?? [],
1313
+ },
1314
+ };
1278
1315
  if (spec.reader === "routes") {
1279
1316
  const routes = selectedRoutes(spec, evaluated.routes ?? []).sort((a, b) => `${a.path} ${a.method}` < `${b.path} ${b.method}` ? -1 : 1);
1280
1317
  if (typeof spec.path_prefix === "string" && routes.length === 0)
@@ -1306,6 +1343,8 @@ export function describeSource(spec) {
1306
1343
  return `routes of ${spec.export} in ${spec.file}${spec.path_prefix ? ` under ${spec.path_prefix}` : ""}`;
1307
1344
  case "validator":
1308
1345
  return `validator ${spec.export} in ${spec.file}`;
1346
+ case "prolog":
1347
+ return `${spec.functor} facts in ${spec.file}${spec.arg ? ` (argument ${spec.arg})` : ""}`;
1309
1348
  }
1310
1349
  }
1311
1350
  /** Unresolved references, as one rejection reason naming the first few. */
@@ -2,7 +2,7 @@
2
2
  id: kibi-usage
3
3
  name: Kibi Usage
4
4
  description: Use Kibi's source-first, exact-Git, migration-aware, proof-aware operations safely across MCP or the trusted local CLI, including partial completion repair.
5
- version: 2.37.0
5
+ version: 2.40.1
6
6
  kibiCompatibility: ">=1.0.0"
7
7
  tags:
8
8
  - kibi
@@ -20,6 +20,7 @@ resources:
20
20
  - resources/fact-lanes.md
21
21
  - resources/workflows.md
22
22
  - resources/proof.md
23
+ - resources/prolog-proofs.md
23
24
  - resources/ui-requirements.md
24
25
  - resources/logic-ir.md
25
26
  - resources/kb-improvement.md
@@ -94,8 +95,10 @@ it is a pointer to the knowledge, never proof. Each line answers one question:
94
95
  requirement first. Read the lead requirement with `kb_query({id})` before
95
96
  changing behavior; add `includeBody: true` to see its authored prose, and
96
97
  fix a stale sentence there with `kb_upsert` `document.body`.
97
- - `REQ-… must keep true: FACT-…` (edit only): the ground facts the lead
98
- requirement requires. An edit that breaks one of them is a requirement
98
+ - `REQ-… must keep true: <claim>` (edit only): what the lead requirement
99
+ requires, as the claims its facts model (with the operator and members,
100
+ such as "The greet function must not call console.log") or, without
101
+ them, its own statement. An edit that breaks one of them is a requirement
99
102
  change: ask before changing the rule (see Decision firmness), and never
100
103
  code around the fact.
101
104
  - `Decision: ADR-…` (edit only): the decision behind the lead requirement.
@@ -0,0 +1,207 @@
1
+ # SWI-Prolog Code Proofs
2
+
3
+ Kibi reads code models from SWI-Prolog files (`.pl`, `.plt`) with the
4
+ SWI-Prolog it runs on (KIBI_SWIPL, the bundled runtime, then `swipl` on
5
+ PATH). It loads the file a symbol names (a module, or a plain file into
6
+ `user`) and reads a predicate named by its indicator, the symbol's title
7
+ (`operator/2`, `lists:append/3`, `greeting//1`) or `export`.
8
+
9
+ - A domain (`exhaustive`, `domains`, `value_source` with `measure: count`)
10
+ is the distinct solutions of one argument. A one-argument predicate needs
11
+ nothing more; for more arguments set `arg` (1-based) to the one that names
12
+ each member: `domain_source: {symbol_id: SYM-operator, arg: 1}` lists every
13
+ `Name` of `operator(Name, Description)`. A solution that leaves that
14
+ argument unbound refuses the read.
15
+ - A value (`value_source`) is the single number a constant holds:
16
+ `hard_limit_seconds(10).` Zero or several solutions refuse the read.
17
+ - A `rule` predicate is called once per row of its argument domains; success
18
+ is true, failure false, an exception an error row (which rejects).
19
+ - A `state_machine` transition table is a `Name/2` (from, to) or `Name/3`
20
+ (from, event, to) fact table: every solution is an edge. With `domains:
21
+ {state, event}` a `Name/3` next-state predicate is called on every state
22
+ and event. `initial_source` names an `initial/1`-style fact.
23
+ - A `regex` reads an atom or string constant as a `type: string` pattern;
24
+ Kibi decides string facts on it. Patterns for `library(pcre)` are not read.
25
+
26
+ Loading a module runs its directives, the same trust a JavaScript import
27
+ gives. The proof file must name the predicate and load its file
28
+ (`use_module`, `ensure_loaded`, `consult`, a `:- [..]` load list, or
29
+ `library(X)` for a pack's `prolog/X.pl`), or be the plunit `.plt` file
30
+ beside it; otherwise Kibi treats the domain as hand-listed. `arg` on a
31
+ TypeScript, JavaScript or Python export is refused, and so is `field` on a
32
+ Prolog predicate.
33
+
34
+ ## Writing the certificate
35
+
36
+ A Prolog test writes the `kibi.code-certificate.v1` JSON into the directory
37
+ `kibi prove` sets in `KIBI_PROOF_CERTIFICATES`. Copy this module into the
38
+ project's test directory (for example `test/kibi_certificate.pl`) and call it
39
+ from the proof. Read members from the code with `findall/3` over the domain
40
+ predicate; never list them by hand.
41
+
42
+ ```prolog
43
+ :- module(kibi_certificate,
44
+ [ kibi_exhaustive_certificate/5, % +TestId, +SymbolId, +Members, :Check, -Certificate
45
+ kibi_rule_certificate/4, % +TestId, +Domains, +Predicates, -Certificate
46
+ kibi_machine_certificate/5, % +TestId, +SymbolId, +Edges, +Initial, -Certificate
47
+ kibi_pattern_certificate/4, % +TestId, +SymbolId, +Text, -Certificate
48
+ kibi_write_certificate/1 % +Certificate
49
+ ]).
50
+ :- use_module(library(http/json)).
51
+ :- use_module(library(apply)).
52
+ :- use_module(library(lists)).
53
+
54
+ :- meta_predicate
55
+ kibi_exhaustive_certificate(+, +, +, 1, -).
56
+
57
+ % Members as Kibi reads them: atoms and strings as text, numbers as written,
58
+ % other terms quoted.
59
+ kibi_text(Value, Text) :- string(Value), !, Text = Value.
60
+ kibi_text(Value, Text) :- atom(Value), !, atom_string(Value, Text).
61
+ kibi_text(Value, Text) :- number(Value), !, number_string(Value, Text).
62
+ kibi_text(Value, Text) :- format(string(Text), "~q", [Value]).
63
+
64
+ %! kibi_exhaustive_certificate(+TestId, +SymbolId, +Members, :Check, -Certificate)
65
+ %
66
+ % Run Check on every member of the domain and record each outcome. Read
67
+ % Members from the code (findall over the domain predicate), never list
68
+ % them by hand: Kibi re-reads the predicate and rejects a different set.
69
+ kibi_exhaustive_certificate(TestId, SymbolId, Members, Check, Certificate) :-
70
+ maplist(kibi_text, Members, Texts),
71
+ maplist(exhaustive_result(Check), Members, Texts, Results),
72
+ Certificate = _{version: "kibi.code-certificate.v1", kind: "exhaustive",
73
+ test_id: TestId,
74
+ domain: _{symbol_id: SymbolId, members: Texts},
75
+ results: Results}.
76
+
77
+ exhaustive_result(Check, Member, Text, Result) :-
78
+ catch(( call(Check, Member)
79
+ -> Result = _{member: Text, outcome: "passed"}
80
+ ; Result = _{member: Text, outcome: "failed", message: "the check failed"}
81
+ ),
82
+ Error,
83
+ ( message_to_text(Error, Message),
84
+ Result = _{member: Text, outcome: "failed", message: Message} )).
85
+
86
+ %! kibi_rule_certificate(+TestId, +Domains, +Predicates, -Certificate)
87
+ %
88
+ % Domains is a list of domain(Type, SymbolId, Members); Predicates a list
89
+ % of predicate(Name, SymbolId, ArgTypes, Goal), where Goal is called with
90
+ % one argument per type appended and decides the row by success or
91
+ % failure.
92
+ kibi_rule_certificate(TestId, Domains, Predicates, Certificate) :-
93
+ findall(Type-_{symbol_id: SymbolId, members: Texts},
94
+ ( member(domain(Type, SymbolId, Members), Domains), maplist(kibi_text, Members, Texts) ),
95
+ DomainPairs),
96
+ dict_pairs(DomainDict, _, DomainPairs),
97
+ findall(Name-_{symbol_id: SymbolId, arg_types: ArgTypes, rows: Rows},
98
+ ( member(predicate(Name, SymbolId, ArgTypes, Goal), Predicates),
99
+ maplist(domain_members(Domains), ArgTypes, Lists),
100
+ findall(Row, (maplist(member, Tuple, Lists), rule_row(Goal, Tuple, Row)), Rows)
101
+ ),
102
+ PredicatePairs),
103
+ dict_pairs(PredicateDict, _, PredicatePairs),
104
+ Certificate = _{version: "kibi.code-certificate.v1", kind: "rule",
105
+ test_id: TestId, domains: DomainDict, predicates: PredicateDict}.
106
+
107
+ domain_members(Domains, Type, Members) :-
108
+ memberchk(domain(Type, _, Members), Domains).
109
+
110
+ rule_row(Goal, Tuple, Row) :-
111
+ maplist(kibi_text, Tuple, Args),
112
+ Call =.. [call, Goal|Tuple],
113
+ catch(( once(Call) -> Row = _{args: Args, value: true} ; Row = _{args: Args, value: false} ),
114
+ Error,
115
+ ( message_to_text(Error, Message), Row = _{args: Args, error: Message} )).
116
+
117
+ %! kibi_machine_certificate(+TestId, +SymbolId, +Edges, +Initial, -Certificate)
118
+ %
119
+ % Edges is the list of From-To pairs of the transition table (findall over
120
+ % it); Initial is the list of initial states, or [] when the contract names
121
+ % no initial_source.
122
+ kibi_machine_certificate(TestId, SymbolId, Edges, Initial, Certificate) :-
123
+ findall([F, T], (member(From-To, Edges), kibi_text(From, F), kibi_text(To, T)), Pairs0),
124
+ sort(Pairs0, Pairs),
125
+ findall(S, (member([A, B], Pairs), member(S, [A, B])), Ends),
126
+ sort(Ends, States),
127
+ Machine0 = _{symbol_id: SymbolId, states: States, transitions: Pairs},
128
+ ( Initial == []
129
+ -> Machine = Machine0
130
+ ; maplist(kibi_text, Initial, InitialTexts0),
131
+ sort(InitialTexts0, InitialTexts),
132
+ Machine = Machine0.put(initial, InitialTexts)
133
+ ),
134
+ Certificate = _{version: "kibi.code-certificate.v1", kind: "state_machine",
135
+ test_id: TestId, machine: Machine}.
136
+
137
+ %! kibi_pattern_certificate(+TestId, +SymbolId, +Text, -Certificate)
138
+ %
139
+ % The string or atom constant a string claim is about.
140
+ kibi_pattern_certificate(TestId, SymbolId, Value, Certificate) :-
141
+ kibi_text(Value, Text),
142
+ Certificate = _{version: "kibi.code-certificate.v1", kind: "regex", test_id: TestId,
143
+ pattern: _{symbol_id: SymbolId, type: "string", value: Text}}.
144
+
145
+ %! kibi_write_certificate(+Certificate)
146
+ %
147
+ % Leave the certificate where kibi prove reads it (the directory in
148
+ % KIBI_PROOF_CERTIFICATES). Does nothing outside a kibi prove run.
149
+ kibi_write_certificate(Certificate) :-
150
+ ( getenv('KIBI_PROOF_CERTIFICATES', Directory), Directory \== ''
151
+ -> make_directory_path(Directory),
152
+ format(atom(Name), "~w.json", [Certificate.test_id]),
153
+ directory_file_path(Directory, Name, File),
154
+ setup_call_cleanup(open(File, write, Out, [encoding(utf8)]),
155
+ json_write_dict(Out, Certificate, [width(0)]),
156
+ close(Out))
157
+ ; true
158
+ ).
159
+
160
+ message_to_text(Error, Text) :-
161
+ catch(message_to_codes(Error, Text), _, fail), !.
162
+ message_to_text(Error, Text) :- format(string(Text), "~q", [Error]).
163
+
164
+ message_to_codes(Error, Text) :-
165
+ '$messages':translate_message(Error, Lines, []),
166
+ with_output_to(string(Raw), print_message_lines(current_output, '', Lines)),
167
+ split_string(Raw, "", "\n ", [Text]).
168
+ ```
169
+
170
+ A proof that the operators are exactly the claimed set:
171
+
172
+ ```prolog
173
+ :- use_module('../prolog/operators').
174
+ :- use_module(kibi_certificate).
175
+ :- initialization(main, main).
176
+
177
+ main :-
178
+ findall(Name, operator(Name, _), Names0),
179
+ list_to_set(Names0, Names),
180
+ kibi_exhaustive_certificate('TEST-operator-set', 'SYM-operator', Names,
181
+ [Name]>>operator(Name, _), Certificate),
182
+ kibi_write_certificate(Certificate).
183
+ ```
184
+
185
+ Its contract: `kind: exhaustive`, `domain_source: {symbol_id: SYM-operator,
186
+ arg: 1}`, `proves: [CLAIM-...]`. A rule proof passes
187
+ `[domain(status, 'SYM-status', Statuses)]` and
188
+ `[predicate(detected, 'SYM-detected', [status], detected)]`; its contract
189
+ names `predicate_source: {detected: {symbol_id: SYM-detected}}` and
190
+ `domains: {status: {symbol_id: SYM-status}}`.
191
+
192
+ ## Source proofs over Prolog code
193
+
194
+ A `source` proof needs no certificate: Kibi reads the Prolog files itself,
195
+ term by term, and never runs them. Use the `references` reader on `.pl` and
196
+ `.plt` files for what modules load (`extract: imports`, members as written:
197
+ `library(lists)`, `helpers`), call (`calls`, `Name/Arity` or
198
+ `Module:Name/Arity`), read from the environment (`env`, `getenv/2`), pass as
199
+ a first argument (`string_args` with `callee`) and throw (`thrown`: the error
200
+ of `error(type_error(...), _)` is `type_error`). Use the `prolog` reader for
201
+ facts: `{reader: prolog, file: pack.pl, functor: requires/1}` lists a pack's
202
+ requirements, and `arg` picks the argument of a fact with several. A goal or
203
+ closure held in a variable (`call(Goal)`, `maplist(G, L)`), a goal with a
204
+ variable module, a clause asserted from a variable and `:- if(...)` fail the
205
+ read with their place: name the predicate instead. The claim cannot be
206
+ decided for a file the read refuses; never drop a file the claim is about
207
+ from `files`.
@@ -262,11 +262,15 @@ left:
262
262
  each list item, such as the `run` of each workflow step), `glob` (`pattern`, `capture`),
263
263
  `openapi` (`file`, `select: operations|unsecured_operations|...`),
264
264
  `references` (`files`, `extract: env|imports|calls|string_args|thrown|
265
- property`), `schema` (`format: drizzle|prisma|sql`, `select:
265
+ property`; TypeScript, JavaScript, Python and SWI-Prolog files, and Go,
266
+ Java, C# and Rust files through `kibi-plugin-treesitter`), `schema` (`format: drizzle|prisma|sql`, `select:
266
267
  tables|columns|required_columns|nullable_columns|foreign_keys`), `routes`
267
268
  (Hono or Express app export, `path_prefix`, `names_from`, `select:
268
269
  routes|middleware`) or `validator` (zod, valibot or pydantic, `select:
269
- fields|required_fields|optional_fields`). A member Kibi cannot read
270
+ fields|required_fields|optional_fields`) or `prolog` (`file`, `functor:
271
+ requires/1`, `arg`: one argument of each fact, such as a pack's
272
+ requirements in `pack.pl`). Prolog files are read term by term and never
273
+ run; see `resources/prolog-proofs.md`. A member Kibi cannot read
270
274
  statically (a computed env name, a dynamic import, an env object handed
271
275
  to a variable) fails the read with its location, and so does an empty
272
276
  read (a glob matching no file, migrations with no `CREATE TABLE`), so a
@@ -288,6 +292,40 @@ left:
288
292
  The builders need kibi-cli 2.33.0 or newer in the project. The env
289
293
  extractor reads `process.env`, `import.meta.env`, `Bun.env`,
290
294
  `Deno.env.get`, `os.environ` and `os.getenv`, through casts.
295
+ - `references` over Go, Java, C# or Rust needs `kibi-plugin-treesitter` and
296
+ the language's grammar pack (`kibi-lang-go`, `kibi-lang-java`,
297
+ `kibi-lang-csharp`, `kibi-lang-rust`) in `devDependencies`, with the
298
+ plugin activated for proofs:
299
+ `"kibi.reference-extractor.v1": { "mode": "augment" }` in its
300
+ `kibi.plugins` entry (next to `"kibi.symbol-extractor.v2"`). A project
301
+ with no `package.json` creates one that only holds this list. Without it
302
+ the read is refused with what to install, so ask the operator before
303
+ installing; `kibi doctor` names what the project needs. Members are
304
+ written as the code names them (`os.Getenv`, `System.out.println`,
305
+ `Console.WriteLine`, `std::env::var`, Go import paths, `java.util.*`,
306
+ `std::io::Write`); a method on an expression Kibi cannot name is
307
+ `*.name`. Reflection, a name computed at run time, the whole
308
+ environment, C# `dynamic` and `#if`, Rust `#[cfg(...)]` items other than
309
+ `#[cfg(test)]`, and any macro for Rust `calls` and `thrown` fail the
310
+ read with their place: the claim cannot be decided for that file, so
311
+ model a claim the code can show (Rust `calls` over a file with
312
+ `println!` is always refused). Never drop a file the claim is about
313
+ from `files`: the read decides a claim only for the files it covers,
314
+ and a proof is rejected when a symbol the test covers or that
315
+ implements the claim's requirement lies outside them.
316
+ - Reference members match by name segments (`.`, `/`, `::`). `excludes`
317
+ fails on anything that is or may be an excluded item: `java.sql`
318
+ excludes `java.sql.Connection`, `github.com/labstack/echo/v4` excludes
319
+ `.../echo/v4/middleware`, a trailing `*` is a prefix (`java.sql.*`), a
320
+ wildcard import or a shorter name (`File.delete`) may be the item, and
321
+ `*.delete` (a call on a receiver Kibi cannot name) may be
322
+ `java.io.File.delete`, so the claim is refused naming it. `includes` and
323
+ `subset_of` count only members that certainly are an item (the item, a
324
+ member under `X.*`, or `a.b.m` for `*.m`); `eq` compares spellings.
325
+ - For a claim about what the code reads from the environment use
326
+ `extract: env`: `string_args` on a getter (`os.Getenv`, `env::var`,
327
+ `System.getenv`, `getenv/2`, ...) sees only that getter, so Kibi refuses
328
+ it for `eq`, `subset_of` and `excludes`.
291
329
 
292
330
  `arithmetic` and `smt` from `constraint_source` alone prove that the
293
331
  knowledge base's facts entail the claim, not that code follows the facts:
@@ -318,7 +356,10 @@ read for a test that wants to assert on it), fail the test when it records a fai
318
356
  (`failedMembers`, `failedCalls`), and call `writeCodeCertificate`; it writes to the
319
357
  directory `kibi prove` sets in `KIBI_PROOF_CERTIFICATES` and does nothing
320
358
  elsewhere. A Python test writes the same `kibi.code-certificate.v1` JSON
321
- to that directory itself. Wire the KB: the proof file symbol is
359
+ to that directory itself. Kibi also reads SWI-Prolog domains, constants,
360
+ rule predicates, transition tables and string constants (`arg` picks a
361
+ predicate's argument); `resources/prolog-proofs.md` has the rules and a
362
+ certificate module to copy. Wire the KB: the proof file symbol is
322
363
  `executable_for` the test and named in `required_proofs`; the domain symbol
323
364
  (and every symbol a rule, machine or pattern contract names) `implements`
324
365
  the requirement and is `covered_by` the test; the test
@@ -833,7 +833,7 @@
833
833
  },
834
834
  "source": {
835
835
  "type": "object",
836
- "description": "source: the project source a source proof reads. A project source Kibi reads by itself. reader json or yaml: {file, path?, select?: keys|values|items}. glob: {pattern, capture?, ignore?} (capture true reads what each * matched). openapi: {file, select?: operations|unsecured_operations|security_schemes|responses}. references: {files, extract: env|imports|calls|string_args|thrown|property, callee?, key?, ignore?}. schema: {format: drizzle|prisma|sql, file (drizzle, prisma) or files (sql migrations), exports?, table?, select?: tables|columns|required_columns|nullable_columns|foreign_keys}. routes: {file, export, framework?: hono|express, path_prefix?, names_from?, select?: routes|middleware}. validator: {file, export, select?: fields|required_fields|optional_fields}. Paths are repository-relative. A member Kibi cannot read statically fails the read with its location.",
836
+ "description": "source: the project source a source proof reads. A project source Kibi reads by itself. reader json or yaml: {file, path?, select?: keys|values|items}. glob: {pattern, capture?, ignore?} (capture true reads what each * matched). openapi: {file, select?: operations|unsecured_operations|security_schemes|responses}. references: {files, extract: env|imports|calls|string_args|thrown|property, callee?, key?, ignore?} over TypeScript, JavaScript, Python and SWI-Prolog files. schema: {format: drizzle|prisma|sql, file (drizzle, prisma) or files (sql migrations), exports?, table?, select?: tables|columns|required_columns|nullable_columns|foreign_keys}. routes: {file, export, framework?: hono|express, path_prefix?, names_from?, select?: routes|middleware}. validator: {file, export, select?: fields|required_fields|optional_fields}. prolog: {file, functor: Name/Arity, arg?} reads one argument of every fact with that functor in a SWI-Prolog file (requires/1 in pack.pl), without running it. Paths are repository-relative. A member Kibi cannot read statically fails the read with its location.",
837
837
  "required": [
838
838
  "reader"
839
839
  ],
@@ -848,7 +848,8 @@
848
848
  "references",
849
849
  "schema",
850
850
  "routes",
851
- "validator"
851
+ "validator",
852
+ "prolog"
852
853
  ]
853
854
  }
854
855
  },
@@ -874,6 +875,11 @@
874
875
  "type": "string",
875
876
  "minLength": 1,
876
877
  "description": "exhaustive: when the export is a list of records, the field of each record that names a domain member (a catalog's name)."
878
+ },
879
+ "arg": {
880
+ "type": "integer",
881
+ "minimum": 1,
882
+ "description": "A SWI-Prolog predicate's argument (1-based) whose solutions Kibi reads, when the predicate takes more than one argument (operator/2 with arg 1 lists each operator's name)."
877
883
  }
878
884
  },
879
885
  "additionalProperties": false
@@ -917,9 +923,14 @@
917
923
  "type": "string",
918
924
  "minLength": 1
919
925
  },
926
+ "arg": {
927
+ "type": "integer",
928
+ "minimum": 1,
929
+ "description": "A SWI-Prolog predicate's argument (1-based) whose solutions Kibi reads, when the predicate takes more than one argument (operator/2 with arg 1 lists each operator's name)."
930
+ },
920
931
  "source": {
921
932
  "type": "object",
922
- "description": "A project source Kibi reads by itself. reader json or yaml: {file, path?, select?: keys|values|items}. glob: {pattern, capture?, ignore?} (capture true reads what each * matched). openapi: {file, select?: operations|unsecured_operations|security_schemes|responses}. references: {files, extract: env|imports|calls|string_args|thrown|property, callee?, key?, ignore?}. schema: {format: drizzle|prisma|sql, file (drizzle, prisma) or files (sql migrations), exports?, table?, select?: tables|columns|required_columns|nullable_columns|foreign_keys}. routes: {file, export, framework?: hono|express, path_prefix?, names_from?, select?: routes|middleware}. validator: {file, export, select?: fields|required_fields|optional_fields}. Paths are repository-relative. A member Kibi cannot read statically fails the read with its location.",
933
+ "description": "A project source Kibi reads by itself. reader json or yaml: {file, path?, select?: keys|values|items}. glob: {pattern, capture?, ignore?} (capture true reads what each * matched). openapi: {file, select?: operations|unsecured_operations|security_schemes|responses}. references: {files, extract: env|imports|calls|string_args|thrown|property, callee?, key?, ignore?} over TypeScript, JavaScript, Python and SWI-Prolog files. schema: {format: drizzle|prisma|sql, file (drizzle, prisma) or files (sql migrations), exports?, table?, select?: tables|columns|required_columns|nullable_columns|foreign_keys}. routes: {file, export, framework?: hono|express, path_prefix?, names_from?, select?: routes|middleware}. validator: {file, export, select?: fields|required_fields|optional_fields}. prolog: {file, functor: Name/Arity, arg?} reads one argument of every fact with that functor in a SWI-Prolog file (requires/1 in pack.pl), without running it. Paths are repository-relative. A member Kibi cannot read statically fails the read with its location.",
923
934
  "required": [
924
935
  "reader"
925
936
  ],
@@ -934,7 +945,8 @@
934
945
  "references",
935
946
  "schema",
936
947
  "routes",
937
- "validator"
948
+ "validator",
949
+ "prolog"
938
950
  ]
939
951
  }
940
952
  },
@@ -1003,6 +1015,11 @@
1003
1015
  "export": {
1004
1016
  "type": "string",
1005
1017
  "minLength": 1
1018
+ },
1019
+ "arg": {
1020
+ "type": "integer",
1021
+ "minimum": 1,
1022
+ "description": "A SWI-Prolog predicate's argument (1-based) whose solutions Kibi reads, when the predicate takes more than one argument (operator/2 with arg 1 lists each operator's name)."
1006
1023
  }
1007
1024
  },
1008
1025
  "additionalProperties": false
@@ -1015,7 +1032,7 @@
1015
1032
  "properties": {
1016
1033
  "source": {
1017
1034
  "type": "object",
1018
- "description": "A project source Kibi reads by itself. reader json or yaml: {file, path?, select?: keys|values|items}. glob: {pattern, capture?, ignore?} (capture true reads what each * matched). openapi: {file, select?: operations|unsecured_operations|security_schemes|responses}. references: {files, extract: env|imports|calls|string_args|thrown|property, callee?, key?, ignore?}. schema: {format: drizzle|prisma|sql, file (drizzle, prisma) or files (sql migrations), exports?, table?, select?: tables|columns|required_columns|nullable_columns|foreign_keys}. routes: {file, export, framework?: hono|express, path_prefix?, names_from?, select?: routes|middleware}. validator: {file, export, select?: fields|required_fields|optional_fields}. Paths are repository-relative. A member Kibi cannot read statically fails the read with its location.",
1035
+ "description": "A project source Kibi reads by itself. reader json or yaml: {file, path?, select?: keys|values|items}. glob: {pattern, capture?, ignore?} (capture true reads what each * matched). openapi: {file, select?: operations|unsecured_operations|security_schemes|responses}. references: {files, extract: env|imports|calls|string_args|thrown|property, callee?, key?, ignore?} over TypeScript, JavaScript, Python and SWI-Prolog files. schema: {format: drizzle|prisma|sql, file (drizzle, prisma) or files (sql migrations), exports?, table?, select?: tables|columns|required_columns|nullable_columns|foreign_keys}. routes: {file, export, framework?: hono|express, path_prefix?, names_from?, select?: routes|middleware}. validator: {file, export, select?: fields|required_fields|optional_fields}. prolog: {file, functor: Name/Arity, arg?} reads one argument of every fact with that functor in a SWI-Prolog file (requires/1 in pack.pl), without running it. Paths are repository-relative. A member Kibi cannot read statically fails the read with its location.",
1019
1036
  "required": [
1020
1037
  "reader"
1021
1038
  ],
@@ -1030,7 +1047,8 @@
1030
1047
  "references",
1031
1048
  "schema",
1032
1049
  "routes",
1033
- "validator"
1050
+ "validator",
1051
+ "prolog"
1034
1052
  ]
1035
1053
  }
1036
1054
  },
@@ -1055,6 +1073,11 @@
1055
1073
  "export": {
1056
1074
  "type": "string",
1057
1075
  "minLength": 1
1076
+ },
1077
+ "arg": {
1078
+ "type": "integer",
1079
+ "minimum": 1,
1080
+ "description": "A SWI-Prolog predicate's argument (1-based) whose solutions Kibi reads, when the predicate takes more than one argument (operator/2 with arg 1 lists each operator's name)."
1058
1081
  }
1059
1082
  },
1060
1083
  "additionalProperties": false,
@@ -1073,6 +1096,11 @@
1073
1096
  "export": {
1074
1097
  "type": "string",
1075
1098
  "minLength": 1
1099
+ },
1100
+ "arg": {
1101
+ "type": "integer",
1102
+ "minimum": 1,
1103
+ "description": "A SWI-Prolog predicate's argument (1-based) whose solutions Kibi reads, when the predicate takes more than one argument (operator/2 with arg 1 lists each operator's name)."
1076
1104
  }
1077
1105
  },
1078
1106
  "additionalProperties": false,
@@ -32,7 +32,9 @@ type AnalysisObligation<Range extends LineRange> = Readonly<{
32
32
  * - A local gap (a macro, decorator or other declared limitation) matters only
33
33
  * where it overlaps the changed lines; elsewhere the file was already in that
34
34
  * state and this change did not touch it.
35
- * - Unsupported after-side analysis needs one whole-file review.
35
+ * - Unsupported after-side analysis needs one whole-file review, unless the
36
+ * project lists the grammar plugin and only its kibi-lang pack is missing or
37
+ * another version: that blocks, so a missing install never disarms the gate.
36
38
  */
37
39
  export declare function analysisObligation<Range extends LineRange>(side: "before" | "after", analysis: GateAnalysis<Range> | null | undefined, newHunkRanges: readonly HunkRange[]): AnalysisObligation<Range>;
38
40
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"analysis-gate.d.ts","sourceRoot":"","sources":["../../src/traceability/analysis-gate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAUjD,KAAK,SAAS,GAAG,QAAQ,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAGlE,MAAM,MAAM,YAAY,CAAC,KAAK,SAAS,SAAS,IAAI,QAAQ,CAAC;IAC3D,MAAM,EAAE,IAAI,GAAG,SAAS,GAAG,aAAa,GAAG,QAAQ,CAAC;IACpD,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,eAAe,EAAE,SAAS,CAAC,KAAK,GAAG,QAAQ,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,EAAE,CAAC;CACpE,CAAC,CAAC;AAEH,gEAAgE;AAChE,KAAK,kBAAkB,CAAC,KAAK,SAAS,SAAS,IAC3C,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GAC1B,QAAQ,CAAC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,GAC7C,QAAQ,CAAC;IAAE,IAAI,EAAE,oBAAoB,CAAA;CAAE,CAAC,GACxC,QAAQ,CAAC;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAA;CAAE,CAAC,CAAC;AAuBnE;;;;;;;;;;;GAWG;AAEH,wBAAgB,kBAAkB,CAAC,KAAK,SAAS,SAAS,EACxD,IAAI,EAAE,QAAQ,GAAG,OAAO,EACxB,QAAQ,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,IAAI,GAAG,SAAS,EAChD,aAAa,EAAE,SAAS,SAAS,EAAE,GAClC,kBAAkB,CAAC,KAAK,CAAC,CAqB3B"}
1
+ {"version":3,"file":"analysis-gate.d.ts","sourceRoot":"","sources":["../../src/traceability/analysis-gate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAUjD,KAAK,SAAS,GAAG,QAAQ,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAGlE,MAAM,MAAM,YAAY,CAAC,KAAK,SAAS,SAAS,IAAI,QAAQ,CAAC;IAC3D,MAAM,EAAE,IAAI,GAAG,SAAS,GAAG,aAAa,GAAG,QAAQ,CAAC;IACpD,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,eAAe,EAAE,SAAS,CAAC,KAAK,GAAG,QAAQ,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,EAAE,CAAC;CACpE,CAAC,CAAC;AAEH,gEAAgE;AAChE,KAAK,kBAAkB,CAAC,KAAK,SAAS,SAAS,IAC3C,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GAC1B,QAAQ,CAAC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,GAC7C,QAAQ,CAAC;IAAE,IAAI,EAAE,oBAAoB,CAAA;CAAE,CAAC,GACxC,QAAQ,CAAC;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAA;CAAE,CAAC,CAAC;AAuBnE;;;;;;;;;;;;;GAaG;AAEH,wBAAgB,kBAAkB,CAAC,KAAK,SAAS,SAAS,EACxD,IAAI,EAAE,QAAQ,GAAG,OAAO,EACxB,QAAQ,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,IAAI,GAAG,SAAS,EAChD,aAAa,EAAE,SAAS,SAAS,EAAE,GAClC,kBAAkB,CAAC,KAAK,CAAC,CAgC3B"}
@@ -24,7 +24,9 @@ function rangesTouchingHunks(ranges, hunks) {
24
24
  * - A local gap (a macro, decorator or other declared limitation) matters only
25
25
  * where it overlaps the changed lines; elsewhere the file was already in that
26
26
  * state and this change did not touch it.
27
- * - Unsupported after-side analysis needs one whole-file review.
27
+ * - Unsupported after-side analysis needs one whole-file review, unless the
28
+ * project lists the grammar plugin and only its kibi-lang pack is missing or
29
+ * another version: that blocks, so a missing install never disarms the gate.
28
30
  */
29
31
  // implements REQ-source-analysis-v2
30
32
  export function analysisObligation(side, analysis, newHunkRanges) {
@@ -32,6 +34,12 @@ export function analysisObligation(side, analysis, newHunkRanges) {
32
34
  return { kind: "none" };
33
35
  if (analysis.status === "failed")
34
36
  return { kind: "blocked", reason: "source analysis failed" };
37
+ if (analysis.status === "unsupported" &&
38
+ analysis.diagnosticCodes.some((code) => code.startsWith("TREESITTER_LANGUAGE_PACK_")))
39
+ return {
40
+ kind: "blocked",
41
+ reason: "the kibi-lang grammar pack for this file is not installed at the version kibi-plugin-treesitter pins; kibi doctor gives the install line",
42
+ };
35
43
  if (analysis.status === "unsupported")
36
44
  return { kind: "unsupported_review" };
37
45
  if (analysis.uncoveredRanges.length === 0)
@@ -1 +1 @@
1
- {"version":3,"file":"staged-file-coverage.d.ts","sourceRoot":"","sources":["../../src/traceability/staged-file-coverage.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,eAAO,MAAM,mCAAmC,EAC9C,8BAAuC,CAAC;AAE1C,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC7B,aAAa,EAAE,UAAU,CAAC,eAAe,CAAC,CAAC;IAC3C,WAAW,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC;IACvC,MAAM,CAAC,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC;IAClC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,CAAC,EAAE;QACf,MAAM,EAAE;YACN,MAAM,EAAE,MAAM,CAAC;YACf,QAAQ,EAAE,MAAM,CAAC;YACjB,WAAW,EAAE,MAAM,CAAC;YACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;YAC1B,gBAAgB,EAAE,MAAM,CAAC;YACzB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;SACpC,GAAG,IAAI,CAAC;QACT,KAAK,EAAE;YACL,MAAM,EAAE,MAAM,CAAC;YACf,QAAQ,EAAE,MAAM,CAAC;YACjB,WAAW,EAAE,MAAM,CAAC;YACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;YAC1B,gBAAgB,EAAE,MAAM,CAAC;YACzB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;SACpC,GAAG,IAAI,CAAC;KACV,CAAC;CACH;AAED,MAAM,WAAW,4BAA4B;IAC3C,EAAE,EAAE,+BAA+B,GAAG,kCAAkC,CAAC;IACzE,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,EAAE,KAAK,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,mCAAmC,CAAC;IACpD,QAAQ,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC7E,KAAK,EAAE,wBAAwB,EAAE,CAAC;IAClC,WAAW,EAAE,4BAA4B,EAAE,CAAC;CAC7C;AAGD,KAAK,SAAS,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,MAAM,CAAC;AA+OrD,2FAA2F;AAC3F,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,SAAS,UAAU,EAAE,EAChC,MAAM,GAAE,SAA4B,GACnC,wBAAwB,CA0G1B"}
1
+ {"version":3,"file":"staged-file-coverage.d.ts","sourceRoot":"","sources":["../../src/traceability/staged-file-coverage.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,eAAO,MAAM,mCAAmC,EAC9C,8BAAuC,CAAC;AAE1C,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC7B,aAAa,EAAE,UAAU,CAAC,eAAe,CAAC,CAAC;IAC3C,WAAW,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC;IACvC,MAAM,CAAC,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC;IAClC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,CAAC,EAAE;QACf,MAAM,EAAE;YACN,MAAM,EAAE,MAAM,CAAC;YACf,QAAQ,EAAE,MAAM,CAAC;YACjB,WAAW,EAAE,MAAM,CAAC;YACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;YAC1B,gBAAgB,EAAE,MAAM,CAAC;YACzB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;SACpC,GAAG,IAAI,CAAC;QACT,KAAK,EAAE;YACL,MAAM,EAAE,MAAM,CAAC;YACf,QAAQ,EAAE,MAAM,CAAC;YACjB,WAAW,EAAE,MAAM,CAAC;YACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;YAC1B,gBAAgB,EAAE,MAAM,CAAC;YACzB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;SACpC,GAAG,IAAI,CAAC;KACV,CAAC;CACH;AAED,MAAM,WAAW,4BAA4B;IAC3C,EAAE,EAAE,+BAA+B,GAAG,kCAAkC,CAAC;IACzE,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,EAAE,KAAK,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,mCAAmC,CAAC;IACpD,QAAQ,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC7E,KAAK,EAAE,wBAAwB,EAAE,CAAC;IAClC,WAAW,EAAE,4BAA4B,EAAE,CAAC;CAC7C;AAGD,KAAK,SAAS,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,MAAM,CAAC;AAmPrD,2FAA2F;AAC3F,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,SAAS,UAAU,EAAE,EAChC,MAAM,GAAE,SAA4B,GACnC,wBAAwB,CA6G1B"}
@@ -2,7 +2,7 @@ import { execFileSync } from "node:child_process";
2
2
  import { load as parseYaml } from "js-yaml";
3
3
  import { extractFromManifestString } from "../extractors/manifest.js";
4
4
  import { extractFromMarkdownString } from "../extractors/markdown.js";
5
- import { CANONICAL_ENTITY_PATHS, isEntityLanePath } from "../utils/kb-paths.js";
5
+ import { CANONICAL_ENTITY_PATHS, KB_ROOT, isEntityLanePath, } from "../utils/kb-paths.js";
6
6
  export const STAGED_FILE_COVERAGE_RESULT_VERSION = "kibi.staged-file-coverage.v1";
7
7
  function defaultGitReader(args) {
8
8
  return execFileSync("git", args, {
@@ -136,6 +136,9 @@ function stagedManifestContent(inventory) {
136
136
  return undefined;
137
137
  return file.status === "D" ? null : (file.content ?? null);
138
138
  }
139
+ function isKibiManagedPath(path) {
140
+ return path.replaceAll("\\", "/").startsWith(`${KB_ROOT}/`);
141
+ }
139
142
  function sourcePaths(entry) {
140
143
  return new Set([entry.path, ...(entry.oldPath ? [entry.oldPath] : [])]);
141
144
  }
@@ -253,7 +256,9 @@ export function analyzeStagedFileCoverage(inventory, reader = defaultGitReader)
253
256
  evidencePaths,
254
257
  providerId: entry.analysisDepth === "symbol" ? "ts-morph" : null,
255
258
  });
256
- if (entry.analysisDepth !== "file")
259
+ // Kibi writes everything under .kb/ (schema, manifest, entities); it is
260
+ // knowledge, not product code, so it needs no requirement ownership.
261
+ if (entry.analysisDepth !== "file" || isKibiManagedPath(entry.path))
257
262
  continue;
258
263
  if (requirementIds.length === 0) {
259
264
  diagnostics.push({
@@ -45,5 +45,22 @@ export declare function extractSymbolsFromStagedFile(stagedFile: StagedFile, man
45
45
  export declare function extractSymbolsFromStagedFileAsync(stagedFile: StagedFile, manifestLookup: ManifestLookup | undefined, options: ExtractSymbolsOptions & Readonly<{
46
46
  registry?: import("../plugins/registry.js").CapabilityRegistry;
47
47
  }>): Promise<ExtractedSymbol[]>;
48
+ type HunkLineRange = {
49
+ startLine: number;
50
+ endLine: number;
51
+ };
52
+ /**
53
+ * Whether a partial result still places its declarations: every gap is local
54
+ * (no parser, timeout or integrity finding) and no output cap hid symbols.
55
+ */
56
+ export declare function partialAnalysisSymbolsUsable(analysis: {
57
+ status?: string;
58
+ diagnostics?: readonly {
59
+ code: string;
60
+ }[];
61
+ uncoveredRanges?: readonly (HunkLineRange & {
62
+ reason: string;
63
+ })[];
64
+ }): boolean;
48
65
  export { isPrivateClassMember };
49
66
  //# sourceMappingURL=symbol-extract.d.ts.map