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.
- package/dist/cli-register-proof.d.ts.map +1 -1
- package/dist/cli-register-proof.js +19 -7
- package/dist/cli-register-reporting.d.ts.map +1 -1
- package/dist/cli-register-reporting.js +2 -0
- package/dist/commands/check.d.ts +1 -0
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +14 -5
- package/dist/commands/discovery-table.d.ts.map +1 -1
- package/dist/commands/discovery-table.js +51 -4
- package/dist/commands/doctor.js +19 -4
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +89 -3
- package/dist/commands/prove.d.ts +48 -1
- package/dist/commands/prove.d.ts.map +1 -1
- package/dist/commands/prove.js +293 -8
- package/dist/commands/report.d.ts +1 -0
- package/dist/commands/report.d.ts.map +1 -1
- package/dist/commands/report.js +70 -5
- package/dist/commands/signoff.d.ts.map +1 -1
- package/dist/commands/signoff.js +21 -2
- package/dist/commands/sync/manifest.d.ts.map +1 -1
- package/dist/commands/sync/manifest.js +20 -4
- package/dist/commands/sync/persistence.d.ts.map +1 -1
- package/dist/commands/sync/persistence.js +16 -5
- package/dist/diagnostics.js +1 -1
- package/dist/engine.js +1 -1
- package/dist/extractors/markdown.d.ts +3 -1
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +17 -0
- package/dist/operations/bootstrap/candidate-helpers.d.ts +3 -0
- package/dist/operations/bootstrap/candidate-helpers.d.ts.map +1 -1
- package/dist/operations/bootstrap/candidate-helpers.js +4 -0
- package/dist/operations/migration/evidence-floor.d.ts +41 -0
- package/dist/operations/migration/evidence-floor.d.ts.map +1 -0
- package/dist/operations/migration/evidence-floor.js +230 -0
- package/dist/operations/migration/proof-contract-claims.d.ts +59 -0
- package/dist/operations/migration/proof-contract-claims.d.ts.map +1 -0
- package/dist/operations/migration/proof-contract-claims.js +182 -0
- package/dist/operations/migration/schema6.d.ts +6 -0
- package/dist/operations/migration/schema6.d.ts.map +1 -1
- package/dist/operations/migration/schema6.js +94 -0
- package/dist/operations/mutation/omitted-properties.d.ts +11 -0
- package/dist/operations/mutation/omitted-properties.d.ts.map +1 -0
- package/dist/operations/mutation/omitted-properties.js +76 -0
- package/dist/operations/mutation/serialization.d.ts.map +1 -1
- package/dist/operations/mutation/serialization.js +1 -0
- package/dist/operations/mutation/strict-fact.d.ts.map +1 -1
- package/dist/operations/mutation/strict-fact.js +6 -2
- package/dist/operations/mutation/symbol-granularity.d.ts.map +1 -1
- package/dist/operations/mutation/symbol-granularity.js +5 -3
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +7 -1
- package/dist/operations/mutation/validation.d.ts +2 -0
- package/dist/operations/mutation/validation.d.ts.map +1 -1
- package/dist/operations/mutation/validation.js +4 -0
- package/dist/operations/proof/claim-bindings.d.ts +23 -0
- package/dist/operations/proof/claim-bindings.d.ts.map +1 -0
- package/dist/operations/proof/claim-bindings.js +211 -0
- package/dist/operations/proof/code-certificates.d.ts +135 -0
- package/dist/operations/proof/code-certificates.d.ts.map +1 -0
- package/dist/operations/proof/code-certificates.js +785 -0
- package/dist/operations/proof/code-scope.d.ts +11 -1
- package/dist/operations/proof/code-scope.d.ts.map +1 -1
- package/dist/operations/proof/code-scope.js +20 -2
- package/dist/operations/proof/compact-receipts.d.ts.map +1 -1
- package/dist/operations/proof/compact-receipts.js +4 -3
- package/dist/operations/proof/explain.d.ts +32 -0
- package/dist/operations/proof/explain.d.ts.map +1 -1
- package/dist/operations/proof/explain.js +91 -0
- package/dist/operations/proof/ingest-proof.d.ts +9 -1
- package/dist/operations/proof/ingest-proof.d.ts.map +1 -1
- package/dist/operations/proof/ingest-proof.js +41 -2
- package/dist/operations/proof/receipt-compaction.d.ts +2 -0
- package/dist/operations/proof/receipt-compaction.d.ts.map +1 -1
- package/dist/operations/proof/receipt-compaction.js +6 -2
- package/dist/operations/semantic-advisor/shared.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/shared.js +4 -0
- package/dist/operations/semantic-advisor/strict-rules.js +3 -3
- package/dist/operations/semantic-advisor/types.d.ts +2 -1
- package/dist/operations/semantic-advisor/types.d.ts.map +1 -1
- package/dist/plugins/approved-source-analyzers.generated.d.ts +6 -6
- package/dist/plugins/approved-source-analyzers.generated.js +6 -6
- package/dist/proof/command-test-report.d.ts +4 -3
- package/dist/proof/command-test-report.d.ts.map +1 -1
- package/dist/proof/command-test-report.js +4 -10
- package/dist/proof/evaluate.d.ts.map +1 -1
- package/dist/proof/evaluate.js +18 -2
- package/dist/proof/inspect.d.ts.map +1 -1
- package/dist/proof/inspect.js +58 -0
- package/dist/proof/producers/playwright-reporter.d.ts +3 -0
- package/dist/proof/producers/playwright-reporter.d.ts.map +1 -1
- package/dist/proof/producers/playwright-reporter.js +25 -2
- package/dist/proof/step-runner.d.ts +36 -0
- package/dist/proof/step-runner.d.ts.map +1 -0
- package/dist/proof/step-runner.js +234 -0
- package/dist/public/evidence-levels.d.ts +12 -0
- package/dist/public/evidence-levels.d.ts.map +1 -0
- package/dist/public/evidence-levels.js +19 -0
- package/dist/public/impact/coverage-depth-quality.d.ts +7 -0
- package/dist/public/impact/coverage-depth-quality.d.ts.map +1 -1
- package/dist/public/impact/coverage-depth-quality.js +59 -0
- package/dist/public/impact/full-kb-quality.d.ts.map +1 -1
- package/dist/public/impact/full-kb-quality.js +3 -1
- package/dist/public/operations/catalog.d.ts +167 -6
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/check-executor.d.ts +2 -0
- package/dist/public/operations/check-executor.d.ts.map +1 -1
- package/dist/public/operations/check-executor.js +6 -0
- package/dist/public/operations/evidence-floor.d.ts +48 -0
- package/dist/public/operations/evidence-floor.d.ts.map +1 -0
- package/dist/public/operations/evidence-floor.js +143 -0
- package/dist/public/operations/migration-plan.d.ts +19 -5
- package/dist/public/operations/migration-plan.d.ts.map +1 -1
- package/dist/public/operations/migration-plan.js +22 -5
- package/dist/public/operations/node-ports.d.ts.map +1 -1
- package/dist/public/operations/node-ports.js +4 -1
- package/dist/public/operations/proof-contract-claims.d.ts +26 -0
- package/dist/public/operations/proof-contract-claims.d.ts.map +1 -0
- package/dist/public/operations/proof-contract-claims.js +71 -0
- package/dist/public/operations/specs/check-rules.generated.d.ts +1 -1
- package/dist/public/operations/specs/check-rules.generated.d.ts.map +1 -1
- package/dist/public/operations/specs/check-rules.generated.js +3 -1
- package/dist/public/operations/specs/check.d.ts +1 -1
- package/dist/public/operations/specs/mutation-schemas.d.ts +157 -5
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +15 -2
- package/dist/public/operations/specs/proof.d.ts +9 -0
- package/dist/public/operations/specs/proof.d.ts.map +1 -1
- package/dist/public/operations/specs/reporting.d.ts.map +1 -1
- package/dist/public/operations/specs/reporting.js +19 -10
- package/dist/public/operations/specs/upsert.d.ts +157 -5
- package/dist/public/operations/specs/upsert.d.ts.map +1 -1
- package/dist/public/proof-certificates.d.ts +89 -0
- package/dist/public/proof-certificates.d.ts.map +1 -0
- package/dist/public/proof-certificates.js +207 -0
- package/dist/public/proof-protocol.d.ts +126 -3
- package/dist/public/proof-protocol.d.ts.map +1 -1
- package/dist/public/proof-protocol.js +239 -3
- package/dist/public/proof-receipt.d.ts +89 -6
- package/dist/public/proof-receipt.d.ts.map +1 -1
- package/dist/public/proof-receipt.js +83 -7
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +18 -1
- package/dist/public/skills/kibi-bootstrap/SKILL.md +2 -2
- package/dist/public/skills/kibi-commit-review/SKILL.md +4 -3
- package/dist/public/skills/kibi-commit-review/resources/staged-gate.md +6 -1
- package/dist/public/skills/kibi-decisions/SKILL.md +10 -2
- package/dist/public/skills/kibi-decisions/resources/decision-records.md +6 -1
- package/dist/public/skills/kibi-decisions/resources/signoff-views.md +3 -2
- package/dist/public/skills/kibi-freshness/SKILL.md +5 -1
- package/dist/public/skills/kibi-traceability/SKILL.md +11 -1
- package/dist/public/skills/kibi-usage/SKILL.md +6 -4
- package/dist/public/skills/kibi-usage/resources/proof.md +124 -19
- package/dist/public/skills/kibi-usage/resources/workflows.md +4 -4
- package/dist/report/html-report.css +38 -1
- package/dist/report/html-report.d.ts +8 -0
- package/dist/report/html-report.d.ts.map +1 -1
- package/dist/report/html-report.js +141 -6
- package/dist/report/report-view.d.ts +1 -1
- package/dist/report/report-view.d.ts.map +1 -1
- package/dist/report/report-view.js +7 -0
- package/dist/schemas/entity.schema.json +212 -4
- package/dist/search-answer.d.ts.map +1 -1
- package/dist/search-answer.js +1 -0
- package/dist/signoff/html.d.ts.map +1 -1
- package/dist/signoff/html.js +3 -0
- package/dist/signoff/markdown.d.ts.map +1 -1
- package/dist/signoff/markdown.js +3 -0
- package/dist/signoff/model.d.ts +20 -0
- package/dist/signoff/model.d.ts.map +1 -1
- package/dist/signoff/model.js +20 -1
- package/dist/traceability/impact-knowledge.d.ts.map +1 -1
- package/dist/traceability/impact-knowledge.js +1 -0
- package/dist/traceability/temp-kb.d.ts.map +1 -1
- package/dist/traceability/temp-kb.js +1 -0
- package/dist/types/entities.d.ts +4 -1
- package/dist/types/entities.d.ts.map +1 -1
- package/dist/utils/merge-driver-setup.d.ts +8 -1
- package/dist/utils/merge-driver-setup.d.ts.map +1 -1
- package/dist/utils/merge-driver-setup.js +23 -2
- package/dist/utils/rule-registry.generated.d.ts +10 -0
- package/dist/utils/rule-registry.generated.d.ts.map +1 -1
- package/dist/utils/rule-registry.generated.js +12 -0
- package/dist/utils/schema-version.d.ts +1 -1
- package/dist/utils/schema-version.d.ts.map +1 -1
- package/dist/utils/schema-version.js +5 -1
- package/package.json +6 -2
- package/schema/entities.pl +6 -0
- package/schema/validation.pl +4 -1
- package/src/public/evidence-levels.ts +23 -0
- package/src/public/impact/coverage-depth-quality.ts +73 -0
- package/src/public/impact/full-kb-quality.ts +6 -1
- package/src/public/operations/check-executor.ts +13 -0
- package/src/public/operations/evidence-floor.ts +203 -0
- package/src/public/operations/migration-plan.ts +39 -6
- package/src/public/operations/node-ports.ts +3 -1
- package/src/public/operations/proof-contract-claims.ts +103 -0
- package/src/public/operations/specs/check-rules.generated.ts +3 -1
- package/src/public/operations/specs/mutation-schemas.ts +17 -2
- package/src/public/operations/specs/reporting.ts +20 -10
- package/src/public/proof-certificates.ts +271 -0
- package/src/public/proof-protocol-types.d.ts +17 -1
- package/src/public/proof-protocol.ts +318 -3
- package/src/public/proof-receipt.ts +127 -7
- package/src/public/schemas/entity.ts +19 -1
- package/src/public/skills/kibi-bootstrap/SKILL.md +2 -2
- package/src/public/skills/kibi-commit-review/SKILL.md +4 -3
- package/src/public/skills/kibi-commit-review/resources/staged-gate.md +6 -1
- package/src/public/skills/kibi-decisions/SKILL.md +10 -2
- package/src/public/skills/kibi-decisions/resources/decision-records.md +6 -1
- package/src/public/skills/kibi-decisions/resources/signoff-views.md +3 -2
- package/src/public/skills/kibi-freshness/SKILL.md +5 -1
- package/src/public/skills/kibi-traceability/SKILL.md +11 -1
- package/src/public/skills/kibi-usage/SKILL.md +6 -4
- package/src/public/skills/kibi-usage/resources/proof.md +124 -19
- package/src/public/skills/kibi-usage/resources/workflows.md +4 -4
- package/src/schemas/entity.schema.json +212 -4
- package/dist/commands/proof-impact.d.ts +0 -7
- package/dist/commands/proof-impact.d.ts.map +0 -1
- package/dist/commands/proof-impact.js +0 -39
- package/dist/operations/proof/baseline-diff.d.ts +0 -41
- package/dist/operations/proof/baseline-diff.d.ts.map +0 -1
- package/dist/operations/proof/baseline-diff.js +0 -153
- package/dist/operations/proof/impact.d.ts +0 -51
- package/dist/operations/proof/impact.d.ts.map +0 -1
- package/dist/operations/proof/impact.js +0 -138
|
@@ -65,9 +65,11 @@ export const SELECTABLE_RULE_NAMES: readonly string[] = [
|
|
|
65
65
|
"policy-markers",
|
|
66
66
|
"kb-consistency",
|
|
67
67
|
"kb-consistency-unresolved",
|
|
68
|
+
"evidence-floor",
|
|
69
|
+
"proof-contract-claims",
|
|
68
70
|
];
|
|
69
71
|
|
|
70
72
|
// implements REQ-006
|
|
71
73
|
/** Comma-separated "Allowed:" fragment for the kb_check rules description. */
|
|
72
74
|
export const SELECTABLE_RULES_ALLOWED =
|
|
73
|
-
"must-priority-coverage, symbol-coverage, symbol-traceability, symbol-granularity, no-dangling-refs, source-relationship-parity, branch-store-not-compiled, source-path-dangling, no-cycles, required-fields, deprecated-adr-no-successor, superseded-requirement-open, scenario-feasibility, scenario-feasibility-unknown, exception-claim-keys, numeric-string-value, rule-key-arguments-missing, domain-contradictions, logic-coverage, rule-safety, rule-verifiability, query-plan-safety, req-status-vocabulary, strict-fact-shape, strict-req-fact-pairing, predicate-verifiability, strict-readiness, semantic-completeness, related-requirement-unmodeled, proof-contract-symbols, entity-id-style, domain-redundancy, domain-implication, subject-key-identity, subject-key-shape, ontology-quality, exception-unapproved, exception-approval-self-attested, agent-requirement-unapproved, requirement-rationale-missing, symbol-owner-superseded, adr-unlinked, adr-proposed, predicate-schema-conformance, entity-context-missing, entity-context-acknowledged, decision-firm-unreferenced, decision-firm-superseded, decision-firm-edited, supersedes-reason-missing, supersedes-reason-acknowledged, policy-ownership, policy-markers, kb-consistency, kb-consistency-unresolved";
|
|
75
|
+
"must-priority-coverage, symbol-coverage, symbol-traceability, symbol-granularity, no-dangling-refs, source-relationship-parity, branch-store-not-compiled, source-path-dangling, no-cycles, required-fields, deprecated-adr-no-successor, superseded-requirement-open, scenario-feasibility, scenario-feasibility-unknown, exception-claim-keys, numeric-string-value, rule-key-arguments-missing, domain-contradictions, logic-coverage, rule-safety, rule-verifiability, query-plan-safety, req-status-vocabulary, strict-fact-shape, strict-req-fact-pairing, predicate-verifiability, strict-readiness, semantic-completeness, related-requirement-unmodeled, proof-contract-symbols, entity-id-style, domain-redundancy, domain-implication, subject-key-identity, subject-key-shape, ontology-quality, exception-unapproved, exception-approval-self-attested, agent-requirement-unapproved, requirement-rationale-missing, symbol-owner-superseded, adr-unlinked, adr-proposed, predicate-schema-conformance, entity-context-missing, entity-context-acknowledged, decision-firm-unreferenced, decision-firm-superseded, decision-firm-edited, supersedes-reason-missing, supersedes-reason-acknowledged, policy-ownership, policy-markers, kb-consistency, kb-consistency-unresolved, evidence-floor, proof-contract-claims";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ENTITY_ORIGIN_SCHEMA } from "../../entity-origin.js";
|
|
2
|
+
import { EVIDENCE_LEVELS } from "../../evidence-levels.js";
|
|
2
3
|
import {
|
|
3
4
|
PROOF_BINDINGS_SCHEMA,
|
|
4
5
|
PROOF_CONTRACT_SCHEMA,
|
|
@@ -131,6 +132,12 @@ export const ENTITY_PROPERTIES_SCHEMA = {
|
|
|
131
132
|
description:
|
|
132
133
|
"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.",
|
|
133
134
|
},
|
|
135
|
+
required_evidence: {
|
|
136
|
+
type: "string",
|
|
137
|
+
enum: [...EVIDENCE_LEVELS],
|
|
138
|
+
description:
|
|
139
|
+
"Requirement-only. Weakest evidence level it accepts; the evidence-floor rule fails below it. Absent = tested if firm, else unverified.",
|
|
140
|
+
},
|
|
134
141
|
rationale: {
|
|
135
142
|
type: "string",
|
|
136
143
|
minLength: 1,
|
|
@@ -243,9 +250,9 @@ export const ENTITY_PROPERTIES_SCHEMA = {
|
|
|
243
250
|
},
|
|
244
251
|
value_type: {
|
|
245
252
|
type: "string",
|
|
246
|
-
enum: ["string", "int", "number", "bool"],
|
|
253
|
+
enum: ["string", "int", "number", "bool", "set"],
|
|
247
254
|
description:
|
|
248
|
-
"Optional typed value discriminator for property_value facts. Pair with exactly one value_string, value_int, value_number, or
|
|
255
|
+
"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.",
|
|
249
256
|
},
|
|
250
257
|
value_string: {
|
|
251
258
|
type: "string",
|
|
@@ -263,6 +270,14 @@ export const ENTITY_PROPERTIES_SCHEMA = {
|
|
|
263
270
|
type: "boolean",
|
|
264
271
|
description: "Optional boolean value for property_value facts.",
|
|
265
272
|
},
|
|
273
|
+
value_set: {
|
|
274
|
+
type: "array",
|
|
275
|
+
items: { type: "string", minLength: 1 },
|
|
276
|
+
minItems: 1,
|
|
277
|
+
uniqueItems: true,
|
|
278
|
+
description:
|
|
279
|
+
"Optional exact set of values for property_value facts with value_type set, such as the members a domain must have.",
|
|
280
|
+
},
|
|
266
281
|
unit: {
|
|
267
282
|
type: "string",
|
|
268
283
|
description: "Optional unit for numeric property_value facts.",
|
|
@@ -242,7 +242,7 @@ export async function perContractTestBindings(
|
|
|
242
242
|
): Promise<string | null> {
|
|
243
243
|
if (currentProofBindingMode() !== "per_contract") return null;
|
|
244
244
|
const { loadEntities } = await import("../discovery-entities.js");
|
|
245
|
-
const {
|
|
245
|
+
const { currentReceiptBindingHashes, loadCoveredBySymbolsByTest } =
|
|
246
246
|
await import("../../../operations/proof/code-scope.js");
|
|
247
247
|
// Only the contract, scoped code, and authored source feed the binding
|
|
248
248
|
// hash. The paged projection never materializes receipt histories, which
|
|
@@ -269,14 +269,19 @@ export async function perContractTestBindings(
|
|
|
269
269
|
if (testId === "" || fs === undefined) continue;
|
|
270
270
|
// The same computation ingest uses to write binding_hash. Unreadable or
|
|
271
271
|
// non-markdown documents keep strict snapshot semantics for that test.
|
|
272
|
-
const
|
|
272
|
+
const bindings = await currentReceiptBindingHashes({
|
|
273
273
|
workspaceRoot: context.workspaceRoot,
|
|
274
274
|
readFile: (absolute) => fs.readFile(absolute),
|
|
275
275
|
test,
|
|
276
276
|
coveredBySymbols: coveredBy.get(testId) ?? [],
|
|
277
277
|
});
|
|
278
|
-
if (
|
|
279
|
-
|
|
278
|
+
if (bindings !== undefined) {
|
|
279
|
+
// One hash, or the current and the earlier binding a receipt may carry.
|
|
280
|
+
const value =
|
|
281
|
+
bindings.length === 1
|
|
282
|
+
? toPrologAtom(bindings[0] as string)
|
|
283
|
+
: `[${bindings.map(toPrologAtom).join(", ")}]`;
|
|
284
|
+
entries.push(`${toPrologAtom(testId)}: ${value}`);
|
|
280
285
|
}
|
|
281
286
|
}
|
|
282
287
|
if (entries.length === 0) return null;
|
|
@@ -332,16 +337,21 @@ export async function executeCoverage(
|
|
|
332
337
|
const statuses = (input.statuses ?? []).map((status) =>
|
|
333
338
|
validateCoverageStatus(status),
|
|
334
339
|
);
|
|
340
|
+
// A status filter judges receipts with the same per-contract binding as
|
|
341
|
+
// the unfiltered report; otherwise its rows and summary disagree with
|
|
342
|
+
// every other proof view.
|
|
335
343
|
const bindingsDict =
|
|
336
|
-
|
|
344
|
+
(input.by ?? "req") === "req"
|
|
337
345
|
? await perContractTestBindings(context)
|
|
338
346
|
: null;
|
|
339
347
|
const goalFor = (limit: number, offset: number): string =>
|
|
340
|
-
bindingsDict !== null
|
|
341
|
-
? `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)`
|
|
342
|
-
:
|
|
343
|
-
? `discovery:coverage_report_json('${input.by ?? "req"}', ${toPrologList(input.tags)}, ${input.includePassing ?? false}, ${
|
|
344
|
-
:
|
|
348
|
+
bindingsDict !== null && statuses.length > 0
|
|
349
|
+
? `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)`
|
|
350
|
+
: bindingsDict !== null
|
|
351
|
+
? `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)`
|
|
352
|
+
: statuses.length > 0
|
|
353
|
+
? `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)`
|
|
354
|
+
: `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)`;
|
|
345
355
|
const payload = await readCoveragePages(
|
|
346
356
|
requireProlog(context),
|
|
347
357
|
goalFor,
|
|
@@ -0,0 +1,271 @@
|
|
|
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
|
+
/**
|
|
20
|
+
* Builders for the kibi.code-certificate.v1 a certificate-kind proof contract
|
|
21
|
+
* leaves for `kibi prove`. A test builds its certificate and writes it with
|
|
22
|
+
* writeCodeCertificate; outside `kibi prove` the write is a no-op, so the same
|
|
23
|
+
* test runs unchanged in an ordinary test run. Kibi re-checks every
|
|
24
|
+
* certificate at ingest and again whenever it reports evidence, so a
|
|
25
|
+
* certificate only records what the test did; it never vouches for itself.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { createHash } from "node:crypto";
|
|
29
|
+
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
30
|
+
import path from "node:path";
|
|
31
|
+
import { CODE_CERTIFICATE_VERSION } from "./proof-protocol.js";
|
|
32
|
+
|
|
33
|
+
/** Where `kibi prove` asks a run to leave its certificates. */
|
|
34
|
+
// implements REQ-kibi-code-proof-kinds
|
|
35
|
+
export const PROOF_CERTIFICATES_ENV = "KIBI_PROOF_CERTIFICATES";
|
|
36
|
+
|
|
37
|
+
// implements REQ-kibi-code-proof-kinds
|
|
38
|
+
export type CodeCertificate = Readonly<Record<string, unknown>> &
|
|
39
|
+
Readonly<{
|
|
40
|
+
version: typeof CODE_CERTIFICATE_VERSION;
|
|
41
|
+
kind: "exhaustive" | "typecheck" | "arithmetic" | "smt";
|
|
42
|
+
test_id: string;
|
|
43
|
+
}>;
|
|
44
|
+
|
|
45
|
+
function compareCodePoints(left: string, right: string): number {
|
|
46
|
+
const a = Array.from(left, (char) => char.codePointAt(0) ?? 0);
|
|
47
|
+
const b = Array.from(right, (char) => char.codePointAt(0) ?? 0);
|
|
48
|
+
for (let index = 0; index < Math.min(a.length, b.length); index++) {
|
|
49
|
+
const difference = (a[index] ?? 0) - (b[index] ?? 0);
|
|
50
|
+
if (difference !== 0) return difference;
|
|
51
|
+
}
|
|
52
|
+
return a.length - b.length;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const JSON_ESCAPES: Readonly<Record<string, string>> = {
|
|
56
|
+
'"': '\\"',
|
|
57
|
+
"\\": "\\\\",
|
|
58
|
+
"\b": "\\b",
|
|
59
|
+
"\f": "\\f",
|
|
60
|
+
"\n": "\\n",
|
|
61
|
+
"\r": "\\r",
|
|
62
|
+
"\t": "\\t",
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
function canonicalString(value: string): string {
|
|
66
|
+
let out = '"';
|
|
67
|
+
for (let index = 0; index < value.length; index++) {
|
|
68
|
+
const char = value[index] as string;
|
|
69
|
+
const unit = value.charCodeAt(index);
|
|
70
|
+
const escaped = JSON_ESCAPES[char];
|
|
71
|
+
if (escaped !== undefined) out += escaped;
|
|
72
|
+
else if (unit >= 0x20 && unit <= 0x7e) out += char;
|
|
73
|
+
else out += `\\u${unit.toString(16).padStart(4, "0")}`;
|
|
74
|
+
}
|
|
75
|
+
return `${out}"`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The canonical JSON of a certificate, byte for byte what
|
|
80
|
+
* code_certificates.pl hashes: keys sorted by code point, no whitespace,
|
|
81
|
+
* non-ASCII and control characters as \u escapes of UTF-16 code units.
|
|
82
|
+
*/
|
|
83
|
+
// implements REQ-kibi-code-proof-kinds
|
|
84
|
+
export function canonicalCertificateJson(value: unknown): string {
|
|
85
|
+
if (value === null || value === undefined) return "null";
|
|
86
|
+
if (Array.isArray(value))
|
|
87
|
+
return `[${value.map(canonicalCertificateJson).join(",")}]`;
|
|
88
|
+
if (typeof value === "object")
|
|
89
|
+
return `{${Object.keys(value)
|
|
90
|
+
.sort(compareCodePoints)
|
|
91
|
+
.map(
|
|
92
|
+
(key) =>
|
|
93
|
+
`${canonicalString(key)}:${canonicalCertificateJson((value as Record<string, unknown>)[key])}`,
|
|
94
|
+
)
|
|
95
|
+
.join(",")}}`;
|
|
96
|
+
if (typeof value === "string") return canonicalString(value);
|
|
97
|
+
return JSON.stringify(value);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** The sha256 a receipt records for its certificate. */
|
|
101
|
+
// implements REQ-kibi-code-proof-kinds
|
|
102
|
+
export function certificateDigest(certificate: unknown): string {
|
|
103
|
+
return createHash("sha256")
|
|
104
|
+
.update(canonicalCertificateJson(certificate), "utf8")
|
|
105
|
+
.digest("hex");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// implements REQ-kibi-code-proof-kinds
|
|
109
|
+
export type ExhaustiveResult = Readonly<{
|
|
110
|
+
member: string;
|
|
111
|
+
outcome: "passed" | "failed";
|
|
112
|
+
message?: string;
|
|
113
|
+
}>;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Run `check` on every member of a finite domain and record each outcome.
|
|
117
|
+
* `members` must be the domain as the code defines it (import it from its
|
|
118
|
+
* source, never restate it): Kibi rejects the certificate unless the proof
|
|
119
|
+
* file imports the contract's domain_source symbol.
|
|
120
|
+
*/
|
|
121
|
+
// implements REQ-kibi-code-proof-kinds
|
|
122
|
+
export async function exhaustiveCertificate<T>(input: {
|
|
123
|
+
testId: string;
|
|
124
|
+
domain: Readonly<{ symbolId: string; members: Iterable<T> }>;
|
|
125
|
+
key?: (member: T) => string;
|
|
126
|
+
check: (member: T) => void | Promise<void>;
|
|
127
|
+
}): Promise<CodeCertificate> {
|
|
128
|
+
const key = input.key ?? ((member: T) => String(member));
|
|
129
|
+
const members = [...input.domain.members];
|
|
130
|
+
const results: ExhaustiveResult[] = [];
|
|
131
|
+
for (const member of members) {
|
|
132
|
+
try {
|
|
133
|
+
await input.check(member);
|
|
134
|
+
results.push({ member: key(member), outcome: "passed" });
|
|
135
|
+
} catch (error) {
|
|
136
|
+
results.push({
|
|
137
|
+
member: key(member),
|
|
138
|
+
outcome: "failed",
|
|
139
|
+
message: error instanceof Error ? error.message : String(error),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
version: CODE_CERTIFICATE_VERSION,
|
|
145
|
+
kind: "exhaustive",
|
|
146
|
+
test_id: input.testId,
|
|
147
|
+
domain: {
|
|
148
|
+
symbol_id: input.domain.symbolId,
|
|
149
|
+
members: members.map(key),
|
|
150
|
+
},
|
|
151
|
+
results,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** The members an exhaustive certificate records as failed. */
|
|
156
|
+
// implements REQ-kibi-code-proof-kinds
|
|
157
|
+
export function failedMembers(certificate: CodeCertificate): string[] {
|
|
158
|
+
const results = Array.isArray(certificate.results)
|
|
159
|
+
? (certificate.results as ExhaustiveResult[])
|
|
160
|
+
: [];
|
|
161
|
+
return results
|
|
162
|
+
.filter((result) => result.outcome !== "passed")
|
|
163
|
+
.map((result) =>
|
|
164
|
+
result.message ? `${result.member}: ${result.message}` : result.member,
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* A type checker accepted `witnessPath`, a file that fails to compile when a
|
|
170
|
+
* member of the domain goes unhandled (an exhaustive switch ending in a
|
|
171
|
+
* `never` assignment, or a mapped type over the domain).
|
|
172
|
+
*/
|
|
173
|
+
// implements REQ-kibi-code-proof-kinds
|
|
174
|
+
export function typecheckCertificate(input: {
|
|
175
|
+
testId: string;
|
|
176
|
+
domainSymbolId: string;
|
|
177
|
+
witnessPath: string;
|
|
178
|
+
workspaceRoot?: string;
|
|
179
|
+
compiler: Readonly<{ name: string; version: string }>;
|
|
180
|
+
accepted: boolean;
|
|
181
|
+
}): CodeCertificate {
|
|
182
|
+
const absolute = path.resolve(
|
|
183
|
+
input.workspaceRoot ?? process.cwd(),
|
|
184
|
+
input.witnessPath,
|
|
185
|
+
);
|
|
186
|
+
return {
|
|
187
|
+
version: CODE_CERTIFICATE_VERSION,
|
|
188
|
+
kind: "typecheck",
|
|
189
|
+
test_id: input.testId,
|
|
190
|
+
domain: { symbol_id: input.domainSymbolId },
|
|
191
|
+
witness: {
|
|
192
|
+
path: input.witnessPath,
|
|
193
|
+
sha256: createHash("sha256")
|
|
194
|
+
.update(readFileSync(absolute, "utf8"))
|
|
195
|
+
.digest("hex"),
|
|
196
|
+
},
|
|
197
|
+
compiler: { ...input.compiler },
|
|
198
|
+
outcome: input.accepted ? "passed" : "failed",
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// implements REQ-kibi-code-proof-kinds
|
|
203
|
+
export type ArithmeticConstraint = Readonly<{
|
|
204
|
+
operator: "eq" | "neq" | "lt" | "lte" | "gt" | "gte";
|
|
205
|
+
value: number;
|
|
206
|
+
}>;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* A claim about one numeric variable that Kibi decides exactly: the
|
|
210
|
+
* assumptions must be satisfiable and must entail the claim for every value
|
|
211
|
+
* of the variable, not only the values a test happened to try.
|
|
212
|
+
*/
|
|
213
|
+
// implements REQ-kibi-code-proof-kinds
|
|
214
|
+
export function arithmeticCertificate(input: {
|
|
215
|
+
testId: string;
|
|
216
|
+
variable: string;
|
|
217
|
+
valueType: "int" | "real";
|
|
218
|
+
assumptions: readonly ArithmeticConstraint[];
|
|
219
|
+
claim: ArithmeticConstraint;
|
|
220
|
+
}): CodeCertificate {
|
|
221
|
+
return {
|
|
222
|
+
version: CODE_CERTIFICATE_VERSION,
|
|
223
|
+
kind: "arithmetic",
|
|
224
|
+
test_id: input.testId,
|
|
225
|
+
variable: input.variable,
|
|
226
|
+
value_type: input.valueType,
|
|
227
|
+
assumptions: input.assumptions.map((row) => ({ ...row })),
|
|
228
|
+
claim: { ...input.claim },
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* An SMT-LIB query whose unsat answer proves the claim (the query asserts
|
|
234
|
+
* the claim's negation). Kibi re-runs the named solver on the query.
|
|
235
|
+
*/
|
|
236
|
+
// implements REQ-kibi-code-proof-kinds
|
|
237
|
+
export function smtCertificate(input: {
|
|
238
|
+
testId: string;
|
|
239
|
+
solver: Readonly<{ name: "z3" | "cvc5"; version: string }>;
|
|
240
|
+
query: string;
|
|
241
|
+
result: string;
|
|
242
|
+
}): CodeCertificate {
|
|
243
|
+
return {
|
|
244
|
+
version: CODE_CERTIFICATE_VERSION,
|
|
245
|
+
kind: "smt",
|
|
246
|
+
test_id: input.testId,
|
|
247
|
+
solver: { ...input.solver },
|
|
248
|
+
query: input.query,
|
|
249
|
+
result: input.result,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Leave the certificate where `kibi prove` reads it. Returns the file written,
|
|
255
|
+
* or null outside a `kibi prove` run.
|
|
256
|
+
*/
|
|
257
|
+
// implements REQ-kibi-code-proof-kinds
|
|
258
|
+
export function writeCodeCertificate(
|
|
259
|
+
certificate: CodeCertificate,
|
|
260
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
261
|
+
): string | null {
|
|
262
|
+
const directory = env[PROOF_CERTIFICATES_ENV];
|
|
263
|
+
if (directory === undefined || directory.trim() === "") return null;
|
|
264
|
+
mkdirSync(directory, { recursive: true });
|
|
265
|
+
const file = path.join(
|
|
266
|
+
directory,
|
|
267
|
+
`${certificate.test_id.replace(/[^A-Za-z0-9._-]/g, "_")}.json`,
|
|
268
|
+
);
|
|
269
|
+
writeFileSync(file, `${JSON.stringify(certificate, null, 2)}\n`, "utf8");
|
|
270
|
+
return file;
|
|
271
|
+
}
|
|
@@ -24,7 +24,9 @@ export type RunFailurePhase =
|
|
|
24
24
|
| "execution"
|
|
25
25
|
| "teardown"
|
|
26
26
|
| "infrastructure";
|
|
27
|
-
export type SuccessPolicy =
|
|
27
|
+
export type SuccessPolicy =
|
|
28
|
+
| "all_required_first_attempt"
|
|
29
|
+
| "own_results_first_attempt";
|
|
28
30
|
|
|
29
31
|
export type ProofAttempt = Readonly<{
|
|
30
32
|
outcome: ProofResultOutcome;
|
|
@@ -72,6 +74,7 @@ export type ProofRunArtifact = Readonly<{
|
|
|
72
74
|
proof_results: readonly ProofResult[];
|
|
73
75
|
integration?: string;
|
|
74
76
|
diagnostics?: readonly string[];
|
|
77
|
+
certificates?: readonly Readonly<Record<string, unknown>>[];
|
|
75
78
|
}>;
|
|
76
79
|
|
|
77
80
|
export type ProofObligation = Readonly<{
|
|
@@ -84,6 +87,19 @@ export type ProofContract = Readonly<{
|
|
|
84
87
|
integration: string;
|
|
85
88
|
required_proofs: readonly ProofObligation[];
|
|
86
89
|
success_policy: SuccessPolicy;
|
|
90
|
+
kind?:
|
|
91
|
+
| "e2e"
|
|
92
|
+
| "example"
|
|
93
|
+
| "property"
|
|
94
|
+
| "exhaustive"
|
|
95
|
+
| "typecheck"
|
|
96
|
+
| "arithmetic"
|
|
97
|
+
| "smt";
|
|
98
|
+
domain_source?: Readonly<{ symbol_id: string; export?: string }>;
|
|
99
|
+
witness?: Readonly<{ path: string }>;
|
|
100
|
+
constraint_source?: Readonly<{ fact_ids: readonly string[] }>;
|
|
101
|
+
value_source?: readonly Readonly<{ symbol_id: string; export?: string }>[];
|
|
102
|
+
proves?: readonly string[];
|
|
87
103
|
}>;
|
|
88
104
|
|
|
89
105
|
export type ProofBinding = Readonly<{
|