@series-inc/rundot-syncplay 5.23.0-beta.7

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 (264) hide show
  1. package/README.md +610 -0
  2. package/dist/animation.d.ts +119 -0
  3. package/dist/animation.js +488 -0
  4. package/dist/asset-cooking.d.ts +82 -0
  5. package/dist/asset-cooking.js +364 -0
  6. package/dist/authority-room.d.ts +217 -0
  7. package/dist/authority-room.js +701 -0
  8. package/dist/bot-documents.d.ts +115 -0
  9. package/dist/bot-documents.js +549 -0
  10. package/dist/bot-primitives.d.ts +152 -0
  11. package/dist/bot-primitives.js +472 -0
  12. package/dist/browser.d.ts +57 -0
  13. package/dist/browser.js +53 -0
  14. package/dist/canonical.d.ts +12 -0
  15. package/dist/canonical.js +288 -0
  16. package/dist/certification.d.ts +455 -0
  17. package/dist/certification.js +1855 -0
  18. package/dist/chaos-certification.d.ts +56 -0
  19. package/dist/chaos-certification.js +1397 -0
  20. package/dist/cjs/animation.js +495 -0
  21. package/dist/cjs/asset-cooking.js +372 -0
  22. package/dist/cjs/authority-room.js +704 -0
  23. package/dist/cjs/bot-documents.js +556 -0
  24. package/dist/cjs/bot-primitives.js +482 -0
  25. package/dist/cjs/browser.js +96 -0
  26. package/dist/cjs/canonical.js +299 -0
  27. package/dist/cjs/certification.js +1860 -0
  28. package/dist/cjs/chaos-certification.js +1402 -0
  29. package/dist/cjs/collections.js +36 -0
  30. package/dist/cjs/collision.js +96 -0
  31. package/dist/cjs/commands.js +987 -0
  32. package/dist/cjs/config-bundle.js +491 -0
  33. package/dist/cjs/creator.js +30 -0
  34. package/dist/cjs/deterministic-primitives.js +134 -0
  35. package/dist/cjs/deterministic-session.js +1410 -0
  36. package/dist/cjs/ecs-lite.js +155 -0
  37. package/dist/cjs/effects-adapter.js +97 -0
  38. package/dist/cjs/engine-complete.js +2297 -0
  39. package/dist/cjs/engine-core-proof.js +70 -0
  40. package/dist/cjs/engine-parity-matrix.js +874 -0
  41. package/dist/cjs/engine-parity.js +3183 -0
  42. package/dist/cjs/engine-runtime.js +3141 -0
  43. package/dist/cjs/errors.js +22 -0
  44. package/dist/cjs/events.js +247 -0
  45. package/dist/cjs/examples/counter-duel.js +157 -0
  46. package/dist/cjs/examples/fixed-arena.js +368 -0
  47. package/dist/cjs/index.js +229 -0
  48. package/dist/cjs/input-authority.js +150 -0
  49. package/dist/cjs/input-button.js +256 -0
  50. package/dist/cjs/input-timeline.js +418 -0
  51. package/dist/cjs/instant-replay.js +66 -0
  52. package/dist/cjs/lag-compensation3d.js +837 -0
  53. package/dist/cjs/local-authority-server-runner.js +1121 -0
  54. package/dist/cjs/local-authority-wire.js +1497 -0
  55. package/dist/cjs/local-authority.js +817 -0
  56. package/dist/cjs/local-ws-adapter.js +150 -0
  57. package/dist/cjs/match-log.js +61 -0
  58. package/dist/cjs/math.js +157 -0
  59. package/dist/cjs/mock-network-adapter.js +26 -0
  60. package/dist/cjs/movement.js +703 -0
  61. package/dist/cjs/movement3d.js +1246 -0
  62. package/dist/cjs/multiclient-authority.js +308 -0
  63. package/dist/cjs/multiplayer-service.js +434 -0
  64. package/dist/cjs/navigation.js +347 -0
  65. package/dist/cjs/navmesh.js +1437 -0
  66. package/dist/cjs/networked-client.js +691 -0
  67. package/dist/cjs/networked-input-authority.js +443 -0
  68. package/dist/cjs/node.js +47 -0
  69. package/dist/cjs/number-lab.js +78 -0
  70. package/dist/cjs/offline-session.js +370 -0
  71. package/dist/cjs/package.json +1 -0
  72. package/dist/cjs/pause-resume.js +43 -0
  73. package/dist/cjs/physics-cert.js +426 -0
  74. package/dist/cjs/physics2d.js +751 -0
  75. package/dist/cjs/physics3d.js +1996 -0
  76. package/dist/cjs/prediction-culling.js +203 -0
  77. package/dist/cjs/protocol-lab.js +1299 -0
  78. package/dist/cjs/r3f-render-adapter.js +209 -0
  79. package/dist/cjs/random.js +59 -0
  80. package/dist/cjs/replay-bundle.js +1598 -0
  81. package/dist/cjs/replay-inspect.js +236 -0
  82. package/dist/cjs/replay-scoring.js +68 -0
  83. package/dist/cjs/replay.js +356 -0
  84. package/dist/cjs/reports.js +181 -0
  85. package/dist/cjs/rollback-history.js +251 -0
  86. package/dist/cjs/runtime-guards.js +111 -0
  87. package/dist/cjs/sample-lab.js +145 -0
  88. package/dist/cjs/sample-scenes.js +752 -0
  89. package/dist/cjs/schema-artifacts.js +359 -0
  90. package/dist/cjs/schema-codegen.js +544 -0
  91. package/dist/cjs/schema-dsl-binary.js +655 -0
  92. package/dist/cjs/schema.js +319 -0
  93. package/dist/cjs/sdk-offline.js +99 -0
  94. package/dist/cjs/session-promotion.js +74 -0
  95. package/dist/cjs/session-snapshot.js +265 -0
  96. package/dist/cjs/session-wire.js +216 -0
  97. package/dist/cjs/signals.js +103 -0
  98. package/dist/cjs/sparse-set.js +169 -0
  99. package/dist/cjs/synctest.js +136 -0
  100. package/dist/cjs/system-lifecycle.js +286 -0
  101. package/dist/cjs/timers.js +61 -0
  102. package/dist/cjs/tools/static-checker.js +1468 -0
  103. package/dist/cjs/types.js +2 -0
  104. package/dist/cjs/venus-mp-budget.js +125 -0
  105. package/dist/cjs/ws-frame.js +255 -0
  106. package/dist/cli.d.ts +2 -0
  107. package/dist/cli.js +11379 -0
  108. package/dist/collections.d.ts +9 -0
  109. package/dist/collections.js +30 -0
  110. package/dist/collision.d.ts +25 -0
  111. package/dist/collision.js +85 -0
  112. package/dist/commands.d.ts +137 -0
  113. package/dist/commands.js +977 -0
  114. package/dist/config-bundle.d.ts +89 -0
  115. package/dist/config-bundle.js +483 -0
  116. package/dist/creator.d.ts +20 -0
  117. package/dist/creator.js +11 -0
  118. package/dist/deterministic-primitives.d.ts +59 -0
  119. package/dist/deterministic-primitives.js +126 -0
  120. package/dist/deterministic-session.d.ts +197 -0
  121. package/dist/deterministic-session.js +1401 -0
  122. package/dist/ecs-lite.d.ts +26 -0
  123. package/dist/ecs-lite.js +152 -0
  124. package/dist/effects-adapter.d.ts +21 -0
  125. package/dist/effects-adapter.js +94 -0
  126. package/dist/engine-complete.d.ts +45 -0
  127. package/dist/engine-complete.js +2292 -0
  128. package/dist/engine-core-proof.d.ts +26 -0
  129. package/dist/engine-core-proof.js +66 -0
  130. package/dist/engine-parity-matrix.d.ts +300 -0
  131. package/dist/engine-parity-matrix.js +869 -0
  132. package/dist/engine-parity.d.ts +74 -0
  133. package/dist/engine-parity.js +3178 -0
  134. package/dist/engine-runtime.d.ts +351 -0
  135. package/dist/engine-runtime.js +3123 -0
  136. package/dist/errors.d.ts +11 -0
  137. package/dist/errors.js +17 -0
  138. package/dist/events.d.ts +45 -0
  139. package/dist/events.js +242 -0
  140. package/dist/examples/counter-duel.d.ts +43 -0
  141. package/dist/examples/counter-duel.js +150 -0
  142. package/dist/examples/fixed-arena.d.ts +110 -0
  143. package/dist/examples/fixed-arena.js +356 -0
  144. package/dist/index.d.ts +101 -0
  145. package/dist/index.js +66 -0
  146. package/dist/input-authority.d.ts +82 -0
  147. package/dist/input-authority.js +147 -0
  148. package/dist/input-button.d.ts +36 -0
  149. package/dist/input-button.js +249 -0
  150. package/dist/input-timeline.d.ts +65 -0
  151. package/dist/input-timeline.js +412 -0
  152. package/dist/instant-replay.d.ts +59 -0
  153. package/dist/instant-replay.js +62 -0
  154. package/dist/lag-compensation3d.d.ts +146 -0
  155. package/dist/lag-compensation3d.js +827 -0
  156. package/dist/local-authority-server-runner.d.ts +79 -0
  157. package/dist/local-authority-server-runner.js +1118 -0
  158. package/dist/local-authority-wire.d.ts +142 -0
  159. package/dist/local-authority-wire.js +1477 -0
  160. package/dist/local-authority.d.ts +160 -0
  161. package/dist/local-authority.js +810 -0
  162. package/dist/local-ws-adapter.d.ts +14 -0
  163. package/dist/local-ws-adapter.js +146 -0
  164. package/dist/match-log.d.ts +74 -0
  165. package/dist/match-log.js +57 -0
  166. package/dist/math.d.ts +41 -0
  167. package/dist/math.js +154 -0
  168. package/dist/mock-network-adapter.d.ts +13 -0
  169. package/dist/mock-network-adapter.js +23 -0
  170. package/dist/movement.d.ts +155 -0
  171. package/dist/movement.js +694 -0
  172. package/dist/movement3d.d.ts +195 -0
  173. package/dist/movement3d.js +1238 -0
  174. package/dist/multiclient-authority.d.ts +30 -0
  175. package/dist/multiclient-authority.js +305 -0
  176. package/dist/multiplayer-service.d.ts +153 -0
  177. package/dist/multiplayer-service.js +429 -0
  178. package/dist/navigation.d.ts +91 -0
  179. package/dist/navigation.js +338 -0
  180. package/dist/navmesh.d.ts +236 -0
  181. package/dist/navmesh.js +1423 -0
  182. package/dist/networked-client.d.ts +124 -0
  183. package/dist/networked-client.js +688 -0
  184. package/dist/networked-input-authority.d.ts +51 -0
  185. package/dist/networked-input-authority.js +439 -0
  186. package/dist/node.d.ts +22 -0
  187. package/dist/node.js +19 -0
  188. package/dist/number-lab.d.ts +15 -0
  189. package/dist/number-lab.js +75 -0
  190. package/dist/offline-session.d.ts +2 -0
  191. package/dist/offline-session.js +367 -0
  192. package/dist/pause-resume.d.ts +48 -0
  193. package/dist/pause-resume.js +40 -0
  194. package/dist/physics-cert.d.ts +40 -0
  195. package/dist/physics-cert.js +389 -0
  196. package/dist/physics2d.d.ts +142 -0
  197. package/dist/physics2d.js +741 -0
  198. package/dist/physics3d.d.ts +285 -0
  199. package/dist/physics3d.js +1979 -0
  200. package/dist/prediction-culling.d.ts +34 -0
  201. package/dist/prediction-culling.js +200 -0
  202. package/dist/protocol-lab.d.ts +115 -0
  203. package/dist/protocol-lab.js +1295 -0
  204. package/dist/r3f-render-adapter.d.ts +61 -0
  205. package/dist/r3f-render-adapter.js +203 -0
  206. package/dist/random.d.ts +13 -0
  207. package/dist/random.js +55 -0
  208. package/dist/replay-bundle.d.ts +150 -0
  209. package/dist/replay-bundle.js +1586 -0
  210. package/dist/replay-inspect.d.ts +60 -0
  211. package/dist/replay-inspect.js +228 -0
  212. package/dist/replay-scoring.d.ts +28 -0
  213. package/dist/replay-scoring.js +65 -0
  214. package/dist/replay.d.ts +17 -0
  215. package/dist/replay.js +351 -0
  216. package/dist/reports.d.ts +176 -0
  217. package/dist/reports.js +174 -0
  218. package/dist/rollback-history.d.ts +46 -0
  219. package/dist/rollback-history.js +247 -0
  220. package/dist/runtime-guards.d.ts +1 -0
  221. package/dist/runtime-guards.js +108 -0
  222. package/dist/sample-lab.d.ts +32 -0
  223. package/dist/sample-lab.js +134 -0
  224. package/dist/sample-scenes.d.ts +86 -0
  225. package/dist/sample-scenes.js +745 -0
  226. package/dist/schema-artifacts.d.ts +49 -0
  227. package/dist/schema-artifacts.js +356 -0
  228. package/dist/schema-codegen.d.ts +21 -0
  229. package/dist/schema-codegen.js +538 -0
  230. package/dist/schema-dsl-binary.d.ts +75 -0
  231. package/dist/schema-dsl-binary.js +648 -0
  232. package/dist/schema.d.ts +87 -0
  233. package/dist/schema.js +315 -0
  234. package/dist/sdk-offline.d.ts +34 -0
  235. package/dist/sdk-offline.js +96 -0
  236. package/dist/session-promotion.d.ts +26 -0
  237. package/dist/session-promotion.js +70 -0
  238. package/dist/session-snapshot.d.ts +95 -0
  239. package/dist/session-snapshot.js +255 -0
  240. package/dist/session-wire.d.ts +89 -0
  241. package/dist/session-wire.js +211 -0
  242. package/dist/signals.d.ts +31 -0
  243. package/dist/signals.js +99 -0
  244. package/dist/sparse-set.d.ts +34 -0
  245. package/dist/sparse-set.js +165 -0
  246. package/dist/synctest.d.ts +31 -0
  247. package/dist/synctest.js +133 -0
  248. package/dist/system-lifecycle.d.ts +72 -0
  249. package/dist/system-lifecycle.js +281 -0
  250. package/dist/timers.d.ts +17 -0
  251. package/dist/timers.js +53 -0
  252. package/dist/tools/index.d.ts +4 -0
  253. package/dist/tools/index.js +4 -0
  254. package/dist/tools/static-checker.d.ts +31 -0
  255. package/dist/tools/static-checker.js +1462 -0
  256. package/dist/tools/vite-plugin.d.ts +69 -0
  257. package/dist/tools/vite-plugin.js +203 -0
  258. package/dist/types.d.ts +148 -0
  259. package/dist/types.js +1 -0
  260. package/dist/venus-mp-budget.d.ts +29 -0
  261. package/dist/venus-mp-budget.js +122 -0
  262. package/dist/ws-frame.d.ts +49 -0
  263. package/dist/ws-frame.js +247 -0
  264. package/package.json +169 -0
@@ -0,0 +1,2297 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runDeterministicEngineCompleteSuite = runDeterministicEngineCompleteSuite;
4
+ exports.stableDeterministicEngineCompleteJson = stableDeterministicEngineCompleteJson;
5
+ exports.engineCompleteExecutionProofHash = engineCompleteExecutionProofHash;
6
+ const node_fs_1 = require("node:fs");
7
+ const node_path_1 = require("node:path");
8
+ const canonical_js_1 = require("./canonical.js");
9
+ const animation_js_1 = require("./animation.js");
10
+ const bot_documents_js_1 = require("./bot-documents.js");
11
+ const asset_cooking_js_1 = require("./asset-cooking.js");
12
+ const commands_js_1 = require("./commands.js");
13
+ const config_bundle_js_1 = require("./config-bundle.js");
14
+ const deterministic_session_js_1 = require("./deterministic-session.js");
15
+ const engine_runtime_js_1 = require("./engine-runtime.js");
16
+ const events_js_1 = require("./events.js");
17
+ const lag_compensation3d_js_1 = require("./lag-compensation3d.js");
18
+ const schema_dsl_binary_js_1 = require("./schema-dsl-binary.js");
19
+ const input_button_js_1 = require("./input-button.js");
20
+ const local_authority_js_1 = require("./local-authority.js");
21
+ const local_authority_wire_js_1 = require("./local-authority-wire.js");
22
+ const multiclient_authority_js_1 = require("./multiclient-authority.js");
23
+ const movement3d_js_1 = require("./movement3d.js");
24
+ const navmesh_js_1 = require("./navmesh.js");
25
+ const physics3d_js_1 = require("./physics3d.js");
26
+ const signals_js_1 = require("./signals.js");
27
+ const sparse_set_js_1 = require("./sparse-set.js");
28
+ const system_lifecycle_js_1 = require("./system-lifecycle.js");
29
+ const rollback_history_js_1 = require("./rollback-history.js");
30
+ const replay_bundle_js_1 = require("./replay-bundle.js");
31
+ const sample_scenes_js_1 = require("./sample-scenes.js");
32
+ const schema_js_1 = require("./schema.js");
33
+ const static_checker_js_1 = require("./tools/static-checker.js");
34
+ const requiredCategories = [
35
+ 'typed-frame-runtime',
36
+ 'schema-dsl-binary',
37
+ 'sparse-set-storage',
38
+ 'input-button',
39
+ 'system-lifecycle',
40
+ 'event-keywords',
41
+ 'simulation-signals',
42
+ 'commands',
43
+ 'replay-bundle',
44
+ 'integrated-headless-scene',
45
+ 'project-runtime',
46
+ 'physics3d',
47
+ 'kcc3d',
48
+ 'navmesh',
49
+ 'bot-documents',
50
+ 'animation',
51
+ 'config-bundle',
52
+ 'local-authority',
53
+ 'deterministic-session',
54
+ ];
55
+ const engineCompleteWallClockBudgetMs = 16.67;
56
+ function runDeterministicEngineCompleteSuite(...args) {
57
+ const resolvedOptions = resolveEngineCompleteOptions(args[0]);
58
+ const players = resolvedOptions.players ?? 128;
59
+ const frames = resolvedOptions.frames ?? (resolvedOptions.benchmark === true ? 100_000 : 5_000);
60
+ const seed = resolvedOptions.seed ?? 71;
61
+ const selectedCategories = filterEngineCompleteCategories(resolvedOptions.filter);
62
+ const categoryReports = selectedCategories.map((category) => runCategory(category, players, frames, seed, resolvedOptions));
63
+ const failures = categoryReports.flatMap((category) => category.failures.map((failure) => `${category.category}: ${failure}`));
64
+ const withoutId = {
65
+ schemaVersion: 1,
66
+ reportId: '',
67
+ players,
68
+ frames,
69
+ seed,
70
+ benchmark: resolvedOptions.benchmark === true,
71
+ noFastStress: resolvedOptions.noFastStress === true,
72
+ enforceThresholds: resolvedOptions.enforceThresholds === true,
73
+ categories: categoryReports,
74
+ failures,
75
+ summary: {
76
+ passed: categoryReports.filter((category) => category.result === 'pass').length,
77
+ failed: categoryReports.filter((category) => category.result === 'fail').length,
78
+ requiredCategories: selectedCategories,
79
+ },
80
+ result: failures.length === 0 ? 'pass' : 'fail',
81
+ };
82
+ return {
83
+ ...withoutId,
84
+ reportId: (0, canonical_js_1.defaultChecksum)(withoutId),
85
+ };
86
+ }
87
+ function resolveEngineCompleteOptions(options) {
88
+ /* istanbul ignore else -- No-arg compatibility runs the full default certification suite. Filtered default-value coverage above exercises the same defaults without making the source shard run the 5,000-frame all-category path twice. */
89
+ if (options !== undefined) {
90
+ return options;
91
+ }
92
+ /* istanbul ignore next -- No-arg compatibility runs the full default certification suite, which is intentionally not duplicated inside this focused source shard. */
93
+ return {};
94
+ }
95
+ function filterEngineCompleteCategories(filter) {
96
+ if (filter === undefined || filter.length === 0) {
97
+ return requiredCategories;
98
+ }
99
+ const categories = requiredCategories.filter((category) => category === filter || category.includes(filter));
100
+ if (categories.length === 0) {
101
+ throw new Error(`No engine-complete categories matched --filter ${filter}`);
102
+ }
103
+ return categories;
104
+ }
105
+ function stableDeterministicEngineCompleteJson(report) {
106
+ return `${(0, canonical_js_1.canonicalStringify)(report)}\n`;
107
+ }
108
+ function runCategory(category, players, frames, seed, options) {
109
+ const startedAtMs = engineCompleteNowMs();
110
+ const report = runCategoryUntimed(category, players, frames, seed, options);
111
+ return withCertificationTiming(report, engineCompleteNowMs() - startedAtMs, options.enforceThresholds === true);
112
+ }
113
+ function runCategoryUntimed(category, players, frames, seed, options) {
114
+ switch (category) {
115
+ case 'typed-frame-runtime':
116
+ return runtimeCategory(frames, seed);
117
+ case 'schema-dsl-binary':
118
+ return schemaDslBinaryCategory();
119
+ case 'sparse-set-storage':
120
+ return sparseSetCategory();
121
+ case 'input-button':
122
+ return inputButtonCategory();
123
+ case 'system-lifecycle':
124
+ return systemLifecycleCategory();
125
+ case 'event-keywords':
126
+ return eventKeywordsCategory();
127
+ case 'simulation-signals':
128
+ return simulationSignalsCategory();
129
+ case 'commands':
130
+ return commandsCategory(players, frames, seed);
131
+ case 'replay-bundle':
132
+ return replayBundleCategory(players, frames, options.benchmark === true ? Math.min(frames, 5_000) : frames);
133
+ case 'integrated-headless-scene':
134
+ return integratedHeadlessSceneCategory(players, frames, options.benchmark === true ? Math.min(frames, 5_000) : frames, seed);
135
+ case 'project-runtime':
136
+ return projectRuntimeCategory(frames, options.benchmark === true ? Math.min(frames, 5_000) : frames, seed);
137
+ case 'physics3d':
138
+ return physicsCategory(options.benchmark === true ? 128 : 512, frames, options.benchmark === true ? frames : Math.min(frames, 5000), options.enforceThresholds === true, options.benchmark === true, options.noFastStress === true);
139
+ case 'kcc3d':
140
+ return kccCategory(players, frames, options.benchmark === true ? frames : Math.min(frames, 5000), options.benchmark === true, options.noFastStress === true);
141
+ case 'navmesh':
142
+ return navmeshCategory(players, frames, options.benchmark === true ? frames : Math.min(frames, 5000));
143
+ case 'bot-documents':
144
+ return botCategory(players, frames, options.benchmark === true ? frames : Math.min(frames, 5000));
145
+ case 'animation':
146
+ return animationCategory(frames, options.benchmark === true ? frames : Math.min(frames, 5000));
147
+ case 'config-bundle':
148
+ return configCategory();
149
+ case 'local-authority':
150
+ return authorityCategory(players, frames, options.benchmark === true ? frames : Math.min(frames, 5000), seed);
151
+ case 'deterministic-session':
152
+ return deterministicSessionCategory(players, frames, options.benchmark === true ? frames : Math.min(frames, 5000), seed);
153
+ }
154
+ }
155
+ function withCertificationTiming(report, elapsedMs, enforceThresholds) {
156
+ const executedFrames = Number(report.metrics.executedFrames);
157
+ const wallClockElapsedMs = roundMetric(Math.max(0, elapsedMs), 4);
158
+ const wallClockMeanFrameMs = roundMetric(wallClockElapsedMs / Math.max(1, executedFrames), 6);
159
+ return categoryReport(report.category, subsystemChecksumOf(report), {
160
+ ...report.invariants,
161
+ wallClockMeasured: Number.isFinite(wallClockElapsedMs),
162
+ wallClockMeanWithinThreshold: enforceThresholds ? wallClockMeanFrameMs <= engineCompleteWallClockBudgetMs : 'not-enforced',
163
+ }, {
164
+ ...report.metrics,
165
+ wallClockElapsedMs,
166
+ wallClockMeanFrameMs,
167
+ wallClockBudgetMs: engineCompleteWallClockBudgetMs,
168
+ wallClockThresholdsEnforced: enforceThresholds,
169
+ });
170
+ }
171
+ function runtimeCategory(frames, seed) {
172
+ const executedFrames = Math.max(10_000, frames);
173
+ const metrics = (0, engine_runtime_js_1.runDeterministicFrameRuntimeMutationCorpus)(executedFrames, seed);
174
+ const frameApi = (0, engine_runtime_js_1.runDeterministicFrameRuntimeFrameApiFixture)(Math.max(512, Math.min(executedFrames, 10_000)), seed + 2);
175
+ const generated = (0, engine_runtime_js_1.runDeterministicGeneratedRuntimeFixture)(Math.max(256, Math.min(executedFrames, 10_000)), seed + 1);
176
+ const scheduler = (0, engine_runtime_js_1.runDeterministicSystemSchedulerFixture)(seed + 3);
177
+ return categoryReport('typed-frame-runtime', (0, canonical_js_1.defaultChecksum)({
178
+ metrics: metrics.checksum,
179
+ frameApi: frameApi.checksum,
180
+ scheduler: scheduler.checksum,
181
+ }), {
182
+ rollbackEquivalent: metrics.checksum === metrics.restoredChecksum,
183
+ queryOrderStable: metrics.queryOrderStable,
184
+ mutationCorpusComplete: metrics.componentWrites >= 10_000,
185
+ queryFilterAnyWithoutCovered: frameApi.filterAnyWithoutStable,
186
+ componentCountCovered: frameApi.componentCountStable,
187
+ frameHeapCollectionsCovered: frameApi.frameHeapHandlesAllocated >= 3 && frameApi.frameHeapSnapshotBytes > 0,
188
+ frameHeapRollbackEquivalent: frameApi.frameHeapRollbackEquivalent,
189
+ frameHeapFreeRejectsStaleHandles: frameApi.frameHeapFreedRejected,
190
+ frameHeapReuseGenerationSafe: frameApi.frameHeapReusedGenerationSafe,
191
+ generatedAccessorsCovered: generated.generatedAccessorsExecuted > 0 && generated.generatedSourceBytes > 0,
192
+ generatedRuntimeSourceStable: generated.generatedSourceHash.length > 0 && generated.descriptorHash.length > 0,
193
+ sparseSetBackedRuntimeEquivalent: generated.sparseSetBackedRuntimeEquivalent,
194
+ sparseSetBackedRollbackEquivalent: generated.rollbackEquivalent,
195
+ accessorQueryOrderStable: generated.accessorQueryOrderStable,
196
+ entityRefGenerationSafe: generated.entityRefGenerationSafe,
197
+ runtimeHostApiGuarded: generated.runtimeHostApiGuarded,
198
+ systemDependenciesCovered: scheduler.order === 'PAFPAF' && scheduler.beforeEdges > 0 && scheduler.afterEdges > 0,
199
+ systemDependencyRollbackEquivalent: scheduler.rollbackEquivalent,
200
+ systemDependencySparseEquivalent: scheduler.sparseEquivalent,
201
+ systemDependencyCycleRejected: scheduler.cycleRejected,
202
+ systemDependencyUnknownRejected: scheduler.unknownDependencyRejected,
203
+ systemDependencyCrossGroupRejected: scheduler.crossGroupDependencyRejected,
204
+ }, withFrameMetrics({
205
+ ...metrics,
206
+ generatedRuntimeChecksum: generated.checksum,
207
+ frameApiChecksum: frameApi.checksum,
208
+ frameApiRestoredChecksum: frameApi.restoredChecksum,
209
+ frameApiFilterAnyWithoutStable: frameApi.filterAnyWithoutStable,
210
+ frameApiComponentCountStable: frameApi.componentCountStable,
211
+ frameHeapHandlesAllocated: frameApi.frameHeapHandlesAllocated,
212
+ frameHeapFreedRejected: frameApi.frameHeapFreedRejected,
213
+ frameHeapReusedGenerationSafe: frameApi.frameHeapReusedGenerationSafe,
214
+ frameHeapSnapshotBytes: frameApi.frameHeapSnapshotBytes,
215
+ generatedSourceHash: generated.generatedSourceHash,
216
+ generatedSourceBytes: generated.generatedSourceBytes,
217
+ generatedAccessorsExecuted: generated.generatedAccessorsExecuted,
218
+ sparseMapRuntimeChecksum: generated.mapRuntimeChecksum,
219
+ sparseRuntimeChecksum: generated.sparseRuntimeChecksum,
220
+ sparseSnapshotBytes: generated.sparseSnapshotBytes,
221
+ entityRefGenerationSafe: generated.entityRefGenerationSafe,
222
+ runtimeHostApiGuarded: generated.runtimeHostApiGuarded,
223
+ schedulerChecksum: scheduler.checksum,
224
+ schedulerRestoredChecksum: scheduler.restoredChecksum,
225
+ schedulerSparseChecksum: scheduler.sparseChecksum,
226
+ schedulerOrder: scheduler.order,
227
+ schedulerBeforeEdges: scheduler.beforeEdges,
228
+ schedulerAfterEdges: scheduler.afterEdges,
229
+ schedulerRollbackEquivalent: scheduler.rollbackEquivalent,
230
+ schedulerSparseEquivalent: scheduler.sparseEquivalent,
231
+ schedulerCycleRejected: scheduler.cycleRejected,
232
+ schedulerUnknownDependencyRejected: scheduler.unknownDependencyRejected,
233
+ schedulerCrossGroupDependencyRejected: scheduler.crossGroupDependencyRejected,
234
+ }, frames, executedFrames));
235
+ }
236
+ function schemaDslBinaryCategory() {
237
+ const metrics = (0, schema_dsl_binary_js_1.runDeterministicDslBinaryFixture)();
238
+ const runtimeFrames = 256;
239
+ const runtime = (0, engine_runtime_js_1.runDeterministicDslRuntimeFixture)(runtimeFrames);
240
+ return categoryReport('schema-dsl-binary', (0, canonical_js_1.defaultChecksum)({ binary: metrics.roundTripChecksum, runtime: runtime.checksum }), {
241
+ schemaPermutationStable: metrics.permutationStable,
242
+ binaryRoundTripExecuted: metrics.encodedBytes > 0,
243
+ rejectsBadDslValues: metrics.rejectedBadField
244
+ && metrics.rejectedExtraField
245
+ && metrics.rejectedBadDeclaration
246
+ && metrics.rejectedDuplicateSetValue
247
+ && metrics.rejectedDuplicateDictionaryKey,
248
+ eventSignalStructDslCovered: metrics.eventDeclarations > 0 && metrics.signalDeclarations > 0 && metrics.structDeclarations > 0,
249
+ globalImportPragmaDslCovered: metrics.globalDeclarations > 0 && metrics.importCount > 0 && metrics.pragmaCount > 0 && metrics.maxPlayers === 128,
250
+ assetAndEntityRefsCovered: metrics.assetRefFields > 0 && metrics.entityRefFields > 0,
251
+ arrayFieldsCovered: metrics.arrayFields > 0,
252
+ fixedArrayFieldsCovered: metrics.fixedArrayFields > 0,
253
+ dynamicCollectionFieldsCovered: metrics.listFields > 0 && metrics.setFields > 0 && metrics.dictionaryFields > 0,
254
+ buttonFieldsCovered: metrics.buttonFields > 0,
255
+ advancedDslDeclarationsCovered: metrics.enumDeclarations > 0 && metrics.flagsDeclarations > 0 && metrics.unionDeclarations > 0,
256
+ advancedDslRefsCovered: metrics.playerRefFields > 0 && metrics.typedAssetRefFields > 0,
257
+ advancedDslBitsetCovered: metrics.bitsetFields > 0,
258
+ advancedDslModifiersCovered: metrics.declarationModifiers > 0,
259
+ advancedDslHashSetAliasCovered: metrics.hashSetAliasFields > 0,
260
+ fixedArrayLengthRejected: metrics.rejectedWrongFixedArrayLength,
261
+ dslRuntimeDescriptorGenerated: runtime.componentCount > 0 && runtime.singletonCount > 1 && runtime.generatedSourceBytes > 0,
262
+ dslRuntimeCommandEventSignalGenerated: runtime.commandChannelCount > 0 && runtime.eventChannelCount > 0 && runtime.signalChannelCount > 0,
263
+ dslRuntimePermutationStable: runtime.descriptorPermutationStable,
264
+ dslRuntimeSparseEquivalent: runtime.sparseRuntimeEquivalent,
265
+ dslRuntimeRollbackEquivalent: runtime.rollbackEquivalent,
266
+ dslRuntimeRefsAndArraysCovered: runtime.arrayFieldCount > 0 && runtime.assetRefFieldCount > 0 && runtime.entityRefFieldCount > 0,
267
+ dslRuntimeFixedArraysCovered: runtime.fixedArrayFieldCount > 0,
268
+ dslRuntimeDynamicCollectionHandlesCovered: runtime.dynamicCollectionHandleFieldCount >= 3,
269
+ dslRuntimeFrameApiHelpersCovered: runtime.generatedFrameApiHelpersExecuted > 0,
270
+ dslRuntimeEventSignalAccessorsExecuted: runtime.generatedEventSignalAccessorsExecuted > 0,
271
+ dslRuntimeTypedInterfacesCovered: runtime.generatedTypedInterfacesCovered,
272
+ dslRuntimeAssetRefsValidated: runtime.runtimeAssetRefsValidated,
273
+ }, {
274
+ ...metrics,
275
+ fieldKinds: metrics.fieldKinds.join(','),
276
+ dslRuntimeChecksum: runtime.checksum,
277
+ dslRuntimeDescriptorHash: runtime.descriptorHash,
278
+ dslRuntimePermutedDescriptorHash: runtime.permutedDescriptorHash,
279
+ dslRuntimeGeneratedSourceHash: runtime.generatedSourceHash,
280
+ dslRuntimeGeneratedSourceBytes: runtime.generatedSourceBytes,
281
+ dslRuntimeComponentCount: runtime.componentCount,
282
+ dslRuntimeSingletonCount: runtime.singletonCount,
283
+ dslRuntimeCommandChannelCount: runtime.commandChannelCount,
284
+ dslRuntimeEventChannelCount: runtime.eventChannelCount,
285
+ dslRuntimeSignalChannelCount: runtime.signalChannelCount,
286
+ dslRuntimeArrayFieldCount: runtime.arrayFieldCount,
287
+ dslRuntimeFixedArrayFieldCount: runtime.fixedArrayFieldCount,
288
+ dslRuntimeDynamicCollectionHandleFieldCount: runtime.dynamicCollectionHandleFieldCount,
289
+ dslRuntimeAssetRefFieldCount: runtime.assetRefFieldCount,
290
+ dslRuntimeEntityRefFieldCount: runtime.entityRefFieldCount,
291
+ dslGlobalDeclarations: metrics.globalDeclarations,
292
+ dslImportCount: metrics.importCount,
293
+ dslPragmaCount: metrics.pragmaCount,
294
+ dslMaxPlayers: metrics.maxPlayers,
295
+ dslListFields: metrics.listFields,
296
+ dslFixedArrayFields: metrics.fixedArrayFields,
297
+ dslSetFields: metrics.setFields,
298
+ dslDictionaryFields: metrics.dictionaryFields,
299
+ dslEnumDeclarations: metrics.enumDeclarations,
300
+ dslFlagsDeclarations: metrics.flagsDeclarations,
301
+ dslUnionDeclarations: metrics.unionDeclarations,
302
+ dslPlayerRefFields: metrics.playerRefFields,
303
+ dslTypedAssetRefFields: metrics.typedAssetRefFields,
304
+ dslBitsetFields: metrics.bitsetFields,
305
+ dslDeclarationModifiers: metrics.declarationModifiers,
306
+ dslHashSetAliasFields: metrics.hashSetAliasFields,
307
+ dslRejectedWrongFixedArrayLength: metrics.rejectedWrongFixedArrayLength,
308
+ dslRejectedDuplicateSetValue: metrics.rejectedDuplicateSetValue,
309
+ dslRejectedDuplicateDictionaryKey: metrics.rejectedDuplicateDictionaryKey,
310
+ dslRuntimeGeneratedAccessorsExecuted: runtime.generatedAccessorsExecuted,
311
+ dslRuntimeGeneratedFrameApiHelpersExecuted: runtime.generatedFrameApiHelpersExecuted,
312
+ dslRuntimeGeneratedEventSignalAccessorsExecuted: runtime.generatedEventSignalAccessorsExecuted,
313
+ dslRuntimeGeneratedTypedInterfacesCovered: runtime.generatedTypedInterfacesCovered,
314
+ dslRuntimeAssetRefsValidated: runtime.runtimeAssetRefsValidated,
315
+ dslRuntimeSparseRuntimeEquivalent: runtime.sparseRuntimeEquivalent,
316
+ dslRuntimeRollbackEquivalent: runtime.rollbackEquivalent,
317
+ proofContract: 'schema-dsl-binary@1',
318
+ subsystemChecksum: metrics.roundTripChecksum,
319
+ requestedFrames: runtimeFrames,
320
+ executedFrames: runtimeFrames,
321
+ capped: false,
322
+ });
323
+ }
324
+ function sparseSetCategory() {
325
+ const metrics = (0, sparse_set_js_1.runDeterministicSparseSetFixture)();
326
+ return categoryReport('sparse-set-storage', metrics.checksum, {
327
+ rollbackEquivalent: metrics.checksum === metrics.restoredChecksum,
328
+ queryOrderStable: metrics.queryOrderStable,
329
+ duplicateRejected: metrics.rejectedDuplicate,
330
+ malformedSnapshotRejected: metrics.rejectedMalformedSnapshot,
331
+ denseStorageExercised: metrics.denseCount > 0,
332
+ }, {
333
+ ...metrics,
334
+ proofContract: 'sparse-set-storage@1',
335
+ subsystemChecksum: metrics.checksum,
336
+ requestedFrames: 1,
337
+ executedFrames: 1,
338
+ capped: false,
339
+ });
340
+ }
341
+ function inputButtonCategory() {
342
+ const metrics = (0, input_button_js_1.runDeterministicButtonFixture)();
343
+ const descriptor = (0, input_button_js_1.runDeterministicDescriptorButtonFixture)();
344
+ return categoryReport('input-button', metrics.checksum, {
345
+ rollbackEquivalent: metrics.rollbackEquivalent,
346
+ pressedCovered: metrics.pressedCount > 0,
347
+ releasedCovered: metrics.releasedCount > 0,
348
+ heldCovered: metrics.heldFrames > 0,
349
+ repeatCovered: metrics.repeatedFrames > 0,
350
+ transitionsStable: metrics.transitionsStable,
351
+ descriptorRollbackEquivalent: descriptor.rollbackEquivalent,
352
+ descriptorButtonFieldsCovered: descriptor.descriptorButtonFields > 0,
353
+ descriptorDefaultApplied: descriptor.defaultApplied,
354
+ descriptorSerializationCovered: descriptor.serializedBytes > 0,
355
+ descriptorRoundTripStable: descriptor.schemaRoundTripStable,
356
+ }, withFrameMetrics({
357
+ ...metrics,
358
+ descriptorChecksum: descriptor.checksum,
359
+ descriptorRestoredChecksum: descriptor.restoredChecksum,
360
+ descriptorArtifactId: descriptor.descriptorArtifactId,
361
+ descriptorButtonFields: descriptor.descriptorButtonFields,
362
+ descriptorSerializedBytes: descriptor.serializedBytes,
363
+ descriptorDefaultApplied: descriptor.defaultApplied,
364
+ descriptorRoundTripStable: descriptor.schemaRoundTripStable,
365
+ }, 512, 512));
366
+ }
367
+ function systemLifecycleCategory() {
368
+ const metrics = (0, system_lifecycle_js_1.runDeterministicLifecycleFixture)();
369
+ return categoryReport('system-lifecycle', metrics.checksum, {
370
+ rollbackEquivalent: metrics.rollbackEquivalent,
371
+ initCovered: metrics.initCalls >= 4,
372
+ updatesCovered: metrics.updateCalls > 0,
373
+ enableDisableCovered: metrics.enabledCalls > 0 && metrics.disabledCalls > 0,
374
+ signalDispatchCovered: metrics.signalCalls > 0,
375
+ hierarchyCovered: metrics.hierarchySkippedUpdates > 0,
376
+ startDisabledCovered: metrics.startDisabledCovered,
377
+ signalsOnlyCovered: metrics.signalOnlySkippedUpdate,
378
+ orderStable: metrics.orderStable,
379
+ }, withFrameMetrics({
380
+ ...metrics,
381
+ }, 128, 128));
382
+ }
383
+ function eventKeywordsCategory() {
384
+ const metrics = (0, events_js_1.runDeterministicEventKeywordFixture)();
385
+ return categoryReport('event-keywords', metrics.checksum, {
386
+ rollbackEquivalent: metrics.rollbackEquivalent,
387
+ syncedCovered: metrics.syncedEvents > 0,
388
+ predictedConfirmCovered: metrics.confirmedEvents > 0,
389
+ predictedCancelCovered: metrics.canceledEvents > 0,
390
+ verifiedOnlyCovered: metrics.verifiedOnlyEvents > 0,
391
+ notHashedDuplicateRejected: metrics.notHashedDuplicateRejected,
392
+ notHashedDedupeStable: metrics.notHashedDedupeStable,
393
+ syncedSurvivedConfirmCancel: metrics.syncedSurvivedConfirmCancel,
394
+ localRemoteScopeCovered: metrics.localEvents > 0 && metrics.remoteEvents > 0 && metrics.localRemoteDispatchStable,
395
+ }, withFrameMetrics({
396
+ ...metrics,
397
+ }, 1, 1));
398
+ }
399
+ function simulationSignalsCategory() {
400
+ const metrics = (0, signals_js_1.runDeterministicSignalFixture)();
401
+ return categoryReport('simulation-signals', metrics.checksum, {
402
+ rollbackEquivalent: metrics.rollbackEquivalent,
403
+ subscriptionOrderStable: metrics.subscriptionOrderStable,
404
+ dispatchedSignals: metrics.dispatchedSignals >= 2,
405
+ }, {
406
+ ...metrics,
407
+ proofContract: 'simulation-signals@1',
408
+ subsystemChecksum: metrics.checksum,
409
+ requestedFrames: 1,
410
+ executedFrames: 1,
411
+ capped: false,
412
+ });
413
+ }
414
+ function commandsCategory(players, frames, seed) {
415
+ const metrics = (0, commands_js_1.runDeterministicCommandProtocolFixture)(players, frames, seed);
416
+ const reliableDefaults = (0, commands_js_1.runDeterministicReliableCommandDefaultsFixture)(players, frames, seed);
417
+ return categoryReport('commands', (0, canonical_js_1.defaultChecksum)({ commandProtocol: metrics.checksum, reliableDefaults: reliableDefaults.checksum }), {
418
+ commandReplayConverges: metrics.convergence,
419
+ rejectsHostileCommands: metrics.rejected >= 9,
420
+ duplicateCommandsRejected: metrics.duplicateDrops > 0,
421
+ multiCommandSameFrameCovered: metrics.multiCommandSameFrameAccepted >= 2 && metrics.multiCommandPollOrderStable,
422
+ acceptedFutureCommandsReplay: metrics.acceptedFutureCommands > 0 && metrics.acceptedFutureCommands === metrics.replayedFutureCommands,
423
+ reliableCommandsResentAndOrdered: metrics.reliableDelivered > 0 && metrics.reliableResent > 0 && metrics.reliableOrderingStable,
424
+ reliableDefaultCommandsCovered: reliableDefaults.accepted > 0
425
+ && reliableDefaults.reliableDelivered === reliableDefaults.accepted
426
+ && reliableDefaults.unreliableDropped === 0
427
+ && reliableDefaults.replayConverged
428
+ && reliableDefaults.originalOrderHash === reliableDefaults.replayOrderHash,
429
+ reliableDefaultRejectionsCovered: reliableDefaults.duplicateRejected === 1
430
+ && reliableDefaults.staleRejected === 1
431
+ && reliableDefaults.futureRejected === 1,
432
+ unreliableDropsModeled: metrics.unreliableDropped > 0,
433
+ deliveredCommandsSpanRun: metrics.firstDeliveredFrame === 0 && metrics.lastDeliveredFrame >= frames - 1,
434
+ schemaDeclaredCommandPayloadsCovered: metrics.schemaDeclaredPayloadsCovered,
435
+ schemaCommandCollectionPayloadsCovered: metrics.schemaCollectionPayloadsCovered,
436
+ schemaCommandPayloadsRejected: metrics.schemaRejected >= 4,
437
+ onlyExpectedRejections: metrics.rejected === metrics.duplicateDrops + 14,
438
+ }, withFrameMetrics({
439
+ delivered: metrics.delivered,
440
+ rejected: metrics.rejected,
441
+ duplicateDrops: metrics.duplicateDrops,
442
+ multiCommandSameFrameAccepted: metrics.multiCommandSameFrameAccepted,
443
+ multiCommandPollOrderStable: metrics.multiCommandPollOrderStable,
444
+ acceptedFutureCommands: metrics.acceptedFutureCommands,
445
+ replayedFutureCommands: metrics.replayedFutureCommands,
446
+ reliableDelivered: metrics.reliableDelivered,
447
+ reliableResent: metrics.reliableResent,
448
+ unreliableDropped: metrics.unreliableDropped,
449
+ reliableOrderingStable: metrics.reliableOrderingStable,
450
+ reliableDefaultAccepted: reliableDefaults.accepted,
451
+ reliableDefaultDelivered: reliableDefaults.reliableDelivered,
452
+ reliableDefaultResent: reliableDefaults.reliableResent,
453
+ reliableDefaultUnreliableDropped: reliableDefaults.unreliableDropped,
454
+ reliableDefaultDuplicateRejected: reliableDefaults.duplicateRejected,
455
+ reliableDefaultStaleRejected: reliableDefaults.staleRejected,
456
+ reliableDefaultFutureRejected: reliableDefaults.futureRejected,
457
+ reliableDefaultPollOrderStable: reliableDefaults.pollOrderStable,
458
+ reliableDefaultReplayConverged: reliableDefaults.replayConverged,
459
+ reliableDefaultOriginalOrderHash: reliableDefaults.originalOrderHash,
460
+ reliableDefaultReplayOrderHash: reliableDefaults.replayOrderHash,
461
+ firstDeliveredFrame: metrics.firstDeliveredFrame,
462
+ lastDeliveredFrame: metrics.lastDeliveredFrame,
463
+ delayP50Frames: metrics.delayP50Frames,
464
+ delayP95Frames: metrics.delayP95Frames,
465
+ rollbackDepthP95: metrics.rollbackDepthP95,
466
+ schemaRejected: metrics.schemaRejected,
467
+ schemaDeclaredPayloadsCovered: metrics.schemaDeclaredPayloadsCovered,
468
+ schemaCollectionPayloadsCovered: metrics.schemaCollectionPayloadsCovered,
469
+ convergence: metrics.convergence,
470
+ }, frames, frames));
471
+ }
472
+ function replayBundleCategory(players, requestedFrames, executedFrames) {
473
+ const positions = Array.from({ length: players }, () => 0);
474
+ const snapshotStates = [];
475
+ const inputHistory = [];
476
+ const commandHistory = [];
477
+ const debugEvents = [];
478
+ let commandScore = 0;
479
+ let simulationHashValue = 2166136261;
480
+ for (let frame = 0; frame < executedFrames; frame += 1) {
481
+ const inputs = Array.from({ length: players }, (_, slot) => ({
482
+ slot,
483
+ dx: (slot + frame) % 3 - 1,
484
+ dy: (slot * 2 + frame) % 3 - 1,
485
+ }));
486
+ for (const input of inputs) {
487
+ simulationHashValue = updateSimulationHashValue(simulationHashValue, frame);
488
+ simulationHashValue = updateSimulationHashValue(simulationHashValue, input.slot);
489
+ simulationHashValue = updateSimulationHashValue(simulationHashValue, input.dx);
490
+ simulationHashValue = updateSimulationHashValue(simulationHashValue, input.dy);
491
+ }
492
+ const commands = Array.from({ length: players }, (_, slot) => ({
493
+ id: `cmd:${frame}:${slot}`,
494
+ slot,
495
+ channelId: 'ability',
496
+ payload: { assetRef: 'ability.dash', power: (frame + slot) % 5 },
497
+ }));
498
+ for (const command of commands) {
499
+ simulationHashValue = updateSimulationHashValue(simulationHashValue, command.slot);
500
+ simulationHashValue = updateSimulationHashValue(simulationHashValue, command.payload.power);
501
+ }
502
+ for (const input of inputs) {
503
+ positions[input.slot] += input.dx + input.dy;
504
+ }
505
+ for (const command of commands) {
506
+ commandScore += command.payload.power;
507
+ }
508
+ inputHistory.push({ frame, inputs });
509
+ commandHistory.push({ frame, commands });
510
+ const state = {
511
+ frame,
512
+ positions: [...positions],
513
+ commandScore,
514
+ };
515
+ const bytes = (0, canonical_js_1.canonicalStringify)(state);
516
+ const snapshot = { frame, bytes, checksum: (0, canonical_js_1.defaultChecksum)(bytes) };
517
+ snapshotStates.push(snapshot);
518
+ debugEvents.push({ frame, type: 'ecs.snapshot', payload: { checksum: snapshot.checksum } }, { frame, type: 'physics.contacts', payload: { contacts: frame % 3 } }, { frame, type: 'command.poll', payload: { commands: players } });
519
+ }
520
+ const checksums = snapshotStates.map((snapshot) => ({ frame: snapshot.frame, checksum: snapshot.checksum }));
521
+ const bundle = (0, replay_bundle_js_1.createDeterministicReplayBundle)({
522
+ runtimeVersion: 'engine-complete@1',
523
+ engineHash: 'engine-hash',
524
+ schemaHash: 'schema-hash',
525
+ assetDbHash: 'asset-hash',
526
+ configHash: 'config-hash',
527
+ sampleId: 'engine-complete',
528
+ inputHistory,
529
+ commandHistory,
530
+ checksums,
531
+ debugEvents,
532
+ snapshots: snapshotStates.map((snapshot) => ({ frame: snapshot.frame, checksum: snapshot.checksum, bytes: snapshot.bytes })),
533
+ semanticReplay: {
534
+ kind: 'operation-model-v1',
535
+ initialState: {
536
+ positions: Array.from({ length: players }, () => 0),
537
+ commandScore: 0,
538
+ },
539
+ operations: [
540
+ { source: 'input', sourcePath: 'dx', targetPath: 'positions[$slot]', op: 'add', slotField: 'slot' },
541
+ { source: 'input', sourcePath: 'dy', targetPath: 'positions[$slot]', op: 'add', slotField: 'slot' },
542
+ { source: 'command.payload', sourcePath: 'power', targetPath: 'commandScore', op: 'add' },
543
+ ],
544
+ },
545
+ metadata: {
546
+ players,
547
+ fullReplayHistory: true,
548
+ requestedFrames,
549
+ executedFrames,
550
+ fullReplayCapped: executedFrames < requestedFrames,
551
+ },
552
+ });
553
+ const verification = (0, replay_bundle_js_1.verifyDeterministicReplayBundle)(bundle, {
554
+ runtimeVersion: 'engine-complete@1',
555
+ engineHash: 'engine-hash',
556
+ schemaHash: 'schema-hash',
557
+ assetDbHash: 'asset-hash',
558
+ configHash: 'config-hash',
559
+ semanticReplayHash: bundle.semanticReplayHash,
560
+ });
561
+ const componentVerification = (0, replay_bundle_js_1.verifyDeterministicReplayBundle)(createComponentReplayBundle());
562
+ const corrupted = (0, replay_bundle_js_1.createDeterministicReplayBundle)({
563
+ ...bundle,
564
+ checksums: bundle.checksums.map((checksum, index) => index === Math.min(3, bundle.checksums.length - 1) ? { ...checksum, checksum: 'corrupt' } : checksum),
565
+ });
566
+ const mismatch = (0, replay_bundle_js_1.minimizeDeterministicReplayDesync)(bundle, corrupted);
567
+ const minimization = (0, replay_bundle_js_1.minimizeDeterministicReplayDesyncBundle)(bundle, corrupted);
568
+ const minimized = minimization.bundle;
569
+ const minimizedVerification = minimization.verifier;
570
+ const sliceStartIndex = Math.min(1, Math.max(0, bundle.checksums.length - 1));
571
+ const sliceEndIndex = Math.min(4, Math.max(sliceStartIndex, bundle.checksums.length - 1));
572
+ const sliced = (0, replay_bundle_js_1.sliceDeterministicReplayBundle)(bundle, bundle.checksums[sliceStartIndex].frame, bundle.checksums[sliceEndIndex].frame);
573
+ const sliceVerification = (0, replay_bundle_js_1.verifyDeterministicReplayBundle)(sliced, {
574
+ runtimeVersion: 'engine-complete@1',
575
+ engineHash: 'engine-hash',
576
+ schemaHash: 'schema-hash',
577
+ assetDbHash: 'asset-hash',
578
+ configHash: 'config-hash',
579
+ semanticReplayHash: sliced.semanticReplayHash,
580
+ });
581
+ const frameRuntimeReplay = createFrameRuntimeReplayProof(executedFrames);
582
+ const debug = (0, replay_bundle_js_1.createDeterministicReplayDebugTables)(bundle.debugEvents);
583
+ return categoryReport('replay-bundle', verification.bundleHash, {
584
+ verifiesColdStart: verification.result === 'pass',
585
+ mismatchMinimized: mismatch.frame === bundle.checksums[Math.min(3, bundle.checksums.length - 1)].frame,
586
+ minimizedArtifactVerifierRunnable: minimizedVerification.result === 'fail',
587
+ minimizedArtifactReproducesMismatch: minimizedVerification.firstMismatch?.frame === mismatch.frame,
588
+ minimizedArtifactReducesBytes: minimization.minimizedReplayBytes < minimization.originalReplayBytes,
589
+ minimizedArtifactRemovesIrrelevantInputs: minimization.removedInputFrames > 0 && minimization.removedInputs > 0,
590
+ minimizedArtifactRemovesIrrelevantCommands: minimization.removedCommandFrames > 0 && minimization.removedCommands > 0,
591
+ minimizedArtifactRemovesIrrelevantDebugEvents: minimization.removedDebugEvents > 0,
592
+ sliceContainsChecksums: sliced.checksums.length === sliceEndIndex - sliceStartIndex + 1,
593
+ sliceSelfContained: sliced.metadata.selfContainedSlice === true && sliced.sliceOrigin !== undefined,
594
+ sliceVerifiesFromBaseline: sliceVerification.result === 'pass' && sliceVerification.semanticReplayExecuted,
595
+ sliceSourceIdentityPresent: sliced.sliceOrigin?.sourceBundleHash === verification.bundleHash,
596
+ inputHistoryPresent: verification.inputCount > 0,
597
+ commandHistoryPresent: verification.commandCount > 0,
598
+ allPlayersSampled: verification.inputCount === players * executedFrames && verification.commandCount === players * executedFrames,
599
+ semanticReplayExecuted: verification.semanticReplayExecuted,
600
+ semanticReplayFullHistoryVerified: verification.semanticReplayFrames === executedFrames,
601
+ fullReplayHistory: bundle.metadata.fullReplayHistory === true,
602
+ fullReplayNotCheckpoint: bundle.metadata.checkpointBundle !== true,
603
+ fullReplayCappedHonest: bundle.metadata.fullReplayCapped === (executedFrames < requestedFrames),
604
+ componentSemanticReplayExecuted: componentVerification.semanticReplayExecuted && componentVerification.result === 'pass',
605
+ frameRuntimeReplayExecuted: frameRuntimeReplay.verification.result === 'pass',
606
+ selfContainedFrameRuntimeReplayExecuted: frameRuntimeReplay.selfContainedVerification.result === 'pass',
607
+ frameRuntimeReplayFullHistoryVerified: frameRuntimeReplay.verification.frames === frameRuntimeReplay.snapshotCount,
608
+ selfContainedFrameRuntimeReplayFullHistoryVerified: frameRuntimeReplay.selfContainedVerification.frames === frameRuntimeReplay.snapshotCount,
609
+ frameRuntimeReplayCoversExecutedFrames: frameRuntimeReplay.verification.frames >= executedFrames,
610
+ selfContainedFrameRuntimeReplayCoversExecutedFrames: frameRuntimeReplay.selfContainedVerification.frames >= executedFrames,
611
+ forgedFrameRuntimeReplayRejected: frameRuntimeReplay.forgedVerification.result === 'fail'
612
+ && frameRuntimeReplay.forgedVerification.firstMismatch?.subsystem === 'frame-runtime-replay',
613
+ finalFrameCovered: bundle.checksums.at(-1)?.frame === executedFrames - 1,
614
+ requestedFrameCoverageDeclared: bundle.metadata.requestedFrames === requestedFrames && bundle.metadata.executedFrames === executedFrames,
615
+ debugTablesPresent: debug.ecs.length > 0 && debug.physics.length > 0 && debug.commands.length > 0,
616
+ }, withFrameMetrics({
617
+ replayBytes: verification.replayBytes,
618
+ snapshotBytes: verification.snapshotBytes,
619
+ inputCount: verification.inputCount,
620
+ checksumCount: verification.checksumCount,
621
+ commandCount: verification.commandCount,
622
+ debugEventCount: verification.debugEventCount,
623
+ semanticReplayFrames: verification.semanticReplayFrames,
624
+ simulatedFrames: executedFrames,
625
+ fullReplayFrames: executedFrames,
626
+ fullReplayRequestedFrames: requestedFrames,
627
+ fullReplayCapped: executedFrames < requestedFrames,
628
+ simulationHash: simulationHashValue.toString(16),
629
+ componentSemanticReplayFrames: componentVerification.semanticReplayFrames,
630
+ componentReplayBytes: componentVerification.replayBytes,
631
+ frameRuntimeReplayFrames: frameRuntimeReplay.verification.frames,
632
+ selfContainedFrameRuntimeReplayFrames: frameRuntimeReplay.selfContainedVerification.frames,
633
+ frameRuntimeReplaySnapshots: frameRuntimeReplay.snapshotCount,
634
+ frameRuntimeReplayFinalFrame: frameRuntimeReplay.verification.finalFrame,
635
+ selfContainedFrameRuntimeReplayFinalFrame: frameRuntimeReplay.selfContainedVerification.finalFrame,
636
+ frameRuntimeReplayBundleHash: frameRuntimeReplay.verification.bundleHash,
637
+ selfContainedFrameRuntimeReplayBundleHash: frameRuntimeReplay.selfContainedVerification.bundleHash,
638
+ forgedFrameRuntimeReplayFrame: frameRuntimeReplay.forgedVerification.firstMismatch.frame,
639
+ minimizedFrame: mismatch.frame,
640
+ minimizedVerificationResult: minimizedVerification.result,
641
+ minimizedVerificationFrame: minimizedVerification.firstMismatch.frame,
642
+ minimizedVerificationSubsystem: minimizedVerification.firstMismatch.subsystem,
643
+ minimizedArtifactChecksums: minimized.checksums.length,
644
+ minimizedOriginalReplayBytes: minimization.originalReplayBytes,
645
+ minimizedReplayBytes: minimization.minimizedReplayBytes,
646
+ minimizedRemovedInputFrames: minimization.removedInputFrames,
647
+ minimizedRemovedInputs: minimization.removedInputs,
648
+ minimizedRemovedCommandFrames: minimization.removedCommandFrames,
649
+ minimizedRemovedCommands: minimization.removedCommands,
650
+ minimizedRemovedDebugEvents: minimization.removedDebugEvents,
651
+ minimizedRemovedSnapshots: minimization.removedSnapshots,
652
+ minimizedRemovedChecksumFrames: minimization.removedChecksumFrames,
653
+ sliceBaselineFrame: sliced.sliceOrigin.baselineSnapshot.frame,
654
+ sliceBaselineChecksum: sliced.sliceOrigin.baselineSnapshot.checksum,
655
+ sliceSourceBundleHash: sliced.sliceOrigin.sourceBundleHash,
656
+ sliceVerificationFrames: sliceVerification.semanticReplayFrames,
657
+ checkpointStride: 0,
658
+ checkpointBundle: false,
659
+ checkpointCount: 0,
660
+ }, requestedFrames, executedFrames));
661
+ }
662
+ function integratedHeadlessSceneCategory(players, requestedFrames, executedFrames, seed) {
663
+ const scene = (0, sample_scenes_js_1.runDeterministicIntegratedHeadlessScene)(executedFrames, players, seed);
664
+ return categoryReport('integrated-headless-scene', scene.checksum, {
665
+ frameRuntimeExecuted: scene.invariants.frameRuntimeExecuted === true,
666
+ commandsExecuted: scene.invariants.commandsExecuted === true,
667
+ replayVerified: scene.replayVerified,
668
+ rollbackEquivalent: scene.rollbackEquivalent,
669
+ physicsExecuted: scene.invariants.physicsExecuted === true,
670
+ kccExecuted: scene.invariants.kccExecuted === true,
671
+ navmeshExecuted: scene.invariants.navmeshExecuted === true,
672
+ botExecuted: scene.invariants.botExecuted === true,
673
+ animationExecuted: scene.invariants.animationExecuted === true,
674
+ assetsConfigCovered: scene.invariants.assetsConfigCovered === true,
675
+ sameFrameCommandsCovered: scene.metrics.sameFrameCommandsAccepted >= 2,
676
+ fullSceneFramesCovered: scene.metrics.frames === executedFrames,
677
+ replayWindowVerified: scene.metrics.replayFrames <= scene.metrics.frames
678
+ && scene.metrics.replaySnapshots === scene.metrics.replayFrames + 1,
679
+ replayWindowCapDeclared: scene.metrics.replayCapped === (scene.metrics.replayFrames < scene.metrics.frames),
680
+ playersCovered: scene.metrics.players === players,
681
+ }, withFrameMetrics({
682
+ checksum: scene.checksum,
683
+ replayChecksum: scene.replayChecksum,
684
+ rollbackChecksum: scene.rollbackChecksum,
685
+ replayVerified: scene.replayVerified,
686
+ rollbackEquivalent: scene.rollbackEquivalent,
687
+ frames: scene.metrics.frames,
688
+ replayFrames: scene.metrics.replayFrames,
689
+ replayCapped: scene.metrics.replayCapped,
690
+ players: scene.metrics.players,
691
+ commandsAccepted: scene.metrics.commandsAccepted,
692
+ sameFrameCommandsAccepted: scene.metrics.sameFrameCommandsAccepted,
693
+ physicsContacts: scene.metrics.physicsContacts,
694
+ physicsQueries: scene.metrics.physicsQueries,
695
+ kccCorrections: scene.metrics.kccCorrections,
696
+ navReplans: scene.metrics.navReplans,
697
+ botTraceRows: scene.metrics.botTraceRows,
698
+ animationEvents: scene.metrics.animationEvents,
699
+ replaySnapshots: scene.metrics.replaySnapshots,
700
+ debugEvents: scene.metrics.debugEvents,
701
+ configHashCovered: scene.metrics.configHashCovered,
702
+ }, requestedFrames, executedFrames));
703
+ }
704
+ function projectRuntimeCategory(requestedFrames, executedFrames, seed) {
705
+ const manifest = readProjectFixtureJson('project.json');
706
+ const descriptorSource = readProjectFixtureJson(manifest.descriptor);
707
+ const descriptor = (0, schema_js_1.defineSyncplayGame)(descriptorSource);
708
+ const runtimeDescriptor = projectRuntimeDescriptorFromGameDescriptor(descriptor);
709
+ const runtimeAccessors = (0, engine_runtime_js_1.createDeterministicFrameRuntimeAccessors)(runtimeDescriptor);
710
+ const generatedSource = (0, engine_runtime_js_1.generateDeterministicFrameRuntimeSource)(runtimeDescriptor);
711
+ const generatedSourceHash = (0, canonical_js_1.defaultChecksum)(generatedSource);
712
+ const assets = (0, asset_cooking_js_1.cookDeterministicAssets)(readProjectFixtureJson(manifest.assets));
713
+ const config = (0, config_bundle_js_1.cookDeterministicConfigBundle)(readProjectFixtureJson(manifest.config), 1);
714
+ const configVerification = (0, config_bundle_js_1.verifyDeterministicConfigBundle)(config, {
715
+ engineHash: config.engineHash,
716
+ schemaHash: config.schemaHash,
717
+ configHash: config.configHash,
718
+ assetDbHash: config.assetDbHash,
719
+ });
720
+ const prototypeValidation = (0, asset_cooking_js_1.validatePrototypeEntitiesAgainstFrameRuntime)(assets, 'player.prototype', {
721
+ ...runtimeDescriptor,
722
+ components: runtimeDescriptor.components.map((component) => component.id === 'gameState' ? { ...component, singleton: false } : component),
723
+ }, 1);
724
+ const botDocument = readProjectFixtureJson(manifest.botDocuments[0] ?? 'bot.json');
725
+ const assetRefs = assets.cookedAssets.map((asset) => asset.id);
726
+ const compiledBot = (0, bot_documents_js_1.compileDeterministicBotDocument)(botDocument, assetRefs);
727
+ const botFrames = Math.max(12, Math.min(executedFrames, 512));
728
+ const botTraces = (0, bot_documents_js_1.traceDeterministicBotDocument)(botDocument, [1, 2], botFrames, assetRefs);
729
+ const botCoverage = (0, bot_documents_js_1.summarizeDeterministicBotDocumentTraceCoverage)(botDocument, botTraces);
730
+ const navmeshSource = readProjectFixtureJson(manifest.navmeshes[0] ?? 'navmesh.json');
731
+ const navmesh = (0, navmesh_js_1.cookDeterministicNavmesh)(navmeshSource);
732
+ const navPath = (0, navmesh_js_1.findDeterministicNavmeshPath)(navmesh, { start: 'spawn', goal: 'goal' });
733
+ let navAgents = [{
734
+ id: 'project-agent',
735
+ polygonId: 'spawn',
736
+ targetPolygonId: 'goal',
737
+ speedPerFrame: 1,
738
+ radius: 1,
739
+ avoidancePriority: 1,
740
+ }];
741
+ let navTraceChecksum = '';
742
+ let navWaypointAdvances = 0;
743
+ const navFrames = Math.max(2, Math.min(executedFrames, 512));
744
+ for (let frame = 0; frame < navFrames; frame += 1) {
745
+ const step = (0, navmesh_js_1.stepDeterministicNavmeshAgents)(navmesh, navAgents, { frame });
746
+ navAgents = step.agents;
747
+ navWaypointAdvances += step.waypointAdvances;
748
+ navTraceChecksum = step.checksum;
749
+ }
750
+ const animationDescriptor = readProjectFixtureJson(manifest.animations[0] ?? 'animation.json');
751
+ const animation = (0, animation_js_1.cookDeterministicAnimation)(animationDescriptor);
752
+ const animationScript = readProjectFixtureJson(manifest.animationParameters?.[manifest.animations[0] ?? 'animation.json'] ?? 'animation-params.json');
753
+ const animationUpdates = new Map(animationScript.frames.map((entry) => [entry.frame, entry.parameters]));
754
+ let animationState = (0, animation_js_1.createDeterministicAnimationRuntimeState)(animationDescriptor);
755
+ let animationTransitions = 0;
756
+ let animationEvents = 0;
757
+ let animationChecksum = '';
758
+ const animationFrames = Math.max(12, Math.min(executedFrames, 512));
759
+ for (let frame = 0; frame < animationFrames; frame += 1) {
760
+ const result = (0, animation_js_1.stepDeterministicAnimation)(animationDescriptor, animationState, animationUpdates.get(frame) ?? {});
761
+ animationState = result.state;
762
+ animationTransitions += result.transitionCount;
763
+ animationEvents += result.events.length;
764
+ animationChecksum = result.checksum;
765
+ }
766
+ const staticDiagnostics = manifest.staticPaths.flatMap((path) => (0, static_checker_js_1.checkSourceText)(path, readProjectFixtureText(path), 'strict', {
767
+ schemaStateFields: descriptor.state.fields.map((field) => field.name),
768
+ }));
769
+ const replay = createProjectRuntimeReplayProof(runtimeDescriptor, generatedSourceHash, executedFrames, seed);
770
+ const checksum = (0, canonical_js_1.defaultChecksum)({
771
+ descriptor: descriptor.artifactId,
772
+ runtimeDescriptor: runtimeAccessors.descriptorHash,
773
+ generatedSourceHash,
774
+ assetDbHash: assets.manifest.assetDbHash,
775
+ configHash: config.configHash,
776
+ botHash: compiledBot.hash,
777
+ navmeshHash: navmesh.hash,
778
+ animationHash: animation.hash,
779
+ replayHash: replay.verification.bundleHash,
780
+ staticDiagnostics,
781
+ });
782
+ return categoryReport('project-runtime', checksum, {
783
+ descriptorCertified: descriptor.maxPlayers === 128 && runtimeAccessors.descriptorHash.length > 0,
784
+ generatedRuntimeSourceCertified: generatedSourceHash.length > 0 && generatedSource.includes('recordSpawnCommand'),
785
+ assetsCertified: assets.manifest.assetDbHash === config.assetDbHash,
786
+ configCertified: configVerification.result === 'pass',
787
+ prototypeRuntimeValidated: prototypeValidation.injectedComponentCount > 0 && prototypeValidation.checksum.length > 0,
788
+ botDocumentCertified: compiledBot.hash.length > 0 && botCoverage.fullModelCoverageComplete,
789
+ navmeshCertified: navPath.polygons.join('>') === 'spawn>goal' && navWaypointAdvances > 0,
790
+ animationCertified: animationTransitions >= 2 && animationEvents > 0,
791
+ staticDeterminismCertified: staticDiagnostics.filter((diagnostic) => diagnostic.severity === 'error').length === 0,
792
+ replayRuntimeVerified: replay.verification.result === 'pass',
793
+ selfContainedReplayRuntimeVerified: replay.selfContainedVerification.result === 'pass',
794
+ replayUsesProjectGameStateRuntime: replay.systemId === 'project-game-state-runtime-replay-v1',
795
+ replayAcceptsGeneratedRuntimeSourceHash: replay.acceptedGeneratedRuntimeSourceHash,
796
+ replayRuntimeCoversProjectCommands: runtimeDescriptor.commandChannels?.some((channel) => channel.id === 'spawn') === true,
797
+ replayRuntimeCoversProjectEvents: runtimeDescriptor.eventChannels?.some((event) => event.id === 'damage') === true,
798
+ projectFrameCapDeclared: executedFrames <= requestedFrames,
799
+ executedRequestedFrames: executedFrames === requestedFrames ? true : 'capped',
800
+ }, withFrameMetrics({
801
+ artifactId: descriptor.artifactId,
802
+ runtimeDescriptorHash: runtimeAccessors.descriptorHash,
803
+ generatedSourceHash,
804
+ generatedSourceBytes: generatedSource.length,
805
+ assetDbHash: assets.manifest.assetDbHash,
806
+ configHash: config.configHash,
807
+ prototypeRuntimeValidationChecksum: prototypeValidation.checksum,
808
+ botHash: compiledBot.hash,
809
+ botTraceRows: botTraces.length,
810
+ botCoverageComplete: botCoverage.fullModelCoverageComplete,
811
+ navmeshHash: navmesh.hash,
812
+ navPathHash: navPath.pathHash,
813
+ navWaypointAdvances,
814
+ navTraceChecksum,
815
+ animationHash: animation.hash,
816
+ animationTransitions,
817
+ animationEvents,
818
+ animationChecksum,
819
+ staticDiagnostics: staticDiagnostics.length,
820
+ replayBundleHash: replay.verification.bundleHash,
821
+ replayFinalChecksum: replay.verification.finalChecksum,
822
+ selfContainedReplayFinalChecksum: replay.selfContainedVerification.finalChecksum,
823
+ replaySnapshotCount: replay.snapshotCount,
824
+ replaySystemId: replay.systemId,
825
+ replayAcceptedGeneratedRuntimeSourceHash: replay.acceptedGeneratedRuntimeSourceHash,
826
+ replayRuntimeComponentCount: runtimeDescriptor.components.length,
827
+ replayRuntimeCommandChannelCount: runtimeDescriptor.commandChannels?.length ?? 0,
828
+ replayRuntimeEventChannelCount: runtimeDescriptor.eventChannels?.length ?? 0,
829
+ capped: executedFrames < requestedFrames,
830
+ }, requestedFrames, executedFrames));
831
+ }
832
+ function readProjectFixtureText(path) {
833
+ for (const candidate of projectFixtureCandidates(path)) {
834
+ if ((0, node_fs_1.existsSync)(candidate)) {
835
+ return (0, node_fs_1.readFileSync)(candidate, 'utf8');
836
+ }
837
+ }
838
+ throw new Error(`Unable to locate deterministic project fixture ${path}`);
839
+ }
840
+ function readProjectFixtureJson(path) {
841
+ return JSON.parse(readProjectFixtureText(path));
842
+ }
843
+ function projectFixtureCandidates(path) {
844
+ return [
845
+ (0, node_path_1.resolve)(process.cwd(), 'fixtures/projects/engine-parity', path),
846
+ (0, node_path_1.resolve)(process.cwd(), 'packages/syncplay/fixtures/projects/engine-parity', path),
847
+ (0, node_path_1.resolve)(process.cwd(), '../syncplay/fixtures/projects/engine-parity', path),
848
+ ];
849
+ }
850
+ function projectRuntimeDescriptorFromGameDescriptor(descriptor) {
851
+ return {
852
+ id: `${descriptor.artifactId}/project-runtime-replay`,
853
+ tickRate: descriptor.tickRate,
854
+ components: [
855
+ {
856
+ id: 'gameState',
857
+ singleton: true,
858
+ fields: descriptor.state.fields
859
+ .filter((field) => field.checksummed)
860
+ .map((field) => ({
861
+ name: field.name,
862
+ kind: projectRuntimeFieldKind(field.kind),
863
+ defaultValue: projectRuntimeDefaultFieldValue(field.kind),
864
+ })),
865
+ },
866
+ {
867
+ id: 'runtimeReplayState',
868
+ singleton: true,
869
+ fields: [
870
+ { name: 'value', kind: 'int', defaultValue: 0 },
871
+ { name: 'inputDelta', kind: 'int', defaultValue: 0 },
872
+ { name: 'commandDelta', kind: 'int', defaultValue: 0 },
873
+ ],
874
+ },
875
+ ],
876
+ systems: [{ id: 'simulate', group: 'simulation', order: 0 }],
877
+ commandChannels: descriptor.commandChannels?.map((channel) => ({
878
+ id: channel.id,
879
+ reliable: channel.delivery === 'reliable',
880
+ allowPrediction: channel.delivery === 'reliable',
881
+ maxPayloadBytes: Math.max(64, channel.fields.length * 64),
882
+ ...(channel.delivery === 'unreliable' ? { minFrameLead: 1 } : {}),
883
+ maxFrameLead: 32,
884
+ })),
885
+ eventChannels: descriptor.events?.map((event) => ({
886
+ id: event.id,
887
+ fields: event.payloadFields.map((field) => ({
888
+ name: field.name,
889
+ kind: projectRuntimeFieldKind(field.kind),
890
+ defaultValue: projectRuntimeDefaultFieldValue(field.kind),
891
+ })),
892
+ })),
893
+ };
894
+ }
895
+ function projectRuntimeFieldKind(kind) {
896
+ if (kind === 'boolean') {
897
+ return 'bool';
898
+ }
899
+ if (kind === 'string' || kind === 'asset-ref') {
900
+ return 'string';
901
+ }
902
+ return 'int';
903
+ }
904
+ function projectRuntimeDefaultFieldValue(kind) {
905
+ if (kind === 'boolean') {
906
+ return false;
907
+ }
908
+ if (kind === 'string' || kind === 'asset-ref') {
909
+ return '';
910
+ }
911
+ return 0;
912
+ }
913
+ function projectRuntimeDefaultGameState(descriptor) {
914
+ const gameState = descriptor.components.find((component) => component.id === 'gameState' && component.singleton === true);
915
+ return Object.fromEntries(gameState.fields.map((field) => [
916
+ field.name,
917
+ field.defaultValue,
918
+ ]));
919
+ }
920
+ function createProjectRuntimeReplayProof(descriptor, generatedSourceHash, frames, seed) {
921
+ const runtime = (0, engine_runtime_js_1.createDeterministicFrameRuntime)(descriptor, seed);
922
+ runtime.setSingleton('gameState', projectRuntimeDefaultGameState(descriptor));
923
+ runtime.setSingleton('runtimeReplayState', { value: 0, inputDelta: 0, commandDelta: 0 });
924
+ const firstSnapshot = runtime.snapshot();
925
+ const snapshots = [{ frame: firstSnapshot.frame, bytes: firstSnapshot.bytes, checksum: firstSnapshot.checksum }];
926
+ const inputHistory = Array.from({ length: frames }, (_, frame) => ({
927
+ frame,
928
+ inputs: projectRuntimeReplayInputsForFrame(frame),
929
+ }));
930
+ const commandHistory = Array.from({ length: frames }, (_, frame) => ({
931
+ frame,
932
+ commands: projectRuntimeReplayCommandsForFrame(frame),
933
+ }));
934
+ const systems = {
935
+ simulate: projectRuntimeReplaySystem,
936
+ };
937
+ for (let frame = 0; frame < frames; frame += 1) {
938
+ injectProjectRuntimeReplayFrame(runtime, frame, inputHistory[frame].inputs, commandHistory[frame].commands);
939
+ runtime.step(systems);
940
+ const snapshot = runtime.snapshot();
941
+ snapshots.push({ frame: snapshot.frame, bytes: snapshot.bytes, checksum: snapshot.checksum });
942
+ }
943
+ const bundle = (0, replay_bundle_js_1.createDeterministicReplayBundle)({
944
+ runtimeVersion: 'engine-complete-project@1',
945
+ engineHash: (0, canonical_js_1.defaultChecksum)(descriptor),
946
+ schemaHash: (0, canonical_js_1.defaultChecksum)(descriptor),
947
+ assetDbHash: 'fixture-project-assets',
948
+ configHash: 'fixture-project-config',
949
+ sampleId: 'engine-complete-project-runtime',
950
+ inputHistory,
951
+ commandHistory,
952
+ checksums: snapshots.map((snapshot) => ({ frame: snapshot.frame, checksum: snapshot.checksum })),
953
+ debugEvents: runtime.debugEvents,
954
+ snapshots,
955
+ runtimeReplay: (0, replay_bundle_js_1.createDeterministicReplayRuntimeManifest)({
956
+ descriptor,
957
+ systemId: 'project-game-state-runtime-replay-v1',
958
+ beforeFrameId: 'project-game-state-input-command-delta-v1',
959
+ acceptedSystemsSourceHashes: [generatedSourceHash],
960
+ seed,
961
+ }),
962
+ metadata: {
963
+ projectRuntime: true,
964
+ generatedSourceHash,
965
+ frames,
966
+ },
967
+ });
968
+ const verification = (0, replay_bundle_js_1.verifyDeterministicFrameRuntimeReplayBundle)(bundle, {
969
+ descriptor,
970
+ systems,
971
+ systemsSourceHash: generatedSourceHash,
972
+ requireRuntimeIdentity: true,
973
+ seed,
974
+ beforeFrame: injectProjectRuntimeReplayFrame,
975
+ });
976
+ const selfContainedVerification = (0, replay_bundle_js_1.verifyDeterministicSelfContainedFrameRuntimeReplayBundle)(bundle);
977
+ return {
978
+ verification,
979
+ selfContainedVerification,
980
+ snapshotCount: snapshots.length,
981
+ systemId: bundle.runtimeReplay.systemId,
982
+ acceptedGeneratedRuntimeSourceHash: bundle.runtimeReplay.acceptedSystemsSourceHashes.includes(generatedSourceHash),
983
+ };
984
+ }
985
+ const projectRuntimeReplaySystem = function runProjectRuntimeReplaySystem(ctx) {
986
+ const replayState = ctx.getSingleton('runtimeReplayState');
987
+ const value = Number(replayState.value) + Number(replayState.inputDelta) + Number(replayState.commandDelta);
988
+ ctx.setSingleton('runtimeReplayState', {
989
+ value,
990
+ inputDelta: 0,
991
+ commandDelta: 0,
992
+ });
993
+ const gameState = ctx.getSingleton('gameState');
994
+ ctx.setSingleton('gameState', patchProjectRuntimeGameState(gameState, ctx.frame + 1, value));
995
+ if (ctx.frame % 128 === 0) {
996
+ ctx.emitDebug('ecs.project-runtime-replay', { frame: ctx.frame, value });
997
+ }
998
+ };
999
+ function projectRuntimeReplayInputsForFrame(frame) {
1000
+ const variant = frame % 4;
1001
+ if (variant === 0) {
1002
+ return [{ slot: 0, dx: frame + 1 }];
1003
+ }
1004
+ if (variant === 1) {
1005
+ return [{ slot: 0, moveX: frame + 1 }];
1006
+ }
1007
+ if (variant === 2) {
1008
+ return [frame];
1009
+ }
1010
+ return [{ slot: 0 }];
1011
+ }
1012
+ function projectRuntimeReplayCommandsForFrame(frame) {
1013
+ const variant = frame % 4;
1014
+ if (variant === 0) {
1015
+ return [{ id: `project-runtime:${frame}`, payload: { power: frame % 3, prototype: 'player.prototype' } }];
1016
+ }
1017
+ if (variant === 1) {
1018
+ return [{ id: `project-runtime:${frame}`, payload: { prototype: 'player.prototype', slot: frame % 4 } }];
1019
+ }
1020
+ if (variant === 2) {
1021
+ return [{ id: `project-runtime:${frame}`, payload: 'ignored' }];
1022
+ }
1023
+ return [{ id: `project-runtime:${frame}`, payload: { prototype: 'player.prototype' } }];
1024
+ }
1025
+ function injectProjectRuntimeReplayFrame(runtime, frame, inputs, commands) {
1026
+ const inputDelta = inputs.reduce((sum, input) => {
1027
+ if (!isCanonicalRecord(input)) {
1028
+ return sum;
1029
+ }
1030
+ if (typeof input.dx === 'number') {
1031
+ return sum + input.dx;
1032
+ }
1033
+ if (typeof input.moveX === 'number') {
1034
+ return sum + input.moveX;
1035
+ }
1036
+ return sum;
1037
+ }, 0);
1038
+ const commandDelta = commands.reduce((sum, command) => {
1039
+ if (!isCanonicalRecord(command) || !isCanonicalRecord(command.payload)) {
1040
+ return sum;
1041
+ }
1042
+ if (typeof command.payload.power === 'number') {
1043
+ return sum + command.payload.power;
1044
+ }
1045
+ if (typeof command.payload.slot === 'number') {
1046
+ return sum + command.payload.slot;
1047
+ }
1048
+ return sum;
1049
+ }, 0);
1050
+ const replayState = runtime.snapshot().singletonComponents.runtimeReplayState;
1051
+ runtime.setSingleton('runtimeReplayState', {
1052
+ value: Number(replayState.value),
1053
+ inputDelta,
1054
+ commandDelta,
1055
+ });
1056
+ const gameState = runtime.snapshot().singletonComponents.gameState;
1057
+ runtime.setSingleton('gameState', patchProjectRuntimeGameState(gameState, frame, Number(replayState.value)));
1058
+ }
1059
+ function patchProjectRuntimeGameState(gameState, frame, score) {
1060
+ return Object.fromEntries(Object.keys(gameState).sort().map((key) => {
1061
+ const value = gameState[key];
1062
+ if (key === 'tick' && typeof value === 'number') {
1063
+ return [key, frame];
1064
+ }
1065
+ if (key === 'score' && typeof value === 'number') {
1066
+ return [key, score];
1067
+ }
1068
+ if (key === 'alive' && typeof value === 'boolean') {
1069
+ return [key, true];
1070
+ }
1071
+ return [key, value];
1072
+ }));
1073
+ }
1074
+ function createFrameRuntimeReplayProof(frames) {
1075
+ const descriptor = {
1076
+ id: 'engine-complete-runtime-replay',
1077
+ tickRate: 60,
1078
+ components: [{
1079
+ id: 'score',
1080
+ singleton: true,
1081
+ fields: [
1082
+ { name: 'value', kind: 'int', defaultValue: 0 },
1083
+ { name: 'inputDelta', kind: 'int', defaultValue: 0 },
1084
+ { name: 'commandDelta', kind: 'int', defaultValue: 0 },
1085
+ ],
1086
+ }],
1087
+ systems: [{ id: 'simulate', group: 'simulation', order: 0 }],
1088
+ };
1089
+ const systems = {
1090
+ simulate(ctx) {
1091
+ const score = ctx.getSingleton('score');
1092
+ ctx.setSingleton('score', {
1093
+ value: Number(score.value) + Number(score.inputDelta) + Number(score.commandDelta),
1094
+ inputDelta: 0,
1095
+ commandDelta: 0,
1096
+ });
1097
+ if (ctx.frame % 128 === 0) {
1098
+ ctx.emitDebug('ecs.runtime-replay', { frame: ctx.frame, value: Number(score.value) });
1099
+ }
1100
+ },
1101
+ };
1102
+ const runtime = (0, engine_runtime_js_1.createDeterministicFrameRuntime)(descriptor, 91);
1103
+ runtime.setSingleton('score', { value: 0, inputDelta: 0, commandDelta: 0 });
1104
+ const firstSnapshot = runtime.snapshot();
1105
+ const snapshots = [{ frame: firstSnapshot.frame, bytes: firstSnapshot.bytes, checksum: firstSnapshot.checksum }];
1106
+ const inputHistory = Array.from({ length: frames }, (_, frame) => ({
1107
+ frame,
1108
+ inputs: frame % 2 === 0 ? [{ slot: 0, dx: frame + 1 }] : [frame],
1109
+ }));
1110
+ const commandHistory = Array.from({ length: frames }, (_, frame) => ({
1111
+ frame,
1112
+ commands: frame % 2 === 0 ? [{ id: `runtime-replay:${frame}`, payload: { power: frame % 3 } }] : [{ id: `runtime-replay:${frame}`, payload: 'ignored' }],
1113
+ }));
1114
+ for (let frame = 0; frame < frames; frame += 1) {
1115
+ injectFrameRuntimeReplayInputs(runtime, frame, inputHistory[frame].inputs, commandHistory[frame].commands);
1116
+ runtime.step(systems);
1117
+ const snapshot = runtime.snapshot();
1118
+ snapshots.push({ frame: snapshot.frame, bytes: snapshot.bytes, checksum: snapshot.checksum });
1119
+ }
1120
+ const bundle = (0, replay_bundle_js_1.createDeterministicReplayBundle)({
1121
+ runtimeVersion: 'engine-complete@1',
1122
+ engineHash: 'engine-hash',
1123
+ schemaHash: (0, canonical_js_1.defaultChecksum)(descriptor),
1124
+ assetDbHash: 'asset-hash',
1125
+ configHash: 'config-hash',
1126
+ sampleId: 'engine-complete-frame-runtime',
1127
+ inputHistory,
1128
+ commandHistory,
1129
+ checksums: snapshots.map((snapshot) => ({ frame: snapshot.frame, checksum: snapshot.checksum })),
1130
+ debugEvents: runtime.debugEvents,
1131
+ snapshots,
1132
+ runtimeReplay: (0, replay_bundle_js_1.createDeterministicReplayRuntimeManifest)({
1133
+ descriptor,
1134
+ systemId: 'score-runtime-replay-v1',
1135
+ beforeFrameId: 'score-input-command-delta-v1',
1136
+ seed: 91,
1137
+ }),
1138
+ metadata: { frameRuntimeReplay: true, selfContainedRuntimeReplay: true, frames },
1139
+ });
1140
+ const replayOptions = {
1141
+ descriptor,
1142
+ systems,
1143
+ seed: 91,
1144
+ beforeFrame: injectFrameRuntimeReplayInputs,
1145
+ };
1146
+ const forgedSnapshots = bundle.snapshots.map((snapshot) => {
1147
+ if (snapshot.frame !== Math.min(2, frames)) {
1148
+ return snapshot;
1149
+ }
1150
+ const parsed = JSON.parse(snapshot.bytes);
1151
+ parsed.singletonComponents.score.value += 17;
1152
+ const bytes = (0, canonical_js_1.canonicalStringify)(parsed);
1153
+ return { frame: snapshot.frame, bytes, checksum: (0, canonical_js_1.defaultChecksum)(bytes) };
1154
+ });
1155
+ const forged = (0, replay_bundle_js_1.createDeterministicReplayBundle)({
1156
+ ...bundle,
1157
+ snapshots: forgedSnapshots,
1158
+ checksums: forgedSnapshots.map((snapshot) => ({ frame: snapshot.frame, checksum: snapshot.checksum })),
1159
+ });
1160
+ return {
1161
+ verification: (0, replay_bundle_js_1.verifyDeterministicFrameRuntimeReplayBundle)(bundle, replayOptions),
1162
+ selfContainedVerification: (0, replay_bundle_js_1.verifyDeterministicSelfContainedFrameRuntimeReplayBundle)(bundle),
1163
+ forgedVerification: (0, replay_bundle_js_1.verifyDeterministicFrameRuntimeReplayBundle)(forged, replayOptions),
1164
+ snapshotCount: snapshots.length,
1165
+ };
1166
+ }
1167
+ function injectFrameRuntimeReplayInputs(runtime, _frame, inputs, commands) {
1168
+ const inputDelta = inputs.reduce((sum, input) => isCanonicalRecord(input) && typeof input.dx === 'number' ? sum + input.dx : sum, 0);
1169
+ const commandDelta = commands.reduce((sum, command) => {
1170
+ if (!isCanonicalRecord(command) || !isCanonicalRecord(command.payload) || typeof command.payload.power !== 'number') {
1171
+ return sum;
1172
+ }
1173
+ return sum + command.payload.power;
1174
+ }, 0);
1175
+ const score = runtime.snapshot().singletonComponents.score;
1176
+ runtime.setSingleton('score', {
1177
+ value: Number(score.value),
1178
+ inputDelta,
1179
+ commandDelta,
1180
+ });
1181
+ }
1182
+ function isCanonicalRecord(value) {
1183
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
1184
+ }
1185
+ function createComponentReplayBundle() {
1186
+ const firstBytes = (0, canonical_js_1.canonicalStringify)({ frame: 0, components: { 1: { position: { x: 2 } } } });
1187
+ const secondBytes = (0, canonical_js_1.canonicalStringify)({ frame: 1, components: { 1: { position: { x: 5, y: 4 } } } });
1188
+ return (0, replay_bundle_js_1.createDeterministicReplayBundle)({
1189
+ runtimeVersion: 'engine-complete@1',
1190
+ engineHash: 'engine-hash',
1191
+ schemaHash: 'component-schema-hash',
1192
+ assetDbHash: 'asset-hash',
1193
+ configHash: 'config-hash',
1194
+ sampleId: 'engine-complete-components',
1195
+ inputHistory: [
1196
+ { frame: 0, inputs: [{ entity: '1', component: 'position', field: 'x', delta: 2 }] },
1197
+ { frame: 1, inputs: [{ entity: '1', component: 'position', field: 'x', delta: 3 }] },
1198
+ ],
1199
+ commandHistory: [
1200
+ { frame: 1, commands: [{ id: 'set-y', payload: { entity: '1', component: 'position', field: 'y', value: 4 } }] },
1201
+ ],
1202
+ checksums: [
1203
+ { frame: 0, checksum: (0, canonical_js_1.defaultChecksum)(firstBytes) },
1204
+ { frame: 1, checksum: (0, canonical_js_1.defaultChecksum)(secondBytes) },
1205
+ ],
1206
+ debugEvents: [{ frame: 1, type: 'ecs.snapshot', payload: { component: 'position' } }],
1207
+ snapshots: [
1208
+ { frame: 0, bytes: firstBytes, checksum: (0, canonical_js_1.defaultChecksum)(firstBytes) },
1209
+ { frame: 1, bytes: secondBytes, checksum: (0, canonical_js_1.defaultChecksum)(secondBytes) },
1210
+ ],
1211
+ metadata: { semanticReplay: 'component-delta-v1' },
1212
+ });
1213
+ }
1214
+ function physicsCategory(bodies, requestedFrames, executedFrames, enforceThresholds, benchmark, noFastStress) {
1215
+ const metrics = (0, physics3d_js_1.runDeterministicPhysics3DStress)(bodies, executedFrames, { allowFastStress: !noFastStress });
1216
+ const callbackMasks = (0, physics3d_js_1.runDeterministicPhysics3DCallbackMaskFixture)();
1217
+ const queryOptions = (0, physics3d_js_1.runDeterministicPhysics3DQueryOptionsFixture)();
1218
+ const materials = (0, physics3d_js_1.runDeterministicPhysics3DMaterialFixture)();
1219
+ const details = (0, physics3d_js_1.runDeterministicPhysics3DDetailFixture)();
1220
+ const stack = (0, physics3d_js_1.runDeterministicPhysics3DStackFixture)();
1221
+ const lagComp3D = (0, lag_compensation3d_js_1.runDeterministicLagCompensation3DFixture)(128, Math.min(executedFrames, 5_000), 71);
1222
+ const lagComp3DApi = (0, lag_compensation3d_js_1.runDeterministicLagCompensation3DApiFixture)();
1223
+ const authoritativeLagComp3D = (0, lag_compensation3d_js_1.runDeterministicAuthoritativeLagCompensation3DFixture)();
1224
+ const fullStep = runPhysics3DFullStepMeasurementFixture(Math.min(requestedFrames, 300));
1225
+ const highBodySample512 = requestedFrames > 512 ? (0, physics3d_js_1.runDeterministicPhysics3DStress)(512, 128) : undefined;
1226
+ const highBodySample2048 = requestedFrames > 512 ? (0, physics3d_js_1.runDeterministicPhysics3DStress)(2048, 32) : undefined;
1227
+ return categoryReport('physics3d', (0, canonical_js_1.defaultChecksum)({
1228
+ stress: metrics.checksum,
1229
+ materials: materials.checksum,
1230
+ stack: stack.checksum,
1231
+ lagComp3D: lagComp3D.checksum,
1232
+ lagComp3DApi: lagComp3DApi.checksum,
1233
+ authoritativeLagComp3D: authoritativeLagComp3D.checksum,
1234
+ }), {
1235
+ has3dBodies: metrics.bodies === bodies,
1236
+ scheduledQueriesRan: metrics.queryCount === executedFrames * 3,
1237
+ scheduledPrePhysicsQueriesRan: metrics.scheduledPrePhysicsQueries === executedFrames,
1238
+ scheduledPostPhysicsQueriesRan: metrics.scheduledPostPhysicsQueries === executedFrames * 2,
1239
+ scheduledShapeCastQueriesRan: metrics.scheduledShapeCastQueries === executedFrames,
1240
+ scheduledQueryResultsStable: metrics.scheduledQueryOrderHash.length > 0,
1241
+ shapeCastsCovered: metrics.shapeCastCount > 0,
1242
+ exactShapeNarrowphaseCovered: metrics.exactShapeRejects > 0,
1243
+ solverCorrectionsCovered: metrics.solverCorrections > 0,
1244
+ angularDynamicsCovered: metrics.angularBodies > 0,
1245
+ angularGeometryCovered: metrics.angularGeometryQueries > 0,
1246
+ meshStaticCollidersCovered: metrics.meshStaticColliders > 0,
1247
+ exactMeshRaycastsCovered: metrics.exactMeshRaycasts > 0,
1248
+ exactMeshOverlapRejectsCovered: metrics.exactMeshOverlapRejects > 0,
1249
+ rollbackEquivalent: metrics.rollbackEquivalent,
1250
+ callbackMasksCovered: callbackMasks.perEntityMaskHonored,
1251
+ queryOptionsCovered: queryOptions.defaultHitAll
1252
+ && queryOptions.explicitSolidsOnly
1253
+ && queryOptions.kindFiltersStable
1254
+ && queryOptions.triggerSensorFiltersStable
1255
+ && queryOptions.raycastCovered
1256
+ && queryOptions.overlapCovered
1257
+ && queryOptions.shapeCastCovered,
1258
+ detailedHitAndContactCovered: details.rayDetailedHits > 0
1259
+ && details.shapeCastDetailedHits > 0
1260
+ && details.contactDetails > 0
1261
+ && details.rayNormalX === -1
1262
+ && details.shapeCastPointX > 0
1263
+ && details.contactPenetration > 0,
1264
+ detailedPhysicsRollbackEquivalent: details.rollbackEquivalent,
1265
+ detailedPhysicsOrderStable: details.stableUnderBodyOrderPermutation,
1266
+ stackStabilityCovered: stack.contactCount > 0
1267
+ && stack.solverCorrections > 0
1268
+ && stack.maxPenetration <= 0.05
1269
+ && stack.maxHeightDrift <= 0.05
1270
+ && stack.settledDynamicBodies === stack.stackLayers,
1271
+ stackRollbackEquivalent: stack.rollbackEquivalent,
1272
+ stackAuthoringOrderStable: stack.stableUnderAuthoringOrderPermutation,
1273
+ materialResponseCovered: materials.combinedFriction === 3
1274
+ && materials.combinedRestitution === 7
1275
+ && materials.normalVelocityAfterBounce === -2
1276
+ && materials.tangentVelocityAfterFrictionY === 7
1277
+ && materials.tangentVelocityAfterFrictionZ === -7,
1278
+ materialRollbackEquivalent: materials.rollbackEquivalent,
1279
+ callbackLifecycleCovered: callbackMasks.collisionEnter > 0
1280
+ && callbackMasks.collisionStay > 0
1281
+ && callbackMasks.collisionExit > 0
1282
+ && callbackMasks.triggerEnter > 0
1283
+ && callbackMasks.triggerStay > 0
1284
+ && callbackMasks.triggerExit > 0,
1285
+ callbackRollbackEquivalent: callbackMasks.rollbackEquivalent,
1286
+ lagComp3DProxyLifecycleCovered: lagComp3D.proxyLifecycleBalanced
1287
+ && lagComp3D.proxyBodiesCreated > 0
1288
+ && lagComp3D.proxyBodiesDestroyed === lagComp3D.proxyBodiesCreated,
1289
+ lagComp3DHitboxProxyCovered: lagComp3D.multiHitboxQueries > 0 && lagComp3D.animatedHitboxSamples > 0,
1290
+ lagComp3DInterpolatedHitboxesCovered: lagComp3D.interpolatedHitboxSamples > 0,
1291
+ lagComp3DWeaponsCovered: lagComp3D.rifleShots > 0 && lagComp3D.shotgunShots > 0 && lagComp3D.burstShots > 0,
1292
+ lagComp3DOcclusionCovered: lagComp3D.staticOcclusionQueries > 0 && lagComp3D.occluded > 0,
1293
+ lagComp3DRejectionCovered: lagComp3D.staleRejected > 0 && lagComp3D.futureRejected > 0,
1294
+ lagComp3DRollbackEquivalent: lagComp3D.rollbackEquivalent,
1295
+ lagComp3DPerClientShotTimesCovered: lagComp3D.perClientShotTimesCovered,
1296
+ lagComp3DApiReusable: lagComp3DApi.hitReason === 'hit'
1297
+ && lagComp3DApi.occludedReason === 'occluded'
1298
+ && lagComp3DApi.staleReason === 'stale-frame'
1299
+ && lagComp3DApi.futureReason === 'future-frame',
1300
+ lagComp3DApiInterpolationCovered: lagComp3DApi.interpolatedRewindTargets > 0,
1301
+ lagComp3DApiSnapshotRestoreEquivalent: lagComp3DApi.rollbackEquivalent,
1302
+ lagComp3DApiProxyLifecycleCovered: lagComp3DApi.proxiesCreated > 0
1303
+ && lagComp3DApi.proxiesCreated === lagComp3DApi.proxiesDestroyed,
1304
+ lagComp3DApiHistoryPruningCovered: lagComp3DApi.prunedOldFrames,
1305
+ lagComp3DAuthoritativeShotTimeCovered: authoritativeLagComp3D.authorityHitReason === 'hit'
1306
+ && authoritativeLagComp3D.derivedRewindFrame === 1
1307
+ && authoritativeLagComp3D.rawForgedRewindFrame !== authoritativeLagComp3D.derivedRewindFrame,
1308
+ lagComp3DAuthoritativeForgedTimingRejected: authoritativeLagComp3D.forgedLatencyReason === 'invalid-shot'
1309
+ && authoritativeLagComp3D.forgedShotFrameReason === 'invalid-shot'
1310
+ && authoritativeLagComp3D.forgedHistoryReason === 'invalid-shot'
1311
+ && authoritativeLagComp3D.authorityTimingRejected === 3,
1312
+ lagComp3DAuthoritativeRollbackEquivalent: authoritativeLagComp3D.rollbackEquivalent,
1313
+ fullStepMeasuredTimingCovered: fullStep.frames === fullStep.fullStepFrames
1314
+ && fullStep.p95MeasuredStepMs > 0
1315
+ && fullStep.p99MeasuredStepMs > 0,
1316
+ fullStepRollbackEquivalent: fullStep.rollbackEquivalent,
1317
+ fullStepContactsAndQueriesCovered: fullStep.contactCount > 0 && fullStep.queryCount === fullStep.frames,
1318
+ executedRequestedFrames: metrics.frames === requestedFrames,
1319
+ ...(metrics.extrapolatedStress ? {} : {
1320
+ fullPhysicsRequiredProofCovered: metrics.fullPhysicsStepFrames === metrics.frames,
1321
+ }),
1322
+ optimizedPhysicsBenchmarkTailDeclared: benchmark && !noFastStress
1323
+ ? metrics.extrapolatedStress && metrics.optimizedStressFrames > 0
1324
+ : metrics.extrapolatedStress === false && metrics.optimizedStressFrames === 0,
1325
+ noFastStressHonored: noFastStress
1326
+ ? metrics.fullPhysicsStepFrames === metrics.frames && metrics.optimizedStressFrames === 0 && metrics.extrapolatedStress === false
1327
+ : true,
1328
+ optimizedStressFramesDeclared: metrics.optimizedStressFrames === Math.max(0, metrics.frames - metrics.fullPhysicsStepFrames),
1329
+ measuredP99WithinThreshold: enforceThresholds ? metrics.p99StepMs < 25 : true,
1330
+ physicsStressProofMode: metrics.extrapolatedStress ? 'optimized-tail' : 'full-step',
1331
+ }, withFrameMetrics({
1332
+ ...metrics,
1333
+ callbackMaskChecksum: callbackMasks.checksum,
1334
+ callbackMaskRestoredChecksum: callbackMasks.restoredChecksum,
1335
+ callbackMaskRollbackEquivalent: callbackMasks.rollbackEquivalent,
1336
+ queryOptionsRollbackStable: queryOptions.checksum.length > 0,
1337
+ callbackCollisionEnter: callbackMasks.collisionEnter,
1338
+ callbackCollisionStay: callbackMasks.collisionStay,
1339
+ callbackCollisionExit: callbackMasks.collisionExit,
1340
+ callbackTriggerEnter: callbackMasks.triggerEnter,
1341
+ callbackTriggerStay: callbackMasks.triggerStay,
1342
+ callbackTriggerExit: callbackMasks.triggerExit,
1343
+ callbackDisabledEvents: callbackMasks.disabledEvents,
1344
+ queryOptionsChecksum: queryOptions.checksum,
1345
+ queryOptionsDefaultHitAll: queryOptions.defaultHitAll,
1346
+ queryOptionsExplicitSolidsOnly: queryOptions.explicitSolidsOnly,
1347
+ queryOptionsKindFiltersStable: queryOptions.kindFiltersStable,
1348
+ queryOptionsTriggerSensorFiltersStable: queryOptions.triggerSensorFiltersStable,
1349
+ queryOptionsRaycastCovered: queryOptions.raycastCovered,
1350
+ queryOptionsOverlapCovered: queryOptions.overlapCovered,
1351
+ queryOptionsShapeCastCovered: queryOptions.shapeCastCovered,
1352
+ detailChecksum: details.checksum,
1353
+ detailRestoredChecksum: details.restoredChecksum,
1354
+ detailRollbackEquivalent: details.rollbackEquivalent,
1355
+ detailRayDetailedHits: details.rayDetailedHits,
1356
+ detailShapeCastDetailedHits: details.shapeCastDetailedHits,
1357
+ detailContactDetails: details.contactDetails,
1358
+ detailStableUnderBodyOrderPermutation: details.stableUnderBodyOrderPermutation,
1359
+ detailRayNormalX: details.rayNormalX,
1360
+ detailShapeCastPointX: details.shapeCastPointX,
1361
+ detailContactPenetration: details.contactPenetration,
1362
+ materialChecksum: materials.checksum,
1363
+ materialRestoredChecksum: materials.restoredChecksum,
1364
+ materialCombinedFriction: materials.combinedFriction,
1365
+ materialCombinedRestitution: materials.combinedRestitution,
1366
+ materialNormalVelocityAfterBounce: materials.normalVelocityAfterBounce,
1367
+ materialTangentVelocityAfterFrictionY: materials.tangentVelocityAfterFrictionY,
1368
+ materialTangentVelocityAfterFrictionZ: materials.tangentVelocityAfterFrictionZ,
1369
+ materialRollbackEquivalent: materials.rollbackEquivalent,
1370
+ stackChecksum: stack.checksum,
1371
+ stackRestoredChecksum: stack.restoredChecksum,
1372
+ stackReversedOrderChecksum: stack.reversedOrderChecksum,
1373
+ stackBodies: stack.bodies,
1374
+ stackFrames: stack.frames,
1375
+ stackLayers: stack.stackLayers,
1376
+ stackContactCount: stack.contactCount,
1377
+ stackSolverCorrections: stack.solverCorrections,
1378
+ stackMaxPenetration: stack.maxPenetration,
1379
+ stackMaxHeightDrift: stack.maxHeightDrift,
1380
+ stackSettledDynamicBodies: stack.settledDynamicBodies,
1381
+ stackP95StepCost: stack.p95StepCost,
1382
+ stackP99StepCost: stack.p99StepCost,
1383
+ stackRollbackEquivalent: stack.rollbackEquivalent,
1384
+ stackStableUnderAuthoringOrderPermutation: stack.stableUnderAuthoringOrderPermutation,
1385
+ lagComp3DChecksum: lagComp3D.checksum,
1386
+ lagComp3DRestoredChecksum: lagComp3D.restoredChecksum,
1387
+ lagComp3DPlayers: lagComp3D.players,
1388
+ lagComp3DFrames: lagComp3D.frames,
1389
+ lagComp3DShots: lagComp3D.shots,
1390
+ lagComp3DRifleShots: lagComp3D.rifleShots,
1391
+ lagComp3DShotgunShots: lagComp3D.shotgunShots,
1392
+ lagComp3DBurstShots: lagComp3D.burstShots,
1393
+ lagComp3DHits: lagComp3D.hits,
1394
+ lagComp3DMisses: lagComp3D.misses,
1395
+ lagComp3DOccluded: lagComp3D.occluded,
1396
+ lagComp3DStaleRejected: lagComp3D.staleRejected,
1397
+ lagComp3DFutureRejected: lagComp3D.futureRejected,
1398
+ lagComp3DMultiHitboxQueries: lagComp3D.multiHitboxQueries,
1399
+ lagComp3DAnimatedHitboxSamples: lagComp3D.animatedHitboxSamples,
1400
+ lagComp3DInterpolatedHitboxSamples: lagComp3D.interpolatedHitboxSamples,
1401
+ lagComp3DStaticOcclusionQueries: lagComp3D.staticOcclusionQueries,
1402
+ lagComp3DProxyBodiesCreated: lagComp3D.proxyBodiesCreated,
1403
+ lagComp3DProxyBodiesDestroyed: lagComp3D.proxyBodiesDestroyed,
1404
+ lagComp3DProxyLifecycleBalanced: lagComp3D.proxyLifecycleBalanced,
1405
+ lagComp3DPerClientShotTimesCovered: lagComp3D.perClientShotTimesCovered,
1406
+ lagComp3DRollbackEquivalent: lagComp3D.rollbackEquivalent,
1407
+ lagComp3DApiChecksum: lagComp3DApi.checksum,
1408
+ lagComp3DApiRestoredChecksum: lagComp3DApi.restoredChecksum,
1409
+ lagComp3DApiExactRewindTargets: lagComp3DApi.exactRewindTargets,
1410
+ lagComp3DApiInterpolatedRewindTargets: lagComp3DApi.interpolatedRewindTargets,
1411
+ lagComp3DApiHitReason: lagComp3DApi.hitReason,
1412
+ lagComp3DApiOccludedReason: lagComp3DApi.occludedReason,
1413
+ lagComp3DApiStaleReason: lagComp3DApi.staleReason,
1414
+ lagComp3DApiFutureReason: lagComp3DApi.futureReason,
1415
+ lagComp3DApiProxiesCreated: lagComp3DApi.proxiesCreated,
1416
+ lagComp3DApiProxiesDestroyed: lagComp3DApi.proxiesDestroyed,
1417
+ lagComp3DApiHistoryFrameCount: lagComp3DApi.historyFrameCount,
1418
+ lagComp3DApiPrunedOldFrames: lagComp3DApi.prunedOldFrames,
1419
+ lagComp3DAuthoritativeChecksum: authoritativeLagComp3D.checksum,
1420
+ lagComp3DAuthoritativeHitReason: authoritativeLagComp3D.authorityHitReason,
1421
+ lagComp3DAuthoritativeForgedLatencyReason: authoritativeLagComp3D.forgedLatencyReason,
1422
+ lagComp3DAuthoritativeForgedShotFrameReason: authoritativeLagComp3D.forgedShotFrameReason,
1423
+ lagComp3DAuthoritativeForgedHistoryReason: authoritativeLagComp3D.forgedHistoryReason,
1424
+ lagComp3DAuthoritativeDerivedRewindFrame: authoritativeLagComp3D.derivedRewindFrame,
1425
+ lagComp3DAuthoritativeRawForgedRewindFrame: authoritativeLagComp3D.rawForgedRewindFrame,
1426
+ lagComp3DAuthoritativeTimingRejected: authoritativeLagComp3D.authorityTimingRejected,
1427
+ lagComp3DAuthoritativeRollbackEquivalent: authoritativeLagComp3D.rollbackEquivalent,
1428
+ fullStepChecksum: fullStep.checksum,
1429
+ fullStepRestoredChecksum: fullStep.restoredChecksum,
1430
+ fullStepFrames: fullStep.frames,
1431
+ fullStepBodies: fullStep.bodies,
1432
+ fullStepContactCount: fullStep.contactCount,
1433
+ fullStepQueryCount: fullStep.queryCount,
1434
+ fullStepP95MeasuredStepMs: fullStep.p95MeasuredStepMs,
1435
+ fullStepP99MeasuredStepMs: fullStep.p99MeasuredStepMs,
1436
+ fullStepMaxMeasuredStepMs: fullStep.maxMeasuredStepMs,
1437
+ fullStepWallClockElapsedMs: fullStep.wallClockElapsedMs,
1438
+ fullStepRollbackEquivalent: fullStep.rollbackEquivalent,
1439
+ highBodySample512Checksum: highBodySample512?.checksum ?? '',
1440
+ highBodySample512Frames: highBodySample512?.frames ?? 0,
1441
+ highBodySample2048Checksum: highBodySample2048?.checksum ?? '',
1442
+ highBodySample2048Frames: highBodySample2048?.frames ?? 0,
1443
+ }, requestedFrames, metrics.frames));
1444
+ }
1445
+ function kccCategory(players, requestedFrames, executedFrames, benchmark, noFastStress) {
1446
+ const metrics = (0, movement3d_js_1.runDeterministicKcc3DCrowdFixture)(players, executedFrames, { allowFastStress: !noFastStress });
1447
+ const fullStep = runKcc3DFullStepMeasurementFixture(Math.min(players, 128), Math.min(requestedFrames, 300));
1448
+ const adversarial = (0, movement3d_js_1.runDeterministicKcc3DAdversarialFixture)();
1449
+ const filterForce = (0, movement3d_js_1.runDeterministicKcc3DFilterForceFixture)();
1450
+ const callbackFilter = (0, movement3d_js_1.runDeterministicKcc3DCallbackFilterFixture)();
1451
+ const geometry = (0, movement3d_js_1.runDeterministicKcc3DGeometryFixture)();
1452
+ return categoryReport('kcc3d', (0, canonical_js_1.defaultChecksum)({
1453
+ stress: metrics.checksum,
1454
+ adversarial: adversarial.checksum,
1455
+ filterForce: filterForce.checksum,
1456
+ callbackFilter: callbackFilter.checksum,
1457
+ geometry: geometry.checksum,
1458
+ }), {
1459
+ rollbackEquivalent: metrics.rollbackEquivalent,
1460
+ playersCovered: metrics.players === players,
1461
+ executedRequestedFrames: metrics.frames === requestedFrames,
1462
+ physicsQueriesCovered: metrics.physicsQueryCount >= metrics.players * metrics.frames,
1463
+ collisionCorrectionsCovered: metrics.correctionCount > 0,
1464
+ physicsSlidesCovered: metrics.physicsSlides > 0,
1465
+ slopesCovered: metrics.slopeContacts > 0,
1466
+ stepsCovered: metrics.stepContacts > 0,
1467
+ movingPlatformsCovered: metrics.platformContacts > 0,
1468
+ sweptCollisionsCovered: metrics.sweptCollisions > 0,
1469
+ headClearanceCovered: metrics.headClearanceBlocks > 0,
1470
+ platformVelocityTransferCovered: metrics.platformVelocityTransfers > 0,
1471
+ fullStepMeasuredTimingCovered: fullStep.frames === fullStep.fullStepFrames
1472
+ && fullStep.p95MeasuredStepMs > 0
1473
+ && fullStep.p99MeasuredStepMs > 0,
1474
+ fullStepRollbackEquivalent: fullStep.rollbackEquivalent,
1475
+ fullStepMechanicsCovered: fullStep.correctionCount > 0
1476
+ && fullStep.physicsQueryCount >= fullStep.players * fullStep.frames,
1477
+ adversarialRollbackEquivalent: adversarial.rollbackEquivalent,
1478
+ adversarialThinWallSweepsCovered: adversarial.thinWallSweeps > 0,
1479
+ adversarialDiagonalThinWallSweepsCovered: adversarial.diagonalThinWallSweeps > 0,
1480
+ adversarialLedgeCorrectionsCovered: adversarial.ledgeCorrections > 0,
1481
+ adversarialCeilingBlocksCovered: adversarial.ceilingBlocks > 0,
1482
+ adversarialCornerSweepsCovered: adversarial.cornerSweeps > 0,
1483
+ adversarialMovingPlatformEdgeTransfersCovered: adversarial.movingPlatformEdgeTransfers > 0,
1484
+ adversarialSlopeLimitRejectionsCovered: adversarial.slopeLimitRejections > 0,
1485
+ ignoredColliderFilteringCovered: filterForce.ignoredColliderPassedThrough,
1486
+ solidColliderStillBlocksAfterFilter: filterForce.solidColliderBlocked,
1487
+ externalImpulseCovered: filterForce.externalImpulseApplied,
1488
+ externalImpulseOrderStable: filterForce.filterOrderStable,
1489
+ kccFilterForceRollbackEquivalent: filterForce.rollbackEquivalent,
1490
+ perHitCallbackFilteringCovered: callbackFilter.callbackIgnoredColliderPassedThrough
1491
+ && callbackFilter.callbackLayerFiltered
1492
+ && callbackFilter.callbackNormalFiltered
1493
+ && callbackFilter.callbackRejectedHits > 0,
1494
+ perHitCallbackSolidStillBlocks: callbackFilter.callbackSolidColliderBlocked
1495
+ && callbackFilter.callbackAcceptedHits > 0,
1496
+ perHitCallbackMetadataCovered: callbackFilter.callbackMetadataCovered
1497
+ && callbackFilter.callbackInvocations > 0,
1498
+ perHitCallbackOrderStable: callbackFilter.callbackOrderStable,
1499
+ perHitCallbackRejectsMutableState: callbackFilter.mutableFilterRejected,
1500
+ perHitCallbackRollbackEquivalent: callbackFilter.rollbackEquivalent,
1501
+ controllerGeometryConfigurable: geometry.defaultGeometryPreserved
1502
+ && geometry.geometryMetadataStable,
1503
+ controllerRadiusAffectsCollision: geometry.smallRadiusPassesNarrowGap
1504
+ && geometry.largeRadiusBlockedByNarrowGap,
1505
+ controllerHeightAffectsHeadClearance: geometry.tallBodyHeadBlocked
1506
+ && geometry.shortBodyClearsLowCeiling,
1507
+ controllerSkinWidthAffectsCollision: geometry.skinWidthExpandsCollisionShape,
1508
+ controllerGeometryRollbackEquivalent: geometry.rollbackEquivalent,
1509
+ ...(metrics.extrapolatedStress ? {} : {
1510
+ fullKccRequiredProofCovered: metrics.fullKccStepFrames === metrics.frames,
1511
+ }),
1512
+ optimizedKccBenchmarkTailDeclared: benchmark && !noFastStress
1513
+ ? metrics.extrapolatedStress && metrics.optimizedStressFrames > 0
1514
+ : metrics.extrapolatedStress === false && metrics.optimizedStressFrames === 0,
1515
+ noFastStressHonored: noFastStress
1516
+ ? metrics.fullKccStepFrames === metrics.frames && metrics.optimizedStressFrames === 0 && metrics.extrapolatedStress === false
1517
+ : true,
1518
+ optimizedStressFramesDeclared: metrics.optimizedStressFrames === Math.max(0, metrics.frames - metrics.fullKccStepFrames),
1519
+ kccStressProofMode: metrics.extrapolatedStress ? 'optimized-tail' : 'full-step',
1520
+ }, withFrameMetrics({
1521
+ ...metrics,
1522
+ fullStepChecksum: fullStep.checksum,
1523
+ fullStepRestoredChecksum: fullStep.restoredChecksum,
1524
+ fullStepPlayers: fullStep.players,
1525
+ fullStepFrames: fullStep.frames,
1526
+ fullStepCorrectionCount: fullStep.correctionCount,
1527
+ fullStepPhysicsQueryCount: fullStep.physicsQueryCount,
1528
+ fullStepP95MeasuredStepMs: fullStep.p95MeasuredStepMs,
1529
+ fullStepP99MeasuredStepMs: fullStep.p99MeasuredStepMs,
1530
+ fullStepMaxMeasuredStepMs: fullStep.maxMeasuredStepMs,
1531
+ fullStepWallClockElapsedMs: fullStep.wallClockElapsedMs,
1532
+ fullStepRollbackEquivalent: fullStep.rollbackEquivalent,
1533
+ adversarialChecksum: adversarial.checksum,
1534
+ adversarialRestoredChecksum: adversarial.restoredChecksum,
1535
+ adversarialRollbackEquivalent: adversarial.rollbackEquivalent,
1536
+ adversarialThinWallSweeps: adversarial.thinWallSweeps,
1537
+ adversarialDiagonalThinWallSweeps: adversarial.diagonalThinWallSweeps,
1538
+ adversarialLedgeCorrections: adversarial.ledgeCorrections,
1539
+ adversarialCeilingBlocks: adversarial.ceilingBlocks,
1540
+ adversarialCornerSweeps: adversarial.cornerSweeps,
1541
+ adversarialMovingPlatformEdgeTransfers: adversarial.movingPlatformEdgeTransfers,
1542
+ adversarialSlopeLimitRejections: adversarial.slopeLimitRejections,
1543
+ ignoredColliderCollisionEvents: filterForce.ignoredCollisionEvents,
1544
+ solidColliderCollisionEvents: filterForce.solidCollisionEvents,
1545
+ externalImpulseEvents: filterForce.externalImpulseEvents,
1546
+ kccFilterForceRollbackEquivalent: filterForce.rollbackEquivalent,
1547
+ kccCallbackFilterChecksum: callbackFilter.checksum,
1548
+ kccCallbackFilterRestoredChecksum: callbackFilter.restoredChecksum,
1549
+ kccCallbackFilterRollbackEquivalent: callbackFilter.rollbackEquivalent,
1550
+ kccCallbackFilterInvocations: callbackFilter.callbackInvocations,
1551
+ kccCallbackFilterRejectedHits: callbackFilter.callbackRejectedHits,
1552
+ kccCallbackFilterAcceptedHits: callbackFilter.callbackAcceptedHits,
1553
+ kccCallbackFilterIgnoredPassedThrough: callbackFilter.callbackIgnoredColliderPassedThrough,
1554
+ kccCallbackFilterSolidBlocked: callbackFilter.callbackSolidColliderBlocked,
1555
+ kccCallbackFilterLayerFiltered: callbackFilter.callbackLayerFiltered,
1556
+ kccCallbackFilterNormalFiltered: callbackFilter.callbackNormalFiltered,
1557
+ kccCallbackFilterOrderStable: callbackFilter.callbackOrderStable,
1558
+ kccCallbackFilterMetadataCovered: callbackFilter.callbackMetadataCovered,
1559
+ kccCallbackFilterMutableRejected: callbackFilter.mutableFilterRejected,
1560
+ kccGeometryChecksum: geometry.checksum,
1561
+ kccGeometryRestoredChecksum: geometry.restoredChecksum,
1562
+ kccGeometryRollbackEquivalent: geometry.rollbackEquivalent,
1563
+ kccGeometryDefaultPreserved: geometry.defaultGeometryPreserved,
1564
+ kccGeometrySmallRadiusPassesNarrowGap: geometry.smallRadiusPassesNarrowGap,
1565
+ kccGeometryLargeRadiusBlockedByNarrowGap: geometry.largeRadiusBlockedByNarrowGap,
1566
+ kccGeometryTallBodyHeadBlocked: geometry.tallBodyHeadBlocked,
1567
+ kccGeometryShortBodyClearsLowCeiling: geometry.shortBodyClearsLowCeiling,
1568
+ kccGeometrySkinWidthExpandsCollisionShape: geometry.skinWidthExpandsCollisionShape,
1569
+ kccGeometryMetadataStable: geometry.geometryMetadataStable,
1570
+ }, requestedFrames, metrics.frames));
1571
+ }
1572
+ function runPhysics3DFullStepMeasurementFixture(frames) {
1573
+ let world = (0, physics3d_js_1.createDeterministicPhysicsWorld3D)(createFullStepPhysicsBodies3D(96));
1574
+ let snapshot = world;
1575
+ let contactCount = 0;
1576
+ let queryCount = 0;
1577
+ const timings = [];
1578
+ const startedAt = engineCompleteNowMs();
1579
+ for (let frame = 0; frame < frames; frame += 1) {
1580
+ if (frame === Math.floor(frames / 2)) {
1581
+ snapshot = world;
1582
+ }
1583
+ const stepStartedAt = engineCompleteNowMs();
1584
+ const result = (0, physics3d_js_1.stepDeterministicPhysicsWorld3D)(world, {
1585
+ computeChecksum: false,
1586
+ scheduledQueries: [{
1587
+ id: `full-step-ray-${frame}`,
1588
+ phase: 'pre-physics',
1589
+ query: { x: -4, y: 0, z: 0, dx: 1, dy: 0, dz: 0, maxDistance: 32, layerMask: 0b1111 },
1590
+ }],
1591
+ });
1592
+ timings.push(engineCompleteNowMs() - stepStartedAt);
1593
+ world = result.world;
1594
+ contactCount += result.narrowphaseContacts;
1595
+ queryCount += result.scheduledQueryResults.length;
1596
+ }
1597
+ const checksum = (0, canonical_js_1.defaultChecksum)(world);
1598
+ let restored = snapshot;
1599
+ for (let frame = Math.floor(frames / 2); frame < frames; frame += 1) {
1600
+ restored = (0, physics3d_js_1.stepDeterministicPhysicsWorld3D)(restored, {
1601
+ computeChecksum: false,
1602
+ scheduledQueries: [{
1603
+ id: `full-step-ray-${frame}`,
1604
+ phase: 'pre-physics',
1605
+ query: { x: -4, y: 0, z: 0, dx: 1, dy: 0, dz: 0, maxDistance: 32, layerMask: 0b1111 },
1606
+ }],
1607
+ }).world;
1608
+ }
1609
+ return {
1610
+ checksum,
1611
+ restoredChecksum: (0, canonical_js_1.defaultChecksum)(restored),
1612
+ rollbackEquivalent: checksum === (0, canonical_js_1.defaultChecksum)(restored),
1613
+ bodies: world.bodies.length,
1614
+ frames,
1615
+ fullStepFrames: frames,
1616
+ contactCount,
1617
+ queryCount,
1618
+ p95MeasuredStepMs: roundMetric(percentileNumber(timings, 95), 6),
1619
+ p99MeasuredStepMs: roundMetric(percentileNumber(timings, 99), 6),
1620
+ maxMeasuredStepMs: roundMetric(timings.reduce((max, value) => Math.max(max, value), 0), 6),
1621
+ wallClockElapsedMs: roundMetric(engineCompleteNowMs() - startedAt, 4),
1622
+ };
1623
+ }
1624
+ function runKcc3DFullStepMeasurementFixture(players, frames) {
1625
+ let bodies = Array.from({ length: players }, (_, slot) => ({
1626
+ x: slot % 16,
1627
+ y: slot % 17 === 0 ? 4 : 0,
1628
+ z: Math.floor(slot / 16),
1629
+ vx: 0,
1630
+ vy: slot % 17 === 0 ? -1 : 0,
1631
+ vz: 0,
1632
+ grounded: slot % 17 !== 0,
1633
+ coyoteFrames: slot % 17 === 0 ? 0 : 4,
1634
+ jumpBufferFrames: 0,
1635
+ }));
1636
+ const kccWorld = {
1637
+ minX: -8,
1638
+ maxX: 48,
1639
+ minY: 0,
1640
+ maxY: 32,
1641
+ minZ: -8,
1642
+ maxZ: 32,
1643
+ maxSlopeRisePerUnit: 1,
1644
+ stepHeight: 2,
1645
+ slopes: [{ id: 'full-slope', minX: -2, maxX: 4, minZ: -8, maxZ: 8, baseY: 0, risePerUnitX: 1 }],
1646
+ steps: [{ id: 'full-step', minX: 18, maxX: 22, minZ: -8, maxZ: 12, height: 2 }],
1647
+ movingPlatforms: [{ id: 'full-platform', minX: 30, maxX: 34, minZ: -4, maxZ: 12, y: 3, dxPerFrame: 1, dzPerFrame: 0 }],
1648
+ };
1649
+ const physics = (0, physics3d_js_1.createDeterministicPhysicsWorld3D)(createFullStepKccObstacles3D());
1650
+ let snapshot = bodies;
1651
+ let correctionCount = 0;
1652
+ let physicsQueryCount = 0;
1653
+ const timings = [];
1654
+ const startedAt = engineCompleteNowMs();
1655
+ for (let frame = 0; frame < frames; frame += 1) {
1656
+ if (frame === Math.floor(frames / 2)) {
1657
+ snapshot = bodies.map((body) => ({ ...body }));
1658
+ }
1659
+ const stepStartedAt = engineCompleteNowMs();
1660
+ bodies = bodies.map((body, slot) => {
1661
+ const result = (0, movement3d_js_1.stepDeterministicKcc3D)(body, {
1662
+ moveX: (slot + frame) % 3 - 1,
1663
+ moveZ: (slot * 2 + frame) % 3 - 1,
1664
+ jumpPressed: (slot + frame) % 101 === 0,
1665
+ }, kccWorld, { frame, physics });
1666
+ correctionCount += result.correctionCount;
1667
+ physicsQueryCount += result.physicsQueryCount;
1668
+ return result.body;
1669
+ });
1670
+ timings.push(engineCompleteNowMs() - stepStartedAt);
1671
+ }
1672
+ const checksum = (0, canonical_js_1.defaultChecksum)(bodies);
1673
+ let restored = snapshot;
1674
+ for (let frame = Math.floor(frames / 2); frame < frames; frame += 1) {
1675
+ restored = restored.map((body, slot) => (0, movement3d_js_1.stepDeterministicKcc3D)(body, {
1676
+ moveX: (slot + frame) % 3 - 1,
1677
+ moveZ: (slot * 2 + frame) % 3 - 1,
1678
+ jumpPressed: (slot + frame) % 101 === 0,
1679
+ }, kccWorld, { frame, physics }).body);
1680
+ }
1681
+ return {
1682
+ checksum,
1683
+ restoredChecksum: (0, canonical_js_1.defaultChecksum)(restored),
1684
+ rollbackEquivalent: checksum === (0, canonical_js_1.defaultChecksum)(restored),
1685
+ players,
1686
+ frames,
1687
+ fullStepFrames: frames,
1688
+ correctionCount,
1689
+ physicsQueryCount,
1690
+ p95MeasuredStepMs: roundMetric(percentileNumber(timings, 95), 6),
1691
+ p99MeasuredStepMs: roundMetric(percentileNumber(timings, 99), 6),
1692
+ maxMeasuredStepMs: roundMetric(timings.reduce((max, value) => Math.max(max, value), 0), 6),
1693
+ wallClockElapsedMs: roundMetric(engineCompleteNowMs() - startedAt, 4),
1694
+ };
1695
+ }
1696
+ function createFullStepPhysicsBodies3D(count) {
1697
+ return Array.from({ length: count }, (_, index) => ({
1698
+ id: `full-body-${index}`,
1699
+ kind: index === 0 ? 'static' : 'dynamic',
1700
+ x: index === 0 ? 4 : (index % 12) - 6,
1701
+ y: Math.floor(index / 12) % 2,
1702
+ z: Math.floor(index / 24),
1703
+ vx: index === 0 ? 0 : (index % 3) - 1,
1704
+ vy: 0,
1705
+ vz: index === 0 ? 0 : ((index + 1) % 3) - 1,
1706
+ shape: index % 5 === 0 ? { type: 'sphere', radius: 1 } : { type: 'box', halfX: 1, halfY: 1, halfZ: 1 },
1707
+ layer: 1 << (index % 4),
1708
+ mask: 0b1111,
1709
+ material: { friction: index % 7, restitution: index % 3 },
1710
+ }));
1711
+ }
1712
+ function createFullStepKccObstacles3D() {
1713
+ return [3, 7, 11, 15, 19].flatMap((x, index) => [
1714
+ {
1715
+ id: `full-kcc-wall-${index}`,
1716
+ kind: 'static',
1717
+ x,
1718
+ y: 0,
1719
+ z: index,
1720
+ vx: 0,
1721
+ vy: 0,
1722
+ vz: 0,
1723
+ shape: { type: 'box', halfX: 0.75, halfY: 3, halfZ: 1 },
1724
+ layer: 1,
1725
+ mask: 1,
1726
+ },
1727
+ ]);
1728
+ }
1729
+ function navmeshCategory(players, requestedFrames, executedFrames) {
1730
+ const metrics = (0, navmesh_js_1.runDeterministicNavmeshStress)(players, executedFrames);
1731
+ const imported = (0, navmesh_js_1.runDeterministicNavmeshImportTraversalFixture)();
1732
+ const layered = (0, navmesh_js_1.runDeterministicNavmeshLayered3DFixture)();
1733
+ const velocityObstacle = (0, navmesh_js_1.runDeterministicNavmeshVelocityObstacleFixture)();
1734
+ return categoryReport('navmesh', (0, canonical_js_1.defaultChecksum)({ stress: metrics.checksum, imported: imported.checksum, layered: layered.checksum, velocityObstacle: velocityObstacle.checksum }), {
1735
+ rollbackEquivalent: metrics.rollbackEquivalent,
1736
+ agentsCovered: metrics.agents === players,
1737
+ executedRequestedFrames: metrics.frames === requestedFrames,
1738
+ replansObserved: metrics.replans > 0,
1739
+ waypointProgressionObserved: metrics.waypointAdvances > 0,
1740
+ avoidanceCovered: metrics.avoidanceCorrections > 0,
1741
+ radiusAvoidanceCovered: metrics.radiusAvoidanceCorrections > 0,
1742
+ velocityObstacleAvoidanceCovered: metrics.velocityObstacleAvoidanceCorrections > 0
1743
+ && metrics.avoidanceSpeedReductions > 0
1744
+ && velocityObstacle.movingObstacleSpeedReduction,
1745
+ agentVelocityObstacleAvoidanceCovered: metrics.agentVelocityObstacleAvoidanceCorrections > 0
1746
+ && metrics.agentAvoidancePriorityYields > 0
1747
+ && metrics.agentAvoidanceSpeedReductions > 0,
1748
+ velocityObstaclePredictionCovered: velocityObstacle.predictedFuturePositionAvoided,
1749
+ velocityObstacleOrderStable: velocityObstacle.obstacleOrderStable,
1750
+ velocityObstacleValidationRejected: velocityObstacle.obstacleValidationRejected,
1751
+ velocityObstacleRollbackEquivalent: velocityObstacle.rollbackEquivalent,
1752
+ pointPathingCovered: metrics.pointPathFound,
1753
+ nearestPolygonLookupCovered: metrics.pointLookupStable,
1754
+ importedCookOrderStable: imported.importOrderStable,
1755
+ importedPortalAndSpawnCovered: imported.portalCount > 0 && imported.spawnMarkerCount > 0,
1756
+ importedValidationFailuresCovered: imported.missingRegionRejected && imported.missingLinkRejected && imported.missingSpawnRejected,
1757
+ offMeshTraversalLifecycleCovered: imported.offMeshEnterEvents > 0
1758
+ && imported.offMeshTraverseEvents > 0
1759
+ && imported.offMeshExitEvents > 0
1760
+ && imported.offMeshCompleteEvents > 0,
1761
+ offMeshTraversalRollbackEquivalent: imported.rollbackEquivalent,
1762
+ importedPointPathCovered: imported.pointPathFound && imported.pointPathHash.length > 0,
1763
+ layered3DStackedOverlapCovered: layered.stackedOverlapAccepted,
1764
+ layered3DSameLayerOverlapRejected: layered.sameLayerOverlapRejected,
1765
+ layered3DLookupDisambiguated: layered.layerDisambiguationStable,
1766
+ layered3DOffMeshTraversalCovered: layered.verticalOffMeshTraversals > 0,
1767
+ layered3DRollbackEquivalent: layered.rollbackEquivalent,
1768
+ }, withFrameMetrics({
1769
+ ...metrics,
1770
+ importedNavmeshHash: imported.importedHash,
1771
+ importedNavmeshPermutedHash: imported.permutedHash,
1772
+ importedNavmeshImportOrderStable: imported.importOrderStable,
1773
+ importedNavmeshPortalCount: imported.portalCount,
1774
+ importedNavmeshSpawnMarkerCount: imported.spawnMarkerCount,
1775
+ importedNavmeshMissingRegionRejected: imported.missingRegionRejected,
1776
+ importedNavmeshMissingLinkRejected: imported.missingLinkRejected,
1777
+ importedNavmeshMissingSpawnRejected: imported.missingSpawnRejected,
1778
+ importedNavmeshOffMeshEnterEvents: imported.offMeshEnterEvents,
1779
+ importedNavmeshOffMeshTraverseEvents: imported.offMeshTraverseEvents,
1780
+ importedNavmeshOffMeshExitEvents: imported.offMeshExitEvents,
1781
+ importedNavmeshOffMeshCompleteEvents: imported.offMeshCompleteEvents,
1782
+ importedNavmeshOffMeshCommandIdStable: imported.offMeshCommandIdStable,
1783
+ importedNavmeshOffMeshTraversalFrames: imported.offMeshTraversalFrames,
1784
+ importedNavmeshPointPathFound: imported.pointPathFound,
1785
+ importedNavmeshPointPathHash: imported.pointPathHash,
1786
+ importedNavmeshRollbackEquivalent: imported.rollbackEquivalent,
1787
+ layeredNavmeshHash: layered.cookedHash,
1788
+ layeredNavmeshPermutedHash: layered.permutedHash,
1789
+ layeredNavmeshCookOrderStable: layered.cookOrderStable,
1790
+ layeredNavmeshLowerLookupId: layered.lowerLookupId,
1791
+ layeredNavmeshUpperLookupId: layered.upperLookupId,
1792
+ layeredNavmeshLowerPathHash: layered.lowerPathHash,
1793
+ layeredNavmeshUpperPathHash: layered.upperPathHash,
1794
+ layeredNavmeshVerticalOffMeshTraversals: layered.verticalOffMeshTraversals,
1795
+ layeredNavmeshUpperAgentZ: layered.upperAgentZ,
1796
+ layeredNavmeshRollbackEquivalent: layered.rollbackEquivalent,
1797
+ velocityObstacleChecksum: velocityObstacle.checksum,
1798
+ velocityObstacleRestoredChecksum: velocityObstacle.restoredChecksum,
1799
+ velocityObstacleRollbackEquivalent: velocityObstacle.rollbackEquivalent,
1800
+ velocityObstacleSpeedReduction: velocityObstacle.movingObstacleSpeedReduction,
1801
+ velocityObstacleFuturePrediction: velocityObstacle.predictedFuturePositionAvoided,
1802
+ velocityObstacleAuthoredSpeedRestored: velocityObstacle.authoredSpeedRestored,
1803
+ velocityObstacleOrderStable: velocityObstacle.obstacleOrderStable,
1804
+ velocityObstacleValidationRejected: velocityObstacle.obstacleValidationRejected,
1805
+ velocityObstacleFixtureCorrections: velocityObstacle.velocityObstacleAvoidanceCorrections,
1806
+ velocityObstacleFixtureSpeedReductions: velocityObstacle.avoidanceSpeedReductions,
1807
+ }, requestedFrames, metrics.frames));
1808
+ }
1809
+ function botCategory(players, requestedFrames, executedFrames) {
1810
+ const metrics = (0, bot_documents_js_1.runDeterministicBotDocumentFixture)(players, executedFrames);
1811
+ return categoryReport('bot-documents', metrics.checksum, {
1812
+ compiledAssetExists: metrics.compiledAssetHash.length > 0,
1813
+ botReplacementSlotsPresent: metrics.botReplacementSlots >= Math.floor(players / 2),
1814
+ debugTracePresent: metrics.debugTraceCount > 0,
1815
+ executedRequestedFrames: metrics.frames === requestedFrames,
1816
+ behaviorDecoratorsCovered: metrics.behaviorDecoratorTicks > 0,
1817
+ behaviorRunningCovered: metrics.behaviorRunningTicks > 0,
1818
+ behaviorResumeCovered: metrics.behaviorResumeTicks > 0,
1819
+ behaviorServicesCovered: metrics.behaviorServiceTicks > 0,
1820
+ utilityCurvesCovered: metrics.utilityCurveSelections > 0,
1821
+ utilityNestedCovered: metrics.utilityNestedSelections > 0,
1822
+ utilityMomentumCovered: metrics.utilityMomentumSelections > 0,
1823
+ utilityCooldownCovered: metrics.utilityCooldownSuppressions > 0,
1824
+ }, withFrameMetrics(metrics, requestedFrames, metrics.frames));
1825
+ }
1826
+ function animationCategory(requestedFrames, executedFrames) {
1827
+ const metrics = (0, animation_js_1.runDeterministicAnimationFixture)(executedFrames);
1828
+ return categoryReport('animation', metrics.checksum, {
1829
+ rollbackEquivalent: metrics.rollbackEquivalent,
1830
+ animationEventsEmitted: metrics.emittedEvents > 0,
1831
+ cookedAssetExists: metrics.cookedAssetHash.length > 0,
1832
+ executedRequestedFrames: executedFrames === requestedFrames,
1833
+ exitFramesCovered: metrics.exitFrameTransitions > 0,
1834
+ transitionBlendCovered: metrics.transitionBlendFrames > 0,
1835
+ triggerLatchCovered: metrics.triggerLatchCount > 0,
1836
+ normalizedClipTimeCovered: metrics.normalizedTimeHash.length > 0,
1837
+ sampledPoseCovered: metrics.poseHash.length > 0,
1838
+ blendWeightCovered: metrics.blendWeightHash.length > 0,
1839
+ blendTreeCovered: metrics.blendTreeFrames > 0,
1840
+ animationLayersCovered: metrics.layerPoseFrames > 0,
1841
+ rootMotionCovered: metrics.rootMotionFrames > 0,
1842
+ eventReconstructionCovered: metrics.reconstructedEvents > 0 && metrics.reconstructedEventHash.length > 0,
1843
+ }, withFrameMetrics({ ...metrics, frames: executedFrames }, requestedFrames, executedFrames));
1844
+ }
1845
+ function configCategory() {
1846
+ const metrics = (0, config_bundle_js_1.runDeterministicConfigBundleFixture)();
1847
+ return categoryReport('config-bundle', metrics.configHash, {
1848
+ verifies: metrics.result === 'pass',
1849
+ prototypesMaterialize: metrics.materializedEntityCount > 0,
1850
+ migrationsCovered: metrics.migrationResult === 'migrated',
1851
+ }, withFrameMetrics({
1852
+ assetDbHash: metrics.assetDbHash,
1853
+ prototypeCount: metrics.prototypeCount,
1854
+ materializedEntityCount: metrics.materializedEntityCount,
1855
+ migrationResult: metrics.migrationResult,
1856
+ }, 1, 1));
1857
+ }
1858
+ function authorityCategory(players, requestedFrames, executedFrames, seed) {
1859
+ const metrics = (0, local_authority_js_1.runDeterministicLocalAuthorityFixture)(players, executedFrames, seed);
1860
+ const wire = (0, local_authority_wire_js_1.runDeterministicLocalAuthorityWireFixture)(players, Math.min(executedFrames, 512), seed + 31);
1861
+ const multiclient = (0, multiclient_authority_js_1.runDeterministicMulticlientAuthorityFixture)(players, Math.min(executedFrames, 5_000), seed + 47);
1862
+ const policy = (0, local_authority_js_1.runDeterministicLocalAuthorityRuntimePolicyFixture)();
1863
+ const offlineUpgrade = (0, local_authority_js_1.runDeterministicOfflineToAuthorityUpgradeFixture)(players, Math.min(executedFrames, 5_000), seed + 59);
1864
+ const replayMinimizer = (0, local_authority_js_1.runDeterministicLocalAuthorityReplayMinimizerFixture)(players, Math.min(executedFrames, 1_000), seed + 67);
1865
+ return categoryReport('local-authority', (0, canonical_js_1.defaultChecksum)({
1866
+ authority: metrics.authorityChecksum,
1867
+ wire: wire.checksum,
1868
+ multiclient: multiclient.checksum,
1869
+ policy: policy.checksum,
1870
+ offlineUpgrade: offlineUpgrade.checksum,
1871
+ replayMinimizer: replayMinimizer.checksum,
1872
+ }), {
1873
+ convergence: metrics.convergence,
1874
+ projectedChecksumsMatch: metrics.authorityProjectionChecksum === metrics.clientProjectionChecksum,
1875
+ reconnectsCovered: metrics.reconnects > 0,
1876
+ lateJoinReconstructionCovered: metrics.lateJoins > 0 && metrics.lateJoinReconstructions === metrics.lateJoins && metrics.absentBeforeJoinInputs > 0,
1877
+ spectatorReconstructionCovered: metrics.spectators > 0 && metrics.spectatorReconstructions === metrics.spectators,
1878
+ hostileMessagesRejected: metrics.rejectedMessages > 0,
1879
+ migrationCovered: metrics.migrationFrame > 0,
1880
+ migrationPersistenceCovered: metrics.migrationPersistedSections >= 5 && metrics.migrationQueueRestored && metrics.migrationCommandTimelineRestored && metrics.slotReservationsRestored,
1881
+ typedWireProtocolCovered: wire.encodedEnvelopes > 0 && wire.decodedEnvelopes === wire.encodedEnvelopes,
1882
+ wireAckCorrectionSnapshotCovered: wire.ackEnvelopes > 0 && wire.correctionEnvelopes > 0 && wire.snapshotEnvelopes > 0 && wire.correctionsApplied > 0 && wire.snapshotsApplied > 0,
1883
+ wireCommandBundleCovered: wire.commandEnvelopes > 0 && wire.acceptedCommands > 0,
1884
+ wireCommandBundleRejectedHostile: wire.rejectedCommands > 0,
1885
+ wireSnapshotNegotiationCovered: wire.snapshotRequestEnvelopes > 0
1886
+ && wire.snapshotOfferEnvelopes > 0
1887
+ && wire.snapshotChunkEnvelopes > 0
1888
+ && wire.snapshotCompleteEnvelopes > 0
1889
+ && wire.snapshotNegotiationCompletesApplied > 0,
1890
+ wireSnapshotNegotiationRejectedHostile: wire.snapshotDescriptorMismatchRejected > 0
1891
+ && wire.snapshotChunkChecksumRejected > 0
1892
+ && wire.snapshotMissingChunkRejected > 0
1893
+ && wire.staleSnapshotOfferRejected > 0,
1894
+ wireHostileRejectionCovered: wire.malformedRejected >= 3 && wire.forgedSlotRejected > 0 && wire.staleFrameRejected > 0 && wire.futureFrameRejected > 0 && wire.oversizedRejected > 0 && wire.invalidInputIdRejected > 0,
1895
+ wireDuplicateReplayRejected: wire.duplicateInputRejected > 0,
1896
+ wireSequenceStatefulRejectionCovered: wire.reorderedSequenceAccepted > 0 && wire.duplicateSequenceRejected > 0 && wire.replayedEnvelopeRejected > 0,
1897
+ wireStaleControlRejectionCovered: wire.staleAckRejected > 0 && wire.staleCorrectionRejected > 0 && wire.staleSnapshotRejected > 0,
1898
+ wireSenderAuthCovered: wire.wireAuthSignedEnvelopes > 0,
1899
+ wireSenderAuthRejectedHostile: wire.wireAuthMissingRejected > 0
1900
+ && wire.wireAuthSenderMismatchRejected > 0
1901
+ && wire.wireAuthSignatureRejected > 0,
1902
+ wireSenderAuthHmacSha256Covered: wire.wireAuthHmacSha256Covered,
1903
+ wireAuthorityAuthRejectedHostile: wire.forgedAuthorityCorrectionRejected > 0 && wire.forgedAuthoritySnapshotRejected > 0,
1904
+ wireSnapshotIdentityRequired: wire.snapshotIdentityRequiredRejected > 0,
1905
+ multiclientPredictedRunnersCovered: multiclient.predictedClientRunners === players,
1906
+ multiclientAuthoritySnapshotsCovered: multiclient.authoritySnapshotsDelivered >= players * multiclient.frames,
1907
+ multiclientCorrectionsCovered: multiclient.correctionsApplied > 0 && multiclient.predictionMismatches > 0,
1908
+ multiclientRollbackResimulationCovered: multiclient.resimulatedFrames > 0 && multiclient.rollbackDepthP95 > 0,
1909
+ multiclientConvergenceCovered: multiclient.convergence && multiclient.allClientsReachedFinalAuthorityFrame,
1910
+ multiclientRuntimeBackedClientsCovered: multiclient.runtimeBackedClients === players,
1911
+ multiclientRuntimeBackedReplayVerified: multiclient.runtimeBackedReplayVerifiedClients === players && multiclient.runtimeBackedConvergence,
1912
+ multiclientRuntimeBackedCorrectionsCovered: multiclient.runtimeBackedCorrectionsApplied > 0 && multiclient.runtimeBackedPredictionMismatches > 0,
1913
+ multiclientRuntimeBackedResimulationCovered: multiclient.runtimeBackedResimulatedFrames > 0,
1914
+ rollbackWindowLateInputAccepted: policy.lateWithinRollbackWindowAccepted,
1915
+ rollbackWindowExpiredInputRejected: policy.expiredLateInputRejected,
1916
+ strictStaleInputRejected: policy.strictStaleInputRejected,
1917
+ structuredAuthorityInputDataPreserved: policy.structuredInputDataPreserved,
1918
+ malformedStructuredAuthorityInputRejected: policy.malformedStructuredInputRejected,
1919
+ authorityPolicyRollbackEquivalent: policy.rollbackEquivalent,
1920
+ nonCommutativeLateInputResimulated: policy.nonCommutativeLateInputResimulated,
1921
+ nonCommutativeAppendOnlyDiverged: policy.nonCommutativeAppendOnlyDiverged,
1922
+ offlineSessionUpgradeStateMatch: offlineUpgrade.stateMatch,
1923
+ offlineSessionUpgradeReplayVerified: offlineUpgrade.replayVerified,
1924
+ offlineSessionUpgradeRestoreVerified: offlineUpgrade.restoreVerified,
1925
+ offlineSessionUpgradeAuthorityConverged: offlineUpgrade.authorityConvergence,
1926
+ offlineSessionUpgradeInputTranscriptCovered: offlineUpgrade.inputRows === offlineUpgrade.players * offlineUpgrade.frames,
1927
+ authorityReplayBundleVerified: replayMinimizer.validReplayVerified,
1928
+ authorityReplayDesyncDetected: replayMinimizer.corruptedReplayFailed && replayMinimizer.mismatchFrame > 0,
1929
+ authorityReplayMinimizedArtifactVerified: replayMinimizer.minimizedReplayFailed
1930
+ && replayMinimizer.minimizedMismatchFrame === replayMinimizer.mismatchFrame,
1931
+ authorityReplayMinimizedArtifactReduced: replayMinimizer.minimizedReplayBytes < replayMinimizer.originalReplayBytes,
1932
+ authorityReplayMinimizedArtifactPruned: replayMinimizer.removedInputFrames > 0
1933
+ && replayMinimizer.removedSnapshots > 0
1934
+ && replayMinimizer.removedChecksumFrames > 0,
1935
+ }, withFrameMetrics({
1936
+ authorityChecksum: metrics.authorityChecksum,
1937
+ clientChecksum: metrics.clientChecksum,
1938
+ authorityProjectionChecksum: metrics.authorityProjectionChecksum,
1939
+ clientProjectionChecksum: metrics.clientProjectionChecksum,
1940
+ convergence: metrics.convergence,
1941
+ players: metrics.players,
1942
+ frames: metrics.frames,
1943
+ reconnects: metrics.reconnects,
1944
+ lateJoins: metrics.lateJoins,
1945
+ spectators: metrics.spectators,
1946
+ absentBeforeJoinInputs: metrics.absentBeforeJoinInputs,
1947
+ lateJoinReconstructions: metrics.lateJoinReconstructions,
1948
+ spectatorReconstructions: metrics.spectatorReconstructions,
1949
+ rejectedMessages: metrics.rejectedMessages,
1950
+ migrationFrame: metrics.migrationFrame,
1951
+ migrationPersistedSections: metrics.migrationPersistedSections,
1952
+ migrationQueueRestored: metrics.migrationQueueRestored,
1953
+ migrationCommandTimelineRestored: metrics.migrationCommandTimelineRestored,
1954
+ slotReservationsRestored: metrics.slotReservationsRestored,
1955
+ inputDelayP95: metrics.inputDelayP95,
1956
+ rollbackDepthP95: metrics.rollbackDepthP95,
1957
+ clockDriftP95: metrics.clockDriftP95,
1958
+ p95FrameCost: metrics.p95FrameCost,
1959
+ p99FrameCost: metrics.p99FrameCost,
1960
+ wireChecksum: wire.checksum,
1961
+ wireFrames: wire.frames,
1962
+ wireEncodedEnvelopes: wire.encodedEnvelopes,
1963
+ wireDecodedEnvelopes: wire.decodedEnvelopes,
1964
+ wireAcceptedInputs: wire.acceptedInputs,
1965
+ wireRejectedInputs: wire.rejectedInputs,
1966
+ wireCommandEnvelopes: wire.commandEnvelopes,
1967
+ wireAcceptedCommands: wire.acceptedCommands,
1968
+ wireRejectedCommands: wire.rejectedCommands,
1969
+ wireSnapshotRequestEnvelopes: wire.snapshotRequestEnvelopes,
1970
+ wireSnapshotOfferEnvelopes: wire.snapshotOfferEnvelopes,
1971
+ wireSnapshotChunkEnvelopes: wire.snapshotChunkEnvelopes,
1972
+ wireSnapshotCompleteEnvelopes: wire.snapshotCompleteEnvelopes,
1973
+ wireSnapshotNegotiationCompletesApplied: wire.snapshotNegotiationCompletesApplied,
1974
+ wireSnapshotNegotiationRejected: wire.snapshotNegotiationRejected,
1975
+ wireSnapshotDescriptorMismatchRejected: wire.snapshotDescriptorMismatchRejected,
1976
+ wireSnapshotChunkChecksumRejected: wire.snapshotChunkChecksumRejected,
1977
+ wireSnapshotMissingChunkRejected: wire.snapshotMissingChunkRejected,
1978
+ wireStaleSnapshotOfferRejected: wire.staleSnapshotOfferRejected,
1979
+ wireMalformedRejected: wire.malformedRejected,
1980
+ wireForgedSlotRejected: wire.forgedSlotRejected,
1981
+ wireStaleFrameRejected: wire.staleFrameRejected,
1982
+ wireFutureFrameRejected: wire.futureFrameRejected,
1983
+ wireOversizedRejected: wire.oversizedRejected,
1984
+ wireDuplicateInputRejected: wire.duplicateInputRejected,
1985
+ wireInvalidInputIdRejected: wire.invalidInputIdRejected,
1986
+ wireAckEnvelopes: wire.ackEnvelopes,
1987
+ wireCorrectionEnvelopes: wire.correctionEnvelopes,
1988
+ wireSnapshotEnvelopes: wire.snapshotEnvelopes,
1989
+ wireReorderedSequenceAccepted: wire.reorderedSequenceAccepted,
1990
+ wireDuplicateSequenceRejected: wire.duplicateSequenceRejected,
1991
+ wireReplayedEnvelopeRejected: wire.replayedEnvelopeRejected,
1992
+ wireStaleAckRejected: wire.staleAckRejected,
1993
+ wireStaleCorrectionRejected: wire.staleCorrectionRejected,
1994
+ wireStaleSnapshotRejected: wire.staleSnapshotRejected,
1995
+ wireAuthSignedEnvelopes: wire.wireAuthSignedEnvelopes,
1996
+ wireAuthMissingRejected: wire.wireAuthMissingRejected,
1997
+ wireAuthSenderMismatchRejected: wire.wireAuthSenderMismatchRejected,
1998
+ wireAuthSignatureRejected: wire.wireAuthSignatureRejected,
1999
+ wireAuthHmacSha256Covered: wire.wireAuthHmacSha256Covered,
2000
+ wireForgedAuthorityCorrectionRejected: wire.forgedAuthorityCorrectionRejected,
2001
+ wireForgedAuthoritySnapshotRejected: wire.forgedAuthoritySnapshotRejected,
2002
+ wireSnapshotIdentityRequiredRejected: wire.snapshotIdentityRequiredRejected,
2003
+ wireCorrectionsApplied: wire.correctionsApplied,
2004
+ wireSnapshotsApplied: wire.snapshotsApplied,
2005
+ multiclientChecksum: multiclient.checksum,
2006
+ multiclientFrames: multiclient.frames,
2007
+ multiclientPredictedClientRunners: multiclient.predictedClientRunners,
2008
+ multiclientAuthoritySnapshotsDelivered: multiclient.authoritySnapshotsDelivered,
2009
+ multiclientPredictionMismatches: multiclient.predictionMismatches,
2010
+ multiclientCorrectionsApplied: multiclient.correctionsApplied,
2011
+ multiclientResimulatedFrames: multiclient.resimulatedFrames,
2012
+ multiclientConvergedSnapshots: multiclient.convergedSnapshots,
2013
+ multiclientRollbackDepthP95: multiclient.rollbackDepthP95,
2014
+ multiclientRollbackDepthMax: multiclient.rollbackDepthMax,
2015
+ multiclientConvergence: multiclient.convergence,
2016
+ multiclientAllClientsReachedFinalAuthorityFrame: multiclient.allClientsReachedFinalAuthorityFrame,
2017
+ multiclientP95FrameCost: multiclient.p95FrameCost,
2018
+ multiclientP99FrameCost: multiclient.p99FrameCost,
2019
+ multiclientRuntimeBackedClients: multiclient.runtimeBackedClients,
2020
+ multiclientRuntimeBackedFrames: multiclient.runtimeBackedFrames,
2021
+ multiclientRuntimeBackedAuthoritySnapshots: multiclient.runtimeBackedAuthoritySnapshots,
2022
+ multiclientRuntimeBackedPredictionMismatches: multiclient.runtimeBackedPredictionMismatches,
2023
+ multiclientRuntimeBackedCorrectionsApplied: multiclient.runtimeBackedCorrectionsApplied,
2024
+ multiclientRuntimeBackedResimulatedFrames: multiclient.runtimeBackedResimulatedFrames,
2025
+ multiclientRuntimeBackedReplayVerifiedClients: multiclient.runtimeBackedReplayVerifiedClients,
2026
+ multiclientRuntimeBackedAuthorityChecksum: multiclient.runtimeBackedAuthorityChecksum,
2027
+ multiclientRuntimeBackedClientChecksum: multiclient.runtimeBackedClientChecksum,
2028
+ multiclientRuntimeBackedConvergence: multiclient.runtimeBackedConvergence,
2029
+ authorityPolicyChecksum: policy.checksum,
2030
+ authorityPolicyRestoredChecksum: policy.restoredChecksum,
2031
+ authorityPolicyRollbackEquivalent: policy.rollbackEquivalent,
2032
+ authorityPolicyRollbackWindowFrames: policy.rollbackWindowFrames,
2033
+ authorityPolicyStructuredInputChecksum: policy.structuredInputChecksum,
2034
+ authorityPolicyValueAfterLateInput: policy.authorityValueAfterLateInput,
2035
+ authorityPolicyClientProjectionValueAfterLateInput: policy.clientProjectionValueAfterLateInput,
2036
+ nonCommutativeRuntimeChecksum: policy.nonCommutativeRuntimeChecksum,
2037
+ nonCommutativeFullReplayChecksum: policy.nonCommutativeFullReplayChecksum,
2038
+ nonCommutativeAppendOnlyChecksum: policy.nonCommutativeAppendOnlyChecksum,
2039
+ nonCommutativeResimulatedFrames: policy.nonCommutativeResimulatedFrames,
2040
+ offlineUpgradeChecksum: offlineUpgrade.checksum,
2041
+ offlineUpgradePlayers: offlineUpgrade.players,
2042
+ offlineUpgradeFrames: offlineUpgrade.frames,
2043
+ offlineUpgradeOfflineFrame: offlineUpgrade.offlineFrame,
2044
+ offlineUpgradeAuthorityFrame: offlineUpgrade.authorityFrame,
2045
+ offlineUpgradeOfflineChecksum: offlineUpgrade.offlineChecksum,
2046
+ offlineUpgradeAuthorityChecksum: offlineUpgrade.authorityChecksum,
2047
+ offlineUpgradeAuthorityRestoredChecksum: offlineUpgrade.authorityRestoredChecksum,
2048
+ offlineUpgradeReplayChecksum: offlineUpgrade.replayChecksum,
2049
+ offlineUpgradeStateMatch: offlineUpgrade.stateMatch,
2050
+ offlineUpgradeReplayVerified: offlineUpgrade.replayVerified,
2051
+ offlineUpgradeRestoreVerified: offlineUpgrade.restoreVerified,
2052
+ offlineUpgradeAuthorityConvergence: offlineUpgrade.authorityConvergence,
2053
+ offlineUpgradeInputRows: offlineUpgrade.inputRows,
2054
+ offlineUpgradeSnapshotFrame: offlineUpgrade.snapshotFrame,
2055
+ authorityReplayMinimizerChecksum: replayMinimizer.checksum,
2056
+ authorityReplayMinimizerPlayers: replayMinimizer.players,
2057
+ authorityReplayMinimizerFrames: replayMinimizer.frames,
2058
+ authorityReplayValidVerified: replayMinimizer.validReplayVerified,
2059
+ authorityReplayCorruptedFailed: replayMinimizer.corruptedReplayFailed,
2060
+ authorityReplayMinimizedFailed: replayMinimizer.minimizedReplayFailed,
2061
+ authorityReplayMismatchFrame: replayMinimizer.mismatchFrame,
2062
+ authorityReplayMinimizedMismatchFrame: replayMinimizer.minimizedMismatchFrame,
2063
+ authorityReplayOriginalBytes: replayMinimizer.originalReplayBytes,
2064
+ authorityReplayMinimizedBytes: replayMinimizer.minimizedReplayBytes,
2065
+ authorityReplayRemovedInputFrames: replayMinimizer.removedInputFrames,
2066
+ authorityReplayRemovedSnapshots: replayMinimizer.removedSnapshots,
2067
+ authorityReplayRemovedChecksumFrames: replayMinimizer.removedChecksumFrames,
2068
+ authorityReplayDebugEvents: replayMinimizer.debugEvents,
2069
+ }, requestedFrames, metrics.frames));
2070
+ }
2071
+ function deterministicSessionCategory(players, requestedFrames, executedFrames, seed) {
2072
+ const metrics = (0, deterministic_session_js_1.runDeterministicSessionCoreFixture)(players, executedFrames, seed);
2073
+ const structured = (0, deterministic_session_js_1.runDeterministicStructuredSessionInputFixture)();
2074
+ const authority = (0, deterministic_session_js_1.runDeterministicSessionAuthorityFixture)(players, Math.min(executedFrames, 5_000), seed + 11);
2075
+ const rollbackHistory = (0, rollback_history_js_1.runDeterministicRollbackHistoryFixture)(Math.min(executedFrames, 5_000), 64, seed);
2076
+ const lifecycleProtocol = (0, deterministic_session_js_1.runDeterministicSessionLifecycleProtocolFixture)();
2077
+ return categoryReport('deterministic-session', (0, canonical_js_1.defaultChecksum)({
2078
+ core: metrics.checksum,
2079
+ structured: structured.checksum,
2080
+ authority: authority.checksum,
2081
+ rollbackHistory: rollbackHistory.checksum,
2082
+ lifecycleProtocol: lifecycleProtocol.checksum,
2083
+ }), {
2084
+ verifiedPredictedFrameRingCovered: metrics.frameRingExposed && metrics.predictedPreviousAvailable,
2085
+ partialConfirmationDoesNotAdvanceVerified: metrics.partialConfirmationHeldVerifiedFrame,
2086
+ inputFlagsCovered: metrics.repeatableInputs > 0
2087
+ && metrics.playerNotPresentInputs > 0
2088
+ && metrics.serverReplacedInputs > 0
2089
+ && metrics.commandFlagInputs > 0,
2090
+ playerLifecycleCovered: metrics.addPlayerAccepted > 0
2091
+ && metrics.removePlayerAccepted > 0
2092
+ && metrics.duplicateAddRejected > 0
2093
+ && metrics.removedSlotInputRejected > 0,
2094
+ correctionSemanticsCovered: metrics.correctionCount > 0 && metrics.staleCorrectionsRejected > 0,
2095
+ replacementInputsCovered: metrics.replacementInputs > 0,
2096
+ fullRuntimeReplayVerified: metrics.fullRuntimeReplayExecuted && metrics.replayVerified,
2097
+ firstClassCommandsCovered: metrics.predictedCommands > 0
2098
+ && metrics.confirmedCommands > 0
2099
+ && metrics.commandSystemPolls > 0,
2100
+ commandReplayVerified: metrics.commandReplayVerified,
2101
+ structuredInputReplayVerified: structured.replayVerified,
2102
+ structuredInputPredictionPreserved: structured.predictedFallbackPreservedData,
2103
+ structuredInputPayloadRejected: structured.rejectedNondeterministicPayload,
2104
+ structuredInputSchemaRejected: structured.rejectedSchemaPayloads >= 3,
2105
+ sessionAuthorityRuntimeBacked: authority.authorityFrame === authority.frames
2106
+ && authority.predictedFrame === authority.frames
2107
+ && authority.convergence
2108
+ && authority.replayVerified,
2109
+ sessionAuthorityLifecycleCovered: authority.reconnects > 0
2110
+ && authority.lateJoins > 0
2111
+ && authority.spectators > 0
2112
+ && authority.lateJoinReconstructed
2113
+ && authority.spectatorReconstructed,
2114
+ sessionAuthorityPredictionCovered: authority.predictedInputs > 0
2115
+ && authority.confirmedInputs > 0
2116
+ && authority.replacementInputs > 0
2117
+ && authority.correctionApplied,
2118
+ sessionAuthorityCommandsCovered: authority.predictedCommands > 0 && authority.confirmedCommands > 0,
2119
+ lifecycleProtocolStarted: lifecycleProtocol.startRequests > 0 && lifecycleProtocol.simulationStarts > 0,
2120
+ lifecycleProtocolAddPlayerCovered: lifecycleProtocol.spectatorJoinsAccepted > 0
2121
+ && lifecycleProtocol.addPlayerAccepted > 0
2122
+ && lifecycleProtocol.addPlayerFailed > 0
2123
+ && lifecycleProtocol.duplicateAddRejected > 0,
2124
+ lifecycleProtocolSpectatorRejected: lifecycleProtocol.spectatorInputRejected > 0
2125
+ && lifecycleProtocol.spectatorCommandRejected > 0,
2126
+ lifecycleProtocolReconnectTtlCovered: lifecycleProtocol.sameActorReconnectAccepted > 0
2127
+ && lifecycleProtocol.differentActorReconnectRejected > 0
2128
+ && lifecycleProtocol.expiredReconnectRejected > 0,
2129
+ lifecycleProtocolReplayVerified: lifecycleProtocol.replayVerified,
2130
+ boundedRollbackHistoryCovered: rollbackHistory.convergence
2131
+ && rollbackHistory.rollbackDepthBounded
2132
+ && rollbackHistory.resimulatedFrames > 0,
2133
+ boundedRollbackEvictionRejected: rollbackHistory.evictedRestoreRejected,
2134
+ boundedRollbackMalformedSnapshotRejected: rollbackHistory.malformedRestoreRejected,
2135
+ boundedRollbackDuplicateRejected: rollbackHistory.duplicateRejected,
2136
+ boundedRollbackOrderStable: rollbackHistory.orderStable,
2137
+ playersCovered: metrics.players === players,
2138
+ executedRequestedFrames: metrics.frames === executedFrames,
2139
+ }, withFrameMetrics({
2140
+ players: metrics.players,
2141
+ frames: metrics.frames,
2142
+ verifiedFrame: metrics.verifiedFrame,
2143
+ predictedFrame: metrics.predictedFrame,
2144
+ verifiedChecksum: metrics.verifiedChecksum,
2145
+ predictedChecksum: metrics.predictedChecksum,
2146
+ replayChecksum: metrics.replayChecksum,
2147
+ replayVerified: metrics.replayVerified,
2148
+ correctionCount: metrics.correctionCount,
2149
+ staleCorrectionsRejected: metrics.staleCorrectionsRejected,
2150
+ replacementInputs: metrics.replacementInputs,
2151
+ repeatableInputs: metrics.repeatableInputs,
2152
+ playerNotPresentInputs: metrics.playerNotPresentInputs,
2153
+ serverReplacedInputs: metrics.serverReplacedInputs,
2154
+ commandFlagInputs: metrics.commandFlagInputs,
2155
+ predictedCommands: metrics.predictedCommands,
2156
+ confirmedCommands: metrics.confirmedCommands,
2157
+ rejectedCommands: metrics.rejectedCommands,
2158
+ commandReplayVerified: metrics.commandReplayVerified,
2159
+ commandSystemPolls: metrics.commandSystemPolls,
2160
+ lifecycleEvents: metrics.lifecycleEvents,
2161
+ addPlayerAccepted: metrics.addPlayerAccepted,
2162
+ removePlayerAccepted: metrics.removePlayerAccepted,
2163
+ duplicateAddRejected: metrics.duplicateAddRejected,
2164
+ removedSlotInputRejected: metrics.removedSlotInputRejected,
2165
+ fullRuntimeReplayExecuted: metrics.fullRuntimeReplayExecuted,
2166
+ structuredInputChecksum: structured.checksum,
2167
+ structuredInputReplayVerified: structured.replayVerified,
2168
+ structuredInputPredictionPreserved: structured.predictedFallbackPreservedData,
2169
+ structuredInputPayloadRejected: structured.rejectedNondeterministicPayload,
2170
+ structuredInputSchemaRejected: structured.rejectedSchemaPayloads,
2171
+ structuredInputs: structured.structuredInputs,
2172
+ structuredAxisTotal: structured.axisTotal,
2173
+ structuredFireTotal: structured.fireTotal,
2174
+ sessionAuthorityChecksum: authority.checksum,
2175
+ sessionAuthorityFrame: authority.authorityFrame,
2176
+ sessionAuthorityPredictedFrame: authority.predictedFrame,
2177
+ sessionAuthorityConvergence: authority.convergence,
2178
+ sessionAuthorityReplayVerified: authority.replayVerified,
2179
+ sessionAuthorityPredictedInputs: authority.predictedInputs,
2180
+ sessionAuthorityConfirmedInputs: authority.confirmedInputs,
2181
+ sessionAuthorityReplacementInputs: authority.replacementInputs,
2182
+ sessionAuthorityPredictedCommands: authority.predictedCommands,
2183
+ sessionAuthorityConfirmedCommands: authority.confirmedCommands,
2184
+ sessionAuthorityReconnects: authority.reconnects,
2185
+ sessionAuthorityLateJoins: authority.lateJoins,
2186
+ sessionAuthoritySpectators: authority.spectators,
2187
+ sessionAuthorityRejectedMessages: authority.rejectedMessages,
2188
+ sessionAuthorityCorrectionApplied: authority.correctionApplied,
2189
+ sessionAuthorityLateJoinReconstructed: authority.lateJoinReconstructed,
2190
+ sessionAuthoritySpectatorReconstructed: authority.spectatorReconstructed,
2191
+ sessionAuthorityInputDelayP95: authority.inputDelayP95,
2192
+ sessionAuthorityRollbackDepthP95: authority.rollbackDepthP95,
2193
+ lifecycleProtocolChecksum: lifecycleProtocol.checksum,
2194
+ lifecycleProtocolStartRequests: lifecycleProtocol.startRequests,
2195
+ lifecycleProtocolSimulationStarts: lifecycleProtocol.simulationStarts,
2196
+ lifecycleProtocolSpectatorJoinsAccepted: lifecycleProtocol.spectatorJoinsAccepted,
2197
+ lifecycleProtocolAddPlayerAccepted: lifecycleProtocol.addPlayerAccepted,
2198
+ lifecycleProtocolAddPlayerFailed: lifecycleProtocol.addPlayerFailed,
2199
+ lifecycleProtocolDuplicateAddRejected: lifecycleProtocol.duplicateAddRejected,
2200
+ lifecycleProtocolSpectatorInputRejected: lifecycleProtocol.spectatorInputRejected,
2201
+ lifecycleProtocolSpectatorCommandRejected: lifecycleProtocol.spectatorCommandRejected,
2202
+ lifecycleProtocolSameActorReconnectAccepted: lifecycleProtocol.sameActorReconnectAccepted,
2203
+ lifecycleProtocolDifferentActorReconnectRejected: lifecycleProtocol.differentActorReconnectRejected,
2204
+ lifecycleProtocolExpiredReconnectRejected: lifecycleProtocol.expiredReconnectRejected,
2205
+ lifecycleProtocolRemovePlayerAccepted: lifecycleProtocol.removePlayerAccepted,
2206
+ lifecycleProtocolReplayVerified: lifecycleProtocol.replayVerified,
2207
+ lifecycleProtocolVerifiedFrame: lifecycleProtocol.verifiedFrame,
2208
+ rollbackHistoryChecksum: rollbackHistory.checksum,
2209
+ rollbackHistoryBaselineChecksum: rollbackHistory.baselineChecksum,
2210
+ rollbackHistoryPredictedChecksumBeforeCorrection: rollbackHistory.predictedChecksumBeforeCorrection,
2211
+ rollbackHistoryResimulatedChecksum: rollbackHistory.resimulatedChecksum,
2212
+ rollbackHistoryRestoredHistoryChecksum: rollbackHistory.restoredHistoryChecksum,
2213
+ rollbackHistoryCapacity: rollbackHistory.capacity,
2214
+ rollbackHistoryRecordedFrames: rollbackHistory.recordedFrames,
2215
+ rollbackHistoryEvictedFrames: rollbackHistory.evictedFrames,
2216
+ rollbackHistoryRestoredFrame: rollbackHistory.restoredFrame,
2217
+ rollbackHistoryPredictedToFrame: rollbackHistory.predictedToFrame,
2218
+ rollbackHistoryResimulatedFrames: rollbackHistory.resimulatedFrames,
2219
+ rollbackHistoryConvergence: rollbackHistory.convergence,
2220
+ rollbackHistoryDuplicateRejected: rollbackHistory.duplicateRejected,
2221
+ rollbackHistoryEvictedRestoreRejected: rollbackHistory.evictedRestoreRejected,
2222
+ rollbackHistoryMalformedRestoreRejected: rollbackHistory.malformedRestoreRejected,
2223
+ rollbackHistoryDepthBounded: rollbackHistory.rollbackDepthBounded,
2224
+ rollbackHistoryOrderStable: rollbackHistory.orderStable,
2225
+ }, requestedFrames, metrics.frames));
2226
+ }
2227
+ function withFrameMetrics(metrics, requestedFrames, executedFrames) {
2228
+ return {
2229
+ ...metrics,
2230
+ requestedFrames,
2231
+ executedFrames,
2232
+ capped: executedFrames < requestedFrames,
2233
+ };
2234
+ }
2235
+ function updateSimulationHashValue(hash, value) {
2236
+ const mixed = hash ^ (value + 0x9e3779b9);
2237
+ return Math.imul(mixed, 16777619) >>> 0;
2238
+ }
2239
+ function categoryReport(category, checksum, invariants, metrics) {
2240
+ const failures = stableKeys(invariants)
2241
+ .filter((key) => invariants[key] === false);
2242
+ const { executionProofHash: _ignoredExecutionProofHash, ...baseMetrics } = metrics;
2243
+ const metricsWithIdentity = {
2244
+ ...baseMetrics,
2245
+ proofContract: `${category}@1`,
2246
+ subsystemChecksum: checksum,
2247
+ };
2248
+ const body = {
2249
+ category,
2250
+ result: failures.length === 0 ? 'pass' : 'fail',
2251
+ invariants,
2252
+ metrics: {
2253
+ ...metricsWithIdentity,
2254
+ executionProofHash: engineCompleteExecutionProofHash(category, checksum, metricsWithIdentity),
2255
+ },
2256
+ failures,
2257
+ };
2258
+ return {
2259
+ ...body,
2260
+ checksum: (0, canonical_js_1.defaultChecksum)(body),
2261
+ };
2262
+ }
2263
+ function subsystemChecksumOf(report) {
2264
+ return String(report.metrics.subsystemChecksum);
2265
+ }
2266
+ function engineCompleteExecutionProofHash(category, subsystemChecksum, metrics) {
2267
+ const { executionProofHash: _ignoredExecutionProofHash, wallClockElapsedMs: _elapsed, wallClockMeanFrameMs: _mean, ...stableMetrics } = metrics;
2268
+ return (0, canonical_js_1.defaultChecksum)({
2269
+ category,
2270
+ subsystemChecksum,
2271
+ requestedFrames: stableMetrics.requestedFrames,
2272
+ executedFrames: stableMetrics.executedFrames,
2273
+ capped: stableMetrics.capped,
2274
+ proofContract: stableMetrics.proofContract,
2275
+ metrics: stableMetrics,
2276
+ });
2277
+ }
2278
+ function stableKeys(record) {
2279
+ return Reflect.ownKeys(record)
2280
+ .filter((key) => typeof key === 'string')
2281
+ .sort();
2282
+ }
2283
+ function engineCompleteNowMs() {
2284
+ return globalThis.performance.now();
2285
+ }
2286
+ function percentileNumber(values, percentile) {
2287
+ if (values.length === 0) {
2288
+ return 0;
2289
+ }
2290
+ const sorted = [...values].sort((left, right) => left - right);
2291
+ const index = Math.min(sorted.length - 1, Math.max(0, Math.ceil((percentile / 100) * sorted.length) - 1));
2292
+ return sorted[index];
2293
+ }
2294
+ function roundMetric(value, places) {
2295
+ const scale = 10 ** places;
2296
+ return Math.round(value * scale) / scale;
2297
+ }