@miragon/pulse-analytics-client 0.0.0-stage → 0.21.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.
Files changed (200) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +84 -2
  3. package/dist/index.d.ts +12 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +14 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/metric-names.d.ts +43 -0
  8. package/dist/metric-names.d.ts.map +1 -0
  9. package/dist/metric-names.js +53 -0
  10. package/dist/metric-names.js.map +1 -0
  11. package/dist/metrics-contract-labels.test.d.ts +2 -0
  12. package/dist/metrics-contract-labels.test.d.ts.map +1 -0
  13. package/dist/metrics-contract-labels.test.js +169 -0
  14. package/dist/metrics-contract-labels.test.js.map +1 -0
  15. package/dist/metrics-contract.test.d.ts +2 -0
  16. package/dist/metrics-contract.test.d.ts.map +1 -0
  17. package/dist/metrics-contract.test.js +247 -0
  18. package/dist/metrics-contract.test.js.map +1 -0
  19. package/dist/prometheus-client.test.d.ts +2 -0
  20. package/dist/prometheus-client.test.d.ts.map +1 -0
  21. package/dist/prometheus-client.test.js +265 -0
  22. package/dist/prometheus-client.test.js.map +1 -0
  23. package/dist/prometheus.d.ts +100 -0
  24. package/dist/prometheus.d.ts.map +1 -0
  25. package/dist/prometheus.js +295 -0
  26. package/dist/prometheus.js.map +1 -0
  27. package/dist/prometheus.test.d.ts +2 -0
  28. package/dist/prometheus.test.d.ts.map +1 -0
  29. package/dist/prometheus.test.js +54 -0
  30. package/dist/prometheus.test.js.map +1 -0
  31. package/dist/promql-labels.test-support.d.ts +53 -0
  32. package/dist/promql-labels.test-support.d.ts.map +1 -0
  33. package/dist/promql-labels.test-support.js +237 -0
  34. package/dist/promql-labels.test-support.js.map +1 -0
  35. package/dist/promql-labels.test.d.ts +2 -0
  36. package/dist/promql-labels.test.d.ts.map +1 -0
  37. package/dist/promql-labels.test.js +190 -0
  38. package/dist/promql-labels.test.js.map +1 -0
  39. package/dist/promql-parse.test-support.d.ts +57 -0
  40. package/dist/promql-parse.test-support.d.ts.map +1 -0
  41. package/dist/promql-parse.test-support.js +284 -0
  42. package/dist/promql-parse.test-support.js.map +1 -0
  43. package/dist/promql-reading-rules.test-support.d.ts +29 -0
  44. package/dist/promql-reading-rules.test-support.d.ts.map +1 -0
  45. package/dist/promql-reading-rules.test-support.js +79 -0
  46. package/dist/promql-reading-rules.test-support.js.map +1 -0
  47. package/dist/promql-reading-rules.test.d.ts +2 -0
  48. package/dist/promql-reading-rules.test.d.ts.map +1 -0
  49. package/dist/promql-reading-rules.test.js +61 -0
  50. package/dist/promql-reading-rules.test.js.map +1 -0
  51. package/dist/promql-sources.test-support.d.ts +29 -0
  52. package/dist/promql-sources.test-support.d.ts.map +1 -0
  53. package/dist/promql-sources.test-support.js +112 -0
  54. package/dist/promql-sources.test-support.js.map +1 -0
  55. package/dist/promql-sources.test.d.ts +2 -0
  56. package/dist/promql-sources.test.d.ts.map +1 -0
  57. package/dist/promql-sources.test.js +93 -0
  58. package/dist/promql-sources.test.js.map +1 -0
  59. package/dist/queries/as-of.test.d.ts +2 -0
  60. package/dist/queries/as-of.test.d.ts.map +1 -0
  61. package/dist/queries/as-of.test.js +80 -0
  62. package/dist/queries/as-of.test.js.map +1 -0
  63. package/dist/queries/cluster-compare.d.ts +62 -0
  64. package/dist/queries/cluster-compare.d.ts.map +1 -0
  65. package/dist/queries/cluster-compare.js +70 -0
  66. package/dist/queries/cluster-compare.js.map +1 -0
  67. package/dist/queries/cluster-compare.test.d.ts +2 -0
  68. package/dist/queries/cluster-compare.test.d.ts.map +1 -0
  69. package/dist/queries/cluster-compare.test.js +81 -0
  70. package/dist/queries/cluster-compare.test.js.map +1 -0
  71. package/dist/queries/dashboard.d.ts +60 -0
  72. package/dist/queries/dashboard.d.ts.map +1 -0
  73. package/dist/queries/dashboard.js +292 -0
  74. package/dist/queries/dashboard.js.map +1 -0
  75. package/dist/queries/dashboard.test.d.ts +2 -0
  76. package/dist/queries/dashboard.test.d.ts.map +1 -0
  77. package/dist/queries/dashboard.test.js +423 -0
  78. package/dist/queries/dashboard.test.js.map +1 -0
  79. package/dist/queries/element.d.ts +68 -0
  80. package/dist/queries/element.d.ts.map +1 -0
  81. package/dist/queries/element.js +98 -0
  82. package/dist/queries/element.js.map +1 -0
  83. package/dist/queries/element.test.d.ts +2 -0
  84. package/dist/queries/element.test.d.ts.map +1 -0
  85. package/dist/queries/element.test.js +105 -0
  86. package/dist/queries/element.test.js.map +1 -0
  87. package/dist/queries/engine-compare.d.ts +52 -0
  88. package/dist/queries/engine-compare.d.ts.map +1 -0
  89. package/dist/queries/engine-compare.js +57 -0
  90. package/dist/queries/engine-compare.js.map +1 -0
  91. package/dist/queries/engine-compare.test.d.ts +2 -0
  92. package/dist/queries/engine-compare.test.d.ts.map +1 -0
  93. package/dist/queries/engine-compare.test.js +159 -0
  94. package/dist/queries/engine-compare.test.js.map +1 -0
  95. package/dist/queries/engine-landscape.d.ts +92 -0
  96. package/dist/queries/engine-landscape.d.ts.map +1 -0
  97. package/dist/queries/engine-landscape.js +183 -0
  98. package/dist/queries/engine-landscape.js.map +1 -0
  99. package/dist/queries/engine-landscape.test.d.ts +2 -0
  100. package/dist/queries/engine-landscape.test.d.ts.map +1 -0
  101. package/dist/queries/engine-landscape.test.js +171 -0
  102. package/dist/queries/engine-landscape.test.js.map +1 -0
  103. package/dist/queries/failures.d.ts +33 -0
  104. package/dist/queries/failures.d.ts.map +1 -0
  105. package/dist/queries/failures.js +31 -0
  106. package/dist/queries/failures.js.map +1 -0
  107. package/dist/queries/health.d.ts +77 -0
  108. package/dist/queries/health.d.ts.map +1 -0
  109. package/dist/queries/health.js +126 -0
  110. package/dist/queries/health.js.map +1 -0
  111. package/dist/queries/health.test.d.ts +2 -0
  112. package/dist/queries/health.test.d.ts.map +1 -0
  113. package/dist/queries/health.test.js +187 -0
  114. package/dist/queries/health.test.js.map +1 -0
  115. package/dist/queries/helpers.d.ts +184 -0
  116. package/dist/queries/helpers.d.ts.map +1 -0
  117. package/dist/queries/helpers.js +219 -0
  118. package/dist/queries/helpers.js.map +1 -0
  119. package/dist/queries/helpers.test.d.ts +2 -0
  120. package/dist/queries/helpers.test.d.ts.map +1 -0
  121. package/dist/queries/helpers.test.js +53 -0
  122. package/dist/queries/helpers.test.js.map +1 -0
  123. package/dist/queries/index.d.ts +19 -0
  124. package/dist/queries/index.d.ts.map +1 -0
  125. package/dist/queries/index.js +10 -0
  126. package/dist/queries/index.js.map +1 -0
  127. package/dist/queries/performance.d.ts +103 -0
  128. package/dist/queries/performance.d.ts.map +1 -0
  129. package/dist/queries/performance.js +173 -0
  130. package/dist/queries/performance.js.map +1 -0
  131. package/dist/queries/performance.test.d.ts +2 -0
  132. package/dist/queries/performance.test.d.ts.map +1 -0
  133. package/dist/queries/performance.test.js +265 -0
  134. package/dist/queries/performance.test.js.map +1 -0
  135. package/dist/queries/version-compare.d.ts +41 -0
  136. package/dist/queries/version-compare.d.ts.map +1 -0
  137. package/dist/queries/version-compare.js +44 -0
  138. package/dist/queries/version-compare.js.map +1 -0
  139. package/dist/queries/version-compare.test.d.ts +2 -0
  140. package/dist/queries/version-compare.test.d.ts.map +1 -0
  141. package/dist/queries/version-compare.test.js +162 -0
  142. package/dist/queries/version-compare.test.js.map +1 -0
  143. package/dist/queries/windows.d.ts +40 -0
  144. package/dist/queries/windows.d.ts.map +1 -0
  145. package/dist/queries/windows.js +56 -0
  146. package/dist/queries/windows.js.map +1 -0
  147. package/dist/query-honesty.test.d.ts +2 -0
  148. package/dist/query-honesty.test.d.ts.map +1 -0
  149. package/dist/query-honesty.test.js +294 -0
  150. package/dist/query-honesty.test.js.map +1 -0
  151. package/dist/query-scenarios.test-support.d.ts +49 -0
  152. package/dist/query-scenarios.test-support.d.ts.map +1 -0
  153. package/dist/query-scenarios.test-support.js +146 -0
  154. package/dist/query-scenarios.test-support.js.map +1 -0
  155. package/dist/schemas/cluster-compare.d.ts +11 -0
  156. package/dist/schemas/cluster-compare.d.ts.map +1 -0
  157. package/dist/schemas/cluster-compare.js +35 -0
  158. package/dist/schemas/cluster-compare.js.map +1 -0
  159. package/dist/schemas/engine-compare.d.ts +10 -0
  160. package/dist/schemas/engine-compare.d.ts.map +1 -0
  161. package/dist/schemas/engine-compare.js +27 -0
  162. package/dist/schemas/engine-compare.js.map +1 -0
  163. package/dist/schemas/engine-landscape.d.ts +5 -0
  164. package/dist/schemas/engine-landscape.d.ts.map +1 -0
  165. package/dist/schemas/engine-landscape.js +8 -0
  166. package/dist/schemas/engine-landscape.js.map +1 -0
  167. package/dist/schemas/failures.d.ts +8 -0
  168. package/dist/schemas/failures.d.ts.map +1 -0
  169. package/dist/schemas/failures.js +9 -0
  170. package/dist/schemas/failures.js.map +1 -0
  171. package/dist/schemas/health.d.ts +5 -0
  172. package/dist/schemas/health.d.ts.map +1 -0
  173. package/dist/schemas/health.js +6 -0
  174. package/dist/schemas/health.js.map +1 -0
  175. package/dist/schemas/index.d.ts +10 -0
  176. package/dist/schemas/index.d.ts.map +1 -0
  177. package/dist/schemas/index.js +10 -0
  178. package/dist/schemas/index.js.map +1 -0
  179. package/dist/schemas/path.d.ts +15 -0
  180. package/dist/schemas/path.d.ts.map +1 -0
  181. package/dist/schemas/path.js +21 -0
  182. package/dist/schemas/path.js.map +1 -0
  183. package/dist/schemas/performance.d.ts +23 -0
  184. package/dist/schemas/performance.d.ts.map +1 -0
  185. package/dist/schemas/performance.js +21 -0
  186. package/dist/schemas/performance.js.map +1 -0
  187. package/dist/schemas/shared.d.ts +34 -0
  188. package/dist/schemas/shared.d.ts.map +1 -0
  189. package/dist/schemas/shared.js +34 -0
  190. package/dist/schemas/shared.js.map +1 -0
  191. package/dist/schemas/version-compare.d.ts +10 -0
  192. package/dist/schemas/version-compare.d.ts.map +1 -0
  193. package/dist/schemas/version-compare.js +25 -0
  194. package/dist/schemas/version-compare.js.map +1 -0
  195. package/dist/widgets.d.ts +138 -0
  196. package/dist/widgets.d.ts.map +1 -0
  197. package/dist/widgets.js +2 -0
  198. package/dist/widgets.js.map +1 -0
  199. package/metrics-contract.json +174 -0
  200. package/package.json +72 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promql-sources.test-support.js","sourceRoot":"","sources":["../src/promql-sources.test-support.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=promql-sources.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promql-sources.test.d.ts","sourceRoot":"","sources":["../src/promql-sources.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,93 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { checkQueryLabels, contractCatalog } from "./promql-labels.test-support.js";
3
+ import { alertExpressions, dashboardQueries } from "./promql-sources.test-support.js";
4
+ /**
5
+ * The extractors feeding alert rules and Grafana dashboards into the label
6
+ * guard (`metrics-contract-labels.test.ts`). A shape they skip, or pass on
7
+ * still quoted, is a shape the guard never checks — these cases pin that each
8
+ * one is read or rejected, never silently dropped.
9
+ */
10
+ const catalog = contractCatalog([
11
+ { promName: "backlog", type: "gauge", labels: ["engine_id"] },
12
+ { promName: "started_total", type: "counter", labels: ["engine_id", "state"] },
13
+ ]);
14
+ describe("alertExpressions", () => {
15
+ it.each([
16
+ ["plain", " expr: sum by (engine_id) (backlog) > 0"],
17
+ ["single-quoted", " expr: 'sum by (engine_id) (backlog) > 0'"],
18
+ ["double-quoted", ' expr: "sum by (engine_id) (backlog) > 0"'],
19
+ ["a list item", " - expr: sum by (engine_id) (backlog) > 0"],
20
+ ["a literal block", " expr: |\n sum by (engine_id) (backlog)\n\n > 0"],
21
+ ["a folded block", " expr: >-\n sum by (engine_id)\n (backlog) > 0"],
22
+ ["a plain multi-line scalar", " expr: sum by (engine_id)\n (backlog) > 0"],
23
+ ["a quoted multi-line scalar", " expr: 'sum by (engine_id)\n (backlog) > 0'"],
24
+ ])("reads %s expr as the PromQL it denotes", (_shape, yaml) => {
25
+ const [expr] = alertExpressions(`${yaml}\n for: 5m\n`);
26
+ expect(expr.replace(/\s+/g, " ")).toBe("sum by (engine_id) (backlog) > 0");
27
+ });
28
+ it("unescapes quotes inside quoted scalars", () => {
29
+ expect(alertExpressions(` expr: 'backlog{engine_id=''a''}'`)).toEqual([
30
+ "backlog{engine_id='a'}",
31
+ ]);
32
+ expect(alertExpressions(` expr: "backlog{engine_id=\\"a\\"}"`)).toEqual([
33
+ 'backlog{engine_id="a"}',
34
+ ]);
35
+ });
36
+ it("lets the checker see the labels of a quoted rule", () => {
37
+ // Left quoted, this parsed as one PromQL string literal: no violation,
38
+ // zero labels checked — the guard passed without looking.
39
+ const [expr] = alertExpressions(` expr: 'sum by (foo) (backlog{bar="x"}) > 0'`);
40
+ const result = checkQueryLabels(expr, catalog);
41
+ expect(result.series).toEqual(["backlog"]);
42
+ expect(result.violations).toHaveLength(2);
43
+ });
44
+ it("stops each value at the next key and returns every rule", () => {
45
+ const yaml = [
46
+ "groups:",
47
+ " - name: g",
48
+ " rules:",
49
+ " - alert: A",
50
+ " expr: backlog > 1",
51
+ " for: 5m",
52
+ " - alert: B",
53
+ " expr: |",
54
+ " started_total > 2",
55
+ " labels:",
56
+ " severity: warning",
57
+ ].join("\n");
58
+ expect(alertExpressions(yaml)).toEqual(["backlog > 1", "started_total > 2"]);
59
+ });
60
+ it.each([
61
+ ["an unterminated single quote", " expr: 'backlog > 0"],
62
+ ["a comment after the closing quote", " expr: 'backlog > 0' # why"],
63
+ ["an escape outside the JSON subset", ' expr: "backlog \\e > 0"'],
64
+ ["an empty value", " expr:\n for: 5m"],
65
+ ])("throws on %s instead of passing it on", (_shape, yaml) => {
66
+ expect(() => alertExpressions(yaml)).toThrow(/alerts\.yml/);
67
+ });
68
+ });
69
+ describe("dashboardQueries", () => {
70
+ it("collects panel exprs from any depth", () => {
71
+ const dashboard = { panels: [{ targets: [{ expr: "backlog" }, { expr: "started_total" }] }] };
72
+ expect(dashboardQueries(dashboard)).toEqual(["backlog", "started_total"]);
73
+ });
74
+ it.each([
75
+ ["label_values(started_total, engine_id)", "count by (engine_id)(started_total)"],
76
+ [
77
+ 'label_values(started_total{engine_id=~"$engine",state="COMPLETED"}, engine_id)',
78
+ 'count by (engine_id)(started_total{engine_id=~"$engine",state="COMPLETED"})',
79
+ ],
80
+ ["query_result(sum by (engine_id) (backlog))", "sum by (engine_id) (backlog)"],
81
+ ])("rewrites the templating query %s", (query, promql) => {
82
+ // Both the plain string and the newer `{ query: { query } }` object form.
83
+ expect(dashboardQueries({ templating: { list: [{ query }] } })).toEqual([promql]);
84
+ expect(dashboardQueries({ templating: { list: [{ query: { query } }] } })).toEqual([promql]);
85
+ });
86
+ it("ignores templating queries that name no label", () => {
87
+ expect(dashboardQueries({ list: [{ query: "a,b,c" }, { query: "label_names()" }] })).toEqual([]);
88
+ });
89
+ it.each(["label_values(engine_id)", "label_values(started_total, )", "query_result()"])("throws on the unreadable templating query %s instead of skipping it", (query) => {
90
+ expect(() => dashboardQueries({ query })).toThrow(/unsupported Grafana templating query/);
91
+ });
92
+ });
93
+ //# sourceMappingURL=promql-sources.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promql-sources.test.js","sourceRoot":"","sources":["../src/promql-sources.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=as-of.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"as-of.test.d.ts","sourceRoot":"","sources":["../../src/queries/as-of.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,80 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { clusterCompare } from "./cluster-compare.js";
3
+ import { dashboardData, failureDashboardData } from "./dashboard.js";
4
+ import { elementHeat } from "./element.js";
5
+ import { engineCompare } from "./engine-compare.js";
6
+ import { engineLandscape } from "./engine-landscape.js";
7
+ import { versionCompare } from "./version-compare.js";
8
+ /**
9
+ * U7: every view result says when its figures were read (`asOf`, the "Stand"
10
+ * a widget shows next to the period and the engine set), and the dashboard
11
+ * names the engines in scope that report metrics, so a view can say how many
12
+ * of them send none. Neither is a guess: `asOf` is the evaluation time of the
13
+ * instant queries, `reportingEngines` the presence probe's answer.
14
+ */
15
+ const NOW = "2026-10-10T12:32:00.000Z";
16
+ beforeEach(() => {
17
+ vi.useFakeTimers({ toFake: ["Date"] });
18
+ vi.setSystemTime(new Date(NOW));
19
+ });
20
+ afterEach(() => vi.useRealTimers());
21
+ /** A client that answers the engine presence probe for `reporting` and nothing else. */
22
+ function client(reporting = []) {
23
+ return {
24
+ instant: vi.fn((q) => Promise.resolve(q.includes("camunda_jobs_executable")
25
+ ? reporting.map((engine_id) => ({ metric: { engine_id }, value: 1 }))
26
+ : [])),
27
+ };
28
+ }
29
+ describe("asOf — when the figures were read", () => {
30
+ it("stamps every view result with the query time", async () => {
31
+ const results = await Promise.all([
32
+ dashboardData(client(), { period: "7d" }),
33
+ failureDashboardData(client(), {}),
34
+ versionCompare(client(), {
35
+ processDefinitionKey: "order",
36
+ versionA: 1,
37
+ versionB: 2,
38
+ windowDays: 14,
39
+ minBucketSize: 10,
40
+ }),
41
+ engineCompare(client(), {
42
+ processDefinitionKey: "order",
43
+ engineA: "prod-a",
44
+ engineB: "prod-b",
45
+ windowDays: 14,
46
+ minBucketSize: 10,
47
+ }),
48
+ engineLandscape(client(), { engine: ["prod-a"] }),
49
+ elementHeat(client(), { processDefinitionKey: "order", period: "7d" }),
50
+ ]);
51
+ for (const result of results)
52
+ expect(result.asOf).toBe(NOW);
53
+ });
54
+ it("stamps a deployment comparison with the `now` its windows were clamped to", async () => {
55
+ const res = await clusterCompare(client(), {
56
+ deploymentTimestamp: "2026-10-08T12:00:00Z",
57
+ windowBeforeDays: 7,
58
+ windowAfterDays: 7,
59
+ minBucketSize: 10,
60
+ });
61
+ expect(res.asOf).toBe(NOW);
62
+ // The post-deployment window ends at that same `now`.
63
+ expect(res.partial).toBe(true);
64
+ });
65
+ });
66
+ describe("reportingEngines — which engines in scope send metrics", () => {
67
+ it("lists the engines the presence probe answered for, ascending and once each", async () => {
68
+ const res = await dashboardData(client(["prod-c", "prod-a", "prod-c"]), {
69
+ period: "7d",
70
+ engine: ["prod-a", "prod-b", "prod-c"],
71
+ });
72
+ expect(res.reportingEngines).toEqual(["prod-a", "prod-c"]);
73
+ });
74
+ it("is empty when no engine in scope reports, and skips a series without an engine id", async () => {
75
+ const instant = vi.fn((q) => Promise.resolve(q.includes("camunda_jobs_executable") ? [{ metric: {}, value: 1 }] : []));
76
+ expect((await dashboardData({ instant }, { period: "7d" })).reportingEngines).toEqual([]);
77
+ expect((await dashboardData(client(), { period: "7d" })).reportingEngines).toEqual([]);
78
+ });
79
+ });
80
+ //# sourceMappingURL=as-of.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"as-of.test.js","sourceRoot":"","sources":["../../src/queries/as-of.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ import { type EngineFilterInput, type PrometheusClient } from "../prometheus.js";
2
+ import { type CompareKpiDelta, type CompareKpis } from "./helpers.js";
3
+ export interface ClusterCompareKpi extends CompareKpis {
4
+ period: "before" | "after";
5
+ window_from: string;
6
+ window_to: string;
7
+ /** The window's ACTUAL length in days, after clamping to now and retention. */
8
+ window_days: number;
9
+ }
10
+ export type ClusterCompareDelta = CompareKpiDelta;
11
+ export interface ClusterCompareResult {
12
+ /** The engine ids covered; `null` = every engine Prometheus holds (unscoped library call). */
13
+ engines: string[] | null;
14
+ processDefinitionKey: string | null;
15
+ activityId: string | null;
16
+ deploymentTimestamp: string;
17
+ /** The window lengths asked for, in whole days (the tool inputs). */
18
+ requestedWindowDays: {
19
+ before: number;
20
+ after: number;
21
+ };
22
+ /** The ACTUAL window lengths in days — what was measured, not what was asked for. */
23
+ windowDays: {
24
+ before: number;
25
+ after: number;
26
+ };
27
+ /**
28
+ * True when a window is shorter than requested: the post-deploy window
29
+ * reaches past now (a recent deployment) or the baseline past retention.
30
+ */
31
+ partial: boolean;
32
+ minBucketSize: number;
33
+ suppressed: boolean;
34
+ kpis: ClusterCompareKpi[];
35
+ delta: ClusterCompareDelta;
36
+ /**
37
+ * When the figures were read from Prometheus (ISO timestamp): the "Stand"
38
+ * a view shows. Optional only for payloads recorded before it existed.
39
+ */
40
+ asOf?: string;
41
+ }
42
+ /**
43
+ * Pre/Post deployment comparison from OTEL metrics. Each window is queried with
44
+ * the PromQL `@ <end>` modifier so the before/after split is exact, and both
45
+ * windows are clamped to `[now − retention, now]`: right after a deployment the
46
+ * post-deploy window holds only the elapsed hours, and is reported as exactly
47
+ * that (`window_days`, `partial`) rather than as the requested span. Instance
48
+ * counts are compared PER DAY, so windows of different length compare fairly.
49
+ *
50
+ * `incident_count`/`incident_rate_pct` cover every activity; with `activityId`
51
+ * the `element_incident_*` fields add the count at that element.
52
+ */
53
+ export declare function clusterCompare(ch: PrometheusClient, params: {
54
+ processDefinitionKey?: string;
55
+ activityId?: string;
56
+ deploymentTimestamp: string;
57
+ windowBeforeDays: number;
58
+ windowAfterDays: number;
59
+ minBucketSize: number;
60
+ engine?: EngineFilterInput;
61
+ }): Promise<ClusterCompareResult>;
62
+ //# sourceMappingURL=cluster-compare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cluster-compare.d.ts","sourceRoot":"","sources":["../../src/queries/cluster-compare.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAKL,KAAK,eAAe,EACpB,KAAK,WAAW,EACjB,MAAM,cAAc,CAAA;AAWrB,MAAM,WAAW,iBAAkB,SAAQ,WAAW;IACpD,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAA;IAC1B,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,MAAM,mBAAmB,GAAG,eAAe,CAAA;AAEjD,MAAM,WAAW,oBAAoB;IACnC,8FAA8F;IAC9F,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;IACxB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,qEAAqE;IACrE,mBAAmB,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IACtD,qFAAqF;IACrF,UAAU,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IAC7C;;;OAGG;IACH,OAAO,EAAE,OAAO,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,OAAO,CAAA;IACnB,IAAI,EAAE,iBAAiB,EAAE,CAAA;IACzB,KAAK,EAAE,mBAAmB,CAAA;IAC1B;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,cAAc,CAClC,EAAE,EAAE,gBAAgB,EACpB,MAAM,EAAE;IACN,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,gBAAgB,EAAE,MAAM,CAAA;IACxB,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;IACrB,MAAM,CAAC,EAAE,iBAAiB,CAAA;CAC3B,GACA,OAAO,CAAC,oBAAoB,CAAC,CAiD/B"}
@@ -0,0 +1,70 @@
1
+ import { engineIdsOf, engineMatcher, escapeLabelValue, selector, } from "../prometheus.js";
2
+ import { belowMinBucket, compareKpiDelta, parseIsoSeconds, queryCompareKpis, } from "./helpers.js";
3
+ import { DAY_SECONDS, clampWindow, daysOf, isoOf, nowSeconds, windowAt, } from "./windows.js";
4
+ /**
5
+ * Pre/Post deployment comparison from OTEL metrics. Each window is queried with
6
+ * the PromQL `@ <end>` modifier so the before/after split is exact, and both
7
+ * windows are clamped to `[now − retention, now]`: right after a deployment the
8
+ * post-deploy window holds only the elapsed hours, and is reported as exactly
9
+ * that (`window_days`, `partial`) rather than as the requested span. Instance
10
+ * counts are compared PER DAY, so windows of different length compare fairly.
11
+ *
12
+ * `incident_count`/`incident_rate_pct` cover every activity; with `activityId`
13
+ * the `element_incident_*` fields add the count at that element.
14
+ */
15
+ export async function clusterCompare(ch, params) {
16
+ const minBucket = Math.max(1, Math.floor(params.minBucketSize));
17
+ const before = Math.max(1, Math.floor(params.windowBeforeDays));
18
+ const after = Math.max(1, Math.floor(params.windowAfterDays));
19
+ const deployTs = parseIsoSeconds(params.deploymentTimestamp, "deploymentTimestamp");
20
+ const now = nowSeconds();
21
+ if (deployTs >= now) {
22
+ throw new Error("deploymentTimestamp lies in the future (or is now) — there is no post-deployment window to compare yet");
23
+ }
24
+ const beforeWin = clampWindow("the pre-deployment window", deployTs - before * DAY_SECONDS, deployTs, now);
25
+ const afterWin = clampWindow("the post-deployment window", deployTs, deployTs + after * DAY_SECONDS, now);
26
+ const [b, a] = await Promise.all([
27
+ windowKpi(ch, params, "before", beforeWin),
28
+ windowKpi(ch, params, "after", afterWin),
29
+ ]);
30
+ return {
31
+ engines: engineIdsOf(params.engine),
32
+ processDefinitionKey: params.processDefinitionKey ?? null,
33
+ activityId: params.activityId ?? null,
34
+ deploymentTimestamp: params.deploymentTimestamp,
35
+ requestedWindowDays: { before, after },
36
+ windowDays: { before: b.window_days, after: a.window_days },
37
+ partial: beforeWin.partial || afterWin.partial,
38
+ minBucketSize: minBucket,
39
+ suppressed: belowMinBucket([b, a], minBucket),
40
+ kpis: [b, a],
41
+ // The windows were clamped to this `now`: the figures are as of it.
42
+ asOf: new Date(now * 1000).toISOString(),
43
+ // Exact lengths, not the rounded `window_days`: a 2 h window is 0.083 d.
44
+ delta: compareKpiDelta(b, a, {
45
+ baseline: beforeWin.seconds / DAY_SECONDS,
46
+ other: afterWin.seconds / DAY_SECONDS,
47
+ }),
48
+ };
49
+ }
50
+ async function windowKpi(ch, params, period, win) {
51
+ const engine = engineMatcher(params.engine);
52
+ const keyMatcher = params.processDefinitionKey
53
+ ? `process_definition_key="${escapeLabelValue(params.processDefinitionKey)}"`
54
+ : undefined;
55
+ const kpis = await queryCompareKpis(ch, {
56
+ sel: selector(keyMatcher, engine),
57
+ completedSel: selector(keyMatcher, `state="COMPLETED"`, engine),
58
+ elementIncidentSel: params.activityId
59
+ ? selector(keyMatcher, `activity_id="${escapeLabelValue(params.activityId)}"`, engine)
60
+ : undefined,
61
+ }, windowAt(win));
62
+ return {
63
+ period,
64
+ ...kpis,
65
+ window_from: isoOf(win.from),
66
+ window_to: isoOf(win.to),
67
+ window_days: daysOf(win.seconds),
68
+ };
69
+ }
70
+ //# sourceMappingURL=cluster-compare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cluster-compare.js","sourceRoot":"","sources":["../../src/queries/cluster-compare.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cluster-compare.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cluster-compare.test.d.ts","sourceRoot":"","sources":["../../src/queries/cluster-compare.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,81 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { clusterCompare } from "./cluster-compare.js";
3
+ import { clusterCompareInput } from "../schemas/cluster-compare.js";
4
+ const NOW = "2026-03-20T12:00:00.000Z";
5
+ const NOW_SEC = Date.parse(NOW) / 1000;
6
+ const DAY = 86_400;
7
+ const DEPLOY = "2026-03-10T12:00:00.000Z";
8
+ const DEPLOY_SEC = Date.parse(DEPLOY) / 1000;
9
+ beforeEach(() => {
10
+ vi.useFakeTimers({ toFake: ["Date"], now: Date.parse(NOW) });
11
+ });
12
+ afterEach(() => {
13
+ vi.useRealTimers();
14
+ });
15
+ const constant = (value) => vi.fn(async () => [{ metric: {}, value }]);
16
+ const base = { windowBeforeDays: 7, windowAfterDays: 7, minBucketSize: 10 };
17
+ describe("clusterCompare", () => {
18
+ it("anchors both windows at exact epoch seconds via the @ modifier", async () => {
19
+ const instant = constant(20);
20
+ const res = await clusterCompare({ instant }, { ...base, deploymentTimestamp: DEPLOY });
21
+ const queries = instant.mock.calls.map((c) => c[0]);
22
+ expect(queries.some((q) => q.includes(`[${7 * DAY}s] @ ${DEPLOY_SEC}`))).toBe(true);
23
+ expect(queries.some((q) => q.includes(`[${7 * DAY}s] @ ${DEPLOY_SEC + 7 * DAY}`))).toBe(true);
24
+ expect(queries.every((q) => !q.includes("NaN"))).toBe(true);
25
+ expect(res.kpis[0].window_to).toBe(DEPLOY);
26
+ expect(res.kpis[1].window_from).toBe(DEPLOY);
27
+ expect(res).toMatchObject({ windowDays: { before: 7, after: 7 }, partial: false });
28
+ });
29
+ it("clamps the post-deploy window to now and reports what was measured (N79)", async () => {
30
+ // Deployed 2 h ago: a "+7d" window would reach 7 days into the future and
31
+ // compare 2 h of data against 7 full days.
32
+ const deployedSec = NOW_SEC - 2 * 3600;
33
+ const instant = constant(20);
34
+ const res = await clusterCompare({ instant }, { ...base, deploymentTimestamp: new Date(deployedSec * 1000).toISOString() });
35
+ const queries = instant.mock.calls.map((c) => c[0]);
36
+ expect(queries.some((q) => q.includes(`[${2 * 3600}s] @ ${NOW_SEC}`))).toBe(true);
37
+ expect(queries.every((q) => !/@ (\d+)/.test(q) || Number(/@ (\d+)/.exec(q)[1]) <= NOW_SEC)).toBe(true);
38
+ expect(res.kpis[1].window_to).toBe(NOW);
39
+ expect(res.windowDays).toEqual({ before: 7, after: 0.08 });
40
+ expect(res.partial).toBe(true);
41
+ // 20 starts in 2 h vs 20 in 7 d: per day that is a massive rise, not "+0 %".
42
+ expect(res.delta.started_per_day_delta_pct).toBeGreaterThan(8000);
43
+ });
44
+ it("clamps the baseline to the retention", async () => {
45
+ const instant = constant(20);
46
+ const res = await clusterCompare({ instant }, { ...base, windowBeforeDays: 14, deploymentTimestamp: "2026-02-25T12:00:00.000Z" });
47
+ // now − 30 d = 2026-02-18T12:00Z: the 14-day baseline keeps only 7 days.
48
+ expect(res.kpis[0].window_from).toBe("2026-02-18T12:00:00.000Z");
49
+ expect(res.windowDays.before).toBe(7);
50
+ expect(res.partial).toBe(true);
51
+ });
52
+ it.each([
53
+ ["in the future", "2026-03-21T12:00:00.000Z", /lies in the future/],
54
+ ["exactly now", NOW, /lies in the future \(or is now\)/],
55
+ ["before the retention", "2026-01-01T00:00:00.000Z", /before the 30-day Prometheus retention/],
56
+ ])("refuses a deployment %s before any PromQL is sent", async (_label, ts, message) => {
57
+ const instant = vi.fn(async () => []);
58
+ await expect(clusterCompare({ instant }, { ...base, deploymentTimestamp: ts })).rejects.toThrow(message);
59
+ expect(instant).not.toHaveBeenCalled();
60
+ });
61
+ it("rejects an unparsable deploymentTimestamp before any PromQL is sent", async () => {
62
+ const instant = vi.fn(async () => []);
63
+ await expect(clusterCompare({ instant }, { ...base, deploymentTimestamp: "last week" })).rejects.toThrow(/deploymentTimestamp "last week" is not a parseable ISO datetime/);
64
+ expect(instant).not.toHaveBeenCalled();
65
+ });
66
+ });
67
+ describe("clusterCompareInput", () => {
68
+ it("accepts ISO datetimes including the engine's local-offset format", () => {
69
+ expect(clusterCompareInput.safeParse({ deploymentTimestamp: DEPLOY }).success).toBe(true);
70
+ expect(clusterCompareInput.safeParse({ deploymentTimestamp: "2026-03-10T14:00:00.000+0200" })
71
+ .success).toBe(true);
72
+ });
73
+ it("rejects non-datetime strings at the tool boundary", () => {
74
+ const res = clusterCompareInput.safeParse({ deploymentTimestamp: "last week" });
75
+ expect(res.success).toBe(false);
76
+ if (!res.success) {
77
+ expect(res.error.issues[0].message).toMatch(/parseable ISO datetime/);
78
+ }
79
+ });
80
+ });
81
+ //# sourceMappingURL=cluster-compare.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cluster-compare.test.js","sourceRoot":"","sources":["../../src/queries/cluster-compare.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAA;AAGnE,MAAM,GAAG,GAAG,0BAA0B,CAAA;AACtC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAA;AACtC,MAAM,GAAG,GAAG,MAAM,CAAA;AAClB,MAAM,MAAM,GAAG,0BAA0B,CAAA;AACzC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,CAAA;AAE5C,UAAU,CAAC,GAAG,EAAE;IACd,EAAE,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;AAC9D,CAAC,CAAC,CAAA;AAEF,SAAS,CAAC,GAAG,EAAE;IACb,EAAE,CAAC,aAAa,EAAE,CAAA;AACpB,CAAC,CAAC,CAAA;AAEF,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAE,EAAE,CACjC,EAAE,CAAC,EAAE,CAAuC,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;AAElF,MAAM,IAAI,GAAG,EAAE,gBAAgB,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,aAAa,EAAE,EAAE,EAAE,CAAA;AAE3E,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;QAC9E,MAAM,OAAO,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;QAC5B,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,mBAAmB,EAAE,MAAM,EAAE,CAAC,CAAA;QAEvF,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACnD,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,GAAG,QAAQ,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACnF,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,GAAG,QAAQ,UAAU,GAAG,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC7F,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC3D,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC1C,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC5C,MAAM,CAAC,GAAG,CAAC,CAAC,aAAa,CAAC,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAA;IACpF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;QACxF,0EAA0E;QAC1E,2CAA2C;QAC3C,MAAM,WAAW,GAAG,OAAO,GAAG,CAAC,GAAG,IAAI,CAAA;QACtC,MAAM,OAAO,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;QAC5B,MAAM,GAAG,GAAG,MAAM,cAAc,CAC9B,EAAE,OAAO,EAAE,EACX,EAAE,GAAG,IAAI,EAAE,mBAAmB,EAAE,IAAI,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAC7E,CAAA;QAED,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACnD,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,QAAQ,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACjF,MAAM,CACJ,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,CACrF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACZ,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACvC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QAC1D,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC9B,6EAA6E;QAC7E,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,CAAA;IACnE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,OAAO,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;QAC5B,MAAM,GAAG,GAAG,MAAM,cAAc,CAC9B,EAAE,OAAO,EAAE,EACX,EAAE,GAAG,IAAI,EAAE,gBAAgB,EAAE,EAAE,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,CACnF,CAAA;QACD,yEAAyE;QACzE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAA;QAChE,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACrC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAChC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,IAAI,CAAC;QACN,CAAC,eAAe,EAAE,0BAA0B,EAAE,oBAAoB,CAAC;QACnE,CAAC,aAAa,EAAE,GAAG,EAAE,kCAAkC,CAAC;QACxD,CAAC,sBAAsB,EAAE,0BAA0B,EAAE,wCAAwC,CAAC;KAC/F,CAAC,CAAC,mDAAmD,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE;QACpF,MAAM,OAAO,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,IAA2B,EAAE,CAAC,EAAE,CAAC,CAAA;QAC5D,MAAM,MAAM,CAAC,cAAc,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,mBAAmB,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAC7F,OAAO,CACR,CAAA;QACD,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAA;IACxC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,OAAO,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,IAA2B,EAAE,CAAC,EAAE,CAAC,CAAA;QAE5D,MAAM,MAAM,CACV,cAAc,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,mBAAmB,EAAE,WAAW,EAAE,CAAC,CAC3E,CAAC,OAAO,CAAC,OAAO,CAAC,iEAAiE,CAAC,CAAA;QACpF,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAA;IACxC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,CAAC,mBAAmB,CAAC,SAAS,CAAC,EAAE,mBAAmB,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACzF,MAAM,CACJ,mBAAmB,CAAC,SAAS,CAAC,EAAE,mBAAmB,EAAE,8BAA8B,EAAE,CAAC;aACnF,OAAO,CACX,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACd,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,GAAG,GAAG,mBAAmB,CAAC,SAAS,CAAC,EAAE,mBAAmB,EAAE,WAAW,EAAE,CAAC,CAAA;QAC/E,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC/B,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAA;QACvE,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,60 @@
1
+ import { type EngineFilterInput, type Period, type PrometheusClient } from "../prometheus.js";
2
+ import type { AnalyticsDashboardData, FailureDashboardData } from "../widgets.js";
3
+ /**
4
+ * How many (process, activity) rows the activity breakdown carries: the top
5
+ * ones by total time. The result says how many there were in all
6
+ * (`activityCount`), so a view calls the list what it is ("Top 20 by total
7
+ * time") instead of showing an unexplained count.
8
+ */
9
+ export declare const ACTIVITY_BREAKDOWN_LIMIT = 20;
10
+ /**
11
+ * Aggregated dashboard KPIs + activity / definition breakdowns, from the
12
+ * engine's process metrics. Shared by the dashboard pipeline step and the
13
+ * `analytics_show_dashboard` widget tool. Two kinds of figures, never mixed:
14
+ *
15
+ * - FLOWS within the window (`period`): starts, completions, incidents created
16
+ * and resolved, and the durations of the instances that ended — counted over
17
+ * the range with {@link increaseIn}. Durations are null when nothing ended; `incidentRatePct` is null
18
+ * when nothing started.
19
+ * - LIVE STATE right now: `runningNow` / `openIncidentsNow` from the state
20
+ * gauges (`camunda_process_instances_running`, `camunda_incidents_open`) —
21
+ * the same numbers the failure dashboard, engine health and the landscape
22
+ * read, independent of the window. A counter difference within the window
23
+ * is no substitute: it misses every instance started before the window.
24
+ * The gauges have rows only for what exists, so whether a missing series is
25
+ * 0 or "not reported" (null) is decided by the engine presence probe
26
+ * ({@link reportingEnginesQuery}): null only while no engine in scope reports.
27
+ *
28
+ * The activity breakdown groups by (process, activity): BPMN ids are only
29
+ * unique within one model, so `StartEvent_1` of two processes are two rows.
30
+ * The result echoes its scope (process key, period, engines).
31
+ *
32
+ * `previous` holds the starts and incidents of the window right before the
33
+ * period: the reference an incident rate is judged against (a rate on its
34
+ * own says nothing about whether it is high). It is null when that window
35
+ * lies wholly before the Prometheus retention (a 30-day period), and
36
+ * `suppressed` when either window started fewer than `minBucketSize`
37
+ * instances: a change of a rate over a handful of starts is noise.
38
+ */
39
+ export declare function dashboardData(ch: PrometheusClient, params: {
40
+ processDefinitionKey?: string;
41
+ period: Period;
42
+ engine?: EngineFilterInput;
43
+ /** The floor per window for judging the rate's change (the caller's saved `minBucketSize`); default 10. */
44
+ minBucketSize?: number;
45
+ }): Promise<AnalyticsDashboardData>;
46
+ /**
47
+ * Current failure / incident state, from the live state gauges
48
+ * (`camunda_incidents_open`, `camunda_jobs_failed`, `camunda_process_instances_running`).
49
+ *
50
+ * Point-in-time ("what is failing now"), so it is robust regardless of how the
51
+ * data arrived — unlike a rate window over `incident_created`, which reads zero
52
+ * on backdated/bulk-imported history. Per process: instances running now, dead
53
+ * jobs, open incidents and open incidents per 100 running instances. Groups
54
+ * are (process, incident type) — the gauge carries no message, activity id,
55
+ * timestamps or instance ids, so the rows carry none either.
56
+ */
57
+ export declare function failureDashboardData(ch: PrometheusClient, params: {
58
+ engine?: EngineFilterInput;
59
+ }): Promise<FailureDashboardData>;
60
+ //# sourceMappingURL=dashboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../src/queries/dashboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,iBAAiB,EACtB,KAAK,MAAM,EACX,KAAK,gBAAgB,EAEtB,MAAM,kBAAkB,CAAA;AAezB,OAAO,KAAK,EAEV,sBAAsB,EAGtB,oBAAoB,EAGrB,MAAM,eAAe,CAAA;AAEtB;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,KAAK,CAAA;AAY1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,aAAa,CACjC,EAAE,EAAE,gBAAgB,EACpB,MAAM,EAAE;IACN,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,iBAAiB,CAAA;IAC1B,2GAA2G;IAC3G,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,GACA,OAAO,CAAC,sBAAsB,CAAC,CAyHjC;AAkID;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,gBAAgB,EACpB,MAAM,EAAE;IAAE,MAAM,CAAC,EAAE,iBAAiB,CAAA;CAAE,GACrC,OAAO,CAAC,oBAAoB,CAAC,CAuD/B"}