kibi-cli 0.17.0 → 0.18.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-json-command.d.ts.map +1 -1
- package/dist/cli-json-command.js +87 -11
- package/dist/cli-register-maintenance.d.ts.map +1 -1
- package/dist/cli-register-maintenance.js +8 -0
- package/dist/cli-register-reporting.d.ts.map +1 -1
- package/dist/cli-register-reporting.js +5 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -1
- package/dist/commands/aggregated-checks.d.ts.map +1 -1
- package/dist/commands/aggregated-checks.js +1 -0
- package/dist/commands/coverage.d.ts +5 -0
- package/dist/commands/coverage.d.ts.map +1 -1
- package/dist/commands/coverage.js +5 -0
- package/dist/commands/discovery-table.d.ts.map +1 -1
- package/dist/commands/discovery-table.js +96 -5
- package/dist/commands/sync/cache.d.ts +2 -0
- package/dist/commands/sync/cache.d.ts.map +1 -1
- package/dist/commands/sync/cache.js +8 -0
- package/dist/commands/sync/persistence.d.ts.map +1 -1
- package/dist/commands/sync/persistence.js +58 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +72 -15
- package/dist/commands/usage-metrics.d.ts +66 -2
- package/dist/commands/usage-metrics.d.ts.map +1 -1
- package/dist/commands/usage-metrics.js +34 -24
- package/dist/commands/usage-remediation.d.ts +9 -0
- package/dist/commands/usage-remediation.d.ts.map +1 -0
- package/dist/commands/usage-remediation.js +52 -0
- package/dist/extractors/markdown.d.ts +8 -0
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +69 -2
- package/dist/operations/modeling/logic-modeling.d.ts.map +1 -1
- package/dist/operations/modeling/logic-modeling.js +14 -5
- package/dist/operations/modeling/model-requirement.d.ts.map +1 -1
- package/dist/operations/modeling/model-requirement.js +27 -2
- package/dist/operations/modeling/predicate-applyplan.d.ts +1 -1
- package/dist/operations/modeling/predicate-applyplan.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-applyplan.js +18 -6
- package/dist/operations/modeling/predicate-inference.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-inference.js +5 -17
- package/dist/operations/modeling/predicate-loader.js +1 -1
- package/dist/operations/modeling/predicate-types.d.ts +9 -1
- package/dist/operations/modeling/predicate-types.d.ts.map +1 -1
- package/dist/operations/modeling/suggest-predicates.d.ts.map +1 -1
- package/dist/operations/modeling/suggest-predicates.js +35 -11
- package/dist/operations/mutation/audit.js +1 -1
- package/dist/operations/mutation/contradictions.d.ts +1 -1
- package/dist/operations/mutation/contradictions.d.ts.map +1 -1
- package/dist/operations/mutation/contradictions.js +23 -18
- package/dist/operations/mutation/serialization.d.ts.map +1 -1
- package/dist/operations/mutation/serialization.js +6 -3
- package/dist/operations/mutation/upsert.d.ts +3 -1
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +51 -12
- package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
- package/dist/operations/mutation/validate-upsert.js +18 -2
- package/dist/operations/mutation/validation.d.ts.map +1 -1
- package/dist/operations/mutation/validation.js +8 -0
- package/dist/operations/semantic-advisor/analysis-receipt.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/analysis-receipt.js +7 -1
- package/dist/operations/semantic-advisor/analyze-prose.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/analyze-prose.js +76 -61
- package/dist/operations/semantic-advisor/clauses.d.ts +1 -0
- package/dist/operations/semantic-advisor/clauses.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/clauses.js +7 -7
- package/dist/operations/semantic-advisor/ingestion-boundary.d.ts +18 -0
- package/dist/operations/semantic-advisor/ingestion-boundary.d.ts.map +1 -0
- package/dist/operations/semantic-advisor/ingestion-boundary.js +167 -0
- package/dist/operations/semantic-advisor/shared.d.ts +8 -0
- package/dist/operations/semantic-advisor/shared.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/shared.js +37 -3
- package/dist/operations/semantic-advisor/types.d.ts +5 -0
- package/dist/operations/semantic-advisor/types.d.ts.map +1 -1
- package/dist/prolog/codec.d.ts.map +1 -1
- package/dist/prolog/codec.js +9 -2
- package/dist/prolog.d.ts +6 -0
- package/dist/prolog.d.ts.map +1 -1
- package/dist/prolog.js +240 -61
- package/dist/public/diagnostic-usage.d.ts +17 -0
- package/dist/public/diagnostic-usage.d.ts.map +1 -0
- package/dist/public/diagnostic-usage.js +152 -0
- package/dist/public/distribution-parity.d.ts +90 -0
- package/dist/public/distribution-parity.d.ts.map +1 -0
- package/dist/public/distribution-parity.js +367 -0
- package/dist/public/impact/full-kb-quality.d.ts +2 -0
- package/dist/public/impact/full-kb-quality.d.ts.map +1 -1
- package/dist/public/impact/full-kb-quality.js +53 -1
- package/dist/public/impact-diagnostics.d.ts +2 -0
- package/dist/public/impact-diagnostics.d.ts.map +1 -1
- package/dist/public/impact-diagnostics.js +1 -0
- package/dist/public/operations/catalog.d.ts +151 -6
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/check-executor.d.ts.map +1 -1
- package/dist/public/operations/check-executor.js +4 -0
- package/dist/public/operations/discovery-executors.d.ts +6 -0
- package/dist/public/operations/discovery-executors.d.ts.map +1 -1
- package/dist/public/operations/discovery-executors.js +18 -2
- package/dist/public/operations/index.d.ts +4 -0
- package/dist/public/operations/index.d.ts.map +1 -1
- package/dist/public/operations/index.js +4 -0
- package/dist/public/operations/legacy-migration-plan.d.ts +113 -0
- package/dist/public/operations/legacy-migration-plan.d.ts.map +1 -0
- package/dist/public/operations/legacy-migration-plan.js +409 -0
- package/dist/public/operations/node-ports.d.ts.map +1 -1
- package/dist/public/operations/node-ports.js +90 -0
- package/dist/public/operations/repair-plan.d.ts +184 -0
- package/dist/public/operations/repair-plan.d.ts.map +1 -0
- package/dist/public/operations/repair-plan.js +397 -0
- package/dist/public/operations/runtime-types.d.ts +7 -0
- package/dist/public/operations/runtime-types.d.ts.map +1 -1
- package/dist/public/operations/specs/check.d.ts +2 -2
- package/dist/public/operations/specs/check.js +2 -2
- package/dist/public/operations/specs/discovery.d.ts +1 -1
- package/dist/public/operations/specs/discovery.js +1 -1
- package/dist/public/operations/specs/modeling.d.ts +19 -1
- package/dist/public/operations/specs/modeling.d.ts.map +1 -1
- package/dist/public/operations/specs/modeling.js +16 -1
- package/dist/public/operations/specs/mutation-schemas.d.ts +96 -1
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +40 -1
- package/dist/public/operations/specs/reporting.d.ts +42 -1
- package/dist/public/operations/specs/reporting.d.ts.map +1 -1
- package/dist/public/operations/specs/reporting.js +70 -6
- package/dist/public/operations/specs/semantic.js +1 -1
- package/dist/public/operations/specs/upsert.d.ts +96 -1
- package/dist/public/operations/specs/upsert.d.ts.map +1 -1
- package/dist/public/operations/workspace-snapshot.d.ts +10 -0
- package/dist/public/operations/workspace-snapshot.d.ts.map +1 -0
- package/dist/public/operations/workspace-snapshot.js +20 -0
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +43 -1
- package/dist/public/skills/kibi-traceability/SKILL.md +7 -1
- package/dist/public/skills/kibi-usage/SKILL.md +10 -4
- package/dist/public/skills/kibi-usage/resources/fact-lanes.md +1 -1
- package/dist/public/skills/kibi-usage/resources/logic-ir.md +1 -1
- package/dist/public/skills/kibi-usage/resources/workflows.md +19 -2
- package/dist/public/telemetry-acceptance.d.ts +89 -0
- package/dist/public/telemetry-acceptance.d.ts.map +1 -0
- package/dist/public/telemetry-acceptance.js +597 -0
- package/dist/public/telemetry-remediation.d.ts +33 -0
- package/dist/public/telemetry-remediation.d.ts.map +1 -0
- package/dist/public/telemetry-remediation.js +257 -0
- package/dist/public/verification-receipt.d.ts +75 -0
- package/dist/public/verification-receipt.d.ts.map +1 -0
- package/dist/public/verification-receipt.js +129 -0
- package/dist/schemas/entity.schema.json +96 -2
- package/dist/traceability/temp-kb.d.ts.map +1 -1
- package/dist/traceability/temp-kb.js +36 -3
- package/dist/types/entities.d.ts +1 -0
- package/dist/types/entities.d.ts.map +1 -1
- package/dist/utils/rule-registry.d.ts +2 -0
- package/dist/utils/rule-registry.d.ts.map +1 -1
- package/package.json +30 -2
- package/src/public/diagnostic-usage.ts +206 -0
- package/src/public/distribution-parity.ts +580 -0
- package/src/public/impact/full-kb-quality.ts +74 -1
- package/src/public/impact-diagnostics.ts +16 -0
- package/src/public/operations/check-executor.ts +4 -0
- package/src/public/operations/discovery-executors.ts +24 -2
- package/src/public/operations/index.ts +4 -0
- package/src/public/operations/legacy-migration-plan.ts +688 -0
- package/src/public/operations/node-ports.ts +109 -0
- package/src/public/operations/repair-plan.ts +562 -0
- package/src/public/operations/runtime-types.ts +8 -0
- package/src/public/operations/specs/check.ts +2 -2
- package/src/public/operations/specs/discovery.ts +1 -1
- package/src/public/operations/specs/modeling.ts +19 -1
- package/src/public/operations/specs/mutation-schemas.ts +47 -1
- package/src/public/operations/specs/reporting.ts +91 -6
- package/src/public/operations/specs/semantic.ts +1 -1
- package/src/public/operations/workspace-snapshot.ts +28 -0
- package/src/public/schemas/entity.ts +44 -1
- package/src/public/skills/kibi-traceability/SKILL.md +7 -1
- package/src/public/skills/kibi-usage/SKILL.md +10 -4
- package/src/public/skills/kibi-usage/resources/fact-lanes.md +1 -1
- package/src/public/skills/kibi-usage/resources/logic-ir.md +1 -1
- package/src/public/skills/kibi-usage/resources/workflows.md +19 -2
- package/src/public/telemetry-acceptance.ts +859 -0
- package/src/public/telemetry-remediation.ts +462 -0
- package/src/public/verification-receipt.ts +170 -0
- package/src/schemas/entity.schema.json +96 -2
|
@@ -0,0 +1,580 @@
|
|
|
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
|
+
|
|
11
|
+
import { existsSync, readFileSync, realpathSync } from "node:fs";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
|
|
14
|
+
export const DISTRIBUTION_PARITY_VERSION =
|
|
15
|
+
"kibi.distribution-parity.v1" as const;
|
|
16
|
+
|
|
17
|
+
export const REQUIREMENT_COMPILER_CAPABILITIES = [
|
|
18
|
+
"semantic_inventory",
|
|
19
|
+
"contradiction_witnesses",
|
|
20
|
+
"conservative_proof",
|
|
21
|
+
"repair_plan",
|
|
22
|
+
"verification_receipts",
|
|
23
|
+
"telemetry_acceptance",
|
|
24
|
+
] as const;
|
|
25
|
+
|
|
26
|
+
export type RequirementCompilerCapability =
|
|
27
|
+
(typeof REQUIREMENT_COMPILER_CAPABILITIES)[number];
|
|
28
|
+
export type DistributionRuntimeKind =
|
|
29
|
+
| "source_checkout"
|
|
30
|
+
| "packed_artifact"
|
|
31
|
+
| "project_resolved";
|
|
32
|
+
export type DistributionSurface = "cli" | "mcp";
|
|
33
|
+
export type CapabilityState = "supported" | "unsupported" | "failed";
|
|
34
|
+
|
|
35
|
+
export interface DistributionRuntimeProvenance {
|
|
36
|
+
readonly status: "resolved" | "unresolved";
|
|
37
|
+
readonly executable: string;
|
|
38
|
+
readonly entrypoint?: string;
|
|
39
|
+
readonly packageRoot?: string;
|
|
40
|
+
readonly version?: string;
|
|
41
|
+
readonly evidence: "executable_resolution" | "entrypoint_resolution";
|
|
42
|
+
readonly detail?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface DistributionRuntime {
|
|
46
|
+
readonly id: string;
|
|
47
|
+
readonly kind: DistributionRuntimeKind;
|
|
48
|
+
readonly surface: DistributionSurface;
|
|
49
|
+
readonly project?: string;
|
|
50
|
+
readonly provenance: DistributionRuntimeProvenance;
|
|
51
|
+
readonly actions?: Partial<
|
|
52
|
+
Record<RequirementCompilerCapability, DistributionParityAction>
|
|
53
|
+
>;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface DistributionParityAction {
|
|
57
|
+
readonly kind: "upgrade" | "compatibility";
|
|
58
|
+
readonly detail: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface DistributionCapabilityResult {
|
|
62
|
+
readonly state: CapabilityState;
|
|
63
|
+
readonly outcome?: unknown;
|
|
64
|
+
readonly diagnosticIds?: readonly string[];
|
|
65
|
+
readonly detail?: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface DistributionRuntimeAdapter {
|
|
69
|
+
readonly runtime: DistributionRuntime;
|
|
70
|
+
readonly execute: (
|
|
71
|
+
capability: RequirementCompilerCapability,
|
|
72
|
+
) => Promise<DistributionCapabilityResult>;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface DistributionParityObservation
|
|
76
|
+
extends DistributionCapabilityResult {
|
|
77
|
+
readonly runtimeId: string;
|
|
78
|
+
readonly capability: RequirementCompilerCapability;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export type DistributionComparison =
|
|
82
|
+
| "match"
|
|
83
|
+
| "diverged"
|
|
84
|
+
| "unsupported"
|
|
85
|
+
| "failed"
|
|
86
|
+
| "not_compared";
|
|
87
|
+
|
|
88
|
+
export interface DistributionParityRow {
|
|
89
|
+
readonly runtimeId: string;
|
|
90
|
+
readonly kind: DistributionRuntimeKind;
|
|
91
|
+
readonly surface: DistributionSurface;
|
|
92
|
+
readonly project?: string;
|
|
93
|
+
readonly capability: RequirementCompilerCapability;
|
|
94
|
+
readonly state: CapabilityState | "missing";
|
|
95
|
+
readonly comparison: DistributionComparison;
|
|
96
|
+
readonly referenceRuntimeId?: string;
|
|
97
|
+
readonly normalizedOutcome?: unknown;
|
|
98
|
+
readonly diagnosticIds: readonly string[];
|
|
99
|
+
readonly action?: DistributionParityAction;
|
|
100
|
+
readonly detail?: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export type DistributionParityIssueCode =
|
|
104
|
+
| "duplicate_runtime_id"
|
|
105
|
+
| "missing_current_runtime"
|
|
106
|
+
| "unresolved_runtime_provenance"
|
|
107
|
+
| "missing_capability_observation"
|
|
108
|
+
| "duplicate_capability_observation"
|
|
109
|
+
| "current_capability_unsupported"
|
|
110
|
+
| "capability_execution_failed"
|
|
111
|
+
| "source_packed_mismatch"
|
|
112
|
+
| "project_divergence_without_action";
|
|
113
|
+
|
|
114
|
+
export interface DistributionParityIssue {
|
|
115
|
+
readonly code: DistributionParityIssueCode;
|
|
116
|
+
readonly runtimeId?: string;
|
|
117
|
+
readonly surface?: DistributionSurface;
|
|
118
|
+
readonly capability?: RequirementCompilerCapability;
|
|
119
|
+
readonly detail: string;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface DistributionParityReport {
|
|
123
|
+
readonly version: typeof DISTRIBUTION_PARITY_VERSION;
|
|
124
|
+
readonly status: "passed" | "failed";
|
|
125
|
+
readonly capabilities: readonly RequirementCompilerCapability[];
|
|
126
|
+
readonly runtimes: readonly DistributionRuntime[];
|
|
127
|
+
readonly rows: readonly DistributionParityRow[];
|
|
128
|
+
readonly issues: readonly DistributionParityIssue[];
|
|
129
|
+
readonly summary: {
|
|
130
|
+
readonly runtimeCount: number;
|
|
131
|
+
readonly observationCount: number;
|
|
132
|
+
readonly matchCount: number;
|
|
133
|
+
readonly divergenceCount: number;
|
|
134
|
+
readonly unsupportedCount: number;
|
|
135
|
+
readonly failedCount: number;
|
|
136
|
+
readonly actionCount: number;
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export interface DistributionParityOptions {
|
|
141
|
+
readonly workspaceRoots?: readonly string[];
|
|
142
|
+
readonly volatileKeys?: ReadonlySet<string>;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const DEFAULT_VOLATILE_KEYS = new Set([
|
|
146
|
+
"_diagnostic_telemetry",
|
|
147
|
+
"active_branch",
|
|
148
|
+
"artifact_digest",
|
|
149
|
+
"branch",
|
|
150
|
+
"branchName",
|
|
151
|
+
"code_snapshot",
|
|
152
|
+
"created_at",
|
|
153
|
+
"createdAt",
|
|
154
|
+
"elapsedMs",
|
|
155
|
+
"environment_hash",
|
|
156
|
+
"finished_at",
|
|
157
|
+
"finishedAt",
|
|
158
|
+
"pid",
|
|
159
|
+
"planId",
|
|
160
|
+
"prologPid",
|
|
161
|
+
"receipt_id",
|
|
162
|
+
"request_id",
|
|
163
|
+
"requestId",
|
|
164
|
+
"snapshot_id",
|
|
165
|
+
"snapshotId",
|
|
166
|
+
"started_at",
|
|
167
|
+
"startedAt",
|
|
168
|
+
"timestamp",
|
|
169
|
+
"updated_at",
|
|
170
|
+
"updatedAt",
|
|
171
|
+
"usageLogLineNumber",
|
|
172
|
+
"verificationSnapshot",
|
|
173
|
+
]);
|
|
174
|
+
|
|
175
|
+
type PackageManifest = {
|
|
176
|
+
readonly name?: string;
|
|
177
|
+
readonly version?: string;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
function nearestPackageInfo(entrypoint: string): {
|
|
181
|
+
readonly packageRoot?: string;
|
|
182
|
+
readonly version?: string;
|
|
183
|
+
} {
|
|
184
|
+
let current = path.dirname(entrypoint);
|
|
185
|
+
while (true) {
|
|
186
|
+
const manifestPath = path.join(current, "package.json");
|
|
187
|
+
if (existsSync(manifestPath)) {
|
|
188
|
+
try {
|
|
189
|
+
const manifest = JSON.parse(
|
|
190
|
+
readFileSync(manifestPath, "utf8"),
|
|
191
|
+
) as PackageManifest;
|
|
192
|
+
return {
|
|
193
|
+
packageRoot: current,
|
|
194
|
+
...(manifest.version === undefined
|
|
195
|
+
? {}
|
|
196
|
+
: { version: manifest.version }),
|
|
197
|
+
};
|
|
198
|
+
} catch {
|
|
199
|
+
return { packageRoot: current };
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
const parent = path.dirname(current);
|
|
203
|
+
if (parent === current) return {};
|
|
204
|
+
current = parent;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function declaredEntrypoint(contents: string): string | undefined {
|
|
209
|
+
const shimTarget = contents.match(/^# cmd-shim-target=(.+)$/m)?.[1]?.trim();
|
|
210
|
+
if (shimTarget) return shimTarget;
|
|
211
|
+
const absoluteImport = contents.match(/\bfrom\s+["'](\/(?:[^"']+))["']/)?.[1];
|
|
212
|
+
return absoluteImport;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// implements REQ-kibi-distribution-parity-matrix
|
|
216
|
+
export function resolveDistributionRuntimeProvenance(
|
|
217
|
+
executable: string,
|
|
218
|
+
): DistributionRuntimeProvenance {
|
|
219
|
+
const requested = path.resolve(executable);
|
|
220
|
+
if (!existsSync(requested)) {
|
|
221
|
+
return {
|
|
222
|
+
status: "unresolved",
|
|
223
|
+
executable: requested,
|
|
224
|
+
evidence: "executable_resolution",
|
|
225
|
+
detail: `Executable does not exist: ${requested}`,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
const resolvedExecutable = realpathSync(requested);
|
|
230
|
+
const contents = readFileSync(resolvedExecutable, "utf8");
|
|
231
|
+
const declared = declaredEntrypoint(contents);
|
|
232
|
+
const entrypoint = declared
|
|
233
|
+
? realpathSync(path.resolve(path.dirname(resolvedExecutable), declared))
|
|
234
|
+
: resolvedExecutable;
|
|
235
|
+
const packageInfo = nearestPackageInfo(entrypoint);
|
|
236
|
+
return {
|
|
237
|
+
status: "resolved",
|
|
238
|
+
executable: resolvedExecutable,
|
|
239
|
+
entrypoint,
|
|
240
|
+
...packageInfo,
|
|
241
|
+
evidence:
|
|
242
|
+
entrypoint === resolvedExecutable
|
|
243
|
+
? "executable_resolution"
|
|
244
|
+
: "entrypoint_resolution",
|
|
245
|
+
};
|
|
246
|
+
} catch (error) {
|
|
247
|
+
return {
|
|
248
|
+
status: "unresolved",
|
|
249
|
+
executable: requested,
|
|
250
|
+
evidence: "executable_resolution",
|
|
251
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function normalizeString(value: string, roots: readonly string[]): string {
|
|
257
|
+
let normalized = value;
|
|
258
|
+
for (const root of [...roots].sort(
|
|
259
|
+
(left, right) => right.length - left.length,
|
|
260
|
+
)) {
|
|
261
|
+
normalized = normalized.replaceAll(root, "<workspace>");
|
|
262
|
+
}
|
|
263
|
+
return normalized
|
|
264
|
+
.replaceAll(
|
|
265
|
+
/[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/gi,
|
|
266
|
+
"<uuid>",
|
|
267
|
+
)
|
|
268
|
+
.replaceAll(
|
|
269
|
+
/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z\b/g,
|
|
270
|
+
"<timestamp>",
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// implements REQ-kibi-distribution-parity-matrix
|
|
275
|
+
export function normalizeDistributionParityValue(
|
|
276
|
+
value: unknown,
|
|
277
|
+
options: DistributionParityOptions = {},
|
|
278
|
+
): unknown {
|
|
279
|
+
if (typeof value === "string") {
|
|
280
|
+
return normalizeString(value, options.workspaceRoots ?? []);
|
|
281
|
+
}
|
|
282
|
+
if (Array.isArray(value)) {
|
|
283
|
+
return value.map((entry) =>
|
|
284
|
+
normalizeDistributionParityValue(entry, options),
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
if (value === null || typeof value !== "object") {
|
|
288
|
+
return value;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const volatileKeys = options.volatileKeys ?? DEFAULT_VOLATILE_KEYS;
|
|
292
|
+
const normalized: Record<string, unknown> = {};
|
|
293
|
+
for (const key of Object.keys(value).sort()) {
|
|
294
|
+
if (volatileKeys.has(key)) continue;
|
|
295
|
+
normalized[key] = normalizeDistributionParityValue(
|
|
296
|
+
(value as Record<string, unknown>)[key],
|
|
297
|
+
options,
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
return normalized;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function semanticFingerprint(value: unknown): string {
|
|
304
|
+
return JSON.stringify(value);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function sortedUnique(values: readonly string[] | undefined): string[] {
|
|
308
|
+
return [...new Set(values ?? [])].sort((left, right) =>
|
|
309
|
+
left.localeCompare(right),
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function currentRuntime(
|
|
314
|
+
runtimes: readonly DistributionRuntime[],
|
|
315
|
+
kind: "source_checkout" | "packed_artifact",
|
|
316
|
+
surface: DistributionSurface,
|
|
317
|
+
): DistributionRuntime | undefined {
|
|
318
|
+
return runtimes.find(
|
|
319
|
+
(runtime) => runtime.kind === kind && runtime.surface === surface,
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function observationKey(
|
|
324
|
+
runtimeId: string,
|
|
325
|
+
capability: RequirementCompilerCapability,
|
|
326
|
+
): string {
|
|
327
|
+
return `${runtimeId}\0${capability}`;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function compareObservation(
|
|
331
|
+
observation: DistributionParityObservation,
|
|
332
|
+
reference: DistributionParityObservation | undefined,
|
|
333
|
+
normalized: unknown,
|
|
334
|
+
normalizedReference: unknown,
|
|
335
|
+
): DistributionComparison {
|
|
336
|
+
if (observation.state === "failed") return "failed";
|
|
337
|
+
if (observation.state === "unsupported") return "unsupported";
|
|
338
|
+
if (!reference || reference.state !== "supported") return "not_compared";
|
|
339
|
+
return semanticFingerprint(normalized) ===
|
|
340
|
+
semanticFingerprint(normalizedReference)
|
|
341
|
+
? "match"
|
|
342
|
+
: "diverged";
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// implements REQ-kibi-distribution-parity-matrix
|
|
346
|
+
export function buildDistributionParityReport(
|
|
347
|
+
runtimes: readonly DistributionRuntime[],
|
|
348
|
+
observations: readonly DistributionParityObservation[],
|
|
349
|
+
options: DistributionParityOptions = {},
|
|
350
|
+
): DistributionParityReport {
|
|
351
|
+
const issues: DistributionParityIssue[] = [];
|
|
352
|
+
const runtimeIds = new Set<string>();
|
|
353
|
+
for (const runtime of runtimes) {
|
|
354
|
+
if (runtimeIds.has(runtime.id)) {
|
|
355
|
+
issues.push({
|
|
356
|
+
code: "duplicate_runtime_id",
|
|
357
|
+
runtimeId: runtime.id,
|
|
358
|
+
surface: runtime.surface,
|
|
359
|
+
detail: `Runtime id ${runtime.id} is declared more than once.`,
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
runtimeIds.add(runtime.id);
|
|
363
|
+
if (runtime.provenance.status === "unresolved") {
|
|
364
|
+
issues.push({
|
|
365
|
+
code: "unresolved_runtime_provenance",
|
|
366
|
+
runtimeId: runtime.id,
|
|
367
|
+
surface: runtime.surface,
|
|
368
|
+
detail:
|
|
369
|
+
runtime.provenance.detail ??
|
|
370
|
+
`Runtime ${runtime.id} has no executable resolution evidence.`,
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
for (const surface of ["cli", "mcp"] as const) {
|
|
376
|
+
for (const kind of ["source_checkout", "packed_artifact"] as const) {
|
|
377
|
+
if (!currentRuntime(runtimes, kind, surface)) {
|
|
378
|
+
issues.push({
|
|
379
|
+
code: "missing_current_runtime",
|
|
380
|
+
surface,
|
|
381
|
+
detail: `Missing ${kind} runtime for ${surface}.`,
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
const indexed = new Map<string, DistributionParityObservation>();
|
|
388
|
+
for (const observation of observations) {
|
|
389
|
+
const key = observationKey(observation.runtimeId, observation.capability);
|
|
390
|
+
if (indexed.has(key)) {
|
|
391
|
+
issues.push({
|
|
392
|
+
code: "duplicate_capability_observation",
|
|
393
|
+
runtimeId: observation.runtimeId,
|
|
394
|
+
capability: observation.capability,
|
|
395
|
+
detail: `Capability ${observation.capability} was observed more than once for ${observation.runtimeId}.`,
|
|
396
|
+
});
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
indexed.set(key, observation);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const rows: DistributionParityRow[] = [];
|
|
403
|
+
for (const runtime of [...runtimes].sort((left, right) =>
|
|
404
|
+
left.id.localeCompare(right.id),
|
|
405
|
+
)) {
|
|
406
|
+
const source = currentRuntime(runtimes, "source_checkout", runtime.surface);
|
|
407
|
+
for (const capability of REQUIREMENT_COMPILER_CAPABILITIES) {
|
|
408
|
+
const observation = indexed.get(observationKey(runtime.id, capability));
|
|
409
|
+
const reference = source
|
|
410
|
+
? indexed.get(observationKey(source.id, capability))
|
|
411
|
+
: undefined;
|
|
412
|
+
const action = runtime.actions?.[capability];
|
|
413
|
+
if (!observation) {
|
|
414
|
+
issues.push({
|
|
415
|
+
code: "missing_capability_observation",
|
|
416
|
+
runtimeId: runtime.id,
|
|
417
|
+
surface: runtime.surface,
|
|
418
|
+
capability,
|
|
419
|
+
detail: `Runtime ${runtime.id} has no ${capability} observation.`,
|
|
420
|
+
});
|
|
421
|
+
rows.push({
|
|
422
|
+
runtimeId: runtime.id,
|
|
423
|
+
kind: runtime.kind,
|
|
424
|
+
surface: runtime.surface,
|
|
425
|
+
...(runtime.project === undefined
|
|
426
|
+
? {}
|
|
427
|
+
: { project: runtime.project }),
|
|
428
|
+
capability,
|
|
429
|
+
state: "missing",
|
|
430
|
+
comparison: "not_compared",
|
|
431
|
+
...(source === undefined ? {} : { referenceRuntimeId: source.id }),
|
|
432
|
+
diagnosticIds: [],
|
|
433
|
+
...(action === undefined ? {} : { action }),
|
|
434
|
+
});
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
const normalized = normalizeDistributionParityValue(
|
|
439
|
+
observation.outcome,
|
|
440
|
+
options,
|
|
441
|
+
);
|
|
442
|
+
const normalizedReference = normalizeDistributionParityValue(
|
|
443
|
+
reference?.outcome,
|
|
444
|
+
options,
|
|
445
|
+
);
|
|
446
|
+
const comparison =
|
|
447
|
+
runtime.kind === "source_checkout"
|
|
448
|
+
? observation.state === "supported"
|
|
449
|
+
? "match"
|
|
450
|
+
: observation.state
|
|
451
|
+
: compareObservation(
|
|
452
|
+
observation,
|
|
453
|
+
reference,
|
|
454
|
+
normalized,
|
|
455
|
+
normalizedReference,
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
if (
|
|
459
|
+
runtime.kind !== "project_resolved" &&
|
|
460
|
+
observation.state === "unsupported"
|
|
461
|
+
) {
|
|
462
|
+
issues.push({
|
|
463
|
+
code: "current_capability_unsupported",
|
|
464
|
+
runtimeId: runtime.id,
|
|
465
|
+
surface: runtime.surface,
|
|
466
|
+
capability,
|
|
467
|
+
detail: `Current ${runtime.kind} runtime does not support ${capability}.`,
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
if (observation.state === "failed") {
|
|
471
|
+
issues.push({
|
|
472
|
+
code: "capability_execution_failed",
|
|
473
|
+
runtimeId: runtime.id,
|
|
474
|
+
surface: runtime.surface,
|
|
475
|
+
capability,
|
|
476
|
+
detail:
|
|
477
|
+
observation.detail ??
|
|
478
|
+
`Runtime ${runtime.id} failed while executing ${capability}.`,
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
if (runtime.kind === "packed_artifact" && comparison === "diverged") {
|
|
482
|
+
issues.push({
|
|
483
|
+
code: "source_packed_mismatch",
|
|
484
|
+
runtimeId: runtime.id,
|
|
485
|
+
surface: runtime.surface,
|
|
486
|
+
capability,
|
|
487
|
+
detail: `Packed ${runtime.surface} outcome diverges from source for ${capability}.`,
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
if (
|
|
491
|
+
runtime.kind === "project_resolved" &&
|
|
492
|
+
(comparison === "diverged" || comparison === "unsupported") &&
|
|
493
|
+
!action
|
|
494
|
+
) {
|
|
495
|
+
issues.push({
|
|
496
|
+
code: "project_divergence_without_action",
|
|
497
|
+
runtimeId: runtime.id,
|
|
498
|
+
surface: runtime.surface,
|
|
499
|
+
capability,
|
|
500
|
+
detail: `Project runtime ${runtime.id} needs an upgrade or compatibility action for ${capability}.`,
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
rows.push({
|
|
505
|
+
runtimeId: runtime.id,
|
|
506
|
+
kind: runtime.kind,
|
|
507
|
+
surface: runtime.surface,
|
|
508
|
+
...(runtime.project === undefined ? {} : { project: runtime.project }),
|
|
509
|
+
capability,
|
|
510
|
+
state: observation.state,
|
|
511
|
+
comparison,
|
|
512
|
+
...(runtime.kind === "source_checkout" || source === undefined
|
|
513
|
+
? {}
|
|
514
|
+
: { referenceRuntimeId: source.id }),
|
|
515
|
+
...(observation.state === "supported"
|
|
516
|
+
? { normalizedOutcome: normalized }
|
|
517
|
+
: {}),
|
|
518
|
+
diagnosticIds: sortedUnique(observation.diagnosticIds),
|
|
519
|
+
...(action === undefined ? {} : { action }),
|
|
520
|
+
...(observation.detail === undefined
|
|
521
|
+
? {}
|
|
522
|
+
: { detail: observation.detail }),
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
return {
|
|
528
|
+
version: DISTRIBUTION_PARITY_VERSION,
|
|
529
|
+
status: issues.length === 0 ? "passed" : "failed",
|
|
530
|
+
capabilities: REQUIREMENT_COMPILER_CAPABILITIES,
|
|
531
|
+
runtimes: [...runtimes].sort((left, right) =>
|
|
532
|
+
left.id.localeCompare(right.id),
|
|
533
|
+
),
|
|
534
|
+
rows,
|
|
535
|
+
issues,
|
|
536
|
+
summary: {
|
|
537
|
+
runtimeCount: runtimes.length,
|
|
538
|
+
observationCount: observations.length,
|
|
539
|
+
matchCount: rows.filter((row) => row.comparison === "match").length,
|
|
540
|
+
divergenceCount: rows.filter((row) => row.comparison === "diverged")
|
|
541
|
+
.length,
|
|
542
|
+
unsupportedCount: rows.filter((row) => row.state === "unsupported")
|
|
543
|
+
.length,
|
|
544
|
+
failedCount: rows.filter((row) => row.state === "failed").length,
|
|
545
|
+
actionCount: rows.filter((row) => row.action !== undefined).length,
|
|
546
|
+
},
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// implements REQ-kibi-distribution-parity-matrix
|
|
551
|
+
export async function runDistributionParityMatrix(
|
|
552
|
+
adapters: readonly DistributionRuntimeAdapter[],
|
|
553
|
+
options: DistributionParityOptions = {},
|
|
554
|
+
): Promise<DistributionParityReport> {
|
|
555
|
+
const observations: DistributionParityObservation[] = [];
|
|
556
|
+
for (const adapter of adapters) {
|
|
557
|
+
for (const capability of REQUIREMENT_COMPILER_CAPABILITIES) {
|
|
558
|
+
try {
|
|
559
|
+
const result = await adapter.execute(capability);
|
|
560
|
+
observations.push({
|
|
561
|
+
runtimeId: adapter.runtime.id,
|
|
562
|
+
capability,
|
|
563
|
+
...result,
|
|
564
|
+
});
|
|
565
|
+
} catch (error) {
|
|
566
|
+
observations.push({
|
|
567
|
+
runtimeId: adapter.runtime.id,
|
|
568
|
+
capability,
|
|
569
|
+
state: "failed",
|
|
570
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
return buildDistributionParityReport(
|
|
576
|
+
adapters.map((adapter) => adapter.runtime),
|
|
577
|
+
observations,
|
|
578
|
+
options,
|
|
579
|
+
);
|
|
580
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
1
3
|
import type {
|
|
2
4
|
ExtractedEntity,
|
|
3
5
|
ExtractionResult,
|
|
@@ -8,6 +10,11 @@ import {
|
|
|
8
10
|
parseListOfLists,
|
|
9
11
|
parseTriples,
|
|
10
12
|
} from "../../prolog/codec.js";
|
|
13
|
+
import {
|
|
14
|
+
analyzeTelemetryAcceptance,
|
|
15
|
+
createTelemetryAcceptanceDiagnostics,
|
|
16
|
+
parseTelemetryUsageLog,
|
|
17
|
+
} from "../telemetry-acceptance.js";
|
|
11
18
|
import { createCoverageDepthQualityDiagnostics } from "./coverage-depth-quality.js";
|
|
12
19
|
import { createRequirementQualityDiagnostics } from "./requirement-quality.js";
|
|
13
20
|
import { createSymbolQualityDiagnostics } from "./symbol-quality.js";
|
|
@@ -36,6 +43,8 @@ type FullKbQualityDiagnosticsOptions = {
|
|
|
36
43
|
readonly prolog: Pick<PrologProcess, "query">;
|
|
37
44
|
readonly hardViolationEntityIds?: ReadonlySet<string>;
|
|
38
45
|
readonly maxDiagnostics?: number;
|
|
46
|
+
readonly workspaceRoot?: string;
|
|
47
|
+
readonly now?: Date;
|
|
39
48
|
};
|
|
40
49
|
|
|
41
50
|
function stringField(entity: Record<string, unknown>, key: string): string {
|
|
@@ -88,6 +97,8 @@ function toExtractedEntity(entity: Record<string, unknown>): ExtractedEntity {
|
|
|
88
97
|
if (severity !== undefined) extracted.severity = severity;
|
|
89
98
|
const textRef = optionalStringField(entity, "text_ref");
|
|
90
99
|
if (textRef !== undefined) extracted.text_ref = textRef;
|
|
100
|
+
const semanticText = optionalStringField(entity, "semantic_text");
|
|
101
|
+
if (semanticText !== undefined) extracted.semantic_text = semanticText;
|
|
91
102
|
const logicClaims = optionalStringArrayField(entity, "logic_claims");
|
|
92
103
|
if (logicClaims !== undefined) extracted.logic_claims = logicClaims;
|
|
93
104
|
const granularityReason = optionalStringField(entity, "granularity_reason");
|
|
@@ -206,13 +217,75 @@ function capDiagnostics(
|
|
|
206
217
|
: diagnostics;
|
|
207
218
|
}
|
|
208
219
|
|
|
220
|
+
function telemetryReadDiagnostic(message: string): QualityDiagnostic {
|
|
221
|
+
return {
|
|
222
|
+
id: "telemetry_evidence_unreadable",
|
|
223
|
+
severity: "review",
|
|
224
|
+
blocking: false,
|
|
225
|
+
category: "telemetry",
|
|
226
|
+
source: ".kb/usage.log",
|
|
227
|
+
message,
|
|
228
|
+
suggestion:
|
|
229
|
+
"Repair or regenerate .kb/usage.log through Kibi diagnostic mode, then rerun kibi usage-metrics --require-acceptance and an unfiltered kb_check.",
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async function collectTelemetryDiagnostics(
|
|
234
|
+
workspaceRoot: string | undefined,
|
|
235
|
+
now: Date,
|
|
236
|
+
): Promise<readonly QualityDiagnostic[]> {
|
|
237
|
+
if (workspaceRoot === undefined) return [];
|
|
238
|
+
const usageLogPath = path.join(workspaceRoot, ".kb", "usage.log");
|
|
239
|
+
let contents: string;
|
|
240
|
+
try {
|
|
241
|
+
contents = await readFile(usageLogPath, "utf8");
|
|
242
|
+
} catch (error) {
|
|
243
|
+
if (
|
|
244
|
+
typeof error === "object" &&
|
|
245
|
+
error !== null &&
|
|
246
|
+
"code" in error &&
|
|
247
|
+
error.code === "ENOENT"
|
|
248
|
+
) {
|
|
249
|
+
return [];
|
|
250
|
+
}
|
|
251
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
252
|
+
return [
|
|
253
|
+
telemetryReadDiagnostic(
|
|
254
|
+
`Telemetry acceptance evidence is unreadable: ${message}`,
|
|
255
|
+
),
|
|
256
|
+
];
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
try {
|
|
260
|
+
const report = analyzeTelemetryAcceptance(
|
|
261
|
+
parseTelemetryUsageLog(contents),
|
|
262
|
+
now,
|
|
263
|
+
);
|
|
264
|
+
return createTelemetryAcceptanceDiagnostics(report);
|
|
265
|
+
} catch (error) {
|
|
266
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
267
|
+
return [
|
|
268
|
+
telemetryReadDiagnostic(
|
|
269
|
+
`Telemetry acceptance evidence is malformed: ${message}`,
|
|
270
|
+
),
|
|
271
|
+
];
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
209
275
|
export async function collectFullKbQualityDiagnostics(
|
|
210
276
|
options: FullKbQualityDiagnosticsOptions,
|
|
211
277
|
): Promise<readonly QualityDiagnostic[]> {
|
|
212
|
-
const manifestResults = await
|
|
278
|
+
const [manifestResults, telemetryDiagnostics] = await Promise.all([
|
|
279
|
+
loadKbExtractionResults(options.prolog),
|
|
280
|
+
collectTelemetryDiagnostics(
|
|
281
|
+
options.workspaceRoot,
|
|
282
|
+
options.now ?? new Date(),
|
|
283
|
+
),
|
|
284
|
+
]);
|
|
213
285
|
const coverageDepthDiagnostics =
|
|
214
286
|
createCoverageDepthQualityDiagnostics(manifestResults);
|
|
215
287
|
const diagnostics = [
|
|
288
|
+
...telemetryDiagnostics,
|
|
216
289
|
...createRequirementQualityDiagnostics({
|
|
217
290
|
manifestResults,
|
|
218
291
|
...(options.hardViolationEntityIds !== undefined
|