kibi-cli 2.31.1 → 2.35.1
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/cli.d.ts.map +1 -1
- package/dist/cli.js +5 -1
- package/dist/commands/check-generated.d.ts +5 -1
- package/dist/commands/check-generated.d.ts.map +1 -1
- package/dist/commands/check-generated.js +24 -35
- 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/init-helpers.d.ts.map +1 -1
- package/dist/commands/init-helpers.js +8 -5
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +109 -5
- 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 +20 -1
- package/dist/commands/sync/manifest.d.ts +10 -1
- package/dist/commands/sync/manifest.d.ts.map +1 -1
- package/dist/commands/sync/manifest.js +106 -17
- package/dist/commands/sync/persistence.d.ts.map +1 -1
- package/dist/commands/sync/persistence.js +16 -5
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +19 -0
- package/dist/diagnostics.js +1 -1
- package/dist/engine.js +1 -1
- package/dist/extractors/markdown.d.ts +4 -2
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +17 -0
- package/dist/extractors/symbol-coordinates.js +2 -2
- package/dist/extractors/symbols-coordinator.d.ts +2 -4
- package/dist/extractors/symbols-coordinator.d.ts.map +1 -1
- package/dist/extractors/symbols-coordinator.js +1 -2
- 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 +72 -0
- package/dist/operations/migration/proof-contract-claims.d.ts.map +1 -0
- package/dist/operations/migration/proof-contract-claims.js +215 -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 +92 -0
- package/dist/operations/migration/symbol-coordinates-refresh.d.ts +3 -2
- package/dist/operations/migration/symbol-coordinates-refresh.d.ts.map +1 -1
- package/dist/operations/migration/symbol-coordinates-refresh.js +4 -3
- package/dist/operations/migration/untrack-symbol-coordinates.d.ts +23 -0
- package/dist/operations/migration/untrack-symbol-coordinates.d.ts.map +1 -0
- package/dist/operations/migration/untrack-symbol-coordinates.js +67 -0
- package/dist/operations/modeling/requirement-modeler.d.ts.map +1 -1
- package/dist/operations/modeling/requirement-modeler.js +48 -1
- package/dist/operations/modeling/requirement-types.d.ts +2 -1
- package/dist/operations/modeling/requirement-types.d.ts.map +1 -1
- package/dist/operations/modeling/requirement-utils.d.ts +1 -1
- package/dist/operations/modeling/requirement-utils.d.ts.map +1 -1
- package/dist/operations/modeling/requirement-utils.js +8 -1
- 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/source-authoring.d.ts.map +1 -1
- package/dist/operations/mutation/source-authoring.js +39 -20
- 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 +41 -0
- package/dist/operations/proof/claim-bindings.d.ts.map +1 -0
- package/dist/operations/proof/claim-bindings.js +364 -0
- package/dist/operations/proof/code-certificates.d.ts +155 -0
- package/dist/operations/proof/code-certificates.d.ts.map +1 -0
- package/dist/operations/proof/code-certificates.js +894 -0
- package/dist/operations/proof/code-models.d.ts +96 -0
- package/dist/operations/proof/code-models.d.ts.map +1 -0
- package/dist/operations/proof/code-models.js +601 -0
- package/dist/operations/proof/code-runner.d.ts +40 -0
- package/dist/operations/proof/code-runner.d.ts.map +1 -0
- package/dist/operations/proof/code-runner.js +164 -0
- package/dist/operations/proof/code-scope.d.ts +14 -1
- package/dist/operations/proof/code-scope.d.ts.map +1 -1
- package/dist/operations/proof/code-scope.js +44 -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 +42 -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/proof/regular-language.d.ts +89 -0
- package/dist/operations/proof/regular-language.d.ts.map +1 -0
- package/dist/operations/proof/regular-language.js +943 -0
- package/dist/operations/proof/source-code-readers.d.ts +12 -0
- package/dist/operations/proof/source-code-readers.d.ts.map +1 -0
- package/dist/operations/proof/source-code-readers.js +699 -0
- package/dist/operations/semantic-advisor/analyze-prose.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/analyze-prose.js +2 -1
- 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-count-rules.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/strict-count-rules.js +8 -2
- package/dist/operations/semantic-advisor/strict-rules.d.ts +8 -0
- package/dist/operations/semantic-advisor/strict-rules.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/strict-rules.js +234 -4
- package/dist/operations/semantic-advisor/types.d.ts +3 -2
- 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/prolog.d.ts.map +1 -1
- package/dist/prolog.js +13 -3
- 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 +315 -11
- 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/composite.d.ts +16 -3
- package/dist/public/operations/specs/composite.d.ts.map +1 -1
- package/dist/public/operations/specs/modeling.d.ts +16 -3
- package/dist/public/operations/specs/modeling.d.ts.map +1 -1
- package/dist/public/operations/specs/modeling.js +22 -3
- package/dist/public/operations/specs/mutation-schemas.d.ts +289 -7
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +28 -4
- 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 +289 -7
- package/dist/public/operations/specs/upsert.d.ts.map +1 -1
- package/dist/public/proof-certificates.d.ts +163 -0
- package/dist/public/proof-certificates.d.ts.map +1 -0
- package/dist/public/proof-certificates.js +419 -0
- package/dist/public/proof-protocol.d.ts +259 -3
- package/dist/public/proof-protocol.d.ts.map +1 -1
- package/dist/public/proof-protocol.js +524 -3
- package/dist/public/proof-receipt.d.ts +90 -6
- package/dist/public/proof-receipt.d.ts.map +1 -1
- package/dist/public/proof-receipt.js +88 -7
- package/dist/public/proof-sources.d.ts +102 -0
- package/dist/public/proof-sources.d.ts.map +1 -0
- package/dist/public/proof-sources.js +1292 -0
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +39 -2
- package/dist/public/skills/kibi-bootstrap/SKILL.md +2 -2
- package/dist/public/skills/kibi-commit-review/SKILL.md +8 -8
- package/dist/public/skills/kibi-commit-review/resources/staged-gate.md +12 -7
- package/dist/public/skills/kibi-decisions/SKILL.md +13 -2
- package/dist/public/skills/kibi-decisions/resources/decision-records.md +9 -1
- package/dist/public/skills/kibi-freshness/SKILL.md +5 -1
- package/dist/public/skills/kibi-traceability/SKILL.md +12 -1
- package/dist/public/skills/kibi-usage/SKILL.md +8 -4
- package/dist/public/skills/kibi-usage/resources/proof.md +221 -20
- package/dist/public/skills/kibi-usage/resources/workflows.md +4 -4
- package/dist/report/html-report.css +83 -11
- 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 +214 -22
- package/dist/report/report-view.d.ts +2 -2
- package/dist/report/report-view.d.ts.map +1 -1
- package/dist/report/report-view.js +8 -0
- package/dist/schemas/entity.schema.json +404 -5
- 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/evidence-model.d.ts +13 -12
- package/dist/traceability/evidence-model.d.ts.map +1 -1
- package/dist/traceability/evidence-model.js +1 -1
- package/dist/traceability/impact-knowledge.d.ts.map +1 -1
- package/dist/traceability/impact-knowledge.js +1 -0
- package/dist/traceability/staged-diagnostics.d.ts.map +1 -1
- package/dist/traceability/staged-diagnostics.js +24 -20
- package/dist/traceability/staged-impact-contract.d.ts +4 -4
- package/dist/traceability/staged-impact-contract.js +9 -9
- package/dist/traceability/staged-symbols-manifest.d.ts +11 -3
- package/dist/traceability/staged-symbols-manifest.d.ts.map +1 -1
- package/dist/traceability/staged-symbols-manifest.js +47 -140
- package/dist/traceability/temp-kb.d.ts.map +1 -1
- package/dist/traceability/temp-kb.js +1 -0
- package/dist/types/entities.d.ts +5 -2
- 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 +7 -1
- package/dist/utils/strict-modeling.d.ts +3 -2
- package/dist/utils/strict-modeling.d.ts.map +1 -1
- package/dist/utils/strict-modeling.js +37 -4
- package/dist/workspace-cwd.d.ts +15 -0
- package/dist/workspace-cwd.d.ts.map +1 -0
- package/dist/workspace-cwd.js +86 -0
- package/package.json +6 -2
- package/schema/entities.pl +6 -0
- package/schema/validation.pl +7 -2
- 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/modeling.ts +24 -5
- package/src/public/operations/specs/mutation-schemas.ts +30 -4
- package/src/public/operations/specs/reporting.ts +20 -10
- package/src/public/proof-certificates.ts +566 -0
- package/src/public/proof-protocol-types.d.ts +69 -1
- package/src/public/proof-protocol.ts +694 -3
- package/src/public/proof-receipt.ts +133 -7
- package/src/public/proof-sources.ts +1656 -0
- package/src/public/schemas/entity.ts +51 -3
- package/src/public/skills/kibi-bootstrap/SKILL.md +2 -2
- package/src/public/skills/kibi-commit-review/SKILL.md +8 -8
- package/src/public/skills/kibi-commit-review/resources/staged-gate.md +12 -7
- package/src/public/skills/kibi-decisions/SKILL.md +13 -2
- package/src/public/skills/kibi-decisions/resources/decision-records.md +9 -1
- package/src/public/skills/kibi-freshness/SKILL.md +5 -1
- package/src/public/skills/kibi-traceability/SKILL.md +12 -1
- package/src/public/skills/kibi-usage/SKILL.md +8 -4
- package/src/public/skills/kibi-usage/resources/proof.md +221 -20
- package/src/public/skills/kibi-usage/resources/workflows.md +4 -4
- package/src/schemas/entity.schema.json +404 -5
- 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
- package/dist/traceability/reviewed-coordinate-refresh.d.ts +0 -10
- package/dist/traceability/reviewed-coordinate-refresh.d.ts.map +0 -1
- package/dist/traceability/reviewed-coordinate-refresh.js +0 -49
|
@@ -0,0 +1,203 @@
|
|
|
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
|
+
import { readKbManifest } from "../../utils/kb-manifest.js";
|
|
20
|
+
import type { Violation } from "../../utils/rule-registry.js";
|
|
21
|
+
import { PROOF_RECEIPT_MAX_AGE_SECONDS } from "../proof-receipt.js";
|
|
22
|
+
import { runOperationJsonQuery, toPrologAtom } from "./prolog-json.js";
|
|
23
|
+
import type { OperationContext } from "./runtime-types.js";
|
|
24
|
+
import { readWorkspaceSnapshot } from "./workspace-snapshot.js";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The schema version from which a current requirement's evidence level must
|
|
28
|
+
* reach its floor; older KBs get the floor with their schema upgrade, whose
|
|
29
|
+
* migration records the floor of firm requirements without a proof path.
|
|
30
|
+
*/
|
|
31
|
+
// implements REQ-kibi-evidence-floors
|
|
32
|
+
export const EVIDENCE_FLOOR_SCHEMA_VERSION = 11;
|
|
33
|
+
|
|
34
|
+
/** A current requirement's evidence level must reach its floor. */
|
|
35
|
+
// implements REQ-kibi-evidence-floors
|
|
36
|
+
export const EVIDENCE_FLOOR_RULE = "evidence-floor";
|
|
37
|
+
|
|
38
|
+
// implements REQ-kibi-evidence-floors
|
|
39
|
+
export type EvidenceFloorRow = Readonly<{
|
|
40
|
+
id: string;
|
|
41
|
+
evidenceLevel: string;
|
|
42
|
+
requiredEvidence: string;
|
|
43
|
+
requiredEvidenceSource: string;
|
|
44
|
+
status: "below" | "pending_reproof";
|
|
45
|
+
proofStatus: string;
|
|
46
|
+
proofGaps: readonly string[];
|
|
47
|
+
/** The tests and symbols behind the gaps; empty lists are left out. */
|
|
48
|
+
gapDetails?: Readonly<Record<string, readonly string[]>>;
|
|
49
|
+
}>;
|
|
50
|
+
|
|
51
|
+
type EvidenceFloorPayload = {
|
|
52
|
+
readonly evaluated?: number;
|
|
53
|
+
readonly rows?: readonly EvidenceFloorRow[];
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export type EvidenceFloorOptions = Readonly<{
|
|
57
|
+
/**
|
|
58
|
+
* Judge receipts as they are: stale receipts no longer count as pending
|
|
59
|
+
* re-proof, and the proof snapshot must be clean. CI uses it right after
|
|
60
|
+
* `kibi prove --all`.
|
|
61
|
+
*/
|
|
62
|
+
freshEvidence?: boolean;
|
|
63
|
+
}>;
|
|
64
|
+
|
|
65
|
+
function floorSource(row: EvidenceFloorRow): string {
|
|
66
|
+
return row.requiredEvidenceSource === "explicit"
|
|
67
|
+
? "its required_evidence"
|
|
68
|
+
: row.requiredEvidence === "tested"
|
|
69
|
+
? "the floor of a firm requirement"
|
|
70
|
+
: "its floor";
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const GAP_DETAIL_LABELS: Readonly<Record<string, string>> = {
|
|
74
|
+
failedReceiptTests: "failing receipts",
|
|
75
|
+
missingReceiptTests: "no receipt",
|
|
76
|
+
staleReceiptTests: "stale receipts",
|
|
77
|
+
invalidReceiptTests: "invalid receipts",
|
|
78
|
+
contractMismatchReceiptTests: "receipts for an older contract",
|
|
79
|
+
uncoveredSymbols: "production symbols without qualifying coverage",
|
|
80
|
+
missingCoordinateSymbols: "symbols without source coordinates",
|
|
81
|
+
unprovedClaims: "claims no certificate derives",
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/** The entities behind the gaps, for a person reading kibi check's text. */
|
|
85
|
+
// implements REQ-kibi-evidence-floors
|
|
86
|
+
export function gapDetailLines(row: EvidenceFloorRow): string[] {
|
|
87
|
+
return Object.entries(row.gapDetails ?? {}).flatMap(([key, ids]) =>
|
|
88
|
+
ids.length === 0
|
|
89
|
+
? []
|
|
90
|
+
: [
|
|
91
|
+
`${GAP_DETAIL_LABELS[key] ?? key}: ${ids.slice(0, 8).join(", ")}${ids.length > 8 ? ` (+${ids.length - 8} more)` : ""}`,
|
|
92
|
+
],
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function suggestionFor(row: EvidenceFloorRow): string {
|
|
97
|
+
if (row.status === "pending_reproof")
|
|
98
|
+
return `Run kibi prove for the tests behind ${row.id} so its receipts match the current code, then rerun kibi check --fresh-evidence.`;
|
|
99
|
+
switch (row.requiredEvidence) {
|
|
100
|
+
case "proved":
|
|
101
|
+
return `Prove every applicable claim of ${row.id}${(row.gapDetails?.unprovedClaims ?? []).length > 0 ? ` (unproved: ${(row.gapDetails?.unprovedClaims ?? []).join(", ")})` : ""}: model each as a set fact (prove it with exhaustive or typecheck), a numeric fact (arithmetic or smt), a rule, predicate or set fact about a predicate (rule or state_machine) or a string fact (regex), name it in a certificate test's proof_contract.proves, and run kibi prove; kibi proof explain ${row.id} shows each claim's bindings. A claim with no such fact can only be attested, so lower required_evidence to tested with the reason in the requirement if that is enough.`;
|
|
102
|
+
case "tested":
|
|
103
|
+
return `Link ${row.id} to a scenario with an end-to-end test that has a proof contract, run kibi prove, and fix its proof gaps (${row.proofGaps.join(", ") || "none listed"}${gapDetailLines(row).length > 0 ? `; ${gapDetailLines(row).join("; ")}` : ""}); kibi proof explain ${row.id} shows each one. Or lower required_evidence if a person decides it does not need tests.`;
|
|
104
|
+
default:
|
|
105
|
+
return `Have a person approve ${row.id} (origin.approved_by) or state it as firm with origin.ref to their words, or lower required_evidence.`;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** One finding per current requirement whose evidence is below its floor. */
|
|
110
|
+
// implements REQ-kibi-evidence-floors
|
|
111
|
+
export function evidenceFloorViolations(
|
|
112
|
+
rows: readonly EvidenceFloorRow[],
|
|
113
|
+
options: EvidenceFloorOptions = {},
|
|
114
|
+
): Violation[] {
|
|
115
|
+
return rows
|
|
116
|
+
.filter((row) => options.freshEvidence === true || row.status === "below")
|
|
117
|
+
.map((row) => ({
|
|
118
|
+
rule: EVIDENCE_FLOOR_RULE,
|
|
119
|
+
entityId: row.id,
|
|
120
|
+
description:
|
|
121
|
+
row.status === "pending_reproof"
|
|
122
|
+
? `${row.id} is ${row.evidenceLevel} but needs ${row.requiredEvidence} (${floorSource(row)}); its receipts are older than the code`
|
|
123
|
+
: `${row.id} is ${row.evidenceLevel} but needs ${row.requiredEvidence} (${floorSource(row)})`,
|
|
124
|
+
suggestion: suggestionFor(row),
|
|
125
|
+
evidence: {
|
|
126
|
+
evidenceLevel: row.evidenceLevel,
|
|
127
|
+
requiredEvidence: row.requiredEvidence,
|
|
128
|
+
requiredEvidenceSource: row.requiredEvidenceSource,
|
|
129
|
+
status: row.status,
|
|
130
|
+
proofStatus: row.proofStatus,
|
|
131
|
+
proofGaps: row.proofGaps,
|
|
132
|
+
...(row.gapDetails === undefined ? {} : { gapDetails: row.gapDetails }),
|
|
133
|
+
},
|
|
134
|
+
}));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Every current requirement whose evidence is below its floor (status below
|
|
139
|
+
* or pending_reproof), judged on the attached store with the same
|
|
140
|
+
* per-contract receipt binding kb_coverage uses. Unlike the check rule this
|
|
141
|
+
* ignores the schema version, so a migration can read the floor the ladder
|
|
142
|
+
* will apply before it records the new schema.
|
|
143
|
+
*/
|
|
144
|
+
// implements REQ-kibi-evidence-floors
|
|
145
|
+
export async function readEvidenceFloorRows(
|
|
146
|
+
context: OperationContext,
|
|
147
|
+
snapshotEvidence?: Awaited<ReturnType<typeof readWorkspaceSnapshot>>,
|
|
148
|
+
): Promise<readonly EvidenceFloorRow[]> {
|
|
149
|
+
const prolog = context.prolog ?? (await context.ensureProlog?.());
|
|
150
|
+
if (prolog === undefined) return [];
|
|
151
|
+
const evidence = snapshotEvidence ?? (await readWorkspaceSnapshot(context));
|
|
152
|
+
const snapshot = evidence.available ? evidence.snapshot.hash : "unknown";
|
|
153
|
+
const { perContractTestBindings } = await import("./specs/reporting.js");
|
|
154
|
+
const bindings = await perContractTestBindings({ ...context, prolog });
|
|
155
|
+
const checkedAt = context.clock().toISOString();
|
|
156
|
+
const goal = `discovery:evidence_floor_json(${bindings === null ? "strict_snapshot, _{}" : `per_contract, ${bindings}`}, ${toPrologAtom(snapshot)}, ${toPrologAtom(checkedAt)}, ${PROOF_RECEIPT_MAX_AGE_SECONDS}, JsonString)`;
|
|
157
|
+
const payload = await runOperationJsonQuery<EvidenceFloorPayload>(
|
|
158
|
+
prolog,
|
|
159
|
+
"discovery.pl",
|
|
160
|
+
goal,
|
|
161
|
+
"Evidence floor evaluation",
|
|
162
|
+
);
|
|
163
|
+
return payload.rows ?? [];
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Evaluate the evidence-floor rule against the attached store, with the same
|
|
168
|
+
* per-contract receipt binding kb_coverage uses.
|
|
169
|
+
*/
|
|
170
|
+
// implements REQ-kibi-evidence-floors
|
|
171
|
+
export async function collectEvidenceFloorViolations(
|
|
172
|
+
context: OperationContext,
|
|
173
|
+
rules: ReadonlySet<string>,
|
|
174
|
+
options: EvidenceFloorOptions = {},
|
|
175
|
+
): Promise<Violation[]> {
|
|
176
|
+
if (!rules.has(EVIDENCE_FLOOR_RULE) || context.prolog === undefined)
|
|
177
|
+
return [];
|
|
178
|
+
// A store without a manifest predates schema 11 as much as an old one.
|
|
179
|
+
const schemaVersion = readKbManifest(context.workspaceRoot)?.schemaVersion;
|
|
180
|
+
if (
|
|
181
|
+
schemaVersion === undefined ||
|
|
182
|
+
schemaVersion < EVIDENCE_FLOOR_SCHEMA_VERSION
|
|
183
|
+
)
|
|
184
|
+
return [];
|
|
185
|
+
const snapshotEvidence = await readWorkspaceSnapshot(context);
|
|
186
|
+
const rows = await readEvidenceFloorRows(context, snapshotEvidence);
|
|
187
|
+
const violations = evidenceFloorViolations(rows, options);
|
|
188
|
+
if (options.freshEvidence === true) {
|
|
189
|
+
const clean =
|
|
190
|
+
snapshotEvidence.available && snapshotEvidence.snapshot.dirty === false;
|
|
191
|
+
if (!clean)
|
|
192
|
+
violations.unshift({
|
|
193
|
+
rule: EVIDENCE_FLOOR_RULE,
|
|
194
|
+
entityId: "proof-snapshot",
|
|
195
|
+
description: snapshotEvidence.available
|
|
196
|
+
? "--fresh-evidence needs a clean proof snapshot, but the working tree has uncommitted changes"
|
|
197
|
+
: `--fresh-evidence needs a proof snapshot, but none is available: ${snapshotEvidence.error}`,
|
|
198
|
+
suggestion:
|
|
199
|
+
"Commit or stash working-tree changes (or run inside a Git checkout), run kibi prove, then rerun kibi check --fresh-evidence.",
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
return violations;
|
|
203
|
+
}
|
|
@@ -297,8 +297,11 @@ export function mergeMigrationPlans(
|
|
|
297
297
|
});
|
|
298
298
|
}
|
|
299
299
|
|
|
300
|
+
/** How many automatic actions a plan digest lists by id. */
|
|
301
|
+
const DIGEST_AUTOMATIC_ACTIONS = 20;
|
|
302
|
+
|
|
300
303
|
export const MIGRATION_PLAN_DIGEST_VERSION =
|
|
301
|
-
"kibi.migration-plan-digest.
|
|
304
|
+
"kibi.migration-plan-digest.v2" as const;
|
|
302
305
|
|
|
303
306
|
export type MigrationPlanDigest = Readonly<{
|
|
304
307
|
version: typeof MIGRATION_PLAN_DIGEST_VERSION;
|
|
@@ -307,7 +310,20 @@ export type MigrationPlanDigest = Readonly<{
|
|
|
307
310
|
expected: MigrationPlan["expected"];
|
|
308
311
|
scope: MigrationPlan["scope"];
|
|
309
312
|
summary: MigrationPlan["summary"];
|
|
310
|
-
|
|
313
|
+
/** The first automatic actions, by id; automaticSummary counts them all. */
|
|
314
|
+
automaticActions: readonly Readonly<{
|
|
315
|
+
id: string;
|
|
316
|
+
code: string;
|
|
317
|
+
state: MigrationActionState;
|
|
318
|
+
autoApplicable: boolean;
|
|
319
|
+
dependsOn: readonly string[];
|
|
320
|
+
}>[];
|
|
321
|
+
automaticSummary: Readonly<{
|
|
322
|
+
total: number;
|
|
323
|
+
ready: number;
|
|
324
|
+
blocked: number;
|
|
325
|
+
omitted: number;
|
|
326
|
+
}>;
|
|
311
327
|
actionGroups: readonly Readonly<{
|
|
312
328
|
code: string;
|
|
313
329
|
safety: MigrationSafety;
|
|
@@ -320,9 +336,10 @@ export type MigrationPlanDigest = Readonly<{
|
|
|
320
336
|
|
|
321
337
|
/**
|
|
322
338
|
* A bounded summary of a plan for responses that report what is left rather
|
|
323
|
-
* than hand over a plan to apply: automatic actions
|
|
324
|
-
* action is counted by code. The full
|
|
325
|
-
* coverage
|
|
339
|
+
* than hand over a plan to apply: the first automatic actions are listed by
|
|
340
|
+
* id and all of them counted, every other action is counted by code. The full
|
|
341
|
+
* plan comes from status, check and coverage, so a response stays small even
|
|
342
|
+
* when hundreds of actions remain.
|
|
326
343
|
*/
|
|
327
344
|
// implements REQ-agent-guided-migration-orchestration
|
|
328
345
|
export function digestMigrationPlan(plan: MigrationPlan): MigrationPlanDigest {
|
|
@@ -365,7 +382,23 @@ export function digestMigrationPlan(plan: MigrationPlan): MigrationPlanDigest {
|
|
|
365
382
|
expected: plan.expected,
|
|
366
383
|
scope: plan.scope,
|
|
367
384
|
summary: plan.summary,
|
|
368
|
-
automaticActions
|
|
385
|
+
automaticActions: automaticActions
|
|
386
|
+
.slice(0, DIGEST_AUTOMATIC_ACTIONS)
|
|
387
|
+
.map((action) => ({
|
|
388
|
+
id: action.id,
|
|
389
|
+
code: action.code,
|
|
390
|
+
state: action.state,
|
|
391
|
+
autoApplicable: action.autoApplicable,
|
|
392
|
+
dependsOn: action.dependsOn,
|
|
393
|
+
})),
|
|
394
|
+
automaticSummary: {
|
|
395
|
+
total: automaticActions.length,
|
|
396
|
+
ready: automaticActions.filter(
|
|
397
|
+
(action) => action.state === "ready" && action.autoApplicable,
|
|
398
|
+
).length,
|
|
399
|
+
blocked: blockedAutomatic,
|
|
400
|
+
omitted: Math.max(0, automaticActions.length - DIGEST_AUTOMATIC_ACTIONS),
|
|
401
|
+
},
|
|
369
402
|
actionGroups: [...groups.values()].sort(
|
|
370
403
|
(left, right) =>
|
|
371
404
|
right.count - left.count ||
|
|
@@ -79,7 +79,9 @@ function isReceiptOnlyMarkdownChange(
|
|
|
79
79
|
const committed = execFileSync(
|
|
80
80
|
"git",
|
|
81
81
|
["-C", workspaceRoot, "show", `HEAD:${relativePath}`],
|
|
82
|
-
|
|
82
|
+
// A file staged but not committed yet has no HEAD blob; git's error is
|
|
83
|
+
// expected here and must not reach the terminal.
|
|
84
|
+
{ encoding: "buffer", maxBuffer: 64 * 1024 * 1024, stdio: "pipe" },
|
|
83
85
|
) as Buffer;
|
|
84
86
|
return working.equals(snapshotFileContent(relativePath, committed));
|
|
85
87
|
} catch {
|
|
@@ -0,0 +1,103 @@
|
|
|
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
|
+
import { readKbManifest } from "../../utils/kb-manifest.js";
|
|
20
|
+
import type { Violation } from "../../utils/rule-registry.js";
|
|
21
|
+
import { runOperationJsonQuery } from "./prolog-json.js";
|
|
22
|
+
import type { OperationContext } from "./runtime-types.js";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The schema version from which every certificate-kind proof contract must
|
|
26
|
+
* name the claims it proves; older KBs get the rule with their schema
|
|
27
|
+
* upgrade, whose migration pins proves where the claim is unambiguous.
|
|
28
|
+
*/
|
|
29
|
+
// implements REQ-kibi-claim-bound-proofs
|
|
30
|
+
export const CLAIM_BINDING_SCHEMA_VERSION = 12;
|
|
31
|
+
|
|
32
|
+
/** A certificate-kind proof contract must name provable claims in proves. */
|
|
33
|
+
// implements REQ-kibi-claim-bound-proofs
|
|
34
|
+
export const PROOF_CONTRACT_CLAIMS_RULE = "proof-contract-claims";
|
|
35
|
+
|
|
36
|
+
// implements REQ-kibi-claim-bound-proofs
|
|
37
|
+
export type ProofContractClaimIssue = Readonly<{
|
|
38
|
+
test_id: string;
|
|
39
|
+
claim_key?: string;
|
|
40
|
+
reason: string;
|
|
41
|
+
}>;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Every certificate-kind proof contract that names no claims, and every
|
|
45
|
+
* named claim no certificate of its kind could prove. Ignores the schema
|
|
46
|
+
* version, so a migration can read what the rule will report.
|
|
47
|
+
*/
|
|
48
|
+
// implements REQ-kibi-claim-bound-proofs
|
|
49
|
+
export async function readProofContractClaimIssues(
|
|
50
|
+
context: OperationContext,
|
|
51
|
+
): Promise<readonly ProofContractClaimIssue[]> {
|
|
52
|
+
const prolog = context.prolog ?? (await context.ensureProlog?.());
|
|
53
|
+
if (prolog === undefined) return [];
|
|
54
|
+
return runOperationJsonQuery<ProofContractClaimIssue[]>(
|
|
55
|
+
prolog,
|
|
56
|
+
"claim_obligations.pl",
|
|
57
|
+
"claim_obligations:proof_contract_claim_issues_json(JsonString)",
|
|
58
|
+
"Proof contract claims",
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** One finding per contract without proves and per unprovable claim key. */
|
|
63
|
+
// implements REQ-kibi-claim-bound-proofs
|
|
64
|
+
export function proofContractClaimViolations(
|
|
65
|
+
issues: readonly ProofContractClaimIssue[],
|
|
66
|
+
): Violation[] {
|
|
67
|
+
return issues.map((issue) => ({
|
|
68
|
+
rule: PROOF_CONTRACT_CLAIMS_RULE,
|
|
69
|
+
entityId: issue.test_id,
|
|
70
|
+
description:
|
|
71
|
+
issue.claim_key === undefined
|
|
72
|
+
? `${issue.test_id}: ${issue.reason}`
|
|
73
|
+
: `${issue.test_id} proves ${issue.claim_key}: ${issue.reason}`,
|
|
74
|
+
suggestion:
|
|
75
|
+
issue.claim_key === undefined
|
|
76
|
+
? `Add proof_contract.proves to ${issue.test_id} with the claim keys (CLAIM-...) of the requirement its certificate establishes; kibi proof explain on the requirement lists its claims.`
|
|
77
|
+
: `Name a modeled claim of a requirement ${issue.test_id} reaches through its scenarios, grounded by a fact this proof kind can express (a set fact for exhaustive or typecheck, a numeric fact for arithmetic or smt, a rule, predicate or set fact for rule or state_machine, a string fact for regex), or remove ${issue.claim_key} from proves.`,
|
|
78
|
+
evidence: {
|
|
79
|
+
testId: issue.test_id,
|
|
80
|
+
...(issue.claim_key === undefined ? {} : { claimKey: issue.claim_key }),
|
|
81
|
+
reason: issue.reason,
|
|
82
|
+
},
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Evaluate the proof-contract-claims rule from schema 12. */
|
|
87
|
+
// implements REQ-kibi-claim-bound-proofs
|
|
88
|
+
export async function collectProofContractClaimViolations(
|
|
89
|
+
context: OperationContext,
|
|
90
|
+
rules: ReadonlySet<string>,
|
|
91
|
+
): Promise<Violation[]> {
|
|
92
|
+
if (!rules.has(PROOF_CONTRACT_CLAIMS_RULE) || context.prolog === undefined)
|
|
93
|
+
return [];
|
|
94
|
+
const schemaVersion = readKbManifest(context.workspaceRoot)?.schemaVersion;
|
|
95
|
+
if (
|
|
96
|
+
schemaVersion === undefined ||
|
|
97
|
+
schemaVersion < CLAIM_BINDING_SCHEMA_VERSION
|
|
98
|
+
)
|
|
99
|
+
return [];
|
|
100
|
+
return proofContractClaimViolations(
|
|
101
|
+
await readProofContractClaimIssues(context),
|
|
102
|
+
);
|
|
103
|
+
}
|
|
@@ -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";
|
|
@@ -55,13 +55,32 @@ export const modelRequirementSpec = {
|
|
|
55
55
|
},
|
|
56
56
|
operator: {
|
|
57
57
|
type: "string",
|
|
58
|
-
enum: [
|
|
59
|
-
|
|
60
|
-
"
|
|
58
|
+
enum: [
|
|
59
|
+
"eq",
|
|
60
|
+
"gt",
|
|
61
|
+
"gte",
|
|
62
|
+
"lt",
|
|
63
|
+
"lte",
|
|
64
|
+
"neq",
|
|
65
|
+
"bool",
|
|
66
|
+
"polarity",
|
|
67
|
+
"matches",
|
|
68
|
+
"includes",
|
|
69
|
+
"subset_of",
|
|
70
|
+
"excludes",
|
|
71
|
+
],
|
|
72
|
+
description:
|
|
73
|
+
"Optional extracted semantic claim operator. Use gt/lt for strict bounds ('greater than zero' is gt 0, not gte 0). A set claim takes a list value with eq (exactly these), includes (at least these), subset_of (only these) or excludes (none of these); matches takes a regular expression string. Example: 'eq'.",
|
|
61
74
|
},
|
|
62
75
|
value: {
|
|
63
|
-
|
|
64
|
-
|
|
76
|
+
anyOf: [
|
|
77
|
+
{ type: "string" },
|
|
78
|
+
{ type: "number" },
|
|
79
|
+
{ type: "boolean" },
|
|
80
|
+
{ type: "array", items: { type: "string" }, minItems: 1 },
|
|
81
|
+
],
|
|
82
|
+
description:
|
|
83
|
+
"Optional extracted semantic claim value: a string, number or boolean, or a list of strings for a set claim. Example: ['requireAuth'] with operator includes.",
|
|
65
84
|
},
|
|
66
85
|
provenance: {
|
|
67
86
|
type: "string",
|
|
@@ -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,
|
|
@@ -237,15 +244,26 @@ export const ENTITY_PROPERTIES_SCHEMA = {
|
|
|
237
244
|
},
|
|
238
245
|
operator: {
|
|
239
246
|
type: "string",
|
|
240
|
-
enum: [
|
|
247
|
+
enum: [
|
|
248
|
+
"eq",
|
|
249
|
+
"neq",
|
|
250
|
+
"lt",
|
|
251
|
+
"lte",
|
|
252
|
+
"gt",
|
|
253
|
+
"gte",
|
|
254
|
+
"matches",
|
|
255
|
+
"includes",
|
|
256
|
+
"subset_of",
|
|
257
|
+
"excludes",
|
|
258
|
+
],
|
|
241
259
|
description:
|
|
242
|
-
"Optional comparison operator for property_value facts. Example: 'eq'.",
|
|
260
|
+
"Optional comparison operator for property_value facts. Example: 'eq'. 'matches' (string facts only): value_string is a JavaScript regular expression (u flag) every value must match as a whole. Set facts only: 'includes' means every member of value_set has the property and other members may have it too; 'subset_of' means every member that has the property is in value_set ('every env var the server reads is one of ...'); 'excludes' means no member of value_set has it ('never imports md5'); 'eq' on a set means exactly those members.",
|
|
243
261
|
},
|
|
244
262
|
value_type: {
|
|
245
263
|
type: "string",
|
|
246
|
-
enum: ["string", "int", "number", "bool"],
|
|
264
|
+
enum: ["string", "int", "number", "bool", "set"],
|
|
247
265
|
description:
|
|
248
|
-
"Optional typed value discriminator for property_value facts. Pair with exactly one value_string, value_int, value_number, or
|
|
266
|
+
"Optional typed value discriminator for property_value facts. Pair with exactly one value_string, value_int, value_number, value_bool, or value_set (set: a list of members, with operator eq, includes, subset_of or excludes); do not use generic value.",
|
|
249
267
|
},
|
|
250
268
|
value_string: {
|
|
251
269
|
type: "string",
|
|
@@ -263,6 +281,14 @@ export const ENTITY_PROPERTIES_SCHEMA = {
|
|
|
263
281
|
type: "boolean",
|
|
264
282
|
description: "Optional boolean value for property_value facts.",
|
|
265
283
|
},
|
|
284
|
+
value_set: {
|
|
285
|
+
type: "array",
|
|
286
|
+
items: { type: "string", minLength: 1 },
|
|
287
|
+
minItems: 1,
|
|
288
|
+
uniqueItems: true,
|
|
289
|
+
description:
|
|
290
|
+
"Optional exact set of values for property_value facts with value_type set, such as the members a domain must have.",
|
|
291
|
+
},
|
|
266
292
|
unit: {
|
|
267
293
|
type: "string",
|
|
268
294
|
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,
|