@smoothbricks/lmao 0.2.2 → 0.3.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 (285) hide show
  1. package/README.md +206 -206
  2. package/dist/allocator.wasm +0 -0
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +1 -0
  6. package/dist/lib/JsBufferStrategy.d.ts +4 -3
  7. package/dist/lib/JsBufferStrategy.d.ts.map +1 -1
  8. package/dist/lib/JsBufferStrategy.js +18 -11
  9. package/dist/lib/arrow/lease.d.ts +10 -0
  10. package/dist/lib/arrow/lease.d.ts.map +1 -0
  11. package/dist/lib/arrow/lease.js +33 -0
  12. package/dist/lib/arrow/utils.d.ts +3 -4
  13. package/dist/lib/arrow/utils.d.ts.map +1 -1
  14. package/dist/lib/arrow/utils.js +12 -13
  15. package/dist/lib/arrow/vocabularyDictionary.d.ts +21 -0
  16. package/dist/lib/arrow/vocabularyDictionary.d.ts.map +1 -0
  17. package/dist/lib/arrow/vocabularyDictionary.js +95 -0
  18. package/dist/lib/bufferStrategy.d.ts +3 -2
  19. package/dist/lib/bufferStrategy.d.ts.map +1 -1
  20. package/dist/lib/cloudflare/traceRows.d.ts.map +1 -1
  21. package/dist/lib/cloudflare/traceRows.js +3 -2
  22. package/dist/lib/codegen/evaluatorGenerator.d.ts.map +1 -1
  23. package/dist/lib/codegen/evaluatorGenerator.js +12 -11
  24. package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts +44 -82
  25. package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts.map +1 -1
  26. package/dist/lib/codegen/fixedPositionWriterGenerator.js +223 -162
  27. package/dist/lib/codegen/spanLoggerClosureMaterializer.d.ts +63 -0
  28. package/dist/lib/codegen/spanLoggerClosureMaterializer.d.ts.map +1 -0
  29. package/dist/lib/codegen/spanLoggerClosureMaterializer.js +447 -0
  30. package/dist/lib/codegen/spanLoggerGenerator.d.ts +36 -19
  31. package/dist/lib/codegen/spanLoggerGenerator.d.ts.map +1 -1
  32. package/dist/lib/codegen/spanLoggerGenerator.js +164 -158
  33. package/dist/lib/convertToArrow.d.ts +7 -2
  34. package/dist/lib/convertToArrow.d.ts.map +1 -1
  35. package/dist/lib/convertToArrow.js +499 -285
  36. package/dist/lib/defineOpContext.js +1 -1
  37. package/dist/lib/enumMetadata.d.ts +19 -0
  38. package/dist/lib/enumMetadata.d.ts.map +1 -0
  39. package/dist/lib/enumMetadata.js +86 -0
  40. package/dist/lib/flushScheduler.d.ts.map +1 -1
  41. package/dist/lib/flushScheduler.js +13 -4
  42. package/dist/lib/library.d.ts +16 -98
  43. package/dist/lib/library.d.ts.map +1 -1
  44. package/dist/lib/library.js +32 -525
  45. package/dist/lib/logBinding.d.ts +21 -27
  46. package/dist/lib/logBinding.d.ts.map +1 -1
  47. package/dist/lib/op.d.ts +30 -30
  48. package/dist/lib/op.d.ts.map +1 -1
  49. package/dist/lib/op.js +15 -22
  50. package/dist/lib/opContext/createOpGroup.d.ts +1 -1
  51. package/dist/lib/opContext/createOpGroup.d.ts.map +1 -1
  52. package/dist/lib/opContext/createOpGroup.js +22 -29
  53. package/dist/lib/opContext/defineOp.d.ts +4 -4
  54. package/dist/lib/opContext/defineOp.d.ts.map +1 -1
  55. package/dist/lib/opContext/defineOp.js +53 -10
  56. package/dist/lib/opContext/opGroupTypes.d.ts +2 -2
  57. package/dist/lib/opContext/opTypes.d.ts +1 -1
  58. package/dist/lib/opContext/opTypes.d.ts.map +1 -1
  59. package/dist/lib/opContext/spanContextTypes.d.ts +33 -18
  60. package/dist/lib/opContext/spanContextTypes.d.ts.map +1 -1
  61. package/dist/lib/opContext/types.d.ts +4 -4
  62. package/dist/lib/opContext/types.d.ts.map +1 -1
  63. package/dist/lib/physicalLayoutPlan.d.ts +89 -0
  64. package/dist/lib/physicalLayoutPlan.d.ts.map +1 -0
  65. package/dist/lib/physicalLayoutPlan.js +442 -0
  66. package/dist/lib/resolveMessage.d.ts +9 -0
  67. package/dist/lib/resolveMessage.d.ts.map +1 -0
  68. package/dist/lib/resolveMessage.js +63 -0
  69. package/dist/lib/result.d.ts +5 -7
  70. package/dist/lib/result.d.ts.map +1 -1
  71. package/dist/lib/result.js +19 -26
  72. package/dist/lib/runtimeHint.d.ts +35 -0
  73. package/dist/lib/runtimeHint.d.ts.map +1 -0
  74. package/dist/lib/runtimeHint.js +79 -0
  75. package/dist/lib/schema/typeGuards.d.ts +7 -47
  76. package/dist/lib/schema/typeGuards.d.ts.map +1 -1
  77. package/dist/lib/schema/typeGuards.js +7 -123
  78. package/dist/lib/schema/types.d.ts +1 -1
  79. package/dist/lib/schema/types.d.ts.map +1 -1
  80. package/dist/lib/span-buffer/aot/v1.d.ts +2 -0
  81. package/dist/lib/span-buffer/aot/v1.d.ts.map +1 -0
  82. package/dist/lib/span-buffer/aot/v1.js +24 -0
  83. package/dist/lib/spanBuffer.d.ts +33 -4
  84. package/dist/lib/spanBuffer.d.ts.map +1 -1
  85. package/dist/lib/spanBuffer.js +583 -91
  86. package/dist/lib/spanBufferStats.d.ts +1 -1
  87. package/dist/lib/spanBufferStats.d.ts.map +1 -1
  88. package/dist/lib/spanContext.d.ts +27 -51
  89. package/dist/lib/spanContext.d.ts.map +1 -1
  90. package/dist/lib/spanContext.js +822 -344
  91. package/dist/lib/sqlite/sqlite-common.d.ts.map +1 -1
  92. package/dist/lib/sqlite/sqlite-common.js +20 -21
  93. package/dist/lib/testing/bun-harness.d.ts +8 -3
  94. package/dist/lib/testing/bun-harness.d.ts.map +1 -1
  95. package/dist/lib/testing/bun-harness.js +30 -18
  96. package/dist/lib/testing/extractFacts.d.ts +1 -1
  97. package/dist/lib/testing/extractFacts.d.ts.map +1 -1
  98. package/dist/lib/testing/extractFacts.js +55 -63
  99. package/dist/lib/testing/facts.d.ts +1 -1
  100. package/dist/lib/testing/facts.d.ts.map +1 -1
  101. package/dist/lib/testing/queryable-span.d.ts +1 -1
  102. package/dist/lib/testing/queryable-span.d.ts.map +1 -1
  103. package/dist/lib/testing/queryable-span.js +26 -28
  104. package/dist/lib/testing/span-query.d.ts.map +1 -1
  105. package/dist/lib/testing/span-query.js +19 -22
  106. package/dist/lib/testing/stdio-replay.d.ts.map +1 -1
  107. package/dist/lib/testing/stdio-replay.js +19 -8
  108. package/dist/lib/threadId.d.ts.map +1 -1
  109. package/dist/lib/threadId.js +6 -3
  110. package/dist/lib/traceContext.d.ts.map +1 -1
  111. package/dist/lib/traceContext.js +1 -4
  112. package/dist/lib/traceRoot.d.ts +30 -8
  113. package/dist/lib/traceRoot.d.ts.map +1 -1
  114. package/dist/lib/traceRoot.es.d.ts +17 -15
  115. package/dist/lib/traceRoot.es.d.ts.map +1 -1
  116. package/dist/lib/traceRoot.es.js +68 -34
  117. package/dist/lib/traceRoot.js +11 -0
  118. package/dist/lib/traceRoot.node.d.ts +17 -19
  119. package/dist/lib/traceRoot.node.d.ts.map +1 -1
  120. package/dist/lib/traceRoot.node.js +66 -38
  121. package/dist/lib/traceTopology.d.ts +42 -0
  122. package/dist/lib/traceTopology.d.ts.map +1 -0
  123. package/dist/lib/traceTopology.js +260 -0
  124. package/dist/lib/tracer.d.ts +9 -5
  125. package/dist/lib/tracer.d.ts.map +1 -1
  126. package/dist/lib/tracer.js +65 -71
  127. package/dist/lib/tracers/ArrayQueueTracer.d.ts +1 -1
  128. package/dist/lib/tracers/ArrayQueueTracer.js +1 -1
  129. package/dist/lib/tracers/StdioTracer.d.ts.map +1 -1
  130. package/dist/lib/tracers/StdioTracer.js +15 -13
  131. package/dist/lib/tracers/TestTracer.d.ts +4 -6
  132. package/dist/lib/tracers/TestTracer.d.ts.map +1 -1
  133. package/dist/lib/tracers/TestTracer.js +6 -8
  134. package/dist/lib/types.d.ts +49 -32
  135. package/dist/lib/types.d.ts.map +1 -1
  136. package/dist/lib/vocabularyRegistry.d.ts +25 -0
  137. package/dist/lib/vocabularyRegistry.d.ts.map +1 -0
  138. package/dist/lib/vocabularyRegistry.js +372 -0
  139. package/dist/lib/wasm/WasmBufferStrategy.d.ts +6 -10
  140. package/dist/lib/wasm/WasmBufferStrategy.d.ts.map +1 -1
  141. package/dist/lib/wasm/WasmBufferStrategy.js +44 -37
  142. package/dist/lib/wasm/wasmAllocator.d.ts +27 -22
  143. package/dist/lib/wasm/wasmAllocator.d.ts.map +1 -1
  144. package/dist/lib/wasm/wasmAllocator.js +66 -44
  145. package/dist/lib/wasm/wasmPhysicalLayout.d.ts +67 -0
  146. package/dist/lib/wasm/wasmPhysicalLayout.d.ts.map +1 -0
  147. package/dist/lib/wasm/wasmPhysicalLayout.js +179 -0
  148. package/dist/lib/wasm/wasmSpanBuffer.d.ts +79 -31
  149. package/dist/lib/wasm/wasmSpanBuffer.d.ts.map +1 -1
  150. package/dist/lib/wasm/wasmSpanBuffer.js +442 -272
  151. package/dist/lib/wasm/wasmTraceRoot.d.ts +24 -22
  152. package/dist/lib/wasm/wasmTraceRoot.d.ts.map +1 -1
  153. package/dist/lib/wasm/wasmTraceRoot.js +110 -71
  154. package/dist/vocabulary/register/v1.d.ts +2 -0
  155. package/dist/vocabulary/register/v1.d.ts.map +1 -0
  156. package/dist/vocabulary/register/v1.js +1 -0
  157. package/dist/wasm.d.ts +5 -0
  158. package/dist/wasm.d.ts.map +1 -0
  159. package/dist/wasm.js +4 -0
  160. package/package.json +54 -6
  161. package/src/index.ts +1 -0
  162. package/src/lib/JsBufferStrategy.ts +27 -9
  163. package/src/lib/__tests__/arrow-builder-integration/arrow-conversion.test.ts +335 -37
  164. package/src/lib/__tests__/arrow-builder-integration/binary-arrow-conversion.test.ts +97 -26
  165. package/src/lib/__tests__/arrow-builder-integration/binary-comparison.test.ts +75 -15
  166. package/src/lib/__tests__/arrow-builder-integration/binary-format-compliance.test.ts +30 -6
  167. package/src/lib/__tests__/arrow-builder-integration/buffer-chaining.test.ts +18 -21
  168. package/src/lib/__tests__/arrow-builder-integration/foundation.test.ts +5 -2
  169. package/src/lib/__tests__/arrow-builder-integration/integration.test.ts +25 -7
  170. package/src/lib/__tests__/arrow-builder-integration/lazy-columns.test.ts +3 -2
  171. package/src/lib/__tests__/buffer-overflow.test.ts +24 -18
  172. package/src/lib/__tests__/capability-span-context.test.ts +505 -0
  173. package/src/lib/__tests__/capacity-tuning.test.ts +5 -3
  174. package/src/lib/__tests__/eager-columns.test.ts +345 -0
  175. package/src/lib/__tests__/enum-metadata-aot.test.ts +153 -0
  176. package/src/lib/__tests__/enum-metadata.test.ts +177 -0
  177. package/src/lib/__tests__/fixtures/empty-vocabulary-runtime.fixture.ts +15 -0
  178. package/src/lib/__tests__/flushScheduler.test.ts +5 -1
  179. package/src/lib/__tests__/identity-view.property.test.ts +179 -0
  180. package/src/lib/__tests__/library.test.ts +19 -235
  181. package/src/lib/__tests__/message-buffer-families.test.ts +878 -0
  182. package/src/lib/__tests__/nested-library-tasks.test.ts +14 -15
  183. package/src/lib/__tests__/op-metadata.test.ts +1 -1
  184. package/src/lib/__tests__/op-type-safety.test.ts +5 -16
  185. package/src/lib/__tests__/physical-layout-plan.test.ts +333 -0
  186. package/src/lib/__tests__/remap-descriptor-integration.test.ts +381 -0
  187. package/src/lib/__tests__/root-context-construction.test.ts +414 -0
  188. package/src/lib/__tests__/span-auto-runtime.test.ts +386 -0
  189. package/src/lib/__tests__/span-buffer-segment-stats.test.ts +221 -0
  190. package/src/lib/__tests__/span-lifecycle.test.ts +53 -25
  191. package/src/lib/__tests__/spanbuffer-materializer-parity.test.ts +266 -0
  192. package/src/lib/__tests__/sync-async-trace.test.ts +24 -23
  193. package/src/lib/__tests__/tag-writer-aot.test.ts +214 -0
  194. package/src/lib/__tests__/test-helpers.ts +67 -12
  195. package/src/lib/__tests__/threadId.test.ts +62 -0
  196. package/src/lib/__tests__/timestamp.test.ts +221 -93
  197. package/src/lib/__tests__/traceTopology.property.test.ts +383 -0
  198. package/src/lib/__tests__/type-narrowing.test.ts +63 -0
  199. package/src/lib/__tests__/vocabulary-dense-decoding.test.ts +405 -0
  200. package/src/lib/__tests__/vocabularyRegistry.test.ts +313 -0
  201. package/src/lib/arrow/lease.ts +43 -0
  202. package/src/lib/arrow/utils.ts +10 -14
  203. package/src/lib/arrow/vocabularyDictionary.ts +123 -0
  204. package/src/lib/bufferStrategy.ts +9 -1
  205. package/src/lib/cloudflare/traceRows.ts +3 -2
  206. package/src/lib/codegen/__tests__/evaluatorGenerator.test.ts +21 -141
  207. package/src/lib/codegen/__tests__/fixedPositionWriter-parity.test.ts +273 -0
  208. package/src/lib/codegen/__tests__/fixedPositionWriter-uint64.test.ts +61 -34
  209. package/src/lib/codegen/__tests__/nullBitmap.test.ts +33 -37
  210. package/src/lib/codegen/__tests__/spanLoggerGenerator.test.ts +34 -18
  211. package/src/lib/codegen/__tests__/spanLoggerMaterializerParity.test.ts +503 -0
  212. package/src/lib/codegen/evaluatorGenerator.ts +18 -13
  213. package/src/lib/codegen/fixedPositionWriterGenerator.ts +329 -245
  214. package/src/lib/codegen/spanLoggerClosureMaterializer.ts +598 -0
  215. package/src/lib/codegen/spanLoggerGenerator.ts +241 -177
  216. package/src/lib/convertToArrow.ts +598 -311
  217. package/src/lib/defineOpContext.ts +1 -1
  218. package/src/lib/enumMetadata.ts +121 -0
  219. package/src/lib/flushScheduler.ts +11 -5
  220. package/src/lib/library.ts +37 -595
  221. package/src/lib/logBinding.ts +21 -27
  222. package/src/lib/op.ts +75 -18
  223. package/src/lib/opContext/__tests__/retry.test.ts +27 -21
  224. package/src/lib/opContext/createOpGroup.ts +33 -31
  225. package/src/lib/opContext/defineOp.ts +88 -11
  226. package/src/lib/opContext/opGroupTypes.ts +2 -2
  227. package/src/lib/opContext/opTypes.ts +1 -1
  228. package/src/lib/opContext/spanContextTypes.ts +122 -24
  229. package/src/lib/opContext/types.ts +7 -3
  230. package/src/lib/physicalLayoutPlan.ts +598 -0
  231. package/src/lib/resolveMessage.ts +67 -0
  232. package/src/lib/result.ts +20 -33
  233. package/src/lib/runtimeHint.ts +98 -0
  234. package/src/lib/schema/__tests__/featureFlags.test.ts +2 -1
  235. package/src/lib/schema/builder.ts +1 -1
  236. package/src/lib/schema/typeGuards.ts +7 -151
  237. package/src/lib/schema/types.ts +1 -1
  238. package/src/lib/span-buffer/aot/v1.ts +26 -0
  239. package/src/lib/spanBuffer.ts +658 -92
  240. package/src/lib/spanBufferStats.ts +1 -1
  241. package/src/lib/spanContext.ts +1350 -861
  242. package/src/lib/sqlite/sqlite-common.ts +20 -31
  243. package/src/lib/testing/__tests__/topology-traversal.test.ts +174 -0
  244. package/src/lib/testing/__tests__/vitest-harness.test.ts +2 -1
  245. package/src/lib/testing/bun-harness.ts +94 -43
  246. package/src/lib/testing/extractFacts.ts +64 -78
  247. package/src/lib/testing/facts.ts +1 -1
  248. package/src/lib/testing/queryable-span.ts +23 -30
  249. package/src/lib/testing/span-query.ts +16 -20
  250. package/src/lib/testing/stdio-replay.ts +25 -8
  251. package/src/lib/testing/vitest-harness.ts +1 -1
  252. package/src/lib/threadId.ts +6 -3
  253. package/src/lib/traceContext.ts +1 -6
  254. package/src/lib/traceRoot.es.ts +77 -42
  255. package/src/lib/traceRoot.node.ts +75 -46
  256. package/src/lib/traceRoot.ts +41 -14
  257. package/src/lib/traceTopology.ts +279 -0
  258. package/src/lib/tracer.ts +109 -98
  259. package/src/lib/tracers/ArrayQueueTracer.ts +1 -1
  260. package/src/lib/tracers/StdioTracer.ts +15 -13
  261. package/src/lib/tracers/TestTracer.ts +6 -8
  262. package/src/lib/tracers/__tests__/ArrayQueueTracer.test.ts +15 -10
  263. package/src/lib/tracers/__tests__/CompositeTracer.test.ts +150 -0
  264. package/src/lib/tracers/__tests__/TestTracer.test.ts +23 -13
  265. package/src/lib/types.ts +64 -33
  266. package/src/lib/vocabularyRegistry.ts +439 -0
  267. package/src/lib/wasm/WasmBufferStrategy.ts +56 -48
  268. package/src/lib/wasm/__tests__/WasmBufferStrategy.test.ts +215 -11
  269. package/src/lib/wasm/__tests__/allocatorFreeBlockClamp.test.ts +86 -0
  270. package/src/lib/wasm/__tests__/wasm-identity-view.test.ts +311 -0
  271. package/src/lib/wasm/__tests__/wasm-integration.test.ts +417 -44
  272. package/src/lib/wasm/__tests__/wasm-message-buffer-families.test.ts +588 -0
  273. package/src/lib/wasm/__tests__/wasmAllocator.test.ts +100 -668
  274. package/src/lib/wasm/__tests__/wasmSpanBuffer.test.ts +419 -63
  275. package/src/lib/wasm/__tests__/wasmTraceRoot.test.ts +24 -29
  276. package/src/lib/wasm/__tests__/wasmTracer.test.ts.disabled +2 -2
  277. package/src/lib/wasm/wasmAllocator.ts +131 -96
  278. package/src/lib/wasm/wasmPhysicalLayout.ts +309 -0
  279. package/src/lib/wasm/wasmSpanBuffer.ts +597 -341
  280. package/src/lib/wasm/wasmTraceRoot.ts +140 -78
  281. package/src/vocabulary/register/v1.ts +1 -0
  282. package/src/wasm.ts +19 -0
  283. package/src/lib/__tests__/remapped-buffer-view-integration.test.ts +0 -319
  284. package/src/lib/__tests__/remapped-buffer-view.test.ts +0 -635
  285. package/src/lib/wasm/allocator.zig +0 -948
@@ -11,7 +11,10 @@
11
11
  */
12
12
 
13
13
  import { afterEach, beforeAll, describe, expect, it } from 'bun:test';
14
+ import { convertToArrowTable } from '../../convertToArrow.js';
14
15
  import { defineOpContext } from '../../defineOpContext.js';
16
+ import { JsBufferStrategy } from '../../JsBufferStrategy.js';
17
+ import { resolveEntryType, resolveMessage } from '../../resolveMessage.js';
15
18
  import { S } from '../../schema/builder.js';
16
19
  import { defineLogSchema } from '../../schema/defineLogSchema.js';
17
20
  import {
@@ -24,9 +27,11 @@ import {
24
27
  ENTRY_TYPE_SPAN_START,
25
28
  ENTRY_TYPE_WARN,
26
29
  } from '../../schema/systemSchema.js';
30
+ import { createTraceRoot as createNodeTraceRoot } from '../../traceRoot.node.js';
27
31
  import { TestTracer } from '../../tracers/TestTracer.js';
32
+ import { iterateSpanChildren } from '../../traceTopology.js';
28
33
  import { WasmBufferStrategy } from '../WasmBufferStrategy.js';
29
- import { createWasmTraceRootFactory } from '../wasmTraceRoot.js';
34
+ import { createWasmTraceRoot } from '../wasmTraceRoot.js';
30
35
 
31
36
  /**
32
37
  * Type for accessing WASM-specific internal buffer properties.
@@ -51,12 +56,22 @@ function asWasm<T>(buffer: T): T & WasmBufferInternals {
51
56
  return buffer as T & WasmBufferInternals;
52
57
  }
53
58
 
59
+ function requireOnlySpanChild(parent: Parameters<typeof iterateSpanChildren>[0], label: string) {
60
+ const children = iterateSpanChildren(parent);
61
+ const first = children.next();
62
+ if (first.done) throw new Error(`${label} has no child span`);
63
+ const extra = children.next();
64
+ if (!extra.done) throw new Error(`${label} has more than one child span`);
65
+ return first.value;
66
+ }
67
+
54
68
  describe('WASM Integration Tests', () => {
55
69
  // Test schema with various field types
56
70
  const schema = defineLogSchema({
57
71
  userId: S.category(),
58
72
  latency: S.number(),
59
73
  operation: S.enum(['CREATE', 'READ', 'UPDATE', 'DELETE']),
74
+ success: S.boolean(),
60
75
  });
61
76
 
62
77
  // Define op context - env is optional (undefined by default, not null-sentinel)
@@ -77,14 +92,14 @@ describe('WASM Integration Tests', () => {
77
92
 
78
93
  tracer = new TestTracer(opContext, {
79
94
  bufferStrategy: strategy,
80
- createTraceRoot: createWasmTraceRootFactory(strategy.allocator),
95
+ createTraceRoot: (traceId, lifecycle) => createWasmTraceRoot(strategy.allocator, traceId, lifecycle),
81
96
  });
82
97
  });
83
98
 
84
99
  afterEach(() => {
85
100
  // Release all WASM memory for buffers
86
101
  for (const buffer of tracer.rootBuffers) {
87
- strategy.releaseBuffer(buffer);
102
+ if (buffer._traceRoot._topology.count !== 0) strategy.releaseBuffer(buffer);
88
103
  }
89
104
  // Clear tracer state
90
105
  tracer.clear();
@@ -94,7 +109,7 @@ describe('WASM Integration Tests', () => {
94
109
  // Create fresh tracer for next test
95
110
  tracer = new TestTracer(opContext, {
96
111
  bufferStrategy: strategy,
97
- createTraceRoot: createWasmTraceRootFactory(strategy.allocator),
112
+ createTraceRoot: (traceId, lifecycle) => createWasmTraceRoot(strategy.allocator, traceId, lifecycle),
98
113
  });
99
114
  });
100
115
 
@@ -108,15 +123,15 @@ describe('WASM Integration Tests', () => {
108
123
  const buffer = tracer.rootBuffers[0];
109
124
 
110
125
  // Verify entry types
111
- expect(buffer.entry_type[0]).toBe(ENTRY_TYPE_SPAN_START);
112
- expect(buffer.entry_type[1]).toBe(ENTRY_TYPE_SPAN_OK);
126
+ expect(resolveEntryType(buffer, 0)).toBe(ENTRY_TYPE_SPAN_START);
127
+ expect(resolveEntryType(buffer, 1)).toBe(ENTRY_TYPE_SPAN_OK);
113
128
 
114
129
  // Verify timestamps are valid
115
130
  expect(buffer.timestamp[0]).toBeGreaterThan(0n);
116
131
  expect(buffer.timestamp[1]).toBeGreaterThanOrEqual(buffer.timestamp[0]);
117
132
 
118
133
  // Verify span name is set
119
- expect(buffer.message_values[0]).toBe('test-op');
134
+ expect(resolveMessage(buffer, 0)).toBe('test-op');
120
135
  });
121
136
 
122
137
  it('writes trace_id correctly', async () => {
@@ -182,14 +197,10 @@ describe('WASM Integration Tests', () => {
182
197
  });
183
198
 
184
199
  const parent = tracer.rootBuffers[0];
185
- expect(parent._children).toHaveLength(1);
186
-
187
- const child = parent._children[0];
188
- // Child should share trace_id with parent
200
+ if (!parent) throw new Error('nested trace did not produce a root buffer');
201
+ const child = requireOnlySpanChild(parent, 'nested trace root');
189
202
  expect(child.trace_id).toBe(parent.trace_id);
190
- // Child's parent_span_id should be parent's span_id
191
203
  expect(child.parent_span_id).toBe(parent.span_id);
192
- // Child should have its own span_id
193
204
  expect(child.span_id).not.toBe(parent.span_id);
194
205
  });
195
206
 
@@ -205,13 +216,11 @@ describe('WASM Integration Tests', () => {
205
216
  });
206
217
 
207
218
  const root = tracer.rootBuffers[0];
208
- expect(root._children).toHaveLength(1);
209
-
210
- const level1 = root._children[0];
211
- expect(level1._children).toHaveLength(1);
219
+ if (!root) throw new Error('deep trace did not produce a root buffer');
220
+ const level1 = requireOnlySpanChild(root, 'deep trace root');
212
221
  expect(level1.parent_span_id).toBe(root.span_id);
213
222
 
214
- const level2 = level1._children[0];
223
+ const level2 = requireOnlySpanChild(level1, 'level-1 span');
215
224
  expect(level2.parent_span_id).toBe(level1.span_id);
216
225
  expect(level2.trace_id).toBe(root.trace_id);
217
226
  });
@@ -224,14 +233,19 @@ describe('WASM Integration Tests', () => {
224
233
  });
225
234
 
226
235
  const parent = tracer.rootBuffers[0];
227
- expect(parent._children).toHaveLength(2);
228
-
229
- const [child1, child2] = parent._children;
230
- expect(child1.message_values[0]).toBe('child-1');
231
- expect(child2.message_values[0]).toBe('child-2');
236
+ if (!parent) throw new Error('sibling trace did not produce a root buffer');
237
+ const children = iterateSpanChildren(parent);
238
+ const first = children.next();
239
+ if (first.done) throw new Error('sibling trace did not produce its first child');
240
+ const second = children.next();
241
+ if (second.done) throw new Error('sibling trace did not produce its second child');
242
+ if (!children.next().done) throw new Error('sibling trace produced an unexpected extra child');
243
+ const child1 = first.value;
244
+ const child2 = second.value;
245
+ expect(resolveMessage(child1, 0)).toBe('child-1');
246
+ expect(resolveMessage(child2, 0)).toBe('child-2');
232
247
  expect(child1.parent_span_id).toBe(parent.span_id);
233
248
  expect(child2.parent_span_id).toBe(parent.span_id);
234
- // Siblings should have different span IDs
235
249
  expect(child1.span_id).not.toBe(child2.span_id);
236
250
  });
237
251
  });
@@ -247,12 +261,10 @@ describe('WASM Integration Tests', () => {
247
261
  }
248
262
 
249
263
  const buffer = asWasm(tracer.rootBuffers[0]);
250
- expect(buffer.entry_type[0]).toBe(ENTRY_TYPE_SPAN_START);
251
- expect(buffer.entry_type[1]).toBe(ENTRY_TYPE_SPAN_EXCEPTION);
264
+ expect(resolveEntryType(buffer, 0)).toBe(ENTRY_TYPE_SPAN_START);
265
+ expect(resolveEntryType(buffer, 1)).toBe(ENTRY_TYPE_SPAN_EXCEPTION);
252
266
 
253
- // Verify error message was written - use message_values getter
254
- const messageValues = buffer.message_values;
255
- const messages = messageValues.slice(0, buffer._writeIndex).filter((m: string) => m !== undefined);
267
+ const messages = Array.from({ length: buffer._writeIndex }, (_, row) => resolveMessage(buffer, row));
256
268
  expect(messages).toContain('test error');
257
269
  });
258
270
 
@@ -279,8 +291,8 @@ describe('WASM Integration Tests', () => {
279
291
  });
280
292
 
281
293
  const buffer = tracer.rootBuffers[0];
282
- expect(buffer.entry_type[0]).toBe(ENTRY_TYPE_SPAN_START);
283
- expect(buffer.entry_type[1]).toBe(ENTRY_TYPE_SPAN_ERR);
294
+ expect(resolveEntryType(buffer, 0)).toBe(ENTRY_TYPE_SPAN_START);
295
+ expect(resolveEntryType(buffer, 1)).toBe(ENTRY_TYPE_SPAN_ERR);
284
296
  });
285
297
 
286
298
  it('writes error code for typed errors', async () => {
@@ -289,7 +301,7 @@ describe('WASM Integration Tests', () => {
289
301
  });
290
302
 
291
303
  const buffer = asWasm(tracer.rootBuffers[0]);
292
- expect(buffer.entry_type[1]).toBe(ENTRY_TYPE_SPAN_ERR);
304
+ expect(resolveEntryType(buffer, 1)).toBe(ENTRY_TYPE_SPAN_ERR);
293
305
  // Error code should be written to error_code column
294
306
  expect(buffer.error_code_values?.[1]).toBe('VALIDATION_ERROR');
295
307
  });
@@ -310,21 +322,18 @@ describe('WASM Integration Tests', () => {
310
322
  expect(buffer._writeIndex).toBeGreaterThan(2);
311
323
 
312
324
  // Row 0 = span-start, Row 1 = span-ok (written at end)
313
- expect(buffer.entry_type[0]).toBe(ENTRY_TYPE_SPAN_START);
314
- expect(buffer.entry_type[1]).toBe(ENTRY_TYPE_SPAN_OK);
325
+ expect(resolveEntryType(buffer, 0)).toBe(ENTRY_TYPE_SPAN_START);
326
+ expect(resolveEntryType(buffer, 1)).toBe(ENTRY_TYPE_SPAN_OK);
315
327
 
316
328
  // Log entries are written at indices 2+
317
- const entryTypes = Array.from(buffer.entry_type.slice(0, buffer._writeIndex));
329
+ const entryTypes = Array.from({ length: buffer._writeIndex }, (_, row) => resolveEntryType(buffer, row));
318
330
 
319
331
  // Use entry type constants from systemSchema
320
332
  expect(entryTypes).toContain(ENTRY_TYPE_INFO);
321
333
  expect(entryTypes).toContain(ENTRY_TYPE_DEBUG);
322
334
  expect(entryTypes).toContain(ENTRY_TYPE_WARN);
323
335
 
324
- // Messages are written via message_values getter (SpanLogger uses this)
325
- // Access via the getter since that's what SpanLogger writes to
326
- const messageValues = buffer.message_values;
327
- const messages = messageValues.slice(0, buffer._writeIndex).filter((m: string) => m !== undefined);
336
+ const messages = Array.from({ length: buffer._writeIndex }, (_, row) => resolveMessage(buffer, row));
328
337
  expect(messages).toContain('info message');
329
338
  expect(messages).toContain('debug message');
330
339
  expect(messages).toContain('warn message');
@@ -338,11 +347,176 @@ describe('WASM Integration Tests', () => {
338
347
 
339
348
  const buffer = asWasm(tracer.rootBuffers[0]);
340
349
  // Use entry type constant from systemSchema
341
- const entryTypes = Array.from(buffer.entry_type.slice(0, buffer._writeIndex));
350
+ const entryTypes = Array.from({ length: buffer._writeIndex }, (_, row) => resolveEntryType(buffer, row));
342
351
  expect(entryTypes).toContain(ENTRY_TYPE_ERROR);
343
352
  });
344
353
  });
345
354
 
355
+ describe('Identity ownership', () => {
356
+ it('invalidates released root and child handles before recycled memory is reused', async () => {
357
+ await tracer.trace('owned-root', async (ctx) => {
358
+ await ctx.span('released-child', async (child) => child.ok('child done'));
359
+ return ctx.ok('root done');
360
+ });
361
+
362
+ const root = tracer.rootBuffers[0];
363
+ if (!root) throw new Error('released trace did not produce a root buffer');
364
+ const child = requireOnlySpanChild(root, 'released trace root');
365
+ const topology = root._traceRoot._topology;
366
+ const rootTraceId = root.trace_id;
367
+ const rootSpanId = root.span_id;
368
+ expect(child.trace_id).toBe(rootTraceId);
369
+ expect(child.span_id).not.toBe(rootSpanId);
370
+ expect(child.parent_span_id).toBe(rootSpanId);
371
+ expect(child._identity).not.toEqual(root._identity);
372
+
373
+ strategy.releaseBuffer(root);
374
+ expect(topology.count).toBe(0);
375
+ expect(() => topology.assertLive(root)).toThrow(/stale/);
376
+ expect(() => topology.assertLive(child)).toThrow(/stale/);
377
+ expect(() => iterateSpanChildren(root).next()).toThrow(/stale/);
378
+
379
+ await tracer.trace('recycled-child-identity', async (ctx) => ctx.ok('done'));
380
+ const recycled = tracer.rootBuffers[1];
381
+ if (!recycled) throw new Error('recycled trace did not produce a root buffer');
382
+ expect(recycled.trace_id).not.toBe(rootTraceId);
383
+ expect(resolveMessage(recycled, 0)).toBe('recycled-child-identity');
384
+ });
385
+
386
+ it('preserves logical span identity and linkage across overflow segments', async () => {
387
+ await tracer.trace('overflow-root', async (ctx) => {
388
+ for (let i = 0; i < 64; i++) {
389
+ ctx.log.info(`root-log-${i}`);
390
+ }
391
+ await ctx.span('overflow-child', async (child) => {
392
+ for (let i = 0; i < 64; i++) {
393
+ child.log.info(`child-log-${i}`);
394
+ }
395
+ return child.ok('child done');
396
+ });
397
+ return ctx.ok('root done');
398
+ });
399
+
400
+ const root = tracer.rootBuffers[0];
401
+ const rootOverflow = root._overflow;
402
+ if (!rootOverflow) throw new Error('root logs did not create an overflow segment');
403
+ expect(rootOverflow.trace_id).toBe(root.trace_id);
404
+ expect(rootOverflow.span_id).toBe(root.span_id);
405
+ expect(rootOverflow.parent_span_id).toBe(root.parent_span_id);
406
+ expect(rootOverflow._identity).toEqual(root._identity);
407
+
408
+ const child = requireOnlySpanChild(root, 'overflow trace root');
409
+ const childOverflow = child._overflow;
410
+ if (!childOverflow) throw new Error('child logs did not create an overflow segment');
411
+ expect(child.trace_id).toBe(root.trace_id);
412
+ expect(child.span_id).not.toBe(root.span_id);
413
+ expect(child.parent_span_id).toBe(root.span_id);
414
+ expect(childOverflow.trace_id).toBe(child.trace_id);
415
+ expect(childOverflow.span_id).toBe(child.span_id);
416
+ expect(childOverflow.parent_span_id).toBe(child.parent_span_id);
417
+ expect(childOverflow._identity).toEqual(child._identity);
418
+ });
419
+ });
420
+
421
+ describe('Released memory ownership', () => {
422
+ it('keeps two new traces independent after repeated tree release', async () => {
423
+ await tracer.trace('released-tree', async (ctx) => {
424
+ await ctx.span('released-child', async (child) => {
425
+ child.tag.latency(1);
426
+ return child.ok('done');
427
+ });
428
+ return ctx.ok('done');
429
+ });
430
+
431
+ const released = tracer.rootBuffers[0];
432
+ strategy.releaseBuffer(released);
433
+ expect(() => strategy.releaseBuffer(released)).toThrow(/stale/);
434
+
435
+ await tracer.trace('first-new-owner', async (ctx) => {
436
+ ctx.tag.latency(11.5);
437
+ return ctx.ok('done');
438
+ });
439
+ await tracer.trace('second-new-owner', async (ctx) => {
440
+ ctx.tag.latency(22.5);
441
+ return ctx.ok('done');
442
+ });
443
+
444
+ const firstTable = strategy.toArrowTable(tracer.rootBuffers[1]);
445
+ const secondTable = strategy.toArrowTable(tracer.rootBuffers[2]);
446
+ expect(firstTable.getChild('message')?.get(0)).toBe('first-new-owner');
447
+ expect(firstTable.getChild('latency')?.get(0)).toBe(11.5);
448
+ expect(secondTable.getChild('message')?.get(0)).toBe('second-new-owner');
449
+ expect(secondTable.getChild('latency')?.get(0)).toBe(22.5);
450
+ });
451
+
452
+ it('keeps single-buffer Arrow output isolated from recycled WASM memory', async () => {
453
+ await tracer.trace('arrow-first', async (ctx) => {
454
+ ctx.tag.latency(91.25).success(true).operation('READ');
455
+ return ctx.ok('done');
456
+ });
457
+
458
+ const firstBuffer = tracer.rootBuffers[0];
459
+ const firstTable = convertToArrowTable(firstBuffer);
460
+ expect(firstTable.numRows).toBe(2);
461
+ expect(firstTable.getChild('message')?.get(0)).toBe('arrow-first');
462
+ expect(firstTable.getChild('latency')?.get(0)).toBe(91.25);
463
+ expect(firstTable.getChild('success')?.get(0)).toBe(true);
464
+ expect(firstTable.getChild('operation')?.get(0)).toBe('READ');
465
+
466
+ strategy.releaseBuffer(firstBuffer);
467
+ await tracer.trace('arrow-second', async (ctx) => {
468
+ ctx.tag.latency(-17.5).success(false).operation('DELETE');
469
+ return ctx.ok('done');
470
+ });
471
+
472
+ const secondTable = convertToArrowTable(tracer.rootBuffers[1]);
473
+ expect(secondTable.getChild('latency')?.get(0)).toBe(-17.5);
474
+ expect(secondTable.getChild('success')?.get(0)).toBe(false);
475
+ expect(secondTable.getChild('operation')?.get(0)).toBe('DELETE');
476
+ expect(firstTable.getChild('message')?.get(0)).toBe('arrow-first');
477
+ expect(firstTable.getChild('latency')?.get(0)).toBe(91.25);
478
+ expect(firstTable.getChild('success')?.get(0)).toBe(true);
479
+ expect(firstTable.getChild('operation')?.get(0)).toBe('READ');
480
+ });
481
+
482
+ it('keeps span-tree Arrow output isolated from recycled WASM memory', async () => {
483
+ await tracer.trace('tree-first', async (ctx) => {
484
+ ctx.tag.latency(1.25);
485
+ await ctx.span('child-first', async (child) => {
486
+ child.tag.latency(2.5);
487
+ return child.ok('done');
488
+ });
489
+ return ctx.ok('done');
490
+ });
491
+
492
+ const firstBuffer = tracer.rootBuffers[0];
493
+ const firstTable = strategy.toArrowTable(firstBuffer);
494
+ expect(firstTable.numRows).toBe(4);
495
+ expect(firstTable.getChild('message')?.get(0)).toBe('tree-first');
496
+ expect(firstTable.getChild('message')?.get(2)).toBe('child-first');
497
+ expect(firstTable.getChild('latency')?.get(0)).toBe(1.25);
498
+ expect(firstTable.getChild('latency')?.get(2)).toBe(2.5);
499
+
500
+ strategy.releaseBuffer(firstBuffer);
501
+ await tracer.trace('tree-second', async (ctx) => {
502
+ ctx.tag.latency(101.25);
503
+ await ctx.span('child-second', async (child) => {
504
+ child.tag.latency(202.5);
505
+ return child.ok('done');
506
+ });
507
+ return ctx.ok('done');
508
+ });
509
+
510
+ const secondTable = strategy.toArrowTable(tracer.rootBuffers[1]);
511
+ expect(secondTable.getChild('latency')?.get(0)).toBe(101.25);
512
+ expect(secondTable.getChild('latency')?.get(2)).toBe(202.5);
513
+ expect(firstTable.getChild('message')?.get(0)).toBe('tree-first');
514
+ expect(firstTable.getChild('message')?.get(2)).toBe('child-first');
515
+ expect(firstTable.getChild('latency')?.get(0)).toBe(1.25);
516
+ expect(firstTable.getChild('latency')?.get(2)).toBe(2.5);
517
+ });
518
+ });
519
+
346
520
  describe('Memory reuse', () => {
347
521
  it('tracks allocation stats', async () => {
348
522
  const statsBefore = strategy.getStats();
@@ -422,7 +596,7 @@ describe('WASM Integration Tests', () => {
422
596
  }
423
597
 
424
598
  const buffer = tracer.rootBuffers[0];
425
- expect(buffer.entry_type[1]).toBe(ENTRY_TYPE_SPAN_OK);
599
+ expect(resolveEntryType(buffer, 1)).toBe(ENTRY_TYPE_SPAN_OK);
426
600
  });
427
601
 
428
602
  it('handles async functions correctly', async () => {
@@ -438,12 +612,211 @@ describe('WASM Integration Tests', () => {
438
612
  }
439
613
 
440
614
  const buffer = tracer.rootBuffers[0];
441
- expect(buffer.entry_type[1]).toBe(ENTRY_TYPE_SPAN_OK);
615
+ expect(resolveEntryType(buffer, 1)).toBe(ENTRY_TYPE_SPAN_OK);
442
616
  // Timestamps should reflect the delay
443
617
  expect(buffer.timestamp[1]).toBeGreaterThan(buffer.timestamp[0]);
444
618
  });
445
619
  });
446
620
 
621
+ describe('JS/WASM timestamp output parity', () => {
622
+ it('emits identical timestamped lifecycle rows across overflow and child spans', async () => {
623
+ const jsSchema = defineLogSchema({
624
+ userId: S.category(),
625
+ latency: S.number(),
626
+ operation: S.enum(['CREATE', 'READ', 'UPDATE', 'DELETE']),
627
+ success: S.boolean(),
628
+ });
629
+ const jsOpContext = defineOpContext({
630
+ logSchema: jsSchema,
631
+ ctx: { env: undefined as { region: string } | undefined },
632
+ });
633
+ const jsStrategy = new JsBufferStrategy<typeof jsSchema>();
634
+ const jsTracer = new TestTracer(jsOpContext, {
635
+ bufferStrategy: jsStrategy,
636
+ createTraceRoot: createNodeTraceRoot,
637
+ });
638
+ const originalDateNow = Date.now;
639
+ const originalHrtime = process.hrtime.bigint;
640
+ const originalPerformanceNow = performance.now;
641
+ const epochMillis = 1_700_000_000_000;
642
+ const nodeAnchor = 5_000_000n;
643
+ const performanceAnchor = 1_000;
644
+
645
+ try {
646
+ Date.now = () => epochMillis;
647
+ let nodeTick = 0n;
648
+ process.hrtime.bigint = () => nodeAnchor + nodeTick++ * 125_000n;
649
+ await jsTracer.trace('parity-root', async (root) => {
650
+ for (let i = 0; i < 70; i++) root.log.info(`root-${i}`);
651
+ await root.span('parity-child', async (child) => {
652
+ for (let i = 0; i < 70; i++) child.log.info(`child-${i}`);
653
+ return child.ok('child done');
654
+ });
655
+ return root.ok('root done');
656
+ });
657
+
658
+ let performanceTick = 0;
659
+ Object.defineProperty(performance, 'now', {
660
+ configurable: true,
661
+ value: () => performanceAnchor + performanceTick++ * 0.125,
662
+ });
663
+ await tracer.trace('parity-root', async (root) => {
664
+ for (let i = 0; i < 70; i++) root.log.info(`root-${i}`);
665
+ await root.span('parity-child', async (child) => {
666
+ for (let i = 0; i < 70; i++) child.log.info(`child-${i}`);
667
+ return child.ok('child done');
668
+ });
669
+ return root.ok('root done');
670
+ });
671
+
672
+ const jsTable = jsStrategy.toArrowTable(jsTracer.rootBuffers[0]);
673
+ const wasmTable = strategy.toArrowTable(tracer.rootBuffers[0]);
674
+ expect(wasmTable.numRows).toBe(jsTable.numRows);
675
+ for (const columnName of ['entry_type', 'message', 'timestamp'] as const) {
676
+ const jsColumn = jsTable.getChild(columnName);
677
+ const wasmColumn = wasmTable.getChild(columnName);
678
+ if (!jsColumn || !wasmColumn) throw new Error(`missing parity column: ${columnName}`);
679
+ const jsValues = Array.from({ length: jsTable.numRows }, (_, row) => jsColumn.get(row));
680
+ const wasmValues = Array.from({ length: wasmTable.numRows }, (_, row) => wasmColumn.get(row));
681
+ expect(wasmValues).toEqual(jsValues);
682
+ }
683
+ } finally {
684
+ Date.now = originalDateNow;
685
+ process.hrtime.bigint = originalHrtime;
686
+ Object.defineProperty(performance, 'now', { configurable: true, value: originalPerformanceNow });
687
+ }
688
+ });
689
+
690
+ it('preserves ordered Arrow rows for root, child, grandchild, random, and overflow workloads', async () => {
691
+ const jsStrategy = new JsBufferStrategy<typeof schema>();
692
+ const jsTracer = new TestTracer(opContext, {
693
+ bufferStrategy: jsStrategy,
694
+ createTraceRoot: createNodeTraceRoot,
695
+ });
696
+ const workloads = [
697
+ {
698
+ name: 'root',
699
+ run: async (target: typeof tracer) => {
700
+ await target.trace('ordered-root', async (root) => {
701
+ root.tag.latency(1.25).success(true).operation('CREATE');
702
+ root.log.info('ordered-root-log');
703
+ return root.ok('root done');
704
+ });
705
+ return ['ordered-root'];
706
+ },
707
+ },
708
+ {
709
+ name: 'child',
710
+ run: async (target: typeof tracer) => {
711
+ await target.trace('ordered-parent', async (root) => {
712
+ await root.span('ordered-child-0', async (child) => child.ok('first child done'));
713
+ await root.span('ordered-child-1', async (child) => child.ok('second child done'));
714
+ return root.ok('parent done');
715
+ });
716
+ return ['ordered-parent', 'ordered-child-0', 'ordered-child-1'];
717
+ },
718
+ },
719
+ {
720
+ name: 'grandchild',
721
+ run: async (target: typeof tracer) => {
722
+ await target.trace('ordered-grand-root', async (root) => {
723
+ await root.span('ordered-branch', async (child) => {
724
+ await child.span('ordered-grandchild', async (grandchild) => grandchild.ok('grandchild done'));
725
+ return child.ok('branch done');
726
+ });
727
+ await root.span('ordered-sibling', async (child) => child.ok('sibling done'));
728
+ return root.ok('grand root done');
729
+ });
730
+ return ['ordered-grand-root', 'ordered-branch', 'ordered-grandchild', 'ordered-sibling'];
731
+ },
732
+ },
733
+ {
734
+ name: 'random',
735
+ run: async (target: typeof tracer) => {
736
+ let state = 0x6d2b_79f5;
737
+ const next = () => {
738
+ state = (Math.imul(state, 1_664_525) + 1_013_904_223) >>> 0;
739
+ return state;
740
+ };
741
+ const expected = ['random-root'];
742
+ await target.trace('random-root', async (root) => {
743
+ for (let childIndex = 0; childIndex < 24; childIndex++) {
744
+ const childName = `random-child-${childIndex}`;
745
+ expected.push(childName);
746
+ await root.span(childName, async (child) => {
747
+ const logCount = next() % 6;
748
+ for (let logIndex = 0; logIndex < logCount; logIndex++) {
749
+ child.log.info(`random-log-${childIndex}-${logIndex}`);
750
+ }
751
+ const grandchildCount = next() % 4;
752
+ for (let grandchildIndex = 0; grandchildIndex < grandchildCount; grandchildIndex++) {
753
+ const grandchildName = `random-grandchild-${childIndex}-${grandchildIndex}`;
754
+ expected.push(grandchildName);
755
+ await child.span(grandchildName, async (grandchild) => {
756
+ grandchild.tag.latency(next() % 10_000).operation('UPDATE');
757
+ return grandchild.ok('random grandchild done');
758
+ });
759
+ }
760
+ return child.ok('random child done');
761
+ });
762
+ }
763
+ return root.ok('random root done');
764
+ });
765
+ return expected;
766
+ },
767
+ },
768
+ {
769
+ name: 'overflow',
770
+ run: async (target: typeof tracer) => {
771
+ await target.trace('overflow-parity-root', async (root) => {
772
+ for (let index = 0; index < 70; index++) root.log.info(`overflow-root-${index}`);
773
+ await root.span('overflow-parity-child', async (child) => {
774
+ for (let index = 0; index < 70; index++) child.log.info(`overflow-child-${index}`);
775
+ return child.ok('overflow child done');
776
+ });
777
+ return root.ok('overflow root done');
778
+ });
779
+ return ['overflow-parity-root', 'overflow-parity-child'];
780
+ },
781
+ },
782
+ ];
783
+
784
+ for (const workload of workloads) {
785
+ const jsRootIndex = jsTracer.rootBuffers.length;
786
+ const wasmRootIndex = tracer.rootBuffers.length;
787
+ const jsExpected = await workload.run(jsTracer);
788
+ const wasmExpected = await workload.run(tracer);
789
+ expect(wasmExpected).toEqual(jsExpected);
790
+
791
+ const jsRoot = jsTracer.rootBuffers[jsRootIndex];
792
+ if (!jsRoot) throw new Error(`${workload.name} JS workload did not produce a root buffer`);
793
+ const wasmRoot = tracer.rootBuffers[wasmRootIndex];
794
+ if (!wasmRoot) throw new Error(`${workload.name} WASM workload did not produce a root buffer`);
795
+ const jsTable = jsStrategy.toArrowTable(jsRoot);
796
+ const wasmTable = strategy.toArrowTable(wasmRoot);
797
+ expect(wasmTable.numRows).toBe(jsTable.numRows);
798
+
799
+ for (const columnName of ['entry_type', 'message', 'latency', 'success', 'operation']) {
800
+ const jsColumn = jsTable.getChild(columnName);
801
+ const wasmColumn = wasmTable.getChild(columnName);
802
+ if (!jsColumn || !wasmColumn) throw new Error(`${workload.name} is missing parity column ${columnName}`);
803
+ const jsValues = Array.from({ length: jsTable.numRows }, (_, row) => jsColumn.get(row));
804
+ const wasmValues = Array.from({ length: wasmTable.numRows }, (_, row) => wasmColumn.get(row));
805
+ expect(wasmValues).toEqual(jsValues);
806
+ }
807
+
808
+ const entryTypes = wasmTable.getChild('entry_type');
809
+ const messages = wasmTable.getChild('message');
810
+ if (!entryTypes || !messages) throw new Error(`${workload.name} is missing ordered span columns`);
811
+ const spanOrder: unknown[] = [];
812
+ for (let row = 0; row < wasmTable.numRows; row++) {
813
+ if (entryTypes.get(row) === 'span-start') spanOrder.push(messages.get(row));
814
+ }
815
+ expect(spanOrder).toEqual(wasmExpected);
816
+ }
817
+ });
818
+ });
819
+
447
820
  describe('Multiple traces', () => {
448
821
  it('maintains separate buffers for each trace', async () => {
449
822
  await tracer.trace('trace-1', async (ctx) => {
@@ -465,8 +838,8 @@ describe('WASM Integration Tests', () => {
465
838
  expect(buffer1.trace_id).not.toBe(buffer2.trace_id);
466
839
 
467
840
  // Different span names
468
- expect(buffer1.message_values[0]).toBe('trace-1');
469
- expect(buffer2.message_values[0]).toBe('trace-2');
841
+ expect(resolveMessage(buffer1, 0)).toBe('trace-1');
842
+ expect(resolveMessage(buffer2, 0)).toBe('trace-2');
470
843
 
471
844
  // Different user IDs
472
845
  expect(buffer1.userId_values?.[0]).toBe('user-1');