@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/{chunk-XYAZOGEX.js → chunk-JSUPWMH3.js} +2 -2
- package/dist/{chunk-XOGTJVUM.js → chunk-KZBFP7L6.js} +153 -3
- package/dist/{chunk-XOGTJVUM.js.map → chunk-KZBFP7L6.js.map} +1 -1
- package/dist/cli.cjs +171 -2
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +21 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +152 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +152 -2
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +152 -2
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- /package/dist/{chunk-XYAZOGEX.js.map → chunk-JSUPWMH3.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-JSUPWMH3.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-KZBFP7L6.js";
|
|
41
41
|
import {
|
|
42
42
|
startOtelGrpcReceiver
|
|
43
43
|
} from "./chunk-ERE47MCR.js";
|
package/dist/neatd.cjs
CHANGED
|
@@ -16847,6 +16847,139 @@ function detectSymbolMismatches(graph, incidents) {
|
|
|
16847
16847
|
}
|
|
16848
16848
|
return out;
|
|
16849
16849
|
}
|
|
16850
|
+
var OBSERVED_FAILING_ERROR_RATE = 0.5;
|
|
16851
|
+
var OBSERVED_FAILING_MIN_SPANS = 5;
|
|
16852
|
+
var OBSERVED_FAILING_CONFIDENCE = 0.6;
|
|
16853
|
+
function detectObservedFailingEdge(graph, bucket) {
|
|
16854
|
+
if (!bucket.extracted || !bucket.observed) return [];
|
|
16855
|
+
if (!OBSERVABLE_EDGE_TYPES.has(bucket.type)) return [];
|
|
16856
|
+
if (bucket.observed.provenance !== import_types58.Provenance.OBSERVED) return [];
|
|
16857
|
+
const signal = bucket.observed.signal;
|
|
16858
|
+
if (!signal) return [];
|
|
16859
|
+
const { spanCount, errorCount } = signal;
|
|
16860
|
+
if (spanCount < OBSERVED_FAILING_MIN_SPANS) return [];
|
|
16861
|
+
const errorRate = errorCount / spanCount;
|
|
16862
|
+
if (errorRate < OBSERVED_FAILING_ERROR_RATE) return [];
|
|
16863
|
+
const pct = Math.round(errorRate * 100);
|
|
16864
|
+
return [
|
|
16865
|
+
{
|
|
16866
|
+
type: "observed-failing",
|
|
16867
|
+
source: bucket.source,
|
|
16868
|
+
target: bucket.target,
|
|
16869
|
+
failureKind: "error-rate",
|
|
16870
|
+
provenance: import_types58.Provenance.INFERRED,
|
|
16871
|
+
edgeType: bucket.type,
|
|
16872
|
+
observed: bucket.observed,
|
|
16873
|
+
spanCount,
|
|
16874
|
+
errorCount,
|
|
16875
|
+
errorRate: clampConfidence(errorRate),
|
|
16876
|
+
confidence: OBSERVED_FAILING_CONFIDENCE,
|
|
16877
|
+
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.`,
|
|
16878
|
+
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."
|
|
16879
|
+
}
|
|
16880
|
+
];
|
|
16881
|
+
}
|
|
16882
|
+
var OBSERVED_FAILURE_PATTERNS = [
|
|
16883
|
+
{
|
|
16884
|
+
kind: "connection-refused",
|
|
16885
|
+
patterns: [/\bECONNREFUSED\b/i, /\bconnection refused\b/i]
|
|
16886
|
+
},
|
|
16887
|
+
{
|
|
16888
|
+
kind: "deadline-exceeded",
|
|
16889
|
+
patterns: [/\bDEADLINE_EXCEEDED\b/i, /\bdeadline exceeded\b/i]
|
|
16890
|
+
},
|
|
16891
|
+
{
|
|
16892
|
+
kind: "timeout",
|
|
16893
|
+
patterns: [/\bETIMEDOUT\b/i, /\btimed[\s-]?out\b/i, /\btimeout\b/i]
|
|
16894
|
+
},
|
|
16895
|
+
{
|
|
16896
|
+
kind: "unavailable",
|
|
16897
|
+
patterns: [
|
|
16898
|
+
/\bUNAVAILABLE\b/i,
|
|
16899
|
+
/\bservice unavailable\b/i,
|
|
16900
|
+
/\bECONNRESET\b/i,
|
|
16901
|
+
/\bconnection reset\b/i,
|
|
16902
|
+
/\bno healthy upstream\b/i
|
|
16903
|
+
]
|
|
16904
|
+
}
|
|
16905
|
+
];
|
|
16906
|
+
function classifyObservedFailure(ev) {
|
|
16907
|
+
const haystack = [ev.errorType, ev.exceptionType, ev.errorMessage].filter((s) => typeof s === "string").join(" \n ");
|
|
16908
|
+
for (const entry2 of OBSERVED_FAILURE_PATTERNS) {
|
|
16909
|
+
for (const re of entry2.patterns) {
|
|
16910
|
+
if (re.test(haystack)) return entry2.kind;
|
|
16911
|
+
}
|
|
16912
|
+
}
|
|
16913
|
+
const code = ev.httpStatusCode;
|
|
16914
|
+
if (typeof code === "number" && code >= 500 && code < 600) return "server-error";
|
|
16915
|
+
return null;
|
|
16916
|
+
}
|
|
16917
|
+
function observedFailureLabel(kind) {
|
|
16918
|
+
switch (kind) {
|
|
16919
|
+
case "error-rate":
|
|
16920
|
+
return "a high error rate";
|
|
16921
|
+
case "connection-refused":
|
|
16922
|
+
return "a refused connection";
|
|
16923
|
+
case "deadline-exceeded":
|
|
16924
|
+
return "a deadline exceeded";
|
|
16925
|
+
case "timeout":
|
|
16926
|
+
return "a timeout";
|
|
16927
|
+
case "unavailable":
|
|
16928
|
+
return "an unavailable or reset connection";
|
|
16929
|
+
case "server-error":
|
|
16930
|
+
return "a server error (5xx)";
|
|
16931
|
+
}
|
|
16932
|
+
}
|
|
16933
|
+
function detectObservedFailingIncidents(graph, incidents) {
|
|
16934
|
+
const groups = /* @__PURE__ */ new Map();
|
|
16935
|
+
for (const ev of incidents) {
|
|
16936
|
+
const kind = classifyObservedFailure(ev);
|
|
16937
|
+
if (!kind) continue;
|
|
16938
|
+
const locus = symbolLocus(graph, ev);
|
|
16939
|
+
if (!locus) continue;
|
|
16940
|
+
const key = `${locus.node}|${kind}`;
|
|
16941
|
+
const existing = groups.get(key);
|
|
16942
|
+
if (!existing) {
|
|
16943
|
+
groups.set(key, {
|
|
16944
|
+
node: locus.node,
|
|
16945
|
+
kind,
|
|
16946
|
+
...locus.location ? { location: locus.location } : {},
|
|
16947
|
+
latest: ev,
|
|
16948
|
+
count: 1,
|
|
16949
|
+
...typeof ev.httpStatusCode === "number" ? { httpStatusCode: ev.httpStatusCode } : {}
|
|
16950
|
+
});
|
|
16951
|
+
} else {
|
|
16952
|
+
existing.count += 1;
|
|
16953
|
+
if (ev.timestamp.localeCompare(existing.latest.timestamp) > 0) {
|
|
16954
|
+
existing.latest = ev;
|
|
16955
|
+
if (locus.location) existing.location = locus.location;
|
|
16956
|
+
if (typeof ev.httpStatusCode === "number") existing.httpStatusCode = ev.httpStatusCode;
|
|
16957
|
+
}
|
|
16958
|
+
}
|
|
16959
|
+
}
|
|
16960
|
+
const out = [];
|
|
16961
|
+
for (const g of groups.values()) {
|
|
16962
|
+
const where = g.location ? ` at ${g.location}` : "";
|
|
16963
|
+
const label = observedFailureLabel(g.kind);
|
|
16964
|
+
const times = g.count > 1 ? ` (${g.count} recorded incidents)` : " (1 recorded incident)";
|
|
16965
|
+
out.push({
|
|
16966
|
+
type: "observed-failing",
|
|
16967
|
+
source: g.node,
|
|
16968
|
+
target: g.node,
|
|
16969
|
+
failureKind: g.kind,
|
|
16970
|
+
provenance: import_types58.Provenance.INFERRED,
|
|
16971
|
+
...g.location ? { location: g.location } : {},
|
|
16972
|
+
incidentId: g.latest.id,
|
|
16973
|
+
errorMessage: g.latest.errorMessage,
|
|
16974
|
+
incidentCount: g.count,
|
|
16975
|
+
...typeof g.httpStatusCode === "number" ? { httpStatusCode: g.httpStatusCode } : {},
|
|
16976
|
+
confidence: OBSERVED_FAILING_CONFIDENCE,
|
|
16977
|
+
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.`,
|
|
16978
|
+
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.`
|
|
16979
|
+
});
|
|
16980
|
+
}
|
|
16981
|
+
return out;
|
|
16982
|
+
}
|
|
16850
16983
|
function involvesNode(d, nodeId) {
|
|
16851
16984
|
return d.source === nodeId || d.target === nodeId;
|
|
16852
16985
|
}
|
|
@@ -16919,6 +17052,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
16919
17052
|
const buckets2 = bucketEdges(graph);
|
|
16920
17053
|
for (const bucket of buckets2.values()) {
|
|
16921
17054
|
for (const d of detectMissingDivergences(graph, bucket)) all.push(d);
|
|
17055
|
+
for (const d of detectObservedFailingEdge(graph, bucket)) all.push(d);
|
|
16922
17056
|
}
|
|
16923
17057
|
graph.forEachNode((nodeId, attrs) => {
|
|
16924
17058
|
const n = attrs;
|
|
@@ -16934,6 +17068,7 @@ function computeDivergences(graph, opts = {}) {
|
|
|
16934
17068
|
});
|
|
16935
17069
|
if (opts.incidents && opts.incidents.length > 0) {
|
|
16936
17070
|
for (const d of detectSymbolMismatches(graph, opts.incidents)) all.push(d);
|
|
17071
|
+
for (const d of detectObservedFailingIncidents(graph, opts.incidents)) all.push(d);
|
|
16937
17072
|
}
|
|
16938
17073
|
const reconciled = suppressHostMismatchHalves(all);
|
|
16939
17074
|
const dampened = dampenDeadCodeProbes(graph, buckets2, reconciled);
|
|
@@ -16960,7 +17095,12 @@ function computeDivergences(graph, opts = {}) {
|
|
|
16960
17095
|
// type; this only breaks a confidence tie, and it orders last so a same-
|
|
16961
17096
|
// confidence edge finding leads. In practice it carries the INFERRED grade
|
|
16962
17097
|
// (0.6), so it sits below the high-confidence edge divergences already.
|
|
16963
|
-
"observed-symbol-mismatch": 5
|
|
17098
|
+
"observed-symbol-mismatch": 5,
|
|
17099
|
+
// Behavioral-failure (ADR-220) also carries the INFERRED grade (0.6); it
|
|
17100
|
+
// orders last so at equal confidence the structural and symbol divergences
|
|
17101
|
+
// lead, per the contract ("rank below the definitive structural and symbol
|
|
17102
|
+
// divergences").
|
|
17103
|
+
"observed-failing": 6
|
|
16964
17104
|
};
|
|
16965
17105
|
filtered.sort((a, b) => {
|
|
16966
17106
|
if (b.confidence !== a.confidence) return b.confidence - a.confidence;
|
|
@@ -16974,7 +17114,13 @@ function computeDivergences(graph, opts = {}) {
|
|
|
16974
17114
|
if (ac !== bc) return ac.localeCompare(bc);
|
|
16975
17115
|
const asym = "symbol" in a && a.symbol ? a.symbol : "";
|
|
16976
17116
|
const bsym = "symbol" in b && b.symbol ? b.symbol : "";
|
|
16977
|
-
return asym.localeCompare(bsym);
|
|
17117
|
+
if (asym !== bsym) return asym.localeCompare(bsym);
|
|
17118
|
+
const afk = "failureKind" in a && a.failureKind ? a.failureKind : "";
|
|
17119
|
+
const bfk = "failureKind" in b && b.failureKind ? b.failureKind : "";
|
|
17120
|
+
if (afk !== bfk) return afk.localeCompare(bfk);
|
|
17121
|
+
const aloc = "location" in a && a.location ? a.location : "";
|
|
17122
|
+
const bloc = "location" in b && b.location ? b.location : "";
|
|
17123
|
+
return aloc.localeCompare(bloc);
|
|
16978
17124
|
});
|
|
16979
17125
|
return import_types58.DivergenceResultSchema.parse({
|
|
16980
17126
|
divergences: filtered,
|
|
@@ -17406,6 +17552,10 @@ function divergenceLine(d) {
|
|
|
17406
17552
|
const member = d.symbol ? ` ${d.symbol}` : "";
|
|
17407
17553
|
return `[${d.type}] ${d.source}${member}${at} \u2014 ${d.reason}`;
|
|
17408
17554
|
}
|
|
17555
|
+
if (d.type === "observed-failing" && !d.edgeType) {
|
|
17556
|
+
const at = d.location ? ` at ${d.location}` : "";
|
|
17557
|
+
return `[${d.type}] ${d.source}${at} \u2014 ${d.reason}`;
|
|
17558
|
+
}
|
|
17409
17559
|
return `[${d.type}] ${d.source} \u2192 ${d.target} \u2014 ${d.reason}`;
|
|
17410
17560
|
}
|
|
17411
17561
|
function buildDivergenceSection(graph, node, incidents) {
|