@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.
@@ -20,7 +20,7 @@ import {
20
20
  startStalenessLoop,
21
21
  touchLastSeen,
22
22
  writeAtomically
23
- } from "./chunk-3PXRQH53.js";
23
+ } from "./chunk-ZGZYZ33B.js";
24
24
  import {
25
25
  assertBindAuthority,
26
26
  buildOtelReceiver,
@@ -891,4 +891,4 @@ export {
891
891
  resolveHost,
892
892
  startDaemon
893
893
  };
894
- //# sourceMappingURL=chunk-OJ6BW63H.js.map
894
+ //# sourceMappingURL=chunk-RQTW7IV3.js.map
@@ -3794,7 +3794,7 @@ function ensureObservedSymbolNode(graph, fileNodeId, service, relPath, fn, line)
3794
3794
  }
3795
3795
  return sid;
3796
3796
  }
3797
- function landObservedSymbol(graph, fileNodeId, service, relPath, callSite) {
3797
+ function landObservedSymbol(graph, fileNodeId, service, relPath, callSite, mint = true) {
3798
3798
  const line = callSite.line;
3799
3799
  if (line === void 0) return fileNodeId;
3800
3800
  let sawSymbol = false;
@@ -3809,7 +3809,7 @@ function landObservedSymbol(graph, fileNodeId, service, relPath, callSite) {
3809
3809
  }
3810
3810
  });
3811
3811
  if (candidates.length > 0) return pickContainingSymbol(candidates, callSite.fn);
3812
- if (sawSymbol && callSite.fn) {
3812
+ if (mint && sawSymbol && callSite.fn) {
3813
3813
  return ensureObservedSymbolNode(graph, fileNodeId, service, relPath, callSite.fn, line);
3814
3814
  }
3815
3815
  return fileNodeId;
@@ -4215,6 +4215,20 @@ function incidentAffectedNode(span, graph, scanPath) {
4215
4215
  const callSite = callSiteFromSpan(span, serviceNode, scanPath);
4216
4216
  if (callSite) {
4217
4217
  const relPath = graph ? reconcileObservedRelPath(graph, span.service, callSite.relPath) : callSite.relPath;
4218
+ const canonicalService = serviceNode && typeof serviceNode.name === "string" ? serviceNode.name : span.service;
4219
+ if (graph) {
4220
+ const fusedFileId = fileId3(canonicalService, relPath);
4221
+ if (graph.hasNode(fusedFileId)) {
4222
+ return landObservedSymbol(
4223
+ graph,
4224
+ fusedFileId,
4225
+ canonicalService,
4226
+ relPath,
4227
+ { ...callSite, relPath },
4228
+ false
4229
+ );
4230
+ }
4231
+ }
4218
4232
  return fileId3(span.service, relPath);
4219
4233
  }
4220
4234
  return sid;
@@ -4578,7 +4592,11 @@ async function handleSpan(ctx, span) {
4578
4592
  ...span.exception?.type ? { exceptionType: span.exception.type } : {},
4579
4593
  ...span.exception?.stacktrace ? { exceptionStacktrace: span.exception.stacktrace } : {},
4580
4594
  ...Object.keys(attrs).length > 0 ? { attributes: attrs } : {},
4581
- affectedNode
4595
+ // Attribute to where the failure originated — the symbol / file / service
4596
+ // the throwing span named (incidentAffectedNode, ADR-191) — the same
4597
+ // source-based attribution the durable receiver write uses, not the
4598
+ // outbound edge target this span happened to mint.
4599
+ affectedNode: incidentAffectedNode(span, ctx.graph, ctx.scanPath)
4582
4600
  };
4583
4601
  await appendErrorEvent(ctx, ev);
4584
4602
  }
@@ -4857,7 +4875,9 @@ import {
4857
4875
  Provenance as Provenance6,
4858
4876
  RelateResultSchema,
4859
4877
  RootCauseResultSchema,
4860
- TransitiveDependenciesResultSchema
4878
+ TransitiveDependenciesResultSchema,
4879
+ fileId as fileId4,
4880
+ parseSymbolId
4861
4881
  } from "@neat.is/types";
4862
4882
  var ROOT_CAUSE_MAX_DEPTH = 5;
4863
4883
  var BLAST_RADIUS_DEFAULT_DEPTH = 10;
@@ -5099,7 +5119,11 @@ function legacyRootCause(graph, errorNodeId, errorEvent, incidents) {
5099
5119
  }
5100
5120
  var INCIDENT_ROOT_CAUSE_CONFIDENCE = 0.6;
5101
5121
  function incidentMatchesNode(ev, nodeId) {
5102
- return ev.affectedNode === nodeId || ev.service === nodeId.replace(/^service:/, "");
5122
+ if (ev.affectedNode === nodeId) return true;
5123
+ if (ev.service === nodeId.replace(/^service:/, "")) return true;
5124
+ const sym = parseSymbolId(ev.affectedNode);
5125
+ if (sym && fileId4(sym.service, sym.relPath) === nodeId) return true;
5126
+ return false;
5103
5127
  }
5104
5128
  function localizeFromIncidents(nodeId, incidents, errorEvent) {
5105
5129
  const pool = incidents && incidents.length > 0 ? incidents : errorEvent ? [errorEvent] : [];
@@ -5117,8 +5141,8 @@ function localizeFromIncidents(nodeId, incidents, errorEvent) {
5117
5141
  const reasonParts = [`${latest.service}: ${latest.errorMessage}`];
5118
5142
  if (location) reasonParts.push(`surfaced at ${location}`);
5119
5143
  const rootCauseReason = `${reasonParts.join(" \u2014 ")}${tail}`;
5120
- const localizesToFile = latest.affectedNode !== nodeId && latest.affectedNode.startsWith("file:");
5121
- const fileNode = localizesToFile ? latest.affectedNode : void 0;
5144
+ const localizesFiner = latest.affectedNode !== nodeId && (latest.affectedNode.startsWith("file:") || latest.affectedNode.startsWith("symbol:"));
5145
+ const fileNode = localizesFiner ? latest.affectedNode : void 0;
5122
5146
  const fixRecommendation = location ? `Inspect ${location}${route ? ` handling ${route}` : ""}` : route ? `Inspect ${latest.service}'s handler for ${route}` : void 0;
5123
5147
  return {
5124
5148
  rootCauseNode: fileNode ?? nodeId,
@@ -5603,6 +5627,22 @@ function findLoadOrigin(graph, alertNodeId, incidents, now) {
5603
5627
  }
5604
5628
  return best ? { node: best.node, ctx: best.ctx } : null;
5605
5629
  }
5630
+ var LOAD_ORIGIN_CONFIDENCE_CEILING = 0.9;
5631
+ function loadOriginConfidence(originCtx, seedCtx) {
5632
+ const cleanSplit = seedCtx.errorsFromCallers > 0 && seedCtx.errorsEmittedHere === 0;
5633
+ const partialSplit = seedCtx.errorsFromCallers > seedCtx.errorsEmittedHere;
5634
+ let evidence = 0;
5635
+ evidence += cleanSplit ? 0.45 : partialSplit ? 0.2 : 0;
5636
+ evidence += seedCtx.stale ? 0.2 : 0;
5637
+ evidence += isSaturated(seedCtx) ? 0.15 : 0;
5638
+ evidence += (volumeWeight(originCtx.outboundVolume) - 0.5) * 0.4;
5639
+ const anchor = 0.45;
5640
+ const confidence = anchor + Math.min(1, evidence) * (LOAD_ORIGIN_CONFIDENCE_CEILING - anchor);
5641
+ return Math.max(0, Math.min(LOAD_ORIGIN_CONFIDENCE_CEILING, confidence));
5642
+ }
5643
+ function displayNameOf(nodeId) {
5644
+ return nodeId.replace(/^[a-z]+:/, "");
5645
+ }
5606
5646
  function getRootCause(graph, errorNodeId, errorEvent, incidents, opts) {
5607
5647
  const legacy = legacyRootCause(graph, errorNodeId, errorEvent, incidents);
5608
5648
  if (!legacy) return null;
@@ -5617,20 +5657,20 @@ function enrichWithNavigation(graph, errorNodeId, legacy, incidents, now) {
5617
5657
  const candidates = [];
5618
5658
  if (seedCtx && isVictimSeed(seedCtx)) {
5619
5659
  const origin = findLoadOrigin(graph, errorNodeId, incidents, now);
5660
+ const staleNote = seedCtx.stale ? "; it has gone STALE under load" : "";
5661
+ const satNote = isSaturated(seedCtx) ? `; its inbound p95 ${Math.round(seedCtx.latencyP95Ms)}ms is saturated` : "";
5620
5662
  if (origin) {
5621
- const path64 = findPath(graph, errorNodeId, origin.node, "up", ROOT_CAUSE_MAX_DEPTH);
5622
- const originConfidence = confidenceFromMix(path64?.edges ?? [], now);
5663
+ const originName = displayNameOf(origin.node);
5664
+ const seedName = displayNameOf(seedNode);
5623
5665
  candidates.push({
5624
5666
  node: origin.node,
5625
5667
  classification: "primary-failure",
5626
- 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.`,
5668
+ 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).`,
5627
5669
  context: origin.ctx,
5628
- confidence: Math.max(0.3, Math.min(0.8, originConfidence || 0.5)),
5670
+ confidence: loadOriginConfidence(origin.ctx, seedCtx),
5629
5671
  provenance: Provenance6.OBSERVED
5630
5672
  });
5631
5673
  }
5632
- const staleNote = seedCtx.stale ? "; the node has gone STALE" : "";
5633
- const satNote = isSaturated(seedCtx) ? `; inbound p95 ${Math.round(seedCtx.latencyP95Ms)}ms is saturated` : "";
5634
5674
  candidates.push({
5635
5675
  node: seedNode,
5636
5676
  classification: "symptom-only",
@@ -5662,16 +5702,27 @@ function enrichWithNavigation(graph, errorNodeId, legacy, incidents, now) {
5662
5702
  edgeProvenances = [top.provenance ?? Provenance6.OBSERVED];
5663
5703
  }
5664
5704
  }
5705
+ const fixRecommendation = fixRecommendationForTop(top, seedNode, legacy);
5665
5706
  return RootCauseResultSchema.parse({
5666
5707
  rootCauseNode: top.node,
5667
5708
  rootCauseReason: top.reason,
5668
5709
  traversalPath,
5669
5710
  edgeProvenances,
5670
5711
  confidence: top.confidence,
5671
- ...legacy.fixRecommendation ? { fixRecommendation: legacy.fixRecommendation } : {},
5712
+ ...fixRecommendation ? { fixRecommendation } : {},
5672
5713
  candidates
5673
5714
  });
5674
5715
  }
5716
+ function fixRecommendationForTop(top, seedNode, legacy) {
5717
+ if (top.classification === "primary-failure" && top.node === seedNode) {
5718
+ return legacy.fixRecommendation;
5719
+ }
5720
+ const name = top.node.replace(/^service:/, "");
5721
+ if (top.classification === "primary-failure") {
5722
+ 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.`;
5723
+ }
5724
+ return `${name} is a saturated/starved downstream victim; investigate its inbound load and upstream callers, not its own handler.`;
5725
+ }
5675
5726
 
5676
5727
  // src/extract/services.ts
5677
5728
  import { promises as fs12 } from "fs";
@@ -16076,7 +16127,7 @@ function createFirebaseConnector(graph, serviceMap) {
16076
16127
  }
16077
16128
 
16078
16129
  // src/connectors/cloudflare/connector.ts
16079
- import { EdgeType as EdgeType29, NodeType as NodeType29, fileId as fileId4, infraId as infraId21 } from "@neat.is/types";
16130
+ import { EdgeType as EdgeType29, NodeType as NodeType29, fileId as fileId5, infraId as infraId21 } from "@neat.is/types";
16080
16131
 
16081
16132
  // src/connectors/cloudflare/client.ts
16082
16133
  import { randomUUID } from "crypto";
@@ -16266,7 +16317,7 @@ function createCloudflareResolveTarget(config, graph) {
16266
16317
  };
16267
16318
  const mapping = config.workers?.[scriptName];
16268
16319
  if (mapping) {
16269
- const wholeFileId = fileId4(mapping.service, mapping.entryFile);
16320
+ const wholeFileId = fileId5(mapping.service, mapping.entryFile);
16270
16321
  return {
16271
16322
  targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),
16272
16323
  serviceName: mapping.service,
@@ -18924,4 +18975,4 @@ export {
18924
18975
  deprovisionConnector,
18925
18976
  buildApi
18926
18977
  };
18927
- //# sourceMappingURL=chunk-3PXRQH53.js.map
18978
+ //# sourceMappingURL=chunk-ZGZYZ33B.js.map