@neat.is/core 0.9.9 → 0.9.10
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/{chunk-B6KJG5KN.js → chunk-C3LHXC55.js} +110 -2
- package/dist/chunk-C3LHXC55.js.map +1 -0
- package/dist/{chunk-QETJIA2Q.js → chunk-UHNE7LGF.js} +2 -2
- package/dist/cli.cjs +109 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/index.cjs +109 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +109 -1
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +109 -1
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-B6KJG5KN.js.map +0 -1
- /package/dist/{chunk-QETJIA2Q.js.map → chunk-UHNE7LGF.js.map} +0 -0
|
@@ -5987,6 +5987,24 @@ function incidentCountForNode(nodeId, incidents) {
|
|
|
5987
5987
|
if (!incidents || incidents.length === 0) return 0;
|
|
5988
5988
|
return incidents.filter((ev) => incidentMatchesNode(ev, nodeId)).length;
|
|
5989
5989
|
}
|
|
5990
|
+
var DEP_EDGE_TYPES = /* @__PURE__ */ new Set([
|
|
5991
|
+
EdgeType6.CALLS,
|
|
5992
|
+
EdgeType6.CONNECTS_TO,
|
|
5993
|
+
EdgeType6.PUBLISHES_TO,
|
|
5994
|
+
EdgeType6.CONSUMES_FROM
|
|
5995
|
+
]);
|
|
5996
|
+
var TIMEOUT_ERROR_PATTERNS = [
|
|
5997
|
+
/\bDEADLINE_EXCEEDED\b/i,
|
|
5998
|
+
/\bdeadline exceeded\b/i,
|
|
5999
|
+
/\bETIMEDOUT\b/i,
|
|
6000
|
+
/\btimed[\s-]?out\b/i,
|
|
6001
|
+
/\btimeout\b/i
|
|
6002
|
+
];
|
|
6003
|
+
function isBoundaryTimeoutError(ev) {
|
|
6004
|
+
if (ev.httpStatusCode === 504) return true;
|
|
6005
|
+
const haystack = [ev.errorType, ev.exceptionType, ev.errorMessage].filter((s) => typeof s === "string").join(" \n ");
|
|
6006
|
+
return TIMEOUT_ERROR_PATTERNS.some((re) => re.test(haystack));
|
|
6007
|
+
}
|
|
5990
6008
|
function nodeContext(graph, nodeId, incidents, now = Date.now()) {
|
|
5991
6009
|
const scope = nodeScope(graph, nodeId);
|
|
5992
6010
|
let errorsFromCallers = 0;
|
|
@@ -5996,6 +6014,8 @@ function nodeContext(graph, nodeId, incidents, now = Date.now()) {
|
|
|
5996
6014
|
let latestInboundMs;
|
|
5997
6015
|
let latencyP95Ms;
|
|
5998
6016
|
let stale = false;
|
|
6017
|
+
let observedErroringDownstream = false;
|
|
6018
|
+
let hasOutboundDeps = false;
|
|
5999
6019
|
for (const n of scope) {
|
|
6000
6020
|
if (!graph.hasNode(n)) continue;
|
|
6001
6021
|
for (const edgeId of graph.inboundEdges(n)) {
|
|
@@ -6017,10 +6037,17 @@ function nodeContext(graph, nodeId, incidents, now = Date.now()) {
|
|
|
6017
6037
|
outboundVolume += e.callCount ?? e.signal?.spanCount ?? 0;
|
|
6018
6038
|
if (e.type === EdgeType6.CALLS) outboundErrors += e.signal?.errorCount ?? 0;
|
|
6019
6039
|
if (e.provenance === Provenance6.STALE) stale = true;
|
|
6040
|
+
if (DEP_EDGE_TYPES.has(e.type)) {
|
|
6041
|
+
hasOutboundDeps = true;
|
|
6042
|
+
if ((e.signal?.errorCount ?? 0) > 0) observedErroringDownstream = true;
|
|
6043
|
+
}
|
|
6020
6044
|
}
|
|
6021
6045
|
}
|
|
6022
6046
|
const errorsEmittedHere = incidentCountForNode(nodeId, incidents) + outboundErrors;
|
|
6023
6047
|
const lastObservedAgeMs = latestInboundMs !== void 0 ? Math.max(0, now - latestInboundMs) : void 0;
|
|
6048
|
+
const boundaryTimeout = (incidents ?? []).some(
|
|
6049
|
+
(ev) => incidentMatchesNode(ev, nodeId) && isBoundaryTimeoutError(ev)
|
|
6050
|
+
);
|
|
6024
6051
|
return {
|
|
6025
6052
|
errorsEmittedHere,
|
|
6026
6053
|
errorsFromCallers,
|
|
@@ -6028,17 +6055,24 @@ function nodeContext(graph, nodeId, incidents, now = Date.now()) {
|
|
|
6028
6055
|
outboundVolume,
|
|
6029
6056
|
...lastObservedAgeMs !== void 0 ? { lastObservedAgeMs } : {},
|
|
6030
6057
|
...latencyP95Ms !== void 0 ? { latencyP95Ms } : {},
|
|
6031
|
-
stale
|
|
6058
|
+
stale,
|
|
6059
|
+
boundaryTimeout,
|
|
6060
|
+
observedErroringDownstream,
|
|
6061
|
+
hasOutboundDeps
|
|
6032
6062
|
};
|
|
6033
6063
|
}
|
|
6034
6064
|
function isSaturated(ctx) {
|
|
6035
6065
|
return ctx.latencyP95Ms !== void 0 && ctx.latencyP95Ms >= SATURATION_P95_MS;
|
|
6036
6066
|
}
|
|
6067
|
+
function isBoundaryTimeoutSymptom(ctx) {
|
|
6068
|
+
return ctx.errorsEmittedHere > 0 && ctx.boundaryTimeout === true && ctx.errorsFromCallers === 0 && ctx.hasOutboundDeps === true && ctx.observedErroringDownstream !== true;
|
|
6069
|
+
}
|
|
6037
6070
|
function classifyNode(ctx) {
|
|
6038
6071
|
if (ctx.errorsEmittedHere > 0) {
|
|
6039
6072
|
if ((ctx.stale || isSaturated(ctx)) && ctx.errorsFromCallers >= ctx.errorsEmittedHere) {
|
|
6040
6073
|
return "symptom-only";
|
|
6041
6074
|
}
|
|
6075
|
+
if (isBoundaryTimeoutSymptom(ctx)) return "symptom-only";
|
|
6042
6076
|
return "primary-failure";
|
|
6043
6077
|
}
|
|
6044
6078
|
if (ctx.errorsFromCallers > 0) return "symptom-only";
|
|
@@ -6243,6 +6277,57 @@ function getRootCause(graph, errorNodeId, errorEvent, incidents, opts) {
|
|
|
6243
6277
|
if (!navigation) return tagged.result;
|
|
6244
6278
|
return enrichWithNavigation(graph, errorNodeId, tagged, incidents, opts?.now ?? Date.now());
|
|
6245
6279
|
}
|
|
6280
|
+
function boundaryIncidentRoute(nodeId, incidents) {
|
|
6281
|
+
for (const ev of incidents ?? []) {
|
|
6282
|
+
if (!incidentMatchesNode(ev, nodeId)) continue;
|
|
6283
|
+
const r = ev.attributes?.["http.route"] ?? ev.attributes?.["http.target"] ?? ev.attributes?.["url.path"];
|
|
6284
|
+
if (typeof r === "string" && r.length > 0) return r;
|
|
6285
|
+
}
|
|
6286
|
+
return void 0;
|
|
6287
|
+
}
|
|
6288
|
+
function declaredOutboundCallees(graph, nodeId) {
|
|
6289
|
+
const byTarget = /* @__PURE__ */ new Map();
|
|
6290
|
+
for (const n of nodeScope(graph, nodeId)) {
|
|
6291
|
+
if (!graph.hasNode(n)) continue;
|
|
6292
|
+
for (const edgeId of graph.outboundEdges(n)) {
|
|
6293
|
+
const e = graph.getEdgeAttributes(edgeId);
|
|
6294
|
+
if (!DEP_EDGE_TYPES.has(e.type)) continue;
|
|
6295
|
+
if (e.provenance !== Provenance6.EXTRACTED) continue;
|
|
6296
|
+
if (e.target === nodeId || byTarget.has(e.target)) continue;
|
|
6297
|
+
const route = e.evidence?.pathTemplate;
|
|
6298
|
+
byTarget.set(
|
|
6299
|
+
e.target,
|
|
6300
|
+
route !== void 0 ? { target: e.target, route } : { target: e.target }
|
|
6301
|
+
);
|
|
6302
|
+
}
|
|
6303
|
+
}
|
|
6304
|
+
return [...byTarget.values()];
|
|
6305
|
+
}
|
|
6306
|
+
function normalizeRoute(s) {
|
|
6307
|
+
return s.replace(/\/+$/, "").toLowerCase();
|
|
6308
|
+
}
|
|
6309
|
+
function routeMatches(declared, incident) {
|
|
6310
|
+
const a = normalizeRoute(declared);
|
|
6311
|
+
const b = normalizeRoute(incident);
|
|
6312
|
+
return a === b || a.startsWith(b) || b.startsWith(a);
|
|
6313
|
+
}
|
|
6314
|
+
function structuralUpstreamPointer(graph, boundaryNode, incidents) {
|
|
6315
|
+
const route = boundaryIncidentRoute(boundaryNode, incidents);
|
|
6316
|
+
const callees = declaredOutboundCallees(graph, boundaryNode);
|
|
6317
|
+
if (callees.length === 0) return null;
|
|
6318
|
+
const narrowed = route !== void 0 ? callees.filter((c) => c.route !== void 0 && routeMatches(c.route, route)) : callees;
|
|
6319
|
+
const chosen = narrowed.length === 1 ? narrowed[0] : callees.length === 1 ? callees[0] : null;
|
|
6320
|
+
if (!chosen) return null;
|
|
6321
|
+
let node = chosen.target;
|
|
6322
|
+
const seen = /* @__PURE__ */ new Set([boundaryNode, node]);
|
|
6323
|
+
for (let depth = 0; depth < ROOT_CAUSE_MAX_DEPTH; depth++) {
|
|
6324
|
+
const next = declaredOutboundCallees(graph, node);
|
|
6325
|
+
if (next.length !== 1 || seen.has(next[0].target)) break;
|
|
6326
|
+
node = next[0].target;
|
|
6327
|
+
seen.add(node);
|
|
6328
|
+
}
|
|
6329
|
+
return route !== void 0 ? { node, route } : { node };
|
|
6330
|
+
}
|
|
6246
6331
|
function enrichWithNavigation(graph, errorNodeId, tagged, incidents, now) {
|
|
6247
6332
|
const legacy = tagged.result;
|
|
6248
6333
|
const seedNode = legacy.rootCauseNode;
|
|
@@ -6276,6 +6361,29 @@ function enrichWithNavigation(graph, errorNodeId, tagged, incidents, now) {
|
|
|
6276
6361
|
confidence: Math.min(legacy.confidence, 0.4),
|
|
6277
6362
|
...lastProv ? { provenance: lastProv } : {}
|
|
6278
6363
|
});
|
|
6364
|
+
} else if (seedCtx && isBoundaryTimeoutSymptom(seedCtx)) {
|
|
6365
|
+
const pointer = structuralUpstreamPointer(graph, seedNode, incidents);
|
|
6366
|
+
const seedName = displayNameOf(seedNode);
|
|
6367
|
+
const routeNote = pointer?.route ? ` serving ${pointer.route}` : "";
|
|
6368
|
+
if (pointer) {
|
|
6369
|
+
const causeName = displayNameOf(pointer.node);
|
|
6370
|
+
candidates.push({
|
|
6371
|
+
node: pointer.node,
|
|
6372
|
+
classification: "primary-failure",
|
|
6373
|
+
reason: `${causeName} is the likely root cause (structural, INFERRED \u2014 not observed): the boundary ${seedName} only timed out waiting, and the actual culprit hung without exporting a span, so this is walked from the declared call graph${routeNote}, not from runtime signal. Restore instrumentation / inspect ${causeName} to confirm.`,
|
|
6374
|
+
context: nodeContext(graph, pointer.node, incidents, now),
|
|
6375
|
+
confidence: Math.min(legacy.confidence, PROVENANCE_CEILING.EXTRACTED),
|
|
6376
|
+
provenance: Provenance6.INFERRED
|
|
6377
|
+
});
|
|
6378
|
+
}
|
|
6379
|
+
candidates.push({
|
|
6380
|
+
node: seedNode,
|
|
6381
|
+
classification: "symptom-only",
|
|
6382
|
+
reason: pointer ? `${seedName} timed out waiting on a downstream that hung and exported nothing \u2014 a boundary reporting an upstream fault, not the fault itself.` : `${seedName} timed out but nothing it can see downstream is erroring \u2014 the cause is downstream and unobserved (the culprit hung and exported no span). No single declared callee${routeNote} resolves, so no confident cause is named; inspect ${seedName}'s declared downstream.`,
|
|
6383
|
+
context: seedCtx,
|
|
6384
|
+
confidence: Math.min(legacy.confidence, 0.3),
|
|
6385
|
+
...lastProv ? { provenance: lastProv } : {}
|
|
6386
|
+
});
|
|
6279
6387
|
} else if (staleChain) {
|
|
6280
6388
|
const culprit = staleChain.culprit;
|
|
6281
6389
|
const culpritName = displayNameOf(culprit);
|
|
@@ -22510,4 +22618,4 @@ export {
|
|
|
22510
22618
|
deprovisionConnector,
|
|
22511
22619
|
buildApi
|
|
22512
22620
|
};
|
|
22513
|
-
//# sourceMappingURL=chunk-
|
|
22621
|
+
//# sourceMappingURL=chunk-C3LHXC55.js.map
|