@neat.is/core 0.9.13-dev.20260901 → 0.9.14

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.
@@ -935,6 +935,7 @@ import {
935
935
  inferredEdgeId,
936
936
  infraId,
937
937
  observedEdgeId,
938
+ frontierEdgeId,
938
939
  serviceId,
939
940
  symbolId,
940
941
  websocketChannelId
@@ -4413,6 +4414,14 @@ function mergeColumnsAt(graph, tableNodeId, columns, provenance, confidence) {
4413
4414
  function mergeObservedColumns(graph, tableNodeId, columns) {
4414
4415
  mergeColumnsAt(graph, tableNodeId, columns, Provenance5.OBSERVED, OBSERVED_COLUMN_CONFIDENCE);
4415
4416
  }
4417
+ function mergeObservedDeployState(graph, serviceNodeId, state) {
4418
+ if (!graph.hasNode(serviceNodeId)) return;
4419
+ const attrs = {};
4420
+ if (typeof state.image === "string" && state.image.length > 0) attrs["observedImage"] = state.image;
4421
+ if (typeof state.readyReplicas === "number") attrs["observedReadyReplicas"] = state.readyReplicas;
4422
+ if (Object.keys(attrs).length === 0) return;
4423
+ graph.mergeNodeAttributes(serviceNodeId, attrs);
4424
+ }
4416
4425
  function ensureDatabaseNode(graph, host, engine) {
4417
4426
  const id = databaseId(host);
4418
4427
  if (graph.hasNode(id)) return id;
@@ -5109,6 +5118,32 @@ function promoteFrontierNodes(graph, opts = {}) {
5109
5118
  }
5110
5119
  return promoted;
5111
5120
  }
5121
+ function stageFrontierEdge(graph, source, target, type) {
5122
+ if (!graph.hasNode(source) || !graph.hasNode(target)) return false;
5123
+ if (graph.hasEdge(observedEdgeId(source, target, type))) return false;
5124
+ const key = frontierEdgeId(source, target, type);
5125
+ if (graph.hasEdge(key)) return false;
5126
+ graph.addEdgeWithKey(key, source, target, {
5127
+ id: key,
5128
+ source,
5129
+ target,
5130
+ type,
5131
+ provenance: Provenance5.FRONTIER
5132
+ });
5133
+ return true;
5134
+ }
5135
+ function promoteFrontierEdges(graph) {
5136
+ const graduated = [];
5137
+ graph.forEachEdge((edgeId, attrs) => {
5138
+ const e = attrs;
5139
+ if (e.provenance !== Provenance5.FRONTIER) return;
5140
+ if (graph.hasEdge(observedEdgeId(e.source, e.target, e.type))) {
5141
+ graduated.push(edgeId);
5142
+ }
5143
+ });
5144
+ for (const edgeId of graduated) graph.dropEdge(edgeId);
5145
+ return graduated.length;
5146
+ }
5112
5147
  function rewireFrontierEdges(graph, frontierId2, serviceId17) {
5113
5148
  const inbound = [...graph.inboundEdges(frontierId2)];
5114
5149
  const outbound = [...graph.outboundEdges(frontierId2)];
@@ -5217,6 +5252,7 @@ function startStalenessLoop(graph, options = {}) {
5217
5252
  project: options.project
5218
5253
  });
5219
5254
  if (options.onPolicyTrigger) await options.onPolicyTrigger(graph);
5255
+ if (options.onReconcile) await options.onReconcile(graph);
5220
5256
  } catch (err) {
5221
5257
  console.error("staleness tick failed", err);
5222
5258
  }
@@ -5360,6 +5396,7 @@ import {
5360
5396
  RootCauseResultSchema,
5361
5397
  TransitiveDependenciesResultSchema,
5362
5398
  fileId as fileId4,
5399
+ frontierEdgeId as frontierEdgeId2,
5363
5400
  parseSymbolId
5364
5401
  } from "@neat.is/types";
5365
5402
  var ROOT_CAUSE_MAX_DEPTH = 5;
@@ -5390,13 +5427,19 @@ function resolveOwningService(graph, nodeId) {
5390
5427
  }
5391
5428
  return null;
5392
5429
  }
5430
+ function isFrontierEdge(e) {
5431
+ return e.provenance === Provenance6.FRONTIER;
5432
+ }
5433
+ function rankOf(p) {
5434
+ return p === Provenance6.FRONTIER ? -1 : PROV_RANK[p];
5435
+ }
5393
5436
  function bestEdgeBySource(graph, edgeIds) {
5394
5437
  const best = /* @__PURE__ */ new Map();
5395
5438
  for (const id of edgeIds) {
5396
5439
  const e = graph.getEdgeAttributes(id);
5397
- if (isFrontierNode(graph, e.source)) continue;
5440
+ if (isFrontierNode(graph, e.source) || isFrontierEdge(e)) continue;
5398
5441
  const cur = best.get(e.source);
5399
- if (!cur || PROV_RANK[e.provenance] > PROV_RANK[cur.provenance]) {
5442
+ if (!cur || rankOf(e.provenance) > rankOf(cur.provenance)) {
5400
5443
  best.set(e.source, e);
5401
5444
  }
5402
5445
  }
@@ -5406,9 +5449,9 @@ function bestEdgeByTarget(graph, edgeIds) {
5406
5449
  const best = /* @__PURE__ */ new Map();
5407
5450
  for (const id of edgeIds) {
5408
5451
  const e = graph.getEdgeAttributes(id);
5409
- if (isFrontierNode(graph, e.target)) continue;
5452
+ if (isFrontierNode(graph, e.target) || isFrontierEdge(e)) continue;
5410
5453
  const cur = best.get(e.target);
5411
- if (!cur || PROV_RANK[e.provenance] > PROV_RANK[cur.provenance]) {
5454
+ if (!cur || rankOf(e.provenance) > rankOf(cur.provenance)) {
5412
5455
  best.set(e.target, e);
5413
5456
  }
5414
5457
  }
@@ -5418,7 +5461,10 @@ var PROVENANCE_CEILING = {
5418
5461
  OBSERVED: 1,
5419
5462
  INFERRED: 0.7,
5420
5463
  EXTRACTED: 0.5,
5421
- STALE: 0.3
5464
+ STALE: 0.3,
5465
+ // A FRONTIER surface (ADR-226) is a proposal about a cause NEAT could not observe
5466
+ // — the least-trusted claim it makes, below STALE (which was at least once seen).
5467
+ FRONTIER: 0.2
5422
5468
  };
5423
5469
  function volumeWeight(spanCount) {
5424
5470
  if (!spanCount || spanCount <= 0) return 0.5;
@@ -5653,7 +5699,7 @@ function rootCauseFromIncidents(nodeId, incidents, errorEvent) {
5653
5699
  });
5654
5700
  }
5655
5701
  function isFailingCallEdge(e) {
5656
- return e.type === EdgeType6.CALLS && (e.signal?.errorCount ?? 0) > 0;
5702
+ return e.type === EdgeType6.CALLS && !isFrontierEdge(e) && (e.signal?.errorCount ?? 0) > 0;
5657
5703
  }
5658
5704
  function callSourcesForService(graph, serviceId17) {
5659
5705
  const ids = [serviceId17];
@@ -5676,8 +5722,8 @@ function failingCallDominates(e, id, curEdge, curId) {
5676
5722
  const ec = e.signal?.errorCount ?? 0;
5677
5723
  const cc = curEdge.signal?.errorCount ?? 0;
5678
5724
  if (ec !== cc) return ec > cc;
5679
- if (PROV_RANK[e.provenance] !== PROV_RANK[curEdge.provenance]) {
5680
- return PROV_RANK[e.provenance] > PROV_RANK[curEdge.provenance];
5725
+ if (rankOf(e.provenance) !== rankOf(curEdge.provenance)) {
5726
+ return rankOf(e.provenance) > rankOf(curEdge.provenance);
5681
5727
  }
5682
5728
  return id < curId;
5683
5729
  }
@@ -5728,11 +5774,11 @@ function dominantStaleCall(graph, serviceId17, visited) {
5728
5774
  for (const edgeId of graph.outboundEdges(src)) {
5729
5775
  const e = graph.getEdgeAttributes(edgeId);
5730
5776
  if (e.type !== EdgeType6.CALLS) continue;
5731
- if (isFrontierNode(graph, e.target)) continue;
5777
+ if (isFrontierNode(graph, e.target) || isFrontierEdge(e)) continue;
5732
5778
  const owner = resolveOwningService(graph, e.target);
5733
5779
  if (!owner || visited.has(owner.id)) continue;
5734
5780
  const cur = bestByCallee.get(owner.id);
5735
- if (!cur || PROV_RANK[e.provenance] > PROV_RANK[cur.provenance]) {
5781
+ if (!cur || rankOf(e.provenance) > rankOf(cur.provenance)) {
5736
5782
  bestByCallee.set(owner.id, e);
5737
5783
  }
5738
5784
  }
@@ -6005,6 +6051,7 @@ function nodeContext(graph, nodeId, incidents, now = Date.now()) {
6005
6051
  for (const edgeId of graph.inboundEdges(n)) {
6006
6052
  const e = graph.getEdgeAttributes(edgeId);
6007
6053
  if (e.type === EdgeType6.CONTAINS) continue;
6054
+ if (isFrontierEdge(e)) continue;
6008
6055
  errorsFromCallers += e.signal?.errorCount ?? 0;
6009
6056
  inboundVolume += e.callCount ?? e.signal?.spanCount ?? 0;
6010
6057
  if (e.provenance === Provenance6.STALE) stale = true;
@@ -6018,6 +6065,7 @@ function nodeContext(graph, nodeId, incidents, now = Date.now()) {
6018
6065
  for (const edgeId of graph.outboundEdges(n)) {
6019
6066
  const e = graph.getEdgeAttributes(edgeId);
6020
6067
  if (e.type === EdgeType6.CONTAINS) continue;
6068
+ if (isFrontierEdge(e)) continue;
6021
6069
  outboundVolume += e.callCount ?? e.signal?.spanCount ?? 0;
6022
6070
  if (e.type === EdgeType6.CALLS) outboundErrors += e.signal?.errorCount ?? 0;
6023
6071
  if (e.provenance === Provenance6.STALE) stale = true;
@@ -6051,6 +6099,11 @@ function isSaturated(ctx) {
6051
6099
  function isBoundaryTimeoutSymptom(ctx) {
6052
6100
  return ctx.errorsEmittedHere > 0 && ctx.boundaryTimeout === true && ctx.errorsFromCallers === 0 && ctx.hasOutboundDeps === true && ctx.observedErroringDownstream !== true;
6053
6101
  }
6102
+ var UNREACHABLE_INBOUND_ERROR_RATE = 0.5;
6103
+ var UNREACHABLE_MIN_INBOUND = 3;
6104
+ function isUnreachableSeed(ctx) {
6105
+ return ctx.callCount >= UNREACHABLE_MIN_INBOUND && ctx.errorsFromCallers > 0 && ctx.errorsFromCallers >= UNREACHABLE_INBOUND_ERROR_RATE * ctx.callCount && ctx.errorsEmittedHere === 0 && ctx.outboundVolume === 0;
6106
+ }
6054
6107
  function classifyNode(ctx) {
6055
6108
  if (ctx.errorsEmittedHere > 0) {
6056
6109
  if ((ctx.stale || isSaturated(ctx)) && ctx.errorsFromCallers >= ctx.errorsEmittedHere) {
@@ -6059,6 +6112,7 @@ function classifyNode(ctx) {
6059
6112
  if (isBoundaryTimeoutSymptom(ctx)) return "symptom-only";
6060
6113
  return "primary-failure";
6061
6114
  }
6115
+ if (isUnreachableSeed(ctx)) return "unreachable";
6062
6116
  if (ctx.errorsFromCallers > 0) return "symptom-only";
6063
6117
  return "unrelated";
6064
6118
  }
@@ -6295,22 +6349,44 @@ function routeMatches(declared, incident) {
6295
6349
  const b = normalizeRoute(incident);
6296
6350
  return a === b || a.startsWith(b) || b.startsWith(a);
6297
6351
  }
6298
- function structuralUpstreamPointer(graph, boundaryNode, incidents) {
6299
- const route = boundaryIncidentRoute(boundaryNode, incidents);
6300
- const callees = declaredOutboundCallees(graph, boundaryNode);
6352
+ function firstDeclaredCallee(graph, node, route) {
6353
+ const callees = declaredOutboundCallees(graph, node);
6301
6354
  if (callees.length === 0) return null;
6302
6355
  const narrowed = route !== void 0 ? callees.filter((c) => c.route !== void 0 && routeMatches(c.route, route)) : callees;
6303
6356
  const chosen = narrowed.length === 1 ? narrowed[0] : callees.length === 1 ? callees[0] : null;
6304
- if (!chosen) return null;
6305
- let node = chosen.target;
6306
- const seen = /* @__PURE__ */ new Set([boundaryNode, node]);
6307
- for (let depth = 0; depth < ROOT_CAUSE_MAX_DEPTH; depth++) {
6308
- const next = declaredOutboundCallees(graph, node);
6309
- if (next.length !== 1 || seen.has(next[0].target)) break;
6310
- node = next[0].target;
6311
- seen.add(node);
6357
+ return chosen ? chosen.target : null;
6358
+ }
6359
+ function observedOutboundNextServices(graph, nodeId) {
6360
+ const targets = /* @__PURE__ */ new Set();
6361
+ for (const n of nodeScope(graph, nodeId)) {
6362
+ if (!graph.hasNode(n)) continue;
6363
+ for (const edgeId of graph.outboundEdges(n)) {
6364
+ const e = graph.getEdgeAttributes(edgeId);
6365
+ if (!DEP_EDGE_TYPES.has(e.type)) continue;
6366
+ if (e.provenance !== Provenance6.OBSERVED) continue;
6367
+ if (e.target !== nodeId) targets.add(e.target);
6368
+ }
6369
+ }
6370
+ return [...targets];
6371
+ }
6372
+ function resolveHangHop(graph, boundaryNode, incidents) {
6373
+ const route = boundaryIncidentRoute(boundaryNode, incidents);
6374
+ const own = firstDeclaredCallee(graph, boundaryNode, route);
6375
+ if (own) {
6376
+ return route !== void 0 ? { source: boundaryNode, target: own, route } : { source: boundaryNode, target: own };
6377
+ }
6378
+ const resolved = observedOutboundNextServices(graph, boundaryNode).map((n) => ({ source: n, target: firstDeclaredCallee(graph, n, route) })).filter((r) => r.target !== null);
6379
+ if (resolved.length === 1) {
6380
+ const hop = resolved[0];
6381
+ return route !== void 0 ? { ...hop, route } : hop;
6312
6382
  }
6313
- return route !== void 0 ? { node, route } : { node };
6383
+ return null;
6384
+ }
6385
+ function stagedHangProposal(graph, boundaryNode, incidents) {
6386
+ const hop = resolveHangHop(graph, boundaryNode, incidents);
6387
+ if (!hop) return null;
6388
+ if (!graph.hasEdge(frontierEdgeId2(hop.source, hop.target, EdgeType6.CALLS))) return null;
6389
+ return hop.route !== void 0 ? { node: hop.target, route: hop.route } : { node: hop.target };
6314
6390
  }
6315
6391
  function enrichWithNavigation(graph, errorNodeId, tagged, incidents, now) {
6316
6392
  const legacy = tagged.result;
@@ -6345,29 +6421,39 @@ function enrichWithNavigation(graph, errorNodeId, tagged, incidents, now) {
6345
6421
  confidence: Math.min(legacy.confidence, 0.4),
6346
6422
  ...lastProv ? { provenance: lastProv } : {}
6347
6423
  });
6424
+ } else if (seedCtx && isUnreachableSeed(seedCtx)) {
6425
+ const name = displayNameOf(seedNode);
6426
+ candidates.push({
6427
+ node: seedNode,
6428
+ classification: "unreachable",
6429
+ reason: `${name} is unreachable: its callers' requests fail (${seedCtx.errorsFromCallers} erroring inbound calls) and it produced no telemetry of its own \u2014 no server spans, no outbound calls \u2014 so it never served. The failure is observed, but its cause is not in the trace: a startup failure, a crash before the first span, or an unschedulable / unhealthy pod. Inspect ${name}'s deploy state and logs \u2014 there is no code fault to find in the graph here.`,
6430
+ context: seedCtx,
6431
+ confidence: legacy.confidence,
6432
+ provenance: Provenance6.OBSERVED
6433
+ });
6348
6434
  } else if (seedCtx && isBoundaryTimeoutSymptom(seedCtx)) {
6349
- const pointer = structuralUpstreamPointer(graph, seedNode, incidents);
6350
6435
  const seedName = displayNameOf(seedNode);
6351
- const routeNote = pointer?.route ? ` serving ${pointer.route}` : "";
6352
- if (pointer) {
6353
- const causeName = displayNameOf(pointer.node);
6354
- candidates.push({
6355
- node: pointer.node,
6356
- classification: "primary-failure",
6357
- 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.`,
6358
- context: nodeContext(graph, pointer.node, incidents, now),
6359
- confidence: Math.min(legacy.confidence, PROVENANCE_CEILING.EXTRACTED),
6360
- provenance: Provenance6.INFERRED
6361
- });
6362
- }
6436
+ const proposal = stagedHangProposal(graph, seedNode, incidents);
6437
+ const routeNote = proposal?.route ? ` serving ${proposal.route}` : "";
6363
6438
  candidates.push({
6364
6439
  node: seedNode,
6365
6440
  classification: "symptom-only",
6366
- 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.`,
6441
+ reason: proposal ? `${seedName} timed out waiting on a downstream that hung and exported no span \u2014 a boundary reporting an upstream fault, not the fault itself. The cause is unobservable; NEAT proposes the staged FRONTIER surface below, a hypothesis to confirm, not an observed cause.` : `${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 FRONTIER surface${routeNote} is staged, so no cause is proposed; inspect ${seedName}'s declared downstream and restore instrumentation.`,
6367
6442
  context: seedCtx,
6368
6443
  confidence: Math.min(legacy.confidence, 0.3),
6369
6444
  ...lastProv ? { provenance: lastProv } : {}
6370
6445
  });
6446
+ if (proposal) {
6447
+ const causeName = displayNameOf(proposal.node);
6448
+ candidates.push({
6449
+ node: proposal.node,
6450
+ classification: "primary-failure",
6451
+ reason: `${causeName} is the proposed hang cause (FRONTIER \u2014 a hypothesis, not observed): the boundary ${seedName} only timed out waiting and the culprit hung without exporting a span, so NEAT staged a FRONTIER surface on the unobservable hop${routeNote}. It graduates to OBSERVED when ${causeName} comes back; until then, inspect it / restore instrumentation to confirm, or it is culled.`,
6452
+ context: nodeContext(graph, proposal.node, incidents, now),
6453
+ confidence: Math.min(legacy.confidence, PROVENANCE_CEILING.FRONTIER),
6454
+ provenance: Provenance6.FRONTIER
6455
+ });
6456
+ }
6371
6457
  } else if (staleChain) {
6372
6458
  const culprit = staleChain.culprit;
6373
6459
  const culpritName = displayNameOf(culprit);
@@ -6431,6 +6517,9 @@ function fixRecommendationForTop(top, seedNode, legacy) {
6431
6517
  return legacy.fixRecommendation;
6432
6518
  }
6433
6519
  const name = top.node.replace(/^service:/, "");
6520
+ if (top.classification === "symptom-only" && top.context.boundaryTimeout === true) {
6521
+ return `${name} timed out waiting on a downstream that hung and exported no span \u2014 the cause is unobservable from traces. Inspect the FRONTIER surface NEAT staged on the unobservable hop (see candidates); it graduates to OBSERVED when that service recovers. Restore instrumentation on that path to confirm, rather than treating ${name} as the fault.`;
6522
+ }
6434
6523
  if (top.provenance === Provenance6.STALE) {
6435
6524
  return `Live telemetry for this path has gone quiet; the last-observed topology traces the failure downstream to ${name}. Restore instrumentation (or re-run with live traces) to confirm, then inspect ${name}.`;
6436
6525
  }
@@ -15708,6 +15797,25 @@ function detectColumnDrift(node) {
15708
15797
  }
15709
15798
  return out;
15710
15799
  }
15800
+ var RECOMMENDATION_DEPLOY_IMAGE_MISMATCH = "The running image differs from the manifest-declared image \u2014 the rollout has not taken (the old ReplicaSet is still serving). Re-apply the deployment or investigate why the new image failed to roll out.";
15801
+ var DEPLOY_DIVERGENCE_CONFIDENCE = 0.9;
15802
+ function detectDeployDivergence(svc) {
15803
+ const out = [];
15804
+ if (typeof svc.declaredImage === "string" && typeof svc.observedImage === "string" && svc.declaredImage !== svc.observedImage) {
15805
+ out.push({
15806
+ type: "deploy-mismatch",
15807
+ kind: "image",
15808
+ source: svc.id,
15809
+ target: svc.id,
15810
+ declaredImage: svc.declaredImage,
15811
+ observedImage: svc.observedImage,
15812
+ confidence: DEPLOY_DIVERGENCE_CONFIDENCE,
15813
+ reason: `Service ${svc.name} declares image ${svc.declaredImage} but its running pods report ${svc.observedImage} \u2014 the deploy has not taken (the old version is still serving), so no incident fires.`,
15814
+ recommendation: RECOMMENDATION_DEPLOY_IMAGE_MISMATCH
15815
+ });
15816
+ }
15817
+ return out;
15818
+ }
15711
15819
  var SYMBOL_MISMATCH_PATTERNS = [
15712
15820
  {
15713
15821
  // "'ListProductsResponse' object has no attribute 'products_list'" and kin.
@@ -16035,6 +16143,7 @@ function computeDivergences(graph, opts = {}) {
16035
16143
  const svc = n;
16036
16144
  for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d);
16037
16145
  for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d);
16146
+ for (const d of detectDeployDivergence(svc)) all.push(d);
16038
16147
  return;
16039
16148
  }
16040
16149
  if (n.type === NodeType30.InfraNode && n.kind === "sql-table") {
@@ -16075,7 +16184,12 @@ function computeDivergences(graph, opts = {}) {
16075
16184
  // orders last so at equal confidence the structural and symbol divergences
16076
16185
  // lead, per the contract ("rank below the definitive structural and symbol
16077
16186
  // divergences").
16078
- "observed-failing": 6
16187
+ "observed-failing": 6,
16188
+ // Deploy mismatch (ADR-225) is a definitive structural declared-vs-observed
16189
+ // divergence carrying high confidence (0.9), so the confidence sort already
16190
+ // places it among the structural leaders; this slot only breaks an exact
16191
+ // confidence tie and sits last as a stable tiebreaker.
16192
+ "deploy-mismatch": 7
16079
16193
  };
16080
16194
  filtered.sort((a, b) => {
16081
16195
  if (b.confidence !== a.confidence) return b.confidence - a.confidence;
@@ -18378,6 +18492,11 @@ async function runConnectorPoll(connector, ctx, graph, resolveTarget) {
18378
18492
  unresolved++;
18379
18493
  continue;
18380
18494
  }
18495
+ if (signal.deployState) {
18496
+ ensureServiceNode(graph, resolved.serviceName, NO_ENV);
18497
+ mergeObservedDeployState(graph, resolved.targetNodeId, signal.deployState);
18498
+ continue;
18499
+ }
18381
18500
  if (signal.incident) {
18382
18501
  ensureServiceNode(graph, resolved.serviceName, NO_ENV);
18383
18502
  if (!ctx.errorsPath || !graph.hasNode(resolved.targetNodeId)) {
@@ -22654,7 +22773,10 @@ export {
22654
22773
  attachGraphToEventBus,
22655
22774
  confidenceForEdge,
22656
22775
  getBlastRadius,
22776
+ nodeContext,
22777
+ isBoundaryTimeoutSymptom,
22657
22778
  getRootCause,
22779
+ resolveHangHop,
22658
22780
  evaluateAllPolicies,
22659
22781
  loadPolicyFile,
22660
22782
  PolicyViolationsLog,
@@ -22669,6 +22791,8 @@ export {
22669
22791
  makeErrorSpanWriter,
22670
22792
  handleSpan,
22671
22793
  promoteFrontierNodes,
22794
+ stageFrontierEdge,
22795
+ promoteFrontierEdges,
22672
22796
  makeSpanHandler,
22673
22797
  markStaleEdges,
22674
22798
  readStaleEvents,
@@ -22733,4 +22857,4 @@ export {
22733
22857
  deprovisionConnector,
22734
22858
  buildApi
22735
22859
  };
22736
- //# sourceMappingURL=chunk-RBZNXA5L.js.map
22860
+ //# sourceMappingURL=chunk-SSLPBQWY.js.map