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,257 @@
|
|
|
1
|
+
import { diagnosticMutationFingerprint } from "./diagnostic-usage.js";
|
|
2
|
+
import { DEFAULT_TELEMETRY_ACCEPTANCE_POLICY, analyzeTelemetryAcceptance, } from "./telemetry-acceptance.js";
|
|
3
|
+
export const TELEMETRY_REMEDIATION_VERSION = "kibi.telemetry-remediation.v1";
|
|
4
|
+
const RANKS = {
|
|
5
|
+
repeated_mutation_failures: 10,
|
|
6
|
+
validation_before_upsert: 20,
|
|
7
|
+
advisor_before_requirement_write: 30,
|
|
8
|
+
e2e_receipt_freshness: 40,
|
|
9
|
+
proof_gap_recovery: 50,
|
|
10
|
+
source_lookup_zero_result_rate: 60,
|
|
11
|
+
telemetry_completeness: 70,
|
|
12
|
+
evidence_freshness: 5,
|
|
13
|
+
};
|
|
14
|
+
function isRecord(value) {
|
|
15
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
16
|
+
}
|
|
17
|
+
function args(event) {
|
|
18
|
+
return event.business_args ?? event.args ?? {};
|
|
19
|
+
}
|
|
20
|
+
function succeeded(event) {
|
|
21
|
+
return event.status === "success" || event.success === true;
|
|
22
|
+
}
|
|
23
|
+
function failed(event) {
|
|
24
|
+
return event.status === "error" || event.success === false;
|
|
25
|
+
}
|
|
26
|
+
function telemetryProvided(event) {
|
|
27
|
+
if (event.telemetry_status === "provided")
|
|
28
|
+
return true;
|
|
29
|
+
if (event.telemetry_status === "missing")
|
|
30
|
+
return false;
|
|
31
|
+
return event.telemetry !== null && event.telemetry !== undefined;
|
|
32
|
+
}
|
|
33
|
+
function correlationValue(event, key) {
|
|
34
|
+
if (typeof event[key] === "string" && event[key].length > 0) {
|
|
35
|
+
return event[key];
|
|
36
|
+
}
|
|
37
|
+
return isRecord(event.telemetry) && typeof event.telemetry[key] === "string"
|
|
38
|
+
? event.telemetry[key]
|
|
39
|
+
: undefined;
|
|
40
|
+
}
|
|
41
|
+
function compatible(left, right) {
|
|
42
|
+
return ["session_id", "actor_id"].every((key) => {
|
|
43
|
+
const leftValue = correlationValue(left, key);
|
|
44
|
+
const rightValue = correlationValue(right, key);
|
|
45
|
+
return (leftValue === undefined ||
|
|
46
|
+
rightValue === undefined ||
|
|
47
|
+
leftValue === rightValue);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
function withinAge(earlier, later, seconds) {
|
|
51
|
+
return (earlier !== null &&
|
|
52
|
+
later !== null &&
|
|
53
|
+
earlier <= later &&
|
|
54
|
+
later - earlier <= seconds * 1_000);
|
|
55
|
+
}
|
|
56
|
+
function fingerprint(event) {
|
|
57
|
+
return (event.mutation_fingerprint ?? diagnosticMutationFingerprint(args(event)));
|
|
58
|
+
}
|
|
59
|
+
function target(event) {
|
|
60
|
+
if (event.mutation_target)
|
|
61
|
+
return event.mutation_target;
|
|
62
|
+
const eventArgs = args(event);
|
|
63
|
+
const type = typeof eventArgs.type === "string" ? eventArgs.type : "unknown";
|
|
64
|
+
const id = typeof eventArgs.id === "string" ? eventArgs.id : fingerprint(event);
|
|
65
|
+
return `${type}:${id}`;
|
|
66
|
+
}
|
|
67
|
+
function reference(entry) {
|
|
68
|
+
return {
|
|
69
|
+
logLine: entry.index + 1,
|
|
70
|
+
requestId: entry.event.request_id ?? null,
|
|
71
|
+
timestamp: entry.event.timestamp ?? null,
|
|
72
|
+
tool: entry.event.tool ?? null,
|
|
73
|
+
sessionId: correlationValue(entry.event, "session_id") ?? null,
|
|
74
|
+
actorId: correlationValue(entry.event, "actor_id") ?? null,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function eventItem(metric, entry, itemTarget, reason, action) {
|
|
78
|
+
return {
|
|
79
|
+
id: `${metric}:line-${entry.index + 1}:${itemTarget}`,
|
|
80
|
+
rank: RANKS[metric],
|
|
81
|
+
metric,
|
|
82
|
+
scope: "event",
|
|
83
|
+
target: itemTarget,
|
|
84
|
+
reason,
|
|
85
|
+
action,
|
|
86
|
+
event: reference(entry),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function reportItem(metric, itemTarget, reason, action) {
|
|
90
|
+
return {
|
|
91
|
+
id: `${metric}:report:${itemTarget}`,
|
|
92
|
+
rank: RANKS[metric],
|
|
93
|
+
metric,
|
|
94
|
+
scope: "report",
|
|
95
|
+
target: itemTarget,
|
|
96
|
+
reason,
|
|
97
|
+
action,
|
|
98
|
+
event: null,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function isActionable(acceptance, metric) {
|
|
102
|
+
const status = acceptance.metrics.find((candidate) => candidate.id === metric)?.status;
|
|
103
|
+
return status === "failed" || status === "insufficient_evidence";
|
|
104
|
+
}
|
|
105
|
+
export function buildTelemetryRemediationReport(events, now = new Date(), policy = DEFAULT_TELEMETRY_ACCEPTANCE_POLICY) {
|
|
106
|
+
const acceptance = analyzeTelemetryAcceptance(events, now, policy);
|
|
107
|
+
const all = events.map((event, index) => ({
|
|
108
|
+
event,
|
|
109
|
+
index,
|
|
110
|
+
time: event.timestamp === undefined ||
|
|
111
|
+
!Number.isFinite(Date.parse(event.timestamp))
|
|
112
|
+
? null
|
|
113
|
+
: Date.parse(event.timestamp),
|
|
114
|
+
}));
|
|
115
|
+
const recentStart = Math.max(0, all.length - policy.eventLimit);
|
|
116
|
+
const recent = all.slice(recentStart);
|
|
117
|
+
const items = [];
|
|
118
|
+
if (!acceptance.scope.fresh) {
|
|
119
|
+
items.push(reportItem("evidence_freshness", ".kb/usage.log", "The acceptance window has no current timestamped evidence.", "Run the current workflow in diagnostic mode, then regenerate this report."));
|
|
120
|
+
}
|
|
121
|
+
if (isActionable(acceptance, "telemetry_completeness")) {
|
|
122
|
+
for (const entry of recent.filter(({ event }) => !telemetryProvided(event))) {
|
|
123
|
+
items.push(eventItem("telemetry_completeness", entry, entry.event.tool ?? "unknown tool", "Diagnostic telemetry is missing for this event.", "Repeat this operation in diagnostic mode with complete _diagnostic_telemetry."));
|
|
124
|
+
}
|
|
125
|
+
if (recent.length < policy.minimumEvents) {
|
|
126
|
+
items.push(reportItem("telemetry_completeness", "acceptance window", `Only ${recent.length}/${policy.minimumEvents} required events are available.`, "Capture enough current diagnostic events to satisfy the minimum evidence window."));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (isActionable(acceptance, "validation_before_upsert")) {
|
|
130
|
+
const preflights = new Map();
|
|
131
|
+
for (const entry of all) {
|
|
132
|
+
if (entry.event.tool === "kb_validate_upsert" &&
|
|
133
|
+
succeeded(entry.event) &&
|
|
134
|
+
entry.event.validation_valid !== false) {
|
|
135
|
+
const matches = preflights.get(fingerprint(entry.event)) ?? [];
|
|
136
|
+
matches.push(entry);
|
|
137
|
+
preflights.set(fingerprint(entry.event), matches);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (entry.index < recentStart || entry.event.tool !== "kb_upsert")
|
|
141
|
+
continue;
|
|
142
|
+
const match = (preflights.get(fingerprint(entry.event)) ?? []).findLast((candidate) => compatible(candidate.event, entry.event) &&
|
|
143
|
+
withinAge(candidate.time, entry.time, policy.preflightMaxAgeSeconds));
|
|
144
|
+
if (match === undefined) {
|
|
145
|
+
items.push(eventItem("validation_before_upsert", entry, target(entry.event), "No recent successful preflight matches this exact payload and correlation context.", "Run kb_validate_upsert for this exact payload in the same session/actor context before retrying once."));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (isActionable(acceptance, "advisor_before_requirement_write")) {
|
|
150
|
+
const advisors = new Map();
|
|
151
|
+
for (const entry of all) {
|
|
152
|
+
const eventArgs = args(entry.event);
|
|
153
|
+
const id = typeof eventArgs.id === "string"
|
|
154
|
+
? eventArgs.id
|
|
155
|
+
: typeof eventArgs.requirementId === "string"
|
|
156
|
+
? eventArgs.requirementId
|
|
157
|
+
: undefined;
|
|
158
|
+
if (entry.event.tool === "kb_semantic_advisor" &&
|
|
159
|
+
succeeded(entry.event) &&
|
|
160
|
+
id) {
|
|
161
|
+
const matches = advisors.get(id) ?? [];
|
|
162
|
+
matches.push(entry);
|
|
163
|
+
advisors.set(id, matches);
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
if (entry.index < recentStart ||
|
|
167
|
+
entry.event.tool !== "kb_upsert" ||
|
|
168
|
+
eventArgs.type !== "req") {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
const requirementId = id ?? target(entry.event);
|
|
172
|
+
const match = (advisors.get(requirementId) ?? []).findLast((candidate) => compatible(candidate.event, entry.event) &&
|
|
173
|
+
(candidate.event.semantic_source_hash === undefined ||
|
|
174
|
+
entry.event.semantic_source_hash === undefined ||
|
|
175
|
+
candidate.event.semantic_source_hash ===
|
|
176
|
+
entry.event.semantic_source_hash) &&
|
|
177
|
+
withinAge(candidate.time, entry.time, policy.advisorMaxAgeSeconds));
|
|
178
|
+
if (match === undefined) {
|
|
179
|
+
items.push(eventItem("advisor_before_requirement_write", entry, requirementId, "No recent semantic-advisor event matches this requirement, source hash, and correlation context.", "Run kb_semantic_advisor on the complete prose in the same session/actor context before the next upsert."));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (isActionable(acceptance, "source_lookup_zero_result_rate")) {
|
|
184
|
+
for (const entry of recent) {
|
|
185
|
+
const sourceFile = args(entry.event).sourceFile;
|
|
186
|
+
if ((entry.event.tool === "kb_query" || entry.event.tool === "kb_search") &&
|
|
187
|
+
succeeded(entry.event) &&
|
|
188
|
+
typeof sourceFile === "string" &&
|
|
189
|
+
(entry.event.zero_results === true || entry.event.result_count === 0)) {
|
|
190
|
+
items.push(eventItem("source_lookup_zero_result_rate", entry, sourceFile, "This source-linked lookup returned zero results.", "Inspect the source, refresh its symbol links if stale, then repeat search followed by exact query."));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
const completeCoverage = recent.filter(({ event }) => event.tool === "kb_coverage" &&
|
|
195
|
+
succeeded(event) &&
|
|
196
|
+
(event.coverage_by ?? "req") === "req" &&
|
|
197
|
+
event.coverage_scope_complete === true &&
|
|
198
|
+
typeof event.coverage_proof_gap_count === "number");
|
|
199
|
+
const latestCoverage = completeCoverage.at(-1);
|
|
200
|
+
if (isActionable(acceptance, "proof_gap_recovery")) {
|
|
201
|
+
items.push(latestCoverage
|
|
202
|
+
? eventItem("proof_gap_recovery", latestCoverage, "coverage:req", `The latest complete report has ${latestCoverage.event.coverage_proof_gap_count} proof gaps without demonstrated recovery.`, "Apply one reviewed repair batch and rerun complete requirement coverage.")
|
|
203
|
+
: reportItem("proof_gap_recovery", "coverage:req", "No complete requirement coverage event contains proof-gap evidence.", "Run kb_coverage by req with complete scope and diagnostic telemetry."));
|
|
204
|
+
}
|
|
205
|
+
if (isActionable(acceptance, "e2e_receipt_freshness")) {
|
|
206
|
+
items.push(latestCoverage &&
|
|
207
|
+
latestCoverage.event.coverage_receipt_gap_count !== undefined
|
|
208
|
+
? eventItem("e2e_receipt_freshness", latestCoverage, "coverage:req", `The latest complete report has ${latestCoverage.event.coverage_receipt_gap_count} receipt gaps.`, "Run the cited E2E tests, append fresh passing receipts, sync, and rerun coverage.")
|
|
209
|
+
: reportItem("e2e_receipt_freshness", "coverage:req", "No complete requirement coverage event contains receipt-freshness evidence.", "Run complete requirement coverage after attaching fresh E2E verification receipts."));
|
|
210
|
+
}
|
|
211
|
+
if (isActionable(acceptance, "repeated_mutation_failures")) {
|
|
212
|
+
const streaks = new Map();
|
|
213
|
+
const offending = [];
|
|
214
|
+
const flush = (itemTarget) => {
|
|
215
|
+
const streak = streaks.get(itemTarget) ?? [];
|
|
216
|
+
if (streak.length >= policy.repeatedMutationFailureThreshold) {
|
|
217
|
+
offending.push(streak);
|
|
218
|
+
}
|
|
219
|
+
streaks.set(itemTarget, []);
|
|
220
|
+
};
|
|
221
|
+
for (const entry of recent) {
|
|
222
|
+
if (entry.event.tool !== "kb_upsert")
|
|
223
|
+
continue;
|
|
224
|
+
const itemTarget = target(entry.event);
|
|
225
|
+
if (failed(entry.event)) {
|
|
226
|
+
const streak = streaks.get(itemTarget) ?? [];
|
|
227
|
+
streak.push(entry);
|
|
228
|
+
streaks.set(itemTarget, streak);
|
|
229
|
+
}
|
|
230
|
+
else if (succeeded(entry.event)) {
|
|
231
|
+
flush(itemTarget);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
for (const itemTarget of streaks.keys())
|
|
235
|
+
flush(itemTarget);
|
|
236
|
+
for (const streak of offending) {
|
|
237
|
+
for (const entry of streak) {
|
|
238
|
+
items.push(eventItem("repeated_mutation_failures", entry, target(entry.event), "This event belongs to a mutation-failure streak at or above the retry threshold.", "Stop retrying; inspect endpoints and the exact preflight result, then make one repaired attempt."));
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
items.sort((left, right) => left.rank - right.rank ||
|
|
243
|
+
(left.event?.logLine ?? Number.MAX_SAFE_INTEGER) -
|
|
244
|
+
(right.event?.logLine ?? Number.MAX_SAFE_INTEGER) ||
|
|
245
|
+
left.id.localeCompare(right.id));
|
|
246
|
+
return {
|
|
247
|
+
version: TELEMETRY_REMEDIATION_VERSION,
|
|
248
|
+
status: items.length === 0 ? "clear" : "action_required",
|
|
249
|
+
acceptance,
|
|
250
|
+
summary: {
|
|
251
|
+
total: items.length,
|
|
252
|
+
eventItems: items.filter((item) => item.scope === "event").length,
|
|
253
|
+
reportItems: items.filter((item) => item.scope === "report").length,
|
|
254
|
+
},
|
|
255
|
+
items,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export declare const VERIFICATION_RECEIPT_VERSION: "kibi.verification-receipt.v1";
|
|
2
|
+
export declare const VERIFICATION_RECEIPT_MAX_AGE_SECONDS: number;
|
|
3
|
+
export declare const VERIFICATION_RECEIPT_OUTCOMES: readonly ["passed", "failed", "errored", "cancelled", "skipped"];
|
|
4
|
+
export declare const VERIFICATION_RECEIPT_SCHEMA: {
|
|
5
|
+
readonly type: "object";
|
|
6
|
+
readonly required: readonly ["version", "receipt_id", "test_id", "runner", "command", "scope", "outcome", "code_snapshot", "environment_hash", "started_at", "finished_at", "artifact_digest"];
|
|
7
|
+
readonly properties: {
|
|
8
|
+
readonly version: {
|
|
9
|
+
readonly type: "string";
|
|
10
|
+
readonly const: "kibi.verification-receipt.v1";
|
|
11
|
+
};
|
|
12
|
+
readonly receipt_id: {
|
|
13
|
+
readonly type: "string";
|
|
14
|
+
readonly pattern: "^VR-[A-Za-z0-9][A-Za-z0-9._:-]{7,127}$";
|
|
15
|
+
};
|
|
16
|
+
readonly test_id: {
|
|
17
|
+
readonly type: "string";
|
|
18
|
+
readonly minLength: 1;
|
|
19
|
+
};
|
|
20
|
+
readonly runner: {
|
|
21
|
+
readonly type: "string";
|
|
22
|
+
readonly minLength: 1;
|
|
23
|
+
};
|
|
24
|
+
readonly command: {
|
|
25
|
+
readonly type: "string";
|
|
26
|
+
readonly minLength: 1;
|
|
27
|
+
};
|
|
28
|
+
readonly scope: {
|
|
29
|
+
readonly type: "string";
|
|
30
|
+
readonly enum: readonly ["unit", "integration", "end_to_end"];
|
|
31
|
+
};
|
|
32
|
+
readonly outcome: {
|
|
33
|
+
readonly type: "string";
|
|
34
|
+
readonly enum: readonly ["passed", "failed", "errored", "cancelled", "skipped"];
|
|
35
|
+
};
|
|
36
|
+
readonly code_snapshot: {
|
|
37
|
+
readonly type: "string";
|
|
38
|
+
readonly pattern: "^[a-f0-9]{64}$";
|
|
39
|
+
};
|
|
40
|
+
readonly environment_hash: {
|
|
41
|
+
readonly type: "string";
|
|
42
|
+
readonly pattern: "^[a-f0-9]{64}$";
|
|
43
|
+
};
|
|
44
|
+
readonly started_at: {
|
|
45
|
+
readonly type: "string";
|
|
46
|
+
readonly minLength: 1;
|
|
47
|
+
};
|
|
48
|
+
readonly finished_at: {
|
|
49
|
+
readonly type: "string";
|
|
50
|
+
readonly minLength: 1;
|
|
51
|
+
};
|
|
52
|
+
readonly artifact_digest: {
|
|
53
|
+
readonly type: "string";
|
|
54
|
+
readonly pattern: "^[a-f0-9]{64}$";
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
readonly additionalProperties: false;
|
|
58
|
+
};
|
|
59
|
+
export type VerificationReceipt = Readonly<{
|
|
60
|
+
version: typeof VERIFICATION_RECEIPT_VERSION;
|
|
61
|
+
receipt_id: string;
|
|
62
|
+
test_id: string;
|
|
63
|
+
runner: string;
|
|
64
|
+
command: string;
|
|
65
|
+
scope: "unit" | "integration" | "end_to_end";
|
|
66
|
+
outcome: (typeof VERIFICATION_RECEIPT_OUTCOMES)[number];
|
|
67
|
+
code_snapshot: string;
|
|
68
|
+
environment_hash: string;
|
|
69
|
+
started_at: string;
|
|
70
|
+
finished_at: string;
|
|
71
|
+
artifact_digest: string;
|
|
72
|
+
}>;
|
|
73
|
+
export declare function verificationReceiptHistoryErrors(testId: string, verificationScope: unknown, receipts: readonly Readonly<Record<string, unknown>>[]): readonly string[];
|
|
74
|
+
export declare function appendOnlyVerificationReceiptHistoryErrors(previous: readonly Readonly<Record<string, unknown>>[], next: readonly Readonly<Record<string, unknown>>[] | undefined): readonly string[];
|
|
75
|
+
//# sourceMappingURL=verification-receipt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verification-receipt.d.ts","sourceRoot":"","sources":["../../src/public/verification-receipt.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,4BAA4B,EACvC,8BAAuC,CAAC;AAE1C,eAAO,MAAM,oCAAoC,QAAmB,CAAC;AAErE,eAAO,MAAM,6BAA6B,kEAMhC,CAAC;AAEX,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkC9B,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,OAAO,EAAE,OAAO,4BAA4B,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,YAAY,CAAC;IAC7C,OAAO,EAAE,CAAC,OAAO,6BAA6B,CAAC,CAAC,MAAM,CAAC,CAAC;IACxD,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC,CAAC;AAeH,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,MAAM,EACd,iBAAiB,EAAE,OAAO,EAC1B,QAAQ,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,GACrD,SAAS,MAAM,EAAE,CAkDnB;AAeD,wBAAgB,0CAA0C,CACxD,QAAQ,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,EACtD,IAAI,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,GAAG,SAAS,GAC7D,SAAS,MAAM,EAAE,CAoBnB"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
export const VERIFICATION_RECEIPT_VERSION = "kibi.verification-receipt.v1";
|
|
2
|
+
export const VERIFICATION_RECEIPT_MAX_AGE_SECONDS = 7 * 24 * 60 * 60;
|
|
3
|
+
export const VERIFICATION_RECEIPT_OUTCOMES = [
|
|
4
|
+
"passed",
|
|
5
|
+
"failed",
|
|
6
|
+
"errored",
|
|
7
|
+
"cancelled",
|
|
8
|
+
"skipped",
|
|
9
|
+
];
|
|
10
|
+
export const VERIFICATION_RECEIPT_SCHEMA = {
|
|
11
|
+
type: "object",
|
|
12
|
+
required: [
|
|
13
|
+
"version",
|
|
14
|
+
"receipt_id",
|
|
15
|
+
"test_id",
|
|
16
|
+
"runner",
|
|
17
|
+
"command",
|
|
18
|
+
"scope",
|
|
19
|
+
"outcome",
|
|
20
|
+
"code_snapshot",
|
|
21
|
+
"environment_hash",
|
|
22
|
+
"started_at",
|
|
23
|
+
"finished_at",
|
|
24
|
+
"artifact_digest",
|
|
25
|
+
],
|
|
26
|
+
properties: {
|
|
27
|
+
version: { type: "string", const: VERIFICATION_RECEIPT_VERSION },
|
|
28
|
+
receipt_id: {
|
|
29
|
+
type: "string",
|
|
30
|
+
pattern: "^VR-[A-Za-z0-9][A-Za-z0-9._:-]{7,127}$",
|
|
31
|
+
},
|
|
32
|
+
test_id: { type: "string", minLength: 1 },
|
|
33
|
+
runner: { type: "string", minLength: 1 },
|
|
34
|
+
command: { type: "string", minLength: 1 },
|
|
35
|
+
scope: { type: "string", enum: ["unit", "integration", "end_to_end"] },
|
|
36
|
+
outcome: { type: "string", enum: [...VERIFICATION_RECEIPT_OUTCOMES] },
|
|
37
|
+
code_snapshot: { type: "string", pattern: "^[a-f0-9]{64}$" },
|
|
38
|
+
environment_hash: { type: "string", pattern: "^[a-f0-9]{64}$" },
|
|
39
|
+
started_at: { type: "string", minLength: 1 },
|
|
40
|
+
finished_at: { type: "string", minLength: 1 },
|
|
41
|
+
artifact_digest: { type: "string", pattern: "^[a-f0-9]{64}$" },
|
|
42
|
+
},
|
|
43
|
+
additionalProperties: false,
|
|
44
|
+
};
|
|
45
|
+
function timestamp(value) {
|
|
46
|
+
if (typeof value !== "string")
|
|
47
|
+
return null;
|
|
48
|
+
if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/.test(value)) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
const parsed = Date.parse(value);
|
|
52
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
53
|
+
}
|
|
54
|
+
export function verificationReceiptHistoryErrors(testId, verificationScope, receipts) {
|
|
55
|
+
const errors = [];
|
|
56
|
+
let previousFinishedAt = null;
|
|
57
|
+
if (receipts.length > 0 && typeof verificationScope !== "string") {
|
|
58
|
+
errors.push("verification_scope is required when verification_receipts are present");
|
|
59
|
+
}
|
|
60
|
+
const receiptIds = new Set();
|
|
61
|
+
for (const [index, receipt] of receipts.entries()) {
|
|
62
|
+
const prefix = `verification_receipts[${index}]`;
|
|
63
|
+
const receiptId = receipt.receipt_id;
|
|
64
|
+
if (typeof receiptId === "string") {
|
|
65
|
+
if (receiptIds.has(receiptId)) {
|
|
66
|
+
errors.push(`${prefix}.receipt_id duplicates '${receiptId}'`);
|
|
67
|
+
}
|
|
68
|
+
receiptIds.add(receiptId);
|
|
69
|
+
}
|
|
70
|
+
if (receipt.test_id !== testId) {
|
|
71
|
+
errors.push(`${prefix}.test_id must equal '${testId}'`);
|
|
72
|
+
}
|
|
73
|
+
if (typeof verificationScope === "string" &&
|
|
74
|
+
receipt.scope !== verificationScope) {
|
|
75
|
+
errors.push(`${prefix}.scope must equal the test verification_scope '${verificationScope}'`);
|
|
76
|
+
}
|
|
77
|
+
const startedAt = timestamp(receipt.started_at);
|
|
78
|
+
const finishedAt = timestamp(receipt.finished_at);
|
|
79
|
+
if (startedAt === null)
|
|
80
|
+
errors.push(`${prefix}.started_at must be ISO-8601`);
|
|
81
|
+
if (finishedAt === null)
|
|
82
|
+
errors.push(`${prefix}.finished_at must be ISO-8601`);
|
|
83
|
+
if (startedAt !== null && finishedAt !== null && finishedAt < startedAt) {
|
|
84
|
+
errors.push(`${prefix}.finished_at must not precede started_at`);
|
|
85
|
+
}
|
|
86
|
+
if (finishedAt !== null &&
|
|
87
|
+
previousFinishedAt !== null &&
|
|
88
|
+
finishedAt <= previousFinishedAt) {
|
|
89
|
+
errors.push(`${prefix}.finished_at must be strictly later than the previous receipt`);
|
|
90
|
+
}
|
|
91
|
+
if (finishedAt !== null)
|
|
92
|
+
previousFinishedAt = finishedAt;
|
|
93
|
+
}
|
|
94
|
+
return errors;
|
|
95
|
+
}
|
|
96
|
+
function canonicalJson(value) {
|
|
97
|
+
if (Array.isArray(value)) {
|
|
98
|
+
return `[${value.map(canonicalJson).join(",")}]`;
|
|
99
|
+
}
|
|
100
|
+
if (value !== null && typeof value === "object") {
|
|
101
|
+
return `{${Object.entries(value)
|
|
102
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
103
|
+
.map(([key, child]) => `${JSON.stringify(key)}:${canonicalJson(child)}`)
|
|
104
|
+
.join(",")}}`;
|
|
105
|
+
}
|
|
106
|
+
return JSON.stringify(value);
|
|
107
|
+
}
|
|
108
|
+
export function appendOnlyVerificationReceiptHistoryErrors(previous, next) {
|
|
109
|
+
if (previous.length === 0)
|
|
110
|
+
return [];
|
|
111
|
+
if (next === undefined) {
|
|
112
|
+
return [
|
|
113
|
+
"verification_receipts is append-only and cannot be removed from an existing test",
|
|
114
|
+
];
|
|
115
|
+
}
|
|
116
|
+
if (next.length < previous.length) {
|
|
117
|
+
return [
|
|
118
|
+
`verification_receipts is append-only: expected at least ${previous.length} historical receipt(s), received ${next.length}`,
|
|
119
|
+
];
|
|
120
|
+
}
|
|
121
|
+
for (const [index, receipt] of previous.entries()) {
|
|
122
|
+
if (canonicalJson(next[index]) !== canonicalJson(receipt)) {
|
|
123
|
+
return [
|
|
124
|
+
`verification_receipts is append-only: historical receipt at index ${index} was changed, removed, or reordered`,
|
|
125
|
+
];
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return [];
|
|
129
|
+
}
|