@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/cli.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  resolveHost,
7
7
  resolveNeatVersion,
8
8
  writeDaemonRecord
9
- } from "./chunk-OJ6BW63H.js";
9
+ } from "./chunk-RQTW7IV3.js";
10
10
  import {
11
11
  buildSearchIndex
12
12
  } from "./chunk-BC53SCT7.js";
@@ -74,7 +74,7 @@ import {
74
74
  startStalenessLoop,
75
75
  upsertConnectorEntry,
76
76
  validateConnectorEntry
77
- } from "./chunk-3PXRQH53.js";
77
+ } from "./chunk-ZGZYZ33B.js";
78
78
  import {
79
79
  startOtelGrpcReceiver
80
80
  } from "./chunk-FCO5Z3RW.js";
package/dist/index.cjs CHANGED
@@ -1464,7 +1464,11 @@ function legacyRootCause(graph, errorNodeId, errorEvent, incidents) {
1464
1464
  }
1465
1465
  var INCIDENT_ROOT_CAUSE_CONFIDENCE = 0.6;
1466
1466
  function incidentMatchesNode(ev, nodeId) {
1467
- return ev.affectedNode === nodeId || ev.service === nodeId.replace(/^service:/, "");
1467
+ if (ev.affectedNode === nodeId) return true;
1468
+ if (ev.service === nodeId.replace(/^service:/, "")) return true;
1469
+ const sym = (0, import_types.parseSymbolId)(ev.affectedNode);
1470
+ if (sym && (0, import_types.fileId)(sym.service, sym.relPath) === nodeId) return true;
1471
+ return false;
1468
1472
  }
1469
1473
  function localizeFromIncidents(nodeId, incidents, errorEvent) {
1470
1474
  const pool = incidents && incidents.length > 0 ? incidents : errorEvent ? [errorEvent] : [];
@@ -1482,8 +1486,8 @@ function localizeFromIncidents(nodeId, incidents, errorEvent) {
1482
1486
  const reasonParts = [`${latest.service}: ${latest.errorMessage}`];
1483
1487
  if (location) reasonParts.push(`surfaced at ${location}`);
1484
1488
  const rootCauseReason = `${reasonParts.join(" \u2014 ")}${tail}`;
1485
- const localizesToFile = latest.affectedNode !== nodeId && latest.affectedNode.startsWith("file:");
1486
- const fileNode = localizesToFile ? latest.affectedNode : void 0;
1489
+ const localizesFiner = latest.affectedNode !== nodeId && (latest.affectedNode.startsWith("file:") || latest.affectedNode.startsWith("symbol:"));
1490
+ const fileNode = localizesFiner ? latest.affectedNode : void 0;
1487
1491
  const fixRecommendation = location ? `Inspect ${location}${route ? ` handling ${route}` : ""}` : route ? `Inspect ${latest.service}'s handler for ${route}` : void 0;
1488
1492
  return {
1489
1493
  rootCauseNode: fileNode ?? nodeId,
@@ -1968,6 +1972,22 @@ function findLoadOrigin(graph, alertNodeId, incidents, now) {
1968
1972
  }
1969
1973
  return best ? { node: best.node, ctx: best.ctx } : null;
1970
1974
  }
1975
+ var LOAD_ORIGIN_CONFIDENCE_CEILING = 0.9;
1976
+ function loadOriginConfidence(originCtx, seedCtx) {
1977
+ const cleanSplit = seedCtx.errorsFromCallers > 0 && seedCtx.errorsEmittedHere === 0;
1978
+ const partialSplit = seedCtx.errorsFromCallers > seedCtx.errorsEmittedHere;
1979
+ let evidence = 0;
1980
+ evidence += cleanSplit ? 0.45 : partialSplit ? 0.2 : 0;
1981
+ evidence += seedCtx.stale ? 0.2 : 0;
1982
+ evidence += isSaturated(seedCtx) ? 0.15 : 0;
1983
+ evidence += (volumeWeight(originCtx.outboundVolume) - 0.5) * 0.4;
1984
+ const anchor = 0.45;
1985
+ const confidence = anchor + Math.min(1, evidence) * (LOAD_ORIGIN_CONFIDENCE_CEILING - anchor);
1986
+ return Math.max(0, Math.min(LOAD_ORIGIN_CONFIDENCE_CEILING, confidence));
1987
+ }
1988
+ function displayNameOf(nodeId) {
1989
+ return nodeId.replace(/^[a-z]+:/, "");
1990
+ }
1971
1991
  function getRootCause(graph, errorNodeId, errorEvent, incidents, opts) {
1972
1992
  const legacy = legacyRootCause(graph, errorNodeId, errorEvent, incidents);
1973
1993
  if (!legacy) return null;
@@ -1982,20 +2002,20 @@ function enrichWithNavigation(graph, errorNodeId, legacy, incidents, now) {
1982
2002
  const candidates = [];
1983
2003
  if (seedCtx && isVictimSeed(seedCtx)) {
1984
2004
  const origin = findLoadOrigin(graph, errorNodeId, incidents, now);
2005
+ const staleNote = seedCtx.stale ? "; it has gone STALE under load" : "";
2006
+ const satNote = isSaturated(seedCtx) ? `; its inbound p95 ${Math.round(seedCtx.latencyP95Ms)}ms is saturated` : "";
1985
2007
  if (origin) {
1986
- const path68 = findPath(graph, errorNodeId, origin.node, "up", ROOT_CAUSE_MAX_DEPTH);
1987
- const originConfidence = confidenceFromMix(path68?.edges ?? [], now);
2008
+ const originName = displayNameOf(origin.node);
2009
+ const seedName = displayNameOf(seedNode);
1988
2010
  candidates.push({
1989
2011
  node: origin.node,
1990
2012
  classification: "primary-failure",
1991
- reason: `Highest-volume upstream source (${origin.ctx.outboundVolume} observed outbound calls) driving a saturated/stale subgraph; the alerting path decays downstream into a starved victim rather than a fault at the callee.`,
2013
+ 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).`,
1992
2014
  context: origin.ctx,
1993
- confidence: Math.max(0.3, Math.min(0.8, originConfidence || 0.5)),
2015
+ confidence: loadOriginConfidence(origin.ctx, seedCtx),
1994
2016
  provenance: import_types.Provenance.OBSERVED
1995
2017
  });
1996
2018
  }
1997
- const staleNote = seedCtx.stale ? "; the node has gone STALE" : "";
1998
- const satNote = isSaturated(seedCtx) ? `; inbound p95 ${Math.round(seedCtx.latencyP95Ms)}ms is saturated` : "";
1999
2019
  candidates.push({
2000
2020
  node: seedNode,
2001
2021
  classification: "symptom-only",
@@ -2027,16 +2047,27 @@ function enrichWithNavigation(graph, errorNodeId, legacy, incidents, now) {
2027
2047
  edgeProvenances = [top.provenance ?? import_types.Provenance.OBSERVED];
2028
2048
  }
2029
2049
  }
2050
+ const fixRecommendation = fixRecommendationForTop(top, seedNode, legacy);
2030
2051
  return import_types.RootCauseResultSchema.parse({
2031
2052
  rootCauseNode: top.node,
2032
2053
  rootCauseReason: top.reason,
2033
2054
  traversalPath,
2034
2055
  edgeProvenances,
2035
2056
  confidence: top.confidence,
2036
- ...legacy.fixRecommendation ? { fixRecommendation: legacy.fixRecommendation } : {},
2057
+ ...fixRecommendation ? { fixRecommendation } : {},
2037
2058
  candidates
2038
2059
  });
2039
2060
  }
2061
+ function fixRecommendationForTop(top, seedNode, legacy) {
2062
+ if (top.classification === "primary-failure" && top.node === seedNode) {
2063
+ return legacy.fixRecommendation;
2064
+ }
2065
+ const name = top.node.replace(/^service:/, "");
2066
+ if (top.classification === "primary-failure") {
2067
+ 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.`;
2068
+ }
2069
+ return `${name} is a saturated/starved downstream victim; investigate its inbound load and upstream callers, not its own handler.`;
2070
+ }
2040
2071
 
2041
2072
  // src/policy.ts
2042
2073
  var DEFAULT_ACTION_BY_SEVERITY = {
@@ -5371,7 +5402,7 @@ function ensureObservedSymbolNode(graph, fileNodeId, service, relPath, fn, line)
5371
5402
  }
5372
5403
  return sid;
5373
5404
  }
5374
- function landObservedSymbol(graph, fileNodeId, service, relPath, callSite) {
5405
+ function landObservedSymbol(graph, fileNodeId, service, relPath, callSite, mint = true) {
5375
5406
  const line = callSite.line;
5376
5407
  if (line === void 0) return fileNodeId;
5377
5408
  let sawSymbol = false;
@@ -5386,7 +5417,7 @@ function landObservedSymbol(graph, fileNodeId, service, relPath, callSite) {
5386
5417
  }
5387
5418
  });
5388
5419
  if (candidates.length > 0) return pickContainingSymbol(candidates, callSite.fn);
5389
- if (sawSymbol && callSite.fn) {
5420
+ if (mint && sawSymbol && callSite.fn) {
5390
5421
  return ensureObservedSymbolNode(graph, fileNodeId, service, relPath, callSite.fn, line);
5391
5422
  }
5392
5423
  return fileNodeId;
@@ -5792,6 +5823,20 @@ function incidentAffectedNode(span, graph, scanPath) {
5792
5823
  const callSite = callSiteFromSpan(span, serviceNode, scanPath);
5793
5824
  if (callSite) {
5794
5825
  const relPath = graph ? reconcileObservedRelPath(graph, span.service, callSite.relPath) : callSite.relPath;
5826
+ const canonicalService = serviceNode && typeof serviceNode.name === "string" ? serviceNode.name : span.service;
5827
+ if (graph) {
5828
+ const fusedFileId = (0, import_types8.fileId)(canonicalService, relPath);
5829
+ if (graph.hasNode(fusedFileId)) {
5830
+ return landObservedSymbol(
5831
+ graph,
5832
+ fusedFileId,
5833
+ canonicalService,
5834
+ relPath,
5835
+ { ...callSite, relPath },
5836
+ false
5837
+ );
5838
+ }
5839
+ }
5795
5840
  return (0, import_types8.fileId)(span.service, relPath);
5796
5841
  }
5797
5842
  return sid;
@@ -6155,7 +6200,11 @@ async function handleSpan(ctx, span) {
6155
6200
  ...span.exception?.type ? { exceptionType: span.exception.type } : {},
6156
6201
  ...span.exception?.stacktrace ? { exceptionStacktrace: span.exception.stacktrace } : {},
6157
6202
  ...Object.keys(attrs).length > 0 ? { attributes: attrs } : {},
6158
- affectedNode
6203
+ // Attribute to where the failure originated — the symbol / file / service
6204
+ // the throwing span named (incidentAffectedNode, ADR-191) — the same
6205
+ // source-based attribution the durable receiver write uses, not the
6206
+ // outbound edge target this span happened to mint.
6207
+ affectedNode: incidentAffectedNode(span, ctx.graph, ctx.scanPath)
6159
6208
  };
6160
6209
  await appendErrorEvent(ctx, ev);
6161
6210
  }