@forgeax/engine-ecs 0.0.0-dev.8d955ade1c79

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 (383) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +278 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/__fixtures__/field-shape-fixture.d.ts +16 -0
  5. package/dist/__fixtures__/field-shape-fixture.d.ts.map +1 -0
  6. package/dist/__tests__/__fixtures__/inspect-scripts.snapshot.d.ts +3 -0
  7. package/dist/__tests__/__fixtures__/inspect-scripts.snapshot.d.ts.map +1 -0
  8. package/dist/__tests__/archetype.unit.test.d.ts +2 -0
  9. package/dist/__tests__/archetype.unit.test.d.ts.map +1 -0
  10. package/dist/__tests__/array-handle-element.test-d.d.ts +2 -0
  11. package/dist/__tests__/array-handle-element.test-d.d.ts.map +1 -0
  12. package/dist/__tests__/buffer-array-vocab.test-d.d.ts +2 -0
  13. package/dist/__tests__/buffer-array-vocab.test-d.d.ts.map +1 -0
  14. package/dist/__tests__/buffer-field-input-widen.unit.test.d.ts +2 -0
  15. package/dist/__tests__/buffer-field-input-widen.unit.test.d.ts.map +1 -0
  16. package/dist/__tests__/buffer-pool.test-d.d.ts +2 -0
  17. package/dist/__tests__/buffer-pool.test-d.d.ts.map +1 -0
  18. package/dist/__tests__/change-detection.unit.test.d.ts +2 -0
  19. package/dist/__tests__/change-detection.unit.test.d.ts.map +1 -0
  20. package/dist/__tests__/command-buffer.test.d.ts +2 -0
  21. package/dist/__tests__/command-buffer.test.d.ts.map +1 -0
  22. package/dist/__tests__/commands-deferred.unit.test.d.ts +2 -0
  23. package/dist/__tests__/commands-deferred.unit.test.d.ts.map +1 -0
  24. package/dist/__tests__/component-catalog.test.d.ts +2 -0
  25. package/dist/__tests__/component-catalog.test.d.ts.map +1 -0
  26. package/dist/__tests__/component-definition-identity.unit.test.d.ts +2 -0
  27. package/dist/__tests__/component-definition-identity.unit.test.d.ts.map +1 -0
  28. package/dist/__tests__/component-nan-preflight.unit.test.d.ts +2 -0
  29. package/dist/__tests__/component-nan-preflight.unit.test.d.ts.map +1 -0
  30. package/dist/__tests__/component-schema.test-d.d.ts +2 -0
  31. package/dist/__tests__/component-schema.test-d.d.ts.map +1 -0
  32. package/dist/__tests__/component-schema.test.d.ts +2 -0
  33. package/dist/__tests__/component-schema.test.d.ts.map +1 -0
  34. package/dist/__tests__/define-component-options.test-d.d.ts +2 -0
  35. package/dist/__tests__/define-component-options.test-d.d.ts.map +1 -0
  36. package/dist/__tests__/deprecated-vocab-rejection.unit.test.d.ts +2 -0
  37. package/dist/__tests__/deprecated-vocab-rejection.unit.test.d.ts.map +1 -0
  38. package/dist/__tests__/despawn-all.unit.test.d.ts +2 -0
  39. package/dist/__tests__/despawn-all.unit.test.d.ts.map +1 -0
  40. package/dist/__tests__/ecs-core-reduction.characterization.test.d.ts +2 -0
  41. package/dist/__tests__/ecs-core-reduction.characterization.test.d.ts.map +1 -0
  42. package/dist/__tests__/ecs-core-reduction.perf.test.d.ts +2 -0
  43. package/dist/__tests__/ecs-core-reduction.perf.test.d.ts.map +1 -0
  44. package/dist/__tests__/ecs-error-code-31.test-d.d.ts +2 -0
  45. package/dist/__tests__/ecs-error-code-31.test-d.d.ts.map +1 -0
  46. package/dist/__tests__/entity-disabling.unit.test.d.ts +2 -0
  47. package/dist/__tests__/entity-disabling.unit.test.d.ts.map +1 -0
  48. package/dist/__tests__/entity-handle-codec-parity.unit.test.d.ts +2 -0
  49. package/dist/__tests__/entity-handle-codec-parity.unit.test.d.ts.map +1 -0
  50. package/dist/__tests__/errors.unit.test.d.ts +2 -0
  51. package/dist/__tests__/errors.unit.test.d.ts.map +1 -0
  52. package/dist/__tests__/execution-conflict-boundary.unit.test.d.ts +2 -0
  53. package/dist/__tests__/execution-conflict-boundary.unit.test.d.ts.map +1 -0
  54. package/dist/__tests__/execution-shared-storage.unit.test.d.ts +2 -0
  55. package/dist/__tests__/execution-shared-storage.unit.test.d.ts.map +1 -0
  56. package/dist/__tests__/externalization-portable-value.unit.test.d.ts +2 -0
  57. package/dist/__tests__/externalization-portable-value.unit.test.d.ts.map +1 -0
  58. package/dist/__tests__/externalization-projection.unit.test.d.ts +2 -0
  59. package/dist/__tests__/externalization-projection.unit.test.d.ts.map +1 -0
  60. package/dist/__tests__/externalization-render-read-lease.test-d.d.ts +2 -0
  61. package/dist/__tests__/externalization-render-read-lease.test-d.d.ts.map +1 -0
  62. package/dist/__tests__/externalization-render-read-lease.unit.test.d.ts +2 -0
  63. package/dist/__tests__/externalization-render-read-lease.unit.test.d.ts.map +1 -0
  64. package/dist/__tests__/externalization-root-surface.unit.test.d.ts +2 -0
  65. package/dist/__tests__/externalization-root-surface.unit.test.d.ts.map +1 -0
  66. package/dist/__tests__/field-enum-labels-reflection.test.d.ts +2 -0
  67. package/dist/__tests__/field-enum-labels-reflection.test.d.ts.map +1 -0
  68. package/dist/__tests__/field-shape-fixture.test.d.ts +2 -0
  69. package/dist/__tests__/field-shape-fixture.test.d.ts.map +1 -0
  70. package/dist/__tests__/field-transient-reflection.test.d.ts +2 -0
  71. package/dist/__tests__/field-transient-reflection.test.d.ts.map +1 -0
  72. package/dist/__tests__/field-value-type.test-d.d.ts +2 -0
  73. package/dist/__tests__/field-value-type.test-d.d.ts.map +1 -0
  74. package/dist/__tests__/fixed-update.unit.test.d.ts +2 -0
  75. package/dist/__tests__/fixed-update.unit.test.d.ts.map +1 -0
  76. package/dist/__tests__/handle.test-d.d.ts +2 -0
  77. package/dist/__tests__/handle.test-d.d.ts.map +1 -0
  78. package/dist/__tests__/hierarchy.unit.test.d.ts +2 -0
  79. package/dist/__tests__/hierarchy.unit.test.d.ts.map +1 -0
  80. package/dist/__tests__/managed-array-vocab.test-d.d.ts +2 -0
  81. package/dist/__tests__/managed-array-vocab.test-d.d.ts.map +1 -0
  82. package/dist/__tests__/minimal-example.test-d.d.ts +2 -0
  83. package/dist/__tests__/minimal-example.test-d.d.ts.map +1 -0
  84. package/dist/__tests__/name-read-types.test-d.d.ts +2 -0
  85. package/dist/__tests__/name-read-types.test-d.d.ts.map +1 -0
  86. package/dist/__tests__/plugin-service.test.d.ts +2 -0
  87. package/dist/__tests__/plugin-service.test.d.ts.map +1 -0
  88. package/dist/__tests__/query-combinations.unit.test.d.ts +2 -0
  89. package/dist/__tests__/query-combinations.unit.test.d.ts.map +1 -0
  90. package/dist/__tests__/query-light-extract-flat-column-ratio.perf.test.d.ts +2 -0
  91. package/dist/__tests__/query-light-extract-flat-column-ratio.perf.test.d.ts.map +1 -0
  92. package/dist/__tests__/query-storage-trends.perf.test.d.ts +2 -0
  93. package/dist/__tests__/query-storage-trends.perf.test.d.ts.map +1 -0
  94. package/dist/__tests__/query-trs-flat-column-ratio.perf.test.d.ts +2 -0
  95. package/dist/__tests__/query-trs-flat-column-ratio.perf.test.d.ts.map +1 -0
  96. package/dist/__tests__/query.unit.test.d.ts +2 -0
  97. package/dist/__tests__/query.unit.test.d.ts.map +1 -0
  98. package/dist/__tests__/relationship-index.perf.test.d.ts +2 -0
  99. package/dist/__tests__/relationship-index.perf.test.d.ts.map +1 -0
  100. package/dist/__tests__/relationship-index.test.d.ts +2 -0
  101. package/dist/__tests__/relationship-index.test.d.ts.map +1 -0
  102. package/dist/__tests__/scalar-field-type-owner.test-d.d.ts +2 -0
  103. package/dist/__tests__/scalar-field-type-owner.test-d.d.ts.map +1 -0
  104. package/dist/__tests__/schedule-determinism.unit.test.d.ts +2 -0
  105. package/dist/__tests__/schedule-determinism.unit.test.d.ts.map +1 -0
  106. package/dist/__tests__/schedule-inspection.unit.test.d.ts +2 -0
  107. package/dist/__tests__/schedule-inspection.unit.test.d.ts.map +1 -0
  108. package/dist/__tests__/schedule-scope-error.unit.test.d.ts +2 -0
  109. package/dist/__tests__/schedule-scope-error.unit.test.d.ts.map +1 -0
  110. package/dist/__tests__/schedule-token.unit.test.d.ts +2 -0
  111. package/dist/__tests__/schedule-token.unit.test.d.ts.map +1 -0
  112. package/dist/__tests__/schema-vocab.test-d.d.ts +2 -0
  113. package/dist/__tests__/schema-vocab.test-d.d.ts.map +1 -0
  114. package/dist/__tests__/serialization.unit.test.d.ts +2 -0
  115. package/dist/__tests__/serialization.unit.test.d.ts.map +1 -0
  116. package/dist/__tests__/shared-kernel-eligibility.test-d.d.ts +2 -0
  117. package/dist/__tests__/shared-kernel-eligibility.test-d.d.ts.map +1 -0
  118. package/dist/__tests__/shared-kernel-eligibility.unit.test.d.ts +2 -0
  119. package/dist/__tests__/shared-kernel-eligibility.unit.test.d.ts.map +1 -0
  120. package/dist/__tests__/shared-ref-store.unit.test.d.ts +2 -0
  121. package/dist/__tests__/shared-ref-store.unit.test.d.ts.map +1 -0
  122. package/dist/__tests__/sparse-tag.unit.test.d.ts +2 -0
  123. package/dist/__tests__/sparse-tag.unit.test.d.ts.map +1 -0
  124. package/dist/__tests__/spawn-field-error.test-d.d.ts +2 -0
  125. package/dist/__tests__/spawn-field-error.test-d.d.ts.map +1 -0
  126. package/dist/__tests__/stale-error.test-d.d.ts +2 -0
  127. package/dist/__tests__/stale-error.test-d.d.ts.map +1 -0
  128. package/dist/__tests__/string-view-symmetry.test-d.d.ts +2 -0
  129. package/dist/__tests__/string-view-symmetry.test-d.d.ts.map +1 -0
  130. package/dist/__tests__/string-vocab.test-d.d.ts +2 -0
  131. package/dist/__tests__/string-vocab.test-d.d.ts.map +1 -0
  132. package/dist/__tests__/structure-epoch-boundaries.unit.test.d.ts +2 -0
  133. package/dist/__tests__/structure-epoch-boundaries.unit.test.d.ts.map +1 -0
  134. package/dist/__tests__/structure-epoch.unit.test.d.ts +2 -0
  135. package/dist/__tests__/structure-epoch.unit.test.d.ts.map +1 -0
  136. package/dist/__tests__/table-archetype-mapping.unit.test.d.ts +2 -0
  137. package/dist/__tests__/table-archetype-mapping.unit.test.d.ts.map +1 -0
  138. package/dist/__tests__/time.unit.test.d.ts +2 -0
  139. package/dist/__tests__/time.unit.test.d.ts.map +1 -0
  140. package/dist/__tests__/types.test-d.d.ts +2 -0
  141. package/dist/__tests__/types.test-d.d.ts.map +1 -0
  142. package/dist/__tests__/unique-ref-store.unit.test.d.ts +2 -0
  143. package/dist/__tests__/unique-ref-store.unit.test.d.ts.map +1 -0
  144. package/dist/__tests__/utils/handle-numeric.d.ts +14 -0
  145. package/dist/__tests__/utils/handle-numeric.d.ts.map +1 -0
  146. package/dist/__tests__/validation-root-surface.unit.test.d.ts +2 -0
  147. package/dist/__tests__/validation-root-surface.unit.test.d.ts.map +1 -0
  148. package/dist/__tests__/visibility-atomic-write.unit.test.d.ts +2 -0
  149. package/dist/__tests__/visibility-atomic-write.unit.test.d.ts.map +1 -0
  150. package/dist/__tests__/world-change-journal.unit.test.d.ts +2 -0
  151. package/dist/__tests__/world-change-journal.unit.test.d.ts.map +1 -0
  152. package/dist/__tests__/world-characterization.unit.test.d.ts +2 -0
  153. package/dist/__tests__/world-characterization.unit.test.d.ts.map +1 -0
  154. package/dist/__tests__/world-consumer-inference.test-d.d.ts +2 -0
  155. package/dist/__tests__/world-consumer-inference.test-d.d.ts.map +1 -0
  156. package/dist/__tests__/world-health.contract.test.d.ts +2 -0
  157. package/dist/__tests__/world-health.contract.test.d.ts.map +1 -0
  158. package/dist/__tests__/world-inspection.test.d.ts +2 -0
  159. package/dist/__tests__/world-inspection.test.d.ts.map +1 -0
  160. package/dist/__tests__/world-internal-identity.unit.test.d.ts +2 -0
  161. package/dist/__tests__/world-internal-identity.unit.test.d.ts.map +1 -0
  162. package/dist/__tests__/world-managed-roundtrip.unit.test.d.ts +2 -0
  163. package/dist/__tests__/world-managed-roundtrip.unit.test.d.ts.map +1 -0
  164. package/dist/__tests__/world-scheduling.m4.test.d.ts +2 -0
  165. package/dist/__tests__/world-scheduling.m4.test.d.ts.map +1 -0
  166. package/dist/__tests__/world-unique-roundtrip.unit.test.d.ts +2 -0
  167. package/dist/__tests__/world-unique-roundtrip.unit.test.d.ts.map +1 -0
  168. package/dist/__tests__/world.test-d.d.ts +2 -0
  169. package/dist/__tests__/world.test-d.d.ts.map +1 -0
  170. package/dist/buffer-pool.d.ts +109 -0
  171. package/dist/buffer-pool.d.ts.map +1 -0
  172. package/dist/commands.d.ts +93 -0
  173. package/dist/commands.d.ts.map +1 -0
  174. package/dist/component-default-fallback.d.ts +88 -0
  175. package/dist/component-default-fallback.d.ts.map +1 -0
  176. package/dist/component-schema.d.ts +34 -0
  177. package/dist/component-schema.d.ts.map +1 -0
  178. package/dist/component-value-validate.d.ts +29 -0
  179. package/dist/component-value-validate.d.ts.map +1 -0
  180. package/dist/component.d.ts +581 -0
  181. package/dist/component.d.ts.map +1 -0
  182. package/dist/entity-handle.d.ts +68 -0
  183. package/dist/entity-handle.d.ts.map +1 -0
  184. package/dist/entity.d.ts +86 -0
  185. package/dist/entity.d.ts.map +1 -0
  186. package/dist/errors/query-and-component-errors.d.ts +132 -0
  187. package/dist/errors/query-and-component-errors.d.ts.map +1 -0
  188. package/dist/errors/relationship-errors.d.ts +112 -0
  189. package/dist/errors/relationship-errors.d.ts.map +1 -0
  190. package/dist/errors/sprite-and-shared-errors.d.ts +107 -0
  191. package/dist/errors/sprite-and-shared-errors.d.ts.map +1 -0
  192. package/dist/errors/validation-errors.d.ts +229 -0
  193. package/dist/errors/validation-errors.d.ts.map +1 -0
  194. package/dist/errors.d.ts +763 -0
  195. package/dist/errors.d.ts.map +1 -0
  196. package/dist/execution/shared-kernel.d.ts +106 -0
  197. package/dist/execution/shared-kernel.d.ts.map +1 -0
  198. package/dist/externalization/index.d.ts +31 -0
  199. package/dist/externalization/index.d.ts.map +1 -0
  200. package/dist/externalization/index.mjs +298 -0
  201. package/dist/externalization/index.mjs.map +1 -0
  202. package/dist/index.d.ts +261 -0
  203. package/dist/index.d.ts.map +1 -0
  204. package/dist/index.mjs +7422 -0
  205. package/dist/index.mjs.map +1 -0
  206. package/dist/internal.mjs +479 -0
  207. package/dist/internal.mjs.map +1 -0
  208. package/dist/plugin-service.d.ts +11 -0
  209. package/dist/plugin-service.d.ts.map +1 -0
  210. package/dist/projection/index.d.ts +103 -0
  211. package/dist/projection/index.d.ts.map +1 -0
  212. package/dist/projection/index.mjs +615 -0
  213. package/dist/projection/index.mjs.map +1 -0
  214. package/dist/query/query.d.ts +58 -0
  215. package/dist/query/query.d.ts.map +1 -0
  216. package/dist/relationship-index.d.ts +81 -0
  217. package/dist/relationship-index.d.ts.map +1 -0
  218. package/dist/resource.d.ts +70 -0
  219. package/dist/resource.d.ts.map +1 -0
  220. package/dist/schedule-token.d.ts +16 -0
  221. package/dist/schedule-token.d.ts.map +1 -0
  222. package/dist/schedule.d.ts +271 -0
  223. package/dist/schedule.d.ts.map +1 -0
  224. package/dist/shared-ref-store.d.ts +144 -0
  225. package/dist/shared-ref-store.d.ts.map +1 -0
  226. package/dist/shared.d.ts +3 -0
  227. package/dist/shared.d.ts.map +1 -0
  228. package/dist/shared.mjs +364 -0
  229. package/dist/shared.mjs.map +1 -0
  230. package/dist/storage/archetype-graph.d.ts +54 -0
  231. package/dist/storage/archetype-graph.d.ts.map +1 -0
  232. package/dist/storage/archetype.d.ts +23 -0
  233. package/dist/storage/archetype.d.ts.map +1 -0
  234. package/dist/storage/change-detection.d.ts +40 -0
  235. package/dist/storage/change-detection.d.ts.map +1 -0
  236. package/dist/storage/column.d.ts +111 -0
  237. package/dist/storage/column.d.ts.map +1 -0
  238. package/dist/storage/table.d.ts +29 -0
  239. package/dist/storage/table.d.ts.map +1 -0
  240. package/dist/time.d.ts +57 -0
  241. package/dist/time.d.ts.map +1 -0
  242. package/dist/unique-ref-store.d.ts +105 -0
  243. package/dist/unique-ref-store.d.ts.map +1 -0
  244. package/dist/world-change-journal.d.ts +34 -0
  245. package/dist/world-change-journal.d.ts.map +1 -0
  246. package/dist/world-component-access.d.ts +265 -0
  247. package/dist/world-component-access.d.ts.map +1 -0
  248. package/dist/world-component-storage.d.ts +282 -0
  249. package/dist/world-component-storage.d.ts.map +1 -0
  250. package/dist/world-core.d.ts +39 -0
  251. package/dist/world-core.d.ts.map +1 -0
  252. package/dist/world-entity-lifecycle.d.ts +30 -0
  253. package/dist/world-entity-lifecycle.d.ts.map +1 -0
  254. package/dist/world-internal.d.ts +14 -0
  255. package/dist/world-internal.d.ts.map +1 -0
  256. package/dist/world-scheduling.d.ts +30 -0
  257. package/dist/world-scheduling.d.ts.map +1 -0
  258. package/dist/world.d.ts +620 -0
  259. package/dist/world.d.ts.map +1 -0
  260. package/package.json +77 -0
  261. package/src/__fixtures__/field-shape-fixture.ts +30 -0
  262. package/src/__tests__/__fixtures__/inspect-scripts.snapshot.ts +2 -0
  263. package/src/__tests__/archetype.unit.test.ts +1837 -0
  264. package/src/__tests__/array-handle-element.test-d.ts +34 -0
  265. package/src/__tests__/buffer-array-vocab.test-d.ts +53 -0
  266. package/src/__tests__/buffer-field-input-widen.unit.test.ts +99 -0
  267. package/src/__tests__/buffer-pool.test-d.ts +32 -0
  268. package/src/__tests__/change-detection.unit.test.ts +86 -0
  269. package/src/__tests__/command-buffer.test.ts +179 -0
  270. package/src/__tests__/commands-deferred.unit.test.ts +68 -0
  271. package/src/__tests__/component-catalog.test.ts +59 -0
  272. package/src/__tests__/component-definition-identity.unit.test.ts +24 -0
  273. package/src/__tests__/component-nan-preflight.unit.test.ts +186 -0
  274. package/src/__tests__/component-schema.test-d.ts +119 -0
  275. package/src/__tests__/component-schema.test.ts +55 -0
  276. package/src/__tests__/define-component-options.test-d.ts +35 -0
  277. package/src/__tests__/deprecated-vocab-rejection.unit.test.ts +59 -0
  278. package/src/__tests__/despawn-all.unit.test.ts +17 -0
  279. package/src/__tests__/ecs-core-reduction.characterization.test.ts +130 -0
  280. package/src/__tests__/ecs-core-reduction.perf.test.ts +260 -0
  281. package/src/__tests__/ecs-error-code-31.test-d.ts +42 -0
  282. package/src/__tests__/entity-disabling.unit.test.ts +37 -0
  283. package/src/__tests__/entity-handle-codec-parity.unit.test.ts +126 -0
  284. package/src/__tests__/errors.unit.test.ts +1456 -0
  285. package/src/__tests__/execution-conflict-boundary.unit.test.ts +123 -0
  286. package/src/__tests__/execution-shared-storage.unit.test.ts +40 -0
  287. package/src/__tests__/externalization-portable-value.unit.test.ts +275 -0
  288. package/src/__tests__/externalization-projection.unit.test.ts +325 -0
  289. package/src/__tests__/externalization-render-read-lease.test-d.ts +30 -0
  290. package/src/__tests__/externalization-render-read-lease.unit.test.ts +79 -0
  291. package/src/__tests__/externalization-root-surface.unit.test.ts +33 -0
  292. package/src/__tests__/field-enum-labels-reflection.test.ts +66 -0
  293. package/src/__tests__/field-shape-fixture.test.ts +61 -0
  294. package/src/__tests__/field-transient-reflection.test.ts +59 -0
  295. package/src/__tests__/field-value-type.test-d.ts +57 -0
  296. package/src/__tests__/fixed-update.unit.test.ts +78 -0
  297. package/src/__tests__/handle.test-d.ts +86 -0
  298. package/src/__tests__/hierarchy.unit.test.ts +2534 -0
  299. package/src/__tests__/managed-array-vocab.test-d.ts +137 -0
  300. package/src/__tests__/minimal-example.test-d.ts +42 -0
  301. package/src/__tests__/name-read-types.test-d.ts +72 -0
  302. package/src/__tests__/plugin-service.test.ts +13 -0
  303. package/src/__tests__/query-combinations.unit.test.ts +42 -0
  304. package/src/__tests__/query-light-extract-flat-column-ratio.perf.test.ts +252 -0
  305. package/src/__tests__/query-storage-trends.perf.test.ts +104 -0
  306. package/src/__tests__/query-trs-flat-column-ratio.perf.test.ts +194 -0
  307. package/src/__tests__/query.unit.test.ts +196 -0
  308. package/src/__tests__/relationship-index.perf.test.ts +126 -0
  309. package/src/__tests__/relationship-index.test.ts +70 -0
  310. package/src/__tests__/scalar-field-type-owner.test-d.ts +71 -0
  311. package/src/__tests__/schedule-determinism.unit.test.ts +36 -0
  312. package/src/__tests__/schedule-inspection.unit.test.ts +81 -0
  313. package/src/__tests__/schedule-scope-error.unit.test.ts +63 -0
  314. package/src/__tests__/schedule-token.unit.test.ts +54 -0
  315. package/src/__tests__/schema-vocab.test-d.ts +103 -0
  316. package/src/__tests__/serialization.unit.test.ts +2740 -0
  317. package/src/__tests__/shared-kernel-eligibility.test-d.ts +18 -0
  318. package/src/__tests__/shared-kernel-eligibility.unit.test.ts +78 -0
  319. package/src/__tests__/shared-ref-store.unit.test.ts +646 -0
  320. package/src/__tests__/sparse-tag.unit.test.ts +201 -0
  321. package/src/__tests__/spawn-field-error.test-d.ts +41 -0
  322. package/src/__tests__/stale-error.test-d.ts +208 -0
  323. package/src/__tests__/string-view-symmetry.test-d.ts +26 -0
  324. package/src/__tests__/string-vocab.test-d.ts +49 -0
  325. package/src/__tests__/structure-epoch-boundaries.unit.test.ts +39 -0
  326. package/src/__tests__/structure-epoch.unit.test.ts +48 -0
  327. package/src/__tests__/table-archetype-mapping.unit.test.ts +78 -0
  328. package/src/__tests__/time.unit.test.ts +79 -0
  329. package/src/__tests__/types.test-d.ts +38 -0
  330. package/src/__tests__/unique-ref-store.unit.test.ts +348 -0
  331. package/src/__tests__/utils/handle-numeric.ts +30 -0
  332. package/src/__tests__/validation-root-surface.unit.test.ts +15 -0
  333. package/src/__tests__/visibility-atomic-write.unit.test.ts +82 -0
  334. package/src/__tests__/world-change-journal.unit.test.ts +97 -0
  335. package/src/__tests__/world-characterization.unit.test.ts +408 -0
  336. package/src/__tests__/world-consumer-inference.test-d.ts +16 -0
  337. package/src/__tests__/world-health.contract.test.ts +87 -0
  338. package/src/__tests__/world-inspection.test.ts +37 -0
  339. package/src/__tests__/world-internal-identity.unit.test.ts +17 -0
  340. package/src/__tests__/world-managed-roundtrip.unit.test.ts +98 -0
  341. package/src/__tests__/world-scheduling.m4.test.ts +52 -0
  342. package/src/__tests__/world-unique-roundtrip.unit.test.ts +357 -0
  343. package/src/__tests__/world.test-d.ts +156 -0
  344. package/src/buffer-pool.ts +357 -0
  345. package/src/commands.ts +644 -0
  346. package/src/component-default-fallback.ts +236 -0
  347. package/src/component-schema.ts +92 -0
  348. package/src/component-value-validate.ts +135 -0
  349. package/src/component.ts +1268 -0
  350. package/src/entity-handle.ts +104 -0
  351. package/src/entity.ts +140 -0
  352. package/src/errors/query-and-component-errors.ts +200 -0
  353. package/src/errors/relationship-errors.ts +198 -0
  354. package/src/errors/sprite-and-shared-errors.ts +231 -0
  355. package/src/errors/validation-errors.ts +506 -0
  356. package/src/errors.ts +1464 -0
  357. package/src/execution/shared-kernel.ts +392 -0
  358. package/src/externalization/index.ts +170 -0
  359. package/src/index.ts +414 -0
  360. package/src/plugin-service.ts +35 -0
  361. package/src/projection/index.ts +318 -0
  362. package/src/query/query.ts +606 -0
  363. package/src/relationship-index.ts +175 -0
  364. package/src/resource.ts +106 -0
  365. package/src/schedule-token.ts +40 -0
  366. package/src/schedule.ts +846 -0
  367. package/src/shared-ref-store.ts +418 -0
  368. package/src/shared.ts +23 -0
  369. package/src/storage/archetype-graph.ts +166 -0
  370. package/src/storage/archetype.ts +78 -0
  371. package/src/storage/change-detection.ts +231 -0
  372. package/src/storage/column.ts +247 -0
  373. package/src/storage/table.ts +153 -0
  374. package/src/time.ts +122 -0
  375. package/src/unique-ref-store.ts +278 -0
  376. package/src/world-change-journal.ts +84 -0
  377. package/src/world-component-access.ts +1421 -0
  378. package/src/world-component-storage.ts +1178 -0
  379. package/src/world-core.ts +74 -0
  380. package/src/world-entity-lifecycle.ts +539 -0
  381. package/src/world-internal.ts +75 -0
  382. package/src/world-scheduling.ts +499 -0
  383. package/src/world.ts +1399 -0
@@ -0,0 +1,186 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { defineComponent } from '../component';
3
+ import { defineRelationship } from '../relationship-index';
4
+ import { Update } from '../schedule-token';
5
+ import { World } from '../world';
6
+
7
+ const Marker = defineComponent('NanPreflightMarker', {});
8
+ const Numeric = defineComponent('NanPreflightNumeric', {
9
+ scalar: 'f32',
10
+ values: 'array<f32>',
11
+ });
12
+ const InlineNumeric = defineComponent('NanPreflightInlineNumeric', {
13
+ scalar: 'f32',
14
+ values: 'array<f32, 2>',
15
+ });
16
+ const { source: ParentOf, target: ChildrenOf } = defineRelationship({
17
+ sourceName: 'NanPreflightParentOf',
18
+ sourceField: 'parent',
19
+ targetName: 'NanPreflightChildrenOf',
20
+ targetField: 'children',
21
+ });
22
+
23
+ interface NumericValueError {
24
+ readonly code: string;
25
+ readonly detail: {
26
+ readonly component: string;
27
+ readonly field: string;
28
+ readonly received: unknown;
29
+ readonly index?: number;
30
+ };
31
+ }
32
+
33
+ function expectNumericValueError(
34
+ error: unknown,
35
+ expected: { readonly field: string; readonly received: unknown; readonly index?: number },
36
+ ): void {
37
+ expect(error).toBeDefined();
38
+ if (error === undefined) return;
39
+ const numericError = error as NumericValueError;
40
+ expect(numericError.code).toBe('component-numeric-value-invalid');
41
+ expect(numericError.detail).toMatchObject({
42
+ component: Numeric.name,
43
+ field: expected.field,
44
+ received: expected.received,
45
+ ...(expected.index === undefined ? {} : { index: expected.index }),
46
+ });
47
+ }
48
+
49
+ describe('component NaN object-write preflight', () => {
50
+ it('rejects spawn scalar NaN before entity or relationship mutation', () => {
51
+ const world = new World();
52
+ const parent = world.spawn({ component: Marker, data: {} }).unwrap();
53
+ const beforeCount = world.inspect().entityCount;
54
+ const beforeEpoch = world.getStructureEpoch();
55
+
56
+ const result = world.spawn(
57
+ { component: Numeric, data: { scalar: Number.NaN, values: [1, 2] } },
58
+ { component: ParentOf, data: { parent } },
59
+ );
60
+
61
+ expect(result.ok).toBe(false);
62
+ if (!result.ok)
63
+ expectNumericValueError(result.error, { field: 'scalar', received: Number.NaN });
64
+ expect(world.inspect().entityCount).toBe(beforeCount);
65
+ expect(world.getStructureEpoch()).toBe(beforeEpoch);
66
+ expect(world.get(parent, ChildrenOf).ok).toBe(false);
67
+ });
68
+
69
+ it('rejects addComponent array NaN before archetype or managed-array mutation', () => {
70
+ const world = new World();
71
+ const entity = world.spawn({ component: Marker, data: {} }).unwrap();
72
+ const beforeEpoch = world.getStructureEpoch();
73
+
74
+ const result = world.addComponent(entity, {
75
+ component: Numeric,
76
+ data: { scalar: 3, values: [1, Number.NaN] },
77
+ });
78
+
79
+ expect(result.ok).toBe(false);
80
+ if (!result.ok) {
81
+ expectNumericValueError(result.error, {
82
+ field: 'values',
83
+ received: Number.NaN,
84
+ index: 1,
85
+ });
86
+ }
87
+ expect(world.get(entity, Numeric).ok).toBe(false);
88
+ expect(world.getStructureEpoch()).toBe(beforeEpoch);
89
+ });
90
+
91
+ it('rejects set array NaN and preserves the complete old value', () => {
92
+ const world = new World();
93
+ const entity = world
94
+ .spawn({ component: Numeric, data: { scalar: 4, values: [1, 2] } })
95
+ .unwrap();
96
+
97
+ const result = world.set(entity, Numeric, { values: [7, Number.NaN] });
98
+
99
+ expect(result.ok).toBe(false);
100
+ if (!result.ok) {
101
+ expectNumericValueError(result.error, {
102
+ field: 'values',
103
+ received: Number.NaN,
104
+ index: 1,
105
+ });
106
+ }
107
+ const current = world.get(entity, Numeric).unwrap();
108
+ expect(current.scalar).toBe(4);
109
+ expect(Array.from(current.values)).toEqual([1, 2]);
110
+ });
111
+
112
+ it('rejects QueryRow.mut scalar NaN and preserves the old field', () => {
113
+ const world = new World();
114
+ const entity = world
115
+ .spawn({ component: Numeric, data: { scalar: 5, values: [1, 2] } })
116
+ .unwrap();
117
+ const row = world
118
+ .query({ write: [Numeric] })
119
+ .unwrap()
120
+ .at(entity);
121
+ expect(row).toBeDefined();
122
+ let thrown: unknown;
123
+
124
+ try {
125
+ if (row !== undefined) row.mut(Numeric).scalar = Number.NaN;
126
+ } catch (error) {
127
+ thrown = error;
128
+ }
129
+
130
+ expectNumericValueError(thrown, { field: 'scalar', received: Number.NaN });
131
+ expect(world.get(entity, Numeric).unwrap().scalar).toBe(5);
132
+ });
133
+
134
+ it('rejects a deferred command before adding the component', () => {
135
+ const world = new World();
136
+ const entity = world.spawn({ component: Marker, data: {} }).unwrap();
137
+ world
138
+ .addSystem(Update, {
139
+ name: 'nan-preflight-command',
140
+ queries: [],
141
+ fn: (_world, _queries, commands) => {
142
+ commands.addComponent(entity, {
143
+ component: Numeric,
144
+ data: { scalar: Number.NaN, values: [1, 2] },
145
+ });
146
+ },
147
+ })
148
+ .unwrap();
149
+
150
+ const result = world.update(0);
151
+
152
+ expect(result.ok).toBe(false);
153
+ if (!result.ok) {
154
+ expect(result.error.code).toBe('command-failed');
155
+ if (result.error.code === 'command-failed') {
156
+ expectNumericValueError(result.error.detail.cause, {
157
+ field: 'scalar',
158
+ received: Number.NaN,
159
+ });
160
+ }
161
+ }
162
+ expect(world.get(entity, Numeric).ok).toBe(false);
163
+ expect(world.execution.health).toBe('healthy');
164
+ });
165
+
166
+ it('accepts positive Infinity while leaving QuerySpan as the raw numeric boundary', () => {
167
+ const world = new World({ storage: 'shared' });
168
+ const entity = world
169
+ .spawn({
170
+ component: InlineNumeric,
171
+ data: { scalar: Number.POSITIVE_INFINITY, values: [Number.POSITIVE_INFINITY, 2] },
172
+ })
173
+ .unwrap();
174
+ expect(world.set(entity, InlineNumeric, { scalar: Number.POSITIVE_INFINITY }).ok).toBe(true);
175
+ expect(world.get(entity, InlineNumeric).unwrap().scalar).toBe(Number.POSITIVE_INFINITY);
176
+
177
+ const spans = world
178
+ .query({ write: [InlineNumeric] })
179
+ .unwrap()
180
+ .spans()
181
+ .unwrap();
182
+ for (const span of spans) span.mut(InlineNumeric).scalar[0] = Number.NaN;
183
+
184
+ expect(world.get(entity, InlineNumeric).unwrap().scalar).toBeNaN();
185
+ });
186
+ });
@@ -0,0 +1,119 @@
1
+ // Compile-time + runtime test for Component field-schema literal preservation +
2
+ // 4-probe quintet over SchemaVocabKeyword (w3, AC-09).
3
+ //
4
+ // Locks two invariants:
5
+ //
6
+ // 1. Literal preservation: defineComponent('Foo', { value: 'string' } as
7
+ // const) yields `SchemaOf<typeof Foo>['value']` typed as the literal `'string'`,
8
+ // not widened to plain `string`. AI users that read
9
+ // `SchemaOf<typeof Component>` gets the schema keyword as a literal
10
+ // type --- the basis of `isManagedField` switch / cascade discrimination.
11
+ //
12
+ // 2. 4-probe quintet (w4, plan-strategy §2.2 / D-R3 predicate merge):
13
+ // The legacy string-only + ref-only probes collapse into a single
14
+ // `isManagedField` arm covering both `'string'` and `'unique<T>'`. The
15
+ // remaining probes target the other SchemaVocabKeyword tiers:
16
+ // isManagedField => 'string' | 'unique<T>' (NEW unified arm)
17
+ // isManagedBufferField => 'buffer' / 'buffer<N>'
18
+ // isEntityField => 'entity'
19
+ // isManagedArrayField => 'array<T,N>' / 'array<T>'
20
+ // AI users grep `isXxxField` once and get the discrimination toolkit.
21
+
22
+ import { describe, expectTypeOf, it } from 'vitest';
23
+ import {
24
+ defineComponent,
25
+ isEntityField,
26
+ isManagedArrayField,
27
+ isManagedBufferField,
28
+ isManagedField,
29
+ type SchemaOf,
30
+ type SchemaVocabKeyword,
31
+ } from '../component';
32
+
33
+ describe('component schema --- literal preservation (w3, AC-09)', () => {
34
+ it("defineComponent('Foo', { value: 'string' }) preserves 'string' literal", () => {
35
+ const Foo = defineComponent('Foo', { value: 'string' });
36
+ type ValueField = SchemaOf<typeof Foo>['value'];
37
+ expectTypeOf<ValueField>().toEqualTypeOf<'string'>();
38
+
39
+ // The token intentionally exposes only name/fields/storage. These
40
+ // negative probes keep removed convenience facts out of autocomplete.
41
+ // @ts-expect-error Component.schema was removed; use SchemaOf<typeof Foo>.
42
+ void Foo.schema;
43
+ // @ts-expect-error Component.id is an ECS-owner fact, not token data.
44
+ void Foo.id;
45
+ // @ts-expect-error Component.defaults lives in componentDefinition(Foo).
46
+ void Foo.defaults;
47
+ // @ts-expect-error Component.toSchemaJSON was removed with the duplicate projection.
48
+ void Foo.toSchemaJSON;
49
+ });
50
+
51
+ it('schema literal is *not* widened to plain `string`', () => {
52
+ const Foo = defineComponent('Foo', { value: 'string' });
53
+ type ValueField = SchemaOf<typeof Foo>['value'];
54
+ // The literal must NOT widen to base `string` --- AI users rely on the
55
+ // narrow type for switch / cascade discrimination.
56
+ expectTypeOf<ValueField>().not.toEqualTypeOf<string>();
57
+ });
58
+
59
+ it('multi-field schemas preserve every keyword literal', () => {
60
+ const Bar = defineComponent('Bar', {
61
+ name: 'string',
62
+ mass: 'f32',
63
+ target: 'entity',
64
+ });
65
+ expectTypeOf<SchemaOf<typeof Bar>['name']>().toEqualTypeOf<'string'>();
66
+ expectTypeOf<SchemaOf<typeof Bar>['mass']>().toEqualTypeOf<'f32'>();
67
+ expectTypeOf<SchemaOf<typeof Bar>['target']>().toEqualTypeOf<'entity'>();
68
+ });
69
+ });
70
+
71
+ describe('component schema --- 4-probe quintet (w3, AC-09)', () => {
72
+ it('all four probes have signature `(s: string) => boolean`', () => {
73
+ expectTypeOf(isManagedField).toEqualTypeOf<(s: string) => boolean>();
74
+ expectTypeOf(isManagedBufferField).toEqualTypeOf<(s: string) => boolean>();
75
+ expectTypeOf(isEntityField).toEqualTypeOf<(s: string) => boolean>();
76
+ expectTypeOf(isManagedArrayField).toEqualTypeOf<(s: string) => boolean>();
77
+ });
78
+
79
+ it("isManagedField recognises 'string' literal and 'unique<T>' template", () => {
80
+ // Behavioural assertions (AC-09) --- the unified arm must cover both
81
+ // `'string'` and `'unique<T>'` keywords in a single predicate.
82
+ expectTypeOf(isManagedField('string')).toEqualTypeOf<boolean>();
83
+ expectTypeOf(isManagedField('unique<MeshAsset>')).toEqualTypeOf<boolean>();
84
+ // Runtime cases:
85
+ if (!isManagedField('string')) throw new Error("isManagedField('string') must be true");
86
+ if (!isManagedField('unique<MeshAsset>'))
87
+ throw new Error("isManagedField('unique<MeshAsset>') must be true");
88
+ if (isManagedField('entity')) throw new Error("isManagedField('entity') must be false");
89
+ if (isManagedField('buffer<128>'))
90
+ throw new Error("isManagedField('buffer<128>') must be false");
91
+ // 'buffer' bare keyword is not a SchemaVocabKeyword but the predicate
92
+ // must still reject it (defensive for the erased runtime call site).
93
+ if (isManagedField('buffer')) throw new Error("isManagedField('buffer') must be false");
94
+ });
95
+
96
+ it('SchemaVocabKeyword closed union has 7 members covered by 4 probes', () => {
97
+ // Mapping (membership <-> probe):
98
+ // buffer / buffer<N> => isManagedBufferField
99
+ // ref<T> => isManagedField (NEW unified arm w/ 'string')
100
+ // handle<T> => (no managed probe; ECS treats handles as opaque)
101
+ // entity => isEntityField
102
+ // array<T,N> + array<T> => isManagedArrayField (counts as one)
103
+ // string => isManagedField (NEW unified arm w/ 'unique<T>')
104
+ //
105
+ // The closed union still has exactly 7 template-literal arms; we lock
106
+ // the union shape so any drift (e.g. removing one arm or adding a
107
+ // sixth probe family) shows up as a type error.
108
+ type Sample =
109
+ | 'buffer<128>'
110
+ | 'unique<MaterialAsset>'
111
+ | 'shared<MeshAsset>'
112
+ | 'entity'
113
+ | 'array<f32, 16>'
114
+ | 'array<u32>'
115
+ | 'string';
116
+ // Every member of `Sample` is assignable to `SchemaVocabKeyword`.
117
+ expectTypeOf<Sample>().toMatchTypeOf<SchemaVocabKeyword>();
118
+ });
119
+ });
@@ -0,0 +1,55 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { defineComponent } from '../component';
3
+ import { assertComponentStorage, componentDefinition, deepFreeze } from '../component-schema';
4
+
5
+ describe('component schema contract', () => {
6
+ it('deep freezes nested field facts and owner defaults', () => {
7
+ const component = defineComponent('SchemaFreeze', {
8
+ mode: { type: 'enum', default: 1, labels: { idle: 0, run: 1 } },
9
+ payload: { type: 'array<f32, 2>', default: [1, 2] as never },
10
+ });
11
+
12
+ expect(Object.isFrozen(component.fields)).toBe(true);
13
+ expect(Object.isFrozen(component.fields.mode)).toBe(true);
14
+ expect(Object.isFrozen(component.fields.mode?.labels)).toBe(true);
15
+ const defaults = componentDefinition(component).defaults;
16
+ expect(Object.isFrozen(defaults)).toBe(true);
17
+ expect(Object.isFrozen(defaults?.payload)).toBe(true);
18
+ });
19
+
20
+ it('keeps the public token surface to name, fields, and storage', () => {
21
+ const component = defineComponent('ComponentSurface', { value: 'f32' });
22
+ expect(Object.keys(component)).toEqual(['name', 'fields', 'storage']);
23
+ expect(Reflect.ownKeys(component)).toEqual(['name', 'fields', 'storage']);
24
+ expect(Object.getPrototypeOf(component)).toBe(Object.prototype);
25
+ expect('schema' in component).toBe(false);
26
+ expect('id' in component).toBe(false);
27
+ expect('defaults' in component).toBe(false);
28
+ expect('toSchemaJSON' in component).toBe(false);
29
+ });
30
+
31
+ it('accepts only the closed table/sparse storage vocabulary', () => {
32
+ expect(() => assertComponentStorage('table')).not.toThrow();
33
+ expect(() => assertComponentStorage('sparse')).not.toThrow();
34
+ expect(() => assertComponentStorage('columnar')).toThrow(/Expected 'table' or 'sparse'/);
35
+ expect(deepFreeze({ nested: { value: 1 } }).nested).toEqual({ value: 1 });
36
+ });
37
+
38
+ it('treats typed arrays and ArrayBuffer as immutable leaf projections', () => {
39
+ const values = new Float32Array([1, 2]);
40
+ const buffer = new ArrayBuffer(8);
41
+
42
+ const projected = deepFreeze({ values, buffer });
43
+ expect(Object.isFrozen(projected)).toBe(true);
44
+ expect(Object.isFrozen(values)).toBe(false);
45
+ expect(Object.isFrozen(buffer)).toBe(false);
46
+ expect(values[0]).toBe(1);
47
+ expect(buffer.byteLength).toBe(8);
48
+ });
49
+
50
+ it('rejects an invalid runtime storage value before registration', () => {
51
+ expect(() => defineComponent('InvalidStorage', {}, { storage: 'columnar' as 'table' })).toThrow(
52
+ /Expected 'table' or 'sparse'/,
53
+ );
54
+ });
55
+ });
@@ -0,0 +1,35 @@
1
+ // Compile-time type-derivation tests for the DefineComponentOptions surface
2
+ // after the M1 buffer/array vocab collapse (w3, AC-05).
3
+ //
4
+ // Locks the `arrayStride` option-bit removal: passing an `arrayStride` map
5
+ // to `defineComponent`'s third options arg is a TS compile-time error after
6
+ // w5. The stride contract migrates to RenderSystem-extract entry-site
7
+ // defensive plus AI user set-site responsibility (plan-strategy §2.3).
8
+ //
9
+ // Pre-M1 (before w5): `arrayStride: { ... }` is a valid option on
10
+ // `DefineComponentOptions` and the @ts-expect-error directive is unsatisfied
11
+ // (TDD red state).
12
+ //
13
+ // Post-M1 (after w5): the option is removed; the directive is satisfied; the
14
+ // surface is narrower.
15
+
16
+ import { describe, it } from 'vitest';
17
+ import { type DefineComponentOptions, defineComponent } from '../component';
18
+
19
+ describe('DefineComponentOptions — arrayStride option-bit removed (w3, AC-05)', () => {
20
+ it('arrayStride is no longer a key on DefineComponentOptions', () => {
21
+ type Opts = DefineComponentOptions;
22
+ // @ts-expect-error 'arrayStride' is no longer a key on DefineComponentOptions
23
+ // after feat-20260515 w5 (stride responsibility migrated to RenderSystem
24
+ // extract entry).
25
+ const opts: Opts = { arrayStride: { f: 16 } };
26
+ void opts;
27
+ });
28
+
29
+ it('defineComponent rejects arrayStride at the call-site', () => {
30
+ // @ts-expect-error 'arrayStride' is no longer accepted by defineComponent
31
+ // after feat-20260515 w5.
32
+ const Bar = defineComponent('Bar', { f: { type: 'array<f32>' } }, { arrayStride: { f: 16 } });
33
+ void Bar;
34
+ });
35
+ });
@@ -0,0 +1,59 @@
1
+ // feat-20260614 M5 / w25 — runtime rejection tests for the two retired
2
+ // schema-vocab keyword families. Both renames preserve brand and storage
3
+ // layout; only the keyword + dispatch arm changed. The
4
+ // SchemaUnsupportedFieldError migration hint redirects AI users straight
5
+ // to the new keyword (charter F1 single-entry indexability).
6
+ //
7
+ // 'ref<T>' -> hint contains 'unique<T>' (M1 rename)
8
+ // 'handle<T>' -> hint contains 'shared<T>' (M5 cut)
9
+ //
10
+ // AC-14 (requirements): writing either deprecated literal to defineComponent
11
+ // must throw a structured error with the migration hint pointing at the
12
+ // replacement keyword.
13
+
14
+ import { describe, expect, it } from 'vitest';
15
+ import { defineComponent } from '../component';
16
+
17
+ describe('w25 deprecated schema-vocab rejection', () => {
18
+ it("'handle<MeshAsset>' throws SchemaUnsupportedFieldError + hint mentions 'shared<MeshAsset>'", () => {
19
+ // gate-allow:ecs-brand
20
+ let caught: unknown;
21
+ try {
22
+ defineComponent('w25HandleSample', { f: { type: 'handle<MeshAsset>' } } as never); // gate-allow:ecs-brand
23
+ } catch (e) {
24
+ caught = e;
25
+ }
26
+ expect(caught).toBeDefined();
27
+ const e = caught as { code: string; hint: string };
28
+ expect(e.code).toBe('schema-unsupported-field');
29
+ expect(e.hint).toContain("'shared<MeshAsset>'");
30
+ expect(e.hint).toContain('feat-20260614 M5');
31
+ });
32
+
33
+ it("'ref<PhysicsBody>' throws SchemaUnsupportedFieldError + hint mentions 'unique<PhysicsBody>'", () => {
34
+ // gate-allow:ecs-brand
35
+ let caught: unknown;
36
+ try {
37
+ defineComponent('w25RefSample', { f: { type: 'ref<PhysicsBody>' } } as never); // gate-allow:ecs-brand
38
+ } catch (e) {
39
+ caught = e;
40
+ }
41
+ expect(caught).toBeDefined();
42
+ const e = caught as { code: string; hint: string };
43
+ expect(e.code).toBe('schema-unsupported-field');
44
+ expect(e.hint).toContain("'unique<PhysicsBody>'");
45
+ expect(e.hint).toContain('feat-20260614 M1');
46
+ });
47
+
48
+ it("'shared<MeshAsset>' is accepted (the new keyword still works)", () => {
49
+ expect(() => {
50
+ defineComponent('w25SharedSample', { f: { type: 'shared<MeshAsset>' } });
51
+ }).not.toThrow();
52
+ });
53
+
54
+ it("'unique<PhysicsBody>' is accepted (the new keyword still works)", () => {
55
+ expect(() => {
56
+ defineComponent('w25UniqueSample', { f: { type: 'unique<PhysicsBody>' } });
57
+ }).not.toThrow();
58
+ });
59
+ });
@@ -0,0 +1,17 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { defineComponent, World } from '../index';
4
+
5
+ describe('World.despawnAll', () => {
6
+ it('routes every live entity through normal despawn cleanup', () => {
7
+ const Marker = defineComponent('DespawnAllMarker', { value: 'u32' });
8
+ const world = new World();
9
+ world.spawn({ component: Marker, data: { value: 1 } }).unwrap();
10
+ world.spawn({ component: Marker, data: { value: 2 } }).unwrap();
11
+
12
+ const result = world.despawnAll();
13
+
14
+ expect(result.ok).toBe(true);
15
+ expect(world.inspect().entityCount).toBe(0);
16
+ });
17
+ });
@@ -0,0 +1,130 @@
1
+ import { defineComponent, defineRelationship, Update, World } from '@forgeax/engine-ecs';
2
+ import { describe, expect, it } from 'vitest';
3
+
4
+ const { source: ChildOf, target: Children } = defineRelationship({
5
+ sourceName: 'ReductionChildOf',
6
+ sourceField: 'parent',
7
+ targetName: 'ReductionChildren',
8
+ targetField: 'entities',
9
+ });
10
+ const { source: AnimatedBy, target: AnimationTargets } = defineRelationship({
11
+ sourceName: 'ReductionAnimatedBy',
12
+ sourceField: 'player',
13
+ targetName: 'ReductionAnimationTargets',
14
+ targetField: 'targets',
15
+ });
16
+
17
+ describe('M0 ECS reduction characterization', () => {
18
+ it('F-01: exposes pending reservations after a system throws', () => {
19
+ const Marker = defineComponent('M0PendingMarker', {});
20
+ const world = new World();
21
+
22
+ world.addSystem(Update, {
23
+ name: 'throw-after-reservation',
24
+ queries: [],
25
+ fn: (_world, _queries, commands) => {
26
+ commands.spawn({ component: Marker, data: {} });
27
+ throw new Error('M0 system failure');
28
+ },
29
+ });
30
+
31
+ const result = world.update(0);
32
+ expect(result.ok).toBe(false);
33
+ if (!result.ok) {
34
+ expect(result.error.code).toBe('system-failed');
35
+ if (result.error.code === 'system-failed') {
36
+ expect(result.error.detail.cause).toBeInstanceOf(Error);
37
+ }
38
+ }
39
+ expect(world.execution.health).toBe('poisoned');
40
+ });
41
+
42
+ it('F-02: preserves a failed command result at the public update boundary', () => {
43
+ const Marker = defineComponent('M0CommandMarker', {});
44
+ const world = new World();
45
+ const entity = world.spawn({ component: Marker, data: {} }).unwrap();
46
+ const before = world.inspect().entityCount;
47
+
48
+ world.addSystem(Update, {
49
+ name: 'duplicate-component-command',
50
+ queries: [],
51
+ fn: (_world, _queries, commands) => {
52
+ commands.addComponent(entity, { component: Marker, data: {} });
53
+ },
54
+ });
55
+
56
+ const result = world.update(0);
57
+ expect(result.ok).toBe(false);
58
+ if (!result.ok) {
59
+ expect(result.error.code).toBe('command-failed');
60
+ if (result.error.code === 'command-failed') {
61
+ expect(result.error.detail.systemName).toBe('duplicate-component-command');
62
+ expect(result.error.detail.commandKind).toBe('addComponent');
63
+ expect((result.error.detail.cause as { readonly code?: string }).code).toBe(
64
+ 'component-already-present',
65
+ );
66
+ }
67
+ }
68
+ expect(world.execution.health).toBe('healthy');
69
+ expect(world.inspect().entityCount).toBe(before);
70
+ });
71
+
72
+ it('F-03: despawn does not own shared payload disposal', () => {
73
+ const world = new World();
74
+ const payload = { id: 1 };
75
+ const handle = world.allocSharedRef('M0Asset', payload);
76
+ const Holder = defineComponent('M0SharedHolder', { asset: 'shared<M0Asset>' });
77
+ const entity = world.spawn({ component: Holder, data: { asset: handle } }).unwrap();
78
+ world.sharedRefs.release(handle).unwrap();
79
+
80
+ expect(() => world.despawn(entity)).not.toThrow();
81
+ expect(world.sharedRefs.readReleaseEvidence()).toEqual([
82
+ { payload, refcount: 0, generation: 1, evidence: 'released' },
83
+ ]);
84
+ });
85
+
86
+ it('F-07: rejects undefined shared payloads before allocating a slot', () => {
87
+ const world = new World();
88
+ expect(() => world.allocSharedRef('M0UndefinedAsset', undefined)).toThrow();
89
+ });
90
+
91
+ it('T-02: rejects an invalid managed-array payload without a row delta', () => {
92
+ const Values = defineComponent('M0ManagedValues', { values: 'array<f32>' });
93
+ const world = new World();
94
+ const beforeEntityCount = world.inspect().entityCount;
95
+ const beforeEpoch = world.getStructureEpoch();
96
+
97
+ const result = world.spawn({
98
+ component: Values,
99
+ data: { values: { invalid: true } as never },
100
+ });
101
+
102
+ expect(result.ok).toBe(false);
103
+ expect(world.inspect().entityCount).toBe(beforeEntityCount);
104
+ expect(world.getStructureEpoch()).toBe(beforeEpoch);
105
+ });
106
+
107
+ it('keeps ChildOf/Children and AnimatedBy/AnimationTargets as materialized target pairs', () => {
108
+ const world = new World();
109
+ const parent = world.spawn({ component: Children, data: { entities: [] } }).unwrap();
110
+ const child = world.spawn({ component: ChildOf, data: { parent } }).unwrap();
111
+ const children = world.get(parent, Children).unwrap().entities;
112
+ expect([...children]).toContain(child);
113
+
114
+ const player = world.spawn({ component: AnimationTargets, data: { targets: [] } }).unwrap();
115
+ const target = world.spawn({ component: AnimatedBy, data: { player } }).unwrap();
116
+ const targets = world.get(player, AnimationTargets).unwrap().targets;
117
+ expect([...targets]).toContain(target);
118
+
119
+ const childrenEpoch = world.getStructureEpoch();
120
+ // Relationship target components are intentionally not writable through
121
+ // the typed mutation facade; the runtime returns a structured refusal.
122
+ // @ts-expect-error relationship target is a read-only projection.
123
+ const targetWrite = world.set(parent, Children, { entities: [] });
124
+ // @ts-expect-error relationship target is a read-only projection.
125
+ const animationTargetWrite = world.set(player, AnimationTargets, { targets: [] });
126
+ expect(childrenEpoch).toBeLessThanOrEqual(world.getStructureEpoch());
127
+ expect(targetWrite.ok).toBe(false);
128
+ expect(animationTargetWrite.ok).toBe(false);
129
+ });
130
+ });