@obsunified/collector 2.2.0 → 2.2.3
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/auth.js +1 -1
- package/dist/{chunk-KMEZKGSO.js → chunk-2FALTDCE.js} +12 -4
- package/dist/chunk-2FALTDCE.js.map +1 -0
- package/dist/index.d.ts +61 -3
- package/dist/index.js +10933 -9769
- package/dist/index.js.map +1 -1
- package/package.json +2 -3
- package/src/__tests__/autosre-closed-loop.test.ts +1554 -17
- package/src/auth/dashboard-auth.test.ts +61 -0
- package/src/auth/dashboard-auth.ts +17 -2
- package/src/lib/ai-store/calls.ts +43 -23
- package/src/lib/ai-store.ts +12 -1
- package/src/lib/analyses-runner.ts +44 -7
- package/src/lib/autosre-change-correlation.ts +39 -12
- package/src/lib/autosre-findings.ts +237 -44
- package/src/lib/autosre-ontology-cache.test.ts +78 -0
- package/src/lib/autosre-ontology.ts +52 -28
- package/src/lib/autosre-remediation-gate.ts +942 -348
- package/src/lib/housekeeping.test.ts +70 -0
- package/src/lib/housekeeping.ts +91 -83
- package/src/lib/projects-store.test.ts +38 -1
- package/src/lib/projects-store.ts +23 -4
- package/src/lib/sql-db-postgres.integration.test.ts +75 -2
- package/src/lib/store/ingest.ts +8 -56
- package/src/lib/usage-store.ts +9 -3
- package/src/migrations/051_incident_active_dedup_unique.sql +31 -0
- package/src/migrations/052_remediation_callback.sql +10 -0
- package/src/migrations/053_remediation_callback_delivery.sql +7 -0
- package/src/migrations/alert-state-notified.test.ts +3 -3
- package/src/migrations-postgres/051_incident_active_dedup_unique.sql +31 -0
- package/src/migrations-postgres/052_remediation_callback.sql +10 -0
- package/src/migrations-postgres/053_remediation_callback_delivery.sql +7 -0
- package/src/plugins/ai-call-by-id.test.ts +73 -0
- package/src/plugins/ai-receiver.ts +10 -0
- package/src/plugins/alerts-evaluator.ts +15 -3
- package/src/plugins/autosre-routes.ts +374 -108
- package/src/plugins/connected-routes/deep-link-shapes.test.ts +44 -0
- package/src/plugins/connected-routes/manifest.test.ts +142 -0
- package/src/plugins/connected-routes/manifest.ts +123 -6
- package/src/plugins/connected-routes-links.test.ts +96 -0
- package/src/plugins/connected-routes.test.ts +3 -3
- package/src/plugins/connected-routes.ts +56 -83
- package/src/plugins/evidence-retrieval-routes.test.ts +32 -0
- package/src/plugins/evidence-retrieval-routes.ts +397 -25
- package/dist/chunk-KMEZKGSO.js.map +0 -1
|
@@ -15,8 +15,12 @@
|
|
|
15
15
|
* RFC 0006 § Connected rail / Empty-state.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
import type { CausalProofTier } from "@obsunified/types";
|
|
18
19
|
import { ActionConfidence } from "@obsunified/types/constants";
|
|
19
20
|
import type { CollectorPlugin } from "../framework/collector";
|
|
21
|
+
import { getChangeEvent } from "../lib/autosre-change-correlation";
|
|
22
|
+
import { getInvestigationFinding } from "../lib/autosre-findings";
|
|
23
|
+
import { getIncidentInvestigation } from "../lib/autosre-remediation-gate";
|
|
20
24
|
import { IdentityIndex } from "../lib/identity-index";
|
|
21
25
|
import {
|
|
22
26
|
mapAction,
|
|
@@ -38,6 +42,7 @@ import {
|
|
|
38
42
|
type ActionContextLinkMetadata,
|
|
39
43
|
type ConnectedEntityKind,
|
|
40
44
|
type ConnectedManifest,
|
|
45
|
+
hrefForEntity,
|
|
41
46
|
KNOWN_KINDS,
|
|
42
47
|
linksFromActions,
|
|
43
48
|
linksFromAi,
|
|
@@ -55,6 +60,7 @@ import {
|
|
|
55
60
|
linkToTrace,
|
|
56
61
|
MAX_LINKS_INLINE,
|
|
57
62
|
profileLinksForTrace,
|
|
63
|
+
resolveFaultLocusTarget,
|
|
58
64
|
} from "./connected-routes/manifest";
|
|
59
65
|
|
|
60
66
|
export type {
|
|
@@ -1051,30 +1057,20 @@ export const connectedRoutesPlugin: CollectorPlugin = {
|
|
|
1051
1057
|
}
|
|
1052
1058
|
} else if (kind === "change") {
|
|
1053
1059
|
const db = sqlDbFor(c.env);
|
|
1054
|
-
const changeRow = await
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
.
|
|
1059
|
-
|
|
1060
|
-
id: string;
|
|
1061
|
-
environment: string;
|
|
1062
|
-
kind: string;
|
|
1063
|
-
target_node_id: string;
|
|
1064
|
-
service_name: string | null;
|
|
1065
|
-
version: string | null;
|
|
1066
|
-
previous_version: string | null;
|
|
1067
|
-
commit_sha: string | null;
|
|
1068
|
-
summary: string;
|
|
1069
|
-
}>();
|
|
1060
|
+
const changeRow = await getChangeEvent(
|
|
1061
|
+
db,
|
|
1062
|
+
projectId,
|
|
1063
|
+
id,
|
|
1064
|
+
c.req.query("environment") || undefined,
|
|
1065
|
+
);
|
|
1070
1066
|
if (changeRow) {
|
|
1071
1067
|
manifest.up = [
|
|
1072
1068
|
{
|
|
1073
1069
|
label: "Target Ontology Node",
|
|
1074
1070
|
links: [
|
|
1075
1071
|
{
|
|
1076
|
-
label: `${changeRow.
|
|
1077
|
-
href: `#/health?node=${encodeURIComponent(changeRow.
|
|
1072
|
+
label: `${changeRow.targetNodeId} (${changeRow.environment})`,
|
|
1073
|
+
href: `#/health?node=${encodeURIComponent(changeRow.targetNodeId)}`,
|
|
1078
1074
|
relationshipCertainty: "exact",
|
|
1079
1075
|
reason: "Target node mutated by this change event.",
|
|
1080
1076
|
},
|
|
@@ -1107,8 +1103,7 @@ export const connectedRoutesPlugin: CollectorPlugin = {
|
|
|
1107
1103
|
entityKind: "finding",
|
|
1108
1104
|
entityId: f.id,
|
|
1109
1105
|
relationshipCertainty: "exact",
|
|
1110
|
-
causalProofTier:
|
|
1111
|
-
f.causal_proof_tier as import("@obsunified/types").CausalProofTier,
|
|
1106
|
+
causalProofTier: f.causal_proof_tier as CausalProofTier,
|
|
1112
1107
|
confidence: f.confidence,
|
|
1113
1108
|
reason: "Finding attributes this change event.",
|
|
1114
1109
|
})),
|
|
@@ -1122,10 +1117,11 @@ export const connectedRoutesPlugin: CollectorPlugin = {
|
|
|
1122
1117
|
const spans = changeRow.version
|
|
1123
1118
|
? await db
|
|
1124
1119
|
.prepare(
|
|
1125
|
-
`SELECT
|
|
1120
|
+
`SELECT trace_id, span_id, service_name, span_name
|
|
1126
1121
|
FROM telemetry_spans
|
|
1127
1122
|
WHERE project_id = ? AND environment = ? AND service_version = ? AND status_code = 2
|
|
1128
|
-
|
|
1123
|
+
GROUP BY trace_id, span_id, service_name, span_name
|
|
1124
|
+
ORDER BY MAX(start_time) DESC LIMIT 5`,
|
|
1129
1125
|
)
|
|
1130
1126
|
.bind(projectId, changeRow.environment, changeRow.version)
|
|
1131
1127
|
.all<{
|
|
@@ -1156,54 +1152,39 @@ export const connectedRoutesPlugin: CollectorPlugin = {
|
|
|
1156
1152
|
}
|
|
1157
1153
|
} else if (kind === "finding") {
|
|
1158
1154
|
const db = sqlDbFor(c.env);
|
|
1159
|
-
const findingRow = await
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
.
|
|
1164
|
-
|
|
1165
|
-
id: string;
|
|
1166
|
-
environment: string;
|
|
1167
|
-
incident_id: string | null;
|
|
1168
|
-
title: string;
|
|
1169
|
-
causal_proof_tier: string;
|
|
1170
|
-
confidence: number;
|
|
1171
|
-
symptom_entity_kind: string;
|
|
1172
|
-
symptom_entity_id: string;
|
|
1173
|
-
fault_locus_entity_kind: string;
|
|
1174
|
-
fault_locus_entity_id: string;
|
|
1175
|
-
contributing_change_id: string | null;
|
|
1176
|
-
contending_trace_id: string | null;
|
|
1177
|
-
agent_run_id: string | null;
|
|
1178
|
-
}>();
|
|
1155
|
+
const findingRow = await getInvestigationFinding(
|
|
1156
|
+
db,
|
|
1157
|
+
projectId,
|
|
1158
|
+
id,
|
|
1159
|
+
c.req.query("environment") || undefined,
|
|
1160
|
+
);
|
|
1179
1161
|
if (findingRow) {
|
|
1180
|
-
const proofTier =
|
|
1181
|
-
findingRow.causal_proof_tier as import("@obsunified/types").CausalProofTier;
|
|
1162
|
+
const proofTier = findingRow.causalProofTier as CausalProofTier;
|
|
1182
1163
|
manifest.up = [];
|
|
1183
|
-
if (findingRow.
|
|
1164
|
+
if (findingRow.incidentId) {
|
|
1184
1165
|
manifest.up.push({
|
|
1185
1166
|
label: "Incident Investigation",
|
|
1186
1167
|
links: [
|
|
1187
1168
|
{
|
|
1188
|
-
label: `incident ${findingRow.
|
|
1189
|
-
href: `#/incidents/${encodeURIComponent(findingRow.
|
|
1169
|
+
label: `incident ${findingRow.incidentId}`,
|
|
1170
|
+
href: `#/incidents/${encodeURIComponent(findingRow.incidentId)}`,
|
|
1190
1171
|
entityKind: "incident",
|
|
1191
|
-
entityId: findingRow.
|
|
1172
|
+
entityId: findingRow.incidentId,
|
|
1192
1173
|
relationshipCertainty: "exact",
|
|
1193
1174
|
causalProofTier: proofTier,
|
|
1194
1175
|
},
|
|
1195
1176
|
],
|
|
1196
1177
|
});
|
|
1197
1178
|
}
|
|
1198
|
-
if (findingRow.
|
|
1179
|
+
if (findingRow.contributingChangeId) {
|
|
1199
1180
|
manifest.up.push({
|
|
1200
1181
|
label: "Contributing Change",
|
|
1201
1182
|
links: [
|
|
1202
1183
|
{
|
|
1203
|
-
label: `change ${findingRow.
|
|
1204
|
-
href: `#/changes/${encodeURIComponent(findingRow.
|
|
1184
|
+
label: `change ${findingRow.contributingChangeId}`,
|
|
1185
|
+
href: `#/changes/${encodeURIComponent(findingRow.contributingChangeId)}`,
|
|
1205
1186
|
entityKind: "change",
|
|
1206
|
-
entityId: findingRow.
|
|
1187
|
+
entityId: findingRow.contributingChangeId,
|
|
1207
1188
|
relationshipCertainty: "exact",
|
|
1208
1189
|
causalProofTier: proofTier,
|
|
1209
1190
|
confidence: findingRow.confidence,
|
|
@@ -1216,18 +1197,18 @@ export const connectedRoutesPlugin: CollectorPlugin = {
|
|
|
1216
1197
|
label: "Fault Locus & Symptom",
|
|
1217
1198
|
links: [
|
|
1218
1199
|
{
|
|
1219
|
-
label: `fault locus: ${findingRow.
|
|
1220
|
-
|
|
1200
|
+
label: `fault locus: ${findingRow.faultLocusEntityId}`,
|
|
1201
|
+
...resolveFaultLocusTarget(findingRow.faultLocusEntityId),
|
|
1221
1202
|
relationshipCertainty: "exact",
|
|
1222
1203
|
causalProofTier: proofTier,
|
|
1223
1204
|
},
|
|
1224
|
-
...(findingRow.
|
|
1205
|
+
...(findingRow.contendingTraceId
|
|
1225
1206
|
? [
|
|
1226
1207
|
{
|
|
1227
|
-
label: `contending trace ${findingRow.
|
|
1228
|
-
href: `#/traces/${encodeURIComponent(findingRow.
|
|
1208
|
+
label: `contending trace ${findingRow.contendingTraceId}`,
|
|
1209
|
+
href: `#/traces/${encodeURIComponent(findingRow.contendingTraceId)}`,
|
|
1229
1210
|
entityKind: "trace" as const,
|
|
1230
|
-
entityId: findingRow.
|
|
1211
|
+
entityId: findingRow.contendingTraceId,
|
|
1231
1212
|
relationshipCertainty: "inferred" as const,
|
|
1232
1213
|
causalProofTier: proofTier,
|
|
1233
1214
|
},
|
|
@@ -1240,17 +1221,17 @@ export const connectedRoutesPlugin: CollectorPlugin = {
|
|
|
1240
1221
|
{
|
|
1241
1222
|
label: "Agent Lineage",
|
|
1242
1223
|
links: [
|
|
1243
|
-
...(findingRow.
|
|
1224
|
+
...(findingRow.agentRunId
|
|
1244
1225
|
? [
|
|
1245
1226
|
{
|
|
1246
|
-
...linkToAgentRun(findingRow.
|
|
1227
|
+
...linkToAgentRun(findingRow.agentRunId),
|
|
1247
1228
|
relationshipCertainty: "exact" as const,
|
|
1248
1229
|
causalProofTier: proofTier,
|
|
1249
1230
|
},
|
|
1250
1231
|
]
|
|
1251
1232
|
: []),
|
|
1252
1233
|
],
|
|
1253
|
-
emptyReason: !findingRow.
|
|
1234
|
+
emptyReason: !findingRow.agentRunId
|
|
1254
1235
|
? "No agent run linked to this finding."
|
|
1255
1236
|
: undefined,
|
|
1256
1237
|
},
|
|
@@ -1258,32 +1239,25 @@ export const connectedRoutesPlugin: CollectorPlugin = {
|
|
|
1258
1239
|
}
|
|
1259
1240
|
} else if (kind === "incident") {
|
|
1260
1241
|
const db = sqlDbFor(c.env);
|
|
1261
|
-
const incRow = await
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
.
|
|
1266
|
-
|
|
1267
|
-
id: string;
|
|
1268
|
-
environment: string;
|
|
1269
|
-
target_node_id: string;
|
|
1270
|
-
symptom_anchor_kind: string;
|
|
1271
|
-
symptom_anchor_id: string;
|
|
1272
|
-
status: string;
|
|
1273
|
-
}>();
|
|
1242
|
+
const incRow = await getIncidentInvestigation(
|
|
1243
|
+
db,
|
|
1244
|
+
projectId,
|
|
1245
|
+
id,
|
|
1246
|
+
c.req.query("environment") || undefined,
|
|
1247
|
+
);
|
|
1274
1248
|
if (incRow) {
|
|
1275
1249
|
manifest.up = [
|
|
1276
1250
|
{
|
|
1277
1251
|
label: "Trigger Signal",
|
|
1278
1252
|
links: [
|
|
1279
1253
|
{
|
|
1280
|
-
label: `${incRow.
|
|
1281
|
-
href:
|
|
1282
|
-
|
|
1283
|
-
incRow.
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
entityId: incRow.
|
|
1254
|
+
label: `${incRow.symptomAnchorKind}: ${incRow.symptomAnchorId}`,
|
|
1255
|
+
href: hrefForEntity(
|
|
1256
|
+
incRow.symptomAnchorKind,
|
|
1257
|
+
incRow.symptomAnchorId,
|
|
1258
|
+
),
|
|
1259
|
+
entityKind: incRow.symptomAnchorKind,
|
|
1260
|
+
entityId: incRow.symptomAnchorId,
|
|
1287
1261
|
relationshipCertainty: "exact",
|
|
1288
1262
|
},
|
|
1289
1263
|
],
|
|
@@ -1310,8 +1284,7 @@ export const connectedRoutesPlugin: CollectorPlugin = {
|
|
|
1310
1284
|
entityKind: "finding" as const,
|
|
1311
1285
|
entityId: f.id,
|
|
1312
1286
|
relationshipCertainty: "exact" as const,
|
|
1313
|
-
causalProofTier:
|
|
1314
|
-
f.causal_proof_tier as import("@obsunified/types").CausalProofTier,
|
|
1287
|
+
causalProofTier: f.causal_proof_tier as CausalProofTier,
|
|
1315
1288
|
})),
|
|
1316
1289
|
emptyReason:
|
|
1317
1290
|
incFindings.results.length > 0
|
|
@@ -519,6 +519,38 @@ describe("evidenceRetrievalRoutesPlugin", () => {
|
|
|
519
519
|
return (await bundleRes.json()) as EvidenceBundle;
|
|
520
520
|
};
|
|
521
521
|
|
|
522
|
+
it("attaches the AutoSRE triage section only for intent triage_incident", async () => {
|
|
523
|
+
const { app, env } = setup();
|
|
524
|
+
const post = async (intent: string, targetTokens = 4000) => {
|
|
525
|
+
const res = await app.request(
|
|
526
|
+
"/internal/evidence/bundle",
|
|
527
|
+
{
|
|
528
|
+
method: "POST",
|
|
529
|
+
body: JSON.stringify({
|
|
530
|
+
anchor: { entityKind: "trace", entityId: "trace-1" },
|
|
531
|
+
intent,
|
|
532
|
+
budget: { targetTokens, detailLevel: "standard" },
|
|
533
|
+
}),
|
|
534
|
+
headers: { "content-type": "application/json" },
|
|
535
|
+
},
|
|
536
|
+
env,
|
|
537
|
+
);
|
|
538
|
+
expect(res.status).toBe(200);
|
|
539
|
+
return (await res.json()) as EvidenceBundle;
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
const debug = await post("debug_failure");
|
|
543
|
+
expect(debug.autosre).toBeUndefined();
|
|
544
|
+
|
|
545
|
+
const triage = await post("triage_incident");
|
|
546
|
+
expect(triage.autosre).toBeDefined();
|
|
547
|
+
// No unfiltered prior-findings fallback: an empty memory yields none.
|
|
548
|
+
expect(triage.autosre?.priorFindings).toEqual([]);
|
|
549
|
+
expect(triage.autosre?.faultLocus?.isBlackoutSuspected ?? false).toBe(
|
|
550
|
+
false,
|
|
551
|
+
);
|
|
552
|
+
});
|
|
553
|
+
|
|
522
554
|
it("returns an incident-local trace bundle with log compaction provenance", async () => {
|
|
523
555
|
const { app, env } = setup();
|
|
524
556
|
const res = await app.request(
|