@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/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
routeSpanToProject,
|
|
3
3
|
startDaemon
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-RQTW7IV3.js";
|
|
5
5
|
import {
|
|
6
6
|
ProjectNameCollisionError,
|
|
7
7
|
addProject,
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
thresholdForEdgeType,
|
|
38
38
|
touchLastSeen,
|
|
39
39
|
writeAtomically
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-ZGZYZ33B.js";
|
|
41
41
|
import {
|
|
42
42
|
startOtelGrpcReceiver
|
|
43
43
|
} from "./chunk-FCO5Z3RW.js";
|
package/dist/neatd.cjs
CHANGED
|
@@ -1427,7 +1427,11 @@ function legacyRootCause(graph, errorNodeId, errorEvent, incidents) {
|
|
|
1427
1427
|
}
|
|
1428
1428
|
var INCIDENT_ROOT_CAUSE_CONFIDENCE = 0.6;
|
|
1429
1429
|
function incidentMatchesNode(ev, nodeId) {
|
|
1430
|
-
|
|
1430
|
+
if (ev.affectedNode === nodeId) return true;
|
|
1431
|
+
if (ev.service === nodeId.replace(/^service:/, "")) return true;
|
|
1432
|
+
const sym = (0, import_types.parseSymbolId)(ev.affectedNode);
|
|
1433
|
+
if (sym && (0, import_types.fileId)(sym.service, sym.relPath) === nodeId) return true;
|
|
1434
|
+
return false;
|
|
1431
1435
|
}
|
|
1432
1436
|
function localizeFromIncidents(nodeId, incidents, errorEvent) {
|
|
1433
1437
|
const pool = incidents && incidents.length > 0 ? incidents : errorEvent ? [errorEvent] : [];
|
|
@@ -1445,8 +1449,8 @@ function localizeFromIncidents(nodeId, incidents, errorEvent) {
|
|
|
1445
1449
|
const reasonParts = [`${latest.service}: ${latest.errorMessage}`];
|
|
1446
1450
|
if (location) reasonParts.push(`surfaced at ${location}`);
|
|
1447
1451
|
const rootCauseReason = `${reasonParts.join(" \u2014 ")}${tail}`;
|
|
1448
|
-
const
|
|
1449
|
-
const fileNode =
|
|
1452
|
+
const localizesFiner = latest.affectedNode !== nodeId && (latest.affectedNode.startsWith("file:") || latest.affectedNode.startsWith("symbol:"));
|
|
1453
|
+
const fileNode = localizesFiner ? latest.affectedNode : void 0;
|
|
1450
1454
|
const fixRecommendation = location ? `Inspect ${location}${route ? ` handling ${route}` : ""}` : route ? `Inspect ${latest.service}'s handler for ${route}` : void 0;
|
|
1451
1455
|
return {
|
|
1452
1456
|
rootCauseNode: fileNode ?? nodeId,
|
|
@@ -1931,6 +1935,22 @@ function findLoadOrigin(graph, alertNodeId, incidents, now) {
|
|
|
1931
1935
|
}
|
|
1932
1936
|
return best ? { node: best.node, ctx: best.ctx } : null;
|
|
1933
1937
|
}
|
|
1938
|
+
var LOAD_ORIGIN_CONFIDENCE_CEILING = 0.9;
|
|
1939
|
+
function loadOriginConfidence(originCtx, seedCtx) {
|
|
1940
|
+
const cleanSplit = seedCtx.errorsFromCallers > 0 && seedCtx.errorsEmittedHere === 0;
|
|
1941
|
+
const partialSplit = seedCtx.errorsFromCallers > seedCtx.errorsEmittedHere;
|
|
1942
|
+
let evidence = 0;
|
|
1943
|
+
evidence += cleanSplit ? 0.45 : partialSplit ? 0.2 : 0;
|
|
1944
|
+
evidence += seedCtx.stale ? 0.2 : 0;
|
|
1945
|
+
evidence += isSaturated(seedCtx) ? 0.15 : 0;
|
|
1946
|
+
evidence += (volumeWeight(originCtx.outboundVolume) - 0.5) * 0.4;
|
|
1947
|
+
const anchor = 0.45;
|
|
1948
|
+
const confidence = anchor + Math.min(1, evidence) * (LOAD_ORIGIN_CONFIDENCE_CEILING - anchor);
|
|
1949
|
+
return Math.max(0, Math.min(LOAD_ORIGIN_CONFIDENCE_CEILING, confidence));
|
|
1950
|
+
}
|
|
1951
|
+
function displayNameOf(nodeId) {
|
|
1952
|
+
return nodeId.replace(/^[a-z]+:/, "");
|
|
1953
|
+
}
|
|
1934
1954
|
function getRootCause(graph, errorNodeId, errorEvent, incidents, opts) {
|
|
1935
1955
|
const legacy = legacyRootCause(graph, errorNodeId, errorEvent, incidents);
|
|
1936
1956
|
if (!legacy) return null;
|
|
@@ -1945,20 +1965,20 @@ function enrichWithNavigation(graph, errorNodeId, legacy, incidents, now) {
|
|
|
1945
1965
|
const candidates = [];
|
|
1946
1966
|
if (seedCtx && isVictimSeed(seedCtx)) {
|
|
1947
1967
|
const origin = findLoadOrigin(graph, errorNodeId, incidents, now);
|
|
1968
|
+
const staleNote = seedCtx.stale ? "; it has gone STALE under load" : "";
|
|
1969
|
+
const satNote = isSaturated(seedCtx) ? `; its inbound p95 ${Math.round(seedCtx.latencyP95Ms)}ms is saturated` : "";
|
|
1948
1970
|
if (origin) {
|
|
1949
|
-
const
|
|
1950
|
-
const
|
|
1971
|
+
const originName = displayNameOf(origin.node);
|
|
1972
|
+
const seedName = displayNameOf(seedNode);
|
|
1951
1973
|
candidates.push({
|
|
1952
1974
|
node: origin.node,
|
|
1953
1975
|
classification: "primary-failure",
|
|
1954
|
-
reason:
|
|
1976
|
+
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).`,
|
|
1955
1977
|
context: origin.ctx,
|
|
1956
|
-
confidence:
|
|
1978
|
+
confidence: loadOriginConfidence(origin.ctx, seedCtx),
|
|
1957
1979
|
provenance: import_types.Provenance.OBSERVED
|
|
1958
1980
|
});
|
|
1959
1981
|
}
|
|
1960
|
-
const staleNote = seedCtx.stale ? "; the node has gone STALE" : "";
|
|
1961
|
-
const satNote = isSaturated(seedCtx) ? `; inbound p95 ${Math.round(seedCtx.latencyP95Ms)}ms is saturated` : "";
|
|
1962
1982
|
candidates.push({
|
|
1963
1983
|
node: seedNode,
|
|
1964
1984
|
classification: "symptom-only",
|
|
@@ -1990,16 +2010,27 @@ function enrichWithNavigation(graph, errorNodeId, legacy, incidents, now) {
|
|
|
1990
2010
|
edgeProvenances = [top.provenance ?? import_types.Provenance.OBSERVED];
|
|
1991
2011
|
}
|
|
1992
2012
|
}
|
|
2013
|
+
const fixRecommendation = fixRecommendationForTop(top, seedNode, legacy);
|
|
1993
2014
|
return import_types.RootCauseResultSchema.parse({
|
|
1994
2015
|
rootCauseNode: top.node,
|
|
1995
2016
|
rootCauseReason: top.reason,
|
|
1996
2017
|
traversalPath,
|
|
1997
2018
|
edgeProvenances,
|
|
1998
2019
|
confidence: top.confidence,
|
|
1999
|
-
...
|
|
2020
|
+
...fixRecommendation ? { fixRecommendation } : {},
|
|
2000
2021
|
candidates
|
|
2001
2022
|
});
|
|
2002
2023
|
}
|
|
2024
|
+
function fixRecommendationForTop(top, seedNode, legacy) {
|
|
2025
|
+
if (top.classification === "primary-failure" && top.node === seedNode) {
|
|
2026
|
+
return legacy.fixRecommendation;
|
|
2027
|
+
}
|
|
2028
|
+
const name = top.node.replace(/^service:/, "");
|
|
2029
|
+
if (top.classification === "primary-failure") {
|
|
2030
|
+
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.`;
|
|
2031
|
+
}
|
|
2032
|
+
return `${name} is a saturated/starved downstream victim; investigate its inbound load and upstream callers, not its own handler.`;
|
|
2033
|
+
}
|
|
2003
2034
|
|
|
2004
2035
|
// src/policy.ts
|
|
2005
2036
|
var DEFAULT_ACTION_BY_SEVERITY = {
|
|
@@ -5334,7 +5365,7 @@ function ensureObservedSymbolNode(graph, fileNodeId, service, relPath, fn, line)
|
|
|
5334
5365
|
}
|
|
5335
5366
|
return sid;
|
|
5336
5367
|
}
|
|
5337
|
-
function landObservedSymbol(graph, fileNodeId, service, relPath, callSite) {
|
|
5368
|
+
function landObservedSymbol(graph, fileNodeId, service, relPath, callSite, mint = true) {
|
|
5338
5369
|
const line = callSite.line;
|
|
5339
5370
|
if (line === void 0) return fileNodeId;
|
|
5340
5371
|
let sawSymbol = false;
|
|
@@ -5349,7 +5380,7 @@ function landObservedSymbol(graph, fileNodeId, service, relPath, callSite) {
|
|
|
5349
5380
|
}
|
|
5350
5381
|
});
|
|
5351
5382
|
if (candidates.length > 0) return pickContainingSymbol(candidates, callSite.fn);
|
|
5352
|
-
if (sawSymbol && callSite.fn) {
|
|
5383
|
+
if (mint && sawSymbol && callSite.fn) {
|
|
5353
5384
|
return ensureObservedSymbolNode(graph, fileNodeId, service, relPath, callSite.fn, line);
|
|
5354
5385
|
}
|
|
5355
5386
|
return fileNodeId;
|
|
@@ -5755,6 +5786,20 @@ function incidentAffectedNode(span, graph, scanPath) {
|
|
|
5755
5786
|
const callSite = callSiteFromSpan(span, serviceNode, scanPath);
|
|
5756
5787
|
if (callSite) {
|
|
5757
5788
|
const relPath = graph ? reconcileObservedRelPath(graph, span.service, callSite.relPath) : callSite.relPath;
|
|
5789
|
+
const canonicalService = serviceNode && typeof serviceNode.name === "string" ? serviceNode.name : span.service;
|
|
5790
|
+
if (graph) {
|
|
5791
|
+
const fusedFileId = (0, import_types8.fileId)(canonicalService, relPath);
|
|
5792
|
+
if (graph.hasNode(fusedFileId)) {
|
|
5793
|
+
return landObservedSymbol(
|
|
5794
|
+
graph,
|
|
5795
|
+
fusedFileId,
|
|
5796
|
+
canonicalService,
|
|
5797
|
+
relPath,
|
|
5798
|
+
{ ...callSite, relPath },
|
|
5799
|
+
false
|
|
5800
|
+
);
|
|
5801
|
+
}
|
|
5802
|
+
}
|
|
5758
5803
|
return (0, import_types8.fileId)(span.service, relPath);
|
|
5759
5804
|
}
|
|
5760
5805
|
return sid;
|
|
@@ -6118,7 +6163,11 @@ async function handleSpan(ctx, span) {
|
|
|
6118
6163
|
...span.exception?.type ? { exceptionType: span.exception.type } : {},
|
|
6119
6164
|
...span.exception?.stacktrace ? { exceptionStacktrace: span.exception.stacktrace } : {},
|
|
6120
6165
|
...Object.keys(attrs).length > 0 ? { attributes: attrs } : {},
|
|
6121
|
-
|
|
6166
|
+
// Attribute to where the failure originated — the symbol / file / service
|
|
6167
|
+
// the throwing span named (incidentAffectedNode, ADR-191) — the same
|
|
6168
|
+
// source-based attribution the durable receiver write uses, not the
|
|
6169
|
+
// outbound edge target this span happened to mint.
|
|
6170
|
+
affectedNode: incidentAffectedNode(span, ctx.graph, ctx.scanPath)
|
|
6122
6171
|
};
|
|
6123
6172
|
await appendErrorEvent(ctx, ev);
|
|
6124
6173
|
}
|