@uptimizr/db 2.0.1 → 2.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.
Files changed (171) hide show
  1. package/AGENTS.md +228 -3
  2. package/README.md +13 -0
  3. package/dist/duckdb/migrations.d.ts.map +1 -1
  4. package/dist/duckdb/migrations.js +169 -0
  5. package/dist/duckdb/migrations.js.map +1 -1
  6. package/dist/duckdb/panelSpecs.d.ts +29 -0
  7. package/dist/duckdb/panelSpecs.d.ts.map +1 -0
  8. package/dist/duckdb/panelSpecs.js +104 -0
  9. package/dist/duckdb/panelSpecs.js.map +1 -0
  10. package/dist/duckdb/projectMetadata.d.ts +43 -0
  11. package/dist/duckdb/projectMetadata.d.ts.map +1 -0
  12. package/dist/duckdb/projectMetadata.js +222 -0
  13. package/dist/duckdb/projectMetadata.js.map +1 -0
  14. package/dist/duckdb/subscriptions.d.ts +45 -0
  15. package/dist/duckdb/subscriptions.d.ts.map +1 -0
  16. package/dist/duckdb/subscriptions.js +202 -0
  17. package/dist/duckdb/subscriptions.js.map +1 -0
  18. package/dist/index.d.ts +18 -4
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +48 -3
  21. package/dist/index.js.map +1 -1
  22. package/dist/insights/anomalies.d.ts +213 -0
  23. package/dist/insights/anomalies.d.ts.map +1 -0
  24. package/dist/insights/anomalies.js +340 -0
  25. package/dist/insights/anomalies.js.map +1 -0
  26. package/dist/insights/baseline.d.ts +51 -0
  27. package/dist/insights/baseline.d.ts.map +1 -0
  28. package/dist/insights/baseline.js +48 -0
  29. package/dist/insights/baseline.js.map +1 -0
  30. package/dist/insights/buckets.d.ts +114 -0
  31. package/dist/insights/buckets.d.ts.map +1 -0
  32. package/dist/insights/buckets.js +220 -0
  33. package/dist/insights/buckets.js.map +1 -0
  34. package/dist/insights/changepoint.d.ts +130 -0
  35. package/dist/insights/changepoint.d.ts.map +1 -0
  36. package/dist/insights/changepoint.js +209 -0
  37. package/dist/insights/changepoint.js.map +1 -0
  38. package/dist/insights/evaluate.d.ts +63 -0
  39. package/dist/insights/evaluate.d.ts.map +1 -0
  40. package/dist/insights/evaluate.js +158 -0
  41. package/dist/insights/evaluate.js.map +1 -0
  42. package/dist/insights/health.d.ts +219 -0
  43. package/dist/insights/health.d.ts.map +1 -0
  44. package/dist/insights/health.js +349 -0
  45. package/dist/insights/health.js.map +1 -0
  46. package/dist/insights/index.d.ts +45 -0
  47. package/dist/insights/index.d.ts.map +1 -0
  48. package/dist/insights/index.js +40 -0
  49. package/dist/insights/index.js.map +1 -0
  50. package/dist/insights/measures.d.ts +222 -0
  51. package/dist/insights/measures.d.ts.map +1 -0
  52. package/dist/insights/measures.js +431 -0
  53. package/dist/insights/measures.js.map +1 -0
  54. package/dist/insights/movers.d.ts +123 -0
  55. package/dist/insights/movers.d.ts.map +1 -0
  56. package/dist/insights/movers.js +166 -0
  57. package/dist/insights/movers.js.map +1 -0
  58. package/dist/insights/significance.d.ts +221 -0
  59. package/dist/insights/significance.d.ts.map +1 -0
  60. package/dist/insights/significance.js +531 -0
  61. package/dist/insights/significance.js.map +1 -0
  62. package/dist/insights/stats.d.ts +104 -0
  63. package/dist/insights/stats.d.ts.map +1 -0
  64. package/dist/insights/stats.js +181 -0
  65. package/dist/insights/stats.js.map +1 -0
  66. package/dist/insights/windows.d.ts +95 -0
  67. package/dist/insights/windows.d.ts.map +1 -0
  68. package/dist/insights/windows.js +97 -0
  69. package/dist/insights/windows.js.map +1 -0
  70. package/dist/metadata.d.ts +178 -1
  71. package/dist/metadata.d.ts.map +1 -1
  72. package/dist/metadata.js +80 -0
  73. package/dist/metadata.js.map +1 -1
  74. package/dist/narrative/build.d.ts +78 -0
  75. package/dist/narrative/build.d.ts.map +1 -0
  76. package/dist/narrative/build.js +437 -0
  77. package/dist/narrative/build.js.map +1 -0
  78. package/dist/narrative/index.d.ts +14 -0
  79. package/dist/narrative/index.d.ts.map +1 -0
  80. package/dist/narrative/index.js +13 -0
  81. package/dist/narrative/index.js.map +1 -0
  82. package/dist/narrative/text.d.ts +25 -0
  83. package/dist/narrative/text.d.ts.map +1 -0
  84. package/dist/narrative/text.js +41 -0
  85. package/dist/narrative/text.js.map +1 -0
  86. package/dist/parity/cases.d.ts +3 -0
  87. package/dist/parity/cases.d.ts.map +1 -1
  88. package/dist/parity/cases.js +387 -7
  89. package/dist/parity/cases.js.map +1 -1
  90. package/dist/parity/compare.d.ts +19 -0
  91. package/dist/parity/compare.d.ts.map +1 -1
  92. package/dist/parity/compare.js +19 -0
  93. package/dist/parity/compare.js.map +1 -1
  94. package/dist/parity/fixtures.d.ts.map +1 -1
  95. package/dist/parity/fixtures.js +25 -0
  96. package/dist/parity/fixtures.js.map +1 -1
  97. package/dist/query/aggregations.d.ts +46 -1
  98. package/dist/query/aggregations.d.ts.map +1 -1
  99. package/dist/query/aggregations.js +86 -0
  100. package/dist/query/aggregations.js.map +1 -1
  101. package/dist/query/clickhouseDialect.d.ts.map +1 -1
  102. package/dist/query/clickhouseDialect.js +5 -1
  103. package/dist/query/clickhouseDialect.js.map +1 -1
  104. package/dist/query/customEventVocabulary.d.ts +46 -0
  105. package/dist/query/customEventVocabulary.d.ts.map +1 -0
  106. package/dist/query/customEventVocabulary.js +127 -0
  107. package/dist/query/customEventVocabulary.js.map +1 -0
  108. package/dist/query/dsl/builders.d.ts +38 -0
  109. package/dist/query/dsl/builders.d.ts.map +1 -0
  110. package/dist/query/dsl/builders.js +35 -0
  111. package/dist/query/dsl/builders.js.map +1 -0
  112. package/dist/query/dsl/compare.d.ts +167 -0
  113. package/dist/query/dsl/compare.d.ts.map +1 -0
  114. package/dist/query/dsl/compare.js +358 -0
  115. package/dist/query/dsl/compare.js.map +1 -0
  116. package/dist/query/dsl/compile.d.ts +89 -0
  117. package/dist/query/dsl/compile.d.ts.map +1 -0
  118. package/dist/query/dsl/compile.js +174 -0
  119. package/dist/query/dsl/compile.js.map +1 -0
  120. package/dist/query/dsl/explain.d.ts +115 -0
  121. package/dist/query/dsl/explain.d.ts.map +1 -0
  122. package/dist/query/dsl/explain.js +143 -0
  123. package/dist/query/dsl/explain.js.map +1 -0
  124. package/dist/query/dsl/generic.d.ts +127 -0
  125. package/dist/query/dsl/generic.d.ts.map +1 -0
  126. package/dist/query/dsl/generic.js +323 -0
  127. package/dist/query/dsl/generic.js.map +1 -0
  128. package/dist/query/dsl/index.d.ts +30 -0
  129. package/dist/query/dsl/index.d.ts.map +1 -0
  130. package/dist/query/dsl/index.js +23 -0
  131. package/dist/query/dsl/index.js.map +1 -0
  132. package/dist/query/dsl/order.d.ts +41 -0
  133. package/dist/query/dsl/order.d.ts.map +1 -0
  134. package/dist/query/dsl/order.js +55 -0
  135. package/dist/query/dsl/order.js.map +1 -0
  136. package/dist/query/dsl/significance.d.ts +130 -0
  137. package/dist/query/dsl/significance.d.ts.map +1 -0
  138. package/dist/query/dsl/significance.js +224 -0
  139. package/dist/query/dsl/significance.js.map +1 -0
  140. package/dist/query/index.d.ts +2 -0
  141. package/dist/query/index.d.ts.map +1 -1
  142. package/dist/query/index.js +8 -0
  143. package/dist/query/index.js.map +1 -1
  144. package/dist/query/summary/index.d.ts +4 -2
  145. package/dist/query/summary/index.d.ts.map +1 -1
  146. package/dist/query/summary/index.js +2 -1
  147. package/dist/query/summary/index.js.map +1 -1
  148. package/dist/query/summary/labels.d.ts +101 -0
  149. package/dist/query/summary/labels.d.ts.map +1 -0
  150. package/dist/query/summary/labels.js +261 -0
  151. package/dist/query/summary/labels.js.map +1 -0
  152. package/dist/query/summary/reading.d.ts.map +1 -1
  153. package/dist/query/summary/reading.js +21 -2
  154. package/dist/query/summary/reading.js.map +1 -1
  155. package/dist/query/summary/schema.d.ts +250 -20
  156. package/dist/query/summary/schema.d.ts.map +1 -1
  157. package/dist/query/summary/schema.js +135 -123
  158. package/dist/query/summary/schema.js.map +1 -1
  159. package/dist/query/summary/summarize.d.ts.map +1 -1
  160. package/dist/query/summary/summarize.js +91 -5
  161. package/dist/query/summary/summarize.js.map +1 -1
  162. package/dist/query/summary/types.d.ts +77 -2
  163. package/dist/query/summary/types.d.ts.map +1 -1
  164. package/dist/query/types.d.ts +47 -1
  165. package/dist/query/types.d.ts.map +1 -1
  166. package/dist/subscriptions.d.ts +208 -0
  167. package/dist/subscriptions.d.ts.map +1 -0
  168. package/dist/subscriptions.js +153 -0
  169. package/dist/subscriptions.js.map +1 -0
  170. package/llms.txt +9 -0
  171. package/package.json +8 -8
@@ -0,0 +1,167 @@
1
+ /**
2
+ * **`compare`: what changed** (ADR 0051 §3/§4, design sketch §C.2).
3
+ *
4
+ * The first of the three things an agent cannot do today. A model asked "is the
5
+ * statue getting less attention than last week?" currently runs two queries,
6
+ * eyeballs two lists of different lengths in different orders, and reports a
7
+ * difference it computed in prose — which is where the arithmetic goes wrong,
8
+ * every time.
9
+ *
10
+ * `compare` runs the *same* validated spec twice — once with the query's own
11
+ * range and segment, once with the comparison's — and joins the two results
12
+ * **here, in TypeScript**, on the dimension key. Not in SQL: a self-join over
13
+ * two windows would have to be written per dialect, would double the parity
14
+ * surface, and would make the "one SQL path" property of the DSL false. The join
15
+ * is a `Map` over at most `limits.maxRows` rows on each side.
16
+ *
17
+ * Everything in this module is pure: rows in, rows out. It never runs a query —
18
+ * the collector does that twice and hands both results here.
19
+ *
20
+ * ## Which rows are joined
21
+ *
22
+ * On the **key columns**: the output columns of the grouping dimensions (the
23
+ * query's, or the metric's own grain). A `bucket`-grain metric's axis is
24
+ * deliberately *not* a key — two ranges have different buckets, so joining on
25
+ * them would produce two disjoint sets and zero matches. Its buckets are
26
+ * collapsed per key instead, and the per-bucket values feed
27
+ * {@link import("./significance.js").welchT} as two samples, which is the one
28
+ * place a t-test on this data is honest.
29
+ *
30
+ * A key present on one side only is still a row: `previous: null` is an arrival
31
+ * and `current: null` a disappearance, and both are usually the answer.
32
+ *
33
+ * ## Significance, only where it is earned
34
+ *
35
+ * For a count or session measure the row's share of its window is a proportion,
36
+ * so a pooled two-proportion z answers "is this share different" — and that is
37
+ * computed only when both windows clear the metric's `comparable.minSample`.
38
+ * For anything else (`fps`, a ratio, a duration average) the field is **absent**
39
+ * rather than guessed, and a caveat says why. An agent that is handed a p-value
40
+ * will quote it; handing it one that the data cannot support is worse than
41
+ * handing it none.
42
+ */
43
+ import { type MetricDefinition, type MetricId } from "@uptimizr/metrics";
44
+ import type { AppliedFilters, ResultRange, SampleSize, SummaryMeasure } from "../summary/types.js";
45
+ import { type MeanSignificance, type Significance } from "./significance.js";
46
+ /** A row as it leaves a store. */
47
+ type Row = Readonly<Record<string, unknown>>;
48
+ /** What the second run varied: the time window, or the slice. */
49
+ export type ComparisonBasis = "range" | "segment";
50
+ /** One side of a comparison, described well enough to be quoted on its own. */
51
+ export interface ComparisonSide {
52
+ range: ResultRange;
53
+ /** The dimensions held fixed on this side, when the basis is `segment`. */
54
+ segment: AppliedFilters;
55
+ /** Rows the store returned before the join. */
56
+ rows: number;
57
+ /** Sum of the measure across those rows; `null` when it cannot be summed. */
58
+ total: number | null;
59
+ sampleSize: SampleSize;
60
+ }
61
+ /** One joined row: the same key, measured twice. */
62
+ export interface ComparisonRow {
63
+ /** The dimension values that identify this row, keyed by output column. */
64
+ key: Readonly<Record<string, string>>;
65
+ /** The row's label — its key columns joined, so a reading can name it. */
66
+ label: string;
67
+ current: number | null;
68
+ previous: number | null;
69
+ /** `current - previous`; `null` when either side is missing. */
70
+ delta: number | null;
71
+ /** `delta / previous`; `null` when `previous` is missing, zero or negative. */
72
+ deltaPct: number | null;
73
+ /** Present only where the registry justifies a test — see the module doc. */
74
+ significance?: Significance;
75
+ }
76
+ /** The envelope a `compare` query answers with. */
77
+ export interface ComparisonMeta {
78
+ metric: MetricId;
79
+ basis: ComparisonBasis;
80
+ /** The columns the two sides were joined on. */
81
+ keys: readonly string[];
82
+ measure: SummaryMeasure | null;
83
+ current: ComparisonSide;
84
+ previous: ComparisonSide;
85
+ /** Rows in the joined result. */
86
+ rows: number;
87
+ /** Whether either side hit its row cap, so a key may be missing from one. */
88
+ truncated: boolean;
89
+ /**
90
+ * Welch's t over the two windows' per-bucket values — present only for a
91
+ * `bucket`-grain metric whose measure is a mean, which is the only shape here
92
+ * that really is two samples.
93
+ */
94
+ overall?: MeanSignificance;
95
+ caveats: readonly string[];
96
+ }
97
+ /** `format=table` on a comparison: the envelope plus the joined rows. */
98
+ export interface ComparisonResult {
99
+ meta: ComparisonMeta;
100
+ rows: readonly ComparisonRow[];
101
+ }
102
+ /** `format=summary` on a comparison: the biggest movers, with a reading. */
103
+ export interface MoversSummary {
104
+ kind: "movers";
105
+ metric: MetricId;
106
+ basis: ComparisonBasis;
107
+ measure: SummaryMeasure | null;
108
+ current: ComparisonSide;
109
+ previous: ComparisonSide;
110
+ /** The rows that moved most, by absolute delta. Bounded by `maxSummaryRows`. */
111
+ top: readonly ComparisonRow[];
112
+ /** Rows the digest did not list individually. */
113
+ rest: {
114
+ rows: number;
115
+ delta: number | null;
116
+ };
117
+ overall?: MeanSignificance;
118
+ /** One sentence, templated from column semantics only — never model-written. */
119
+ reading: string;
120
+ caveats: readonly string[];
121
+ }
122
+ /** What the caller knows about the two runs that produced the rows. */
123
+ export interface ComparisonContext {
124
+ basis: ComparisonBasis;
125
+ /** The output columns the two sides are joined on. */
126
+ keys: readonly string[];
127
+ currentRange: ResultRange;
128
+ previousRange: ResultRange;
129
+ currentSegment?: Readonly<Record<string, string>>;
130
+ previousSegment?: Readonly<Record<string, string>>;
131
+ /** The row cap in force, so `truncated` can be derived. */
132
+ limit?: number;
133
+ /** Extra caveats true of this comparison only. */
134
+ caveats?: readonly string[];
135
+ /** Cap on the movers digest; defaults to the registry's `maxSummaryRows`. */
136
+ maxRows?: number;
137
+ }
138
+ /**
139
+ * The dimension output columns two sides of a comparison are joined on.
140
+ *
141
+ * Deliberately the *dimensions*, not "every non-numeric column": a metric's row
142
+ * can carry descriptive text (a scene name next to a scene id) that is not part
143
+ * of its identity, and joining on it would split a key in two whenever the
144
+ * description changed between the two windows.
145
+ */
146
+ export declare function comparisonKeys(metric: MetricDefinition, columns: readonly string[]): string[];
147
+ /**
148
+ * Join two runs of the same spec into one comparison.
149
+ *
150
+ * `current` and `previous` are the rows each run produced, already coerced by
151
+ * the store edge. Neither array is mutated, and nothing here reads a clock or a
152
+ * store.
153
+ */
154
+ export declare function compareRows(metric: MetricId | MetricDefinition, current: readonly Row[], previous: readonly Row[], ctx: ComparisonContext): ComparisonResult | null;
155
+ /**
156
+ * Turn a comparison into the bounded `format=summary` digest: the rows that
157
+ * moved most, and one sentence that says what happened.
158
+ *
159
+ * The sentence is templated from the registry's column semantics — the measure's
160
+ * name and unit, the metric's `comparable.direction` — and never written by a
161
+ * model, so two identical results always read identically.
162
+ */
163
+ export declare function summarizeComparison(metric: MetricId | MetricDefinition, comparison: ComparisonResult, ctx?: {
164
+ maxRows?: number;
165
+ }): MoversSummary | null;
166
+ export {};
167
+ //# sourceMappingURL=compare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compare.d.ts","sourceRoot":"","sources":["../../../src/query/dsl/compare.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,OAAO,EAAa,KAAK,gBAAgB,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAWpF,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACnG,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAE3B,kCAAkC;AAClC,KAAK,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAE7C,iEAAiE;AACjE,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,SAAS,CAAC;AAElD,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,WAAW,CAAC;IACnB,2EAA2E;IAC3E,OAAO,EAAE,cAAc,CAAC;IACxB,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;CACxB;AAED,oDAAoD;AACpD,MAAM,WAAW,aAAa;IAC5B,2EAA2E;IAC3E,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtC,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,gEAAgE;IAChE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED,mDAAmD;AACnD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,QAAQ,CAAC;IACjB,KAAK,EAAE,eAAe,CAAC;IACvB,gDAAgD;IAChD,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B,OAAO,EAAE,cAAc,CAAC;IACxB,QAAQ,EAAE,cAAc,CAAC;IACzB,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,SAAS,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5B;AAED,yEAAyE;AACzE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,SAAS,aAAa,EAAE,CAAC;CAChC;AAED,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,QAAQ,CAAC;IACjB,KAAK,EAAE,eAAe,CAAC;IACvB,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B,OAAO,EAAE,cAAc,CAAC;IACxB,QAAQ,EAAE,cAAc,CAAC;IACzB,gFAAgF;IAChF,GAAG,EAAE,SAAS,aAAa,EAAE,CAAC;IAC9B,iDAAiD;IACjD,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC7C,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5B;AAED,uEAAuE;AACvE,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,eAAe,CAAC;IACvB,sDAAsD;IACtD,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,YAAY,EAAE,WAAW,CAAC;IAC1B,aAAa,EAAE,WAAW,CAAC;IAC3B,cAAc,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAClD,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA0FD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAO7F;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,QAAQ,GAAG,gBAAgB,EACnC,OAAO,EAAE,SAAS,GAAG,EAAE,EACvB,QAAQ,EAAE,SAAS,GAAG,EAAE,EACxB,GAAG,EAAE,iBAAiB,GACrB,gBAAgB,GAAG,IAAI,CA0HzB;AAiDD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,QAAQ,GAAG,gBAAgB,EACnC,UAAU,EAAE,gBAAgB,EAC5B,GAAG,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7B,aAAa,GAAG,IAAI,CAmEtB"}
@@ -0,0 +1,358 @@
1
+ /**
2
+ * **`compare`: what changed** (ADR 0051 §3/§4, design sketch §C.2).
3
+ *
4
+ * The first of the three things an agent cannot do today. A model asked "is the
5
+ * statue getting less attention than last week?" currently runs two queries,
6
+ * eyeballs two lists of different lengths in different orders, and reports a
7
+ * difference it computed in prose — which is where the arithmetic goes wrong,
8
+ * every time.
9
+ *
10
+ * `compare` runs the *same* validated spec twice — once with the query's own
11
+ * range and segment, once with the comparison's — and joins the two results
12
+ * **here, in TypeScript**, on the dimension key. Not in SQL: a self-join over
13
+ * two windows would have to be written per dialect, would double the parity
14
+ * surface, and would make the "one SQL path" property of the DSL false. The join
15
+ * is a `Map` over at most `limits.maxRows` rows on each side.
16
+ *
17
+ * Everything in this module is pure: rows in, rows out. It never runs a query —
18
+ * the collector does that twice and hands both results here.
19
+ *
20
+ * ## Which rows are joined
21
+ *
22
+ * On the **key columns**: the output columns of the grouping dimensions (the
23
+ * query's, or the metric's own grain). A `bucket`-grain metric's axis is
24
+ * deliberately *not* a key — two ranges have different buckets, so joining on
25
+ * them would produce two disjoint sets and zero matches. Its buckets are
26
+ * collapsed per key instead, and the per-bucket values feed
27
+ * {@link import("./significance.js").welchT} as two samples, which is the one
28
+ * place a t-test on this data is honest.
29
+ *
30
+ * A key present on one side only is still a row: `previous: null` is an arrival
31
+ * and `current: null` a disappearance, and both are usually the answer.
32
+ *
33
+ * ## Significance, only where it is earned
34
+ *
35
+ * For a count or session measure the row's share of its window is a proportion,
36
+ * so a pooled two-proportion z answers "is this share different" — and that is
37
+ * computed only when both windows clear the metric's `comparable.minSample`.
38
+ * For anything else (`fps`, a ratio, a duration average) the field is **absent**
39
+ * rather than guessed, and a caveat says why. An agent that is handed a p-value
40
+ * will quote it; handing it one that the data cannot support is worse than
41
+ * handing it none.
42
+ */
43
+ import { getMetric } from "@uptimizr/metrics";
44
+ import { axisColumn, columnsOf, labelColumn, measureColumn, numberAt, sampleSizeOf, } from "../summary/columns.js";
45
+ import { formatNumber, formatShare } from "../summary/format.js";
46
+ import { isAdditiveUnit } from "../summary/format.js";
47
+ import { sampleOf, twoProportionZ, welchT, } from "./significance.js";
48
+ /** A key's identity as one string, so it can index a `Map`. */
49
+ function keyOf(row, keys) {
50
+ return keys.map((column) => `${column}=${String(row[column] ?? "")}`).join("\u0000");
51
+ }
52
+ /** The key columns' values, as the row reports them. */
53
+ function keyValues(row, keys) {
54
+ const out = {};
55
+ for (const column of keys)
56
+ out[column] = String(row[column] ?? "");
57
+ return out;
58
+ }
59
+ /** What `total` counts, and whether it may be summed at all. */
60
+ function measureOf(metric) {
61
+ const column = measureColumn(metric);
62
+ if (column == null)
63
+ return null;
64
+ const [name, semantics] = column;
65
+ return { column: name, unit: semantics.unit ?? null, additive: isAdditiveUnit(semantics.unit) };
66
+ }
67
+ /** One side's rows, collapsed to one value per key. */
68
+ function collapse(rows, keys, column, additive) {
69
+ const out = new Map();
70
+ for (const row of rows) {
71
+ const id = keyOf(row, keys);
72
+ const value = column == null ? null : numberAt(row, column);
73
+ const bucket = out.get(id) ?? { key: keyValues(row, keys), sum: 0, count: 0 };
74
+ if (value != null) {
75
+ bucket.sum += value;
76
+ bucket.count += 1;
77
+ }
78
+ out.set(id, bucket);
79
+ }
80
+ return new Map([...out].map(([id, bucket]) => [
81
+ id,
82
+ {
83
+ key: bucket.key,
84
+ // Several rows collapse into one key only for a `bucket`-grain metric,
85
+ // whose axis is not a join key. Counts add; means average, for the same
86
+ // reason the series summary averages them.
87
+ value: bucket.count === 0 ? null : additive ? bucket.sum : bucket.sum / bucket.count,
88
+ },
89
+ ]));
90
+ }
91
+ /** Per-bucket values of one side, for the Welch sample. */
92
+ function bucketValues(metric, rows, column, additive) {
93
+ const axis = axisColumn(metric)?.[0];
94
+ if (axis == null || column == null)
95
+ return [];
96
+ const buckets = new Map();
97
+ for (const row of rows) {
98
+ const value = numberAt(row, column);
99
+ if (value == null)
100
+ continue;
101
+ const id = String(row[axis] ?? "");
102
+ const bucket = buckets.get(id) ?? { sum: 0, count: 0 };
103
+ bucket.sum += value;
104
+ bucket.count += 1;
105
+ buckets.set(id, bucket);
106
+ }
107
+ return [...buckets.values()].map((bucket) => (additive ? bucket.sum : bucket.sum / bucket.count));
108
+ }
109
+ /** Sum a column over rows, or `null` when nothing was measurable. */
110
+ function totalOf(rows, column) {
111
+ if (column == null)
112
+ return null;
113
+ let total = 0;
114
+ let seen = false;
115
+ for (const row of rows) {
116
+ const value = numberAt(row, column);
117
+ if (value == null)
118
+ continue;
119
+ seen = true;
120
+ total += value;
121
+ }
122
+ return seen ? total : null;
123
+ }
124
+ /**
125
+ * The dimension output columns two sides of a comparison are joined on.
126
+ *
127
+ * Deliberately the *dimensions*, not "every non-numeric column": a metric's row
128
+ * can carry descriptive text (a scene name next to a scene id) that is not part
129
+ * of its identity, and joining on it would split a key in two whenever the
130
+ * description changed between the two windows.
131
+ */
132
+ export function comparisonKeys(metric, columns) {
133
+ // Only a real `axis: true` column is excluded. `axisColumn` falls back to the
134
+ // label for metrics that declare none, and the label is exactly what a
135
+ // leaderboard comparison must join on — dropping it would collapse every mesh
136
+ // into one unkeyed row.
137
+ const axis = columnsOf(metric).find(([, semantics]) => semantics.axis === true)?.[0];
138
+ return columns.filter((column) => column !== axis);
139
+ }
140
+ /**
141
+ * Join two runs of the same spec into one comparison.
142
+ *
143
+ * `current` and `previous` are the rows each run produced, already coerced by
144
+ * the store edge. Neither array is mutated, and nothing here reads a clock or a
145
+ * store.
146
+ */
147
+ export function compareRows(metric, current, previous, ctx) {
148
+ const definition = typeof metric === "string" ? getMetric(metric) : metric;
149
+ if (definition == null)
150
+ return null;
151
+ const measure = measureOf(definition);
152
+ const column = measure?.column;
153
+ const additive = measure?.additive === true;
154
+ const keys = [...ctx.keys];
155
+ const currentTotal = totalOf(current, column);
156
+ const previousTotal = totalOf(previous, column);
157
+ const currentByKey = collapse(current, keys, column, additive);
158
+ const previousByKey = collapse(previous, keys, column, additive);
159
+ // A proportion test needs a denominator that means something: a count or a
160
+ // session count, present on both sides, and past the metric's own minimum.
161
+ const minSample = definition.comparable?.minSample ?? 0;
162
+ const proportional = (measure?.unit === "count" || measure?.unit === "sessions") &&
163
+ currentTotal != null &&
164
+ previousTotal != null &&
165
+ currentTotal >= minSample &&
166
+ previousTotal >= minSample &&
167
+ currentTotal > 0 &&
168
+ previousTotal > 0;
169
+ const ids = new Set([...currentByKey.keys(), ...previousByKey.keys()]);
170
+ const rows = [];
171
+ for (const id of ids) {
172
+ const left = currentByKey.get(id);
173
+ const right = previousByKey.get(id);
174
+ const key = left?.key ?? right?.key ?? {};
175
+ const currentValue = left?.value ?? null;
176
+ const previousValue = right?.value ?? null;
177
+ const delta = currentValue != null && previousValue != null ? currentValue - previousValue : null;
178
+ const significance = proportional && currentValue != null && previousValue != null
179
+ ? twoProportionZ({ successes: currentValue, trials: currentTotal }, { successes: previousValue, trials: previousTotal })
180
+ : null;
181
+ rows.push({
182
+ key,
183
+ label: keys.map((name) => String(key[name] ?? "")).join(" · "),
184
+ current: currentValue,
185
+ previous: previousValue,
186
+ delta,
187
+ deltaPct: delta != null && previousValue != null && previousValue > 0 ? delta / previousValue : null,
188
+ ...(significance != null ? { significance } : {}),
189
+ });
190
+ }
191
+ // Biggest absolute movement first, then alphabetically, so the order is a
192
+ // function of the data rather than of iteration order.
193
+ rows.sort((a, b) => {
194
+ const left = Math.abs(a.delta ?? 0);
195
+ const right = Math.abs(b.delta ?? 0);
196
+ if (left !== right)
197
+ return right - left;
198
+ return a.label < b.label ? -1 : a.label > b.label ? 1 : 0;
199
+ });
200
+ const overall = definition.grain === "bucket" && measure != null && !measure.additive
201
+ ? welchOf(definition, current, previous, column, additive)
202
+ : null;
203
+ const cap = ctx.limit ?? definition.limits.maxRows;
204
+ const truncated = Number.isFinite(cap) && (current.length >= cap || previous.length >= cap);
205
+ const caveats = [...definition.caveats, ...(ctx.caveats ?? [])];
206
+ if (!proportional) {
207
+ caveats.push(measure?.unit === "count" || measure?.unit === "sessions"
208
+ ? `Neither window reaches the ${minSample}-${measure.unit === "sessions" ? "session" : "event"} ` +
209
+ "minimum this metric declares, so no significance is reported — read the deltas as " +
210
+ "direction only."
211
+ : "This metric's measure is not a count, so a row's share of the window is not a " +
212
+ "proportion and no significance test applies. The deltas are still exact.");
213
+ }
214
+ if (truncated) {
215
+ caveats.push(`One or both windows hit the ${cap}-row cap, so a key missing from a side may be truncated ` +
216
+ "rather than absent.");
217
+ }
218
+ if (keys.length === 0) {
219
+ caveats.push("This metric has no dimension key, so the comparison is a single total per window.");
220
+ }
221
+ return {
222
+ meta: {
223
+ metric: definition.id,
224
+ basis: ctx.basis,
225
+ keys,
226
+ measure,
227
+ current: {
228
+ range: ctx.currentRange,
229
+ segment: { ...(ctx.currentSegment ?? {}) },
230
+ rows: current.length,
231
+ total: currentTotal,
232
+ sampleSize: sampleSizeOf(definition, current),
233
+ },
234
+ previous: {
235
+ range: ctx.previousRange,
236
+ segment: { ...(ctx.previousSegment ?? {}) },
237
+ rows: previous.length,
238
+ total: previousTotal,
239
+ sampleSize: sampleSizeOf(definition, previous),
240
+ },
241
+ rows: rows.length,
242
+ truncated,
243
+ ...(overall != null ? { overall } : {}),
244
+ caveats,
245
+ },
246
+ rows,
247
+ };
248
+ }
249
+ /** Welch's t over the two windows' per-bucket values. */
250
+ function welchOf(metric, current, previous, column, additive) {
251
+ const left = sampleOf(bucketValues(metric, current, column, additive));
252
+ const right = sampleOf(bucketValues(metric, previous, column, additive));
253
+ if (left == null || right == null)
254
+ return null;
255
+ return welchT(left, right);
256
+ }
257
+ /**
258
+ * The headline when one side has no rows at all.
259
+ *
260
+ * "The two windows cannot be totalled" would be true and useless: what actually
261
+ * happened is that one of them is empty, and saying which is the whole answer —
262
+ * a metric that appeared or disappeared between two windows is the single most
263
+ * interesting thing a comparison can report.
264
+ */
265
+ function emptySideHeadline(title, measure, meta) {
266
+ const side = meta.basis === "range" ? "window" : "segment";
267
+ if (meta.current.total != null) {
268
+ return (`${title}: \`${measure}\` totalled ${formatNumber(meta.current.total)} in this ${side}, ` +
269
+ `and the comparison ${side} has no rows at all — everything here is new.`);
270
+ }
271
+ if (meta.previous.total != null) {
272
+ return (`${title}: this ${side} has no rows at all, against ${formatNumber(meta.previous.total)} ` +
273
+ `in the comparison ${side} — everything there has gone.`);
274
+ }
275
+ return `${title}: neither ${side} has any \`${measure}\` to compare.`;
276
+ }
277
+ /** How a delta reads in prose. */
278
+ function movement(delta) {
279
+ if (delta == null)
280
+ return "changed";
281
+ if (delta > 0)
282
+ return "rose";
283
+ if (delta < 0)
284
+ return "fell";
285
+ return "held";
286
+ }
287
+ /**
288
+ * Turn a comparison into the bounded `format=summary` digest: the rows that
289
+ * moved most, and one sentence that says what happened.
290
+ *
291
+ * The sentence is templated from the registry's column semantics — the measure's
292
+ * name and unit, the metric's `comparable.direction` — and never written by a
293
+ * model, so two identical results always read identically.
294
+ */
295
+ export function summarizeComparison(metric, comparison, ctx = {}) {
296
+ const definition = typeof metric === "string" ? getMetric(metric) : metric;
297
+ if (definition == null)
298
+ return null;
299
+ const cap = Math.max(0, ctx.maxRows ?? definition.limits.maxSummaryRows);
300
+ const top = comparison.rows.slice(0, cap);
301
+ const restRows = comparison.rows.slice(cap);
302
+ const restDelta = restRows.reduce((sum, row) => (row.delta == null ? sum : (sum ?? 0) + row.delta), null);
303
+ const { meta } = comparison;
304
+ const measureName = meta.measure?.column ?? "the measure";
305
+ const totalDelta = meta.current.total != null && meta.previous.total != null
306
+ ? meta.current.total - meta.previous.total
307
+ : null;
308
+ const totalPct = totalDelta != null && meta.previous.total != null && meta.previous.total > 0
309
+ ? totalDelta / meta.previous.total
310
+ : null;
311
+ const window = meta.basis === "range" ? "against the comparison window" : "against the comparison segment";
312
+ const headline = totalDelta == null
313
+ ? emptySideHeadline(definition.title, measureName, meta)
314
+ : `${definition.title}: \`${measureName}\` ${movement(totalDelta)} from ` +
315
+ `${formatNumber(meta.previous.total)} to ${formatNumber(meta.current.total)} ` +
316
+ `(${totalDelta >= 0 ? "+" : ""}${formatNumber(totalDelta)}` +
317
+ `${totalPct == null ? "" : `, ${totalPct >= 0 ? "+" : ""}${formatShare(totalPct)}`}) ${window}.`;
318
+ const biggest = top[0];
319
+ const mover = biggest == null || biggest.delta == null || biggest.label.length === 0
320
+ ? ""
321
+ : ` Biggest mover: ${labelNoun(definition)} \`${biggest.label}\`, ` +
322
+ `${formatNumber(biggest.previous)} → ${formatNumber(biggest.current)} ` +
323
+ `(${biggest.delta >= 0 ? "+" : ""}${formatNumber(biggest.delta)})` +
324
+ `${biggest.significance?.test === "two-proportion-z"
325
+ ? biggest.significance.significant
326
+ ? `, significant at p = ${formatPValue(biggest.significance.pValue)}`
327
+ : `, not significant (p = ${formatPValue(biggest.significance.pValue)})`
328
+ : ""}.`;
329
+ const trend = meta.overall == null
330
+ ? ""
331
+ : ` Across buckets, the mean moved ${formatNumber(meta.overall.previous)} → ` +
332
+ `${formatNumber(meta.overall.current)} (Welch t = ${formatNumber(meta.overall.t)}, ` +
333
+ `p = ${formatPValue(meta.overall.pValue)}).`;
334
+ return {
335
+ kind: "movers",
336
+ metric: definition.id,
337
+ basis: meta.basis,
338
+ measure: meta.measure,
339
+ current: meta.current,
340
+ previous: meta.previous,
341
+ top,
342
+ rest: { rows: restRows.length, delta: restDelta },
343
+ ...(meta.overall != null ? { overall: meta.overall } : {}),
344
+ reading: `${headline}${mover}${trend}`,
345
+ caveats: meta.caveats,
346
+ };
347
+ }
348
+ /** What one row of this metric is called, for the reading sentence. */
349
+ function labelNoun(metric) {
350
+ return labelColumn(metric)?.[0] ?? metric.grain;
351
+ }
352
+ /** A p-value at three decimals, or `< 0.001` when it is smaller than that. */
353
+ function formatPValue(p) {
354
+ if (!Number.isFinite(p))
355
+ return "n/a";
356
+ return p < 0.001 ? "< 0.001" : p.toFixed(3);
357
+ }
358
+ //# sourceMappingURL=compare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compare.js","sourceRoot":"","sources":["../../../src/query/dsl/compare.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * **The delegated query compiler** (ADR 0051 §3, design sketch §C.2, tier 1).
3
+ *
4
+ * A validated `queryV1` document becomes a `QuerySpec` by way of the metric's
5
+ * *existing* aggregation builder: the registry says which `build*` computes the
6
+ * metric, `FILTER_TARGETS` says which option field each filter drives, and the
7
+ * builder renders the SQL it has always rendered, through the same `Dialect`.
8
+ *
9
+ * That is the point of the delegated tier. Every registry metric is reachable
10
+ * through the DSL on day one at exactly the power its canned endpoint has — no
11
+ * second SQL path, no "DSL-only" subset of metrics, and nothing new for the
12
+ * cross-engine parity harness to cover, because the specs it compiles *are* the
13
+ * specs the parity cases already pin (`src/__tests__/queryDsl.test.ts` asserts
14
+ * that equality builder by builder, on all four dialects).
15
+ *
16
+ * It also means the DSL inherits the two properties that matter most and cannot
17
+ * be bolted on afterwards: every value reaches SQL as a bound parameter (the
18
+ * builders' `ParamBag`), and the returned spec carries its `metric`, so the
19
+ * store edge coerces the rows (`coerceRows`, ADR 0051 §2) without knowing a DSL
20
+ * exists.
21
+ *
22
+ * What this module does **not** do: validate. A query must already have passed
23
+ * `queryV1Schema` (shape) and `validateQuery` (vocabulary) — by the time it gets
24
+ * here, the metric exists, has a builder, accepts every filter named, and asks
25
+ * for a grain it can produce. The two `throw`s below are guards against a caller
26
+ * skipping that, not a client-facing error path.
27
+ */
28
+ import { type MetricId, type QueryTier } from "@uptimizr/metrics";
29
+ import type { QueryV1 } from "@uptimizr/schema";
30
+ import type { Dialect } from "../dialect.js";
31
+ import type { QuerySpec, WorldAabb } from "../types.js";
32
+ /**
33
+ * The option bag an aggregation builder takes, assembled from a query. Loosely
34
+ * typed for the reason given on {@link import("./builders.js").AggregationBuilder}:
35
+ * each builder's own options are a different intersection, and what makes the
36
+ * bag correct is registry validation upstream, not a type here.
37
+ */
38
+ export type MetricQueryOptions = Readonly<Record<string, unknown>>;
39
+ /**
40
+ * The dashboard's camera-mode toggle → the `scene.cameraType` the events carry
41
+ * (ADR 0026). The same mapping the canned routes apply; it lives here too so a
42
+ * DSL query and a `?cameraMode=` request produce the identical spec.
43
+ */
44
+ export declare function cameraTypeForMode(mode: "viewer" | "first-person" | undefined): string | undefined;
45
+ /**
46
+ * Values a query cannot carry on its own and the caller resolves first.
47
+ *
48
+ * `region` may be the **id** of a registered scene region (ADR 0051 §2), which
49
+ * only a store can turn into bounds, and `cellSize` may be derived from the
50
+ * scene's registered extent when the caller did not pin one (ADR 0040 §1). Both
51
+ * are looked up by the collector before compilation, exactly as the canned
52
+ * spatial routes do, and passed in here.
53
+ */
54
+ export interface QueryResolution {
55
+ /** Bounds for a `filters.region` given as a region id. */
56
+ region?: WorldAabb;
57
+ /** The effective voxel edge, when the caller left `cellSize` to the collector. */
58
+ cellSize?: number;
59
+ }
60
+ /**
61
+ * Turn a validated query into the option bag its builder takes.
62
+ *
63
+ * The mapping is the registry's, not this file's: for each filter the query
64
+ * carries, `FILTER_TARGETS[filter].field` names the option field it drives. Only
65
+ * two values are transformed on the way — the camera-mode toggle becomes the
66
+ * stored `cameraType`, and a region id becomes the bounds the caller resolved.
67
+ */
68
+ export declare function toBuilderOptions(query: QueryV1, resolved?: QueryResolution, tier?: QueryTier): MetricQueryOptions;
69
+ /**
70
+ * Render the `QuerySpec` for one metric and an already-assembled option bag.
71
+ *
72
+ * This is the seam the stores use: a store's `runMetric` is exactly
73
+ * `run<Engine>Query(compileMetric(metric, projectId, options, <engine>Dialect))`,
74
+ * so the DSL reaches every engine through the one code path aggregations already
75
+ * take — and therefore through the same parity harness and the same numeric
76
+ * coercion.
77
+ */
78
+ export declare function compileMetric(metric: MetricId, projectId: string, options: MetricQueryOptions, dialect: Dialect): QuerySpec;
79
+ /**
80
+ * Compile a validated query end to end: filters → option bag → the metric's
81
+ * builder (or the generic one) → a `QuerySpec`.
82
+ *
83
+ * The tier is derived here rather than passed in, so a caller that has a
84
+ * validated query cannot compile it onto the wrong compiler; the collector,
85
+ * which already has the tier from `validateQuery`, may pass it to save the
86
+ * lookup.
87
+ */
88
+ export declare function compileQuery(projectId: string, query: QueryV1, dialect: Dialect, resolved?: QueryResolution, tier?: QueryTier): QuerySpec;
89
+ //# sourceMappingURL=compile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/query/dsl/compile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAML,KAAK,QAAQ,EACb,KAAK,SAAS,EACf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAIxD;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEnE;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,GAAG,cAAc,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAIjG;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAC9B,0DAA0D;IAC1D,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAoBD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,OAAO,EACd,QAAQ,GAAE,eAAoB,EAC9B,IAAI,GAAE,SAAuB,GAC5B,kBAAkB,CAoEpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,QAAQ,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,OAAO,GACf,SAAS,CAmBX;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,OAAO,EAChB,QAAQ,GAAE,eAAoB,EAC9B,IAAI,CAAC,EAAE,SAAS,GACf,SAAS,CASX"}