progmune-runtime 2.0.2 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/.mcp.json +11 -0
  2. package/.progmune_allowlist +50 -0
  3. package/.test_report/test_report.md +87 -0
  4. package/Dockerfile +2 -10
  5. package/FAQ.md +167 -0
  6. package/demo-project/auth.ts +55 -0
  7. package/demo-project/tsconfig.json +8 -0
  8. package/dist/ab-stats.js +11 -0
  9. package/dist/acl-breakdown.js +13 -0
  10. package/dist/all-sessions.js +11 -0
  11. package/dist/antibody-stats.js +11 -0
  12. package/dist/audit.js +218 -0
  13. package/dist/benchmark-count.js +7 -0
  14. package/dist/benchmark-full.js +17 -0
  15. package/dist/benchmark-pass-rate.js +54 -0
  16. package/dist/benchmark-report.js +67 -0
  17. package/dist/benchmark-save.js +62 -0
  18. package/dist/benchmark-status.js +15 -0
  19. package/dist/branch-ledger.js +365 -0
  20. package/dist/branch-tree-count.js +14 -0
  21. package/dist/check.js +506 -0
  22. package/dist/common-fixpath.js +12 -0
  23. package/dist/constraint-types.js +12 -0
  24. package/dist/deterministic-replay.js +277 -0
  25. package/dist/emitter.js +112 -12
  26. package/dist/exec-metrics.js +11 -0
  27. package/dist/execute.js +242 -0
  28. package/dist/extract-ir.js +550 -5
  29. package/dist/failure-collector.js +143 -0
  30. package/dist/failure-corpus.js +481 -35
  31. package/dist/failure-report.js +11 -0
  32. package/dist/failures.js +11 -0
  33. package/dist/fast-path-hits.js +13 -0
  34. package/dist/feedback.js +6 -3
  35. package/dist/file-lock.js +82 -0
  36. package/dist/find-session.js +10 -0
  37. package/dist/fingerprint-list.js +15 -0
  38. package/dist/gen-history-log.js +13 -0
  39. package/dist/generate.js +2 -1
  40. package/dist/generate_500.js +4 -2
  41. package/dist/genome.js +11 -0
  42. package/dist/heatmap-data.js +11 -0
  43. package/dist/heatmap.js +11 -0
  44. package/dist/immune-reporter.js +137 -0
  45. package/dist/learned.js +11 -0
  46. package/dist/ledger-registry.js +241 -0
  47. package/dist/llm.js +43 -2
  48. package/dist/load-benchmarks.js +47 -0
  49. package/dist/main.js +2 -1
  50. package/dist/mcp-server.mjs +446 -34
  51. package/dist/memory-layer.js +51 -13
  52. package/dist/metrics.js +11 -0
  53. package/dist/obs-web.js +561 -0
  54. package/dist/p0_ssg_demo.js +255 -40
  55. package/dist/planner.js +933 -65
  56. package/dist/protocol-registry.js +105 -0
  57. package/dist/recent-session.js +12 -0
  58. package/dist/repair-proposal.js +353 -0
  59. package/dist/report.js +32 -0
  60. package/dist/runtime-invariants.js +161 -0
  61. package/dist/runtime-types.js +117 -0
  62. package/dist/search-planner.js +38 -9
  63. package/dist/semantic-snapshot.js +155 -0
  64. package/dist/semantic-trace.js +1497 -0
  65. package/dist/semantic-validator.js +3 -2
  66. package/dist/semantic_guard_test.js +2 -1
  67. package/dist/sessions.js +11 -0
  68. package/dist/ssg-validator.js +658 -20
  69. package/dist/svl-distribution.js +11 -0
  70. package/dist/terminal-status.js +11 -0
  71. package/dist/test_failure_corpus.js +3 -1
  72. package/dist/token-savings.js +11 -0
  73. package/dist/total-repairs.js +12 -0
  74. package/dist/unresolved-count.js +12 -0
  75. package/dist/valid-fingerprints.js +13 -0
  76. package/dist/validator.js +116 -60
  77. package/dist/verify-fps.js +11 -0
  78. package/dist/verify-ledgers.js +11 -0
  79. package/docs/whitepaper-style.css +77 -0
  80. package/docs/whitepaper-v2.1.md +609 -0
  81. package/docs/whitepaper-v2.2.md +1064 -0
  82. package/docs/whitepaper-v2.2.pdf +0 -0
  83. package/fly.toml +1 -1
  84. package/package.json +13 -4
  85. package/protocols.json +136 -0
  86. package/public/dashboard.html +119 -0
  87. package/readme.md +829 -0
  88. package/server/hub.js +84 -12
  89. package/test/replay-golden/sess_1780063202050_mgeld.json +9 -0
  90. package/test/replay-golden/sess_1780064032560_gocld.json +354 -0
  91. package/test/replay-golden/sess_1780064413331_s2709.json +606 -0
  92. package/test/replay-golden/sess_1780064792710_y3avo.json +614 -0
  93. package/test/replay-golden.ts +84 -0
  94. package/test_benchmark.js +165 -0
  95. package/test_comprehensive.mjs +638 -0
  96. package/test_concurrency.js +129 -0
  97. package/test_ir_robustness.js +85 -0
  98. package/test_semantic_contracts.js +269 -0
  99. package/test_ssg_stress.js +156 -0
  100. package/test_svl3.js +58 -0
  101. package/tsconfig.json +1 -1
  102. package/.env.example +0 -3
  103. package/.progmune_memory/fingerprints.json +0 -7
  104. package/.progmune_memory/opt_in.json +0 -4
  105. package/README.md +0 -118
  106. package/dist/mcp-server.js +0 -55
  107. package/immune_hub_data/2026-05-14.json +0 -50
@@ -0,0 +1,614 @@
1
+ {
2
+ "sessionId": "sess_1780064792710_y3avo",
3
+ "intent": "extract IR then validate and emit code",
4
+ "attempts": [
5
+ {
6
+ "id": "att_1780064797675_ak469",
7
+ "sessionId": "sess_1780064792710_y3avo",
8
+ "attemptNumber": 1,
9
+ "inputIntent": "extract IR then validate and emit code",
10
+ "plannerSeed": "3dfe9cef",
11
+ "constraintSnapshotId": "snap_1780064792712_82709ff22603",
12
+ "generatedActions": [
13
+ {
14
+ "kind": "call",
15
+ "function": "extractIRPython",
16
+ "args": [
17
+ {
18
+ "name": "projectRoot",
19
+ "type": "string",
20
+ "value": "{{projectRoot}}"
21
+ }
22
+ ],
23
+ "assignTo": "extractIRPython_result"
24
+ },
25
+ {
26
+ "kind": "call",
27
+ "function": "extractDirectCalls",
28
+ "args": [
29
+ {
30
+ "name": "func",
31
+ "type": "FunctionDeclaration | ArrowFunction",
32
+ "value": "{{func}}"
33
+ }
34
+ ],
35
+ "assignTo": "extractDirectCalls_result"
36
+ },
37
+ {
38
+ "kind": "call",
39
+ "function": "extractIR",
40
+ "args": [
41
+ {
42
+ "name": "projectRoot",
43
+ "type": "string",
44
+ "value": "{{projectRoot}}"
45
+ }
46
+ ],
47
+ "assignTo": "extractIR_result"
48
+ },
49
+ {
50
+ "kind": "call",
51
+ "function": "extractFingerprints",
52
+ "args": [
53
+ {
54
+ "name": "cursor",
55
+ "type": "{ lastTimestamp: string | null }",
56
+ "value": "{{cursor}}"
57
+ }
58
+ ],
59
+ "assignTo": "extractFingerprints_result"
60
+ },
61
+ {
62
+ "kind": "call",
63
+ "function": "extractKeywords",
64
+ "args": [
65
+ {
66
+ "name": "intent",
67
+ "type": "string",
68
+ "value": "{{intent}}"
69
+ }
70
+ ],
71
+ "assignTo": "extractKeywords_result"
72
+ },
73
+ {
74
+ "kind": "call",
75
+ "function": "ensureDir",
76
+ "args": [
77
+ {
78
+ "name": "dir",
79
+ "type": "string",
80
+ "value": "{{dir}}"
81
+ }
82
+ ],
83
+ "assignTo": "ensureDir_result"
84
+ },
85
+ {
86
+ "kind": "call",
87
+ "function": "ensureLockDir",
88
+ "args": [],
89
+ "assignTo": "ensureLockDir_result"
90
+ },
91
+ {
92
+ "kind": "call",
93
+ "function": "loadProtocolsFromIR",
94
+ "args": [
95
+ {
96
+ "name": "ir",
97
+ "type": "any[]",
98
+ "value": "{{ir}}"
99
+ }
100
+ ],
101
+ "assignTo": "loadProtocolsFromIR_result"
102
+ },
103
+ {
104
+ "kind": "call",
105
+ "function": "attemptSSGRepair",
106
+ "args": [
107
+ {
108
+ "name": "actions",
109
+ "type": "Action[]",
110
+ "value": "{{actions}}"
111
+ },
112
+ {
113
+ "name": "rejection",
114
+ "type": "SSGRejection",
115
+ "value": "{{rejection}}"
116
+ },
117
+ {
118
+ "name": "ir",
119
+ "type": "any[]",
120
+ "value": "{{ir}}"
121
+ },
122
+ {
123
+ "name": "protocols",
124
+ "type": "FunctionProtocol[]",
125
+ "value": "{{protocols}}"
126
+ },
127
+ {
128
+ "name": "namespaceInitialStates",
129
+ "type": "Map<string, string>",
130
+ "value": "{{namespaceInitialStates}}"
131
+ }
132
+ ],
133
+ "assignTo": "attemptSSGRepair_result"
134
+ },
135
+ {
136
+ "kind": "call",
137
+ "function": "loadIR",
138
+ "args": [],
139
+ "assignTo": "loadIR_result"
140
+ },
141
+ {
142
+ "kind": "call",
143
+ "function": "mkdirSync",
144
+ "args": [
145
+ {
146
+ "name": "path",
147
+ "type": "string",
148
+ "value": "{{path}}"
149
+ },
150
+ {
151
+ "name": "options",
152
+ "type": "object",
153
+ "value": "{{options}}"
154
+ }
155
+ ]
156
+ },
157
+ {
158
+ "kind": "call",
159
+ "function": "readdirSync",
160
+ "args": [
161
+ {
162
+ "name": "path",
163
+ "type": "string",
164
+ "value": "{{path}}"
165
+ }
166
+ ],
167
+ "assignTo": "readdirSync_result"
168
+ },
169
+ {
170
+ "kind": "call",
171
+ "function": "rmdirSync",
172
+ "args": [],
173
+ "assignTo": "rmdirSync_result"
174
+ },
175
+ {
176
+ "kind": "call",
177
+ "function": "require",
178
+ "args": [],
179
+ "assignTo": "require_result"
180
+ },
181
+ {
182
+ "kind": "call",
183
+ "function": "dirname",
184
+ "args": [
185
+ {
186
+ "name": "path",
187
+ "type": "string",
188
+ "value": "{{path}}"
189
+ }
190
+ ],
191
+ "assignTo": "dirname_result"
192
+ },
193
+ {
194
+ "kind": "call",
195
+ "function": "validateProtocolWithTransitions",
196
+ "args": [
197
+ {
198
+ "name": "actions",
199
+ "type": "Action[]",
200
+ "value": "{{actions}}"
201
+ },
202
+ {
203
+ "name": "protocols",
204
+ "type": "FunctionProtocol[]",
205
+ "value": "{{protocols}}"
206
+ },
207
+ {
208
+ "name": "namespaceInitialStates",
209
+ "type": "Map<string, string>",
210
+ "value": "{{namespaceInitialStates}}"
211
+ }
212
+ ],
213
+ "assignTo": "validateProtocolWithTransitions_result"
214
+ },
215
+ {
216
+ "kind": "call",
217
+ "function": "validateAction",
218
+ "args": [
219
+ {
220
+ "name": "action",
221
+ "type": "Action",
222
+ "value": "{{action}}"
223
+ }
224
+ ],
225
+ "assignTo": "validateAction_result"
226
+ },
227
+ {
228
+ "kind": "call",
229
+ "function": "validateActionSequence",
230
+ "args": [
231
+ {
232
+ "name": "actions",
233
+ "type": "Action[]",
234
+ "value": "{{actions}}"
235
+ }
236
+ ],
237
+ "assignTo": "validateActionSequence_result"
238
+ },
239
+ {
240
+ "kind": "call",
241
+ "function": "generateCandidateRules",
242
+ "args": [],
243
+ "assignTo": "generateCandidateRules_result"
244
+ },
245
+ {
246
+ "kind": "call",
247
+ "function": "runAndCheck",
248
+ "args": [
249
+ {
250
+ "name": "code",
251
+ "type": "string",
252
+ "value": "{{code}}"
253
+ }
254
+ ],
255
+ "assignTo": "runAndCheck_result"
256
+ },
257
+ {
258
+ "kind": "call",
259
+ "function": "random",
260
+ "args": [],
261
+ "assignTo": "random_result"
262
+ },
263
+ {
264
+ "kind": "call",
265
+ "function": "emitCode",
266
+ "args": [
267
+ {
268
+ "name": "actions",
269
+ "type": "Action[]",
270
+ "value": "{{actions}}"
271
+ }
272
+ ],
273
+ "assignTo": "emitCode_result"
274
+ },
275
+ {
276
+ "kind": "call",
277
+ "function": "emitPython",
278
+ "args": [
279
+ {
280
+ "name": "actions",
281
+ "type": "Action[]",
282
+ "value": "{{actions}}"
283
+ }
284
+ ],
285
+ "assignTo": "emitPython_result"
286
+ },
287
+ {
288
+ "kind": "call",
289
+ "function": "executeActionCode",
290
+ "args": [
291
+ {
292
+ "name": "code",
293
+ "type": "string",
294
+ "value": "{{code}}"
295
+ }
296
+ ],
297
+ "assignTo": "executeActionCode_result"
298
+ }
299
+ ],
300
+ "transitions": [],
301
+ "violations": [],
302
+ "outcome": "success",
303
+ "timestamp": 1780064797675,
304
+ "llmCallCount": 0,
305
+ "durationMs": 0
306
+ }
307
+ ],
308
+ "resolved": true,
309
+ "startedAt": 1780064792710,
310
+ "successfulAttempt": {
311
+ "id": "att_1780064797675_ak469",
312
+ "sessionId": "sess_1780064792710_y3avo",
313
+ "attemptNumber": 1,
314
+ "inputIntent": "extract IR then validate and emit code",
315
+ "plannerSeed": "3dfe9cef",
316
+ "constraintSnapshotId": "snap_1780064792712_82709ff22603",
317
+ "generatedActions": [
318
+ {
319
+ "kind": "call",
320
+ "function": "extractIRPython",
321
+ "args": [
322
+ {
323
+ "name": "projectRoot",
324
+ "type": "string",
325
+ "value": "{{projectRoot}}"
326
+ }
327
+ ],
328
+ "assignTo": "extractIRPython_result"
329
+ },
330
+ {
331
+ "kind": "call",
332
+ "function": "extractDirectCalls",
333
+ "args": [
334
+ {
335
+ "name": "func",
336
+ "type": "FunctionDeclaration | ArrowFunction",
337
+ "value": "{{func}}"
338
+ }
339
+ ],
340
+ "assignTo": "extractDirectCalls_result"
341
+ },
342
+ {
343
+ "kind": "call",
344
+ "function": "extractIR",
345
+ "args": [
346
+ {
347
+ "name": "projectRoot",
348
+ "type": "string",
349
+ "value": "{{projectRoot}}"
350
+ }
351
+ ],
352
+ "assignTo": "extractIR_result"
353
+ },
354
+ {
355
+ "kind": "call",
356
+ "function": "extractFingerprints",
357
+ "args": [
358
+ {
359
+ "name": "cursor",
360
+ "type": "{ lastTimestamp: string | null }",
361
+ "value": "{{cursor}}"
362
+ }
363
+ ],
364
+ "assignTo": "extractFingerprints_result"
365
+ },
366
+ {
367
+ "kind": "call",
368
+ "function": "extractKeywords",
369
+ "args": [
370
+ {
371
+ "name": "intent",
372
+ "type": "string",
373
+ "value": "{{intent}}"
374
+ }
375
+ ],
376
+ "assignTo": "extractKeywords_result"
377
+ },
378
+ {
379
+ "kind": "call",
380
+ "function": "ensureDir",
381
+ "args": [
382
+ {
383
+ "name": "dir",
384
+ "type": "string",
385
+ "value": "{{dir}}"
386
+ }
387
+ ],
388
+ "assignTo": "ensureDir_result"
389
+ },
390
+ {
391
+ "kind": "call",
392
+ "function": "ensureLockDir",
393
+ "args": [],
394
+ "assignTo": "ensureLockDir_result"
395
+ },
396
+ {
397
+ "kind": "call",
398
+ "function": "loadProtocolsFromIR",
399
+ "args": [
400
+ {
401
+ "name": "ir",
402
+ "type": "any[]",
403
+ "value": "{{ir}}"
404
+ }
405
+ ],
406
+ "assignTo": "loadProtocolsFromIR_result"
407
+ },
408
+ {
409
+ "kind": "call",
410
+ "function": "attemptSSGRepair",
411
+ "args": [
412
+ {
413
+ "name": "actions",
414
+ "type": "Action[]",
415
+ "value": "{{actions}}"
416
+ },
417
+ {
418
+ "name": "rejection",
419
+ "type": "SSGRejection",
420
+ "value": "{{rejection}}"
421
+ },
422
+ {
423
+ "name": "ir",
424
+ "type": "any[]",
425
+ "value": "{{ir}}"
426
+ },
427
+ {
428
+ "name": "protocols",
429
+ "type": "FunctionProtocol[]",
430
+ "value": "{{protocols}}"
431
+ },
432
+ {
433
+ "name": "namespaceInitialStates",
434
+ "type": "Map<string, string>",
435
+ "value": "{{namespaceInitialStates}}"
436
+ }
437
+ ],
438
+ "assignTo": "attemptSSGRepair_result"
439
+ },
440
+ {
441
+ "kind": "call",
442
+ "function": "loadIR",
443
+ "args": [],
444
+ "assignTo": "loadIR_result"
445
+ },
446
+ {
447
+ "kind": "call",
448
+ "function": "mkdirSync",
449
+ "args": [
450
+ {
451
+ "name": "path",
452
+ "type": "string",
453
+ "value": "{{path}}"
454
+ },
455
+ {
456
+ "name": "options",
457
+ "type": "object",
458
+ "value": "{{options}}"
459
+ }
460
+ ]
461
+ },
462
+ {
463
+ "kind": "call",
464
+ "function": "readdirSync",
465
+ "args": [
466
+ {
467
+ "name": "path",
468
+ "type": "string",
469
+ "value": "{{path}}"
470
+ }
471
+ ],
472
+ "assignTo": "readdirSync_result"
473
+ },
474
+ {
475
+ "kind": "call",
476
+ "function": "rmdirSync",
477
+ "args": [],
478
+ "assignTo": "rmdirSync_result"
479
+ },
480
+ {
481
+ "kind": "call",
482
+ "function": "require",
483
+ "args": [],
484
+ "assignTo": "require_result"
485
+ },
486
+ {
487
+ "kind": "call",
488
+ "function": "dirname",
489
+ "args": [
490
+ {
491
+ "name": "path",
492
+ "type": "string",
493
+ "value": "{{path}}"
494
+ }
495
+ ],
496
+ "assignTo": "dirname_result"
497
+ },
498
+ {
499
+ "kind": "call",
500
+ "function": "validateProtocolWithTransitions",
501
+ "args": [
502
+ {
503
+ "name": "actions",
504
+ "type": "Action[]",
505
+ "value": "{{actions}}"
506
+ },
507
+ {
508
+ "name": "protocols",
509
+ "type": "FunctionProtocol[]",
510
+ "value": "{{protocols}}"
511
+ },
512
+ {
513
+ "name": "namespaceInitialStates",
514
+ "type": "Map<string, string>",
515
+ "value": "{{namespaceInitialStates}}"
516
+ }
517
+ ],
518
+ "assignTo": "validateProtocolWithTransitions_result"
519
+ },
520
+ {
521
+ "kind": "call",
522
+ "function": "validateAction",
523
+ "args": [
524
+ {
525
+ "name": "action",
526
+ "type": "Action",
527
+ "value": "{{action}}"
528
+ }
529
+ ],
530
+ "assignTo": "validateAction_result"
531
+ },
532
+ {
533
+ "kind": "call",
534
+ "function": "validateActionSequence",
535
+ "args": [
536
+ {
537
+ "name": "actions",
538
+ "type": "Action[]",
539
+ "value": "{{actions}}"
540
+ }
541
+ ],
542
+ "assignTo": "validateActionSequence_result"
543
+ },
544
+ {
545
+ "kind": "call",
546
+ "function": "generateCandidateRules",
547
+ "args": [],
548
+ "assignTo": "generateCandidateRules_result"
549
+ },
550
+ {
551
+ "kind": "call",
552
+ "function": "runAndCheck",
553
+ "args": [
554
+ {
555
+ "name": "code",
556
+ "type": "string",
557
+ "value": "{{code}}"
558
+ }
559
+ ],
560
+ "assignTo": "runAndCheck_result"
561
+ },
562
+ {
563
+ "kind": "call",
564
+ "function": "random",
565
+ "args": [],
566
+ "assignTo": "random_result"
567
+ },
568
+ {
569
+ "kind": "call",
570
+ "function": "emitCode",
571
+ "args": [
572
+ {
573
+ "name": "actions",
574
+ "type": "Action[]",
575
+ "value": "{{actions}}"
576
+ }
577
+ ],
578
+ "assignTo": "emitCode_result"
579
+ },
580
+ {
581
+ "kind": "call",
582
+ "function": "emitPython",
583
+ "args": [
584
+ {
585
+ "name": "actions",
586
+ "type": "Action[]",
587
+ "value": "{{actions}}"
588
+ }
589
+ ],
590
+ "assignTo": "emitPython_result"
591
+ },
592
+ {
593
+ "kind": "call",
594
+ "function": "executeActionCode",
595
+ "args": [
596
+ {
597
+ "name": "code",
598
+ "type": "string",
599
+ "value": "{{code}}"
600
+ }
601
+ ],
602
+ "assignTo": "executeActionCode_result"
603
+ }
604
+ ],
605
+ "transitions": [],
606
+ "violations": [],
607
+ "outcome": "success",
608
+ "timestamp": 1780064797675,
609
+ "llmCallCount": 0,
610
+ "durationMs": 0
611
+ },
612
+ "snapshotId": "snap_1780064792712_82709ff22603",
613
+ "endedAt": 1780064797675
614
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Replay Golden Set — CI gate.
3
+ *
4
+ * Verifies all golden sessions pass deterministic replay.
5
+ * Any failure blocks the build.
6
+ *
7
+ * Usage: npx ts-node test/replay-golden.ts
8
+ */
9
+
10
+ import * as fs from "fs";
11
+ import * as path from "path";
12
+ import { replaySession } from "../src/deterministic-replay";
13
+
14
+ const GOLDEN_DIR = path.resolve(__dirname, "replay-golden");
15
+
16
+ function main() {
17
+ const files = fs.readdirSync(GOLDEN_DIR).filter(f => f.endsWith(".json"));
18
+ if (files.length === 0) {
19
+ console.error("No golden sessions found.");
20
+ process.exit(1);
21
+ }
22
+
23
+ let passed = 0;
24
+ let failed = 0;
25
+ const failures: string[] = [];
26
+
27
+ for (const file of files) {
28
+ const sessionId = file.replace(".json", "");
29
+ // Temporarily override sessions dir to use golden set
30
+ // We replay from the golden file directly
31
+ const session = JSON.parse(fs.readFileSync(path.join(GOLDEN_DIR, file), "utf-8"));
32
+ const result = replaySessionFromData(sessionId, session);
33
+
34
+ if (result.success) {
35
+ passed++;
36
+ } else {
37
+ failed++;
38
+ failures.push(`${sessionId.slice(0, 13)}...: ${result.divergenceDetail || "unknown"}`);
39
+ }
40
+ }
41
+
42
+ console.log(`Replay Golden: ${passed}/${files.length} passed`);
43
+
44
+ if (failed > 0) {
45
+ console.error(`\n${failed} FAILURES:`);
46
+ for (const f of failures) console.error(` ❌ ${f}`);
47
+ console.error(`\n❌ Replay Golden Set FAILED — blocking.`);
48
+ process.exit(1);
49
+ }
50
+
51
+ console.log("✅ All golden sessions replay consistently.");
52
+ process.exit(0);
53
+ }
54
+
55
+ /** Replay from a pre-loaded session object (avoids corpus dir dependency). */
56
+ function replaySessionFromData(sessionId: string, session: any): ReturnType<typeof replaySession> {
57
+ // Use the same replay logic but from in-memory data
58
+ const { replayLedger } = require("../src/deterministic-replay");
59
+ const { getNsInit } = require("../src/protocol-registry");
60
+
61
+ let transitions: any[] = [];
62
+ let sessionRuleHash = session.ruleHash || "";
63
+ for (const attempt of (session.attempts || [])) {
64
+ transitions = transitions.concat(attempt.transitions || []);
65
+ if (!sessionRuleHash && (attempt.ruleHash || session.ruleHash)) {
66
+ sessionRuleHash = attempt.ruleHash || session.ruleHash;
67
+ }
68
+ }
69
+
70
+ const { hashLedger } = require("../src/ssg-validator");
71
+ const storedHash = transitions.length > 0 ? hashLedger(transitions) : "";
72
+
73
+ return replayLedger(
74
+ sessionId,
75
+ transitions,
76
+ sessionRuleHash,
77
+ storedHash,
78
+ undefined,
79
+ undefined,
80
+ getNsInit()
81
+ );
82
+ }
83
+
84
+ main();