@obsunified/collector 2.2.0 → 2.2.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/index.d.ts +53 -3
- package/dist/index.js +10459 -9696
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/autosre-closed-loop.test.ts +964 -17
- package/src/lib/analyses-runner.ts +44 -7
- package/src/lib/autosre-change-correlation.ts +39 -12
- package/src/lib/autosre-findings.ts +68 -30
- 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 +799 -335
- package/src/lib/housekeeping.test.ts +70 -0
- package/src/lib/housekeeping.ts +91 -83
- package/src/lib/store/ingest.ts +8 -56
- package/src/migrations/051_incident_active_dedup_unique.sql +31 -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/plugins/alerts-evaluator.ts +15 -3
- package/src/plugins/autosre-routes.ts +223 -108
- package/src/plugins/connected-routes/manifest.ts +1 -4
- package/src/plugins/connected-routes.ts +48 -78
- package/src/plugins/evidence-retrieval-routes.test.ts +32 -0
- package/src/plugins/evidence-retrieval-routes.ts +372 -30
|
@@ -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,
|
|
@@ -1051,30 +1055,20 @@ export const connectedRoutesPlugin: CollectorPlugin = {
|
|
|
1051
1055
|
}
|
|
1052
1056
|
} else if (kind === "change") {
|
|
1053
1057
|
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
|
-
}>();
|
|
1058
|
+
const changeRow = await getChangeEvent(
|
|
1059
|
+
db,
|
|
1060
|
+
projectId,
|
|
1061
|
+
id,
|
|
1062
|
+
c.req.query("environment") || undefined,
|
|
1063
|
+
);
|
|
1070
1064
|
if (changeRow) {
|
|
1071
1065
|
manifest.up = [
|
|
1072
1066
|
{
|
|
1073
1067
|
label: "Target Ontology Node",
|
|
1074
1068
|
links: [
|
|
1075
1069
|
{
|
|
1076
|
-
label: `${changeRow.
|
|
1077
|
-
href: `#/health?node=${encodeURIComponent(changeRow.
|
|
1070
|
+
label: `${changeRow.targetNodeId} (${changeRow.environment})`,
|
|
1071
|
+
href: `#/health?node=${encodeURIComponent(changeRow.targetNodeId)}`,
|
|
1078
1072
|
relationshipCertainty: "exact",
|
|
1079
1073
|
reason: "Target node mutated by this change event.",
|
|
1080
1074
|
},
|
|
@@ -1107,8 +1101,7 @@ export const connectedRoutesPlugin: CollectorPlugin = {
|
|
|
1107
1101
|
entityKind: "finding",
|
|
1108
1102
|
entityId: f.id,
|
|
1109
1103
|
relationshipCertainty: "exact",
|
|
1110
|
-
causalProofTier:
|
|
1111
|
-
f.causal_proof_tier as import("@obsunified/types").CausalProofTier,
|
|
1104
|
+
causalProofTier: f.causal_proof_tier as CausalProofTier,
|
|
1112
1105
|
confidence: f.confidence,
|
|
1113
1106
|
reason: "Finding attributes this change event.",
|
|
1114
1107
|
})),
|
|
@@ -1156,54 +1149,39 @@ export const connectedRoutesPlugin: CollectorPlugin = {
|
|
|
1156
1149
|
}
|
|
1157
1150
|
} else if (kind === "finding") {
|
|
1158
1151
|
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
|
-
}>();
|
|
1152
|
+
const findingRow = await getInvestigationFinding(
|
|
1153
|
+
db,
|
|
1154
|
+
projectId,
|
|
1155
|
+
id,
|
|
1156
|
+
c.req.query("environment") || undefined,
|
|
1157
|
+
);
|
|
1179
1158
|
if (findingRow) {
|
|
1180
|
-
const proofTier =
|
|
1181
|
-
findingRow.causal_proof_tier as import("@obsunified/types").CausalProofTier;
|
|
1159
|
+
const proofTier = findingRow.causalProofTier as CausalProofTier;
|
|
1182
1160
|
manifest.up = [];
|
|
1183
|
-
if (findingRow.
|
|
1161
|
+
if (findingRow.incidentId) {
|
|
1184
1162
|
manifest.up.push({
|
|
1185
1163
|
label: "Incident Investigation",
|
|
1186
1164
|
links: [
|
|
1187
1165
|
{
|
|
1188
|
-
label: `incident ${findingRow.
|
|
1189
|
-
href: `#/incidents/${encodeURIComponent(findingRow.
|
|
1166
|
+
label: `incident ${findingRow.incidentId}`,
|
|
1167
|
+
href: `#/incidents/${encodeURIComponent(findingRow.incidentId)}`,
|
|
1190
1168
|
entityKind: "incident",
|
|
1191
|
-
entityId: findingRow.
|
|
1169
|
+
entityId: findingRow.incidentId,
|
|
1192
1170
|
relationshipCertainty: "exact",
|
|
1193
1171
|
causalProofTier: proofTier,
|
|
1194
1172
|
},
|
|
1195
1173
|
],
|
|
1196
1174
|
});
|
|
1197
1175
|
}
|
|
1198
|
-
if (findingRow.
|
|
1176
|
+
if (findingRow.contributingChangeId) {
|
|
1199
1177
|
manifest.up.push({
|
|
1200
1178
|
label: "Contributing Change",
|
|
1201
1179
|
links: [
|
|
1202
1180
|
{
|
|
1203
|
-
label: `change ${findingRow.
|
|
1204
|
-
href: `#/changes/${encodeURIComponent(findingRow.
|
|
1181
|
+
label: `change ${findingRow.contributingChangeId}`,
|
|
1182
|
+
href: `#/changes/${encodeURIComponent(findingRow.contributingChangeId)}`,
|
|
1205
1183
|
entityKind: "change",
|
|
1206
|
-
entityId: findingRow.
|
|
1184
|
+
entityId: findingRow.contributingChangeId,
|
|
1207
1185
|
relationshipCertainty: "exact",
|
|
1208
1186
|
causalProofTier: proofTier,
|
|
1209
1187
|
confidence: findingRow.confidence,
|
|
@@ -1216,18 +1194,18 @@ export const connectedRoutesPlugin: CollectorPlugin = {
|
|
|
1216
1194
|
label: "Fault Locus & Symptom",
|
|
1217
1195
|
links: [
|
|
1218
1196
|
{
|
|
1219
|
-
label: `fault locus: ${findingRow.
|
|
1220
|
-
href: `#/traces?q=${encodeURIComponent(findingRow.
|
|
1197
|
+
label: `fault locus: ${findingRow.faultLocusEntityId}`,
|
|
1198
|
+
href: `#/traces?q=${encodeURIComponent(findingRow.faultLocusEntityId)}`,
|
|
1221
1199
|
relationshipCertainty: "exact",
|
|
1222
1200
|
causalProofTier: proofTier,
|
|
1223
1201
|
},
|
|
1224
|
-
...(findingRow.
|
|
1202
|
+
...(findingRow.contendingTraceId
|
|
1225
1203
|
? [
|
|
1226
1204
|
{
|
|
1227
|
-
label: `contending trace ${findingRow.
|
|
1228
|
-
href: `#/traces/${encodeURIComponent(findingRow.
|
|
1205
|
+
label: `contending trace ${findingRow.contendingTraceId}`,
|
|
1206
|
+
href: `#/traces/${encodeURIComponent(findingRow.contendingTraceId)}`,
|
|
1229
1207
|
entityKind: "trace" as const,
|
|
1230
|
-
entityId: findingRow.
|
|
1208
|
+
entityId: findingRow.contendingTraceId,
|
|
1231
1209
|
relationshipCertainty: "inferred" as const,
|
|
1232
1210
|
causalProofTier: proofTier,
|
|
1233
1211
|
},
|
|
@@ -1240,17 +1218,17 @@ export const connectedRoutesPlugin: CollectorPlugin = {
|
|
|
1240
1218
|
{
|
|
1241
1219
|
label: "Agent Lineage",
|
|
1242
1220
|
links: [
|
|
1243
|
-
...(findingRow.
|
|
1221
|
+
...(findingRow.agentRunId
|
|
1244
1222
|
? [
|
|
1245
1223
|
{
|
|
1246
|
-
...linkToAgentRun(findingRow.
|
|
1224
|
+
...linkToAgentRun(findingRow.agentRunId),
|
|
1247
1225
|
relationshipCertainty: "exact" as const,
|
|
1248
1226
|
causalProofTier: proofTier,
|
|
1249
1227
|
},
|
|
1250
1228
|
]
|
|
1251
1229
|
: []),
|
|
1252
1230
|
],
|
|
1253
|
-
emptyReason: !findingRow.
|
|
1231
|
+
emptyReason: !findingRow.agentRunId
|
|
1254
1232
|
? "No agent run linked to this finding."
|
|
1255
1233
|
: undefined,
|
|
1256
1234
|
},
|
|
@@ -1258,32 +1236,25 @@ export const connectedRoutesPlugin: CollectorPlugin = {
|
|
|
1258
1236
|
}
|
|
1259
1237
|
} else if (kind === "incident") {
|
|
1260
1238
|
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
|
-
}>();
|
|
1239
|
+
const incRow = await getIncidentInvestigation(
|
|
1240
|
+
db,
|
|
1241
|
+
projectId,
|
|
1242
|
+
id,
|
|
1243
|
+
c.req.query("environment") || undefined,
|
|
1244
|
+
);
|
|
1274
1245
|
if (incRow) {
|
|
1275
1246
|
manifest.up = [
|
|
1276
1247
|
{
|
|
1277
1248
|
label: "Trigger Signal",
|
|
1278
1249
|
links: [
|
|
1279
1250
|
{
|
|
1280
|
-
label: `${incRow.
|
|
1281
|
-
href: `#/alerts?id=${encodeURIComponent(incRow.
|
|
1251
|
+
label: `${incRow.symptomAnchorKind}: ${incRow.symptomAnchorId}`,
|
|
1252
|
+
href: `#/alerts?id=${encodeURIComponent(incRow.symptomAnchorId)}`,
|
|
1282
1253
|
entityKind:
|
|
1283
|
-
incRow.
|
|
1254
|
+
incRow.symptomAnchorKind === "analysis"
|
|
1284
1255
|
? "analysis"
|
|
1285
1256
|
: "alert",
|
|
1286
|
-
entityId: incRow.
|
|
1257
|
+
entityId: incRow.symptomAnchorId,
|
|
1287
1258
|
relationshipCertainty: "exact",
|
|
1288
1259
|
},
|
|
1289
1260
|
],
|
|
@@ -1310,8 +1281,7 @@ export const connectedRoutesPlugin: CollectorPlugin = {
|
|
|
1310
1281
|
entityKind: "finding" as const,
|
|
1311
1282
|
entityId: f.id,
|
|
1312
1283
|
relationshipCertainty: "exact" as const,
|
|
1313
|
-
causalProofTier:
|
|
1314
|
-
f.causal_proof_tier as import("@obsunified/types").CausalProofTier,
|
|
1284
|
+
causalProofTier: f.causal_proof_tier as CausalProofTier,
|
|
1315
1285
|
})),
|
|
1316
1286
|
emptyReason:
|
|
1317
1287
|
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(
|