@uptimizr/db 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/AGENTS.md +109 -0
  2. package/LICENSE +201 -0
  3. package/README.md +89 -0
  4. package/dist/cli/createProject.d.ts +3 -0
  5. package/dist/cli/createProject.d.ts.map +1 -0
  6. package/dist/cli/createProject.js +41 -0
  7. package/dist/cli/createProject.js.map +1 -0
  8. package/dist/cli/migrate.d.ts +3 -0
  9. package/dist/cli/migrate.d.ts.map +1 -0
  10. package/dist/cli/migrate.js +21 -0
  11. package/dist/cli/migrate.js.map +1 -0
  12. package/dist/cli/seed.d.ts +2 -0
  13. package/dist/cli/seed.d.ts.map +1 -0
  14. package/dist/cli/seed.js +175 -0
  15. package/dist/cli/seed.js.map +1 -0
  16. package/dist/duckdb/client.d.ts +42 -0
  17. package/dist/duckdb/client.d.ts.map +1 -0
  18. package/dist/duckdb/client.js +93 -0
  19. package/dist/duckdb/client.js.map +1 -0
  20. package/dist/duckdb/events.d.ts +44 -0
  21. package/dist/duckdb/events.d.ts.map +1 -0
  22. package/dist/duckdb/events.js +225 -0
  23. package/dist/duckdb/events.js.map +1 -0
  24. package/dist/duckdb/migrations.d.ts +20 -0
  25. package/dist/duckdb/migrations.d.ts.map +1 -0
  26. package/dist/duckdb/migrations.js +323 -0
  27. package/dist/duckdb/migrations.js.map +1 -0
  28. package/dist/duckdb/projects.d.ts +23 -0
  29. package/dist/duckdb/projects.d.ts.map +1 -0
  30. package/dist/duckdb/projects.js +55 -0
  31. package/dist/duckdb/projects.js.map +1 -0
  32. package/dist/duckdb/queries.d.ts +10 -0
  33. package/dist/duckdb/queries.d.ts.map +1 -0
  34. package/dist/duckdb/queries.js +10 -0
  35. package/dist/duckdb/queries.js.map +1 -0
  36. package/dist/duckdb/sceneRegistry.d.ts +15 -0
  37. package/dist/duckdb/sceneRegistry.d.ts.map +1 -0
  38. package/dist/duckdb/sceneRegistry.js +98 -0
  39. package/dist/duckdb/sceneRegistry.js.map +1 -0
  40. package/dist/env.d.ts +25 -0
  41. package/dist/env.d.ts.map +1 -0
  42. package/dist/env.js +55 -0
  43. package/dist/env.js.map +1 -0
  44. package/dist/events.d.ts +107 -0
  45. package/dist/events.d.ts.map +1 -0
  46. package/dist/events.js +153 -0
  47. package/dist/events.js.map +1 -0
  48. package/dist/index.d.ts +36 -0
  49. package/dist/index.d.ts.map +1 -0
  50. package/dist/index.js +34 -0
  51. package/dist/index.js.map +1 -0
  52. package/dist/metadata.d.ts +84 -0
  53. package/dist/metadata.d.ts.map +1 -0
  54. package/dist/metadata.js +23 -0
  55. package/dist/metadata.js.map +1 -0
  56. package/dist/parity/cases.d.ts +31 -0
  57. package/dist/parity/cases.d.ts.map +1 -0
  58. package/dist/parity/cases.js +524 -0
  59. package/dist/parity/cases.js.map +1 -0
  60. package/dist/parity/compare.d.ts +47 -0
  61. package/dist/parity/compare.d.ts.map +1 -0
  62. package/dist/parity/compare.js +90 -0
  63. package/dist/parity/compare.js.map +1 -0
  64. package/dist/parity/fixtures.d.ts +45 -0
  65. package/dist/parity/fixtures.d.ts.map +1 -0
  66. package/dist/parity/fixtures.js +157 -0
  67. package/dist/parity/fixtures.js.map +1 -0
  68. package/dist/parity/index.d.ts +12 -0
  69. package/dist/parity/index.d.ts.map +1 -0
  70. package/dist/parity/index.js +12 -0
  71. package/dist/parity/index.js.map +1 -0
  72. package/dist/query/aggregations.d.ts +393 -0
  73. package/dist/query/aggregations.d.ts.map +1 -0
  74. package/dist/query/aggregations.js +1412 -0
  75. package/dist/query/aggregations.js.map +1 -0
  76. package/dist/query/dialect.d.ts +100 -0
  77. package/dist/query/dialect.d.ts.map +1 -0
  78. package/dist/query/dialect.js +88 -0
  79. package/dist/query/dialect.js.map +1 -0
  80. package/dist/query/duckdbDialect.d.ts +27 -0
  81. package/dist/query/duckdbDialect.d.ts.map +1 -0
  82. package/dist/query/duckdbDialect.js +83 -0
  83. package/dist/query/duckdbDialect.js.map +1 -0
  84. package/dist/query/index.d.ts +22 -0
  85. package/dist/query/index.d.ts.map +1 -0
  86. package/dist/query/index.js +30 -0
  87. package/dist/query/index.js.map +1 -0
  88. package/dist/query/types.d.ts +388 -0
  89. package/dist/query/types.d.ts.map +1 -0
  90. package/dist/query/types.js +11 -0
  91. package/dist/query/types.js.map +1 -0
  92. package/llms.txt +21 -0
  93. package/package.json +71 -0
@@ -0,0 +1,524 @@
1
+ /**
2
+ * Cross-engine parity cases (Phase C, ADR 0020).
3
+ *
4
+ * Each case pairs one dialect-agnostic aggregation builder with the
5
+ * engine-independent golden output it must produce for {@link PARITY_EVENTS}.
6
+ * The golden is authored as truth (hand-verified from the fixtures) so that any
7
+ * engine — DuckDB in OSS, ClickHouse in the scale tier — can be checked against
8
+ * the same expectations. Two engines that both match the golden are, by
9
+ * transitivity, in parity with each other.
10
+ *
11
+ * Comparison uses the tolerance rules in {@link diffParity}: order-insensitive,
12
+ * float-tolerant on continuous columns, integer-exact on bin indices, and
13
+ * temporal projection columns excluded.
14
+ */
15
+ import { buildCameraDirectionHeatmap, buildCameraDistance, buildCameraPositionHeatmap, buildClickGazeRay, buildDistinctScenes, buildEventTypeCounts, buildEventsDaily, buildFlowHeatmap, buildListSessions, buildMeshDwell, buildDeadClicks, buildRageClicks, buildHoverDwell, buildCompileStalls, buildResourceSummary, buildCapabilityChanges, buildCameraGestures, buildNavigationStats, buildXrRotationRate, buildXrSourceUsage, buildXrAbandonment, buildInteractionsBySource, buildPerfDaily, buildPerfSummary, buildPerfDistribution, buildFpsHistogram, buildFrameTimePercentiles, buildJankRate, buildPerfByDevice, buildPerfByScene, buildResourcePercentiles, buildStabilityCounts, buildPointerHeatmap, buildSceneCoverage, buildSessionTrajectory, buildTimeseries, buildTopMeshes, buildWorldHeatmap, buildGazeHeatmap, } from "../query/aggregations.js";
16
+ import { PARITY_DAY, PARITY_DAY_RANGE, PARITY_PROJECT_ID, PARITY_RANGE, PARITY_T0, } from "./fixtures.js";
17
+ const PID = PARITY_PROJECT_ID;
18
+ export const PARITY_CASES = [
19
+ {
20
+ name: "listSessions",
21
+ build: (d) => buildListSessions(PID, PARITY_RANGE, d),
22
+ sortKeys: ["session_id"],
23
+ ignoreColumns: ["started_at", "ended_at"],
24
+ golden: [
25
+ { session_id: "s1", visitor_id: "", events: 9 },
26
+ { session_id: "s2", visitor_id: "", events: 5 },
27
+ ],
28
+ },
29
+ {
30
+ name: "pointerHeatmap",
31
+ build: (d) => buildPointerHeatmap(PID, { ...PARITY_RANGE, bins: 10 }, d),
32
+ sortKeys: ["gx", "gy"],
33
+ golden: [
34
+ { gx: 1, gy: 1, count: 1 },
35
+ { gx: 5, gy: 5, count: 2 },
36
+ { gx: 9, gy: 9, count: 1 },
37
+ ],
38
+ },
39
+ {
40
+ name: "worldHeatmap",
41
+ build: (d) => buildWorldHeatmap(PID, { ...PARITY_RANGE, cellSize: 1 }, d),
42
+ sortKeys: ["vx", "vy", "vz"],
43
+ golden: [
44
+ { vx: 0, vy: 0, vz: 0, count: 1 },
45
+ { vx: 1, vy: 1, vz: 1, count: 2 },
46
+ { vx: 5, vy: 5, vz: 5, count: 1 },
47
+ ],
48
+ },
49
+ {
50
+ // Gaze heatmap (ADR 0030): voxel-binned `camera_sample.hitPoint`. Three camera
51
+ // samples carry a gaze hit ([0.2,0.2,0.2], [1,1,1], [5,5,5]); at cellSize 1
52
+ // they fall in three distinct voxels. Hand-verified from the fixtures.
53
+ name: "gazeHeatmap",
54
+ build: (d) => buildGazeHeatmap(PID, { ...PARITY_RANGE, cellSize: 1 }, d),
55
+ sortKeys: ["vx", "vy", "vz"],
56
+ golden: [
57
+ { vx: 0, vy: 0, vz: 0, count: 1 },
58
+ { vx: 1, vy: 1, vz: 1, count: 1 },
59
+ { vx: 5, vy: 5, vz: 5, count: 1 },
60
+ ],
61
+ },
62
+ {
63
+ name: "cameraDirectionHeatmap",
64
+ build: (d) => buildCameraDirectionHeatmap(PID, { ...PARITY_RANGE, bins: 8 }, d),
65
+ sortKeys: ["azimuth_bin", "elevation_bin"],
66
+ // Hand-verified from the three camera directions ([2,1,2], [1,3,-2],
67
+ // [-2,-1,1]) via azimuth=atan2(z,x), elevation=asin(y/|v|) into 8 bins.
68
+ golden: [
69
+ { azimuth_bin: 2, elevation_bin: 6, count: 1 },
70
+ { azimuth_bin: 5, elevation_bin: 4, count: 1 },
71
+ { azimuth_bin: 7, elevation_bin: 2, count: 1 },
72
+ ],
73
+ },
74
+ {
75
+ name: "cameraPositionHeatmap",
76
+ build: (d) => buildCameraPositionHeatmap(PID, { ...PARITY_RANGE, cellSize: 1 }, d),
77
+ sortKeys: ["gx", "gz"],
78
+ // The three camera positions [0,0,0], [10,0,0], [0,0,0] binned on X/Z at
79
+ // cellSize 1: two samples share cell (0,0), one lands in (10,0).
80
+ golden: [
81
+ { gx: 0, gz: 0, avg_y: 0, count: 2 },
82
+ { gx: 10, gz: 0, avg_y: 0, count: 1 },
83
+ ],
84
+ },
85
+ {
86
+ name: "sessionTrajectory",
87
+ build: (d) => buildSessionTrajectory(PID, { ...PARITY_RANGE, session: "s1" }, d),
88
+ sortKeys: ["x", "z"],
89
+ ignoreColumns: ["ts"],
90
+ // Session s1's two camera samples in order: [0,0,0] then [10,0,0].
91
+ golden: [
92
+ { x: 0, y: 0, z: 0 },
93
+ { x: 10, y: 0, z: 0 },
94
+ ],
95
+ },
96
+ {
97
+ name: "clickGazeRay",
98
+ build: (d) => buildClickGazeRay(PID, { ...PARITY_RANGE, cellSize: 1 }, d),
99
+ sortKeys: ["mesh"],
100
+ golden: [
101
+ {
102
+ cam_vx: 0,
103
+ cam_vy: 0,
104
+ cam_vz: 0,
105
+ origin_x: 0,
106
+ origin_y: 0,
107
+ origin_z: 0,
108
+ hit_vx: 0,
109
+ hit_vy: 0,
110
+ hit_vz: 0,
111
+ hit_x: 0.2,
112
+ hit_y: 0.2,
113
+ hit_z: 0.2,
114
+ mesh: "box",
115
+ count: 1,
116
+ },
117
+ {
118
+ cam_vx: 0,
119
+ cam_vy: 0,
120
+ cam_vz: 0,
121
+ origin_x: 0,
122
+ origin_y: 0,
123
+ origin_z: 0,
124
+ hit_vx: 1,
125
+ hit_vy: 1,
126
+ hit_vz: 1,
127
+ hit_x: 1,
128
+ hit_y: 1,
129
+ hit_z: 1,
130
+ mesh: "floor",
131
+ count: 1,
132
+ },
133
+ {
134
+ cam_vx: 10,
135
+ cam_vy: 0,
136
+ cam_vz: 0,
137
+ origin_x: 10,
138
+ origin_y: 0,
139
+ origin_z: 0,
140
+ hit_vx: 5,
141
+ hit_vy: 5,
142
+ hit_vz: 5,
143
+ hit_x: 5,
144
+ hit_y: 5,
145
+ hit_z: 5,
146
+ mesh: "sphere",
147
+ count: 1,
148
+ },
149
+ ],
150
+ },
151
+ {
152
+ name: "flowHeatmap",
153
+ build: (d) => buildFlowHeatmap(PID, { ...PARITY_RANGE, bins: 24 }, d),
154
+ sortKeys: ["mesh"],
155
+ // One link per (clicked mesh, ASOF-preceding gaze direction), binned into 24
156
+ // azimuth/elevation buckets. Hand-verified from the fixtures.
157
+ golden: [
158
+ { azimuth_bin: 15, elevation_bin: 14, mesh: "box", count: 1 },
159
+ { azimuth_bin: 22, elevation_bin: 8, mesh: "floor", count: 1 },
160
+ { azimuth_bin: 7, elevation_bin: 19, mesh: "sphere", count: 1 },
161
+ ],
162
+ },
163
+ {
164
+ // Position-aware flow (§7.8): same three links, now also carrying the
165
+ // ASOF-preceding camera *position* as a standpoint voxel. At cellSize 1 the
166
+ // standpoints are box→(0,0,0), sphere→(10,0,0), floor→(0,0,0). The direction
167
+ // bins are unchanged from `flowHeatmap`. Hand-verified from the fixtures.
168
+ name: "flowHeatmapByStandpoint",
169
+ build: (d) => buildFlowHeatmap(PID, { ...PARITY_RANGE, bins: 24, cellSize: 1, groupByOrigin: true }, d),
170
+ sortKeys: ["mesh"],
171
+ golden: [
172
+ {
173
+ azimuth_bin: 15,
174
+ elevation_bin: 14,
175
+ origin_vx: 0,
176
+ origin_vy: 0,
177
+ origin_vz: 0,
178
+ origin_x: 0,
179
+ origin_y: 0,
180
+ origin_z: 0,
181
+ mesh: "box",
182
+ count: 1,
183
+ },
184
+ {
185
+ azimuth_bin: 22,
186
+ elevation_bin: 8,
187
+ origin_vx: 0,
188
+ origin_vy: 0,
189
+ origin_vz: 0,
190
+ origin_x: 0,
191
+ origin_y: 0,
192
+ origin_z: 0,
193
+ mesh: "floor",
194
+ count: 1,
195
+ },
196
+ {
197
+ azimuth_bin: 7,
198
+ elevation_bin: 19,
199
+ origin_vx: 10,
200
+ origin_vy: 0,
201
+ origin_vz: 0,
202
+ origin_x: 10,
203
+ origin_y: 0,
204
+ origin_z: 0,
205
+ mesh: "sphere",
206
+ count: 1,
207
+ },
208
+ ],
209
+ },
210
+ {
211
+ name: "topMeshes",
212
+ build: (d) => buildTopMeshes(PID, PARITY_RANGE, d),
213
+ sortKeys: ["mesh"],
214
+ // Counts any event carrying a mesh (interactions plus mesh_visibility):
215
+ // box has 1 click + 1 visibility, floor 2 hits, sphere 1 click + 1 visibility.
216
+ golden: [
217
+ { mesh: "box", count: 2 },
218
+ { mesh: "floor", count: 2 },
219
+ { mesh: "sphere", count: 2 },
220
+ ],
221
+ },
222
+ {
223
+ name: "meshDwell",
224
+ build: (d) => buildMeshDwell(PID, PARITY_RANGE, d),
225
+ sortKeys: ["mesh"],
226
+ // Per-object dwell from the two mesh_visibility summaries, ranked by total
227
+ // on-screen time (box 4000 > sphere 2000).
228
+ golden: [
229
+ { mesh: "box", visible_ms: 4000, centered_ms: 1500, max_screen_fraction: 0.4, samples: 1 },
230
+ { mesh: "sphere", visible_ms: 2000, centered_ms: 800, max_screen_fraction: 0.7, samples: 1 },
231
+ ],
232
+ },
233
+ {
234
+ name: "perfSummary",
235
+ build: (d) => buildPerfSummary(PID, PARITY_RANGE, d),
236
+ sortKeys: ["samples"],
237
+ golden: [{ samples: 3, avg_fps: 45, min_fps: 30, p50_fps: 45 }],
238
+ },
239
+ {
240
+ name: "perfDistribution",
241
+ build: (d) => buildPerfDistribution(PID, PARITY_RANGE, d),
242
+ sortKeys: ["sessions"],
243
+ // Per session: s1 fps [30,60] -> p05 31.5 / p50 45 / p95 58.5; s2 fps [45] ->
244
+ // 45 across the board. Median across the two sessions of each percentile.
245
+ golden: [{ sessions: 2, samples: 3, p05_fps: 38.25, p50_fps: 45, p95_fps: 51.75 }],
246
+ },
247
+ {
248
+ name: "fpsHistogram",
249
+ build: (d) => buildFpsHistogram(PID, PARITY_RANGE, d),
250
+ sortKeys: ["bucket"],
251
+ // Session medians: s1 -> 45, s2 -> 45. Both land in the [40,50) bin (width 10).
252
+ golden: [{ bucket: 40, sessions: 2 }],
253
+ },
254
+ {
255
+ name: "frameTimePercentiles",
256
+ build: (d) => buildFrameTimePercentiles(PID, PARITY_RANGE, d),
257
+ sortKeys: ["sessions"],
258
+ // Per session: s1 median frame_time_ms = median(16,33) = 24.5, worst p95 =
259
+ // max(20,40) = 40; s2 = 22 / 28. Median across sessions of each.
260
+ golden: [{ sessions: 2, samples: 3, p50_ms: 23.25, p95_ms: 34 }],
261
+ },
262
+ {
263
+ name: "jankRate",
264
+ build: (d) => buildJankRate(PID, PARITY_RANGE, d),
265
+ sortKeys: ["sessions"],
266
+ // Per session long-frames-per-window: s1 = (1+5)/2 = 3, s2 = 2/1 = 2.
267
+ // median(3,2) = 2.5; p90 of [2,3] = 2.9; total long frames = 8.
268
+ golden: [{ sessions: 2, total_long_frames: 8, median_rate: 2.5, worst_decile_rate: 2.9 }],
269
+ },
270
+ {
271
+ name: "perfByDevice",
272
+ build: (d) => buildPerfByDevice(PID, PARITY_RANGE, d),
273
+ sortKeys: ["engine"],
274
+ // s1 -> webgpu (2 samples), s2 -> webgl2 (1 sample); both sessions have a
275
+ // single median FPS of 45. isMobile/renderer were never reported -> ''.
276
+ golden: [
277
+ { engine: "webgl2", is_mobile: "", renderer: "", sessions: 1, samples: 1, p50_fps: 45 },
278
+ { engine: "webgpu", is_mobile: "", renderer: "", sessions: 1, samples: 2, p50_fps: 45 },
279
+ ],
280
+ },
281
+ {
282
+ name: "perfByScene",
283
+ build: (d) => buildPerfByScene(PID, PARITY_RANGE, d),
284
+ sortKeys: ["scene_id"],
285
+ // s1 renders lobby (2 samples), s2 renders arena (1 sample); each session's
286
+ // median FPS is 45.
287
+ golden: [
288
+ { scene_id: "arena", sessions: 1, samples: 1, p50_fps: 45 },
289
+ { scene_id: "lobby", sessions: 1, samples: 2, p50_fps: 45 },
290
+ ],
291
+ },
292
+ {
293
+ name: "resourcePercentiles",
294
+ build: (d) => buildResourcePercentiles(PID, PARITY_RANGE, d),
295
+ sortKeys: ["sessions"],
296
+ // No resource_sample fixtures: no sessions contribute, so every percentile is
297
+ // NULL and the sample total is NULL. Validates the nested per-session
298
+ // aggregation renders identically on both engines.
299
+ golden: [
300
+ {
301
+ sessions: 0,
302
+ samples: null,
303
+ p50_js_heap_bytes: null,
304
+ p95_js_heap_bytes: null,
305
+ p50_texture_bytes: null,
306
+ p95_texture_bytes: null,
307
+ p50_triangles: null,
308
+ p95_triangles: null,
309
+ },
310
+ ],
311
+ },
312
+ {
313
+ name: "stabilityCounts",
314
+ build: (d) => buildStabilityCounts(PID, PARITY_RANGE, d),
315
+ sortKeys: ["incidents"],
316
+ // No context_lost / compile_stall fixtures: all counts coalesce to 0.
317
+ golden: [{ context_losses: 0, compile_stalls: 0, incidents: 0 }],
318
+ },
319
+ {
320
+ name: "deadClicks",
321
+ build: (d) => buildDeadClicks(PID, PARITY_RANGE, d),
322
+ sortKeys: ["total_clicks"],
323
+ // All three pointer_click fixtures hit a mesh, so none are dead. Validates
324
+ // the empty-mesh count renders identically on both engines (#46).
325
+ golden: [{ total_clicks: 3, dead_clicks: 0 }],
326
+ },
327
+ {
328
+ name: "rageClicks",
329
+ build: (d) => buildRageClicks(PID, PARITY_RANGE, d),
330
+ sortKeys: ["session_id", "mesh", "bucket"],
331
+ // The three clicks are on distinct meshes spread across time, so no burst
332
+ // reaches the default threshold. Validates the GROUP/HAVING renders the same
333
+ // (empty) result on both engines (#47).
334
+ golden: [],
335
+ },
336
+ {
337
+ name: "hoverDwell",
338
+ build: (d) => buildHoverDwell(PID, PARITY_RANGE, d),
339
+ sortKeys: ["mesh"],
340
+ // No hover_dwell fixtures in the parity set, so the per-mesh hesitation roll-up
341
+ // is empty. Validates the GROUP/ORDER renders identically on both engines (#48).
342
+ golden: [],
343
+ },
344
+ {
345
+ name: "compileStalls",
346
+ build: (d) => buildCompileStalls(PID, PARITY_RANGE, d),
347
+ sortKeys: ["phase"],
348
+ // No compile_stall fixtures in the parity set, so the per-phase compile-stall
349
+ // roll-up is empty. Validates the GROUP/ORDER renders identically on both
350
+ // engines (#42).
351
+ golden: [],
352
+ },
353
+ {
354
+ name: "resourceSummary",
355
+ build: (d) => buildResourceSummary(PID, PARITY_RANGE, d),
356
+ sortKeys: ["samples"],
357
+ // No resource_sample fixtures in the parity set: count is 0 and every
358
+ // avg/max is NULL. Validates the aggregate (incl. NULLIF) renders identically
359
+ // on both engines (#44).
360
+ golden: [
361
+ {
362
+ samples: 0,
363
+ avg_js_heap_bytes: null,
364
+ max_js_heap_bytes: null,
365
+ avg_triangles: null,
366
+ max_triangles: null,
367
+ avg_vertices: null,
368
+ max_vertices: null,
369
+ avg_texture_bytes: null,
370
+ max_texture_bytes: null,
371
+ avg_geometry_bytes: null,
372
+ max_geometry_bytes: null,
373
+ },
374
+ ],
375
+ },
376
+ {
377
+ name: "capabilityChanges",
378
+ build: (d) => buildCapabilityChanges(PID, PARITY_RANGE, d),
379
+ sortKeys: ["kind", "from", "to"],
380
+ // No capability_change fixtures in the parity set, so the per-transition
381
+ // roll-up is empty. Validates the GROUP/ORDER (with reserved-word aliases)
382
+ // renders identically on both engines (#49).
383
+ golden: [],
384
+ },
385
+ {
386
+ name: "cameraGestures",
387
+ build: (d) => buildCameraGestures(PID, PARITY_RANGE, d),
388
+ sortKeys: ["kind"],
389
+ // No camera_gesture fixtures in the parity set, so the per-kind navigation
390
+ // roll-up is empty. Validates the GROUP/ORDER renders identically on both
391
+ // engines (ADR 0025).
392
+ golden: [],
393
+ },
394
+ {
395
+ name: "perfDaily",
396
+ build: (d) => buildPerfDaily(PID, PARITY_DAY_RANGE, d),
397
+ sortKeys: ["day"],
398
+ golden: [{ day: PARITY_DAY, samples: 3, avg_fps: 45, min_fps: 30, p50_fps: 45 }],
399
+ },
400
+ {
401
+ name: "eventsDaily",
402
+ build: (d) => buildEventsDaily(PID, PARITY_DAY_RANGE, d),
403
+ sortKeys: ["event_type"],
404
+ golden: [
405
+ { day: PARITY_DAY, event_type: "camera_sample", events: 3 },
406
+ { day: PARITY_DAY, event_type: "frame_perf", events: 3 },
407
+ { day: PARITY_DAY, event_type: "mesh_visibility", events: 2 },
408
+ { day: PARITY_DAY, event_type: "pointer_click", events: 3 },
409
+ { day: PARITY_DAY, event_type: "pointer_move", events: 1 },
410
+ { day: PARITY_DAY, event_type: "session_start", events: 2 },
411
+ ],
412
+ },
413
+ {
414
+ name: "distinctScenes",
415
+ build: (d) => buildDistinctScenes(PID, PARITY_RANGE, d),
416
+ sortKeys: ["scene_id"],
417
+ ignoreColumns: ["last_seen"],
418
+ golden: [
419
+ { scene_id: "arena", events: 5 },
420
+ { scene_id: "lobby", events: 9 },
421
+ ],
422
+ },
423
+ {
424
+ name: "timeseries",
425
+ build: (d) => buildTimeseries(PID, { ...PARITY_RANGE, interval: 60 }, d),
426
+ sortKeys: ["bucket"],
427
+ golden: [{ bucket: PARITY_T0, events: 14, avg_fps: 45 }],
428
+ },
429
+ {
430
+ name: "eventTypeCounts",
431
+ build: (d) => buildEventTypeCounts(PID, PARITY_RANGE, d),
432
+ sortKeys: ["event_type"],
433
+ golden: [
434
+ { event_type: "camera_sample", count: 3 },
435
+ { event_type: "frame_perf", count: 3 },
436
+ { event_type: "mesh_visibility", count: 2 },
437
+ { event_type: "pointer_click", count: 3 },
438
+ { event_type: "pointer_move", count: 1 },
439
+ { event_type: "session_start", count: 2 },
440
+ ],
441
+ },
442
+ {
443
+ name: "sceneCoverage",
444
+ build: (d) => buildSceneCoverage(PID, { ...PARITY_RANGE, cellSize: 1 }, d),
445
+ sortKeys: ["vx", "vy", "vz"],
446
+ // Camera positions [0,0,0] (s1 + s2) and [10,0,0] (s1) voxel-binned at size 1.
447
+ golden: [
448
+ { vx: 0, vy: 0, vz: 0, count: 2 },
449
+ { vx: 10, vy: 0, vz: 0, count: 1 },
450
+ ],
451
+ },
452
+ {
453
+ name: "cameraDistance",
454
+ build: (d) => buildCameraDistance(PID, { ...PARITY_RANGE, center: [0, 0, 0], bucketSize: 1 }, d),
455
+ sortKeys: ["bucket"],
456
+ // Distances from origin: 0 (s1 + s2) and 10 (s1), bucketed by 1.
457
+ golden: [
458
+ { bucket: 0, count: 2 },
459
+ { bucket: 10, count: 1 },
460
+ ],
461
+ },
462
+ {
463
+ name: "navigationStats",
464
+ build: (d) => buildNavigationStats(PID, PARITY_RANGE, d),
465
+ sortKeys: ["session_id"],
466
+ // s1 travels [0,0,0] -> [10,0,0] = 10 units (one active segment); s2 has a
467
+ // single sample, so it yields no segment and drops out of the inner join.
468
+ golden: [
469
+ {
470
+ session_id: "s1",
471
+ segments: 1,
472
+ total_distance: 10,
473
+ active_segments: 1,
474
+ active_distance: 10,
475
+ },
476
+ ],
477
+ },
478
+ {
479
+ name: "xrRotationRate",
480
+ build: (d) => buildXrRotationRate(PID, PARITY_RANGE, d),
481
+ sortKeys: ["session_id"],
482
+ // s1's two view directions ([2,1,2] -> [1,3,-2]) subtend
483
+ // acos(1 / (3*sqrt(14))) = 1.4815909832 rad — one segment, above the 0.5 rad
484
+ // rapid threshold. s2 has a single sample, so no segment.
485
+ golden: [
486
+ {
487
+ session_id: "s1",
488
+ samples: 1,
489
+ avg_turn_rad: 1.4815909832473548,
490
+ max_turn_rad: 1.4815909832473548,
491
+ total_turn_rad: 1.4815909832473548,
492
+ rapid_segments: 1,
493
+ },
494
+ ],
495
+ },
496
+ {
497
+ name: "xrSourceUsage",
498
+ build: (d) => buildXrSourceUsage(PID, PARITY_RANGE, d),
499
+ sortKeys: ["source"],
500
+ // The fixtures use only `mouse`, so no immersive input source is present.
501
+ golden: [],
502
+ },
503
+ {
504
+ name: "xrAbandonment",
505
+ build: (d) => buildXrAbandonment(PID, PARITY_RANGE, d),
506
+ sortKeys: ["session_id"],
507
+ ignoreColumns: ["started_at", "ended_at"],
508
+ // No session used an XR input source in the fixtures, so none qualifies.
509
+ golden: [],
510
+ },
511
+ {
512
+ name: "interactionsBySource",
513
+ build: (d) => buildInteractionsBySource(PID, PARITY_RANGE, d),
514
+ sortKeys: ["event_type", "source"],
515
+ // The fixtures hold three mouse clicks (two in s1, one in s2) and one mouse
516
+ // move (s2). Validates the per-(event_type, source) GROUP and the
517
+ // DISTINCT-session count render identically on both engines (ADR 0011).
518
+ golden: [
519
+ { event_type: "pointer_click", source: "mouse", count: 3, sessions: 2 },
520
+ { event_type: "pointer_move", source: "mouse", count: 1, sessions: 1 },
521
+ ],
522
+ },
523
+ ];
524
+ //# sourceMappingURL=cases.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cases.js","sourceRoot":"","sources":["../../src/parity/cases.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Tolerance-aware row comparison for cross-engine parity (Phase C, ADR 0020).
3
+ *
4
+ * Two SQL engines (DuckDB for OSS, ClickHouse for the scale tier)
5
+ * implement the same dialect-agnostic aggregations. Their numeric output can
6
+ * differ in the last bits of floating-point arithmetic and their row order is
7
+ * only as stable as the query's `ORDER BY`. This module encodes the tolerance
8
+ * rules that let "equal analytics" be asserted despite those differences.
9
+ *
10
+ * ## Tolerance rules
11
+ *
12
+ * 1. **Order-insensitive.** Rows are compared as a multiset: both sides are
13
+ * sorted by the case's `sortKeys` before comparison. SQL guarantees no row
14
+ * order beyond an explicit `ORDER BY`, and ties under `ORDER BY count` are
15
+ * unstable across engines.
16
+ * 2. **Float tolerance.** Numeric columns (averages, quantiles, ASOF ray
17
+ * origins/hits) match when their absolute difference is within
18
+ * {@link PARITY_ABS_TOLERANCE} or their relative difference is within
19
+ * {@link PARITY_REL_TOLERANCE}. Counts and bin indices are integers and so
20
+ * compare exactly under the same rule (difference 0).
21
+ * 3. **Bin indices are integer-exact.** Heatmap bin columns come from
22
+ * `floor(...)` and are deterministic within an engine; they are integers and
23
+ * compared exactly. Inputs are chosen to avoid landing exactly on a bin
24
+ * boundary, where a sub-ulp difference could flip the floor across engines.
25
+ * 4. **Temporal projections are excluded.** Wall-clock `TIMESTAMP` columns
26
+ * (e.g. `started_at`, `ended_at`, `last_seen`) are presentation metadata, not
27
+ * analytics, and their string rendering differs by engine; list them in a
28
+ * case's `ignoreColumns`. Date-granular `day` strings (`YYYY-MM-DD`) render
29
+ * identically in both engines and are compared.
30
+ */
31
+ /** Absolute tolerance for floating-point column comparison. */
32
+ export declare const PARITY_ABS_TOLERANCE = 0.000001;
33
+ /** Relative tolerance for floating-point column comparison. */
34
+ export declare const PARITY_REL_TOLERANCE = 1e-9;
35
+ export type ParityRow = Record<string, unknown>;
36
+ export interface ParityCompareOptions {
37
+ /** Columns that, together, uniquely order a row for multiset comparison. */
38
+ readonly sortKeys: readonly string[];
39
+ /** Columns ignored entirely (engine-specific temporal renderings). */
40
+ readonly ignoreColumns?: readonly string[];
41
+ }
42
+ /**
43
+ * Compare engine output against golden rows under the tolerance rules above.
44
+ * Returns a list of human-readable differences; an empty list means parity.
45
+ */
46
+ export declare function diffParity(actual: readonly ParityRow[], golden: readonly ParityRow[], options: ParityCompareOptions): string[];
47
+ //# sourceMappingURL=compare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compare.d.ts","sourceRoot":"","sources":["../../src/parity/compare.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,+DAA+D;AAC/D,eAAO,MAAM,oBAAoB,WAAO,CAAC;AAEzC,+DAA+D;AAC/D,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAEzC,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD,MAAM,WAAW,oBAAoB;IACnC,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,sEAAsE;IACtE,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5C;AAiCD;;;GAGG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,SAAS,SAAS,EAAE,EAC5B,MAAM,EAAE,SAAS,SAAS,EAAE,EAC5B,OAAO,EAAE,oBAAoB,GAC5B,MAAM,EAAE,CA0BV"}