kibi-cli 2.35.1 → 2.38.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-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-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 +16 -1
- package/dist/commands/aggregated-checks.d.ts.map +1 -1
- package/dist/commands/aggregated-checks.js +89 -16
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +56 -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/sync/persistence.d.ts.map +1 -1
- package/dist/commands/sync/persistence.js +43 -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/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/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/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/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 +13 -3
- 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/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/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 +6 -1
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/upsert.d.ts +6 -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/skills/kibi-bootstrap/SKILL.md +2 -2
- package/dist/public/skills/kibi-usage/SKILL.md +42 -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 +6 -1
- package/dist/search-answer.js +1 -1
- 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/usage-telemetry.d.ts +11 -0
- package/dist/usage-telemetry.d.ts.map +1 -0
- package/dist/usage-telemetry.js +47 -0
- package/dist/utils/branch-resolver.d.ts.map +1 -1
- package/dist/utils/branch-resolver.js +1 -0
- package/package.json +5 -4
- 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/source-analysis-cache.ts +196 -0
- package/src/public/operations/specs/discovery.ts +8 -2
- 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/skills/kibi-bootstrap/SKILL.md +2 -2
- package/src/public/skills/kibi-usage/SKILL.md +42 -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 +6 -1
|
@@ -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",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kibi-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.38.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.27.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.10.0"
|
|
249
250
|
},
|
|
250
251
|
"devDependencies": {
|
|
251
252
|
"@types/node": "latest",
|
|
@@ -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
|
});
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type IntentSearchAnalysis,
|
|
11
11
|
type IntentSearchFacets,
|
|
12
12
|
type IntentSearchMatch,
|
|
13
|
+
type MarkdownBodyCache,
|
|
13
14
|
type SourceLocation,
|
|
14
15
|
executeIntentSearch,
|
|
15
16
|
questionPaths,
|
|
@@ -18,6 +19,12 @@ import {
|
|
|
18
19
|
import { classifyActivation } from "../../operations/bootstrap/activation.js";
|
|
19
20
|
import { SwiplResolutionError } from "../../prolog/swipl-resolver.js";
|
|
20
21
|
import { type SearchAnswer, buildSearchAnswer } from "../../search-answer.js";
|
|
22
|
+
import {
|
|
23
|
+
type SearchHintsAnalysis,
|
|
24
|
+
buildSearchHints,
|
|
25
|
+
searchHintsNote,
|
|
26
|
+
searchHintsTrigger,
|
|
27
|
+
} from "../../search-hints.js";
|
|
21
28
|
import { rankEntities } from "../../search-ranking.js";
|
|
22
29
|
import type { SearchMatch } from "../../search-ranking.js";
|
|
23
30
|
import { resolveBranchAttachment } from "../../utils/branch-resolver.js";
|
|
@@ -51,7 +58,11 @@ import {
|
|
|
51
58
|
runOperationJsonQuery,
|
|
52
59
|
toPrologAtom,
|
|
53
60
|
} from "./prolog-json.js";
|
|
54
|
-
import type {
|
|
61
|
+
import type {
|
|
62
|
+
CapabilityRegistry,
|
|
63
|
+
OperationContext,
|
|
64
|
+
PrologPort,
|
|
65
|
+
} from "./runtime-types.js";
|
|
55
66
|
import type { OperationResult } from "./types.js";
|
|
56
67
|
import { readWorkspaceSnapshot } from "./workspace-snapshot.js";
|
|
57
68
|
|
|
@@ -176,6 +187,7 @@ export type SearchInput = {
|
|
|
176
187
|
readonly minScore?: number;
|
|
177
188
|
readonly fields?: "summary" | "full";
|
|
178
189
|
readonly answer?: boolean;
|
|
190
|
+
readonly hints?: boolean;
|
|
179
191
|
};
|
|
180
192
|
|
|
181
193
|
export type SearchPayload = {
|
|
@@ -185,7 +197,9 @@ export type SearchPayload = {
|
|
|
185
197
|
/** Rows in `results`: the page this call returned. */
|
|
186
198
|
readonly returned: number;
|
|
187
199
|
readonly truncated?: boolean;
|
|
188
|
-
readonly queryAnalysis?: IntentSearchAnalysis
|
|
200
|
+
readonly queryAnalysis?: IntentSearchAnalysis & {
|
|
201
|
+
readonly hints?: SearchHintsAnalysis;
|
|
202
|
+
};
|
|
189
203
|
readonly answer?: SearchAnswer;
|
|
190
204
|
/** The Kibi branch whose store was searched, when the runtime attached one. */
|
|
191
205
|
readonly branch?: string | null;
|
|
@@ -912,6 +926,51 @@ function questionPathHint(
|
|
|
912
926
|
: ` The question names ${list}; their words were left out of the topic. Pass them as sourceLocations to also see the requirements linked to those files.`;
|
|
913
927
|
}
|
|
914
928
|
|
|
929
|
+
/**
|
|
930
|
+
* Hints from the workspace's kibi.search-hints.v1 provider. A host without a
|
|
931
|
+
* plugin runtime, or a registry that fails to load, gives no hints rather than
|
|
932
|
+
* failing the search.
|
|
933
|
+
*/
|
|
934
|
+
// implements REQ-kibi-search-hints-host
|
|
935
|
+
async function searchHintsFor(
|
|
936
|
+
context: OperationContext,
|
|
937
|
+
options: Omit<
|
|
938
|
+
Parameters<typeof buildSearchHints>[0],
|
|
939
|
+
"resolution" | "workspaceRoot"
|
|
940
|
+
>,
|
|
941
|
+
): Promise<SearchHintsAnalysis | undefined> {
|
|
942
|
+
if (!context.ensurePlugins) return undefined;
|
|
943
|
+
let resolution: Awaited<ReturnType<CapabilityRegistry["resolveSearchHints"]>>;
|
|
944
|
+
try {
|
|
945
|
+
resolution = await (await context.ensurePlugins()).resolveSearchHints();
|
|
946
|
+
} catch (error) {
|
|
947
|
+
// A configured provider that cannot load is reported, not thrown: the
|
|
948
|
+
// lexical answer stands on its own.
|
|
949
|
+
const trigger = searchHintsTrigger(options.analysis);
|
|
950
|
+
return trigger === null
|
|
951
|
+
? undefined
|
|
952
|
+
: {
|
|
953
|
+
trigger,
|
|
954
|
+
provider: null,
|
|
955
|
+
items: [],
|
|
956
|
+
diagnostics: [
|
|
957
|
+
{
|
|
958
|
+
pluginId: "unresolved",
|
|
959
|
+
packageName: null,
|
|
960
|
+
mode: "replace",
|
|
961
|
+
code: "provider_unavailable",
|
|
962
|
+
message: error instanceof Error ? error.message : String(error),
|
|
963
|
+
},
|
|
964
|
+
],
|
|
965
|
+
};
|
|
966
|
+
}
|
|
967
|
+
return buildSearchHints({
|
|
968
|
+
...options,
|
|
969
|
+
resolution,
|
|
970
|
+
workspaceRoot: context.workspaceRoot,
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
|
|
915
974
|
export async function executeSearch(
|
|
916
975
|
input: SearchInput,
|
|
917
976
|
context: OperationContext,
|
|
@@ -928,6 +987,7 @@ export async function executeSearch(
|
|
|
928
987
|
minScore,
|
|
929
988
|
fields = "summary",
|
|
930
989
|
answer,
|
|
990
|
+
hints: hintsWanted = true,
|
|
931
991
|
} = input;
|
|
932
992
|
const trimmedQuery = query.trim();
|
|
933
993
|
if (!trimmedQuery) {
|
|
@@ -960,10 +1020,19 @@ export async function executeSearch(
|
|
|
960
1020
|
...(minScore !== undefined ? { minScore } : {}),
|
|
961
1021
|
} as const;
|
|
962
1022
|
validateIntentSearchInput(intentInput);
|
|
1023
|
+
let corpus:
|
|
1024
|
+
| {
|
|
1025
|
+
entities: readonly Record<string, unknown>[];
|
|
1026
|
+
bodies: MarkdownBodyCache;
|
|
1027
|
+
}
|
|
1028
|
+
| undefined;
|
|
963
1029
|
const intentResult = await executeIntentSearch(
|
|
964
1030
|
intentInput,
|
|
965
1031
|
prolog,
|
|
966
1032
|
context.workspaceRoot,
|
|
1033
|
+
(entities, bodies) => {
|
|
1034
|
+
corpus = { entities, bodies };
|
|
1035
|
+
},
|
|
967
1036
|
);
|
|
968
1037
|
const paginated = paginateResults(intentResult.matches, limit, offset);
|
|
969
1038
|
// The answer layer summarizes the whole ranking, so it belongs to the
|
|
@@ -982,6 +1051,22 @@ export async function executeSearch(
|
|
|
982
1051
|
const topUngoverned = answerLayer?.ungoverned.find(
|
|
983
1052
|
(entry) => entry.rank === 1,
|
|
984
1053
|
);
|
|
1054
|
+
// Hints come after the lexical answer and never change it; a strong
|
|
1055
|
+
// answer never reaches a provider.
|
|
1056
|
+
const hints =
|
|
1057
|
+
hintsWanted &&
|
|
1058
|
+
offset === 0 &&
|
|
1059
|
+
corpus !== undefined &&
|
|
1060
|
+
searchHintsTrigger(intentResult.analysis) !== null
|
|
1061
|
+
? await searchHintsFor(context, {
|
|
1062
|
+
query: trimmedQuery,
|
|
1063
|
+
analysis: intentResult.analysis,
|
|
1064
|
+
entities: corpus.entities,
|
|
1065
|
+
bodies: corpus.bodies,
|
|
1066
|
+
governingIds: (answerLayer?.governing ?? []).map((req) => req.id),
|
|
1067
|
+
prolog,
|
|
1068
|
+
})
|
|
1069
|
+
: undefined;
|
|
985
1070
|
const text = `${
|
|
986
1071
|
intentResult.matches.length === 0
|
|
987
1072
|
? `No intent search results for '${trimmedQuery}' (abstained). No entity shares enough of the question's words: ask again in the words and language the KB is written in, or pass sourceLocations.`
|
|
@@ -991,7 +1076,7 @@ export async function executeSearch(
|
|
|
991
1076
|
.join(
|
|
992
1077
|
", ",
|
|
993
1078
|
)}${answerLayer ? `. Governing: ${answerLayer.governing.map((req) => req.id).join(", ") || "none found"}` : ""}${topUngoverned ? ` (the top match ${topUngoverned.id} is linked to no requirement)` : ""}.`
|
|
994
|
-
}${questionPathHint(trimmedQuery, sourceLocations)}${CONTRADICTION_QUESTION.test(trimmedQuery) ? CONTRADICTION_HINT : ""}${storeNote}`;
|
|
1079
|
+
}${searchHintsNote(hints)}${questionPathHint(trimmedQuery, sourceLocations)}${CONTRADICTION_QUESTION.test(trimmedQuery) ? CONTRADICTION_HINT : ""}${storeNote}`;
|
|
995
1080
|
return {
|
|
996
1081
|
content: [{ type: "text", text }],
|
|
997
1082
|
structuredContent: {
|
|
@@ -999,7 +1084,10 @@ export async function executeSearch(
|
|
|
999
1084
|
count: intentResult.matches.length,
|
|
1000
1085
|
returned: paginated.length,
|
|
1001
1086
|
truncated: offset + paginated.length < intentResult.matches.length,
|
|
1002
|
-
queryAnalysis:
|
|
1087
|
+
queryAnalysis:
|
|
1088
|
+
hints !== undefined
|
|
1089
|
+
? { ...intentResult.analysis, hints }
|
|
1090
|
+
: intentResult.analysis,
|
|
1003
1091
|
...(answerLayer ? { answer: answerLayer } : {}),
|
|
1004
1092
|
...branchFields,
|
|
1005
1093
|
},
|