@unrdf/kgc-runtime 26.4.2

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 (70) hide show
  1. package/IMPLEMENTATION_SUMMARY.json +150 -0
  2. package/PLUGIN_SYSTEM_SUMMARY.json +149 -0
  3. package/README.md +98 -0
  4. package/TRANSACTION_IMPLEMENTATION.json +119 -0
  5. package/capability-map.md +93 -0
  6. package/docs/api-stability.md +269 -0
  7. package/docs/extensions/plugin-development.md +382 -0
  8. package/package.json +40 -0
  9. package/plugins/registry.json +35 -0
  10. package/src/admission-gate.mjs +414 -0
  11. package/src/api-version.mjs +373 -0
  12. package/src/atomic-admission.mjs +310 -0
  13. package/src/bounds.mjs +289 -0
  14. package/src/bulkhead-manager.mjs +280 -0
  15. package/src/capsule.mjs +524 -0
  16. package/src/crdt.mjs +361 -0
  17. package/src/enhanced-bounds.mjs +614 -0
  18. package/src/executor.mjs +73 -0
  19. package/src/freeze-restore.mjs +521 -0
  20. package/src/index.mjs +62 -0
  21. package/src/materialized-views.mjs +371 -0
  22. package/src/merge.mjs +472 -0
  23. package/src/plugin-isolation.mjs +392 -0
  24. package/src/plugin-manager.mjs +441 -0
  25. package/src/projections-api.mjs +336 -0
  26. package/src/projections-cli.mjs +238 -0
  27. package/src/projections-docs.mjs +300 -0
  28. package/src/projections-ide.mjs +278 -0
  29. package/src/receipt.mjs +340 -0
  30. package/src/rollback.mjs +258 -0
  31. package/src/saga-orchestrator.mjs +355 -0
  32. package/src/schemas.mjs +1330 -0
  33. package/src/storage-optimization.mjs +359 -0
  34. package/src/tool-registry.mjs +272 -0
  35. package/src/transaction.mjs +466 -0
  36. package/src/validators.mjs +485 -0
  37. package/src/work-item.mjs +449 -0
  38. package/templates/plugin-template/README.md +58 -0
  39. package/templates/plugin-template/index.mjs +162 -0
  40. package/templates/plugin-template/plugin.json +19 -0
  41. package/test/admission-gate.test.mjs +583 -0
  42. package/test/api-version.test.mjs +74 -0
  43. package/test/atomic-admission.test.mjs +155 -0
  44. package/test/bounds.test.mjs +341 -0
  45. package/test/bulkhead-manager.test.mjs +236 -0
  46. package/test/capsule.test.mjs +625 -0
  47. package/test/crdt.test.mjs +215 -0
  48. package/test/enhanced-bounds.test.mjs +487 -0
  49. package/test/freeze-restore.test.mjs +472 -0
  50. package/test/materialized-views.test.mjs +243 -0
  51. package/test/merge.test.mjs +665 -0
  52. package/test/plugin-isolation.test.mjs +109 -0
  53. package/test/plugin-manager.test.mjs +208 -0
  54. package/test/projections-api.test.mjs +293 -0
  55. package/test/projections-cli.test.mjs +204 -0
  56. package/test/projections-docs.test.mjs +173 -0
  57. package/test/projections-ide.test.mjs +230 -0
  58. package/test/receipt.test.mjs +295 -0
  59. package/test/rollback.test.mjs +132 -0
  60. package/test/saga-orchestrator.test.mjs +279 -0
  61. package/test/schemas.test.mjs +716 -0
  62. package/test/storage-optimization.test.mjs +503 -0
  63. package/test/tool-registry.test.mjs +341 -0
  64. package/test/transaction.test.mjs +189 -0
  65. package/test/validators.test.mjs +463 -0
  66. package/test/work-item.test.mjs +548 -0
  67. package/test/work-item.test.mjs.bak +548 -0
  68. package/var/kgc/test-atomic-log.json +519 -0
  69. package/var/kgc/test-cascading-log.json +145 -0
  70. package/vitest.config.mjs +18 -0
@@ -0,0 +1,472 @@
1
+ /**
2
+ * Tests for KGC Runtime Freeze-Restore functionality
3
+ *
4
+ * Validates:
5
+ * - Freeze and verify operations
6
+ * - Reconstruct from snapshot
7
+ * - Hash consistency
8
+ * - Multi-snapshot handling
9
+ */
10
+
11
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
12
+ import { promises as fs } from 'fs';
13
+ import * as path from 'path';
14
+ import { fileURLToPath } from 'url';
15
+ import { dirname } from 'path';
16
+ import {
17
+ freezeUniverse,
18
+ verifyFreeze,
19
+ reconstructTo,
20
+ getSnapshotList,
21
+ } from '../src/freeze-restore.mjs';
22
+
23
+ const __filename = fileURLToPath(import.meta.url);
24
+ const __dirname = dirname(__filename);
25
+
26
+ // Test snapshot directory
27
+ const TEST_SNAPSHOT_DIR = path.join(__dirname, '../var/kgc/snapshots-test');
28
+
29
+ /**
30
+ * Clean test snapshot directory
31
+ */
32
+ async function cleanTestSnapshots() {
33
+ try {
34
+ await fs.rm(TEST_SNAPSHOT_DIR, { recursive: true, force: true });
35
+ } catch (error) {
36
+ // Ignore if doesn't exist
37
+ }
38
+ }
39
+
40
+ describe('KGC Runtime Freeze-Restore', () => {
41
+ beforeEach(async () => {
42
+ await cleanTestSnapshots();
43
+ });
44
+
45
+ afterEach(async () => {
46
+ await cleanTestSnapshots();
47
+ });
48
+
49
+ describe('freezeUniverse', () => {
50
+ it('should freeze simple universe state', async () => {
51
+ const universe = {
52
+ entities: ['entity1', 'entity2'],
53
+ count: 2,
54
+ };
55
+
56
+ const manifest = await freezeUniverse(universe, { snapshotDir: TEST_SNAPSHOT_DIR });
57
+
58
+ expect(manifest).toBeDefined();
59
+ expect(manifest.timestamp_ns).toBeDefined();
60
+ expect(manifest.o_hash).toBeDefined();
61
+ expect(manifest.o_hash).toHaveLength(64); // BLAKE3 produces 32-byte (64-char hex) hash
62
+ expect(manifest.file_count).toBe(1);
63
+ expect(manifest.total_bytes).toBeGreaterThan(0);
64
+ expect(manifest.created_at).toBeDefined();
65
+ });
66
+
67
+ it('should freeze empty universe', async () => {
68
+ const universe = {};
69
+
70
+ const manifest = await freezeUniverse(universe, { snapshotDir: TEST_SNAPSHOT_DIR });
71
+
72
+ expect(manifest).toBeDefined();
73
+ expect(manifest.o_hash).toBeDefined();
74
+ expect(manifest.file_count).toBe(1);
75
+ });
76
+
77
+ it('should freeze universe with BigInt timestamp', async () => {
78
+ const universe = {
79
+ data: 'test',
80
+ timestamp: 1234567890123456789n,
81
+ };
82
+
83
+ const manifest = await freezeUniverse(universe, { snapshotDir: TEST_SNAPSHOT_DIR });
84
+
85
+ expect(manifest).toBeDefined();
86
+ expect(manifest.timestamp_ns).toBeDefined();
87
+ });
88
+
89
+ it('should produce deterministic hash for same state', async () => {
90
+ const universe = {
91
+ entities: ['a', 'b', 'c'],
92
+ count: 3,
93
+ };
94
+
95
+ const manifest1 = await freezeUniverse(universe, { snapshotDir: TEST_SNAPSHOT_DIR });
96
+
97
+ // Wait a bit to ensure different timestamp
98
+ await new Promise(resolve => setTimeout(resolve, 10));
99
+
100
+ const manifest2 = await freezeUniverse(universe, { snapshotDir: TEST_SNAPSHOT_DIR });
101
+
102
+ // Different timestamps but same hash for same content
103
+ expect(manifest1.timestamp_ns).not.toBe(manifest2.timestamp_ns);
104
+ expect(manifest1.o_hash).toBe(manifest2.o_hash);
105
+ });
106
+
107
+ it('should produce different hash for different state', async () => {
108
+ const universe1 = { data: 'version1' };
109
+ const universe2 = { data: 'version2' };
110
+
111
+ const manifest1 = await freezeUniverse(universe1, { snapshotDir: TEST_SNAPSHOT_DIR });
112
+ const manifest2 = await freezeUniverse(universe2, { snapshotDir: TEST_SNAPSHOT_DIR });
113
+
114
+ expect(manifest1.o_hash).not.toBe(manifest2.o_hash);
115
+ });
116
+
117
+ it('should handle nested objects', async () => {
118
+ const universe = {
119
+ level1: {
120
+ level2: {
121
+ level3: {
122
+ data: 'deep',
123
+ },
124
+ },
125
+ },
126
+ };
127
+
128
+ const manifest = await freezeUniverse(universe, { snapshotDir: TEST_SNAPSHOT_DIR });
129
+
130
+ expect(manifest).toBeDefined();
131
+ expect(manifest.o_hash).toBeDefined();
132
+ });
133
+
134
+ it('should throw TypeError for non-object input', async () => {
135
+ await expect(freezeUniverse(null, { snapshotDir: TEST_SNAPSHOT_DIR }))
136
+ .rejects.toThrow(TypeError);
137
+
138
+ await expect(freezeUniverse('string', { snapshotDir: TEST_SNAPSHOT_DIR }))
139
+ .rejects.toThrow(TypeError);
140
+
141
+ await expect(freezeUniverse(123, { snapshotDir: TEST_SNAPSHOT_DIR }))
142
+ .rejects.toThrow(TypeError);
143
+ });
144
+ });
145
+
146
+ describe('verifyFreeze', () => {
147
+ it('should verify valid snapshot', async () => {
148
+ const universe = { data: 'test' };
149
+ const manifest = await freezeUniverse(universe, { snapshotDir: TEST_SNAPSHOT_DIR });
150
+
151
+ const isValid = await verifyFreeze(manifest, { snapshotDir: TEST_SNAPSHOT_DIR });
152
+
153
+ expect(isValid).toBe(true);
154
+ });
155
+
156
+ it('should verify snapshot by timestamp string', async () => {
157
+ const universe = { data: 'test' };
158
+ const manifest = await freezeUniverse(universe, { snapshotDir: TEST_SNAPSHOT_DIR });
159
+
160
+ const isValid = await verifyFreeze(manifest.timestamp_ns, { snapshotDir: TEST_SNAPSHOT_DIR });
161
+
162
+ expect(isValid).toBe(true);
163
+ });
164
+
165
+ it('should detect corrupted snapshot', async () => {
166
+ const universe = { data: 'original' };
167
+ const manifest = await freezeUniverse(universe, { snapshotDir: TEST_SNAPSHOT_DIR });
168
+
169
+ // Corrupt the state file
170
+ const statePath = path.join(TEST_SNAPSHOT_DIR, manifest.timestamp_ns, 'state.json');
171
+ await fs.writeFile(statePath, JSON.stringify({ data: 'corrupted' }), 'utf-8');
172
+
173
+ const isValid = await verifyFreeze(manifest, { snapshotDir: TEST_SNAPSHOT_DIR });
174
+
175
+ expect(isValid).toBe(false);
176
+ });
177
+
178
+ it('should throw for non-existent snapshot', async () => {
179
+ await expect(verifyFreeze('999999999999999999', { snapshotDir: TEST_SNAPSHOT_DIR }))
180
+ .rejects.toThrow('Snapshot not found');
181
+ });
182
+
183
+ it('should throw TypeError for invalid input', async () => {
184
+ await expect(verifyFreeze(null, { snapshotDir: TEST_SNAPSHOT_DIR }))
185
+ .rejects.toThrow(TypeError);
186
+
187
+ await expect(verifyFreeze(123, { snapshotDir: TEST_SNAPSHOT_DIR }))
188
+ .rejects.toThrow(TypeError);
189
+
190
+ await expect(verifyFreeze({}, { snapshotDir: TEST_SNAPSHOT_DIR }))
191
+ .rejects.toThrow(TypeError);
192
+ });
193
+ });
194
+
195
+ describe('reconstructTo', () => {
196
+ it('should reconstruct from snapshot', async () => {
197
+ const universe = {
198
+ entities: ['e1', 'e2', 'e3'],
199
+ count: 3,
200
+ metadata: { version: 1 },
201
+ };
202
+
203
+ const manifest = await freezeUniverse(universe, { snapshotDir: TEST_SNAPSHOT_DIR });
204
+ const targetTime = BigInt(manifest.timestamp_ns);
205
+
206
+ const reconstructed = await reconstructTo(targetTime, { snapshotDir: TEST_SNAPSHOT_DIR });
207
+
208
+ expect(reconstructed).toEqual(universe);
209
+ });
210
+
211
+ it('should reconstruct from string timestamp', async () => {
212
+ const universe = { data: 'test' };
213
+ const manifest = await freezeUniverse(universe, { snapshotDir: TEST_SNAPSHOT_DIR });
214
+
215
+ const reconstructed = await reconstructTo(manifest.timestamp_ns, { snapshotDir: TEST_SNAPSHOT_DIR });
216
+
217
+ expect(reconstructed).toEqual(universe);
218
+ });
219
+
220
+ it('should find closest snapshot before target time', async () => {
221
+ const universe1 = { version: 1 };
222
+ const manifest1 = await freezeUniverse(universe1, { snapshotDir: TEST_SNAPSHOT_DIR });
223
+
224
+ await new Promise(resolve => setTimeout(resolve, 10));
225
+
226
+ const universe2 = { version: 2 };
227
+ const manifest2 = await freezeUniverse(universe2, { snapshotDir: TEST_SNAPSHOT_DIR });
228
+
229
+ // Target time far in the future should get latest snapshot
230
+ const futureTime = BigInt(manifest2.timestamp_ns) + 1000000n;
231
+ const reconstructed = await reconstructTo(futureTime, { snapshotDir: TEST_SNAPSHOT_DIR });
232
+
233
+ expect(reconstructed).toEqual(universe2);
234
+ });
235
+
236
+ it('should reconstruct earliest snapshot when target is far past', async () => {
237
+ const universe = { data: 'earliest' };
238
+ const manifest = await freezeUniverse(universe, { snapshotDir: TEST_SNAPSHOT_DIR });
239
+
240
+ // Target time slightly after snapshot
241
+ const targetTime = BigInt(manifest.timestamp_ns) + 1n;
242
+ const reconstructed = await reconstructTo(targetTime, { snapshotDir: TEST_SNAPSHOT_DIR });
243
+
244
+ expect(reconstructed).toEqual(universe);
245
+ });
246
+
247
+ it('should handle BigInt values in reconstructed state', async () => {
248
+ const universe = {
249
+ timestamp: 9876543210123456789n,
250
+ value: 42n,
251
+ };
252
+
253
+ const manifest = await freezeUniverse(universe, { snapshotDir: TEST_SNAPSHOT_DIR });
254
+ const reconstructed = await reconstructTo(BigInt(manifest.timestamp_ns), { snapshotDir: TEST_SNAPSHOT_DIR });
255
+
256
+ expect(reconstructed.timestamp).toBe(9876543210123456789n);
257
+ expect(reconstructed.value).toBe(42n);
258
+ });
259
+
260
+ it('should throw when no snapshots exist', async () => {
261
+ await expect(reconstructTo(123456789n, { snapshotDir: TEST_SNAPSHOT_DIR }))
262
+ .rejects.toThrow('No snapshots available');
263
+ });
264
+
265
+ it('should throw when target time is before all snapshots', async () => {
266
+ const universe = { data: 'test' };
267
+ const manifest = await freezeUniverse(universe, { snapshotDir: TEST_SNAPSHOT_DIR });
268
+
269
+ const earlyTime = BigInt(manifest.timestamp_ns) - 1000000n;
270
+
271
+ await expect(reconstructTo(earlyTime, { snapshotDir: TEST_SNAPSHOT_DIR }))
272
+ .rejects.toThrow('No snapshot found');
273
+ });
274
+
275
+ it('should require exact match when exact option is true', async () => {
276
+ const universe = { data: 'test' };
277
+ const manifest = await freezeUniverse(universe, { snapshotDir: TEST_SNAPSHOT_DIR });
278
+
279
+ const exactTime = BigInt(manifest.timestamp_ns);
280
+ const reconstructed = await reconstructTo(exactTime, {
281
+ snapshotDir: TEST_SNAPSHOT_DIR,
282
+ exact: true,
283
+ });
284
+
285
+ expect(reconstructed).toEqual(universe);
286
+
287
+ // Different time should fail with exact option
288
+ const differentTime = exactTime + 1n;
289
+ await expect(reconstructTo(differentTime, {
290
+ snapshotDir: TEST_SNAPSHOT_DIR,
291
+ exact: true,
292
+ })).rejects.toThrow('No snapshot found');
293
+ });
294
+
295
+ it('should throw TypeError for invalid time', async () => {
296
+ await expect(reconstructTo('not-a-number', { snapshotDir: TEST_SNAPSHOT_DIR }))
297
+ .rejects.toThrow();
298
+
299
+ await expect(reconstructTo(null, { snapshotDir: TEST_SNAPSHOT_DIR }))
300
+ .rejects.toThrow(TypeError);
301
+
302
+ await expect(reconstructTo({}, { snapshotDir: TEST_SNAPSHOT_DIR }))
303
+ .rejects.toThrow(TypeError);
304
+ });
305
+
306
+ it('should throw RangeError for negative time', async () => {
307
+ await expect(reconstructTo(-1n, { snapshotDir: TEST_SNAPSHOT_DIR }))
308
+ .rejects.toThrow(RangeError);
309
+ });
310
+ });
311
+
312
+ describe('getSnapshotList', () => {
313
+ it('should return empty array when no snapshots exist', async () => {
314
+ const snapshots = await getSnapshotList({ snapshotDir: TEST_SNAPSHOT_DIR });
315
+
316
+ expect(snapshots).toEqual([]);
317
+ });
318
+
319
+ it('should list all snapshots sorted by time (newest first)', async () => {
320
+ const universe1 = { version: 1 };
321
+ await freezeUniverse(universe1, { snapshotDir: TEST_SNAPSHOT_DIR });
322
+
323
+ await new Promise(resolve => setTimeout(resolve, 10));
324
+
325
+ const universe2 = { version: 2 };
326
+ await freezeUniverse(universe2, { snapshotDir: TEST_SNAPSHOT_DIR });
327
+
328
+ await new Promise(resolve => setTimeout(resolve, 10));
329
+
330
+ const universe3 = { version: 3 };
331
+ await freezeUniverse(universe3, { snapshotDir: TEST_SNAPSHOT_DIR });
332
+
333
+ const snapshots = await getSnapshotList({ snapshotDir: TEST_SNAPSHOT_DIR });
334
+
335
+ expect(snapshots).toHaveLength(3);
336
+
337
+ // Verify sorted newest first
338
+ const time1 = BigInt(snapshots[0].manifest.timestamp_ns);
339
+ const time2 = BigInt(snapshots[1].manifest.timestamp_ns);
340
+ const time3 = BigInt(snapshots[2].manifest.timestamp_ns);
341
+
342
+ expect(time1 > time2).toBe(true);
343
+ expect(time2 > time3).toBe(true);
344
+ });
345
+
346
+ it('should list snapshots in ascending order when requested', async () => {
347
+ const universe1 = { version: 1 };
348
+ await freezeUniverse(universe1, { snapshotDir: TEST_SNAPSHOT_DIR });
349
+
350
+ await new Promise(resolve => setTimeout(resolve, 10));
351
+
352
+ const universe2 = { version: 2 };
353
+ await freezeUniverse(universe2, { snapshotDir: TEST_SNAPSHOT_DIR });
354
+
355
+ const snapshots = await getSnapshotList({
356
+ snapshotDir: TEST_SNAPSHOT_DIR,
357
+ ascending: true,
358
+ });
359
+
360
+ expect(snapshots).toHaveLength(2);
361
+
362
+ // Verify sorted oldest first
363
+ const time1 = BigInt(snapshots[0].manifest.timestamp_ns);
364
+ const time2 = BigInt(snapshots[1].manifest.timestamp_ns);
365
+
366
+ expect(time1 < time2).toBe(true);
367
+ });
368
+
369
+ it('should include manifest and path for each snapshot', async () => {
370
+ const universe = { data: 'test' };
371
+ await freezeUniverse(universe, { snapshotDir: TEST_SNAPSHOT_DIR });
372
+
373
+ const snapshots = await getSnapshotList({ snapshotDir: TEST_SNAPSHOT_DIR });
374
+
375
+ expect(snapshots).toHaveLength(1);
376
+ expect(snapshots[0].manifest).toBeDefined();
377
+ expect(snapshots[0].manifest.timestamp_ns).toBeDefined();
378
+ expect(snapshots[0].manifest.o_hash).toBeDefined();
379
+ expect(snapshots[0].path).toBeDefined();
380
+ expect(snapshots[0].path).toContain(TEST_SNAPSHOT_DIR);
381
+ });
382
+
383
+ it('should skip invalid snapshots', async () => {
384
+ const universe = { data: 'test' };
385
+ await freezeUniverse(universe, { snapshotDir: TEST_SNAPSHOT_DIR });
386
+
387
+ // Create invalid snapshot directory (no manifest)
388
+ const invalidPath = path.join(TEST_SNAPSHOT_DIR, 'invalid-snapshot');
389
+ await fs.mkdir(invalidPath, { recursive: true });
390
+
391
+ const snapshots = await getSnapshotList({ snapshotDir: TEST_SNAPSHOT_DIR });
392
+
393
+ // Should only return the valid snapshot
394
+ expect(snapshots).toHaveLength(1);
395
+ });
396
+ });
397
+
398
+ describe('Hash Consistency', () => {
399
+ it('should produce same hash regardless of property order', async () => {
400
+ const universe1 = { a: 1, b: 2, c: 3 };
401
+ const universe2 = { c: 3, a: 1, b: 2 };
402
+
403
+ const manifest1 = await freezeUniverse(universe1, { snapshotDir: TEST_SNAPSHOT_DIR });
404
+
405
+ await new Promise(resolve => setTimeout(resolve, 10));
406
+
407
+ const manifest2 = await freezeUniverse(universe2, { snapshotDir: TEST_SNAPSHOT_DIR });
408
+
409
+ expect(manifest1.o_hash).toBe(manifest2.o_hash);
410
+ });
411
+
412
+ it('should produce same hash for nested objects with different property order', async () => {
413
+ const universe1 = {
414
+ outer: { a: 1, b: { x: 10, y: 20 } },
415
+ };
416
+ const universe2 = {
417
+ outer: { b: { y: 20, x: 10 }, a: 1 },
418
+ };
419
+
420
+ const manifest1 = await freezeUniverse(universe1, { snapshotDir: TEST_SNAPSHOT_DIR });
421
+
422
+ await new Promise(resolve => setTimeout(resolve, 10));
423
+
424
+ const manifest2 = await freezeUniverse(universe2, { snapshotDir: TEST_SNAPSHOT_DIR });
425
+
426
+ expect(manifest1.o_hash).toBe(manifest2.o_hash);
427
+ });
428
+ });
429
+
430
+ describe('Multi-Snapshot Handling', () => {
431
+ it('should manage multiple snapshots independently', async () => {
432
+ const snapshots = [];
433
+
434
+ for (let i = 0; i < 5; i++) {
435
+ const universe = { version: i, data: `snapshot-${i}` };
436
+ const manifest = await freezeUniverse(universe, { snapshotDir: TEST_SNAPSHOT_DIR });
437
+ snapshots.push(manifest);
438
+
439
+ await new Promise(resolve => setTimeout(resolve, 10));
440
+ }
441
+
442
+ const list = await getSnapshotList({ snapshotDir: TEST_SNAPSHOT_DIR });
443
+ expect(list).toHaveLength(5);
444
+
445
+ // Verify each snapshot independently
446
+ for (const manifest of snapshots) {
447
+ const isValid = await verifyFreeze(manifest, { snapshotDir: TEST_SNAPSHOT_DIR });
448
+ expect(isValid).toBe(true);
449
+ }
450
+ });
451
+
452
+ it('should reconstruct correct state from multiple snapshots', async () => {
453
+ const states = [];
454
+
455
+ for (let i = 0; i < 3; i++) {
456
+ const universe = { version: i };
457
+ const manifest = await freezeUniverse(universe, { snapshotDir: TEST_SNAPSHOT_DIR });
458
+ states.push({ manifest, universe });
459
+
460
+ await new Promise(resolve => setTimeout(resolve, 10));
461
+ }
462
+
463
+ // Reconstruct each state
464
+ for (const { manifest, universe } of states) {
465
+ const reconstructed = await reconstructTo(BigInt(manifest.timestamp_ns), {
466
+ snapshotDir: TEST_SNAPSHOT_DIR
467
+ });
468
+ expect(reconstructed).toEqual(universe);
469
+ }
470
+ });
471
+ });
472
+ });