@miragon/pulse-analytics-client 0.0.0-bootstrap.0 → 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 +83 -3
  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 -5
@@ -0,0 +1,56 @@
1
+ import { RETENTION_DAYS } from "../prometheus.js";
2
+ export const DAY_SECONDS = 86_400;
3
+ /** Now, in epoch seconds — the upper bound of every window. */
4
+ export const nowSeconds = () => Math.floor(Date.now() / 1000);
5
+ /**
6
+ * Holds `[from, to]` inside `[now − RETENTION_DAYS, now]`: Prometheus answers
7
+ * a future `@` with whatever exists so far and a pre-retention one with
8
+ * nothing, so an unclamped window silently reads a fraction of its span while
9
+ * being reported at full length. Refuses what no clamp can repair — a
10
+ * reversed or empty window, one entirely in the future or entirely before
11
+ * retention — with a message naming `name`.
12
+ */
13
+ export function clampWindow(name, from, to, now = nowSeconds()) {
14
+ if (to <= from) {
15
+ throw new Error(`${name}: the window ends before it starts — swap from and to`);
16
+ }
17
+ const oldest = now - RETENTION_DAYS * DAY_SECONDS;
18
+ if (from >= now) {
19
+ throw new Error(`${name}: the window lies in the future — no metrics exist for it yet`);
20
+ }
21
+ if (to <= oldest) {
22
+ throw new Error(`${name}: the window lies before the ${RETENTION_DAYS}-day Prometheus retention — its metrics are gone`);
23
+ }
24
+ const clampedFrom = Math.max(from, oldest);
25
+ const clampedTo = Math.min(to, now);
26
+ return {
27
+ from: clampedFrom,
28
+ to: clampedTo,
29
+ seconds: clampedTo - clampedFrom,
30
+ partial: clampedFrom !== from || clampedTo !== to,
31
+ };
32
+ }
33
+ const UNIT_SECONDS = {
34
+ s: 1,
35
+ m: 60,
36
+ h: 3600,
37
+ d: DAY_SECONDS,
38
+ w: 7 * DAY_SECONDS,
39
+ };
40
+ /** The length of a single-unit PromQL duration (`7d`, `86400s`) in seconds. */
41
+ export function rangeSeconds(range) {
42
+ const match = /^(\d+)([smhdw])$/.exec(range);
43
+ if (!match)
44
+ throw new Error(`"${range}" is not a single-unit PromQL duration such as 7d or 86400s`);
45
+ return Number(match[1]) * UNIT_SECONDS[match[2]];
46
+ }
47
+ /** The window reading exactly `w`: `<seconds>s` ending `@ <to>`. */
48
+ export const windowAt = (w) => ({
49
+ range: `${w.seconds}s`,
50
+ at: w.to,
51
+ });
52
+ /** A window length in days, two decimals (a clamped window is rarely whole days). */
53
+ export const daysOf = (seconds) => Math.round((seconds / DAY_SECONDS) * 100) / 100;
54
+ /** ISO timestamp of an epoch-second instant. */
55
+ export const isoOf = (seconds) => new Date(seconds * 1000).toISOString();
56
+ //# sourceMappingURL=windows.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows.js","sourceRoot":"","sources":["../../src/queries/windows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEjD,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAA;AAEjC,+DAA+D;AAC/D,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;AAY7D;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CACzB,IAAY,EACZ,IAAY,EACZ,EAAU,EACV,MAAc,UAAU,EAAE;IAE1B,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,uDAAuD,CAAC,CAAA;IACjF,CAAC;IACD,MAAM,MAAM,GAAG,GAAG,GAAG,cAAc,GAAG,WAAW,CAAA;IACjD,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,+DAA+D,CAAC,CAAA;IACzF,CAAC;IACD,IAAI,EAAE,IAAI,MAAM,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CACb,GAAG,IAAI,gCAAgC,cAAc,kDAAkD,CACxG,CAAA;IACH,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAA;IACnC,OAAO;QACL,IAAI,EAAE,WAAW;QACjB,EAAE,EAAE,SAAS;QACb,OAAO,EAAE,SAAS,GAAG,WAAW;QAChC,OAAO,EAAE,WAAW,KAAK,IAAI,IAAI,SAAS,KAAK,EAAE;KAClD,CAAA;AACH,CAAC;AAaD,MAAM,YAAY,GAAqC;IACrD,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,IAAI;IACP,CAAC,EAAE,WAAW;IACd,CAAC,EAAE,CAAC,GAAG,WAAW;CACnB,CAAA;AAED,+EAA+E;AAC/E,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC5C,IAAI,CAAC,KAAK;QACR,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,6DAA6D,CAAC,CAAA;IACzF,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;AAClD,CAAC;AAED,oEAAoE;AACpE,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAwC,EAAe,EAAE,CAAC,CAAC;IAClF,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,GAAG;IACtB,EAAE,EAAE,CAAC,CAAC,EAAE;CACT,CAAC,CAAA;AAEF,qFAAqF;AACrF,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,OAAe,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,WAAW,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAA;AAE1F,gDAAgD;AAChD,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,OAAe,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=query-honesty.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-honesty.test.d.ts","sourceRoot":"","sources":["../src/query-honesty.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,294 @@
1
+ import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
2
+ import { RETENTION_DAYS } from "./prometheus.js";
3
+ import * as queries from "./queries/index.js";
4
+ import { SCENARIOS, exportedQueryFunctions, recordingClient, } from "./query-scenarios.test-support.js";
5
+ /**
6
+ * Behavioural honesty guard (#336) over EVERY exported query function, on the
7
+ * shared scenarios (`query-scenarios.test-support.ts`):
8
+ *
9
+ * 1. Time windows — every range a PromQL reads lies inside
10
+ * `[now − retention, now]`: no `@` anchor in the future, no window
11
+ * reaching past the retention Prometheus still holds.
12
+ * 2. No data — against a Prometheus that holds nothing, each function says
13
+ * "unknown"/"not measured" (null, `unknown`, empty) instead of a plausible
14
+ * healthy 0: no 0 s duration, no 0 % rate, no `healthy` verdict.
15
+ * 3. Scope — every aggregate that takes an engine filter names the engines
16
+ * it covers, so a fleet figure never reads as one engine's.
17
+ * 4. No placeholders — with every label present, no result carries an empty
18
+ * string a query could never fill.
19
+ */
20
+ const NOW = Date.parse("2026-10-09T12:00:00Z");
21
+ const NOW_SECONDS = NOW / 1000;
22
+ const RETENTION_SECONDS = RETENTION_DAYS * 86_400;
23
+ beforeAll(() => {
24
+ vi.useFakeTimers({ toFake: ["Date"], now: NOW });
25
+ });
26
+ afterAll(() => {
27
+ vi.useRealTimers();
28
+ });
29
+ const UNIT_SECONDS = { s: 1, m: 60, h: 3600, d: 86_400, w: 604_800 };
30
+ /** Every `[<n><unit>]` range of a PromQL string, with its `@ <t>` anchor (else now). */
31
+ function windowsOf(promql) {
32
+ return [...promql.matchAll(/\[(\d+)([smhdw])\](?:\s*@\s*(\d+))?/g)].map((m) => {
33
+ const to = m[3] === undefined ? NOW_SECONDS : Number(m[3]);
34
+ return { from: to - Number(m[1]) * UNIT_SECONDS[m[2]], to, text: m[0] };
35
+ });
36
+ }
37
+ describe("query honesty — time windows", () => {
38
+ it.each(Object.entries(SCENARIOS))("%s reads only windows inside [now − retention, now]", async (_name, scenarios) => {
39
+ const outside = [];
40
+ for (const run of scenarios) {
41
+ const { ch, sent } = recordingClient();
42
+ await run(ch);
43
+ for (const promql of sent) {
44
+ for (const w of windowsOf(promql)) {
45
+ if (w.to > NOW_SECONDS)
46
+ outside.push(`future anchor ${w.text}: ${promql}`);
47
+ if (w.from < NOW_SECONDS - RETENTION_SECONDS) {
48
+ outside.push(`past retention ${w.text}: ${promql}`);
49
+ }
50
+ if (w.to <= w.from)
51
+ outside.push(`empty window ${w.text}: ${promql}`);
52
+ }
53
+ }
54
+ }
55
+ expect(outside).toEqual([]);
56
+ });
57
+ });
58
+ /**
59
+ * What each function must say when Prometheus holds no data at all — a total
60
+ * map over the `queries` namespace, so a new export has to state its no-data
61
+ * shape (`pnpm typecheck`).
62
+ */
63
+ const NO_DATA = {
64
+ analyzePerformance: (r) => {
65
+ expect(r.kpi).toBeNull();
66
+ expect(r.activityBreakdown).toEqual([]);
67
+ },
68
+ comparePeriods: (r) => {
69
+ for (const k of r.kpiComparison) {
70
+ expect(k).toMatchObject({
71
+ total_instances: 0,
72
+ incident_rate_pct: null,
73
+ avg_duration_sec: null,
74
+ median_sec: null,
75
+ p95_sec: null,
76
+ });
77
+ }
78
+ },
79
+ findFailedInstances: (r) => expect(r.patterns).toEqual([]),
80
+ elementBottleneck: (r) => expect(r.activities).toEqual([]),
81
+ elementHeat: (r) => expect({ frequency: r.frequency, durationSec: r.durationSec }).toEqual({
82
+ frequency: {},
83
+ durationSec: {},
84
+ }),
85
+ clusterCompare: (r) => {
86
+ expect(r.suppressed).toBe(true);
87
+ expectUnmeasuredCompare(r.kpis, r.delta);
88
+ },
89
+ versionCompare: (r) => {
90
+ expect(r.suppressed).toBe(true);
91
+ expectUnmeasuredCompare(r.kpis, r.delta);
92
+ },
93
+ engineCompare: (r) => {
94
+ expect(r.suppressed).toBe(true);
95
+ expectUnmeasuredCompare(r.kpis, r.delta);
96
+ },
97
+ engineLandscape: (r) => {
98
+ expect(r.engines.every((e) => !e.reporting)).toBe(true);
99
+ // A silent engine's counts are unknown, never a row of plausible zeros.
100
+ for (const e of r.engines) {
101
+ expect(e).toMatchObject({ runningInstances: null, openIncidents: null, executableJobs: null });
102
+ }
103
+ expect(r.totals).toMatchObject({
104
+ reportingEngineCount: 0,
105
+ runningInstances: null,
106
+ openIncidents: null,
107
+ failedJobs: null,
108
+ });
109
+ },
110
+ dashboardData: (r) => {
111
+ expect(r).toMatchObject({
112
+ totalCount: 0,
113
+ incidentRatePct: null,
114
+ avgDurationMs: null,
115
+ medianDurationMs: null,
116
+ p95DurationMs: null,
117
+ // No engine in scope reports: the live gauges are "not reported", never 0 running.
118
+ runningNow: null,
119
+ openIncidentsNow: null,
120
+ activityBreakdown: [],
121
+ activityCount: 0,
122
+ definitionBreakdown: [],
123
+ });
124
+ // Nothing started before either: no rate to judge against, and no verdict.
125
+ expect(r.previous).toMatchObject({ totalCount: 0, incidentRatePct: null, suppressed: true });
126
+ },
127
+ failureDashboardData: (r) => {
128
+ expect(r).toMatchObject({ totalIncidents: 0, mostAffectedProcess: null, errorPatterns: [] });
129
+ },
130
+ engineHealth: (r) => {
131
+ // Silence is not health.
132
+ expect(r.status).toBe("unknown");
133
+ expect(r.reportingEngines).toEqual([]);
134
+ expect(r.silentEngines).toEqual(r.engines ?? []);
135
+ },
136
+ };
137
+ function expectUnmeasuredCompare(kpis, delta) {
138
+ for (const k of kpis) {
139
+ // "Nothing ended" is no 0 s duration, "nothing started" no 0 % rate.
140
+ expect(k.avg_duration_sec).toBeNull();
141
+ expect(k.p95_duration_sec).toBeNull();
142
+ expect(k.incident_rate_pct).toBeNull();
143
+ }
144
+ // …so no delta against them either — never a −100 % from a missing value.
145
+ expect(Object.values(delta).every((v) => v === null)).toBe(true);
146
+ }
147
+ describe("query honesty — a Prometheus without data", () => {
148
+ it("states a no-data shape for every exported query function", () => {
149
+ expect(Object.keys(NO_DATA).sort()).toEqual(exportedQueryFunctions().sort());
150
+ });
151
+ it.each(Object.entries(SCENARIOS))("%s reports unknown / not measured, never a healthy zero", async (name, scenarios) => {
152
+ const expectNoData = NO_DATA[name];
153
+ for (const run of scenarios) {
154
+ const { ch } = recordingClient(() => []);
155
+ expectNoData(await run(ch));
156
+ }
157
+ });
158
+ });
159
+ /**
160
+ * The commonest live state — an engine that reports, with nothing open. The
161
+ * metrics plugin registers per-key gauge rows only for what exists, so with
162
+ * no incident open `camunda_incidents_open` has NO series at all while the
163
+ * engine's own presence gauges still answer. Every surface reading that state
164
+ * must say the same measured 0, never "not measured".
165
+ */
166
+ describe("query honesty — a reporting engine with nothing open", () => {
167
+ it("dashboard, failure dashboard, engine health and landscape agree on 0", async () => {
168
+ const { ch } = recordingClient((q) => q.includes("camunda_jobs_executable") || q.includes("camunda_external_tasks_open")
169
+ ? [{ metric: { engine_id: "prod-a" }, value: 0 }]
170
+ : []);
171
+ const engine = "prod-a";
172
+ const [dashboard, failures, health, landscape] = await Promise.all([
173
+ queries.dashboardData(ch, { period: "7d", engine }),
174
+ queries.failureDashboardData(ch, { engine }),
175
+ queries.engineHealth(ch, { engine }),
176
+ queries.engineLandscape(ch, { engine }),
177
+ ]);
178
+ expect(health.status).toBe("healthy");
179
+ expect({
180
+ dashboard: dashboard.openIncidentsNow,
181
+ failureDashboard: failures.totalIncidents,
182
+ engineHealth: health.openIncidents,
183
+ landscape: landscape.engines.find((e) => e.engineId === engine)?.openIncidents,
184
+ }).toEqual({ dashboard: 0, failureDashboard: 0, engineHealth: 0, landscape: 0 });
185
+ expect({ dashboard: dashboard.runningNow, engineHealth: health.runningInstances }).toEqual({
186
+ dashboard: 0,
187
+ engineHealth: 0,
188
+ });
189
+ });
190
+ });
191
+ const FLEET = ["prod-a", "prod-b"];
192
+ /**
193
+ * How each function states WHICH engines its numbers cover — a total map, so a
194
+ * new export has to decide. With `engine` omitted a figure is a fleet
195
+ * aggregate; unless the result names the engines, nobody reading it can tell
196
+ * one engine from the whole fleet.
197
+ */
198
+ const SCOPE_ECHO = {
199
+ analyzePerformance: {
200
+ echo: (ch, engine) => queries.analyzePerformance(ch, {
201
+ processDefinitionKey: "invoice",
202
+ period: "7d",
203
+ includeActivityBreakdown: false,
204
+ engine,
205
+ }),
206
+ },
207
+ comparePeriods: {
208
+ echo: (ch, engine) => queries.comparePeriods(ch, {
209
+ processDefinitionKey: "invoice",
210
+ periodAFrom: "2026-10-01T00:00:00Z",
211
+ periodATo: "2026-10-02T00:00:00Z",
212
+ periodBFrom: "2026-10-02T00:00:00Z",
213
+ periodBTo: "2026-10-03T00:00:00Z",
214
+ includeActivityBreakdown: false,
215
+ engine,
216
+ }),
217
+ },
218
+ findFailedInstances: {
219
+ echo: (ch, engine) => queries.findFailedInstances(ch, { maxResults: 5, engine }),
220
+ },
221
+ elementBottleneck: {
222
+ echo: (ch, engine) => queries.elementBottleneck(ch, {
223
+ processDefinitionKey: "invoice",
224
+ period: "7d",
225
+ minBucketSize: 1,
226
+ maxResults: 5,
227
+ engine,
228
+ }),
229
+ },
230
+ elementHeat: {
231
+ exempt: "heatmap values only — its show tool and feed carry the scope in their own payload (analytics-connector engine-scope.test.ts)",
232
+ },
233
+ clusterCompare: {
234
+ echo: (ch, engine) => queries.clusterCompare(ch, {
235
+ deploymentTimestamp: "2026-10-05T00:00:00Z",
236
+ windowBeforeDays: 3,
237
+ windowAfterDays: 3,
238
+ minBucketSize: 1,
239
+ engine,
240
+ }),
241
+ },
242
+ versionCompare: {
243
+ echo: (ch, engine) => queries.versionCompare(ch, {
244
+ processDefinitionKey: "invoice",
245
+ versionA: 1,
246
+ versionB: 2,
247
+ windowDays: 7,
248
+ minBucketSize: 1,
249
+ engine,
250
+ }),
251
+ },
252
+ engineCompare: { exempt: "partitions by exactly engineA and engineB, both echoed" },
253
+ engineLandscape: { exempt: "lists every engine it covers, one row each" },
254
+ dashboardData: {
255
+ echo: (ch, engine) => queries.dashboardData(ch, { period: "7d", engine }),
256
+ },
257
+ failureDashboardData: {
258
+ echo: (ch, engine) => queries.failureDashboardData(ch, { engine }),
259
+ },
260
+ engineHealth: { echo: (ch, engine) => queries.engineHealth(ch, { engine }) },
261
+ };
262
+ describe("query honesty — every aggregate names the engines it covers", () => {
263
+ it.each(Object.entries(SCOPE_ECHO))("%s", async (_name, rule) => {
264
+ if ("exempt" in rule)
265
+ return;
266
+ const { ch } = recordingClient();
267
+ expect((await rule.echo(ch, FLEET)).engines).toEqual(FLEET);
268
+ // Unscoped library call: `null` = every engine Prometheus holds — never a
269
+ // made-up list, never silently absent.
270
+ expect((await rule.echo(ch, [])).engines).toBeNull();
271
+ });
272
+ });
273
+ /** Every path in `value` whose value is the empty string. */
274
+ function emptyStrings(value, path = "$") {
275
+ if (value === "")
276
+ return [path];
277
+ if (Array.isArray(value))
278
+ return value.flatMap((v, i) => emptyStrings(v, `${path}[${i}]`));
279
+ if (value && typeof value === "object") {
280
+ return Object.entries(value).flatMap(([k, v]) => emptyStrings(v, `${path}.${k}`));
281
+ }
282
+ return [];
283
+ }
284
+ describe("query honesty — no placeholder fields", () => {
285
+ it.each(Object.entries(SCENARIOS))("%s fills every string field it returns", async (_name, scenarios) => {
286
+ for (const run of scenarios) {
287
+ // Every sample carries every label, so an empty string can only be a
288
+ // field no query fills — a placeholder posing as data.
289
+ const { ch } = recordingClient();
290
+ expect(emptyStrings(await run(ch))).toEqual([]);
291
+ }
292
+ });
293
+ });
294
+ //# sourceMappingURL=query-honesty.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-honesty.test.js","sourceRoot":"","sources":["../src/query-honesty.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Test support shared by the behavioural query guards — never imported by
3
+ * runtime code. One recording Prometheus client plus a representative
4
+ * argument set for EVERY exported query function, so each guard runs the
5
+ * same calls:
6
+ *
7
+ * - `metrics-contract-labels.test.ts` (#327) checks every label each sent
8
+ * PromQL names against the metrics contract;
9
+ * - `query-honesty.test.ts` (#336) checks the time window each PromQL reads
10
+ * and the shape each function returns when Prometheus has no data.
11
+ */
12
+ import type { PrometheusClient, PromSample } from "./prometheus.js";
13
+ import * as queries from "./queries/index.js";
14
+ /** One representative sample carrying every label a query may group or join on. */
15
+ export declare const REPRESENTATIVE_SAMPLE: PromSample;
16
+ export interface RecordingClient {
17
+ ch: PrometheusClient;
18
+ /** Every instant PromQL string, in the order it was sent. */
19
+ sent: string[];
20
+ }
21
+ /**
22
+ * PrometheusClient that records every instant PromQL string and answers each
23
+ * one with `answer` — by default a single {@link REPRESENTATIVE_SAMPLE}, so the
24
+ * result mapping runs too (a function that only queries further after
25
+ * non-empty data still gets there). Pass `() => []` for a Prometheus that
26
+ * holds no data at all.
27
+ */
28
+ export declare function recordingClient(answer?: (query: string) => PromSample[]): RecordingClient;
29
+ export type Scenario = (ch: PrometheusClient) => Promise<unknown>;
30
+ /**
31
+ * ISO timestamp `days` before now (whole days, at call time — so a guard that
32
+ * pins the clock sees windows relative to ITS now). Scenario windows must sit
33
+ * inside the retention or the query refuses them.
34
+ */
35
+ export declare const isoDaysAgo: (days: number) => string;
36
+ /**
37
+ * Representative argument sets for EVERY exported query function — typed as a
38
+ * total map over the `queries` namespace, so a new export without a scenario
39
+ * fails `pnpm typecheck` (and the runtime check in each guard). Between them
40
+ * the sets switch on every optional matcher: engine filter (single and multi),
41
+ * element scope, incident type, process scope present and absent, the
42
+ * breakdowns.
43
+ */
44
+ export declare const SCENARIOS: {
45
+ [K in keyof typeof queries]: Scenario[];
46
+ };
47
+ /** The exported query functions, by name — what the scenario map must cover. */
48
+ export declare function exportedQueryFunctions(): string[];
49
+ //# sourceMappingURL=query-scenarios.test-support.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-scenarios.test-support.d.ts","sourceRoot":"","sources":["../src/query-scenarios.test-support.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AACnE,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAA;AAE7C,mFAAmF;AACnF,eAAO,MAAM,qBAAqB,EAAE,UAWnC,CAAA;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,gBAAgB,CAAA;IACpB,6DAA6D;IAC7D,IAAI,EAAE,MAAM,EAAE,CAAA;CACf;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,MAAM,GAAE,CAAC,KAAK,EAAE,MAAM,KAAK,UAAU,EAAkC,GACtE,eAAe,CAWjB;AAED,MAAM,MAAM,QAAQ,GAAG,CAAC,EAAE,EAAE,gBAAgB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;AAEjE;;;;GAIG;AACH,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,WAA2D,CAAA;AAElG;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,EAAE;KAAG,CAAC,IAAI,MAAM,OAAO,OAAO,GAAG,QAAQ,EAAE;CAqGhE,CAAA;AAED,gFAAgF;AAChF,wBAAgB,sBAAsB,IAAI,MAAM,EAAE,CAIjD"}
@@ -0,0 +1,146 @@
1
+ import * as queries from "./queries/index.js";
2
+ /** One representative sample carrying every label a query may group or join on. */
3
+ export const REPRESENTATIVE_SAMPLE = {
4
+ metric: {
5
+ engine_id: "prod-a",
6
+ process_definition_key: "invoice",
7
+ activity_id: "Task_check",
8
+ activity_type: "serviceTask",
9
+ incident_type: "failedJob",
10
+ alertname: "CibSevenDeadJobs",
11
+ severity: "warning",
12
+ },
13
+ value: 1,
14
+ };
15
+ /**
16
+ * PrometheusClient that records every instant PromQL string and answers each
17
+ * one with `answer` — by default a single {@link REPRESENTATIVE_SAMPLE}, so the
18
+ * result mapping runs too (a function that only queries further after
19
+ * non-empty data still gets there). Pass `() => []` for a Prometheus that
20
+ * holds no data at all.
21
+ */
22
+ export function recordingClient(answer = () => [REPRESENTATIVE_SAMPLE]) {
23
+ const sent = [];
24
+ return {
25
+ ch: {
26
+ instant: (query) => {
27
+ sent.push(query);
28
+ return Promise.resolve(answer(query));
29
+ },
30
+ },
31
+ sent,
32
+ };
33
+ }
34
+ /**
35
+ * ISO timestamp `days` before now (whole days, at call time — so a guard that
36
+ * pins the clock sees windows relative to ITS now). Scenario windows must sit
37
+ * inside the retention or the query refuses them.
38
+ */
39
+ export const isoDaysAgo = (days) => new Date(Date.now() - days * 86_400_000).toISOString();
40
+ /**
41
+ * Representative argument sets for EVERY exported query function — typed as a
42
+ * total map over the `queries` namespace, so a new export without a scenario
43
+ * fails `pnpm typecheck` (and the runtime check in each guard). Between them
44
+ * the sets switch on every optional matcher: engine filter (single and multi),
45
+ * element scope, incident type, process scope present and absent, the
46
+ * breakdowns.
47
+ */
48
+ export const SCENARIOS = {
49
+ analyzePerformance: [
50
+ (ch) => queries.analyzePerformance(ch, {
51
+ processDefinitionKey: "invoice",
52
+ period: "7d",
53
+ includeActivityBreakdown: true,
54
+ engine: "prod-a",
55
+ }),
56
+ ],
57
+ comparePeriods: [
58
+ (ch) => queries.comparePeriods(ch, {
59
+ processDefinitionKey: "invoice",
60
+ periodAFrom: isoDaysAgo(14),
61
+ periodATo: isoDaysAgo(7),
62
+ periodBFrom: isoDaysAgo(7),
63
+ periodBTo: isoDaysAgo(0),
64
+ includeActivityBreakdown: true,
65
+ engine: ["prod-a", "prod-b"],
66
+ }),
67
+ ],
68
+ findFailedInstances: [
69
+ (ch) => queries.findFailedInstances(ch, {
70
+ processDefinitionKey: "invoice",
71
+ incidentType: "failedJob",
72
+ maxResults: 10,
73
+ engine: "prod-a",
74
+ }),
75
+ (ch) => queries.findFailedInstances(ch, { maxResults: 10 }),
76
+ ],
77
+ elementBottleneck: [
78
+ (ch) => queries.elementBottleneck(ch, {
79
+ processDefinitionKey: "invoice",
80
+ period: "7d",
81
+ minBucketSize: 1,
82
+ maxResults: 10,
83
+ engine: "prod-a",
84
+ }),
85
+ ],
86
+ elementHeat: [
87
+ (ch) => queries.elementHeat(ch, { processDefinitionKey: "invoice", period: "7d", engine: "a" }),
88
+ ],
89
+ clusterCompare: [
90
+ (ch) => queries.clusterCompare(ch, {
91
+ processDefinitionKey: "invoice",
92
+ activityId: "Task_check",
93
+ deploymentTimestamp: isoDaysAgo(10),
94
+ windowBeforeDays: 7,
95
+ windowAfterDays: 7,
96
+ minBucketSize: 1,
97
+ engine: "prod-a",
98
+ }),
99
+ // A recent deployment: the post-deploy window reaches past now.
100
+ (ch) => queries.clusterCompare(ch, {
101
+ deploymentTimestamp: isoDaysAgo(2),
102
+ windowBeforeDays: 7,
103
+ windowAfterDays: 7,
104
+ minBucketSize: 1,
105
+ }),
106
+ ],
107
+ versionCompare: [
108
+ (ch) => queries.versionCompare(ch, {
109
+ processDefinitionKey: "invoice",
110
+ versionA: 1,
111
+ versionB: 2,
112
+ windowDays: 14,
113
+ minBucketSize: 1,
114
+ engine: ["prod-a", "prod-b"],
115
+ }),
116
+ ],
117
+ engineCompare: [
118
+ (ch) => queries.engineCompare(ch, {
119
+ processDefinitionKey: "invoice",
120
+ engineA: "prod-a",
121
+ engineB: "prod-b",
122
+ windowDays: 14,
123
+ activityId: "Task_check",
124
+ minBucketSize: 1,
125
+ }),
126
+ ],
127
+ engineLandscape: [
128
+ (ch) => queries.engineLandscape(ch),
129
+ (ch) => queries.engineLandscape(ch, { engine: ["prod-a", "prod-b"] }),
130
+ ],
131
+ dashboardData: [
132
+ (ch) => queries.dashboardData(ch, { processDefinitionKey: "invoice", period: "7d" }),
133
+ (ch) => queries.dashboardData(ch, { period: "1d", engine: "prod-a" }),
134
+ ],
135
+ failureDashboardData: [(ch) => queries.failureDashboardData(ch, { engine: "prod-a" })],
136
+ engineHealth: [
137
+ (ch) => queries.engineHealth(ch, {}),
138
+ (ch) => queries.engineHealth(ch, { engine: "prod-a" }),
139
+ (ch) => queries.engineHealth(ch, { engine: ["prod-a", "prod-b"], includeFleetAlerts: true }),
140
+ ],
141
+ };
142
+ /** The exported query functions, by name — what the scenario map must cover. */
143
+ export function exportedQueryFunctions() {
144
+ return Object.keys(queries).filter((k) => typeof queries[k] === "function");
145
+ }
146
+ //# sourceMappingURL=query-scenarios.test-support.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-scenarios.test-support.js","sourceRoot":"","sources":["../src/query-scenarios.test-support.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { z } from "zod";
2
+ export declare const clusterCompareInput: z.ZodObject<{
3
+ engine: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
4
+ processDefinitionKey: z.ZodOptional<z.ZodString>;
5
+ activityId: z.ZodOptional<z.ZodString>;
6
+ deploymentTimestamp: z.ZodString;
7
+ windowBeforeDays: z.ZodDefault<z.ZodNumber>;
8
+ windowAfterDays: z.ZodDefault<z.ZodNumber>;
9
+ minBucketSize: z.ZodDefault<z.ZodNumber>;
10
+ }, z.core.$strip>;
11
+ //# sourceMappingURL=cluster-compare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cluster-compare.d.ts","sourceRoot":"","sources":["../../src/schemas/cluster-compare.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,mBAAmB;;;;;;;;iBAiC9B,CAAA"}
@@ -0,0 +1,35 @@
1
+ import { z } from "zod";
2
+ import { engineFilterShape, isoDatetimeString } from "./shared.js";
3
+ export const clusterCompareInput = z.object({
4
+ processDefinitionKey: z
5
+ .string()
6
+ .optional()
7
+ .describe("Restrict to a single process definition (optional)"),
8
+ activityId: z
9
+ .string()
10
+ .optional()
11
+ .describe("Also count the incidents at this BPMN element (element_incident_*; optional)"),
12
+ deploymentTimestamp: isoDatetimeString.describe("Deployment timestamp (ISO datetime). Pulled from camunda7_get_deployment."),
13
+ windowBeforeDays: z
14
+ .number()
15
+ .int()
16
+ .min(1)
17
+ .max(30)
18
+ .default(7)
19
+ .describe("Window size before the deployment, in days (max 30 — Prometheus retention)"),
20
+ windowAfterDays: z
21
+ .number()
22
+ .int()
23
+ .min(1)
24
+ .max(30)
25
+ .default(7)
26
+ .describe("Window size after the deployment, in days (max 30); clamped to now"),
27
+ minBucketSize: z
28
+ .number()
29
+ .int()
30
+ .min(1)
31
+ .default(10)
32
+ .describe("Minimum started and completed instances per window before results are trusted"),
33
+ ...engineFilterShape,
34
+ });
35
+ //# sourceMappingURL=cluster-compare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cluster-compare.js","sourceRoot":"","sources":["../../src/schemas/cluster-compare.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAElE,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,oBAAoB,EAAE,CAAC;SACpB,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,oDAAoD,CAAC;IACjE,UAAU,EAAE,CAAC;SACV,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,8EAA8E,CAAC;IAC3F,mBAAmB,EAAE,iBAAiB,CAAC,QAAQ,CAC7C,2EAA2E,CAC5E;IACD,gBAAgB,EAAE,CAAC;SAChB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,EAAE,CAAC;SACP,OAAO,CAAC,CAAC,CAAC;SACV,QAAQ,CAAC,4EAA4E,CAAC;IACzF,eAAe,EAAE,CAAC;SACf,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,EAAE,CAAC;SACP,OAAO,CAAC,CAAC,CAAC;SACV,QAAQ,CAAC,oEAAoE,CAAC;IACjF,aAAa,EAAE,CAAC;SACb,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,OAAO,CAAC,EAAE,CAAC;SACX,QAAQ,CAAC,+EAA+E,CAAC;IAC5F,GAAG,iBAAiB;CACrB,CAAC,CAAA"}