kibi-cli 0.16.1 → 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/check.d.ts.map +1 -1
- package/dist/commands/check.js +1 -1
- 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/manifest.d.ts +12 -1
- package/dist/commands/sync/manifest.d.ts.map +1 -1
- package/dist/commands/sync/manifest.js +22 -5
- package/dist/commands/sync/persistence.d.ts.map +1 -1
- package/dist/commands/sync/persistence.js +76 -2
- 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 +17 -1
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +81 -2
- package/dist/logic/ir.d.ts +112 -0
- package/dist/logic/ir.d.ts.map +1 -0
- package/dist/logic/ir.js +729 -0
- package/dist/operations/modeling/logic-modeling.d.ts +22 -0
- package/dist/operations/modeling/logic-modeling.d.ts.map +1 -0
- package/dist/operations/modeling/logic-modeling.js +120 -0
- package/dist/operations/modeling/model-requirement.d.ts.map +1 -1
- package/dist/operations/modeling/model-requirement.js +83 -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 +29 -4
- package/dist/operations/modeling/predicate-inference.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-inference.js +3 -0
- package/dist/operations/modeling/predicate-loader.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-loader.js +7 -1
- package/dist/operations/modeling/predicate-ranker.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-ranker.js +40 -2
- package/dist/operations/modeling/predicate-types.d.ts +12 -1
- package/dist/operations/modeling/predicate-types.d.ts.map +1 -1
- package/dist/operations/modeling/requirement-types.d.ts +12 -0
- package/dist/operations/modeling/requirement-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/relationships.d.ts.map +1 -1
- package/dist/operations/mutation/relationships.js +8 -0
- package/dist/operations/mutation/serialization.d.ts.map +1 -1
- package/dist/operations/mutation/serialization.js +6 -0
- package/dist/operations/mutation/strict-fact.d.ts.map +1 -1
- package/dist/operations/mutation/strict-fact.js +68 -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 +2 -2
- package/dist/operations/semantic-advisor/analysis-receipt.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/analysis-receipt.js +30 -16
- package/dist/operations/semantic-advisor/analyze-prose.d.ts +1 -1
- package/dist/operations/semantic-advisor/analyze-prose.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/analyze-prose.js +464 -27
- 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/observation-plan.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/observation-plan.js +15 -3
- package/dist/operations/semantic-advisor/shared.d.ts +9 -0
- package/dist/operations/semantic-advisor/shared.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/shared.js +38 -4
- package/dist/operations/semantic-advisor/types.d.ts +66 -1
- 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 +19 -2
- package/dist/prolog.d.ts +6 -0
- package/dist/prolog.d.ts.map +1 -1
- package/dist/prolog.js +247 -63
- 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 +235 -11
- 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 +5 -0
- package/dist/public/operations/index.d.ts.map +1 -1
- package/dist/public/operations/index.js +5 -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 +3 -3
- package/dist/public/operations/specs/check.d.ts.map +1 -1
- package/dist/public/operations/specs/check.js +5 -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 +35 -1
- package/dist/public/operations/specs/modeling.d.ts.map +1 -1
- package/dist/public/operations/specs/modeling.js +32 -1
- package/dist/public/operations/specs/mutation-schemas.d.ts +133 -3
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +67 -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.d.ts +30 -2
- package/dist/public/operations/specs/semantic.d.ts.map +1 -1
- package/dist/public/operations/specs/semantic.js +35 -3
- package/dist/public/operations/specs/upsert.d.ts +133 -3
- 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 +332 -0
- package/dist/public/schemas/relationship.d.ts.map +1 -1
- package/dist/public/schemas/relationship.js +1 -0
- package/dist/public/skills/kibi-traceability/SKILL.md +7 -1
- package/dist/public/skills/kibi-usage/SKILL.md +44 -12
- package/dist/public/skills/kibi-usage/resources/fact-lanes.md +12 -2
- package/dist/public/skills/kibi-usage/resources/logic-ir.md +43 -0
- package/dist/public/skills/kibi-usage/resources/operation-access.md +19 -19
- package/dist/public/skills/kibi-usage/resources/ui-requirements.md +96 -0
- package/dist/public/skills/kibi-usage/resources/workflows.md +40 -8
- package/dist/public/symbol-granularity.d.ts +9 -0
- package/dist/public/symbol-granularity.d.ts.map +1 -1
- package/dist/public/symbol-granularity.js +16 -0
- 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 +401 -4
- package/dist/traceability/staged-diagnostics.d.ts +1 -1
- package/dist/traceability/staged-diagnostics.d.ts.map +1 -1
- package/dist/traceability/staged-diagnostics.js +17 -10
- package/dist/traceability/staged-impact-contract.js +1 -1
- package/dist/traceability/staged-symbols-manifest.d.ts.map +1 -1
- package/dist/traceability/staged-symbols-manifest.js +28 -10
- package/dist/traceability/temp-kb.d.ts.map +1 -1
- package/dist/traceability/temp-kb.js +49 -3
- package/dist/types/entities.d.ts +1 -0
- package/dist/types/entities.d.ts.map +1 -1
- package/dist/types/relationships.d.ts +1 -1
- package/dist/types/relationships.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/dist/utils/rule-registry.js +18 -0
- package/dist/utils/schema-version.d.ts +1 -1
- package/dist/utils/schema-version.js +1 -1
- package/package.json +34 -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 +5 -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 +5 -2
- package/src/public/operations/specs/discovery.ts +1 -1
- package/src/public/operations/specs/modeling.ts +39 -1
- package/src/public/operations/specs/mutation-schemas.ts +77 -1
- package/src/public/operations/specs/reporting.ts +91 -6
- package/src/public/operations/specs/semantic.ts +42 -3
- package/src/public/operations/workspace-snapshot.ts +28 -0
- package/src/public/schemas/entity.ts +340 -1
- package/src/public/schemas/relationship.ts +1 -0
- package/src/public/skills/kibi-traceability/SKILL.md +7 -1
- package/src/public/skills/kibi-usage/SKILL.md +44 -12
- package/src/public/skills/kibi-usage/resources/fact-lanes.md +12 -2
- package/src/public/skills/kibi-usage/resources/logic-ir.md +43 -0
- package/src/public/skills/kibi-usage/resources/operation-access.md +19 -19
- package/src/public/skills/kibi-usage/resources/ui-requirements.md +96 -0
- package/src/public/skills/kibi-usage/resources/workflows.md +40 -8
- package/src/public/symbol-granularity.ts +25 -0
- 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 +401 -4
- package/src/schemas/relationship.schema.json +1 -0
|
@@ -0,0 +1,597 @@
|
|
|
1
|
+
export const TELEMETRY_ACCEPTANCE_VERSION = "kibi.telemetry-acceptance.v1";
|
|
2
|
+
export const DEFAULT_TELEMETRY_ACCEPTANCE_POLICY = {
|
|
3
|
+
eventLimit: 200,
|
|
4
|
+
minimumEvents: 20,
|
|
5
|
+
maxEvidenceAgeSeconds: 7 * 24 * 60 * 60,
|
|
6
|
+
maxFutureSkewSeconds: 5 * 60,
|
|
7
|
+
telemetryCompletenessMinimum: 0.95,
|
|
8
|
+
validationBeforeUpsertMinimum: 1,
|
|
9
|
+
advisorBeforeRequirementWriteMinimum: 1,
|
|
10
|
+
sourceLookupZeroResultMaximum: 0.2,
|
|
11
|
+
preflightMaxAgeSeconds: 60 * 60,
|
|
12
|
+
advisorMaxAgeSeconds: 24 * 60 * 60,
|
|
13
|
+
repeatedMutationFailureThreshold: 3,
|
|
14
|
+
};
|
|
15
|
+
function isRecord(value) {
|
|
16
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
17
|
+
}
|
|
18
|
+
export function parseTelemetryUsageLog(contents) {
|
|
19
|
+
const events = [];
|
|
20
|
+
for (const [index, line] of contents.split(/\r?\n/).entries()) {
|
|
21
|
+
const trimmed = line.trim();
|
|
22
|
+
if (!trimmed)
|
|
23
|
+
continue;
|
|
24
|
+
let parsed;
|
|
25
|
+
try {
|
|
26
|
+
parsed = JSON.parse(trimmed);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
30
|
+
throw new Error(`Failed to parse .kb/usage.log line ${index + 1}: ${message}`);
|
|
31
|
+
}
|
|
32
|
+
if (!isRecord(parsed)) {
|
|
33
|
+
throw new Error(`Failed to parse .kb/usage.log line ${index + 1}: expected object`);
|
|
34
|
+
}
|
|
35
|
+
events.push(parsed);
|
|
36
|
+
}
|
|
37
|
+
return events;
|
|
38
|
+
}
|
|
39
|
+
function eventArgs(event) {
|
|
40
|
+
return event.business_args ?? event.args ?? {};
|
|
41
|
+
}
|
|
42
|
+
function eventSucceeded(event) {
|
|
43
|
+
return event.status === "success" || event.success === true;
|
|
44
|
+
}
|
|
45
|
+
function eventFailed(event) {
|
|
46
|
+
return event.status === "error" || event.success === false;
|
|
47
|
+
}
|
|
48
|
+
function telemetryProvided(event) {
|
|
49
|
+
if (event.telemetry_status === "provided")
|
|
50
|
+
return true;
|
|
51
|
+
if (event.telemetry_status === "missing")
|
|
52
|
+
return false;
|
|
53
|
+
return event.telemetry !== null && event.telemetry !== undefined;
|
|
54
|
+
}
|
|
55
|
+
function timestampMillis(timestamp) {
|
|
56
|
+
if (timestamp === undefined)
|
|
57
|
+
return null;
|
|
58
|
+
const parsed = Date.parse(timestamp);
|
|
59
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
60
|
+
}
|
|
61
|
+
function canonicalValue(value) {
|
|
62
|
+
if (Array.isArray(value))
|
|
63
|
+
return value.map(canonicalValue);
|
|
64
|
+
if (!isRecord(value))
|
|
65
|
+
return value;
|
|
66
|
+
return Object.fromEntries(Object.entries(value)
|
|
67
|
+
.filter(([key]) => key !== "_diagnostic_telemetry")
|
|
68
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
69
|
+
.map(([key, child]) => [key, canonicalValue(child)]));
|
|
70
|
+
}
|
|
71
|
+
function mutationFingerprint(event) {
|
|
72
|
+
return (event.mutation_fingerprint ??
|
|
73
|
+
JSON.stringify(canonicalValue(eventArgs(event))));
|
|
74
|
+
}
|
|
75
|
+
function mutationTarget(event) {
|
|
76
|
+
if (event.mutation_target)
|
|
77
|
+
return event.mutation_target;
|
|
78
|
+
const args = eventArgs(event);
|
|
79
|
+
const type = typeof args.type === "string" ? args.type : "unknown";
|
|
80
|
+
const id = typeof args.id === "string" ? args.id : mutationFingerprint(event);
|
|
81
|
+
return `${type}:${id}`;
|
|
82
|
+
}
|
|
83
|
+
function rate(numerator, denominator) {
|
|
84
|
+
return denominator === 0 ? undefined : numerator / denominator;
|
|
85
|
+
}
|
|
86
|
+
function thresholdStatus(actual, operator, expected) {
|
|
87
|
+
if (actual === undefined)
|
|
88
|
+
return "not_applicable";
|
|
89
|
+
if (operator === ">=")
|
|
90
|
+
return actual >= expected ? "passed" : "failed";
|
|
91
|
+
if (operator === "<=")
|
|
92
|
+
return actual <= expected ? "passed" : "failed";
|
|
93
|
+
return actual < expected ? "passed" : "failed";
|
|
94
|
+
}
|
|
95
|
+
function withinAge(earlier, later, maxAgeSeconds) {
|
|
96
|
+
if (earlier === null || later === null || earlier > later)
|
|
97
|
+
return false;
|
|
98
|
+
return later - earlier <= maxAgeSeconds * 1_000;
|
|
99
|
+
}
|
|
100
|
+
function telemetryCorrelationValue(event, key) {
|
|
101
|
+
if (typeof event[key] === "string" && event[key].length > 0) {
|
|
102
|
+
return event[key];
|
|
103
|
+
}
|
|
104
|
+
return isRecord(event.telemetry) && typeof event.telemetry[key] === "string"
|
|
105
|
+
? event.telemetry[key]
|
|
106
|
+
: undefined;
|
|
107
|
+
}
|
|
108
|
+
function correlationCompatible(evidence, action) {
|
|
109
|
+
for (const key of ["session_id", "actor_id"]) {
|
|
110
|
+
const evidenceValue = telemetryCorrelationValue(evidence, key);
|
|
111
|
+
const actionValue = telemetryCorrelationValue(action, key);
|
|
112
|
+
if (evidenceValue !== undefined &&
|
|
113
|
+
actionValue !== undefined &&
|
|
114
|
+
evidenceValue !== actionValue) {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
function telemetryCompletenessMetric(recent, policy) {
|
|
121
|
+
const complete = recent.filter(({ event }) => telemetryProvided(event)).length;
|
|
122
|
+
const actual = rate(complete, recent.length);
|
|
123
|
+
const enoughEvidence = recent.length >= policy.minimumEvents;
|
|
124
|
+
return {
|
|
125
|
+
id: "telemetry_completeness",
|
|
126
|
+
status: enoughEvidence
|
|
127
|
+
? thresholdStatus(actual, ">=", policy.telemetryCompletenessMinimum)
|
|
128
|
+
: "insufficient_evidence",
|
|
129
|
+
numerator: complete,
|
|
130
|
+
denominator: recent.length,
|
|
131
|
+
...(actual !== undefined ? { rate: actual } : {}),
|
|
132
|
+
threshold: {
|
|
133
|
+
operator: ">=",
|
|
134
|
+
value: policy.telemetryCompletenessMinimum,
|
|
135
|
+
},
|
|
136
|
+
message: enoughEvidence
|
|
137
|
+
? `${complete}/${recent.length} recent events include diagnostic telemetry.`
|
|
138
|
+
: `Only ${recent.length}/${policy.minimumEvents} required recent events are available.`,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function validationBeforeUpsertMetric(all, recentStart, policy) {
|
|
142
|
+
const validPreflights = new Map();
|
|
143
|
+
let attempts = 0;
|
|
144
|
+
let validated = 0;
|
|
145
|
+
const unvalidatedTargets = new Set();
|
|
146
|
+
for (const current of all) {
|
|
147
|
+
if (current.event.tool === "kb_validate_upsert" &&
|
|
148
|
+
eventSucceeded(current.event) &&
|
|
149
|
+
current.event.validation_valid !== false) {
|
|
150
|
+
const fingerprint = mutationFingerprint(current.event);
|
|
151
|
+
const matches = validPreflights.get(fingerprint) ?? [];
|
|
152
|
+
matches.push(current);
|
|
153
|
+
validPreflights.set(fingerprint, matches);
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (current.event.tool !== "kb_upsert" || current.index < recentStart) {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
attempts += 1;
|
|
160
|
+
const fingerprint = mutationFingerprint(current.event);
|
|
161
|
+
const match = (validPreflights.get(fingerprint) ?? []).findLast((candidate) => correlationCompatible(candidate.event, current.event) &&
|
|
162
|
+
withinAge(candidate.time, current.time, policy.preflightMaxAgeSeconds));
|
|
163
|
+
if (match !== undefined) {
|
|
164
|
+
validated += 1;
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
unvalidatedTargets.add(mutationTarget(current.event));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const actual = rate(validated, attempts);
|
|
171
|
+
return {
|
|
172
|
+
id: "validation_before_upsert",
|
|
173
|
+
status: thresholdStatus(actual, ">=", policy.validationBeforeUpsertMinimum),
|
|
174
|
+
numerator: validated,
|
|
175
|
+
denominator: attempts,
|
|
176
|
+
...(actual !== undefined ? { rate: actual } : {}),
|
|
177
|
+
threshold: {
|
|
178
|
+
operator: ">=",
|
|
179
|
+
value: policy.validationBeforeUpsertMinimum,
|
|
180
|
+
},
|
|
181
|
+
message: attempts === 0
|
|
182
|
+
? "No upsert attempts occurred in the evaluated window."
|
|
183
|
+
: `${validated}/${attempts} upsert attempts had a recent successful preflight for the exact payload.`,
|
|
184
|
+
evidence: {
|
|
185
|
+
unvalidatedTargets: [...unvalidatedTargets].sort().slice(0, 20),
|
|
186
|
+
preflightMaxAgeSeconds: policy.preflightMaxAgeSeconds,
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function advisorBeforeRequirementWriteMetric(all, recentStart, policy) {
|
|
191
|
+
const advisors = new Map();
|
|
192
|
+
let attempts = 0;
|
|
193
|
+
let advised = 0;
|
|
194
|
+
const unadvisedRequirements = new Set();
|
|
195
|
+
for (const current of all) {
|
|
196
|
+
const args = eventArgs(current.event);
|
|
197
|
+
const id = typeof args.id === "string"
|
|
198
|
+
? args.id
|
|
199
|
+
: typeof args.requirementId === "string"
|
|
200
|
+
? args.requirementId
|
|
201
|
+
: undefined;
|
|
202
|
+
if (current.event.tool === "kb_semantic_advisor" &&
|
|
203
|
+
eventSucceeded(current.event) &&
|
|
204
|
+
id !== undefined) {
|
|
205
|
+
const matches = advisors.get(id) ?? [];
|
|
206
|
+
matches.push({
|
|
207
|
+
entry: current,
|
|
208
|
+
...(current.event.semantic_source_hash !== undefined
|
|
209
|
+
? { sourceHash: current.event.semantic_source_hash }
|
|
210
|
+
: {}),
|
|
211
|
+
});
|
|
212
|
+
advisors.set(id, matches);
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
if (current.event.tool !== "kb_upsert" ||
|
|
216
|
+
current.index < recentStart ||
|
|
217
|
+
args.type !== "req") {
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
attempts += 1;
|
|
221
|
+
const requirementId = id ?? mutationTarget(current.event);
|
|
222
|
+
const advisor = (advisors.get(requirementId) ?? []).findLast((candidate) => (candidate.sourceHash === undefined ||
|
|
223
|
+
current.event.semantic_source_hash === undefined ||
|
|
224
|
+
candidate.sourceHash === current.event.semantic_source_hash) &&
|
|
225
|
+
correlationCompatible(candidate.entry.event, current.event) &&
|
|
226
|
+
withinAge(candidate.entry.time, current.time, policy.advisorMaxAgeSeconds));
|
|
227
|
+
if (advisor !== undefined) {
|
|
228
|
+
advised += 1;
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
unadvisedRequirements.add(requirementId);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const actual = rate(advised, attempts);
|
|
235
|
+
return {
|
|
236
|
+
id: "advisor_before_requirement_write",
|
|
237
|
+
status: thresholdStatus(actual, ">=", policy.advisorBeforeRequirementWriteMinimum),
|
|
238
|
+
numerator: advised,
|
|
239
|
+
denominator: attempts,
|
|
240
|
+
...(actual !== undefined ? { rate: actual } : {}),
|
|
241
|
+
threshold: {
|
|
242
|
+
operator: ">=",
|
|
243
|
+
value: policy.advisorBeforeRequirementWriteMinimum,
|
|
244
|
+
},
|
|
245
|
+
message: attempts === 0
|
|
246
|
+
? "No requirement upsert attempts occurred in the evaluated window."
|
|
247
|
+
: `${advised}/${attempts} requirement upserts followed a recent semantic-advisor pass for the same requirement and source hash when observable.`,
|
|
248
|
+
evidence: {
|
|
249
|
+
unadvisedRequirements: [...unadvisedRequirements].sort().slice(0, 20),
|
|
250
|
+
advisorMaxAgeSeconds: policy.advisorMaxAgeSeconds,
|
|
251
|
+
},
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function sourceLookupMetric(recent, policy) {
|
|
255
|
+
const lookups = recent.filter(({ event }) => {
|
|
256
|
+
if ((event.tool !== "kb_query" && event.tool !== "kb_search") ||
|
|
257
|
+
!eventSucceeded(event)) {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
return typeof eventArgs(event).sourceFile === "string";
|
|
261
|
+
});
|
|
262
|
+
const zeroResults = lookups.filter(({ event }) => event.zero_results === true || event.result_count === 0);
|
|
263
|
+
const actual = rate(zeroResults.length, lookups.length);
|
|
264
|
+
const sourceCounts = new Map();
|
|
265
|
+
for (const { event } of zeroResults) {
|
|
266
|
+
const sourceFile = String(eventArgs(event).sourceFile);
|
|
267
|
+
sourceCounts.set(sourceFile, (sourceCounts.get(sourceFile) ?? 0) + 1);
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
id: "source_lookup_zero_result_rate",
|
|
271
|
+
status: thresholdStatus(actual, "<=", policy.sourceLookupZeroResultMaximum),
|
|
272
|
+
numerator: zeroResults.length,
|
|
273
|
+
denominator: lookups.length,
|
|
274
|
+
...(actual !== undefined ? { rate: actual } : {}),
|
|
275
|
+
threshold: {
|
|
276
|
+
operator: "<=",
|
|
277
|
+
value: policy.sourceLookupZeroResultMaximum,
|
|
278
|
+
},
|
|
279
|
+
message: lookups.length === 0
|
|
280
|
+
? "No source-linked query or search calls occurred in the evaluated window."
|
|
281
|
+
: `${zeroResults.length}/${lookups.length} source-linked lookups returned zero results.`,
|
|
282
|
+
evidence: {
|
|
283
|
+
zeroResultSourceFiles: [...sourceCounts.entries()]
|
|
284
|
+
.sort(([leftFile, leftCount], [rightFile, rightCount]) => rightCount - leftCount || leftFile.localeCompare(rightFile))
|
|
285
|
+
.slice(0, 20)
|
|
286
|
+
.map(([sourceFile, count]) => ({ sourceFile, count })),
|
|
287
|
+
},
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
function completeRequirementCoverageEvents(recent) {
|
|
291
|
+
return recent.filter(({ event }) => event.tool === "kb_coverage" &&
|
|
292
|
+
eventSucceeded(event) &&
|
|
293
|
+
(event.coverage_by ?? "req") === "req" &&
|
|
294
|
+
event.coverage_scope_complete === true &&
|
|
295
|
+
typeof event.coverage_proof_gap_count === "number");
|
|
296
|
+
}
|
|
297
|
+
function proofGapRecoveryMetric(recent) {
|
|
298
|
+
const coverage = completeRequirementCoverageEvents(recent);
|
|
299
|
+
const latest = coverage.at(-1)?.event.coverage_proof_gap_count;
|
|
300
|
+
const previous = coverage.at(-2)?.event.coverage_proof_gap_count;
|
|
301
|
+
if (latest === undefined) {
|
|
302
|
+
return {
|
|
303
|
+
id: "proof_gap_recovery",
|
|
304
|
+
status: "insufficient_evidence",
|
|
305
|
+
numerator: 0,
|
|
306
|
+
denominator: 0,
|
|
307
|
+
message: "No complete requirement coverage event with proof-gap telemetry is available.",
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
if (latest === 0) {
|
|
311
|
+
return {
|
|
312
|
+
id: "proof_gap_recovery",
|
|
313
|
+
status: "passed",
|
|
314
|
+
numerator: previous === undefined ? 0 : Math.max(0, previous - latest),
|
|
315
|
+
denominator: previous ?? latest,
|
|
316
|
+
message: "The latest complete requirement coverage event has zero proof gaps.",
|
|
317
|
+
evidence: { previousGapCount: previous ?? null, latestGapCount: latest },
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
if (previous === undefined) {
|
|
321
|
+
return {
|
|
322
|
+
id: "proof_gap_recovery",
|
|
323
|
+
status: "insufficient_evidence",
|
|
324
|
+
numerator: 0,
|
|
325
|
+
denominator: latest,
|
|
326
|
+
message: `The latest complete coverage event reports ${latest} proof gaps, but no comparable earlier event is available.`,
|
|
327
|
+
evidence: { previousGapCount: null, latestGapCount: latest },
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
const recovered = Math.max(0, previous - latest);
|
|
331
|
+
return {
|
|
332
|
+
id: "proof_gap_recovery",
|
|
333
|
+
status: latest < previous ? "passed" : "failed",
|
|
334
|
+
numerator: recovered,
|
|
335
|
+
denominator: previous,
|
|
336
|
+
rate: previous === 0 ? 0 : recovered / previous,
|
|
337
|
+
threshold: { operator: "<", value: previous },
|
|
338
|
+
message: latest < previous
|
|
339
|
+
? `Proof gaps decreased from ${previous} to ${latest}.`
|
|
340
|
+
: `Proof gaps did not recover: the previous complete report had ${previous} and the latest has ${latest}.`,
|
|
341
|
+
evidence: { previousGapCount: previous, latestGapCount: latest },
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
function receiptFreshnessMetric(recent) {
|
|
345
|
+
const latest = completeRequirementCoverageEvents(recent).at(-1)?.event;
|
|
346
|
+
if (latest === undefined || latest.coverage_receipt_gap_count === undefined) {
|
|
347
|
+
return {
|
|
348
|
+
id: "e2e_receipt_freshness",
|
|
349
|
+
status: "insufficient_evidence",
|
|
350
|
+
numerator: 0,
|
|
351
|
+
denominator: 0,
|
|
352
|
+
message: "No complete requirement coverage event with receipt-freshness telemetry is available.",
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
const gapCount = latest.coverage_receipt_gap_count;
|
|
356
|
+
return {
|
|
357
|
+
id: "e2e_receipt_freshness",
|
|
358
|
+
status: gapCount === 0 ? "passed" : "failed",
|
|
359
|
+
numerator: gapCount,
|
|
360
|
+
denominator: Number(latest.coverage_proof_gap_count ?? gapCount),
|
|
361
|
+
threshold: { operator: "<=", value: 0 },
|
|
362
|
+
message: gapCount === 0
|
|
363
|
+
? "The latest complete requirement coverage event has no receipt-specific gaps."
|
|
364
|
+
: `The latest complete requirement coverage event has ${gapCount} missing, stale, failed, invalid, or uncheckable receipt gaps.`,
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
function repeatedMutationFailuresMetric(recent, policy) {
|
|
368
|
+
const streaks = new Map();
|
|
369
|
+
const maxima = new Map();
|
|
370
|
+
const categories = new Map();
|
|
371
|
+
let attempts = 0;
|
|
372
|
+
for (const { event } of recent) {
|
|
373
|
+
if (event.tool !== "kb_upsert")
|
|
374
|
+
continue;
|
|
375
|
+
attempts += 1;
|
|
376
|
+
const target = mutationTarget(event);
|
|
377
|
+
if (eventFailed(event)) {
|
|
378
|
+
const next = (streaks.get(target) ?? 0) + 1;
|
|
379
|
+
streaks.set(target, next);
|
|
380
|
+
maxima.set(target, Math.max(maxima.get(target) ?? 0, next));
|
|
381
|
+
if (event.error_category) {
|
|
382
|
+
const targetCategories = categories.get(target) ?? new Set();
|
|
383
|
+
targetCategories.add(event.error_category);
|
|
384
|
+
categories.set(target, targetCategories);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
else if (eventSucceeded(event)) {
|
|
388
|
+
streaks.set(target, 0);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
const repeated = [...maxima.entries()]
|
|
392
|
+
.filter(([, count]) => count >= policy.repeatedMutationFailureThreshold)
|
|
393
|
+
.sort(([leftTarget, leftCount], [rightTarget, rightCount]) => rightCount - leftCount || leftTarget.localeCompare(rightTarget));
|
|
394
|
+
return {
|
|
395
|
+
id: "repeated_mutation_failures",
|
|
396
|
+
status: attempts === 0
|
|
397
|
+
? "not_applicable"
|
|
398
|
+
: repeated.length === 0
|
|
399
|
+
? "passed"
|
|
400
|
+
: "failed",
|
|
401
|
+
numerator: repeated.length,
|
|
402
|
+
denominator: attempts,
|
|
403
|
+
threshold: {
|
|
404
|
+
operator: "<",
|
|
405
|
+
value: policy.repeatedMutationFailureThreshold,
|
|
406
|
+
},
|
|
407
|
+
message: attempts === 0
|
|
408
|
+
? "No upsert attempts occurred in the evaluated window."
|
|
409
|
+
: repeated.length === 0
|
|
410
|
+
? `No target reached ${policy.repeatedMutationFailureThreshold} consecutive mutation failures.`
|
|
411
|
+
: `${repeated.length} target(s) reached at least ${policy.repeatedMutationFailureThreshold} consecutive mutation failures.`,
|
|
412
|
+
evidence: {
|
|
413
|
+
targets: repeated.slice(0, 20).map(([target, count]) => ({
|
|
414
|
+
target,
|
|
415
|
+
consecutiveFailures: count,
|
|
416
|
+
errorCategories: [...(categories.get(target) ?? [])].sort(),
|
|
417
|
+
})),
|
|
418
|
+
},
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
function reportStatus(metrics, fresh) {
|
|
422
|
+
if (!fresh)
|
|
423
|
+
return "insufficient_evidence";
|
|
424
|
+
if (metrics.some((metric) => metric.status === "failed"))
|
|
425
|
+
return "failed";
|
|
426
|
+
if (metrics.some((metric) => metric.status === "insufficient_evidence")) {
|
|
427
|
+
return "insufficient_evidence";
|
|
428
|
+
}
|
|
429
|
+
return "passed";
|
|
430
|
+
}
|
|
431
|
+
export function analyzeTelemetryAcceptance(events, now = new Date(), policy = DEFAULT_TELEMETRY_ACCEPTANCE_POLICY) {
|
|
432
|
+
const all = events.map((event, index) => ({
|
|
433
|
+
event,
|
|
434
|
+
index,
|
|
435
|
+
time: timestampMillis(event.timestamp),
|
|
436
|
+
}));
|
|
437
|
+
const recentStart = Math.max(0, all.length - policy.eventLimit);
|
|
438
|
+
const recent = all.slice(recentStart);
|
|
439
|
+
const validTimes = recent
|
|
440
|
+
.map((entry) => entry.time)
|
|
441
|
+
.filter((value) => value !== null)
|
|
442
|
+
.sort((left, right) => left - right);
|
|
443
|
+
const firstTime = validTimes[0] ?? null;
|
|
444
|
+
const lastTime = validTimes.at(-1) ?? null;
|
|
445
|
+
const ageSeconds = lastTime === null ? null : Math.round((now.getTime() - lastTime) / 1_000);
|
|
446
|
+
const fresh = ageSeconds !== null &&
|
|
447
|
+
ageSeconds <= policy.maxEvidenceAgeSeconds &&
|
|
448
|
+
ageSeconds >= -policy.maxFutureSkewSeconds;
|
|
449
|
+
const metrics = [
|
|
450
|
+
telemetryCompletenessMetric(recent, policy),
|
|
451
|
+
advisorBeforeRequirementWriteMetric(all, recentStart, policy),
|
|
452
|
+
validationBeforeUpsertMetric(all, recentStart, policy),
|
|
453
|
+
sourceLookupMetric(recent, policy),
|
|
454
|
+
proofGapRecoveryMetric(recent),
|
|
455
|
+
receiptFreshnessMetric(recent),
|
|
456
|
+
repeatedMutationFailuresMetric(recent, policy),
|
|
457
|
+
];
|
|
458
|
+
const diagnostics = [];
|
|
459
|
+
if (events.length === 0)
|
|
460
|
+
diagnostics.push("usage_log_empty");
|
|
461
|
+
if (lastTime === null && events.length > 0) {
|
|
462
|
+
diagnostics.push("usage_log_timestamps_unavailable");
|
|
463
|
+
}
|
|
464
|
+
else if (!fresh) {
|
|
465
|
+
diagnostics.push(ageSeconds !== null && ageSeconds < -policy.maxFutureSkewSeconds
|
|
466
|
+
? "usage_log_future_dated"
|
|
467
|
+
: "usage_log_stale");
|
|
468
|
+
}
|
|
469
|
+
return {
|
|
470
|
+
version: TELEMETRY_ACCEPTANCE_VERSION,
|
|
471
|
+
status: reportStatus(metrics, fresh),
|
|
472
|
+
evaluatedAt: now.toISOString(),
|
|
473
|
+
policy,
|
|
474
|
+
scope: {
|
|
475
|
+
totalEvents: events.length,
|
|
476
|
+
evaluatedEvents: recent.length,
|
|
477
|
+
truncated: events.length > recent.length,
|
|
478
|
+
firstTimestamp: firstTime === null ? null : new Date(firstTime).toISOString(),
|
|
479
|
+
lastTimestamp: lastTime === null ? null : new Date(lastTime).toISOString(),
|
|
480
|
+
evidenceAgeSeconds: ageSeconds,
|
|
481
|
+
fresh,
|
|
482
|
+
},
|
|
483
|
+
metrics,
|
|
484
|
+
diagnostics,
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
const METRIC_DIAGNOSTICS = {
|
|
488
|
+
telemetry_completeness: {
|
|
489
|
+
id: "telemetry_completeness_low",
|
|
490
|
+
severity: "warning",
|
|
491
|
+
rank: 70,
|
|
492
|
+
suggestion: "Enable diagnostic mode and supply complete _diagnostic_telemetry on every MCP operation, then rerun the workflow.",
|
|
493
|
+
},
|
|
494
|
+
advisor_before_requirement_write: {
|
|
495
|
+
id: "semantic_advisor_bypassed",
|
|
496
|
+
severity: "warning",
|
|
497
|
+
rank: 30,
|
|
498
|
+
suggestion: "Run kb_semantic_advisor on the complete current requirement prose before its next upsert, preserve the returned source hash, and recheck telemetry.",
|
|
499
|
+
},
|
|
500
|
+
validation_before_upsert: {
|
|
501
|
+
id: "mutation_validation_bypassed",
|
|
502
|
+
severity: "warning",
|
|
503
|
+
rank: 20,
|
|
504
|
+
suggestion: "Run kb_validate_upsert for the exact payload no more than one hour before each sequential kb_upsert attempt.",
|
|
505
|
+
},
|
|
506
|
+
source_lookup_zero_result_rate: {
|
|
507
|
+
id: "source_lookup_zero_result_rate_high",
|
|
508
|
+
severity: "warning",
|
|
509
|
+
rank: 60,
|
|
510
|
+
suggestion: "Inspect the cited source files, refresh symbol/source links when stale, and repeat focused kb_search then exact kb_query lookups.",
|
|
511
|
+
},
|
|
512
|
+
proof_gap_recovery: {
|
|
513
|
+
id: "proof_gap_recovery_stalled",
|
|
514
|
+
severity: "warning",
|
|
515
|
+
rank: 50,
|
|
516
|
+
suggestion: "Run complete requirement coverage, apply one reviewed ready repair batch per requirement, and rerun coverage to demonstrate a smaller gap count.",
|
|
517
|
+
},
|
|
518
|
+
e2e_receipt_freshness: {
|
|
519
|
+
id: "e2e_receipt_freshness_low",
|
|
520
|
+
severity: "warning",
|
|
521
|
+
rank: 40,
|
|
522
|
+
suggestion: "Run each scenario-backed E2E test against the live snapshot, append a passing kibi.verification-receipt.v1, sync, and rerun complete coverage.",
|
|
523
|
+
},
|
|
524
|
+
repeated_mutation_failures: {
|
|
525
|
+
id: "repeated_mutation_failures",
|
|
526
|
+
severity: "warning",
|
|
527
|
+
rank: 10,
|
|
528
|
+
suggestion: "Stop retrying the failing target; query current endpoints, preflight the exact reduced payload, repair runtime health if needed, and retry once.",
|
|
529
|
+
},
|
|
530
|
+
};
|
|
531
|
+
export function createTelemetryAcceptanceDiagnostics(report) {
|
|
532
|
+
const diagnostics = [];
|
|
533
|
+
if (!report.scope.fresh) {
|
|
534
|
+
diagnostics.push({
|
|
535
|
+
id: "telemetry_evidence_stale",
|
|
536
|
+
severity: "review",
|
|
537
|
+
blocking: false,
|
|
538
|
+
category: "telemetry",
|
|
539
|
+
source: ".kb/usage.log",
|
|
540
|
+
message: report.scope.lastTimestamp === null
|
|
541
|
+
? "Telemetry acceptance has no valid timestamped evidence, so current workflow quality is unresolved."
|
|
542
|
+
: `Telemetry evidence is not current (latest ${report.scope.lastTimestamp}); historical metrics cannot prove current workflow quality.`,
|
|
543
|
+
suggestion: "Run the current Kibi workflow in diagnostic mode, then rerun kibi usage-metrics --require-acceptance and an unfiltered kb_check.",
|
|
544
|
+
evidence: {
|
|
545
|
+
version: report.version,
|
|
546
|
+
rank: 5,
|
|
547
|
+
scope: report.scope,
|
|
548
|
+
diagnostics: report.diagnostics,
|
|
549
|
+
},
|
|
550
|
+
rank: 5,
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
const insufficient = report.metrics.filter((metric) => metric.status === "insufficient_evidence");
|
|
554
|
+
if (insufficient.length > 0) {
|
|
555
|
+
diagnostics.push({
|
|
556
|
+
id: "telemetry_acceptance_incomplete",
|
|
557
|
+
severity: "review",
|
|
558
|
+
blocking: false,
|
|
559
|
+
category: "telemetry",
|
|
560
|
+
source: ".kb/usage.log",
|
|
561
|
+
message: `Telemetry cannot evaluate ${insufficient.length} required metric(s): ${insufficient
|
|
562
|
+
.map((metric) => metric.id)
|
|
563
|
+
.join(", ")}.`,
|
|
564
|
+
suggestion: "Capture complete diagnostic events, including a complete requirement coverage run, then rerun the telemetry acceptance report.",
|
|
565
|
+
evidence: {
|
|
566
|
+
version: report.version,
|
|
567
|
+
rank: 80,
|
|
568
|
+
metrics: insufficient,
|
|
569
|
+
},
|
|
570
|
+
rank: 80,
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
for (const metric of report.metrics) {
|
|
574
|
+
if (metric.status !== "failed")
|
|
575
|
+
continue;
|
|
576
|
+
const definition = METRIC_DIAGNOSTICS[metric.id];
|
|
577
|
+
diagnostics.push({
|
|
578
|
+
id: definition.id,
|
|
579
|
+
severity: definition.severity,
|
|
580
|
+
blocking: false,
|
|
581
|
+
category: "telemetry",
|
|
582
|
+
source: ".kb/usage.log",
|
|
583
|
+
message: metric.message,
|
|
584
|
+
suggestion: definition.suggestion,
|
|
585
|
+
evidence: {
|
|
586
|
+
version: report.version,
|
|
587
|
+
rank: definition.rank,
|
|
588
|
+
metric,
|
|
589
|
+
scope: report.scope,
|
|
590
|
+
},
|
|
591
|
+
rank: definition.rank,
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
return diagnostics
|
|
595
|
+
.sort((left, right) => left.rank - right.rank || left.id.localeCompare(right.id))
|
|
596
|
+
.map(({ rank: _rank, ...diagnostic }) => diagnostic);
|
|
597
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type TelemetryAcceptancePolicy, type TelemetryAcceptanceReport, type TelemetryMetricId, type TelemetryUsageEvent } from "./telemetry-acceptance.js";
|
|
2
|
+
export declare const TELEMETRY_REMEDIATION_VERSION: "kibi.telemetry-remediation.v1";
|
|
3
|
+
export interface TelemetryRemediationEventReference {
|
|
4
|
+
readonly logLine: number;
|
|
5
|
+
readonly requestId: string | null;
|
|
6
|
+
readonly timestamp: string | null;
|
|
7
|
+
readonly tool: string | null;
|
|
8
|
+
readonly sessionId: string | null;
|
|
9
|
+
readonly actorId: string | null;
|
|
10
|
+
}
|
|
11
|
+
export interface TelemetryRemediationItem {
|
|
12
|
+
readonly id: string;
|
|
13
|
+
readonly rank: number;
|
|
14
|
+
readonly metric: TelemetryMetricId | "evidence_freshness";
|
|
15
|
+
readonly scope: "event" | "report";
|
|
16
|
+
readonly target: string;
|
|
17
|
+
readonly reason: string;
|
|
18
|
+
readonly action: string;
|
|
19
|
+
readonly event: TelemetryRemediationEventReference | null;
|
|
20
|
+
}
|
|
21
|
+
export interface TelemetryRemediationReport {
|
|
22
|
+
readonly version: typeof TELEMETRY_REMEDIATION_VERSION;
|
|
23
|
+
readonly status: "clear" | "action_required";
|
|
24
|
+
readonly acceptance: TelemetryAcceptanceReport;
|
|
25
|
+
readonly summary: Readonly<{
|
|
26
|
+
total: number;
|
|
27
|
+
eventItems: number;
|
|
28
|
+
reportItems: number;
|
|
29
|
+
}>;
|
|
30
|
+
readonly items: readonly TelemetryRemediationItem[];
|
|
31
|
+
}
|
|
32
|
+
export declare function buildTelemetryRemediationReport(events: readonly TelemetryUsageEvent[], now?: Date, policy?: TelemetryAcceptancePolicy): TelemetryRemediationReport;
|
|
33
|
+
//# sourceMappingURL=telemetry-remediation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry-remediation.d.ts","sourceRoot":"","sources":["../../src/public/telemetry-remediation.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,yBAAyB,EAC9B,KAAK,yBAAyB,EAC9B,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EAEzB,MAAM,2BAA2B,CAAC;AAEnC,eAAO,MAAM,6BAA6B,EACxC,+BAAwC,CAAC;AAE3C,MAAM,WAAW,kCAAkC;IACjD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,GAAG,oBAAoB,CAAC;IAC1D,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,kCAAkC,GAAG,IAAI,CAAC;CAC3D;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,OAAO,EAAE,OAAO,6BAA6B,CAAC;IACvD,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,iBAAiB,CAAC;IAC7C,QAAQ,CAAC,UAAU,EAAE,yBAAyB,CAAC;IAC/C,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;QACzB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC,CAAC;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,wBAAwB,EAAE,CAAC;CACrD;AAyJD,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,SAAS,mBAAmB,EAAE,EACtC,GAAG,GAAE,IAAiB,EACtB,MAAM,GAAE,yBAA+D,GACtE,0BAA0B,CAqQ5B"}
|