@neat.is/core 0.9.13 → 0.9.15-dev.20260902
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-BKSM2YLV.js → chunk-NV4WWJSU.js} +45 -5
- package/dist/chunk-NV4WWJSU.js.map +1 -0
- package/dist/{chunk-RL6H3VVD.js → chunk-SSLPBQWY.js} +107 -37
- package/dist/chunk-SSLPBQWY.js.map +1 -0
- package/dist/cli.cjs +156 -58
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +7 -3
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +138 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +138 -41
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +73 -36
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-BKSM2YLV.js.map +0 -1
- package/dist/chunk-RL6H3VVD.js.map +0 -1
package/dist/neatd.js
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
import {
|
|
3
3
|
reconcileDaemonRecordSync,
|
|
4
4
|
startDaemon
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-NV4WWJSU.js";
|
|
6
6
|
import {
|
|
7
7
|
listProjects,
|
|
8
8
|
registryPath
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-SSLPBQWY.js";
|
|
10
10
|
import {
|
|
11
11
|
BindAuthorityError,
|
|
12
12
|
__require
|
package/dist/server.cjs
CHANGED
|
@@ -6231,6 +6231,7 @@ function startStalenessLoop(graph, options = {}) {
|
|
|
6231
6231
|
project: options.project
|
|
6232
6232
|
});
|
|
6233
6233
|
if (options.onPolicyTrigger) await options.onPolicyTrigger(graph);
|
|
6234
|
+
if (options.onReconcile) await options.onReconcile(graph);
|
|
6234
6235
|
} catch (err) {
|
|
6235
6236
|
console.error("staleness tick failed", err);
|
|
6236
6237
|
}
|
|
@@ -6391,13 +6392,19 @@ function resolveOwningService(graph, nodeId) {
|
|
|
6391
6392
|
}
|
|
6392
6393
|
return null;
|
|
6393
6394
|
}
|
|
6395
|
+
function isFrontierEdge(e) {
|
|
6396
|
+
return e.provenance === import_types8.Provenance.FRONTIER;
|
|
6397
|
+
}
|
|
6398
|
+
function rankOf(p) {
|
|
6399
|
+
return p === import_types8.Provenance.FRONTIER ? -1 : import_types8.PROV_RANK[p];
|
|
6400
|
+
}
|
|
6394
6401
|
function bestEdgeBySource(graph, edgeIds) {
|
|
6395
6402
|
const best = /* @__PURE__ */ new Map();
|
|
6396
6403
|
for (const id of edgeIds) {
|
|
6397
6404
|
const e = graph.getEdgeAttributes(id);
|
|
6398
|
-
if (isFrontierNode(graph, e.source)) continue;
|
|
6405
|
+
if (isFrontierNode(graph, e.source) || isFrontierEdge(e)) continue;
|
|
6399
6406
|
const cur = best.get(e.source);
|
|
6400
|
-
if (!cur ||
|
|
6407
|
+
if (!cur || rankOf(e.provenance) > rankOf(cur.provenance)) {
|
|
6401
6408
|
best.set(e.source, e);
|
|
6402
6409
|
}
|
|
6403
6410
|
}
|
|
@@ -6407,9 +6414,9 @@ function bestEdgeByTarget(graph, edgeIds) {
|
|
|
6407
6414
|
const best = /* @__PURE__ */ new Map();
|
|
6408
6415
|
for (const id of edgeIds) {
|
|
6409
6416
|
const e = graph.getEdgeAttributes(id);
|
|
6410
|
-
if (isFrontierNode(graph, e.target)) continue;
|
|
6417
|
+
if (isFrontierNode(graph, e.target) || isFrontierEdge(e)) continue;
|
|
6411
6418
|
const cur = best.get(e.target);
|
|
6412
|
-
if (!cur ||
|
|
6419
|
+
if (!cur || rankOf(e.provenance) > rankOf(cur.provenance)) {
|
|
6413
6420
|
best.set(e.target, e);
|
|
6414
6421
|
}
|
|
6415
6422
|
}
|
|
@@ -6419,7 +6426,10 @@ var PROVENANCE_CEILING = {
|
|
|
6419
6426
|
OBSERVED: 1,
|
|
6420
6427
|
INFERRED: 0.7,
|
|
6421
6428
|
EXTRACTED: 0.5,
|
|
6422
|
-
STALE: 0.3
|
|
6429
|
+
STALE: 0.3,
|
|
6430
|
+
// A FRONTIER surface (ADR-226) is a proposal about a cause NEAT could not observe
|
|
6431
|
+
// — the least-trusted claim it makes, below STALE (which was at least once seen).
|
|
6432
|
+
FRONTIER: 0.2
|
|
6423
6433
|
};
|
|
6424
6434
|
function volumeWeight(spanCount) {
|
|
6425
6435
|
if (!spanCount || spanCount <= 0) return 0.5;
|
|
@@ -6654,7 +6664,7 @@ function rootCauseFromIncidents(nodeId, incidents, errorEvent) {
|
|
|
6654
6664
|
});
|
|
6655
6665
|
}
|
|
6656
6666
|
function isFailingCallEdge(e) {
|
|
6657
|
-
return e.type === import_types8.EdgeType.CALLS && (e.signal?.errorCount ?? 0) > 0;
|
|
6667
|
+
return e.type === import_types8.EdgeType.CALLS && !isFrontierEdge(e) && (e.signal?.errorCount ?? 0) > 0;
|
|
6658
6668
|
}
|
|
6659
6669
|
function callSourcesForService(graph, serviceId17) {
|
|
6660
6670
|
const ids = [serviceId17];
|
|
@@ -6677,8 +6687,8 @@ function failingCallDominates(e, id, curEdge, curId) {
|
|
|
6677
6687
|
const ec = e.signal?.errorCount ?? 0;
|
|
6678
6688
|
const cc = curEdge.signal?.errorCount ?? 0;
|
|
6679
6689
|
if (ec !== cc) return ec > cc;
|
|
6680
|
-
if (
|
|
6681
|
-
return
|
|
6690
|
+
if (rankOf(e.provenance) !== rankOf(curEdge.provenance)) {
|
|
6691
|
+
return rankOf(e.provenance) > rankOf(curEdge.provenance);
|
|
6682
6692
|
}
|
|
6683
6693
|
return id < curId;
|
|
6684
6694
|
}
|
|
@@ -6729,11 +6739,11 @@ function dominantStaleCall(graph, serviceId17, visited) {
|
|
|
6729
6739
|
for (const edgeId of graph.outboundEdges(src)) {
|
|
6730
6740
|
const e = graph.getEdgeAttributes(edgeId);
|
|
6731
6741
|
if (e.type !== import_types8.EdgeType.CALLS) continue;
|
|
6732
|
-
if (isFrontierNode(graph, e.target)) continue;
|
|
6742
|
+
if (isFrontierNode(graph, e.target) || isFrontierEdge(e)) continue;
|
|
6733
6743
|
const owner = resolveOwningService(graph, e.target);
|
|
6734
6744
|
if (!owner || visited.has(owner.id)) continue;
|
|
6735
6745
|
const cur = bestByCallee.get(owner.id);
|
|
6736
|
-
if (!cur ||
|
|
6746
|
+
if (!cur || rankOf(e.provenance) > rankOf(cur.provenance)) {
|
|
6737
6747
|
bestByCallee.set(owner.id, e);
|
|
6738
6748
|
}
|
|
6739
6749
|
}
|
|
@@ -7006,6 +7016,7 @@ function nodeContext(graph, nodeId, incidents, now = Date.now()) {
|
|
|
7006
7016
|
for (const edgeId of graph.inboundEdges(n)) {
|
|
7007
7017
|
const e = graph.getEdgeAttributes(edgeId);
|
|
7008
7018
|
if (e.type === import_types8.EdgeType.CONTAINS) continue;
|
|
7019
|
+
if (isFrontierEdge(e)) continue;
|
|
7009
7020
|
errorsFromCallers += e.signal?.errorCount ?? 0;
|
|
7010
7021
|
inboundVolume += e.callCount ?? e.signal?.spanCount ?? 0;
|
|
7011
7022
|
if (e.provenance === import_types8.Provenance.STALE) stale = true;
|
|
@@ -7019,6 +7030,7 @@ function nodeContext(graph, nodeId, incidents, now = Date.now()) {
|
|
|
7019
7030
|
for (const edgeId of graph.outboundEdges(n)) {
|
|
7020
7031
|
const e = graph.getEdgeAttributes(edgeId);
|
|
7021
7032
|
if (e.type === import_types8.EdgeType.CONTAINS) continue;
|
|
7033
|
+
if (isFrontierEdge(e)) continue;
|
|
7022
7034
|
outboundVolume += e.callCount ?? e.signal?.spanCount ?? 0;
|
|
7023
7035
|
if (e.type === import_types8.EdgeType.CALLS) outboundErrors += e.signal?.errorCount ?? 0;
|
|
7024
7036
|
if (e.provenance === import_types8.Provenance.STALE) stale = true;
|
|
@@ -7302,22 +7314,44 @@ function routeMatches(declared, incident) {
|
|
|
7302
7314
|
const b = normalizeRoute(incident);
|
|
7303
7315
|
return a === b || a.startsWith(b) || b.startsWith(a);
|
|
7304
7316
|
}
|
|
7305
|
-
function
|
|
7306
|
-
const
|
|
7307
|
-
const callees = declaredOutboundCallees(graph, boundaryNode);
|
|
7317
|
+
function firstDeclaredCallee(graph, node, route) {
|
|
7318
|
+
const callees = declaredOutboundCallees(graph, node);
|
|
7308
7319
|
if (callees.length === 0) return null;
|
|
7309
7320
|
const narrowed = route !== void 0 ? callees.filter((c) => c.route !== void 0 && routeMatches(c.route, route)) : callees;
|
|
7310
7321
|
const chosen = narrowed.length === 1 ? narrowed[0] : callees.length === 1 ? callees[0] : null;
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
|
|
7316
|
-
if (
|
|
7317
|
-
|
|
7318
|
-
|
|
7322
|
+
return chosen ? chosen.target : null;
|
|
7323
|
+
}
|
|
7324
|
+
function observedOutboundNextServices(graph, nodeId) {
|
|
7325
|
+
const targets = /* @__PURE__ */ new Set();
|
|
7326
|
+
for (const n of nodeScope(graph, nodeId)) {
|
|
7327
|
+
if (!graph.hasNode(n)) continue;
|
|
7328
|
+
for (const edgeId of graph.outboundEdges(n)) {
|
|
7329
|
+
const e = graph.getEdgeAttributes(edgeId);
|
|
7330
|
+
if (!DEP_EDGE_TYPES.has(e.type)) continue;
|
|
7331
|
+
if (e.provenance !== import_types8.Provenance.OBSERVED) continue;
|
|
7332
|
+
if (e.target !== nodeId) targets.add(e.target);
|
|
7333
|
+
}
|
|
7334
|
+
}
|
|
7335
|
+
return [...targets];
|
|
7336
|
+
}
|
|
7337
|
+
function resolveHangHop(graph, boundaryNode, incidents) {
|
|
7338
|
+
const route = boundaryIncidentRoute(boundaryNode, incidents);
|
|
7339
|
+
const own = firstDeclaredCallee(graph, boundaryNode, route);
|
|
7340
|
+
if (own) {
|
|
7341
|
+
return route !== void 0 ? { source: boundaryNode, target: own, route } : { source: boundaryNode, target: own };
|
|
7342
|
+
}
|
|
7343
|
+
const resolved = observedOutboundNextServices(graph, boundaryNode).map((n) => ({ source: n, target: firstDeclaredCallee(graph, n, route) })).filter((r) => r.target !== null);
|
|
7344
|
+
if (resolved.length === 1) {
|
|
7345
|
+
const hop = resolved[0];
|
|
7346
|
+
return route !== void 0 ? { ...hop, route } : hop;
|
|
7319
7347
|
}
|
|
7320
|
-
return
|
|
7348
|
+
return null;
|
|
7349
|
+
}
|
|
7350
|
+
function stagedHangProposal(graph, boundaryNode, incidents) {
|
|
7351
|
+
const hop = resolveHangHop(graph, boundaryNode, incidents);
|
|
7352
|
+
if (!hop) return null;
|
|
7353
|
+
if (!graph.hasEdge((0, import_types8.frontierEdgeId)(hop.source, hop.target, import_types8.EdgeType.CALLS))) return null;
|
|
7354
|
+
return hop.route !== void 0 ? { node: hop.target, route: hop.route } : { node: hop.target };
|
|
7321
7355
|
}
|
|
7322
7356
|
function enrichWithNavigation(graph, errorNodeId, tagged, incidents, now) {
|
|
7323
7357
|
const legacy = tagged.result;
|
|
@@ -7363,28 +7397,28 @@ function enrichWithNavigation(graph, errorNodeId, tagged, incidents, now) {
|
|
|
7363
7397
|
provenance: import_types8.Provenance.OBSERVED
|
|
7364
7398
|
});
|
|
7365
7399
|
} else if (seedCtx && isBoundaryTimeoutSymptom(seedCtx)) {
|
|
7366
|
-
const pointer = structuralUpstreamPointer(graph, seedNode, incidents);
|
|
7367
7400
|
const seedName = displayNameOf(seedNode);
|
|
7368
|
-
const
|
|
7369
|
-
|
|
7370
|
-
const causeName = displayNameOf(pointer.node);
|
|
7371
|
-
candidates.push({
|
|
7372
|
-
node: pointer.node,
|
|
7373
|
-
classification: "primary-failure",
|
|
7374
|
-
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.`,
|
|
7375
|
-
context: nodeContext(graph, pointer.node, incidents, now),
|
|
7376
|
-
confidence: Math.min(legacy.confidence, PROVENANCE_CEILING.EXTRACTED),
|
|
7377
|
-
provenance: import_types8.Provenance.INFERRED
|
|
7378
|
-
});
|
|
7379
|
-
}
|
|
7401
|
+
const proposal = stagedHangProposal(graph, seedNode, incidents);
|
|
7402
|
+
const routeNote = proposal?.route ? ` serving ${proposal.route}` : "";
|
|
7380
7403
|
candidates.push({
|
|
7381
7404
|
node: seedNode,
|
|
7382
7405
|
classification: "symptom-only",
|
|
7383
|
-
reason:
|
|
7406
|
+
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.`,
|
|
7384
7407
|
context: seedCtx,
|
|
7385
7408
|
confidence: Math.min(legacy.confidence, 0.3),
|
|
7386
7409
|
...lastProv ? { provenance: lastProv } : {}
|
|
7387
7410
|
});
|
|
7411
|
+
if (proposal) {
|
|
7412
|
+
const causeName = displayNameOf(proposal.node);
|
|
7413
|
+
candidates.push({
|
|
7414
|
+
node: proposal.node,
|
|
7415
|
+
classification: "primary-failure",
|
|
7416
|
+
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.`,
|
|
7417
|
+
context: nodeContext(graph, proposal.node, incidents, now),
|
|
7418
|
+
confidence: Math.min(legacy.confidence, PROVENANCE_CEILING.FRONTIER),
|
|
7419
|
+
provenance: import_types8.Provenance.FRONTIER
|
|
7420
|
+
});
|
|
7421
|
+
}
|
|
7388
7422
|
} else if (staleChain) {
|
|
7389
7423
|
const culprit = staleChain.culprit;
|
|
7390
7424
|
const culpritName = displayNameOf(culprit);
|
|
@@ -7448,6 +7482,9 @@ function fixRecommendationForTop(top, seedNode, legacy) {
|
|
|
7448
7482
|
return legacy.fixRecommendation;
|
|
7449
7483
|
}
|
|
7450
7484
|
const name = top.node.replace(/^service:/, "");
|
|
7485
|
+
if (top.classification === "symptom-only" && top.context.boundaryTimeout === true) {
|
|
7486
|
+
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.`;
|
|
7487
|
+
}
|
|
7451
7488
|
if (top.provenance === import_types8.Provenance.STALE) {
|
|
7452
7489
|
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}.`;
|
|
7453
7490
|
}
|