kibi-cli 2.36.0 → 2.39.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-json-command.d.ts.map +1 -1
- package/dist/cli-json-command.js +4 -0
- package/dist/cli-operation-metadata.d.ts +1 -1
- package/dist/cli-operation-metadata.js +1 -1
- package/dist/cli-register-foundation.d.ts.map +1 -1
- package/dist/cli-register-foundation.js +2 -1
- package/dist/cli-register-maintenance.d.ts.map +1 -1
- package/dist/cli-register-maintenance.js +5 -0
- package/dist/cli-register-reporting.d.ts.map +1 -1
- package/dist/cli-register-reporting.js +1 -0
- package/dist/cli-validate.d.ts.map +1 -1
- package/dist/cli-validate.js +21 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +19 -1
- package/dist/commands/aggregated-checks.d.ts.map +1 -1
- package/dist/commands/aggregated-checks.js +89 -16
- package/dist/commands/coverage.d.ts +1 -0
- package/dist/commands/coverage.d.ts.map +1 -1
- package/dist/commands/coverage.js +40 -0
- package/dist/commands/doctor.d.ts +5 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +70 -35
- package/dist/commands/github-init.d.ts.map +1 -1
- package/dist/commands/github-init.js +4 -2
- package/dist/commands/hook-managers.d.ts +43 -0
- package/dist/commands/hook-managers.d.ts.map +1 -0
- package/dist/commands/hook-managers.js +426 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +40 -5
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +9 -3
- package/dist/commands/sync/persistence.d.ts.map +1 -1
- package/dist/commands/sync/persistence.js +49 -1
- package/dist/commands/telemetry.d.ts +7 -0
- package/dist/commands/telemetry.d.ts.map +1 -0
- package/dist/commands/telemetry.js +23 -0
- package/dist/decision-firmness.d.ts.map +1 -1
- package/dist/decision-firmness.js +11 -14
- package/dist/engine-limits.d.ts.map +1 -1
- package/dist/engine-limits.js +8 -10
- package/dist/entity-body-context.d.ts.map +1 -1
- package/dist/entity-body-context.js +39 -36
- package/dist/extractors/markdown.d.ts +6 -0
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +21 -0
- package/dist/extractors/symbol-coordinates.d.ts.map +1 -1
- package/dist/extractors/symbol-coordinates.js +23 -4
- package/dist/firm-decision-edit.d.ts.map +1 -1
- package/dist/firm-decision-edit.js +1 -3
- package/dist/intent-search.d.ts +5 -1
- package/dist/intent-search.d.ts.map +1 -1
- package/dist/intent-search.js +118 -33
- package/dist/logic/ir.d.ts.map +1 -1
- package/dist/logic/ir.js +82 -108
- package/dist/operations/bootstrap/discovery-evidence.d.ts.map +1 -1
- package/dist/operations/bootstrap/discovery-evidence.js +44 -2
- package/dist/operations/bootstrap/discovery.d.ts.map +1 -1
- package/dist/operations/bootstrap/discovery.js +1 -0
- package/dist/operations/bootstrap/guidance-actions.d.ts.map +1 -1
- package/dist/operations/bootstrap/guidance-actions.js +2 -1
- package/dist/operations/bootstrap/plugin-offers.d.ts +11 -2
- package/dist/operations/bootstrap/plugin-offers.d.ts.map +1 -1
- package/dist/operations/bootstrap/plugin-offers.js +48 -9
- package/dist/operations/proof/claim-bindings.d.ts.map +1 -1
- package/dist/operations/proof/claim-bindings.js +1 -0
- package/dist/operations/proof/code-certificates.d.ts +2 -0
- package/dist/operations/proof/code-certificates.d.ts.map +1 -1
- package/dist/operations/proof/code-certificates.js +34 -14
- package/dist/operations/proof/code-models.d.ts.map +1 -1
- package/dist/operations/proof/code-models.js +19 -5
- package/dist/operations/proof/code-runner.d.ts +16 -0
- package/dist/operations/proof/code-runner.d.ts.map +1 -1
- package/dist/operations/proof/code-runner.js +42 -6
- package/dist/operations/proof/explain.d.ts +63 -0
- package/dist/operations/proof/explain.d.ts.map +1 -1
- package/dist/operations/proof/explain.js +162 -0
- package/dist/operations/semantic-advisor/analyze-prose.d.ts +9 -1
- package/dist/operations/semantic-advisor/analyze-prose.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/analyze-prose.js +21 -0
- package/dist/operations/semantic-advisor/case-preview.d.ts +24 -0
- package/dist/operations/semantic-advisor/case-preview.d.ts.map +1 -0
- package/dist/operations/semantic-advisor/case-preview.js +216 -0
- package/dist/operations/semantic-advisor/shared.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/shared.js +3 -0
- package/dist/operations/semantic-advisor/types.d.ts +23 -0
- package/dist/operations/semantic-advisor/types.d.ts.map +1 -1
- package/dist/plugins/approved-source-analyzers.generated.d.ts +11 -8
- package/dist/plugins/approved-source-analyzers.generated.d.ts.map +1 -1
- package/dist/plugins/approved-source-analyzers.generated.js +11 -8
- package/dist/plugins/compose-search-hints.d.ts +29 -0
- package/dist/plugins/compose-search-hints.d.ts.map +1 -0
- package/dist/plugins/compose-search-hints.js +94 -0
- package/dist/plugins/external-allowlist.d.ts +7 -0
- package/dist/plugins/external-allowlist.d.ts.map +1 -1
- package/dist/plugins/external-allowlist.js +11 -0
- package/dist/plugins/registry.d.ts +8 -1
- package/dist/plugins/registry.d.ts.map +1 -1
- package/dist/plugins/registry.js +22 -3
- package/dist/plugins/source-classification.d.ts +2 -2
- package/dist/plugins/source-classification.d.ts.map +1 -1
- package/dist/plugins/source-classification.js +25 -1
- package/dist/prolog/codec.d.ts.map +1 -1
- package/dist/prolog/codec.js +10 -20
- package/dist/public/impact/coverage-depth-quality.d.ts.map +1 -1
- package/dist/public/impact/coverage-depth-quality.js +32 -16
- package/dist/public/impact/full-kb-quality.d.ts +6 -0
- package/dist/public/impact/full-kb-quality.d.ts.map +1 -1
- package/dist/public/impact/full-kb-quality.js +8 -3
- package/dist/public/impact/requirement-quality.d.ts.map +1 -1
- package/dist/public/impact/requirement-quality.js +56 -29
- package/dist/public/operations/catalog.d.ts +44 -4
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/check-executor.d.ts +6 -0
- package/dist/public/operations/check-executor.d.ts.map +1 -1
- package/dist/public/operations/check-executor.js +34 -2
- package/dist/public/operations/discovery-executors.d.ts +5 -1
- package/dist/public/operations/discovery-executors.d.ts.map +1 -1
- package/dist/public/operations/discovery-executors.js +65 -4
- package/dist/public/operations/evidence-floor.d.ts +8 -1
- package/dist/public/operations/evidence-floor.d.ts.map +1 -1
- package/dist/public/operations/evidence-floor.js +3 -4
- package/dist/public/operations/migration-plan.d.ts.map +1 -1
- package/dist/public/operations/migration-plan.js +41 -10
- package/dist/public/operations/node-ports.d.ts.map +1 -1
- package/dist/public/operations/node-ports.js +3 -1
- package/dist/public/operations/repair-plan.d.ts +46 -0
- package/dist/public/operations/repair-plan.d.ts.map +1 -1
- package/dist/public/operations/repair-plan.js +110 -1
- package/dist/public/operations/schema6-check-actions.js +1 -1
- package/dist/public/operations/source-analysis-cache.d.ts +22 -0
- package/dist/public/operations/source-analysis-cache.d.ts.map +1 -0
- package/dist/public/operations/source-analysis-cache.js +157 -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 +2 -1
- package/dist/public/operations/specs/check.d.ts +1 -1
- package/dist/public/operations/specs/discovery.d.ts +7 -2
- package/dist/public/operations/specs/discovery.d.ts.map +1 -1
- package/dist/public/operations/specs/discovery.js +7 -2
- package/dist/public/operations/specs/mutation-schemas.d.ts +36 -1
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +30 -0
- package/dist/public/operations/specs/upsert.d.ts +36 -1
- package/dist/public/operations/specs/upsert.d.ts.map +1 -1
- package/dist/public/operations/symbol-granularity-check.d.ts +3 -1
- package/dist/public/operations/symbol-granularity-check.d.ts.map +1 -1
- package/dist/public/operations/symbol-granularity-check.js +21 -7
- package/dist/public/proof-protocol.d.ts +6 -1
- package/dist/public/proof-protocol.d.ts.map +1 -1
- package/dist/public/proof-protocol.js +12 -3
- package/dist/public/proof-sources.d.ts +2 -0
- package/dist/public/proof-sources.d.ts.map +1 -1
- package/dist/public/proof-sources.js +32 -6
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +59 -0
- package/dist/public/skills/kibi-bootstrap/SKILL.md +2 -2
- package/dist/public/skills/kibi-commit-review/SKILL.md +6 -2
- package/dist/public/skills/kibi-decisions/SKILL.md +7 -2
- package/dist/public/skills/kibi-decisions/resources/signoff-views.md +3 -1
- package/dist/public/skills/kibi-usage/SKILL.md +50 -3
- package/dist/public/skills/kibi-usage/resources/fact-lanes.md +34 -0
- package/dist/public/skills/kibi-usage/resources/proof.md +13 -5
- package/dist/public/skills/kibi-usage/resources/workflows.md +10 -0
- package/dist/relationships/shards.d.ts +2 -0
- package/dist/relationships/shards.d.ts.map +1 -1
- package/dist/relationships/shards.js +25 -1
- package/dist/schemas/entity.schema.json +98 -1
- package/dist/search-answer.d.ts +3 -2
- package/dist/search-answer.d.ts.map +1 -1
- package/dist/search-answer.js +57 -4
- package/dist/search-hints.d.ts +58 -0
- package/dist/search-hints.d.ts.map +1 -0
- package/dist/search-hints.js +187 -0
- package/dist/search-ranking.d.ts +7 -0
- package/dist/search-ranking.d.ts.map +1 -1
- package/dist/search-ranking.js +54 -56
- package/dist/search-token-cache.d.ts +30 -0
- package/dist/search-token-cache.d.ts.map +1 -0
- package/dist/search-token-cache.js +86 -0
- package/dist/traceability/impact-knowledge.d.ts.map +1 -1
- package/dist/traceability/impact-knowledge.js +2 -0
- package/dist/traceability/temp-kb.d.ts.map +1 -1
- package/dist/traceability/temp-kb.js +11 -1
- package/dist/types/entities.d.ts +12 -0
- package/dist/types/entities.d.ts.map +1 -1
- package/dist/usage-telemetry.d.ts +20 -0
- package/dist/usage-telemetry.d.ts.map +1 -0
- package/dist/usage-telemetry.js +93 -0
- package/dist/utils/branch-resolver.d.ts.map +1 -1
- package/dist/utils/branch-resolver.js +1 -0
- package/dist/utils/rule-registry.generated.d.ts +5 -0
- package/dist/utils/rule-registry.generated.d.ts.map +1 -1
- package/dist/utils/rule-registry.generated.js +6 -0
- package/package.json +5 -4
- package/schema/entities.pl +12 -0
- package/src/public/impact/coverage-depth-quality.ts +59 -21
- package/src/public/impact/full-kb-quality.ts +15 -1
- package/src/public/impact/requirement-quality.ts +95 -38
- package/src/public/operations/check-executor.ts +41 -1
- package/src/public/operations/discovery-executors.ts +92 -4
- package/src/public/operations/evidence-floor.ts +15 -3
- package/src/public/operations/migration-plan.ts +41 -9
- package/src/public/operations/node-ports.ts +3 -1
- package/src/public/operations/repair-plan.ts +152 -1
- package/src/public/operations/schema6-check-actions.ts +1 -1
- package/src/public/operations/source-analysis-cache.ts +196 -0
- package/src/public/operations/specs/check-rules.generated.ts +2 -1
- package/src/public/operations/specs/discovery.ts +8 -2
- package/src/public/operations/specs/mutation-schemas.ts +34 -0
- package/src/public/operations/symbol-granularity-check.ts +25 -5
- package/src/public/proof-protocol-types.d.ts +1 -1
- package/src/public/proof-protocol.ts +18 -4
- package/src/public/proof-sources.ts +37 -6
- package/src/public/schemas/entity.ts +65 -0
- package/src/public/skills/kibi-bootstrap/SKILL.md +2 -2
- package/src/public/skills/kibi-commit-review/SKILL.md +6 -2
- package/src/public/skills/kibi-decisions/SKILL.md +7 -2
- package/src/public/skills/kibi-decisions/resources/signoff-views.md +3 -1
- package/src/public/skills/kibi-usage/SKILL.md +50 -3
- package/src/public/skills/kibi-usage/resources/fact-lanes.md +34 -0
- package/src/public/skills/kibi-usage/resources/proof.md +13 -5
- package/src/public/skills/kibi-usage/resources/workflows.md +10 -0
- package/src/schemas/entity.schema.json +98 -1
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { detectTelemetryHost, flushTelemetry, recordOperationTelemetry, takeTelemetryNotice, } from "kibi-agent-core/usage-telemetry";
|
|
2
|
+
/**
|
|
3
|
+
* Anonymous usage telemetry for the CLI: one summary event per command,
|
|
4
|
+
* named by its registered command path (`sync`, `storage compact`, `search`)
|
|
5
|
+
* and never by its arguments. The queue is sent only when a batch is due, so
|
|
6
|
+
* most runs exit without touching the network.
|
|
7
|
+
*/
|
|
8
|
+
/** Commands that manage telemetry itself are not recorded. */
|
|
9
|
+
const UNRECORDED_COMMANDS = new Set(["telemetry"]);
|
|
10
|
+
let notedErrorCategory;
|
|
11
|
+
// implements REQ-kibi-anonymous-usage-telemetry
|
|
12
|
+
/**
|
|
13
|
+
* Name why this command failed with a fixed identifier (an error code, a
|
|
14
|
+
* failing doctor check), for the event recorded at exit. The first note wins.
|
|
15
|
+
*/
|
|
16
|
+
export function noteCliErrorCategory(category) {
|
|
17
|
+
if (category && notedErrorCategory === undefined) {
|
|
18
|
+
notedErrorCategory = category;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// implements REQ-kibi-anonymous-usage-telemetry
|
|
22
|
+
/** The error code of a failed JSON result printed by a command, if any. */
|
|
23
|
+
export function noteCliResultError(stdout) {
|
|
24
|
+
if (!stdout)
|
|
25
|
+
return;
|
|
26
|
+
try {
|
|
27
|
+
const parsed = JSON.parse(stdout);
|
|
28
|
+
if (parsed.status === "error" && typeof parsed.error?.code === "string") {
|
|
29
|
+
noteCliErrorCategory(parsed.error.code);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Not a JSON result.
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** A thrown error's code or class name; never its message. */
|
|
37
|
+
function thrownErrorCategory(error) {
|
|
38
|
+
if (error !== null && typeof error === "object") {
|
|
39
|
+
const code = error.code;
|
|
40
|
+
if (typeof code === "string" && code !== "")
|
|
41
|
+
return code;
|
|
42
|
+
const name = error.name;
|
|
43
|
+
if (typeof name === "string" && name !== "" && name !== "Error") {
|
|
44
|
+
return name;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return "uncaught_error";
|
|
48
|
+
}
|
|
49
|
+
// implements REQ-kibi-anonymous-usage-telemetry
|
|
50
|
+
/** Remember which registered command ran, for the event recorded at exit. */
|
|
51
|
+
export function trackCommandPath(program) {
|
|
52
|
+
let commandPath;
|
|
53
|
+
program.hook("preAction", (_root, actionCommand) => {
|
|
54
|
+
const names = [];
|
|
55
|
+
for (let current = actionCommand; current?.parent; current = current.parent) {
|
|
56
|
+
names.unshift(current.name());
|
|
57
|
+
}
|
|
58
|
+
commandPath = names.join(" ");
|
|
59
|
+
});
|
|
60
|
+
return () => commandPath;
|
|
61
|
+
}
|
|
62
|
+
// implements REQ-kibi-anonymous-usage-telemetry
|
|
63
|
+
export async function finishCliTelemetry(input) {
|
|
64
|
+
const env = input.env ?? process.env;
|
|
65
|
+
const command = input.commandPath;
|
|
66
|
+
const noted = notedErrorCategory;
|
|
67
|
+
notedErrorCategory = undefined;
|
|
68
|
+
if (!command || UNRECORDED_COMMANDS.has(command.split(" ")[0] ?? "")) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const notice = takeTelemetryNotice(env);
|
|
72
|
+
if (notice)
|
|
73
|
+
process.stderr.write(`${notice}\n`);
|
|
74
|
+
recordOperationTelemetry({
|
|
75
|
+
packageName: "kibi-cli",
|
|
76
|
+
packageVersion: input.packageVersion,
|
|
77
|
+
host: detectTelemetryHost(env),
|
|
78
|
+
workspaceRoot: process.cwd(),
|
|
79
|
+
}, {
|
|
80
|
+
interface: "cli",
|
|
81
|
+
operation: command,
|
|
82
|
+
status: input.exitCode === 0 ? "success" : "error",
|
|
83
|
+
durationMs: Date.now() - input.startedAt.getTime(),
|
|
84
|
+
exitCode: input.exitCode,
|
|
85
|
+
errorCategory: input.exitCode === 0
|
|
86
|
+
? undefined
|
|
87
|
+
: (noted ??
|
|
88
|
+
(input.error === undefined
|
|
89
|
+
? undefined
|
|
90
|
+
: thrownErrorCategory(input.error))),
|
|
91
|
+
}, env);
|
|
92
|
+
await flushTelemetry({}, env);
|
|
93
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/branch-resolver.ts"],"names":[],"mappings":"AAsCA,MAAM,MAAM,uBAAuB,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AACzD,MAAM,MAAM,qBAAqB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC;AAC7E,MAAM,MAAM,sBAAsB,GAC9B,uBAAuB,GACvB,qBAAqB,CAAC;AAE1B,wBAAgB,+BAA+B,CAC7C,WAAW,EAAE,MAAM,GAClB,qBAAqB,CAKvB;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,GAAG,mBAAmB,GAAG,eAAe,GAAG,mBAAmB,CAAC;IAC5E,iBAAiB,EAAE,OAAO,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,0BAA0B,CAAC;CACvC,CAAC;AAGF,MAAM,MAAM,0BAA0B,GAAG;IACvC,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;GAIG;AAEH,eAAO,MAAM,2BAA2B,yCACA,CAAC;AAEzC,MAAM,MAAM,eAAe,GACvB,cAAc,GACd,eAAe,GACf,eAAe,GACf,mBAAmB,GACnB,gBAAgB,GAChB,sBAAsB,GACtB,6BAA6B,GAC7B,eAAe,CAAC;AAEpB,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,cAAc,oBAAoB,EAAE,QAAQ,CAAC;IACvD,YAAY,EAAE,cAAc,oBAAoB,EAAE,YAAY,CAAC;CAChE;AAOD,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAChC,IAAI,CAIN;
|
|
1
|
+
{"version":3,"file":"branch-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/branch-resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -45,6 +45,7 @@ export function _setBranchResolverDepsForTests(deps) {
|
|
|
45
45
|
// Files to exclude when copying branch snapshots (volatile artifacts)
|
|
46
46
|
const VOLATILE_ARTIFACTS = new Set([
|
|
47
47
|
"sync-cache.json",
|
|
48
|
+
"source-analysis-cache.json",
|
|
48
49
|
"journal.log",
|
|
49
50
|
"audit.log",
|
|
50
51
|
"lock",
|
|
@@ -68,6 +68,11 @@ export declare const GENERATED_RULES: readonly [{
|
|
|
68
68
|
readonly description: "Advisory: a scenario that expects success assumes nothing, assumes values that contradict each other, assumes a property value no governing requirement constrains comparably (type, unit or operator mismatch, or conflicting requirements), leaves a governing rule's conditions undecided, or conflicts only with constraints whose validity window may not cover it, so its feasibility cannot be decided";
|
|
69
69
|
readonly enforcementClass: "advisory";
|
|
70
70
|
readonly category: "integrity";
|
|
71
|
+
}, {
|
|
72
|
+
readonly name: "scenario-outcome-mismatch";
|
|
73
|
+
readonly description: "A scenario that expects rejection or error must assume a value or situation a current requirement forbids: when every assumption is governed by current requirements and they permit all of them together, the knowledge base predicts success and the scenario exercises no failure side";
|
|
74
|
+
readonly enforcementClass: "canonical";
|
|
75
|
+
readonly category: "integrity";
|
|
71
76
|
}, {
|
|
72
77
|
readonly name: "exception-claim-keys";
|
|
73
78
|
readonly description: "An exception requirement's exempts_claims must name claim keys of a requirement it exempts, and requires an exempts link";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule-registry.generated.d.ts","sourceRoot":"","sources":["../../src/utils/rule-registry.generated.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,eAAe
|
|
1
|
+
{"version":3,"file":"rule-registry.generated.d.ts","sourceRoot":"","sources":["../../src/utils/rule-registry.generated.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0ZlB,CAAC"}
|
|
@@ -92,6 +92,12 @@ export const GENERATED_RULES = [
|
|
|
92
92
|
enforcementClass: "advisory",
|
|
93
93
|
category: "integrity",
|
|
94
94
|
},
|
|
95
|
+
{
|
|
96
|
+
name: "scenario-outcome-mismatch",
|
|
97
|
+
description: "A scenario that expects rejection or error must assume a value or situation a current requirement forbids: when every assumption is governed by current requirements and they permit all of them together, the knowledge base predicts success and the scenario exercises no failure side",
|
|
98
|
+
enforcementClass: "canonical",
|
|
99
|
+
category: "integrity",
|
|
100
|
+
},
|
|
95
101
|
{
|
|
96
102
|
name: "exception-claim-keys",
|
|
97
103
|
description: "An exception requirement's exempts_claims must name claim keys of a requirement it exempts, and requires an exempts link",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kibi-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.39.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Kibi CLI for knowledge base management",
|
|
6
6
|
"engines": {
|
|
@@ -239,13 +239,14 @@
|
|
|
239
239
|
"fast-glob": "^3.2.12",
|
|
240
240
|
"gray-matter": "^4.0.3",
|
|
241
241
|
"js-yaml": "^4.1.0",
|
|
242
|
-
"kibi-core": "^0.
|
|
242
|
+
"kibi-core": "^0.28.0",
|
|
243
243
|
"kibi-plugin-builtin": "^0.5.3",
|
|
244
|
-
"kibi-plugin-sdk": "^0.5.
|
|
244
|
+
"kibi-plugin-sdk": "^0.5.1",
|
|
245
245
|
"kibi-swipl": "^1.0.1",
|
|
246
246
|
"saxes": "^6.0.0",
|
|
247
247
|
"ignore": "^5.3.0",
|
|
248
|
-
"yaml": "^2.9.1"
|
|
248
|
+
"yaml": "^2.9.1",
|
|
249
|
+
"kibi-agent-core": "^0.11.0"
|
|
249
250
|
},
|
|
250
251
|
"devDependencies": {
|
|
251
252
|
"@types/node": "latest",
|
package/schema/entities.pl
CHANGED
|
@@ -47,6 +47,10 @@ entity_property(req, proof_exempt_reason, string).
|
|
|
47
47
|
% Only an approved exception makes a success scenario feasible.
|
|
48
48
|
entity_property(req, approved_by, string).
|
|
49
49
|
entity_property(req, approval_ref, string).
|
|
50
|
+
% Why a requirement has no failure side to test (its claims state a
|
|
51
|
+
% capability or output shape), and the human who accepted that.
|
|
52
|
+
entity_property(req, failure_side_waiver, string).
|
|
53
|
+
entity_property(req, failure_side_waiver_approved_by, string).
|
|
50
54
|
% Why the requirement exists, in the words of whoever stated the intent.
|
|
51
55
|
% Explanation only: it is never part of the checked meaning.
|
|
52
56
|
entity_property(req, rationale, string).
|
|
@@ -83,6 +87,12 @@ entity_property(fact, valid_to, datetime).
|
|
|
83
87
|
entity_property(fact, canonical_key, string).
|
|
84
88
|
entity_property(fact, claim_key, string).
|
|
85
89
|
entity_property(fact, claim_text, string).
|
|
90
|
+
% Why a quantifier word in claim_text ranges over nothing, so the claim
|
|
91
|
+
% needs no dimension, and the human who accepted that.
|
|
92
|
+
entity_property(fact, dimension_waiver, string).
|
|
93
|
+
entity_property(fact, dimension_waiver_approved_by, string).
|
|
94
|
+
entity_property(fact, case_waiver, string).
|
|
95
|
+
entity_property(fact, case_waiver_approved_by, string).
|
|
86
96
|
entity_property(fact, predicate_name, string).
|
|
87
97
|
entity_property(fact, predicate_namespace, string).
|
|
88
98
|
entity_property(fact, predicate_arity, integer).
|
|
@@ -149,6 +159,8 @@ optional_property(req, semantic_source_hash).
|
|
|
149
159
|
optional_property(req, semantic_inventory).
|
|
150
160
|
optional_property(req, proof_exempt).
|
|
151
161
|
optional_property(req, proof_exempt_reason).
|
|
162
|
+
optional_property(req, failure_side_waiver).
|
|
163
|
+
optional_property(req, failure_side_waiver_approved_by).
|
|
152
164
|
optional_property(req, approved_by).
|
|
153
165
|
optional_property(req, approval_ref).
|
|
154
166
|
optional_property(req, rationale).
|
|
@@ -33,12 +33,59 @@ type RelationshipLookup = {
|
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
type IncomingLookup = {
|
|
36
|
-
readonly
|
|
36
|
+
readonly index: CoverageIndex;
|
|
37
37
|
readonly targetId: string;
|
|
38
38
|
readonly relationshipType: string;
|
|
39
39
|
readonly type: string;
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Built once per report, so each requirement's coverage is a lookup rather
|
|
44
|
+
* than a scan over every manifest result.
|
|
45
|
+
*/
|
|
46
|
+
type CoverageIndex = {
|
|
47
|
+
readonly resultsById: ReadonlyMap<string, ExtractionResult>;
|
|
48
|
+
/** Source entities by `${type}\0${relationshipType}\0${targetId}`, in manifest order. */
|
|
49
|
+
readonly incomingByTarget: ReadonlyMap<string, readonly ExtractedEntity[]>;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
function incomingKey(
|
|
53
|
+
type: string,
|
|
54
|
+
relationshipType: string,
|
|
55
|
+
targetId: string,
|
|
56
|
+
): string {
|
|
57
|
+
return `${type}\0${relationshipType}\0${targetId}`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function coverageIndex(
|
|
61
|
+
manifestResults: readonly ExtractionResult[],
|
|
62
|
+
): CoverageIndex {
|
|
63
|
+
const incomingByTarget = new Map<string, ExtractedEntity[]>();
|
|
64
|
+
// A result linking the same target twice is listed twice; every reader
|
|
65
|
+
// dedupes by entity id.
|
|
66
|
+
for (const result of manifestResults) {
|
|
67
|
+
for (const relationship of result.relationships) {
|
|
68
|
+
const key = incomingKey(
|
|
69
|
+
result.entity.type,
|
|
70
|
+
relationship.type,
|
|
71
|
+
relationship.to,
|
|
72
|
+
);
|
|
73
|
+
const list = incomingByTarget.get(key);
|
|
74
|
+
if (list === undefined) incomingByTarget.set(key, [result.entity]);
|
|
75
|
+
else list.push(result.entity);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
resultsById: new Map(
|
|
80
|
+
manifestResults.map((manifestResult) => [
|
|
81
|
+
manifestResult.entity.id,
|
|
82
|
+
manifestResult,
|
|
83
|
+
]),
|
|
84
|
+
),
|
|
85
|
+
incomingByTarget,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
42
89
|
function entitiesById(
|
|
43
90
|
manifestResults: readonly ExtractionResult[],
|
|
44
91
|
): ReadonlyMap<string, ExtractedEntity> {
|
|
@@ -58,16 +105,11 @@ function outgoingTargets(
|
|
|
58
105
|
}
|
|
59
106
|
|
|
60
107
|
function incomingSources(lookup: IncomingLookup): readonly ExtractedEntity[] {
|
|
61
|
-
return
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
relationship.to === lookup.targetId,
|
|
67
|
-
)
|
|
68
|
-
? [result.entity]
|
|
69
|
-
: [];
|
|
70
|
-
});
|
|
108
|
+
return (
|
|
109
|
+
lookup.index.incomingByTarget.get(
|
|
110
|
+
incomingKey(lookup.type, lookup.relationshipType, lookup.targetId),
|
|
111
|
+
) ?? []
|
|
112
|
+
);
|
|
71
113
|
}
|
|
72
114
|
|
|
73
115
|
function uniqueEntities(
|
|
@@ -213,15 +255,10 @@ function createDiagnostic(
|
|
|
213
255
|
|
|
214
256
|
function coverageForRequirement(
|
|
215
257
|
result: ExtractionResult,
|
|
216
|
-
|
|
258
|
+
index: CoverageIndex,
|
|
217
259
|
entities: ReadonlyMap<string, ExtractedEntity>,
|
|
218
260
|
): RequirementCoverage {
|
|
219
|
-
const resultsById =
|
|
220
|
-
manifestResults.map((manifestResult) => [
|
|
221
|
-
manifestResult.entity.id,
|
|
222
|
-
manifestResult,
|
|
223
|
-
]),
|
|
224
|
-
);
|
|
261
|
+
const resultsById = index.resultsById;
|
|
225
262
|
const scenarios = outgoingTargets({
|
|
226
263
|
result,
|
|
227
264
|
relationshipType: "specified_by",
|
|
@@ -242,7 +279,7 @@ function coverageForRequirement(
|
|
|
242
279
|
entities,
|
|
243
280
|
}),
|
|
244
281
|
...incomingSources({
|
|
245
|
-
|
|
282
|
+
index,
|
|
246
283
|
targetId: result.entity.id,
|
|
247
284
|
relationshipType: "validates",
|
|
248
285
|
type: "test",
|
|
@@ -253,7 +290,7 @@ function coverageForRequirement(
|
|
|
253
290
|
const scenarioResult = resultsById.get(scenario.id);
|
|
254
291
|
return [
|
|
255
292
|
...incomingSources({
|
|
256
|
-
|
|
293
|
+
index,
|
|
257
294
|
targetId: scenario.id,
|
|
258
295
|
relationshipType: "validates",
|
|
259
296
|
type: "test",
|
|
@@ -331,6 +368,7 @@ export function createCoverageDepthQualityDiagnostics(
|
|
|
331
368
|
): readonly QualityDiagnostic[] {
|
|
332
369
|
const entities = entitiesById(manifestResults);
|
|
333
370
|
const superseded = supersededRequirementIds(manifestResults);
|
|
371
|
+
const index = coverageIndex(manifestResults);
|
|
334
372
|
return manifestResults
|
|
335
373
|
.filter(
|
|
336
374
|
(result) =>
|
|
@@ -339,7 +377,7 @@ export function createCoverageDepthQualityDiagnostics(
|
|
|
339
377
|
)
|
|
340
378
|
.flatMap((result) => {
|
|
341
379
|
const diagnostic = createDiagnostic(
|
|
342
|
-
coverageForRequirement(result,
|
|
380
|
+
coverageForRequirement(result, index, entities),
|
|
343
381
|
proofByRequirement.get(result.entity.id),
|
|
344
382
|
);
|
|
345
383
|
return diagnostic === undefined ? [] : [diagnostic];
|
|
@@ -47,6 +47,12 @@ type FullKbQualityDiagnosticsOptions = {
|
|
|
47
47
|
readonly now?: Date;
|
|
48
48
|
readonly proofSnapshot?: string;
|
|
49
49
|
readonly checkedAt?: string;
|
|
50
|
+
/**
|
|
51
|
+
* The per-contract receipt bindings kb_coverage uses (a Prolog
|
|
52
|
+
* TestId -> binding hash dict), or null for strict snapshot binding. Read
|
|
53
|
+
* lazily so a check without proof evidence never pays for it.
|
|
54
|
+
*/
|
|
55
|
+
readonly proofTestBindings?: () => Promise<string | null>;
|
|
50
56
|
};
|
|
51
57
|
|
|
52
58
|
type CoverageEvidencePayload = Readonly<{
|
|
@@ -633,6 +639,7 @@ async function loadCoverageProofEvidence(
|
|
|
633
639
|
requirementCount: number,
|
|
634
640
|
proofSnapshot: string | undefined,
|
|
635
641
|
checkedAt: string | undefined,
|
|
642
|
+
proofTestBindings: (() => Promise<string | null>) | undefined,
|
|
636
643
|
): Promise<
|
|
637
644
|
ReadonlyMap<
|
|
638
645
|
string,
|
|
@@ -653,6 +660,12 @@ async function loadCoverageProofEvidence(
|
|
|
653
660
|
}
|
|
654
661
|
let payload: CoverageEvidencePayload;
|
|
655
662
|
try {
|
|
663
|
+
// Judge receipts with the binding kb_coverage uses; under strict snapshot
|
|
664
|
+
// binding any unrelated change since kibi prove would read every receipt
|
|
665
|
+
// as stale and bring back the weak-depth review.
|
|
666
|
+
const bindings = (await proofTestBindings?.()) ?? null;
|
|
667
|
+
const binding =
|
|
668
|
+
bindings === null ? "strict_snapshot, _{}" : `per_contract, ${bindings}`;
|
|
656
669
|
// W1 push-down: the slim evidence projection returns only the fields the
|
|
657
670
|
// quality diagnostics consume, keeping the response far below the output
|
|
658
671
|
// capacity limit on large KBs (the full coverage report rows were the
|
|
@@ -660,7 +673,7 @@ async function loadCoverageProofEvidence(
|
|
|
660
673
|
payload = await runOperationJsonQuery<CoverageEvidencePayload>(
|
|
661
674
|
prolog as PrologPort,
|
|
662
675
|
"discovery.pl",
|
|
663
|
-
`discovery:coverage_evidence_json(${toPrologList([])}, ${toPrologAtom(proofSnapshot)}, ${toPrologAtom(checkedAt)}, ${PROOF_RECEIPT_MAX_AGE_SECONDS}, JsonString)`,
|
|
676
|
+
`discovery:coverage_evidence_json(${toPrologList([])}, ${binding}, ${toPrologAtom(proofSnapshot)}, ${toPrologAtom(checkedAt)}, ${PROOF_RECEIPT_MAX_AGE_SECONDS}, JsonString)`,
|
|
664
677
|
"Quality diagnostic coverage evidence",
|
|
665
678
|
);
|
|
666
679
|
} catch {
|
|
@@ -776,6 +789,7 @@ export async function collectFullKbQualityDiagnostics(
|
|
|
776
789
|
manifestResults.filter((result) => result.entity.type === "req").length,
|
|
777
790
|
options.proofSnapshot,
|
|
778
791
|
options.checkedAt,
|
|
792
|
+
options.proofTestBindings,
|
|
779
793
|
);
|
|
780
794
|
const coverageDepthDiagnostics = createCoverageDepthQualityDiagnostics(
|
|
781
795
|
manifestResults,
|
|
@@ -70,55 +70,111 @@ function targetHasType(
|
|
|
70
70
|
return targetType === undefined || targetType === type;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
type FanoutIndex = {
|
|
74
|
+
readonly relationshipsByEntityId: ReadonlyMap<
|
|
75
|
+
string,
|
|
76
|
+
readonly ExtractionResult["relationships"][number][]
|
|
77
|
+
>;
|
|
78
|
+
readonly implementerIdsByRequirementId: ReadonlyMap<
|
|
79
|
+
string,
|
|
80
|
+
readonly string[]
|
|
81
|
+
>;
|
|
82
|
+
readonly dependentRequirementIdsByRequirementId: ReadonlyMap<
|
|
83
|
+
string,
|
|
84
|
+
readonly string[]
|
|
85
|
+
>;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/** One pass over every relationship, so each requirement's fanout is a lookup. */
|
|
89
|
+
function fanoutIndex(results: readonly ExtractionResult[]): FanoutIndex {
|
|
90
|
+
const relationshipsByEntityId = new Map<
|
|
91
|
+
string,
|
|
92
|
+
ExtractionResult["relationships"][number][]
|
|
93
|
+
>();
|
|
94
|
+
const implementerIdsByRequirementId = new Map<string, string[]>();
|
|
95
|
+
const dependentRequirementIdsByRequirementId = new Map<string, string[]>();
|
|
96
|
+
const append = (
|
|
97
|
+
index: Map<string, string[]>,
|
|
98
|
+
key: string,
|
|
99
|
+
value: string,
|
|
100
|
+
): void => {
|
|
101
|
+
const list = index.get(key);
|
|
102
|
+
if (list === undefined) index.set(key, [value]);
|
|
103
|
+
else list.push(value);
|
|
104
|
+
};
|
|
105
|
+
for (const result of results) {
|
|
106
|
+
const relationships = relationshipsByEntityId.get(result.entity.id);
|
|
107
|
+
if (relationships === undefined) {
|
|
108
|
+
relationshipsByEntityId.set(result.entity.id, [...result.relationships]);
|
|
109
|
+
} else {
|
|
110
|
+
relationships.push(...result.relationships);
|
|
111
|
+
}
|
|
112
|
+
for (const relationship of result.relationships) {
|
|
113
|
+
if (relationship.type === "implements") {
|
|
114
|
+
append(
|
|
115
|
+
implementerIdsByRequirementId,
|
|
116
|
+
relationship.to,
|
|
117
|
+
result.entity.id,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
if (relationship.type === "depends_on" && result.entity.type === "req") {
|
|
121
|
+
append(
|
|
122
|
+
dependentRequirementIdsByRequirementId,
|
|
123
|
+
relationship.to,
|
|
124
|
+
result.entity.id,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
relationshipsByEntityId,
|
|
131
|
+
implementerIdsByRequirementId,
|
|
132
|
+
dependentRequirementIdsByRequirementId,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
73
136
|
function collectFanout(
|
|
74
137
|
requirementId: string,
|
|
75
|
-
|
|
138
|
+
index: FanoutIndex,
|
|
76
139
|
typesByEntityId: ReadonlyMap<string, string>,
|
|
77
140
|
): RequirementFanout {
|
|
78
|
-
const implementingSymbolIds: string[] = [];
|
|
79
141
|
const scenarioIds: string[] = [];
|
|
80
142
|
const testIds: string[] = [];
|
|
81
143
|
const dependentRequirementIds: string[] = [];
|
|
82
144
|
|
|
83
|
-
for
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (relationship.type === "depends_on") {
|
|
107
|
-
if (
|
|
108
|
-
result.entity.id === requirementId &&
|
|
109
|
-
targetHasType(relationship.to, "req", typesByEntityId)
|
|
110
|
-
) {
|
|
111
|
-
dependentRequirementIds.push(relationship.to);
|
|
112
|
-
}
|
|
113
|
-
if (relationship.to === requirementId && result.entity.type === "req") {
|
|
114
|
-
dependentRequirementIds.push(result.entity.id);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
145
|
+
// rationale: every requirement this is called for is in the index, so the
|
|
146
|
+
// fallback list is never read.
|
|
147
|
+
// Stryker disable next-line ArrayDeclaration
|
|
148
|
+
const relationships = index.relationshipsByEntityId.get(requirementId) ?? [];
|
|
149
|
+
for (const relationship of relationships) {
|
|
150
|
+
if (
|
|
151
|
+
relationship.type === "specified_by" &&
|
|
152
|
+
targetHasType(relationship.to, "scenario", typesByEntityId)
|
|
153
|
+
) {
|
|
154
|
+
scenarioIds.push(relationship.to);
|
|
155
|
+
}
|
|
156
|
+
if (
|
|
157
|
+
(relationship.type === "verified_by" ||
|
|
158
|
+
relationship.type === "covered_by") &&
|
|
159
|
+
targetHasType(relationship.to, "test", typesByEntityId)
|
|
160
|
+
) {
|
|
161
|
+
testIds.push(relationship.to);
|
|
162
|
+
}
|
|
163
|
+
if (
|
|
164
|
+
relationship.type === "depends_on" &&
|
|
165
|
+
targetHasType(relationship.to, "req", typesByEntityId)
|
|
166
|
+
) {
|
|
167
|
+
dependentRequirementIds.push(relationship.to);
|
|
117
168
|
}
|
|
118
169
|
}
|
|
170
|
+
dependentRequirementIds.push(
|
|
171
|
+
...(index.dependentRequirementIdsByRequirementId.get(requirementId) ?? []),
|
|
172
|
+
);
|
|
119
173
|
|
|
120
174
|
return {
|
|
121
|
-
implementingSymbolIds: sortedUnique(
|
|
175
|
+
implementingSymbolIds: sortedUnique(
|
|
176
|
+
index.implementerIdsByRequirementId.get(requirementId) ?? [],
|
|
177
|
+
),
|
|
122
178
|
scenarioIds: sortedUnique(scenarioIds),
|
|
123
179
|
testIds: sortedUnique(testIds),
|
|
124
180
|
dependentRequirementIds: sortedUnique(dependentRequirementIds),
|
|
@@ -145,9 +201,10 @@ function createBroadRequirementDiagnostics(
|
|
|
145
201
|
results: readonly ExtractionResult[],
|
|
146
202
|
): readonly KibiImpactDiagnostic[] {
|
|
147
203
|
const typesByEntityId = entityTypeById(results);
|
|
204
|
+
const index = fanoutIndex(results);
|
|
148
205
|
return results.flatMap((result) => {
|
|
149
206
|
if (!isCurrentRequirement(result)) return [];
|
|
150
|
-
const fanout = collectFanout(result.entity.id,
|
|
207
|
+
const fanout = collectFanout(result.entity.id, index, typesByEntityId);
|
|
151
208
|
if (!exceedsBroadThreshold(fanout)) return [];
|
|
152
209
|
if (isUmbrellaRequirement(result)) return [];
|
|
153
210
|
|
|
@@ -225,6 +225,35 @@ export function uncompiledBranchStoreViolation(
|
|
|
225
225
|
};
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
+
/**
|
|
229
|
+
* The branch store this check reads, when the engine is known to read it, as
|
|
230
|
+
* the place to keep parsed source analyses. A read-only detached snapshot
|
|
231
|
+
* and an unknown store (an explicit --kb-path) get no cache.
|
|
232
|
+
*/
|
|
233
|
+
// implements REQ-cli-check
|
|
234
|
+
export function analysisCacheDir(
|
|
235
|
+
context: OperationContext,
|
|
236
|
+
workspaceRoot: string,
|
|
237
|
+
options: CheckExecutionOptions,
|
|
238
|
+
): string | undefined {
|
|
239
|
+
if (
|
|
240
|
+
context.branchAttachment === undefined &&
|
|
241
|
+
options.branchStoreAttached !== true
|
|
242
|
+
) {
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
const attachment =
|
|
247
|
+
context.branchAttachment ?? resolveBranchAttachment(workspaceRoot);
|
|
248
|
+
if ("storePath" in attachment && attachment.readOnly === undefined) {
|
|
249
|
+
return attachment.storePath;
|
|
250
|
+
}
|
|
251
|
+
} catch {
|
|
252
|
+
// A branch that cannot be resolved gets no cache.
|
|
253
|
+
}
|
|
254
|
+
return undefined;
|
|
255
|
+
}
|
|
256
|
+
|
|
228
257
|
// implements REQ-kibi-operation-interface-parity, REQ-002
|
|
229
258
|
export async function executeCheck(
|
|
230
259
|
args: CheckInput,
|
|
@@ -239,6 +268,10 @@ export async function executeCheck(
|
|
|
239
268
|
? snapshotEvidence.snapshot.hash
|
|
240
269
|
: undefined;
|
|
241
270
|
const checkedAt = context.clock().toISOString();
|
|
271
|
+
const proofTestBindings = async () => {
|
|
272
|
+
const { perContractTestBindings } = await import("./specs/reporting.js");
|
|
273
|
+
return perContractTestBindings({ ...context, prolog });
|
|
274
|
+
};
|
|
242
275
|
// Enforcement policy is Kibi-owned and deterministic from the installed
|
|
243
276
|
// version. `args.rules` is an invocation-time diagnostic selector only.
|
|
244
277
|
const rulesAllowlist = resolveCheckRules(args);
|
|
@@ -316,6 +349,7 @@ export async function executeCheck(
|
|
|
316
349
|
workspaceRoot,
|
|
317
350
|
...(proofSnapshot !== undefined ? { proofSnapshot } : {}),
|
|
318
351
|
checkedAt,
|
|
352
|
+
proofTestBindings,
|
|
319
353
|
now: context.clock(),
|
|
320
354
|
...maxDiagnosticsOption,
|
|
321
355
|
});
|
|
@@ -378,6 +412,7 @@ export async function executeCheck(
|
|
|
378
412
|
prolog,
|
|
379
413
|
workspaceRoot,
|
|
380
414
|
rulesAllowlist,
|
|
415
|
+
analysisCacheDir(context, workspaceRoot, options),
|
|
381
416
|
);
|
|
382
417
|
const originReviewFindings = await collectOriginReviewViolations(
|
|
383
418
|
prolog,
|
|
@@ -400,7 +435,11 @@ export async function executeCheck(
|
|
|
400
435
|
const evidenceFloorFindings = await collectEvidenceFloorViolations(
|
|
401
436
|
context,
|
|
402
437
|
rulesAllowlist,
|
|
403
|
-
{
|
|
438
|
+
{
|
|
439
|
+
freshEvidence: args.freshEvidence === true,
|
|
440
|
+
checkedAt,
|
|
441
|
+
snapshotEvidence,
|
|
442
|
+
},
|
|
404
443
|
);
|
|
405
444
|
const proofContractClaimFindings =
|
|
406
445
|
await collectProofContractClaimViolations(context, rulesAllowlist);
|
|
@@ -442,6 +481,7 @@ export async function executeCheck(
|
|
|
442
481
|
workspaceRoot,
|
|
443
482
|
...(proofSnapshot !== undefined ? { proofSnapshot } : {}),
|
|
444
483
|
checkedAt,
|
|
484
|
+
proofTestBindings,
|
|
445
485
|
now: context.clock(),
|
|
446
486
|
...maxDiagnosticsOption,
|
|
447
487
|
});
|