next-leak 0.1.0

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.
@@ -0,0 +1,103 @@
1
+ import { createRequire as __nextLeakCreateRequire } from 'node:module';import { fileURLToPath as __nextLeakFileURLToPath } from 'node:url';import { dirname as __nextLeakDirname } from 'node:path';const require = __nextLeakCreateRequire(import.meta.url);const __filename = __nextLeakFileURLToPath(import.meta.url);const __dirname = __nextLeakDirname(__filename);
2
+
3
+ // src/confidence.ts
4
+ function effectiveVerdict(report) {
5
+ return report.confidence.supersededVerdict ?? report.trend.verdict;
6
+ }
7
+ var VERDICT_WEAKENING = /* @__PURE__ */ new Set([
8
+ "near-threshold",
9
+ "spiky-growth"
10
+ ]);
11
+ function warrantsIssueDraft(report) {
12
+ return effectiveVerdict(report) === "leak" && !report.confidence.warnings.some((warning) => VERDICT_WEAKENING.has(warning.code));
13
+ }
14
+ var DEFAULT_MIN_GROWTH = 256 * 1024;
15
+ var LOAD_COMPLETION_FLOOR = 0.99;
16
+ var ABANDON_EFFECTIVE_FLOOR = 0.9;
17
+ var MID_STREAM_FLOOR = 0.1;
18
+ var SPIKE_RATIO = 4;
19
+ var NOISE_FLOOR_MULTIPLE = 2;
20
+ var mb = (bytes) => `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
21
+ var pct = (part, whole) => `${(part / whole * 100).toFixed(1)}%`;
22
+ function assessConfidence(input) {
23
+ const warnings = [];
24
+ const minGrowth = input.minGrowthPerCycle ?? DEFAULT_MIN_GROWTH;
25
+ const isLeak = input.trend.verdict === "leak";
26
+ const moving = input.settleOutcomes.filter((outcome) => outcome.status === "moving");
27
+ if (moving.length > 0) {
28
+ const phases = moving.map((outcome) => outcome.phase).join(", ");
29
+ warnings.push({
30
+ code: "unsettled",
31
+ detail: `the heap never held steady before sampling on ${phases} \u2014 raise --idle-ms so post-load transients finish draining`
32
+ });
33
+ }
34
+ const unverified = input.settleOutcomes.filter((outcome) => outcome.status === "unknown");
35
+ if (unverified.length > 0) {
36
+ const phases = unverified.map((outcome) => outcome.phase).join(", ");
37
+ warnings.push({
38
+ code: "settle-unverified",
39
+ detail: `the idle budget was too short to check whether the heap had settled on ${phases} \u2014 the samples may include post-load transients`
40
+ });
41
+ }
42
+ for (const outcome of input.loadOutcomes) {
43
+ if (input.abandonAfterMs !== void 0) {
44
+ const abandoned = outcome.abandoned ?? 0;
45
+ if (outcome.sent > 0 && abandoned < outcome.sent * ABANDON_EFFECTIVE_FLOOR) {
46
+ warnings.push({
47
+ code: "abandon-ineffective",
48
+ detail: `${outcome.phase} disconnected early on only ${abandoned} of ${outcome.sent} requests (${pct(abandoned, outcome.sent)}) \u2014 the early-disconnect path was largely not exercised`
49
+ });
50
+ continue;
51
+ }
52
+ const midStream = outcome.abandonedMidStream ?? 0;
53
+ if (abandoned > 0 && midStream < abandoned * MID_STREAM_FLOOR) {
54
+ warnings.push({
55
+ code: "abandon-before-response",
56
+ detail: `${outcome.phase} cut ${abandoned} requests before the server sent anything (${midStream} mid-stream) \u2014 this tested pre-response disconnects, not mid-stream teardown; raise abandonAfterMs above the route's time-to-first-byte`
57
+ });
58
+ }
59
+ continue;
60
+ }
61
+ const landed = outcome.ok2xx ?? 0;
62
+ if (outcome.sent > 0 && landed < outcome.sent * LOAD_COMPLETION_FLOOR) {
63
+ warnings.push({
64
+ code: "load-incomplete",
65
+ detail: `${outcome.phase} landed ${landed} of ${outcome.sent} requests (${pct(landed, outcome.sent)}) \u2014 the route saw less traffic than reported`
66
+ });
67
+ }
68
+ }
69
+ const deltas = input.trend.deltas;
70
+ if ((isLeak || input.trend.verdict === "inconclusive") && deltas.length >= 2) {
71
+ const positive = deltas.filter((delta) => delta > 0);
72
+ if (positive.length === deltas.length) {
73
+ const smallest = Math.min(...positive);
74
+ const largest = Math.max(...positive);
75
+ if (largest > smallest * SPIKE_RATIO) {
76
+ warnings.push({
77
+ code: "spiky-growth",
78
+ detail: `one cycle grew ${mb(largest)} and another ${mb(smallest)} \u2014 the mean of ${mb(input.trend.growthPerCycle)}/cycle summarizes an uneven series; measure more cycles before quoting it`
79
+ });
80
+ }
81
+ }
82
+ }
83
+ if (isLeak && input.trend.growthPerCycle < minGrowth * NOISE_FLOOR_MULTIPLE) {
84
+ warnings.push({
85
+ code: "near-threshold",
86
+ detail: `growth of ${mb(input.trend.growthPerCycle)}/cycle barely clears the ${mb(minGrowth)} threshold \u2014 raise --load-requests so the signal outgrows the noise`
87
+ });
88
+ }
89
+ const neverSettled = input.settleOutcomes.length > 0 && moving.length === input.settleOutcomes.length;
90
+ const abandonedNothing = input.abandonAfterMs !== void 0 && input.loadOutcomes.length > 0 && input.loadOutcomes.every((outcome) => (outcome.abandoned ?? 0) === 0);
91
+ const invalid = isLeak && (neverSettled || abandonedNothing);
92
+ return {
93
+ level: warnings.length === 0 ? "high" : "low",
94
+ warnings,
95
+ ...invalid && { supersededVerdict: "inconclusive" }
96
+ };
97
+ }
98
+
99
+ export {
100
+ effectiveVerdict,
101
+ warrantsIssueDraft,
102
+ assessConfidence
103
+ };
@@ -0,0 +1,38 @@
1
+ import { createRequire as __nextLeakCreateRequire } from 'node:module';import { fileURLToPath as __nextLeakFileURLToPath } from 'node:url';import { dirname as __nextLeakDirname } from 'node:path';const require = __nextLeakCreateRequire(import.meta.url);const __filename = __nextLeakFileURLToPath(import.meta.url);const __dirname = __nextLeakDirname(__filename);
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
9
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
10
+ }) : x)(function(x) {
11
+ if (typeof require !== "undefined") return require.apply(this, arguments);
12
+ throw Error('Dynamic require of "' + x + '" is not supported');
13
+ });
14
+ var __commonJS = (cb, mod) => function __require2() {
15
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
16
+ };
17
+ var __copyProps = (to, from, except, desc) => {
18
+ if (from && typeof from === "object" || typeof from === "function") {
19
+ for (let key of __getOwnPropNames(from))
20
+ if (!__hasOwnProp.call(to, key) && key !== except)
21
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
22
+ }
23
+ return to;
24
+ };
25
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
26
+ // If the importer is in node compatibility mode or this is not an ESM
27
+ // file that has been converted to a CommonJS file using a Babel-
28
+ // compatible transform (i.e. "__esModule" has not been set), then set
29
+ // "default" to the CommonJS "module.exports" for node compatibility.
30
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
31
+ mod
32
+ ));
33
+
34
+ export {
35
+ __require,
36
+ __commonJS,
37
+ __toESM
38
+ };