@neat.is/core 0.8.1-dev.20260816 → 0.8.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/{chunk-OJ6BW63H.js → chunk-RQTW7IV3.js} +2 -2
- package/dist/{chunk-3PXRQH53.js → chunk-ZGZYZ33B.js} +68 -17
- package/dist/chunk-ZGZYZ33B.js.map +1 -0
- package/dist/cli.cjs +62 -13
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/index.cjs +62 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +62 -13
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +62 -13
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-3PXRQH53.js.map +0 -1
- /package/dist/{chunk-OJ6BW63H.js.map → chunk-RQTW7IV3.js.map} +0 -0
package/dist/cli.cjs
CHANGED
|
@@ -1472,7 +1472,11 @@ function legacyRootCause(graph, errorNodeId, errorEvent, incidents) {
|
|
|
1472
1472
|
}
|
|
1473
1473
|
var INCIDENT_ROOT_CAUSE_CONFIDENCE = 0.6;
|
|
1474
1474
|
function incidentMatchesNode(ev, nodeId) {
|
|
1475
|
-
|
|
1475
|
+
if (ev.affectedNode === nodeId) return true;
|
|
1476
|
+
if (ev.service === nodeId.replace(/^service:/, "")) return true;
|
|
1477
|
+
const sym = (0, import_types.parseSymbolId)(ev.affectedNode);
|
|
1478
|
+
if (sym && (0, import_types.fileId)(sym.service, sym.relPath) === nodeId) return true;
|
|
1479
|
+
return false;
|
|
1476
1480
|
}
|
|
1477
1481
|
function localizeFromIncidents(nodeId, incidents, errorEvent) {
|
|
1478
1482
|
const pool = incidents && incidents.length > 0 ? incidents : errorEvent ? [errorEvent] : [];
|
|
@@ -1490,8 +1494,8 @@ function localizeFromIncidents(nodeId, incidents, errorEvent) {
|
|
|
1490
1494
|
const reasonParts = [`${latest.service}: ${latest.errorMessage}`];
|
|
1491
1495
|
if (location) reasonParts.push(`surfaced at ${location}`);
|
|
1492
1496
|
const rootCauseReason = `${reasonParts.join(" \u2014 ")}${tail}`;
|
|
1493
|
-
const
|
|
1494
|
-
const fileNode =
|
|
1497
|
+
const localizesFiner = latest.affectedNode !== nodeId && (latest.affectedNode.startsWith("file:") || latest.affectedNode.startsWith("symbol:"));
|
|
1498
|
+
const fileNode = localizesFiner ? latest.affectedNode : void 0;
|
|
1495
1499
|
const fixRecommendation = location ? `Inspect ${location}${route ? ` handling ${route}` : ""}` : route ? `Inspect ${latest.service}'s handler for ${route}` : void 0;
|
|
1496
1500
|
return {
|
|
1497
1501
|
rootCauseNode: fileNode ?? nodeId,
|
|
@@ -1976,6 +1980,22 @@ function findLoadOrigin(graph, alertNodeId, incidents, now) {
|
|
|
1976
1980
|
}
|
|
1977
1981
|
return best ? { node: best.node, ctx: best.ctx } : null;
|
|
1978
1982
|
}
|
|
1983
|
+
var LOAD_ORIGIN_CONFIDENCE_CEILING = 0.9;
|
|
1984
|
+
function loadOriginConfidence(originCtx, seedCtx) {
|
|
1985
|
+
const cleanSplit = seedCtx.errorsFromCallers > 0 && seedCtx.errorsEmittedHere === 0;
|
|
1986
|
+
const partialSplit = seedCtx.errorsFromCallers > seedCtx.errorsEmittedHere;
|
|
1987
|
+
let evidence = 0;
|
|
1988
|
+
evidence += cleanSplit ? 0.45 : partialSplit ? 0.2 : 0;
|
|
1989
|
+
evidence += seedCtx.stale ? 0.2 : 0;
|
|
1990
|
+
evidence += isSaturated(seedCtx) ? 0.15 : 0;
|
|
1991
|
+
evidence += (volumeWeight(originCtx.outboundVolume) - 0.5) * 0.4;
|
|
1992
|
+
const anchor = 0.45;
|
|
1993
|
+
const confidence = anchor + Math.min(1, evidence) * (LOAD_ORIGIN_CONFIDENCE_CEILING - anchor);
|
|
1994
|
+
return Math.max(0, Math.min(LOAD_ORIGIN_CONFIDENCE_CEILING, confidence));
|
|
1995
|
+
}
|
|
1996
|
+
function displayNameOf(nodeId) {
|
|
1997
|
+
return nodeId.replace(/^[a-z]+:/, "");
|
|
1998
|
+
}
|
|
1979
1999
|
function getRootCause(graph, errorNodeId, errorEvent, incidents, opts) {
|
|
1980
2000
|
const legacy = legacyRootCause(graph, errorNodeId, errorEvent, incidents);
|
|
1981
2001
|
if (!legacy) return null;
|
|
@@ -1990,20 +2010,20 @@ function enrichWithNavigation(graph, errorNodeId, legacy, incidents, now) {
|
|
|
1990
2010
|
const candidates = [];
|
|
1991
2011
|
if (seedCtx && isVictimSeed(seedCtx)) {
|
|
1992
2012
|
const origin = findLoadOrigin(graph, errorNodeId, incidents, now);
|
|
2013
|
+
const staleNote = seedCtx.stale ? "; it has gone STALE under load" : "";
|
|
2014
|
+
const satNote = isSaturated(seedCtx) ? `; its inbound p95 ${Math.round(seedCtx.latencyP95Ms)}ms is saturated` : "";
|
|
1993
2015
|
if (origin) {
|
|
1994
|
-
const
|
|
1995
|
-
const
|
|
2016
|
+
const originName = displayNameOf(origin.node);
|
|
2017
|
+
const seedName = displayNameOf(seedNode);
|
|
1996
2018
|
candidates.push({
|
|
1997
2019
|
node: origin.node,
|
|
1998
2020
|
classification: "primary-failure",
|
|
1999
|
-
reason:
|
|
2021
|
+
reason: `${originName} is the root cause: it overloads the failing subgraph, and the alerting node ${seedName} is a downstream symptom, not the fault \u2014 errors reach ${seedName} from its callers (${seedCtx.errorsFromCallers}), none originate there${staleNote}${satNote}. ${originName} is the upstream source driving that load (${origin.ctx.outboundVolume} observed outbound calls).`,
|
|
2000
2022
|
context: origin.ctx,
|
|
2001
|
-
confidence:
|
|
2023
|
+
confidence: loadOriginConfidence(origin.ctx, seedCtx),
|
|
2002
2024
|
provenance: import_types.Provenance.OBSERVED
|
|
2003
2025
|
});
|
|
2004
2026
|
}
|
|
2005
|
-
const staleNote = seedCtx.stale ? "; the node has gone STALE" : "";
|
|
2006
|
-
const satNote = isSaturated(seedCtx) ? `; inbound p95 ${Math.round(seedCtx.latencyP95Ms)}ms is saturated` : "";
|
|
2007
2027
|
candidates.push({
|
|
2008
2028
|
node: seedNode,
|
|
2009
2029
|
classification: "symptom-only",
|
|
@@ -2035,16 +2055,27 @@ function enrichWithNavigation(graph, errorNodeId, legacy, incidents, now) {
|
|
|
2035
2055
|
edgeProvenances = [top.provenance ?? import_types.Provenance.OBSERVED];
|
|
2036
2056
|
}
|
|
2037
2057
|
}
|
|
2058
|
+
const fixRecommendation = fixRecommendationForTop(top, seedNode, legacy);
|
|
2038
2059
|
return import_types.RootCauseResultSchema.parse({
|
|
2039
2060
|
rootCauseNode: top.node,
|
|
2040
2061
|
rootCauseReason: top.reason,
|
|
2041
2062
|
traversalPath,
|
|
2042
2063
|
edgeProvenances,
|
|
2043
2064
|
confidence: top.confidence,
|
|
2044
|
-
...
|
|
2065
|
+
...fixRecommendation ? { fixRecommendation } : {},
|
|
2045
2066
|
candidates
|
|
2046
2067
|
});
|
|
2047
2068
|
}
|
|
2069
|
+
function fixRecommendationForTop(top, seedNode, legacy) {
|
|
2070
|
+
if (top.classification === "primary-failure" && top.node === seedNode) {
|
|
2071
|
+
return legacy.fixRecommendation;
|
|
2072
|
+
}
|
|
2073
|
+
const name = top.node.replace(/^service:/, "");
|
|
2074
|
+
if (top.classification === "primary-failure") {
|
|
2075
|
+
return `Reduce or throttle the load from ${name} (or scale the saturated downstream capacity it drives) \u2014 the failure originates at this overloading source, not the starved callee.`;
|
|
2076
|
+
}
|
|
2077
|
+
return `${name} is a saturated/starved downstream victim; investigate its inbound load and upstream callers, not its own handler.`;
|
|
2078
|
+
}
|
|
2048
2079
|
|
|
2049
2080
|
// src/policy.ts
|
|
2050
2081
|
var DEFAULT_ACTION_BY_SEVERITY = {
|
|
@@ -5391,7 +5422,7 @@ function ensureObservedSymbolNode(graph, fileNodeId, service, relPath, fn, line)
|
|
|
5391
5422
|
}
|
|
5392
5423
|
return sid;
|
|
5393
5424
|
}
|
|
5394
|
-
function landObservedSymbol(graph, fileNodeId, service, relPath, callSite) {
|
|
5425
|
+
function landObservedSymbol(graph, fileNodeId, service, relPath, callSite, mint = true) {
|
|
5395
5426
|
const line = callSite.line;
|
|
5396
5427
|
if (line === void 0) return fileNodeId;
|
|
5397
5428
|
let sawSymbol = false;
|
|
@@ -5406,7 +5437,7 @@ function landObservedSymbol(graph, fileNodeId, service, relPath, callSite) {
|
|
|
5406
5437
|
}
|
|
5407
5438
|
});
|
|
5408
5439
|
if (candidates.length > 0) return pickContainingSymbol(candidates, callSite.fn);
|
|
5409
|
-
if (sawSymbol && callSite.fn) {
|
|
5440
|
+
if (mint && sawSymbol && callSite.fn) {
|
|
5410
5441
|
return ensureObservedSymbolNode(graph, fileNodeId, service, relPath, callSite.fn, line);
|
|
5411
5442
|
}
|
|
5412
5443
|
return fileNodeId;
|
|
@@ -5812,6 +5843,20 @@ function incidentAffectedNode(span, graph, scanPath) {
|
|
|
5812
5843
|
const callSite = callSiteFromSpan(span, serviceNode, scanPath);
|
|
5813
5844
|
if (callSite) {
|
|
5814
5845
|
const relPath = graph ? reconcileObservedRelPath(graph, span.service, callSite.relPath) : callSite.relPath;
|
|
5846
|
+
const canonicalService = serviceNode && typeof serviceNode.name === "string" ? serviceNode.name : span.service;
|
|
5847
|
+
if (graph) {
|
|
5848
|
+
const fusedFileId = (0, import_types8.fileId)(canonicalService, relPath);
|
|
5849
|
+
if (graph.hasNode(fusedFileId)) {
|
|
5850
|
+
return landObservedSymbol(
|
|
5851
|
+
graph,
|
|
5852
|
+
fusedFileId,
|
|
5853
|
+
canonicalService,
|
|
5854
|
+
relPath,
|
|
5855
|
+
{ ...callSite, relPath },
|
|
5856
|
+
false
|
|
5857
|
+
);
|
|
5858
|
+
}
|
|
5859
|
+
}
|
|
5815
5860
|
return (0, import_types8.fileId)(span.service, relPath);
|
|
5816
5861
|
}
|
|
5817
5862
|
return sid;
|
|
@@ -6175,7 +6220,11 @@ async function handleSpan(ctx, span) {
|
|
|
6175
6220
|
...span.exception?.type ? { exceptionType: span.exception.type } : {},
|
|
6176
6221
|
...span.exception?.stacktrace ? { exceptionStacktrace: span.exception.stacktrace } : {},
|
|
6177
6222
|
...Object.keys(attrs).length > 0 ? { attributes: attrs } : {},
|
|
6178
|
-
|
|
6223
|
+
// Attribute to where the failure originated — the symbol / file / service
|
|
6224
|
+
// the throwing span named (incidentAffectedNode, ADR-191) — the same
|
|
6225
|
+
// source-based attribution the durable receiver write uses, not the
|
|
6226
|
+
// outbound edge target this span happened to mint.
|
|
6227
|
+
affectedNode: incidentAffectedNode(span, ctx.graph, ctx.scanPath)
|
|
6179
6228
|
};
|
|
6180
6229
|
await appendErrorEvent(ctx, ev);
|
|
6181
6230
|
}
|