@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.
@@ -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 db
1055
- .prepare(
1056
- `SELECT * FROM change_events WHERE project_id = ? AND id = ? LIMIT 1`,
1057
- )
1058
- .bind(projectId, id)
1059
- .first<{
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.target_node_id} (${changeRow.environment})`,
1077
- href: `#/health?node=${encodeURIComponent(changeRow.target_node_id)}`,
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 db
1160
- .prepare(
1161
- `SELECT * FROM investigation_findings WHERE project_id = ? AND id = ? LIMIT 1`,
1162
- )
1163
- .bind(projectId, id)
1164
- .first<{
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.incident_id) {
1161
+ if (findingRow.incidentId) {
1184
1162
  manifest.up.push({
1185
1163
  label: "Incident Investigation",
1186
1164
  links: [
1187
1165
  {
1188
- label: `incident ${findingRow.incident_id}`,
1189
- href: `#/incidents/${encodeURIComponent(findingRow.incident_id)}`,
1166
+ label: `incident ${findingRow.incidentId}`,
1167
+ href: `#/incidents/${encodeURIComponent(findingRow.incidentId)}`,
1190
1168
  entityKind: "incident",
1191
- entityId: findingRow.incident_id,
1169
+ entityId: findingRow.incidentId,
1192
1170
  relationshipCertainty: "exact",
1193
1171
  causalProofTier: proofTier,
1194
1172
  },
1195
1173
  ],
1196
1174
  });
1197
1175
  }
1198
- if (findingRow.contributing_change_id) {
1176
+ if (findingRow.contributingChangeId) {
1199
1177
  manifest.up.push({
1200
1178
  label: "Contributing Change",
1201
1179
  links: [
1202
1180
  {
1203
- label: `change ${findingRow.contributing_change_id}`,
1204
- href: `#/changes/${encodeURIComponent(findingRow.contributing_change_id)}`,
1181
+ label: `change ${findingRow.contributingChangeId}`,
1182
+ href: `#/changes/${encodeURIComponent(findingRow.contributingChangeId)}`,
1205
1183
  entityKind: "change",
1206
- entityId: findingRow.contributing_change_id,
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.fault_locus_entity_id}`,
1220
- href: `#/traces?q=${encodeURIComponent(findingRow.fault_locus_entity_id)}`,
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.contending_trace_id
1202
+ ...(findingRow.contendingTraceId
1225
1203
  ? [
1226
1204
  {
1227
- label: `contending trace ${findingRow.contending_trace_id}`,
1228
- href: `#/traces/${encodeURIComponent(findingRow.contending_trace_id)}`,
1205
+ label: `contending trace ${findingRow.contendingTraceId}`,
1206
+ href: `#/traces/${encodeURIComponent(findingRow.contendingTraceId)}`,
1229
1207
  entityKind: "trace" as const,
1230
- entityId: findingRow.contending_trace_id,
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.agent_run_id
1221
+ ...(findingRow.agentRunId
1244
1222
  ? [
1245
1223
  {
1246
- ...linkToAgentRun(findingRow.agent_run_id),
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.agent_run_id
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 db
1262
- .prepare(
1263
- `SELECT * FROM incident_investigations WHERE project_id = ? AND id = ? LIMIT 1`,
1264
- )
1265
- .bind(projectId, id)
1266
- .first<{
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.symptom_anchor_kind}: ${incRow.symptom_anchor_id}`,
1281
- href: `#/alerts?id=${encodeURIComponent(incRow.symptom_anchor_id)}`,
1251
+ label: `${incRow.symptomAnchorKind}: ${incRow.symptomAnchorId}`,
1252
+ href: `#/alerts?id=${encodeURIComponent(incRow.symptomAnchorId)}`,
1282
1253
  entityKind:
1283
- incRow.symptom_anchor_kind === "analysis"
1254
+ incRow.symptomAnchorKind === "analysis"
1284
1255
  ? "analysis"
1285
1256
  : "alert",
1286
- entityId: incRow.symptom_anchor_id,
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(