kibi-cli 2.31.0 → 2.32.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 (226) hide show
  1. package/dist/cli-register-proof.d.ts.map +1 -1
  2. package/dist/cli-register-proof.js +19 -7
  3. package/dist/cli-register-reporting.d.ts.map +1 -1
  4. package/dist/cli-register-reporting.js +2 -0
  5. package/dist/commands/check.d.ts +1 -0
  6. package/dist/commands/check.d.ts.map +1 -1
  7. package/dist/commands/check.js +14 -5
  8. package/dist/commands/discovery-table.d.ts.map +1 -1
  9. package/dist/commands/discovery-table.js +51 -4
  10. package/dist/commands/doctor.js +19 -4
  11. package/dist/commands/migrate.d.ts.map +1 -1
  12. package/dist/commands/migrate.js +89 -3
  13. package/dist/commands/prove.d.ts +48 -1
  14. package/dist/commands/prove.d.ts.map +1 -1
  15. package/dist/commands/prove.js +293 -8
  16. package/dist/commands/report.d.ts +1 -0
  17. package/dist/commands/report.d.ts.map +1 -1
  18. package/dist/commands/report.js +70 -5
  19. package/dist/commands/signoff.d.ts.map +1 -1
  20. package/dist/commands/signoff.js +21 -2
  21. package/dist/commands/sync/manifest.d.ts.map +1 -1
  22. package/dist/commands/sync/manifest.js +20 -4
  23. package/dist/commands/sync/persistence.d.ts.map +1 -1
  24. package/dist/commands/sync/persistence.js +16 -5
  25. package/dist/diagnostics.js +1 -1
  26. package/dist/engine.js +1 -1
  27. package/dist/extractors/markdown.d.ts +3 -1
  28. package/dist/extractors/markdown.d.ts.map +1 -1
  29. package/dist/extractors/markdown.js +17 -0
  30. package/dist/operations/bootstrap/candidate-helpers.d.ts +3 -0
  31. package/dist/operations/bootstrap/candidate-helpers.d.ts.map +1 -1
  32. package/dist/operations/bootstrap/candidate-helpers.js +4 -0
  33. package/dist/operations/migration/evidence-floor.d.ts +41 -0
  34. package/dist/operations/migration/evidence-floor.d.ts.map +1 -0
  35. package/dist/operations/migration/evidence-floor.js +230 -0
  36. package/dist/operations/migration/proof-contract-claims.d.ts +59 -0
  37. package/dist/operations/migration/proof-contract-claims.d.ts.map +1 -0
  38. package/dist/operations/migration/proof-contract-claims.js +182 -0
  39. package/dist/operations/migration/schema6.d.ts +6 -0
  40. package/dist/operations/migration/schema6.d.ts.map +1 -1
  41. package/dist/operations/migration/schema6.js +94 -0
  42. package/dist/operations/mutation/omitted-properties.d.ts +11 -0
  43. package/dist/operations/mutation/omitted-properties.d.ts.map +1 -0
  44. package/dist/operations/mutation/omitted-properties.js +76 -0
  45. package/dist/operations/mutation/serialization.d.ts.map +1 -1
  46. package/dist/operations/mutation/serialization.js +1 -0
  47. package/dist/operations/mutation/strict-fact.d.ts.map +1 -1
  48. package/dist/operations/mutation/strict-fact.js +6 -2
  49. package/dist/operations/mutation/symbol-granularity.d.ts.map +1 -1
  50. package/dist/operations/mutation/symbol-granularity.js +5 -3
  51. package/dist/operations/mutation/upsert.d.ts.map +1 -1
  52. package/dist/operations/mutation/upsert.js +7 -1
  53. package/dist/operations/mutation/validation.d.ts +2 -0
  54. package/dist/operations/mutation/validation.d.ts.map +1 -1
  55. package/dist/operations/mutation/validation.js +4 -0
  56. package/dist/operations/proof/claim-bindings.d.ts +23 -0
  57. package/dist/operations/proof/claim-bindings.d.ts.map +1 -0
  58. package/dist/operations/proof/claim-bindings.js +211 -0
  59. package/dist/operations/proof/code-certificates.d.ts +135 -0
  60. package/dist/operations/proof/code-certificates.d.ts.map +1 -0
  61. package/dist/operations/proof/code-certificates.js +785 -0
  62. package/dist/operations/proof/code-scope.d.ts +11 -1
  63. package/dist/operations/proof/code-scope.d.ts.map +1 -1
  64. package/dist/operations/proof/code-scope.js +20 -2
  65. package/dist/operations/proof/compact-receipts.d.ts.map +1 -1
  66. package/dist/operations/proof/compact-receipts.js +4 -3
  67. package/dist/operations/proof/explain.d.ts +32 -0
  68. package/dist/operations/proof/explain.d.ts.map +1 -1
  69. package/dist/operations/proof/explain.js +91 -0
  70. package/dist/operations/proof/ingest-proof.d.ts +9 -1
  71. package/dist/operations/proof/ingest-proof.d.ts.map +1 -1
  72. package/dist/operations/proof/ingest-proof.js +41 -2
  73. package/dist/operations/proof/receipt-compaction.d.ts +2 -0
  74. package/dist/operations/proof/receipt-compaction.d.ts.map +1 -1
  75. package/dist/operations/proof/receipt-compaction.js +6 -2
  76. package/dist/operations/semantic-advisor/shared.d.ts.map +1 -1
  77. package/dist/operations/semantic-advisor/shared.js +4 -0
  78. package/dist/operations/semantic-advisor/strict-rules.js +3 -3
  79. package/dist/operations/semantic-advisor/types.d.ts +2 -1
  80. package/dist/operations/semantic-advisor/types.d.ts.map +1 -1
  81. package/dist/plugins/approved-source-analyzers.generated.d.ts +6 -6
  82. package/dist/plugins/approved-source-analyzers.generated.js +6 -6
  83. package/dist/proof/command-test-report.d.ts +4 -3
  84. package/dist/proof/command-test-report.d.ts.map +1 -1
  85. package/dist/proof/command-test-report.js +4 -10
  86. package/dist/proof/evaluate.d.ts.map +1 -1
  87. package/dist/proof/evaluate.js +18 -2
  88. package/dist/proof/inspect.d.ts.map +1 -1
  89. package/dist/proof/inspect.js +58 -0
  90. package/dist/proof/producers/playwright-reporter.d.ts +3 -0
  91. package/dist/proof/producers/playwright-reporter.d.ts.map +1 -1
  92. package/dist/proof/producers/playwright-reporter.js +25 -2
  93. package/dist/proof/step-runner.d.ts +36 -0
  94. package/dist/proof/step-runner.d.ts.map +1 -0
  95. package/dist/proof/step-runner.js +234 -0
  96. package/dist/public/evidence-levels.d.ts +12 -0
  97. package/dist/public/evidence-levels.d.ts.map +1 -0
  98. package/dist/public/evidence-levels.js +19 -0
  99. package/dist/public/impact/coverage-depth-quality.d.ts +7 -0
  100. package/dist/public/impact/coverage-depth-quality.d.ts.map +1 -1
  101. package/dist/public/impact/coverage-depth-quality.js +59 -0
  102. package/dist/public/impact/full-kb-quality.d.ts.map +1 -1
  103. package/dist/public/impact/full-kb-quality.js +3 -1
  104. package/dist/public/operations/catalog.d.ts +167 -6
  105. package/dist/public/operations/catalog.d.ts.map +1 -1
  106. package/dist/public/operations/check-executor.d.ts +2 -0
  107. package/dist/public/operations/check-executor.d.ts.map +1 -1
  108. package/dist/public/operations/check-executor.js +6 -0
  109. package/dist/public/operations/evidence-floor.d.ts +48 -0
  110. package/dist/public/operations/evidence-floor.d.ts.map +1 -0
  111. package/dist/public/operations/evidence-floor.js +143 -0
  112. package/dist/public/operations/migration-plan.d.ts +19 -5
  113. package/dist/public/operations/migration-plan.d.ts.map +1 -1
  114. package/dist/public/operations/migration-plan.js +22 -5
  115. package/dist/public/operations/node-ports.d.ts.map +1 -1
  116. package/dist/public/operations/node-ports.js +4 -1
  117. package/dist/public/operations/proof-contract-claims.d.ts +26 -0
  118. package/dist/public/operations/proof-contract-claims.d.ts.map +1 -0
  119. package/dist/public/operations/proof-contract-claims.js +71 -0
  120. package/dist/public/operations/specs/check-rules.generated.d.ts +1 -1
  121. package/dist/public/operations/specs/check-rules.generated.d.ts.map +1 -1
  122. package/dist/public/operations/specs/check-rules.generated.js +3 -1
  123. package/dist/public/operations/specs/check.d.ts +1 -1
  124. package/dist/public/operations/specs/mutation-schemas.d.ts +157 -5
  125. package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
  126. package/dist/public/operations/specs/mutation-schemas.js +15 -2
  127. package/dist/public/operations/specs/proof.d.ts +9 -0
  128. package/dist/public/operations/specs/proof.d.ts.map +1 -1
  129. package/dist/public/operations/specs/reporting.d.ts.map +1 -1
  130. package/dist/public/operations/specs/reporting.js +19 -10
  131. package/dist/public/operations/specs/upsert.d.ts +157 -5
  132. package/dist/public/operations/specs/upsert.d.ts.map +1 -1
  133. package/dist/public/proof-certificates.d.ts +89 -0
  134. package/dist/public/proof-certificates.d.ts.map +1 -0
  135. package/dist/public/proof-certificates.js +207 -0
  136. package/dist/public/proof-protocol.d.ts +126 -3
  137. package/dist/public/proof-protocol.d.ts.map +1 -1
  138. package/dist/public/proof-protocol.js +239 -3
  139. package/dist/public/proof-receipt.d.ts +89 -6
  140. package/dist/public/proof-receipt.d.ts.map +1 -1
  141. package/dist/public/proof-receipt.js +83 -7
  142. package/dist/public/schemas/entity.d.ts.map +1 -1
  143. package/dist/public/schemas/entity.js +18 -1
  144. package/dist/public/skills/kibi-bootstrap/SKILL.md +2 -2
  145. package/dist/public/skills/kibi-commit-review/SKILL.md +4 -3
  146. package/dist/public/skills/kibi-commit-review/resources/staged-gate.md +6 -1
  147. package/dist/public/skills/kibi-decisions/SKILL.md +10 -2
  148. package/dist/public/skills/kibi-decisions/resources/decision-records.md +6 -1
  149. package/dist/public/skills/kibi-decisions/resources/signoff-views.md +3 -2
  150. package/dist/public/skills/kibi-freshness/SKILL.md +5 -1
  151. package/dist/public/skills/kibi-traceability/SKILL.md +11 -1
  152. package/dist/public/skills/kibi-usage/SKILL.md +6 -4
  153. package/dist/public/skills/kibi-usage/resources/proof.md +124 -19
  154. package/dist/public/skills/kibi-usage/resources/workflows.md +4 -4
  155. package/dist/report/html-report.css +38 -1
  156. package/dist/report/html-report.d.ts +8 -0
  157. package/dist/report/html-report.d.ts.map +1 -1
  158. package/dist/report/html-report.js +141 -6
  159. package/dist/report/report-view.d.ts +1 -1
  160. package/dist/report/report-view.d.ts.map +1 -1
  161. package/dist/report/report-view.js +7 -0
  162. package/dist/schemas/entity.schema.json +212 -4
  163. package/dist/search-answer.d.ts.map +1 -1
  164. package/dist/search-answer.js +1 -0
  165. package/dist/signoff/html.d.ts.map +1 -1
  166. package/dist/signoff/html.js +3 -0
  167. package/dist/signoff/markdown.d.ts.map +1 -1
  168. package/dist/signoff/markdown.js +3 -0
  169. package/dist/signoff/model.d.ts +20 -0
  170. package/dist/signoff/model.d.ts.map +1 -1
  171. package/dist/signoff/model.js +20 -1
  172. package/dist/traceability/impact-knowledge.d.ts.map +1 -1
  173. package/dist/traceability/impact-knowledge.js +1 -0
  174. package/dist/traceability/temp-kb.d.ts.map +1 -1
  175. package/dist/traceability/temp-kb.js +1 -0
  176. package/dist/types/entities.d.ts +4 -1
  177. package/dist/types/entities.d.ts.map +1 -1
  178. package/dist/utils/merge-driver-setup.d.ts +8 -1
  179. package/dist/utils/merge-driver-setup.d.ts.map +1 -1
  180. package/dist/utils/merge-driver-setup.js +23 -2
  181. package/dist/utils/rule-registry.generated.d.ts +10 -0
  182. package/dist/utils/rule-registry.generated.d.ts.map +1 -1
  183. package/dist/utils/rule-registry.generated.js +12 -0
  184. package/dist/utils/schema-version.d.ts +1 -1
  185. package/dist/utils/schema-version.d.ts.map +1 -1
  186. package/dist/utils/schema-version.js +5 -1
  187. package/package.json +6 -2
  188. package/schema/entities.pl +6 -0
  189. package/schema/validation.pl +4 -1
  190. package/src/public/evidence-levels.ts +23 -0
  191. package/src/public/impact/coverage-depth-quality.ts +73 -0
  192. package/src/public/impact/full-kb-quality.ts +6 -1
  193. package/src/public/operations/check-executor.ts +13 -0
  194. package/src/public/operations/evidence-floor.ts +203 -0
  195. package/src/public/operations/migration-plan.ts +39 -6
  196. package/src/public/operations/node-ports.ts +3 -1
  197. package/src/public/operations/proof-contract-claims.ts +103 -0
  198. package/src/public/operations/specs/check-rules.generated.ts +3 -1
  199. package/src/public/operations/specs/mutation-schemas.ts +17 -2
  200. package/src/public/operations/specs/reporting.ts +20 -10
  201. package/src/public/proof-certificates.ts +271 -0
  202. package/src/public/proof-protocol-types.d.ts +17 -1
  203. package/src/public/proof-protocol.ts +318 -3
  204. package/src/public/proof-receipt.ts +127 -7
  205. package/src/public/schemas/entity.ts +19 -1
  206. package/src/public/skills/kibi-bootstrap/SKILL.md +2 -2
  207. package/src/public/skills/kibi-commit-review/SKILL.md +4 -3
  208. package/src/public/skills/kibi-commit-review/resources/staged-gate.md +6 -1
  209. package/src/public/skills/kibi-decisions/SKILL.md +10 -2
  210. package/src/public/skills/kibi-decisions/resources/decision-records.md +6 -1
  211. package/src/public/skills/kibi-decisions/resources/signoff-views.md +3 -2
  212. package/src/public/skills/kibi-freshness/SKILL.md +5 -1
  213. package/src/public/skills/kibi-traceability/SKILL.md +11 -1
  214. package/src/public/skills/kibi-usage/SKILL.md +6 -4
  215. package/src/public/skills/kibi-usage/resources/proof.md +124 -19
  216. package/src/public/skills/kibi-usage/resources/workflows.md +4 -4
  217. package/src/schemas/entity.schema.json +212 -4
  218. package/dist/commands/proof-impact.d.ts +0 -7
  219. package/dist/commands/proof-impact.d.ts.map +0 -1
  220. package/dist/commands/proof-impact.js +0 -39
  221. package/dist/operations/proof/baseline-diff.d.ts +0 -41
  222. package/dist/operations/proof/baseline-diff.d.ts.map +0 -1
  223. package/dist/operations/proof/baseline-diff.js +0 -153
  224. package/dist/operations/proof/impact.d.ts +0 -51
  225. package/dist/operations/proof/impact.d.ts.map +0 -1
  226. package/dist/operations/proof/impact.js +0 -138
@@ -133,7 +133,7 @@ export async function perContractTestBindings(context) {
133
133
  if (currentProofBindingMode() !== "per_contract")
134
134
  return null;
135
135
  const { loadEntities } = await import("../discovery-entities.js");
136
- const { currentReceiptBindingHash, loadCoveredBySymbolsByTest } = await import("../../../operations/proof/code-scope.js");
136
+ const { currentReceiptBindingHashes, loadCoveredBySymbolsByTest } = await import("../../../operations/proof/code-scope.js");
137
137
  // Only the contract, scoped code, and authored source feed the binding
138
138
  // hash. The paged projection never materializes receipt histories, which
139
139
  // grow without bound and previously overflowed the bounded Prolog output
@@ -161,14 +161,18 @@ export async function perContractTestBindings(context) {
161
161
  continue;
162
162
  // The same computation ingest uses to write binding_hash. Unreadable or
163
163
  // non-markdown documents keep strict snapshot semantics for that test.
164
- const binding = await currentReceiptBindingHash({
164
+ const bindings = await currentReceiptBindingHashes({
165
165
  workspaceRoot: context.workspaceRoot,
166
166
  readFile: (absolute) => fs.readFile(absolute),
167
167
  test,
168
168
  coveredBySymbols: coveredBy.get(testId) ?? [],
169
169
  });
170
- if (binding !== undefined) {
171
- entries.push(`${toPrologAtom(testId)}: ${toPrologAtom(binding)}`);
170
+ if (bindings !== undefined) {
171
+ // One hash, or the current and the earlier binding a receipt may carry.
172
+ const value = bindings.length === 1
173
+ ? toPrologAtom(bindings[0])
174
+ : `[${bindings.map(toPrologAtom).join(", ")}]`;
175
+ entries.push(`${toPrologAtom(testId)}: ${value}`);
172
176
  }
173
177
  }
174
178
  if (entries.length === 0)
@@ -207,14 +211,19 @@ export async function executeCoverage(input, context) {
207
211
  : "unknown";
208
212
  const checkedAt = context.clock().toISOString();
209
213
  const statuses = (input.statuses ?? []).map((status) => validateCoverageStatus(status));
210
- const bindingsDict = statuses.length === 0 && (input.by ?? "req") === "req"
214
+ // A status filter judges receipts with the same per-contract binding as
215
+ // the unfiltered report; otherwise its rows and summary disagree with
216
+ // every other proof view.
217
+ const bindingsDict = (input.by ?? "req") === "req"
211
218
  ? await perContractTestBindings(context)
212
219
  : null;
213
- const goalFor = (limit, offset) => bindingsDict !== null
214
- ? `discovery:coverage_report_json('${input.by ?? "req"}', ${toPrologList(input.tags)}, ${input.includePassing ?? false}, per_contract, ${bindingsDict}, ${input.includeTransitive ?? true}, ${limit}, ${offset}, ${toPrologAtom(codeSnapshot)}, ${toPrologAtom(checkedAt)}, ${PROOF_RECEIPT_MAX_AGE_SECONDS}, JsonString)`
215
- : statuses.length > 0
216
- ? `discovery:coverage_report_json('${input.by ?? "req"}', ${toPrologList(input.tags)}, ${input.includePassing ?? false}, ${toPrologList(statuses)}, ${input.includeTransitive ?? true}, ${limit}, ${offset}, ${toPrologAtom(codeSnapshot)}, ${toPrologAtom(checkedAt)}, ${PROOF_RECEIPT_MAX_AGE_SECONDS}, JsonString)`
217
- : `discovery:coverage_report_json('${input.by ?? "req"}', ${toPrologList(input.tags)}, ${input.includePassing ?? false}, ${input.includeTransitive ?? true}, ${limit}, ${offset}, ${toPrologAtom(codeSnapshot)}, ${toPrologAtom(checkedAt)}, ${PROOF_RECEIPT_MAX_AGE_SECONDS}, JsonString)`;
220
+ const goalFor = (limit, offset) => bindingsDict !== null && statuses.length > 0
221
+ ? `discovery:coverage_report_json('${input.by ?? "req"}', ${toPrologList(input.tags)}, ${input.includePassing ?? false}, ${toPrologList(statuses)}, per_contract, ${bindingsDict}, ${input.includeTransitive ?? true}, ${limit}, ${offset}, ${toPrologAtom(codeSnapshot)}, ${toPrologAtom(checkedAt)}, ${PROOF_RECEIPT_MAX_AGE_SECONDS}, JsonString)`
222
+ : bindingsDict !== null
223
+ ? `discovery:coverage_report_json('${input.by ?? "req"}', ${toPrologList(input.tags)}, ${input.includePassing ?? false}, per_contract, ${bindingsDict}, ${input.includeTransitive ?? true}, ${limit}, ${offset}, ${toPrologAtom(codeSnapshot)}, ${toPrologAtom(checkedAt)}, ${PROOF_RECEIPT_MAX_AGE_SECONDS}, JsonString)`
224
+ : statuses.length > 0
225
+ ? `discovery:coverage_report_json('${input.by ?? "req"}', ${toPrologList(input.tags)}, ${input.includePassing ?? false}, ${toPrologList(statuses)}, ${input.includeTransitive ?? true}, ${limit}, ${offset}, ${toPrologAtom(codeSnapshot)}, ${toPrologAtom(checkedAt)}, ${PROOF_RECEIPT_MAX_AGE_SECONDS}, JsonString)`
226
+ : `discovery:coverage_report_json('${input.by ?? "req"}', ${toPrologList(input.tags)}, ${input.includePassing ?? false}, ${input.includeTransitive ?? true}, ${limit}, ${offset}, ${toPrologAtom(codeSnapshot)}, ${toPrologAtom(checkedAt)}, ${PROOF_RECEIPT_MAX_AGE_SECONDS}, JsonString)`;
218
227
  const payload = await readCoveragePages(requireProlog(context), goalFor, input.limit ?? 100, input.offset ?? 0);
219
228
  const rows = (input.by ?? "req") === "req"
220
229
  ? await addCoordinateRepairEvidence(payload.rows, context)
@@ -140,6 +140,11 @@ export declare const upsertSpec: {
140
140
  readonly enum: readonly ["firm", "default", "exploratory"];
141
141
  readonly description: "req/adr only. firm = a human stated it as a rule (needs origin.ref to their words); its title, meaning or firmness changes only with new human words (a new origin.ref) or by supersede. default = delegated or agent choice; exploratory = flagged guess. Absent = default if an agent wrote it, else firm.";
142
142
  };
143
+ readonly required_evidence: {
144
+ readonly type: "string";
145
+ readonly enum: readonly ["proved", "tested", "asserted", "unverified"];
146
+ readonly description: "Requirement-only. Weakest evidence level it accepts; the evidence-floor rule fails below it. Absent = tested if firm, else unverified.";
147
+ };
143
148
  readonly rationale: {
144
149
  readonly type: "string";
145
150
  readonly minLength: 1;
@@ -219,7 +224,87 @@ export declare const upsertSpec: {
219
224
  };
220
225
  readonly success_policy: {
221
226
  readonly type: "string";
222
- readonly enum: readonly ["all_required_first_attempt"];
227
+ readonly enum: readonly ["all_required_first_attempt", "own_results_first_attempt"];
228
+ };
229
+ readonly kind: {
230
+ readonly type: "string";
231
+ readonly enum: readonly ["e2e", "example", "property", "exhaustive", "typecheck", "arithmetic", "smt"];
232
+ readonly description: "What the checker establishes; absent means e2e. exhaustive, typecheck, arithmetic and smt must leave a kibi.code-certificate.v1 that Kibi re-checks before the receipt counts as proved.";
233
+ };
234
+ readonly domain_source: {
235
+ readonly type: "object";
236
+ readonly description: "exhaustive and typecheck: the symbol that defines the finite domain. The proof must import it from its source file; a hand-listed domain downgrades the receipt to example. Kibi reads the export named `export`, or the symbol's title when `export` is absent.";
237
+ readonly required: readonly ["symbol_id"];
238
+ readonly properties: {
239
+ readonly symbol_id: {
240
+ readonly type: "string";
241
+ readonly minLength: 1;
242
+ };
243
+ readonly export: {
244
+ readonly type: "string";
245
+ readonly minLength: 1;
246
+ readonly description: "The name the domain is exported under in the symbol's source file, when the symbol's title is not that name.";
247
+ };
248
+ };
249
+ readonly additionalProperties: false;
250
+ };
251
+ readonly witness: {
252
+ readonly type: "object";
253
+ readonly description: "typecheck: the repository-relative witness file Kibi compiles (an exhaustive switch ending in never, or a mapped type over the domain).";
254
+ readonly required: readonly ["path"];
255
+ readonly properties: {
256
+ readonly path: {
257
+ readonly type: "string";
258
+ readonly minLength: 1;
259
+ };
260
+ };
261
+ readonly additionalProperties: false;
262
+ };
263
+ readonly proves: {
264
+ readonly type: "array";
265
+ readonly description: "Certificate kinds: the requirement claim keys (CLAIM-...) this certificate proves. Each must be a modeled claim of a current requirement the test reaches through its scenarios. Kibi derives what the certificate must establish from the claim's grounding fact (a set fact for exhaustive or typecheck, a numeric fact for arithmetic or smt); a claim with no such derivation is only attested and never counts as proved.";
266
+ readonly minItems: 1;
267
+ readonly items: {
268
+ readonly type: "string";
269
+ readonly pattern: "^CLAIM-";
270
+ };
271
+ readonly uniqueItems: true;
272
+ };
273
+ readonly value_source: {
274
+ readonly type: "array";
275
+ readonly description: "arithmetic and smt: code constants the assumptions read. Kibi evaluates each export at ingest and requires the certificate to assume the variable equals that value, so the proof is about the code and not only the knowledge base.";
276
+ readonly minItems: 1;
277
+ readonly items: {
278
+ readonly type: "object";
279
+ readonly required: readonly ["symbol_id"];
280
+ readonly properties: {
281
+ readonly symbol_id: {
282
+ readonly type: "string";
283
+ readonly minLength: 1;
284
+ };
285
+ readonly export: {
286
+ readonly type: "string";
287
+ readonly minLength: 1;
288
+ };
289
+ };
290
+ readonly additionalProperties: false;
291
+ };
292
+ };
293
+ readonly constraint_source: {
294
+ readonly type: "object";
295
+ readonly description: "arithmetic and smt: the typed numeric property_value facts the certificate's assumptions come from. Kibi checks the assumptions (or the query's assertions) are exactly these facts' constraints, so the proof is about the knowledge base, not numbers the test chose.";
296
+ readonly required: readonly ["fact_ids"];
297
+ readonly properties: {
298
+ readonly fact_ids: {
299
+ readonly type: "array";
300
+ readonly minItems: 1;
301
+ readonly items: {
302
+ readonly type: "string";
303
+ readonly minLength: 1;
304
+ };
305
+ };
306
+ };
307
+ readonly additionalProperties: false;
223
308
  };
224
309
  };
225
310
  readonly additionalProperties: false;
@@ -267,12 +352,12 @@ export declare const upsertSpec: {
267
352
  readonly maxItems: 50;
268
353
  readonly items: {
269
354
  readonly type: "object";
270
- readonly description: "Kibi-derived kibi.proof-receipt.v1. Receipts are never caller-authored; kb_ingest_proof derives them from kibi.proof-run.v1 artifacts.";
355
+ readonly description: "Kibi-derived kibi.proof-receipt.v2 (kibi.proof-receipt.v1 entries are still read). Receipts are never caller-authored; kb_ingest_proof derives them from kibi.proof-run.v1 artifacts.";
271
356
  readonly required: readonly ["version", "receipt_id", "test_id", "scope", "outcome", "code_snapshot", "environment_hash", "started_at", "finished_at", "artifact_digest", "contract_hash", "fingerprint", "fingerprint_components", "integration_id", "producer", "command_argv", "run_outcome", "proof_results"];
272
357
  readonly properties: {
273
358
  readonly version: {
274
359
  readonly type: "string";
275
- readonly const: "kibi.proof-receipt.v1";
360
+ readonly enum: readonly ["kibi.proof-receipt.v1", "kibi.proof-receipt.v2"];
276
361
  };
277
362
  readonly receipt_id: {
278
363
  readonly type: "string";
@@ -454,6 +539,63 @@ export declare const upsertSpec: {
454
539
  readonly additionalProperties: false;
455
540
  };
456
541
  };
542
+ readonly kind: {
543
+ readonly type: "string";
544
+ readonly enum: readonly ["e2e", "example", "property", "exhaustive", "typecheck", "arithmetic", "smt"];
545
+ };
546
+ readonly evidence_level: {
547
+ readonly type: "string";
548
+ readonly enum: readonly ["proved", "tested"];
549
+ };
550
+ readonly certificate: {
551
+ readonly type: "object";
552
+ };
553
+ readonly certificate_digest: {
554
+ readonly type: "string";
555
+ readonly pattern: "^[a-f0-9]{64}$";
556
+ };
557
+ readonly certificate_rejection: {
558
+ readonly type: "string";
559
+ readonly minLength: 1;
560
+ };
561
+ readonly claim_bindings: {
562
+ readonly type: "array";
563
+ readonly description: "Certificate kinds: how the certificate binds to each claim its contract names in proves, judged at ingest. derived means Kibi derived the certificate's obligation from the claim's grounding fact and the certificate satisfies it; attested means no derivation exists and the author vouches for it (never proved); rejected names why.";
564
+ readonly items: {
565
+ readonly type: "object";
566
+ readonly required: readonly ["claim_key", "binding"];
567
+ readonly properties: {
568
+ readonly claim_key: {
569
+ readonly type: "string";
570
+ readonly minLength: 1;
571
+ };
572
+ readonly requirement_id: {
573
+ readonly type: "string";
574
+ readonly minLength: 1;
575
+ };
576
+ readonly fact_id: {
577
+ readonly type: "string";
578
+ readonly minLength: 1;
579
+ };
580
+ readonly binding: {
581
+ readonly type: "string";
582
+ readonly enum: readonly ["derived", "attested", "rejected"];
583
+ };
584
+ readonly scope: {
585
+ readonly type: "string";
586
+ readonly enum: readonly ["code", "intent"];
587
+ };
588
+ readonly obligation: {
589
+ readonly type: "object";
590
+ };
591
+ readonly reason: {
592
+ readonly type: "string";
593
+ readonly minLength: 1;
594
+ };
595
+ };
596
+ readonly additionalProperties: false;
597
+ };
598
+ };
457
599
  readonly gaps: {
458
600
  readonly type: "array";
459
601
  readonly items: {
@@ -501,8 +643,8 @@ export declare const upsertSpec: {
501
643
  };
502
644
  readonly value_type: {
503
645
  readonly type: "string";
504
- readonly enum: readonly ["string", "int", "number", "bool"];
505
- readonly description: "Optional typed value discriminator for property_value facts. Pair with exactly one value_string, value_int, value_number, or value_bool; do not use generic value.";
646
+ readonly enum: readonly ["string", "int", "number", "bool", "set"];
647
+ readonly description: "Optional typed value discriminator for property_value facts. Pair with exactly one value_string, value_int, value_number, value_bool, or value_set (set: an exact list of allowed values, operator eq or neq); do not use generic value.";
506
648
  };
507
649
  readonly value_string: {
508
650
  readonly type: "string";
@@ -520,6 +662,16 @@ export declare const upsertSpec: {
520
662
  readonly type: "boolean";
521
663
  readonly description: "Optional boolean value for property_value facts.";
522
664
  };
665
+ readonly value_set: {
666
+ readonly type: "array";
667
+ readonly items: {
668
+ readonly type: "string";
669
+ readonly minLength: 1;
670
+ };
671
+ readonly minItems: 1;
672
+ readonly uniqueItems: true;
673
+ readonly description: "Optional exact set of values for property_value facts with value_type set, such as the members a domain must have.";
674
+ };
523
675
  readonly unit: {
524
676
  readonly type: "string";
525
677
  readonly description: "Optional unit for numeric property_value facts.";
@@ -1 +1 @@
1
- {"version":3,"file":"upsert.d.ts","sourceRoot":"","sources":["../../../../src/public/operations/specs/upsert.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAQvE,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0DuC,CAAC"}
1
+ {"version":3,"file":"upsert.d.ts","sourceRoot":"","sources":["../../../../src/public/operations/specs/upsert.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAQvE,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0DuC,CAAC"}
@@ -0,0 +1,89 @@
1
+ import { CODE_CERTIFICATE_VERSION } from "./proof-protocol.js";
2
+ /** Where `kibi prove` asks a run to leave its certificates. */
3
+ export declare const PROOF_CERTIFICATES_ENV = "KIBI_PROOF_CERTIFICATES";
4
+ export type CodeCertificate = Readonly<Record<string, unknown>> & Readonly<{
5
+ version: typeof CODE_CERTIFICATE_VERSION;
6
+ kind: "exhaustive" | "typecheck" | "arithmetic" | "smt";
7
+ test_id: string;
8
+ }>;
9
+ /**
10
+ * The canonical JSON of a certificate, byte for byte what
11
+ * code_certificates.pl hashes: keys sorted by code point, no whitespace,
12
+ * non-ASCII and control characters as \u escapes of UTF-16 code units.
13
+ */
14
+ export declare function canonicalCertificateJson(value: unknown): string;
15
+ /** The sha256 a receipt records for its certificate. */
16
+ export declare function certificateDigest(certificate: unknown): string;
17
+ export type ExhaustiveResult = Readonly<{
18
+ member: string;
19
+ outcome: "passed" | "failed";
20
+ message?: string;
21
+ }>;
22
+ /**
23
+ * Run `check` on every member of a finite domain and record each outcome.
24
+ * `members` must be the domain as the code defines it (import it from its
25
+ * source, never restate it): Kibi rejects the certificate unless the proof
26
+ * file imports the contract's domain_source symbol.
27
+ */
28
+ export declare function exhaustiveCertificate<T>(input: {
29
+ testId: string;
30
+ domain: Readonly<{
31
+ symbolId: string;
32
+ members: Iterable<T>;
33
+ }>;
34
+ key?: (member: T) => string;
35
+ check: (member: T) => void | Promise<void>;
36
+ }): Promise<CodeCertificate>;
37
+ /** The members an exhaustive certificate records as failed. */
38
+ export declare function failedMembers(certificate: CodeCertificate): string[];
39
+ /**
40
+ * A type checker accepted `witnessPath`, a file that fails to compile when a
41
+ * member of the domain goes unhandled (an exhaustive switch ending in a
42
+ * `never` assignment, or a mapped type over the domain).
43
+ */
44
+ export declare function typecheckCertificate(input: {
45
+ testId: string;
46
+ domainSymbolId: string;
47
+ witnessPath: string;
48
+ workspaceRoot?: string;
49
+ compiler: Readonly<{
50
+ name: string;
51
+ version: string;
52
+ }>;
53
+ accepted: boolean;
54
+ }): CodeCertificate;
55
+ export type ArithmeticConstraint = Readonly<{
56
+ operator: "eq" | "neq" | "lt" | "lte" | "gt" | "gte";
57
+ value: number;
58
+ }>;
59
+ /**
60
+ * A claim about one numeric variable that Kibi decides exactly: the
61
+ * assumptions must be satisfiable and must entail the claim for every value
62
+ * of the variable, not only the values a test happened to try.
63
+ */
64
+ export declare function arithmeticCertificate(input: {
65
+ testId: string;
66
+ variable: string;
67
+ valueType: "int" | "real";
68
+ assumptions: readonly ArithmeticConstraint[];
69
+ claim: ArithmeticConstraint;
70
+ }): CodeCertificate;
71
+ /**
72
+ * An SMT-LIB query whose unsat answer proves the claim (the query asserts
73
+ * the claim's negation). Kibi re-runs the named solver on the query.
74
+ */
75
+ export declare function smtCertificate(input: {
76
+ testId: string;
77
+ solver: Readonly<{
78
+ name: "z3" | "cvc5";
79
+ version: string;
80
+ }>;
81
+ query: string;
82
+ result: string;
83
+ }): CodeCertificate;
84
+ /**
85
+ * Leave the certificate where `kibi prove` reads it. Returns the file written,
86
+ * or null outside a `kibi prove` run.
87
+ */
88
+ export declare function writeCodeCertificate(certificate: CodeCertificate, env?: NodeJS.ProcessEnv): string | null;
89
+ //# sourceMappingURL=proof-certificates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proof-certificates.d.ts","sourceRoot":"","sources":["../../src/public/proof-certificates.ts"],"names":[],"mappings":"AA8BA,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,+DAA+D;AAE/D,eAAO,MAAM,sBAAsB,4BAA4B,CAAC;AAGhE,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC7D,QAAQ,CAAC;IACP,OAAO,EAAE,OAAO,wBAAwB,CAAC;IACzC,IAAI,EAAE,YAAY,GAAG,WAAW,GAAG,YAAY,GAAG,KAAK,CAAC;IACxD,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC,CAAC;AAmCL;;;;GAIG;AAEH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAc/D;AAED,wDAAwD;AAExD,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,CAI9D;AAGD,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC,CAAC;AAEH;;;;;GAKG;AAEH,wBAAsB,qBAAqB,CAAC,CAAC,EAAE,KAAK,EAAE;IACpD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,QAAQ,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAA;KAAE,CAAC,CAAC;IAC7D,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,CAAC;IAC5B,KAAK,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5C,GAAG,OAAO,CAAC,eAAe,CAAC,CA0B3B;AAED,+DAA+D;AAE/D,wBAAgB,aAAa,CAAC,WAAW,EAAE,eAAe,GAAG,MAAM,EAAE,CASpE;AAED;;;;GAIG;AAEH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,QAAQ,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtD,QAAQ,EAAE,OAAO,CAAC;CACnB,GAAG,eAAe,CAmBlB;AAGD,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAC1C,QAAQ,EAAE,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,CAAC;IACrD,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CAAC;AAEH;;;;GAIG;AAEH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,KAAK,GAAG,MAAM,CAAC;IAC1B,WAAW,EAAE,SAAS,oBAAoB,EAAE,CAAC;IAC7C,KAAK,EAAE,oBAAoB,CAAC;CAC7B,GAAG,eAAe,CAUlB;AAED;;;GAGG;AAEH,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,QAAQ,CAAC;QAAE,IAAI,EAAE,IAAI,GAAG,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,eAAe,CASlB;AAED;;;GAGG;AAEH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,eAAe,EAC5B,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,GAAG,IAAI,CAUf"}
@@ -0,0 +1,207 @@
1
+ /*
2
+ Kibi — repo-local, per-branch, queryable long-term memory for software projects
3
+ Copyright (C) 2026 Piotr Franczyk
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU Affero General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU Affero General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Affero General Public License
16
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ */
18
+ /**
19
+ * Builders for the kibi.code-certificate.v1 a certificate-kind proof contract
20
+ * leaves for `kibi prove`. A test builds its certificate and writes it with
21
+ * writeCodeCertificate; outside `kibi prove` the write is a no-op, so the same
22
+ * test runs unchanged in an ordinary test run. Kibi re-checks every
23
+ * certificate at ingest and again whenever it reports evidence, so a
24
+ * certificate only records what the test did; it never vouches for itself.
25
+ */
26
+ import { createHash } from "node:crypto";
27
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
28
+ import path from "node:path";
29
+ import { CODE_CERTIFICATE_VERSION } from "./proof-protocol.js";
30
+ /** Where `kibi prove` asks a run to leave its certificates. */
31
+ // implements REQ-kibi-code-proof-kinds
32
+ export const PROOF_CERTIFICATES_ENV = "KIBI_PROOF_CERTIFICATES";
33
+ function compareCodePoints(left, right) {
34
+ const a = Array.from(left, (char) => char.codePointAt(0) ?? 0);
35
+ const b = Array.from(right, (char) => char.codePointAt(0) ?? 0);
36
+ for (let index = 0; index < Math.min(a.length, b.length); index++) {
37
+ const difference = (a[index] ?? 0) - (b[index] ?? 0);
38
+ if (difference !== 0)
39
+ return difference;
40
+ }
41
+ return a.length - b.length;
42
+ }
43
+ const JSON_ESCAPES = {
44
+ '"': '\\"',
45
+ "\\": "\\\\",
46
+ "\b": "\\b",
47
+ "\f": "\\f",
48
+ "\n": "\\n",
49
+ "\r": "\\r",
50
+ "\t": "\\t",
51
+ };
52
+ function canonicalString(value) {
53
+ let out = '"';
54
+ for (let index = 0; index < value.length; index++) {
55
+ const char = value[index];
56
+ const unit = value.charCodeAt(index);
57
+ const escaped = JSON_ESCAPES[char];
58
+ if (escaped !== undefined)
59
+ out += escaped;
60
+ else if (unit >= 0x20 && unit <= 0x7e)
61
+ out += char;
62
+ else
63
+ out += `\\u${unit.toString(16).padStart(4, "0")}`;
64
+ }
65
+ return `${out}"`;
66
+ }
67
+ /**
68
+ * The canonical JSON of a certificate, byte for byte what
69
+ * code_certificates.pl hashes: keys sorted by code point, no whitespace,
70
+ * non-ASCII and control characters as \u escapes of UTF-16 code units.
71
+ */
72
+ // implements REQ-kibi-code-proof-kinds
73
+ export function canonicalCertificateJson(value) {
74
+ if (value === null || value === undefined)
75
+ return "null";
76
+ if (Array.isArray(value))
77
+ return `[${value.map(canonicalCertificateJson).join(",")}]`;
78
+ if (typeof value === "object")
79
+ return `{${Object.keys(value)
80
+ .sort(compareCodePoints)
81
+ .map((key) => `${canonicalString(key)}:${canonicalCertificateJson(value[key])}`)
82
+ .join(",")}}`;
83
+ if (typeof value === "string")
84
+ return canonicalString(value);
85
+ return JSON.stringify(value);
86
+ }
87
+ /** The sha256 a receipt records for its certificate. */
88
+ // implements REQ-kibi-code-proof-kinds
89
+ export function certificateDigest(certificate) {
90
+ return createHash("sha256")
91
+ .update(canonicalCertificateJson(certificate), "utf8")
92
+ .digest("hex");
93
+ }
94
+ /**
95
+ * Run `check` on every member of a finite domain and record each outcome.
96
+ * `members` must be the domain as the code defines it (import it from its
97
+ * source, never restate it): Kibi rejects the certificate unless the proof
98
+ * file imports the contract's domain_source symbol.
99
+ */
100
+ // implements REQ-kibi-code-proof-kinds
101
+ export async function exhaustiveCertificate(input) {
102
+ const key = input.key ?? ((member) => String(member));
103
+ const members = [...input.domain.members];
104
+ const results = [];
105
+ for (const member of members) {
106
+ try {
107
+ await input.check(member);
108
+ results.push({ member: key(member), outcome: "passed" });
109
+ }
110
+ catch (error) {
111
+ results.push({
112
+ member: key(member),
113
+ outcome: "failed",
114
+ message: error instanceof Error ? error.message : String(error),
115
+ });
116
+ }
117
+ }
118
+ return {
119
+ version: CODE_CERTIFICATE_VERSION,
120
+ kind: "exhaustive",
121
+ test_id: input.testId,
122
+ domain: {
123
+ symbol_id: input.domain.symbolId,
124
+ members: members.map(key),
125
+ },
126
+ results,
127
+ };
128
+ }
129
+ /** The members an exhaustive certificate records as failed. */
130
+ // implements REQ-kibi-code-proof-kinds
131
+ export function failedMembers(certificate) {
132
+ const results = Array.isArray(certificate.results)
133
+ ? certificate.results
134
+ : [];
135
+ return results
136
+ .filter((result) => result.outcome !== "passed")
137
+ .map((result) => result.message ? `${result.member}: ${result.message}` : result.member);
138
+ }
139
+ /**
140
+ * A type checker accepted `witnessPath`, a file that fails to compile when a
141
+ * member of the domain goes unhandled (an exhaustive switch ending in a
142
+ * `never` assignment, or a mapped type over the domain).
143
+ */
144
+ // implements REQ-kibi-code-proof-kinds
145
+ export function typecheckCertificate(input) {
146
+ const absolute = path.resolve(input.workspaceRoot ?? process.cwd(), input.witnessPath);
147
+ return {
148
+ version: CODE_CERTIFICATE_VERSION,
149
+ kind: "typecheck",
150
+ test_id: input.testId,
151
+ domain: { symbol_id: input.domainSymbolId },
152
+ witness: {
153
+ path: input.witnessPath,
154
+ sha256: createHash("sha256")
155
+ .update(readFileSync(absolute, "utf8"))
156
+ .digest("hex"),
157
+ },
158
+ compiler: { ...input.compiler },
159
+ outcome: input.accepted ? "passed" : "failed",
160
+ };
161
+ }
162
+ /**
163
+ * A claim about one numeric variable that Kibi decides exactly: the
164
+ * assumptions must be satisfiable and must entail the claim for every value
165
+ * of the variable, not only the values a test happened to try.
166
+ */
167
+ // implements REQ-kibi-code-proof-kinds
168
+ export function arithmeticCertificate(input) {
169
+ return {
170
+ version: CODE_CERTIFICATE_VERSION,
171
+ kind: "arithmetic",
172
+ test_id: input.testId,
173
+ variable: input.variable,
174
+ value_type: input.valueType,
175
+ assumptions: input.assumptions.map((row) => ({ ...row })),
176
+ claim: { ...input.claim },
177
+ };
178
+ }
179
+ /**
180
+ * An SMT-LIB query whose unsat answer proves the claim (the query asserts
181
+ * the claim's negation). Kibi re-runs the named solver on the query.
182
+ */
183
+ // implements REQ-kibi-code-proof-kinds
184
+ export function smtCertificate(input) {
185
+ return {
186
+ version: CODE_CERTIFICATE_VERSION,
187
+ kind: "smt",
188
+ test_id: input.testId,
189
+ solver: { ...input.solver },
190
+ query: input.query,
191
+ result: input.result,
192
+ };
193
+ }
194
+ /**
195
+ * Leave the certificate where `kibi prove` reads it. Returns the file written,
196
+ * or null outside a `kibi prove` run.
197
+ */
198
+ // implements REQ-kibi-code-proof-kinds
199
+ export function writeCodeCertificate(certificate, env = process.env) {
200
+ const directory = env[PROOF_CERTIFICATES_ENV];
201
+ if (directory === undefined || directory.trim() === "")
202
+ return null;
203
+ mkdirSync(directory, { recursive: true });
204
+ const file = path.join(directory, `${certificate.test_id.replace(/[^A-Za-z0-9._-]/g, "_")}.json`);
205
+ writeFileSync(file, `${JSON.stringify(certificate, null, 2)}\n`, "utf8");
206
+ return file;
207
+ }