@neat.is/core 0.9.7-dev.20260827 → 0.9.7

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/index.cjs CHANGED
@@ -16835,6 +16835,139 @@ function detectSymbolMismatches(graph, incidents) {
16835
16835
  }
16836
16836
  return out;
16837
16837
  }
16838
+ var OBSERVED_FAILING_ERROR_RATE = 0.5;
16839
+ var OBSERVED_FAILING_MIN_SPANS = 5;
16840
+ var OBSERVED_FAILING_CONFIDENCE = 0.6;
16841
+ function detectObservedFailingEdge(graph, bucket) {
16842
+ if (!bucket.extracted || !bucket.observed) return [];
16843
+ if (!OBSERVABLE_EDGE_TYPES.has(bucket.type)) return [];
16844
+ if (bucket.observed.provenance !== import_types58.Provenance.OBSERVED) return [];
16845
+ const signal = bucket.observed.signal;
16846
+ if (!signal) return [];
16847
+ const { spanCount, errorCount } = signal;
16848
+ if (spanCount < OBSERVED_FAILING_MIN_SPANS) return [];
16849
+ const errorRate = errorCount / spanCount;
16850
+ if (errorRate < OBSERVED_FAILING_ERROR_RATE) return [];
16851
+ const pct = Math.round(errorRate * 100);
16852
+ return [
16853
+ {
16854
+ type: "observed-failing",
16855
+ source: bucket.source,
16856
+ target: bucket.target,
16857
+ failureKind: "error-rate",
16858
+ provenance: import_types58.Provenance.INFERRED,
16859
+ edgeType: bucket.type,
16860
+ observed: bucket.observed,
16861
+ spanCount,
16862
+ errorCount,
16863
+ errorRate: clampConfidence(errorRate),
16864
+ confidence: OBSERVED_FAILING_CONFIDENCE,
16865
+ reason: `Code declares ${bucket.source} \u2192 ${bucket.target} (${bucket.type}) and production observes it, but ${errorCount}/${spanCount} observed calls fail (${pct}% error rate) \u2014 the declared dependency is predominantly failing. The declared intent (EXTRACTED) and the observed behaviour (OBSERVED) diverge.`,
16866
+ recommendation: "Treat this as a broken declared dependency, not a coverage gap: production runs the call the code declares and most calls error. Check the dependency\u2019s health, recent deploys, and the observed error responses on this edge."
16867
+ }
16868
+ ];
16869
+ }
16870
+ var OBSERVED_FAILURE_PATTERNS = [
16871
+ {
16872
+ kind: "connection-refused",
16873
+ patterns: [/\bECONNREFUSED\b/i, /\bconnection refused\b/i]
16874
+ },
16875
+ {
16876
+ kind: "deadline-exceeded",
16877
+ patterns: [/\bDEADLINE_EXCEEDED\b/i, /\bdeadline exceeded\b/i]
16878
+ },
16879
+ {
16880
+ kind: "timeout",
16881
+ patterns: [/\bETIMEDOUT\b/i, /\btimed[\s-]?out\b/i, /\btimeout\b/i]
16882
+ },
16883
+ {
16884
+ kind: "unavailable",
16885
+ patterns: [
16886
+ /\bUNAVAILABLE\b/i,
16887
+ /\bservice unavailable\b/i,
16888
+ /\bECONNRESET\b/i,
16889
+ /\bconnection reset\b/i,
16890
+ /\bno healthy upstream\b/i
16891
+ ]
16892
+ }
16893
+ ];
16894
+ function classifyObservedFailure(ev) {
16895
+ const haystack = [ev.errorType, ev.exceptionType, ev.errorMessage].filter((s) => typeof s === "string").join(" \n ");
16896
+ for (const entry of OBSERVED_FAILURE_PATTERNS) {
16897
+ for (const re of entry.patterns) {
16898
+ if (re.test(haystack)) return entry.kind;
16899
+ }
16900
+ }
16901
+ const code = ev.httpStatusCode;
16902
+ if (typeof code === "number" && code >= 500 && code < 600) return "server-error";
16903
+ return null;
16904
+ }
16905
+ function observedFailureLabel(kind) {
16906
+ switch (kind) {
16907
+ case "error-rate":
16908
+ return "a high error rate";
16909
+ case "connection-refused":
16910
+ return "a refused connection";
16911
+ case "deadline-exceeded":
16912
+ return "a deadline exceeded";
16913
+ case "timeout":
16914
+ return "a timeout";
16915
+ case "unavailable":
16916
+ return "an unavailable or reset connection";
16917
+ case "server-error":
16918
+ return "a server error (5xx)";
16919
+ }
16920
+ }
16921
+ function detectObservedFailingIncidents(graph, incidents) {
16922
+ const groups = /* @__PURE__ */ new Map();
16923
+ for (const ev of incidents) {
16924
+ const kind = classifyObservedFailure(ev);
16925
+ if (!kind) continue;
16926
+ const locus = symbolLocus(graph, ev);
16927
+ if (!locus) continue;
16928
+ const key = `${locus.node}|${kind}`;
16929
+ const existing = groups.get(key);
16930
+ if (!existing) {
16931
+ groups.set(key, {
16932
+ node: locus.node,
16933
+ kind,
16934
+ ...locus.location ? { location: locus.location } : {},
16935
+ latest: ev,
16936
+ count: 1,
16937
+ ...typeof ev.httpStatusCode === "number" ? { httpStatusCode: ev.httpStatusCode } : {}
16938
+ });
16939
+ } else {
16940
+ existing.count += 1;
16941
+ if (ev.timestamp.localeCompare(existing.latest.timestamp) > 0) {
16942
+ existing.latest = ev;
16943
+ if (locus.location) existing.location = locus.location;
16944
+ if (typeof ev.httpStatusCode === "number") existing.httpStatusCode = ev.httpStatusCode;
16945
+ }
16946
+ }
16947
+ }
16948
+ const out = [];
16949
+ for (const g of groups.values()) {
16950
+ const where = g.location ? ` at ${g.location}` : "";
16951
+ const label = observedFailureLabel(g.kind);
16952
+ const times = g.count > 1 ? ` (${g.count} recorded incidents)` : " (1 recorded incident)";
16953
+ out.push({
16954
+ type: "observed-failing",
16955
+ source: g.node,
16956
+ target: g.node,
16957
+ failureKind: g.kind,
16958
+ provenance: import_types58.Provenance.INFERRED,
16959
+ ...g.location ? { location: g.location } : {},
16960
+ incidentId: g.latest.id,
16961
+ errorMessage: g.latest.errorMessage,
16962
+ incidentCount: g.count,
16963
+ ...typeof g.httpStatusCode === "number" ? { httpStatusCode: g.httpStatusCode } : {},
16964
+ confidence: OBSERVED_FAILING_CONFIDENCE,
16965
+ reason: `Code${where} declares an external call that production observes failing \u2014 ${g.latest.service} recorded ${label}: "${g.latest.errorMessage}"${times}. The declared call (EXTRACTED) and the observed failure (OBSERVED) diverge \u2014 the dependency is reached and does not work.`,
16966
+ recommendation: `The declared call is running in production and failing at the transport or response level (${label}). Check the target host/endpoint the code reaches, connectivity, and the call\u2019s deadline \u2014 a wrong or unreachable host and an exceeded deadline both land here.`
16967
+ });
16968
+ }
16969
+ return out;
16970
+ }
16838
16971
  function involvesNode(d, nodeId) {
16839
16972
  return d.source === nodeId || d.target === nodeId;
16840
16973
  }
@@ -16907,6 +17040,7 @@ function computeDivergences(graph, opts = {}) {
16907
17040
  const buckets2 = bucketEdges(graph);
16908
17041
  for (const bucket of buckets2.values()) {
16909
17042
  for (const d of detectMissingDivergences(graph, bucket)) all.push(d);
17043
+ for (const d of detectObservedFailingEdge(graph, bucket)) all.push(d);
16910
17044
  }
16911
17045
  graph.forEachNode((nodeId, attrs) => {
16912
17046
  const n = attrs;
@@ -16922,6 +17056,7 @@ function computeDivergences(graph, opts = {}) {
16922
17056
  });
16923
17057
  if (opts.incidents && opts.incidents.length > 0) {
16924
17058
  for (const d of detectSymbolMismatches(graph, opts.incidents)) all.push(d);
17059
+ for (const d of detectObservedFailingIncidents(graph, opts.incidents)) all.push(d);
16925
17060
  }
16926
17061
  const reconciled = suppressHostMismatchHalves(all);
16927
17062
  const dampened = dampenDeadCodeProbes(graph, buckets2, reconciled);
@@ -16948,7 +17083,12 @@ function computeDivergences(graph, opts = {}) {
16948
17083
  // type; this only breaks a confidence tie, and it orders last so a same-
16949
17084
  // confidence edge finding leads. In practice it carries the INFERRED grade
16950
17085
  // (0.6), so it sits below the high-confidence edge divergences already.
16951
- "observed-symbol-mismatch": 5
17086
+ "observed-symbol-mismatch": 5,
17087
+ // Behavioral-failure (ADR-220) also carries the INFERRED grade (0.6); it
17088
+ // orders last so at equal confidence the structural and symbol divergences
17089
+ // lead, per the contract ("rank below the definitive structural and symbol
17090
+ // divergences").
17091
+ "observed-failing": 6
16952
17092
  };
16953
17093
  filtered.sort((a, b) => {
16954
17094
  if (b.confidence !== a.confidence) return b.confidence - a.confidence;
@@ -16962,7 +17102,13 @@ function computeDivergences(graph, opts = {}) {
16962
17102
  if (ac !== bc) return ac.localeCompare(bc);
16963
17103
  const asym = "symbol" in a && a.symbol ? a.symbol : "";
16964
17104
  const bsym = "symbol" in b && b.symbol ? b.symbol : "";
16965
- return asym.localeCompare(bsym);
17105
+ if (asym !== bsym) return asym.localeCompare(bsym);
17106
+ const afk = "failureKind" in a && a.failureKind ? a.failureKind : "";
17107
+ const bfk = "failureKind" in b && b.failureKind ? b.failureKind : "";
17108
+ if (afk !== bfk) return afk.localeCompare(bfk);
17109
+ const aloc = "location" in a && a.location ? a.location : "";
17110
+ const bloc = "location" in b && b.location ? b.location : "";
17111
+ return aloc.localeCompare(bloc);
16966
17112
  });
16967
17113
  return import_types58.DivergenceResultSchema.parse({
16968
17114
  divergences: filtered,
@@ -17394,6 +17540,10 @@ function divergenceLine(d) {
17394
17540
  const member = d.symbol ? ` ${d.symbol}` : "";
17395
17541
  return `[${d.type}] ${d.source}${member}${at} \u2014 ${d.reason}`;
17396
17542
  }
17543
+ if (d.type === "observed-failing" && !d.edgeType) {
17544
+ const at = d.location ? ` at ${d.location}` : "";
17545
+ return `[${d.type}] ${d.source}${at} \u2014 ${d.reason}`;
17546
+ }
17397
17547
  return `[${d.type}] ${d.source} \u2192 ${d.target} \u2014 ${d.reason}`;
17398
17548
  }
17399
17549
  function buildDivergenceSection(graph, node, incidents) {