@smoothbricks/lmao 0.2.2 → 0.2.3

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 (276) hide show
  1. package/dist/allocator.wasm +0 -0
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +1 -0
  5. package/dist/lib/JsBufferStrategy.d.ts +4 -3
  6. package/dist/lib/JsBufferStrategy.d.ts.map +1 -1
  7. package/dist/lib/JsBufferStrategy.js +18 -11
  8. package/dist/lib/arrow/lease.d.ts +10 -0
  9. package/dist/lib/arrow/lease.d.ts.map +1 -0
  10. package/dist/lib/arrow/lease.js +33 -0
  11. package/dist/lib/arrow/utils.d.ts +3 -4
  12. package/dist/lib/arrow/utils.d.ts.map +1 -1
  13. package/dist/lib/arrow/utils.js +12 -13
  14. package/dist/lib/arrow/vocabularyDictionary.d.ts +21 -0
  15. package/dist/lib/arrow/vocabularyDictionary.d.ts.map +1 -0
  16. package/dist/lib/arrow/vocabularyDictionary.js +95 -0
  17. package/dist/lib/bufferStrategy.d.ts +3 -2
  18. package/dist/lib/bufferStrategy.d.ts.map +1 -1
  19. package/dist/lib/cloudflare/traceRows.d.ts.map +1 -1
  20. package/dist/lib/cloudflare/traceRows.js +3 -2
  21. package/dist/lib/codegen/evaluatorGenerator.d.ts.map +1 -1
  22. package/dist/lib/codegen/evaluatorGenerator.js +12 -11
  23. package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts +44 -82
  24. package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts.map +1 -1
  25. package/dist/lib/codegen/fixedPositionWriterGenerator.js +223 -162
  26. package/dist/lib/codegen/spanLoggerClosureMaterializer.d.ts +63 -0
  27. package/dist/lib/codegen/spanLoggerClosureMaterializer.d.ts.map +1 -0
  28. package/dist/lib/codegen/spanLoggerClosureMaterializer.js +447 -0
  29. package/dist/lib/codegen/spanLoggerGenerator.d.ts +36 -19
  30. package/dist/lib/codegen/spanLoggerGenerator.d.ts.map +1 -1
  31. package/dist/lib/codegen/spanLoggerGenerator.js +164 -158
  32. package/dist/lib/convertToArrow.d.ts +7 -2
  33. package/dist/lib/convertToArrow.d.ts.map +1 -1
  34. package/dist/lib/convertToArrow.js +499 -285
  35. package/dist/lib/defineOpContext.js +1 -1
  36. package/dist/lib/enumMetadata.d.ts +19 -0
  37. package/dist/lib/enumMetadata.d.ts.map +1 -0
  38. package/dist/lib/enumMetadata.js +86 -0
  39. package/dist/lib/flushScheduler.d.ts.map +1 -1
  40. package/dist/lib/flushScheduler.js +13 -4
  41. package/dist/lib/library.d.ts +16 -98
  42. package/dist/lib/library.d.ts.map +1 -1
  43. package/dist/lib/library.js +32 -525
  44. package/dist/lib/logBinding.d.ts +21 -27
  45. package/dist/lib/logBinding.d.ts.map +1 -1
  46. package/dist/lib/op.d.ts +30 -30
  47. package/dist/lib/op.d.ts.map +1 -1
  48. package/dist/lib/op.js +15 -22
  49. package/dist/lib/opContext/createOpGroup.d.ts +1 -1
  50. package/dist/lib/opContext/createOpGroup.d.ts.map +1 -1
  51. package/dist/lib/opContext/createOpGroup.js +22 -29
  52. package/dist/lib/opContext/defineOp.d.ts +4 -4
  53. package/dist/lib/opContext/defineOp.d.ts.map +1 -1
  54. package/dist/lib/opContext/defineOp.js +53 -10
  55. package/dist/lib/opContext/opGroupTypes.d.ts +2 -2
  56. package/dist/lib/opContext/opTypes.d.ts +1 -1
  57. package/dist/lib/opContext/opTypes.d.ts.map +1 -1
  58. package/dist/lib/opContext/spanContextTypes.d.ts +29 -14
  59. package/dist/lib/opContext/spanContextTypes.d.ts.map +1 -1
  60. package/dist/lib/opContext/types.d.ts +4 -4
  61. package/dist/lib/opContext/types.d.ts.map +1 -1
  62. package/dist/lib/physicalLayoutPlan.d.ts +89 -0
  63. package/dist/lib/physicalLayoutPlan.d.ts.map +1 -0
  64. package/dist/lib/physicalLayoutPlan.js +442 -0
  65. package/dist/lib/resolveMessage.d.ts +9 -0
  66. package/dist/lib/resolveMessage.d.ts.map +1 -0
  67. package/dist/lib/resolveMessage.js +63 -0
  68. package/dist/lib/result.d.ts +5 -7
  69. package/dist/lib/result.d.ts.map +1 -1
  70. package/dist/lib/result.js +19 -26
  71. package/dist/lib/runtimeHint.d.ts +35 -0
  72. package/dist/lib/runtimeHint.d.ts.map +1 -0
  73. package/dist/lib/runtimeHint.js +79 -0
  74. package/dist/lib/schema/types.d.ts +1 -1
  75. package/dist/lib/schema/types.d.ts.map +1 -1
  76. package/dist/lib/span-buffer/aot/v1.d.ts +2 -0
  77. package/dist/lib/span-buffer/aot/v1.d.ts.map +1 -0
  78. package/dist/lib/span-buffer/aot/v1.js +24 -0
  79. package/dist/lib/spanBuffer.d.ts +33 -4
  80. package/dist/lib/spanBuffer.d.ts.map +1 -1
  81. package/dist/lib/spanBuffer.js +583 -91
  82. package/dist/lib/spanBufferStats.d.ts +1 -1
  83. package/dist/lib/spanBufferStats.d.ts.map +1 -1
  84. package/dist/lib/spanContext.d.ts +27 -51
  85. package/dist/lib/spanContext.d.ts.map +1 -1
  86. package/dist/lib/spanContext.js +822 -344
  87. package/dist/lib/sqlite/sqlite-common.d.ts.map +1 -1
  88. package/dist/lib/sqlite/sqlite-common.js +20 -21
  89. package/dist/lib/testing/bun-harness.d.ts +8 -3
  90. package/dist/lib/testing/bun-harness.d.ts.map +1 -1
  91. package/dist/lib/testing/bun-harness.js +30 -18
  92. package/dist/lib/testing/extractFacts.d.ts +1 -1
  93. package/dist/lib/testing/extractFacts.d.ts.map +1 -1
  94. package/dist/lib/testing/extractFacts.js +55 -63
  95. package/dist/lib/testing/facts.d.ts +1 -1
  96. package/dist/lib/testing/facts.d.ts.map +1 -1
  97. package/dist/lib/testing/queryable-span.d.ts +1 -1
  98. package/dist/lib/testing/queryable-span.d.ts.map +1 -1
  99. package/dist/lib/testing/queryable-span.js +26 -28
  100. package/dist/lib/testing/span-query.d.ts.map +1 -1
  101. package/dist/lib/testing/span-query.js +19 -22
  102. package/dist/lib/testing/stdio-replay.d.ts.map +1 -1
  103. package/dist/lib/testing/stdio-replay.js +19 -8
  104. package/dist/lib/threadId.d.ts.map +1 -1
  105. package/dist/lib/threadId.js +6 -3
  106. package/dist/lib/traceRoot.d.ts +30 -8
  107. package/dist/lib/traceRoot.d.ts.map +1 -1
  108. package/dist/lib/traceRoot.es.d.ts +17 -15
  109. package/dist/lib/traceRoot.es.d.ts.map +1 -1
  110. package/dist/lib/traceRoot.es.js +68 -34
  111. package/dist/lib/traceRoot.js +11 -0
  112. package/dist/lib/traceRoot.node.d.ts +17 -19
  113. package/dist/lib/traceRoot.node.d.ts.map +1 -1
  114. package/dist/lib/traceRoot.node.js +66 -38
  115. package/dist/lib/traceTopology.d.ts +42 -0
  116. package/dist/lib/traceTopology.d.ts.map +1 -0
  117. package/dist/lib/traceTopology.js +260 -0
  118. package/dist/lib/tracer.d.ts +9 -5
  119. package/dist/lib/tracer.d.ts.map +1 -1
  120. package/dist/lib/tracer.js +65 -71
  121. package/dist/lib/tracers/ArrayQueueTracer.d.ts +1 -1
  122. package/dist/lib/tracers/ArrayQueueTracer.js +1 -1
  123. package/dist/lib/tracers/StdioTracer.d.ts.map +1 -1
  124. package/dist/lib/tracers/StdioTracer.js +15 -13
  125. package/dist/lib/tracers/TestTracer.d.ts +4 -6
  126. package/dist/lib/tracers/TestTracer.d.ts.map +1 -1
  127. package/dist/lib/tracers/TestTracer.js +6 -8
  128. package/dist/lib/types.d.ts +49 -32
  129. package/dist/lib/types.d.ts.map +1 -1
  130. package/dist/lib/vocabularyRegistry.d.ts +25 -0
  131. package/dist/lib/vocabularyRegistry.d.ts.map +1 -0
  132. package/dist/lib/vocabularyRegistry.js +372 -0
  133. package/dist/lib/wasm/WasmBufferStrategy.d.ts +6 -10
  134. package/dist/lib/wasm/WasmBufferStrategy.d.ts.map +1 -1
  135. package/dist/lib/wasm/WasmBufferStrategy.js +44 -37
  136. package/dist/lib/wasm/wasmAllocator.d.ts +27 -22
  137. package/dist/lib/wasm/wasmAllocator.d.ts.map +1 -1
  138. package/dist/lib/wasm/wasmAllocator.js +66 -44
  139. package/dist/lib/wasm/wasmPhysicalLayout.d.ts +67 -0
  140. package/dist/lib/wasm/wasmPhysicalLayout.d.ts.map +1 -0
  141. package/dist/lib/wasm/wasmPhysicalLayout.js +179 -0
  142. package/dist/lib/wasm/wasmSpanBuffer.d.ts +79 -31
  143. package/dist/lib/wasm/wasmSpanBuffer.d.ts.map +1 -1
  144. package/dist/lib/wasm/wasmSpanBuffer.js +442 -272
  145. package/dist/lib/wasm/wasmTraceRoot.d.ts +24 -22
  146. package/dist/lib/wasm/wasmTraceRoot.d.ts.map +1 -1
  147. package/dist/lib/wasm/wasmTraceRoot.js +110 -71
  148. package/dist/vocabulary/register/v1.d.ts +2 -0
  149. package/dist/vocabulary/register/v1.d.ts.map +1 -0
  150. package/dist/vocabulary/register/v1.js +1 -0
  151. package/dist/wasm.d.ts +5 -0
  152. package/dist/wasm.d.ts.map +1 -0
  153. package/dist/wasm.js +4 -0
  154. package/package.json +54 -6
  155. package/src/index.ts +1 -0
  156. package/src/lib/JsBufferStrategy.ts +27 -9
  157. package/src/lib/__tests__/arrow-builder-integration/arrow-conversion.test.ts +335 -37
  158. package/src/lib/__tests__/arrow-builder-integration/binary-arrow-conversion.test.ts +97 -26
  159. package/src/lib/__tests__/arrow-builder-integration/binary-comparison.test.ts +75 -15
  160. package/src/lib/__tests__/arrow-builder-integration/binary-format-compliance.test.ts +30 -6
  161. package/src/lib/__tests__/arrow-builder-integration/buffer-chaining.test.ts +18 -21
  162. package/src/lib/__tests__/arrow-builder-integration/foundation.test.ts +5 -2
  163. package/src/lib/__tests__/arrow-builder-integration/integration.test.ts +25 -7
  164. package/src/lib/__tests__/arrow-builder-integration/lazy-columns.test.ts +3 -2
  165. package/src/lib/__tests__/buffer-overflow.test.ts +24 -18
  166. package/src/lib/__tests__/capability-span-context.test.ts +505 -0
  167. package/src/lib/__tests__/capacity-tuning.test.ts +5 -3
  168. package/src/lib/__tests__/eager-columns.test.ts +345 -0
  169. package/src/lib/__tests__/enum-metadata-aot.test.ts +153 -0
  170. package/src/lib/__tests__/enum-metadata.test.ts +177 -0
  171. package/src/lib/__tests__/fixtures/empty-vocabulary-runtime.fixture.ts +15 -0
  172. package/src/lib/__tests__/flushScheduler.test.ts +5 -1
  173. package/src/lib/__tests__/identity-view.property.test.ts +179 -0
  174. package/src/lib/__tests__/library.test.ts +19 -235
  175. package/src/lib/__tests__/message-buffer-families.test.ts +878 -0
  176. package/src/lib/__tests__/nested-library-tasks.test.ts +14 -15
  177. package/src/lib/__tests__/op-metadata.test.ts +1 -1
  178. package/src/lib/__tests__/op-type-safety.test.ts +5 -16
  179. package/src/lib/__tests__/physical-layout-plan.test.ts +333 -0
  180. package/src/lib/__tests__/remap-descriptor-integration.test.ts +381 -0
  181. package/src/lib/__tests__/root-context-construction.test.ts +414 -0
  182. package/src/lib/__tests__/span-auto-runtime.test.ts +386 -0
  183. package/src/lib/__tests__/span-buffer-segment-stats.test.ts +221 -0
  184. package/src/lib/__tests__/span-lifecycle.test.ts +53 -25
  185. package/src/lib/__tests__/spanbuffer-materializer-parity.test.ts +266 -0
  186. package/src/lib/__tests__/sync-async-trace.test.ts +24 -23
  187. package/src/lib/__tests__/tag-writer-aot.test.ts +214 -0
  188. package/src/lib/__tests__/test-helpers.ts +67 -12
  189. package/src/lib/__tests__/threadId.test.ts +62 -0
  190. package/src/lib/__tests__/timestamp.test.ts +221 -93
  191. package/src/lib/__tests__/traceTopology.property.test.ts +383 -0
  192. package/src/lib/__tests__/type-narrowing.test.ts +63 -0
  193. package/src/lib/__tests__/vocabulary-dense-decoding.test.ts +405 -0
  194. package/src/lib/__tests__/vocabularyRegistry.test.ts +313 -0
  195. package/src/lib/arrow/lease.ts +43 -0
  196. package/src/lib/arrow/utils.ts +10 -14
  197. package/src/lib/arrow/vocabularyDictionary.ts +123 -0
  198. package/src/lib/bufferStrategy.ts +9 -1
  199. package/src/lib/cloudflare/traceRows.ts +3 -2
  200. package/src/lib/codegen/__tests__/evaluatorGenerator.test.ts +21 -141
  201. package/src/lib/codegen/__tests__/fixedPositionWriter-parity.test.ts +273 -0
  202. package/src/lib/codegen/__tests__/fixedPositionWriter-uint64.test.ts +61 -34
  203. package/src/lib/codegen/__tests__/nullBitmap.test.ts +33 -37
  204. package/src/lib/codegen/__tests__/spanLoggerGenerator.test.ts +34 -18
  205. package/src/lib/codegen/__tests__/spanLoggerMaterializerParity.test.ts +503 -0
  206. package/src/lib/codegen/evaluatorGenerator.ts +18 -13
  207. package/src/lib/codegen/fixedPositionWriterGenerator.ts +329 -245
  208. package/src/lib/codegen/spanLoggerClosureMaterializer.ts +598 -0
  209. package/src/lib/codegen/spanLoggerGenerator.ts +241 -177
  210. package/src/lib/convertToArrow.ts +598 -311
  211. package/src/lib/defineOpContext.ts +1 -1
  212. package/src/lib/enumMetadata.ts +121 -0
  213. package/src/lib/flushScheduler.ts +11 -5
  214. package/src/lib/library.ts +37 -595
  215. package/src/lib/logBinding.ts +21 -27
  216. package/src/lib/op.ts +75 -18
  217. package/src/lib/opContext/__tests__/retry.test.ts +27 -21
  218. package/src/lib/opContext/createOpGroup.ts +33 -31
  219. package/src/lib/opContext/defineOp.ts +88 -11
  220. package/src/lib/opContext/opGroupTypes.ts +2 -2
  221. package/src/lib/opContext/opTypes.ts +1 -1
  222. package/src/lib/opContext/spanContextTypes.ts +98 -17
  223. package/src/lib/opContext/types.ts +7 -3
  224. package/src/lib/physicalLayoutPlan.ts +598 -0
  225. package/src/lib/resolveMessage.ts +67 -0
  226. package/src/lib/result.ts +20 -33
  227. package/src/lib/runtimeHint.ts +98 -0
  228. package/src/lib/schema/__tests__/featureFlags.test.ts +2 -1
  229. package/src/lib/schema/builder.ts +1 -1
  230. package/src/lib/schema/types.ts +1 -1
  231. package/src/lib/span-buffer/aot/v1.ts +26 -0
  232. package/src/lib/spanBuffer.ts +658 -92
  233. package/src/lib/spanBufferStats.ts +1 -1
  234. package/src/lib/spanContext.ts +1350 -861
  235. package/src/lib/sqlite/sqlite-common.ts +20 -31
  236. package/src/lib/testing/__tests__/topology-traversal.test.ts +174 -0
  237. package/src/lib/testing/__tests__/vitest-harness.test.ts +2 -1
  238. package/src/lib/testing/bun-harness.ts +94 -43
  239. package/src/lib/testing/extractFacts.ts +64 -78
  240. package/src/lib/testing/facts.ts +1 -1
  241. package/src/lib/testing/queryable-span.ts +23 -30
  242. package/src/lib/testing/span-query.ts +16 -20
  243. package/src/lib/testing/stdio-replay.ts +25 -8
  244. package/src/lib/testing/vitest-harness.ts +1 -1
  245. package/src/lib/threadId.ts +6 -3
  246. package/src/lib/traceRoot.es.ts +77 -42
  247. package/src/lib/traceRoot.node.ts +75 -46
  248. package/src/lib/traceRoot.ts +41 -14
  249. package/src/lib/traceTopology.ts +279 -0
  250. package/src/lib/tracer.ts +109 -98
  251. package/src/lib/tracers/ArrayQueueTracer.ts +1 -1
  252. package/src/lib/tracers/StdioTracer.ts +15 -13
  253. package/src/lib/tracers/TestTracer.ts +6 -8
  254. package/src/lib/tracers/__tests__/ArrayQueueTracer.test.ts +15 -10
  255. package/src/lib/tracers/__tests__/TestTracer.test.ts +23 -13
  256. package/src/lib/types.ts +64 -33
  257. package/src/lib/vocabularyRegistry.ts +439 -0
  258. package/src/lib/wasm/WasmBufferStrategy.ts +56 -48
  259. package/src/lib/wasm/__tests__/WasmBufferStrategy.test.ts +215 -11
  260. package/src/lib/wasm/__tests__/allocatorFreeBlockClamp.test.ts +86 -0
  261. package/src/lib/wasm/__tests__/wasm-identity-view.test.ts +311 -0
  262. package/src/lib/wasm/__tests__/wasm-integration.test.ts +417 -44
  263. package/src/lib/wasm/__tests__/wasm-message-buffer-families.test.ts +588 -0
  264. package/src/lib/wasm/__tests__/wasmAllocator.test.ts +100 -668
  265. package/src/lib/wasm/__tests__/wasmSpanBuffer.test.ts +419 -63
  266. package/src/lib/wasm/__tests__/wasmTraceRoot.test.ts +24 -29
  267. package/src/lib/wasm/__tests__/wasmTracer.test.ts.disabled +2 -2
  268. package/src/lib/wasm/wasmAllocator.ts +131 -96
  269. package/src/lib/wasm/wasmPhysicalLayout.ts +309 -0
  270. package/src/lib/wasm/wasmSpanBuffer.ts +597 -341
  271. package/src/lib/wasm/wasmTraceRoot.ts +140 -78
  272. package/src/vocabulary/register/v1.ts +1 -0
  273. package/src/wasm.ts +19 -0
  274. package/src/lib/__tests__/remapped-buffer-view-integration.test.ts +0 -319
  275. package/src/lib/__tests__/remapped-buffer-view.test.ts +0 -635
  276. package/src/lib/wasm/allocator.zig +0 -948
@@ -24,6 +24,7 @@ import { defineOpContext } from '../defineOpContext.js';
24
24
  import { S } from '../schema/builder.js';
25
25
  import { defineLogSchema } from '../schema/defineLogSchema.js';
26
26
  import { TestTracer } from '../tracers/TestTracer.js';
27
+ import { iterateSpanChildren, iterateSpanTree, NO_NODE } from '../traceTopology.js';
27
28
  import type { AnySpanBuffer } from '../types.js';
28
29
  import { createTestTracerOptions } from './test-helpers.js';
29
30
 
@@ -128,6 +129,9 @@ describe('Nested Library Tasks', () => {
128
129
  expect(level2Buffer).toBeDefined();
129
130
  expect(level3Buffer).toBeDefined();
130
131
  expect(level4Buffer).toBeDefined();
132
+ if (!rootBuffer || !level2Buffer || !level3Buffer || !level4Buffer) {
133
+ throw new Error('nested trace did not expose all buffers');
134
+ }
131
135
 
132
136
  // Verify parent-child relationships
133
137
  // Root has no parent
@@ -142,11 +146,11 @@ describe('Nested Library Tasks', () => {
142
146
  // Level 4's parent is level 3
143
147
  expect(level4Buffer?._parent).toBe(level3Buffer);
144
148
 
145
- // Verify children array
146
- expect(rootBuffer?._children).toContain(level2Buffer);
147
- expect(level2Buffer?._children).toContain(level3Buffer);
148
- expect(level3Buffer?._children).toContain(level4Buffer);
149
- expect(level4Buffer?._children.length).toBe(0);
149
+ // Verify logical child topology and leaf termination
150
+ expect(Array.from(iterateSpanChildren(rootBuffer))).toEqual([level2Buffer]);
151
+ expect(Array.from(iterateSpanChildren(level2Buffer))).toEqual([level3Buffer]);
152
+ expect(Array.from(iterateSpanChildren(level3Buffer))).toEqual([level4Buffer]);
153
+ expect(level4Buffer._traceRoot._topology.firstChild[level4Buffer._nodeIndex]).toBe(NO_NODE);
150
154
 
151
155
  // Verify all share the same traceId
152
156
  const traceId = rootBuffer?.trace_id;
@@ -428,21 +432,16 @@ describe('Nested Library Tasks', () => {
428
432
  expect(appBuffer).toBeDefined();
429
433
  if (!appBuffer) throw new Error('appBuffer is undefined');
430
434
 
431
- // Walk tree to collect all buffers
432
- const allBuffers: AnySpanBuffer[] = [];
433
- const collectBuffers = (buf: AnySpanBuffer) => {
434
- allBuffers.push(buf);
435
- for (const child of buf._children) {
436
- collectBuffers(child);
437
- }
438
- };
439
- collectBuffers(appBuffer);
435
+ // Collect physical buffers in canonical preorder without recursive test traversal
436
+ const allBuffers = Array.from(iterateSpanTree(appBuffer));
440
437
 
441
438
  // Should have 5 buffers: app, http, db, cache, auth
442
439
  expect(allBuffers.length).toBe(5);
443
440
 
444
441
  // Verify parent-child chain
445
- const httpBuffer = allBuffers.find((b) => b._children.length > 0 && b !== appBuffer);
442
+ const httpBuffer = allBuffers.find(
443
+ (buffer) => buffer !== appBuffer && buffer._traceRoot._topology.firstChild[buffer._nodeIndex] !== NO_NODE,
444
+ );
446
445
  expect(httpBuffer).toBeDefined();
447
446
  expect(httpBuffer?._parent).toBe(appBuffer);
448
447
 
@@ -192,7 +192,7 @@ describe('Op Metadata', () => {
192
192
 
193
193
  expect(myOp.metadata).toBeDefined();
194
194
  expect(myOp.fn).toBeInstanceOf(Function);
195
- expect(myOp.SpanBufferClass).toBeDefined();
195
+ expect(myOp.callsitePlan.SpanBufferClass).toBeDefined();
196
196
  });
197
197
  });
198
198
  });
@@ -49,23 +49,12 @@ describe('Op type safety', () => {
49
49
  await trace('test-a', opA);
50
50
  });
51
51
 
52
- it('should ERROR when passing Op with incompatible schema', async () => {
53
- // New API: pass opContext directly
52
+ it('rejects an incompatible schema at compile time while its callsite plan stays self-contained at runtime', async () => {
54
53
  const { trace } = new TestTracer(opContextA, { ...createTestTracerOptions() });
55
54
 
56
- // This SHOULD cause a type error - opB has different schema than tracer
57
- // The @ts-expect-error verifies the type system catches this at compile time
58
- // At runtime, calling an op with incompatible schema will throw because
59
- // the tag methods don't exist on the buffer
60
- let threw = false;
61
- try {
62
- // @ts-expect-error - opB has schemaB but tracer expects schemaA
63
- await trace('test-b', opB);
64
- } catch (e) {
65
- threw = true;
66
- // Expected: ctx.tag.orderId is not a function because schemaA doesn't have orderId
67
- expect(e).toBeInstanceOf(TypeError);
68
- }
69
- expect(threw).toBe(true);
55
+ // @ts-expect-error - opB has schemaB but tracer expects schemaA
56
+ const result = await trace('test-b', opB);
57
+
58
+ expect(result.success).toBe(true);
70
59
  });
71
60
  });
@@ -0,0 +1,333 @@
1
+ import { describe, expect, it } from 'bun:test';
2
+ import { getResultWriterClass, getTagWriterClass } from '../codegen/fixedPositionWriterGenerator.js';
3
+ import { createSpanLoggerClass } from '../codegen/spanLoggerGenerator.js';
4
+ import { defineOpContext } from '../defineOpContext.js';
5
+ import { createRemapDescriptor } from '../library.js';
6
+ import type { OpContext } from '../opContext/types.js';
7
+ import { getPhysicalLayoutPlan, PHYSICAL_LAYOUT_VERSION } from '../physicalLayoutPlan.js';
8
+ import { resolveMessage } from '../resolveMessage.js';
9
+ import {
10
+ RUNTIME_HINT_ANALYZED_VALID,
11
+ RUNTIME_HINT_LOG,
12
+ RUNTIME_HINT_MESSAGE_LAYOUT_STATIC_ONLY,
13
+ RUNTIME_HINT_RESULT,
14
+ RUNTIME_HINT_TAG,
15
+ } from '../runtimeHint.js';
16
+ import { S } from '../schema/builder.js';
17
+ import { defineLogSchema } from '../schema/defineLogSchema.js';
18
+ import { getSpanBufferClass } from '../spanBuffer.js';
19
+ import { createSpanContextClass, isPhysicalLayoutPlanForContext } from '../spanContext.js';
20
+ import { TestTracer } from '../tracers/TestTracer.js';
21
+ import { iterateSpanChildren } from '../traceTopology.js';
22
+ import { createTestTracerOptions } from './test-helpers.js';
23
+
24
+ const CAPACITY_TIER = 17;
25
+ const HOT_CHILD_CAPABILITIES = RUNTIME_HINT_TAG | RUNTIME_HINT_LOG | RUNTIME_HINT_RESULT;
26
+ const HOT_CHILD_HINT =
27
+ RUNTIME_HINT_ANALYZED_VALID | RUNTIME_HINT_TAG | RUNTIME_HINT_LOG | RUNTIME_HINT_RESULT | CAPACITY_TIER;
28
+
29
+ describe('PhysicalLayoutPlan', () => {
30
+ it('reuses one immutable plan per schema, capability set, context layout, remap, and backend', () => {
31
+ const schema = defineLogSchema({ userId: S.category() });
32
+ const otherSchema = defineLogSchema({ userId: S.category(), duration: S.number() });
33
+ const SpanBufferClass = getSpanBufferClass(schema);
34
+ const logBinding = { logSchema: schema, remapDescriptor: undefined };
35
+ const SpanContextClass = createSpanContextClass<OpContext<typeof schema>>(
36
+ schema,
37
+ logBinding,
38
+ HOT_CHILD_CAPABILITIES,
39
+ );
40
+ const differentCapabilityContextClass = createSpanContextClass<OpContext<typeof schema>>(
41
+ schema,
42
+ logBinding,
43
+ HOT_CHILD_CAPABILITIES ^ RUNTIME_HINT_LOG,
44
+ );
45
+ const differentLayoutContextClass = createSpanContextClass<OpContext<typeof schema>>(
46
+ schema,
47
+ logBinding,
48
+ HOT_CHILD_CAPABILITIES,
49
+ ['requestId'],
50
+ );
51
+ const otherSchemaContextClass = createSpanContextClass<OpContext<typeof otherSchema>>(
52
+ otherSchema,
53
+ { logSchema: otherSchema, remapDescriptor: undefined },
54
+ HOT_CHILD_CAPABILITIES,
55
+ );
56
+ const layout = createRemapDescriptor(schema, { app_user_id: 'userId' });
57
+ const otherLayout = createRemapDescriptor(schema, { lib_user_id: 'userId' });
58
+
59
+ const first = getPhysicalLayoutPlan(SpanBufferClass, HOT_CHILD_HINT, SpanContextClass, layout, 'js-heap');
60
+ const identical = getPhysicalLayoutPlan(SpanBufferClass, HOT_CHILD_HINT, SpanContextClass, layout, 'js-heap');
61
+ const differentCapabilities = getPhysicalLayoutPlan(
62
+ SpanBufferClass,
63
+ HOT_CHILD_HINT ^ RUNTIME_HINT_LOG,
64
+ differentCapabilityContextClass,
65
+ layout,
66
+ 'js-heap',
67
+ );
68
+ const differentBackend = getPhysicalLayoutPlan(SpanBufferClass, HOT_CHILD_HINT, SpanContextClass, layout, 'wasm');
69
+ const differentRemap = getPhysicalLayoutPlan(
70
+ SpanBufferClass,
71
+ HOT_CHILD_HINT,
72
+ SpanContextClass,
73
+ otherLayout,
74
+ 'js-heap',
75
+ );
76
+ const differentContextLayout = getPhysicalLayoutPlan(
77
+ SpanBufferClass,
78
+ HOT_CHILD_HINT,
79
+ differentLayoutContextClass,
80
+ layout,
81
+ 'js-heap',
82
+ 'requestId',
83
+ );
84
+ const differentSchema = getPhysicalLayoutPlan(
85
+ getSpanBufferClass(otherSchema),
86
+ HOT_CHILD_HINT,
87
+ otherSchemaContextClass,
88
+ undefined,
89
+ 'js-heap',
90
+ );
91
+
92
+ expect(identical).toBe(first);
93
+ expect(Object.isFrozen(first)).toBe(true);
94
+ expect(first.SpanContextClass).toBe(SpanContextClass);
95
+ expect(first.remapDescriptor).toBe(layout);
96
+ expect(differentCapabilities).not.toBe(first);
97
+ expect(differentBackend).not.toBe(first);
98
+ expect(differentRemap).not.toBe(first);
99
+ expect(differentContextLayout).not.toBe(first);
100
+ expect(differentSchema).not.toBe(first);
101
+ expect(differentCapabilities.capabilities).toBe(first.capabilities ^ RUNTIME_HINT_LOG);
102
+ expect(differentCapabilities.SpanContextClass).toBe(differentCapabilityContextClass);
103
+ expect(differentBackend.backendKind).toBe('wasm');
104
+ expect(differentRemap.remapDescriptor).toBe(otherLayout);
105
+ expect(differentContextLayout.contextLayoutKey).toBe('requestId');
106
+ expect(differentContextLayout.SpanContextClass).toBe(differentLayoutContextClass);
107
+ expect(differentSchema.schema).toBe(otherSchema);
108
+ });
109
+
110
+ it('owns the schema-specific constructors, capacity, and appenders', () => {
111
+ const schema = defineLogSchema({ userId: S.category() });
112
+ const SpanBufferClass = getSpanBufferClass(schema);
113
+ const SpanContextClass = createSpanContextClass<OpContext<typeof schema>>(
114
+ schema,
115
+ { logSchema: schema, remapDescriptor: undefined },
116
+ HOT_CHILD_CAPABILITIES,
117
+ );
118
+ const plan = getPhysicalLayoutPlan(SpanBufferClass, HOT_CHILD_HINT, SpanContextClass);
119
+ const reusedPlan = getPhysicalLayoutPlan(SpanBufferClass, HOT_CHILD_HINT, SpanContextClass);
120
+
121
+ expect(plan.version).toBe(PHYSICAL_LAYOUT_VERSION);
122
+ expect(plan.schema).toBe(schema);
123
+ expect(plan.SpanContextClass).toBe(SpanContextClass);
124
+ expect(plan.SpanBufferClass).toBe(SpanBufferClass);
125
+ expect(plan.SpanLoggerClass).toBe(createSpanLoggerClass(schema));
126
+ expect(plan.TagWriterClass).toBe(getTagWriterClass(schema));
127
+ expect(plan.ResultWriterClass).toBe(getResultWriterClass(schema));
128
+ expect(plan.capacityTier).toBe(CAPACITY_TIER);
129
+ expect(plan.clock.kind).toBe('trace-root');
130
+ expect(plan.poolRef).toBeNull();
131
+ expect(reusedPlan.clock).toBe(plan.clock);
132
+ expect(reusedPlan.appenders).toBe(plan.appenders);
133
+ expect(Object.isFrozen(plan.clock)).toBe(true);
134
+ expect(Object.isFrozen(plan.appenders)).toBe(true);
135
+ });
136
+
137
+ it('reuses matching SpanBuffer metadata and materializes one constructor for a mismatch', () => {
138
+ const schema = defineLogSchema({ userId: S.category() });
139
+ const opContext = defineOpContext({ logSchema: schema });
140
+ const incomingClass = getSpanBufferClass(opContext.logBinding.logSchema);
141
+ const matchingHint = RUNTIME_HINT_ANALYZED_VALID | RUNTIME_HINT_RESULT;
142
+ const mismatchedHint = matchingHint | RUNTIME_HINT_MESSAGE_LAYOUT_STATIC_ONLY;
143
+
144
+ const originalDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'Function');
145
+ if (!originalDescriptor) throw new Error('Expected global Function descriptor');
146
+ const originalFunction = globalThis.Function;
147
+ const functionSources: string[] = [];
148
+ const recordFunctionSource = (argumentList: unknown[]): void => {
149
+ functionSources.push(String(argumentList.at(-1)));
150
+ };
151
+ const spanBufferCompilerCalls = (): number =>
152
+ functionSources.filter(
153
+ (source) => source.includes('getOrCreateOverflow()') && source.includes('this._statsReservedRows'),
154
+ ).length;
155
+ const functionProbe = new Proxy(originalFunction, {
156
+ apply(target, thisArgument, argumentList) {
157
+ recordFunctionSource(argumentList);
158
+ return Reflect.apply(target, thisArgument, argumentList);
159
+ },
160
+ construct(target, argumentList, newTarget) {
161
+ recordFunctionSource(argumentList);
162
+ return Reflect.construct(target, argumentList, newTarget);
163
+ },
164
+ });
165
+ Object.defineProperty(globalThis, 'Function', { ...originalDescriptor, value: functionProbe });
166
+ try {
167
+ const matching = opContext.defineOp('matching-layout', (ctx) => ctx.ok('matched'), undefined, {
168
+ runtimeHint: matchingHint,
169
+ });
170
+ expect(matching.callsitePlan.SpanBufferClass).toBe(incomingClass);
171
+ expect(spanBufferCompilerCalls()).toBe(0);
172
+
173
+ const mismatched = opContext.defineOp('mismatched-layout', (ctx) => ctx.ok('generated'), undefined, {
174
+ runtimeHint: mismatchedHint,
175
+ });
176
+ const selectedClass = mismatched.callsitePlan.SpanBufferClass;
177
+ expect(selectedClass).not.toBe(incomingClass);
178
+ expect(selectedClass.messageLayoutFamily).toBe('static-only');
179
+ expect(spanBufferCompilerCalls()).toBe(1);
180
+
181
+ const reused = opContext.defineOp('reused-layout', (ctx) => ctx.ok('reused'), undefined, {
182
+ runtimeHint: mismatchedHint,
183
+ });
184
+ expect(reused.callsitePlan.SpanBufferClass).toBe(selectedClass);
185
+ expect(spanBufferCompilerCalls()).toBe(1);
186
+ } finally {
187
+ Object.defineProperty(globalThis, 'Function', originalDescriptor);
188
+ }
189
+ });
190
+
191
+ it('consumes the same plan for repeated hot child creation without mutating it', async () => {
192
+ const schema = defineLogSchema({ userId: S.category() });
193
+ const opContext = defineOpContext({ logSchema: schema });
194
+ const writtenUsers: unknown[] = [];
195
+ const writtenMessages: unknown[] = [];
196
+
197
+ const childOp = opContext.defineOp(
198
+ 'planned-child',
199
+ (ctx) => {
200
+ ctx.tag.userId('planned-user');
201
+ ctx.log.info('planned-log');
202
+ writtenUsers.push(ctx.buffer.userId_values[0]);
203
+ writtenMessages.push(resolveMessage(ctx.buffer, 2));
204
+ return ctx.ok('done');
205
+ },
206
+ undefined,
207
+ { runtimeHint: HOT_CHILD_HINT },
208
+ );
209
+ const plan = childOp.callsitePlan;
210
+ const childSchema = plan.SpanBufferClass.schema;
211
+ if (!isPhysicalLayoutPlanForContext<OpContext<typeof childSchema>>(plan, childSchema)) {
212
+ throw new TypeError('Expected child Op to own a schema-specific physical layout plan');
213
+ }
214
+ const parentOp = opContext.defineOp('parent', async (ctx) => {
215
+ await ctx.span('first-child', childOp);
216
+ await ctx.span('second-child', childOp);
217
+ return ctx.ok('done');
218
+ });
219
+
220
+ const ownedLogger = plan.SpanLoggerClass;
221
+ const ownedTagWriter = plan.TagWriterClass;
222
+ const ownedAppenders = plan.appenders;
223
+ const tracer = new TestTracer(opContext, createTestTracerOptions());
224
+
225
+ await tracer.trace('root', parentOp);
226
+
227
+ const children = Array.from(iterateSpanChildren(tracer.rootBuffers[0]));
228
+ expect(children).toHaveLength(2);
229
+ expect(children.every((buffer) => buffer instanceof plan.SpanBufferClass)).toBe(true);
230
+ expect(children.map((buffer) => buffer._capacity)).toEqual([CAPACITY_TIER, CAPACITY_TIER]);
231
+ const clockBuffer = children[0];
232
+ const beforePlanClock = clockBuffer._traceRoot.getTimestampNanos();
233
+ const planTimestamp = plan.clock.now(clockBuffer);
234
+ const afterPlanClock = clockBuffer._traceRoot.getTimestampNanos();
235
+ expect(planTimestamp >= beforePlanClock && planTimestamp <= afterPlanClock).toBe(true);
236
+ expect(writtenUsers).toEqual(['planned-user', 'planned-user']);
237
+ expect(writtenMessages).toEqual(['planned-log', 'planned-log']);
238
+ expect(plan.SpanLoggerClass).toBe(ownedLogger);
239
+ expect(plan.TagWriterClass).toBe(ownedTagWriter);
240
+ expect(plan.appenders).toBe(ownedAppenders);
241
+ });
242
+ it('reuses one monomorphic CallsitePlan across sync and async calls while separating capability and schema plans', async () => {
243
+ const schema = defineLogSchema({ userId: S.category() });
244
+ const opContext = defineOpContext({ logSchema: schema, ctx: { requestId: 'default-request' } });
245
+ const resultContexts: object[] = [];
246
+ const resultOnly = opContext.defineOp(
247
+ 'result-only-callsite',
248
+ (ctx) => {
249
+ resultContexts.push(ctx);
250
+ return ctx.ok(resultContexts.length);
251
+ },
252
+ undefined,
253
+ { runtimeHint: RUNTIME_HINT_ANALYZED_VALID | RUNTIME_HINT_RESULT | 4 },
254
+ );
255
+ const logResult = opContext.defineOp(
256
+ 'log-result-callsite',
257
+ (ctx) => {
258
+ ctx.log.info('planned-log');
259
+ return ctx.ok('logged');
260
+ },
261
+ undefined,
262
+ { runtimeHint: RUNTIME_HINT_ANALYZED_VALID | RUNTIME_HINT_LOG | RUNTIME_HINT_RESULT | 4 },
263
+ );
264
+ const tagResult = opContext.defineOp(
265
+ 'tag-result-callsite',
266
+ (ctx) => {
267
+ ctx.tag.userId('planned-user');
268
+ return ctx.ok('tagged');
269
+ },
270
+ undefined,
271
+ { runtimeHint: RUNTIME_HINT_ANALYZED_VALID | RUNTIME_HINT_TAG | RUNTIME_HINT_RESULT | 4 },
272
+ );
273
+ const otherSchema = defineLogSchema({ duration: S.number() });
274
+ const otherContext = defineOpContext({ logSchema: otherSchema });
275
+ const otherSchemaOp = otherContext.defineOp('other-schema-callsite', (ctx) => ctx.ok('other'), undefined, {
276
+ runtimeHint: RUNTIME_HINT_ANALYZED_VALID | RUNTIME_HINT_RESULT | 4,
277
+ });
278
+
279
+ const plan = resultOnly.callsitePlan;
280
+ expect(Object.isFrozen(plan)).toBe(true);
281
+ expect(plan.schema).toBe(opContext.logBinding.logSchema);
282
+ expect(plan.metadata.name).toBe('result-only-callsite');
283
+ expect(plan.metadata).toBe(resultOnly.metadata);
284
+ expect(plan.runtimeHint).toBe(RUNTIME_HINT_ANALYZED_VALID | RUNTIME_HINT_RESULT | 4);
285
+ expect(plan.newSpanLogger).toBeUndefined();
286
+ expect(plan.SpanLoggerClass).toBeUndefined();
287
+ expect(plan.newTagWriter).toBeUndefined();
288
+ expect(typeof plan.newCtx0).toBe('function');
289
+ expect(typeof plan.newCtx1).toBe('function');
290
+ const inherited = { requestId: 'default-request' };
291
+ const noOverrides = plan.newCtx0(inherited);
292
+ const withOverrides = plan.newCtx1(inherited, { requestId: 'override-request' });
293
+ expect(noOverrides).toBe(inherited);
294
+ expect(withOverrides).not.toBe(inherited);
295
+ expect(Object.getPrototypeOf(withOverrides)).toBe(Object.prototype);
296
+ expect(Reflect.ownKeys(withOverrides)).toEqual(['requestId']);
297
+ expect(Reflect.get(withOverrides, 'requestId')).toBe('override-request');
298
+
299
+ expect(logResult.callsitePlan).not.toBe(plan);
300
+ expect(logResult.callsitePlan.SpanContextClass).not.toBe(plan.SpanContextClass);
301
+ expect(logResult.callsitePlan.SpanBufferClass).toBe(plan.SpanBufferClass);
302
+ expect(typeof logResult.callsitePlan.newSpanLogger).toBe('function');
303
+ expect(logResult.callsitePlan.SpanLoggerClass).toBeDefined();
304
+ expect(logResult.callsitePlan.newTagWriter).toBeUndefined();
305
+ expect(tagResult.callsitePlan).not.toBe(plan);
306
+ expect(tagResult.callsitePlan.SpanBufferClass).toBe(plan.SpanBufferClass);
307
+ expect(tagResult.callsitePlan.newSpanLogger).toBeUndefined();
308
+ expect(typeof tagResult.callsitePlan.newTagWriter).toBe('function');
309
+ expect(otherSchemaOp.callsitePlan).not.toBe(plan);
310
+ expect(otherSchemaOp.callsitePlan.SpanBufferClass).not.toBe(plan.SpanBufferClass);
311
+
312
+ const parent = opContext.defineOp('callsite-parent', async (ctx) => {
313
+ const syncResult = ctx.spanSync('sync-result', resultOnly);
314
+ const asyncResult = await ctx.span('async-result', resultOnly);
315
+ if (!syncResult.success || !asyncResult.success) throw new Error('expected repeated child calls to succeed');
316
+ return ctx.ok([syncResult.value, asyncResult.value]);
317
+ });
318
+ const tracer = new TestTracer(opContext, createTestTracerOptions());
319
+ const result = await tracer.trace('callsite-root', parent);
320
+
321
+ expect(result.success).toBe(true);
322
+ if (!result.success) throw new Error('expected parent result to succeed');
323
+ expect(result.value).toEqual([1, 2]);
324
+ expect(resultOnly.callsitePlan).toBe(plan);
325
+ expect(resultContexts).toHaveLength(2);
326
+ expect(resultContexts.every((ctx) => ctx instanceof plan.SpanContextClass)).toBe(true);
327
+ const rootBuffer = tracer.rootBuffers[0];
328
+ if (!rootBuffer) throw new Error('expected repeated child buffers');
329
+ const children = Array.from(iterateSpanChildren(rootBuffer));
330
+ expect(children).toHaveLength(2);
331
+ expect(children.every((buffer) => buffer instanceof plan.SpanBufferClass)).toBe(true);
332
+ });
333
+ });