@things-factory/headless-twin 10.0.9 → 10.0.11

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 (354) hide show
  1. package/dist-server/engine/canonical-ingest.d.ts +2 -2
  2. package/dist-server/engine/canonical-ingest.js +24 -2
  3. package/dist-server/engine/canonical-ingest.js.map +1 -1
  4. package/dist-server/engine/command-routing.js +1 -1
  5. package/dist-server/engine/command-routing.js.map +1 -1
  6. package/dist-server/engine/energy-topology.d.ts +86 -0
  7. package/dist-server/engine/energy-topology.js +144 -0
  8. package/dist-server/engine/energy-topology.js.map +1 -0
  9. package/dist-server/engine/index.d.ts +8 -3
  10. package/dist-server/engine/index.js +10 -3
  11. package/dist-server/engine/index.js.map +1 -1
  12. package/dist-server/engine/kpi-baseline.d.ts +1 -1
  13. package/dist-server/engine/kpi-baseline.js.map +1 -1
  14. package/dist-server/engine/kpi-fold.d.ts +137 -1
  15. package/dist-server/engine/kpi-fold.js +225 -0
  16. package/dist-server/engine/kpi-fold.js.map +1 -1
  17. package/dist-server/engine/kpi-query.d.ts +1 -1
  18. package/dist-server/engine/kpi-query.js +212 -18
  19. package/dist-server/engine/kpi-query.js.map +1 -1
  20. package/dist-server/engine/kpi-target.d.ts +17 -0
  21. package/dist-server/engine/kpi-target.js +24 -2
  22. package/dist-server/engine/kpi-target.js.map +1 -1
  23. package/dist-server/engine/live-feed-registry.d.ts +25 -0
  24. package/dist-server/engine/live-feed-registry.js +51 -0
  25. package/dist-server/engine/live-feed-registry.js.map +1 -0
  26. package/dist-server/engine/load-meter.d.ts +181 -0
  27. package/dist-server/engine/load-meter.js +267 -0
  28. package/dist-server/engine/load-meter.js.map +1 -0
  29. package/dist-server/engine/local-declarations.d.ts +262 -0
  30. package/dist-server/engine/local-declarations.js +528 -0
  31. package/dist-server/engine/local-declarations.js.map +1 -0
  32. package/dist-server/engine/model-basis.d.ts +39 -6
  33. package/dist-server/engine/model-basis.js +69 -9
  34. package/dist-server/engine/model-basis.js.map +1 -1
  35. package/dist-server/engine/{board-vocabulary.d.ts → model-vocabulary.d.ts} +4 -4
  36. package/dist-server/engine/{board-vocabulary.js → model-vocabulary.js} +37 -19
  37. package/dist-server/engine/model-vocabulary.js.map +1 -0
  38. package/dist-server/engine/oee-accumulator.d.ts +28 -0
  39. package/dist-server/engine/oee-accumulator.js +26 -1
  40. package/dist-server/engine/oee-accumulator.js.map +1 -1
  41. package/dist-server/engine/operation-basis.d.ts +32 -0
  42. package/dist-server/engine/operation-basis.js +87 -0
  43. package/dist-server/engine/operation-basis.js.map +1 -0
  44. package/dist-server/engine/property-effects.d.ts +30 -0
  45. package/dist-server/engine/property-effects.js +192 -0
  46. package/dist-server/engine/property-effects.js.map +1 -0
  47. package/dist-server/engine/runtime-key.d.ts +1 -1
  48. package/dist-server/engine/runtime-key.js +1 -1
  49. package/dist-server/engine/runtime-key.js.map +1 -1
  50. package/dist-server/engine/spec-coverage.js +3 -3
  51. package/dist-server/engine/spec-coverage.js.map +1 -1
  52. package/dist-server/engine/state-axes.d.ts +7 -2
  53. package/dist-server/engine/state-axes.js +8 -3
  54. package/dist-server/engine/state-axes.js.map +1 -1
  55. package/dist-server/engine/structure-diff.js +1 -1
  56. package/dist-server/engine/structure-diff.js.map +1 -1
  57. package/dist-server/engine/travel-estimator.d.ts +9 -2
  58. package/dist-server/engine/travel-estimator.js +11 -6
  59. package/dist-server/engine/travel-estimator.js.map +1 -1
  60. package/dist-server/engine/twin-engine.d.ts +332 -47
  61. package/dist-server/engine/twin-engine.js +1314 -279
  62. package/dist-server/engine/twin-engine.js.map +1 -1
  63. package/dist-server/engine/warm-start.d.ts +38 -4
  64. package/dist-server/engine/warm-start.js +38 -9
  65. package/dist-server/engine/warm-start.js.map +1 -1
  66. package/dist-server/index.d.ts +1 -0
  67. package/dist-server/index.js +17 -11
  68. package/dist-server/index.js.map +1 -1
  69. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.d.ts +5 -0
  70. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js +48 -0
  71. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js.map +1 -0
  72. package/dist-server/migrations/index.d.ts +2 -0
  73. package/dist-server/migrations/index.js +10 -0
  74. package/dist-server/migrations/index.js.map +1 -0
  75. package/dist-server/service/index.d.ts +3 -2
  76. package/dist-server/service/index.js +25 -17
  77. package/dist-server/service/index.js.map +1 -1
  78. package/dist-server/service/reference/discovery-result.d.ts +1 -1
  79. package/dist-server/service/reference/discovery-result.js +2 -2
  80. package/dist-server/service/reference/discovery-result.js.map +1 -1
  81. package/dist-server/service/reference/ingest-space.d.ts +24 -1
  82. package/dist-server/service/reference/ingest-space.js +17 -1
  83. package/dist-server/service/reference/ingest-space.js.map +1 -1
  84. package/dist-server/service/reference/reference-live.d.ts +23 -0
  85. package/dist-server/service/reference/reference-live.js +121 -4
  86. package/dist-server/service/reference/reference-live.js.map +1 -1
  87. package/dist-server/service/reference/reference-master.d.ts +194 -13
  88. package/dist-server/service/reference/reference-master.js +159 -28
  89. package/dist-server/service/reference/reference-master.js.map +1 -1
  90. package/dist-server/service/reference/reference-resolver.d.ts +31 -1
  91. package/dist-server/service/reference/reference-resolver.js +223 -12
  92. package/dist-server/service/reference/reference-resolver.js.map +1 -1
  93. package/dist-server/service/reference/template-registry.d.ts +19 -3
  94. package/dist-server/service/reference/template-registry.js.map +1 -1
  95. package/dist-server/service/twin-audit/command-audit.d.ts +37 -0
  96. package/dist-server/service/twin-audit/command-audit.js +53 -0
  97. package/dist-server/service/twin-audit/command-audit.js.map +1 -0
  98. package/dist-server/service/twin-audit/index.d.ts +4 -0
  99. package/dist-server/service/twin-audit/index.js +8 -0
  100. package/dist-server/service/twin-audit/index.js.map +1 -0
  101. package/dist-server/service/twin-audit/twin-audit-event.d.ts +24 -0
  102. package/dist-server/service/twin-audit/twin-audit-event.js +141 -0
  103. package/dist-server/service/twin-audit/twin-audit-event.js.map +1 -0
  104. package/dist-server/service/twin-audit/twin-audit-query.d.ts +4 -0
  105. package/dist-server/service/twin-audit/twin-audit-query.js +76 -0
  106. package/dist-server/service/twin-audit/twin-audit-query.js.map +1 -0
  107. package/dist-server/service/twin-control/twin-control-mutation.js +21 -1
  108. package/dist-server/service/twin-control/twin-control-mutation.js.map +1 -1
  109. package/dist-server/service/twin-event/twin-event-keys.d.ts +1 -1
  110. package/dist-server/service/twin-event/twin-event-keys.js +1 -1
  111. package/dist-server/service/twin-event/twin-event-keys.js.map +1 -1
  112. package/dist-server/service/twin-event/twin-event.d.ts +14 -5
  113. package/dist-server/service/twin-event/twin-event.js +45 -13
  114. package/dist-server/service/twin-event/twin-event.js.map +1 -1
  115. package/dist-server/service/twin-forecast/forecast-metrics.d.ts +13 -0
  116. package/dist-server/service/twin-forecast/forecast-metrics.js +57 -0
  117. package/dist-server/service/twin-forecast/forecast-metrics.js.map +1 -0
  118. package/dist-server/service/twin-forecast/forecast-tuning.d.ts +12 -0
  119. package/dist-server/service/twin-forecast/forecast-tuning.js +44 -0
  120. package/dist-server/service/twin-forecast/forecast-tuning.js.map +1 -0
  121. package/dist-server/service/twin-forecast/gap-analytics.d.ts +28 -2
  122. package/dist-server/service/twin-forecast/gap-analytics.js +43 -17
  123. package/dist-server/service/twin-forecast/gap-analytics.js.map +1 -1
  124. package/dist-server/service/twin-forecast/twin-forecast-query.js +217 -38
  125. package/dist-server/service/twin-forecast/twin-forecast-query.js.map +1 -1
  126. package/dist-server/service/twin-instance/twin-instance.d.ts +38 -5
  127. package/dist-server/service/twin-instance/twin-instance.js +66 -20
  128. package/dist-server/service/twin-instance/twin-instance.js.map +1 -1
  129. package/dist-server/service/twin-journal/twin-journal-query.d.ts +5 -2
  130. package/dist-server/service/twin-journal/twin-journal-query.js +71 -9
  131. package/dist-server/service/twin-journal/twin-journal-query.js.map +1 -1
  132. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.d.ts +3 -5
  133. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js +24 -27
  134. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +1 -1
  135. package/dist-server/service/twin-metrics/twin-metrics-query.d.ts +1 -0
  136. package/dist-server/service/twin-metrics/twin-metrics-query.js +62 -0
  137. package/dist-server/service/twin-metrics/twin-metrics-query.js.map +1 -1
  138. package/dist-server/service/twin-model/epcis-coverage.d.ts +14 -0
  139. package/dist-server/service/twin-model/epcis-coverage.js +174 -0
  140. package/dist-server/service/twin-model/epcis-coverage.js.map +1 -0
  141. package/dist-server/service/twin-model/iec61850-coverage.d.ts +14 -0
  142. package/dist-server/service/twin-model/iec61850-coverage.js +98 -0
  143. package/dist-server/service/twin-model/iec61850-coverage.js.map +1 -0
  144. package/dist-server/service/twin-model/index.d.ts +13 -0
  145. package/dist-server/service/twin-model/index.js +29 -0
  146. package/dist-server/service/twin-model/index.js.map +1 -0
  147. package/dist-server/service/twin-model/isa95-coverage.d.ts +48 -0
  148. package/dist-server/service/twin-model/isa95-coverage.js +155 -0
  149. package/dist-server/service/twin-model/isa95-coverage.js.map +1 -0
  150. package/dist-server/service/twin-model/project-structure.d.ts +16 -0
  151. package/dist-server/service/twin-model/project-structure.js +173 -0
  152. package/dist-server/service/twin-model/project-structure.js.map +1 -0
  153. package/dist-server/service/twin-model/standard-coverage.d.ts +9 -0
  154. package/dist-server/service/twin-model/standard-coverage.js +37 -0
  155. package/dist-server/service/twin-model/standard-coverage.js.map +1 -0
  156. package/dist-server/service/twin-model/twin-equipment.d.ts +64 -0
  157. package/dist-server/service/twin-model/twin-equipment.js +134 -0
  158. package/dist-server/service/twin-model/twin-equipment.js.map +1 -0
  159. package/dist-server/service/twin-model/twin-lineage-query.d.ts +3 -0
  160. package/dist-server/service/twin-model/twin-lineage-query.js +206 -0
  161. package/dist-server/service/twin-model/twin-lineage-query.js.map +1 -0
  162. package/dist-server/service/twin-model/twin-location.d.ts +58 -0
  163. package/dist-server/service/twin-model/twin-location.js +130 -0
  164. package/dist-server/service/twin-model/twin-location.js.map +1 -0
  165. package/dist-server/service/twin-model/twin-model-item-query.d.ts +141 -0
  166. package/dist-server/service/twin-model/twin-model-item-query.js +852 -0
  167. package/dist-server/service/twin-model/twin-model-item-query.js.map +1 -0
  168. package/dist-server/service/twin-model/twin-model-mutation.d.ts +57 -0
  169. package/dist-server/service/twin-model/twin-model-mutation.js +490 -0
  170. package/dist-server/service/twin-model/twin-model-mutation.js.map +1 -0
  171. package/dist-server/service/twin-model/twin-model-query.d.ts +43 -0
  172. package/dist-server/service/twin-model/twin-model-query.js +551 -0
  173. package/dist-server/service/twin-model/twin-model-query.js.map +1 -0
  174. package/dist-server/service/twin-model/twin-model-tree-query.d.ts +3 -0
  175. package/dist-server/service/twin-model/twin-model-tree-query.js +158 -0
  176. package/dist-server/service/twin-model/twin-model-tree-query.js.map +1 -0
  177. package/dist-server/service/twin-model/twin-operation.d.ts +61 -0
  178. package/dist-server/service/twin-model/twin-operation.js +137 -0
  179. package/dist-server/service/twin-model/twin-operation.js.map +1 -0
  180. package/dist-server/service/twin-space/move-space.d.ts +65 -0
  181. package/dist-server/service/twin-space/move-space.js +166 -0
  182. package/dist-server/service/twin-space/move-space.js.map +1 -0
  183. package/dist-server/service/twin-space/space-integrity.d.ts +97 -0
  184. package/dist-server/service/twin-space/space-integrity.js +182 -0
  185. package/dist-server/service/twin-space/space-integrity.js.map +1 -0
  186. package/dist-server/service/twin-space/twin-space-area.js +4 -4
  187. package/dist-server/service/twin-space/twin-space-area.js.map +1 -1
  188. package/dist-server/service/twin-space/twin-space-representation.js +6 -6
  189. package/dist-server/service/twin-space/twin-space-representation.js.map +1 -1
  190. package/dist-server/service/twin-space/twin-space-resolver.d.ts +63 -1
  191. package/dist-server/service/twin-space/twin-space-resolver.js +356 -18
  192. package/dist-server/service/twin-space/twin-space-resolver.js.map +1 -1
  193. package/dist-server/service/twin-space/twin-space.d.ts +17 -1
  194. package/dist-server/service/twin-space/twin-space.js +15 -5
  195. package/dist-server/service/twin-space/twin-space.js.map +1 -1
  196. package/dist-server/service/twin-structure/twin-structure.d.ts +1 -1
  197. package/dist-server/service/twin-structure/twin-structure.js +8 -8
  198. package/dist-server/service/twin-structure/twin-structure.js.map +1 -1
  199. package/dist-shared/axis-read.d.ts +12 -0
  200. package/dist-shared/axis-read.js +32 -0
  201. package/dist-shared/axis-read.js.map +1 -0
  202. package/{dist-server/engine → dist-shared}/entity-delta.d.ts +3 -0
  203. package/{dist-server/engine → dist-shared}/entity-delta.js +102 -2
  204. package/dist-shared/entity-delta.js.map +1 -0
  205. package/dist-shared/kpi-broadcast.js.map +1 -0
  206. package/dist-shared/twin-level.js.map +1 -0
  207. package/package.json +14 -12
  208. package/server/engine/canonical-ingest.ts +36 -4
  209. package/server/engine/command-routing.ts +1 -1
  210. package/server/engine/energy-topology.ts +189 -0
  211. package/server/engine/index.ts +10 -3
  212. package/server/engine/kpi-baseline.ts +1 -1
  213. package/server/engine/kpi-fold.ts +389 -1
  214. package/server/engine/kpi-query.ts +214 -19
  215. package/server/engine/kpi-target.ts +24 -2
  216. package/server/engine/live-feed-registry.ts +58 -0
  217. package/server/engine/load-meter.ts +384 -0
  218. package/server/engine/local-declarations.ts +700 -0
  219. package/server/engine/model-basis.ts +78 -10
  220. package/server/engine/{board-vocabulary.ts → model-vocabulary.ts} +36 -15
  221. package/server/engine/oee-accumulator.ts +34 -1
  222. package/server/engine/operation-basis.ts +100 -0
  223. package/server/engine/property-effects.ts +199 -0
  224. package/server/engine/runtime-key.ts +1 -1
  225. package/server/engine/spec-coverage.ts +3 -3
  226. package/server/engine/state-axes.ts +8 -3
  227. package/server/engine/structure-diff.ts +1 -1
  228. package/server/engine/travel-estimator.ts +11 -6
  229. package/server/engine/twin-engine.ts +1414 -274
  230. package/server/engine/warm-start.ts +83 -12
  231. package/server/index.ts +13 -10
  232. package/server/migrations/1786000000000-RenameTwinInstanceBoardToModel.ts +43 -0
  233. package/server/migrations/index.ts +7 -0
  234. package/server/service/index.ts +9 -1
  235. package/server/service/reference/discovery-result.ts +2 -2
  236. package/server/service/reference/ingest-space.ts +35 -1
  237. package/server/service/reference/reference-live.ts +119 -4
  238. package/server/service/reference/reference-master.ts +276 -35
  239. package/server/service/reference/reference-resolver.ts +232 -12
  240. package/server/service/reference/template-registry.ts +20 -5
  241. package/server/service/twin-audit/command-audit.ts +81 -0
  242. package/server/service/twin-audit/index.ts +5 -0
  243. package/server/service/twin-audit/twin-audit-event.ts +138 -0
  244. package/server/service/twin-audit/twin-audit-query.ts +72 -0
  245. package/server/service/twin-control/twin-control-mutation.ts +22 -1
  246. package/server/service/twin-event/twin-event-keys.ts +1 -1
  247. package/server/service/twin-event/twin-event.ts +59 -14
  248. package/server/service/twin-forecast/forecast-metrics.ts +60 -0
  249. package/server/service/twin-forecast/forecast-tuning.ts +40 -0
  250. package/server/service/twin-forecast/gap-analytics.ts +48 -9
  251. package/server/service/twin-forecast/twin-forecast-query.ts +208 -36
  252. package/server/service/twin-instance/twin-instance.ts +126 -25
  253. package/server/service/twin-journal/twin-journal-query.ts +74 -10
  254. package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +23 -22
  255. package/server/service/twin-metrics/twin-metrics-query.ts +59 -2
  256. package/server/service/twin-model/epcis-coverage.ts +195 -0
  257. package/server/service/twin-model/iec61850-coverage.ts +117 -0
  258. package/server/service/twin-model/index.ts +25 -0
  259. package/server/service/twin-model/isa95-coverage.ts +190 -0
  260. package/server/service/twin-model/project-structure.ts +199 -0
  261. package/server/service/twin-model/standard-coverage.ts +35 -0
  262. package/server/service/twin-model/twin-equipment.ts +157 -0
  263. package/server/service/twin-model/twin-lineage-query.ts +193 -0
  264. package/server/service/twin-model/twin-location.ts +147 -0
  265. package/server/service/twin-model/twin-model-item-query.ts +848 -0
  266. package/server/service/twin-model/twin-model-mutation.ts +503 -0
  267. package/server/service/twin-model/twin-model-query.ts +537 -0
  268. package/server/service/twin-model/twin-model-tree-query.ts +180 -0
  269. package/server/service/twin-model/twin-operation.ts +157 -0
  270. package/server/service/twin-space/move-space.ts +262 -0
  271. package/server/service/twin-space/space-integrity.ts +293 -0
  272. package/server/service/twin-space/twin-space-area.ts +4 -4
  273. package/server/service/twin-space/twin-space-representation.ts +6 -6
  274. package/server/service/twin-space/twin-space-resolver.ts +355 -21
  275. package/server/service/twin-space/twin-space.ts +40 -6
  276. package/server/service/twin-structure/twin-structure.ts +10 -10
  277. package/shared/axis-read.ts +28 -0
  278. package/{server/engine → shared}/entity-delta.ts +96 -1
  279. package/test/adopt-structure-live.test.ts +133 -0
  280. package/test/attention-digest.test.ts +3 -3
  281. package/test/axis-read.test.ts +87 -0
  282. package/test/boot-resume.test.ts +205 -0
  283. package/test/canonical-ingest-vocabularies.test.ts +118 -0
  284. package/test/capability-mapping.test.ts +1 -1
  285. package/test/column-type-portability.test.ts +122 -0
  286. package/test/command-routing.test.ts +1 -1
  287. package/test/declaration-reaches-model.test.ts +178 -0
  288. package/test/discovery-result.test.ts +1 -1
  289. package/test/energy-topology.test.ts +113 -0
  290. package/test/entity-delta.test.ts +171 -1
  291. package/test/event-time-column.test.ts +67 -0
  292. package/test/forecast-metrics.test.ts +71 -0
  293. package/test/forecast-tuning.test.ts +42 -0
  294. package/test/gap-analytics.test.ts +34 -7
  295. package/test/ingest-bench.test.ts +6 -6
  296. package/test/ingest-running-guard.test.ts +136 -0
  297. package/test/ingest-space.test.ts +29 -1
  298. package/test/instance-cache-lifecycle.test.ts +110 -0
  299. package/test/kernel-kind-guard.test.ts +96 -0
  300. package/test/kpi-baseline-db.test.ts +3 -1
  301. package/test/kpi-baseline.test.ts +3 -3
  302. package/test/kpi-fold.test.ts +393 -2
  303. package/test/kpi-query-bench.test.ts +5 -3
  304. package/test/lineage-survives-restart.test.ts +203 -0
  305. package/test/live-feed-registry.test.ts +67 -0
  306. package/test/live-kernel-facts.test.ts +161 -0
  307. package/test/live-mirror-parity.test.ts +22 -15
  308. package/test/load-meter.test.ts +314 -0
  309. package/test/local-declarations.test.ts +554 -0
  310. package/test/master-to-twin.test.ts +121 -33
  311. package/test/model-basis.test.ts +56 -1
  312. package/test/{board-vocabulary.test.ts → model-vocabulary.test.ts} +25 -25
  313. package/test/move-space.test.ts +149 -0
  314. package/test/mutation-gate.test.ts +19 -5
  315. package/test/oee-accumulator.test.ts +26 -7
  316. package/test/operation-basis.test.ts +100 -0
  317. package/test/operations-capability-db.test.ts +165 -0
  318. package/test/project-structure-db.test.ts +226 -0
  319. package/test/projection-reaches-screen.test.ts +272 -0
  320. package/test/property-effects.test.ts +96 -0
  321. package/test/resync-origin-site.test.ts +77 -0
  322. package/test/scale-twin-bench.test.ts +5 -5
  323. package/test/snapshot-freshness.test.ts +60 -0
  324. package/test/space-integrity.test.ts +223 -0
  325. package/test/standard-coverage.test.ts +94 -0
  326. package/test/state-axes.test.ts +1 -1
  327. package/test/streamline-e2e.test.ts +14 -14
  328. package/test/structure-revision-db.test.ts +11 -11
  329. package/test/tenant-registry-db.test.ts +5 -5
  330. package/test/twin-audit.test.ts +83 -0
  331. package/test/twin-model-item-db.test.ts +275 -0
  332. package/test/twin-model-tree-db.test.ts +176 -0
  333. package/test/twin-origin-resync.test.ts +114 -0
  334. package/test/warm-start-seam.test.ts +6 -6
  335. package/test/warm-start.test.ts +88 -3
  336. package/tsconfig.json +6 -1
  337. package/tsconfig.shared.json +23 -0
  338. package/tsconfig.shared.tsbuildinfo +1 -0
  339. package/tsconfig.tsbuildinfo +1 -0
  340. package/dist-server/engine/board-vocabulary.js.map +0 -1
  341. package/dist-server/engine/entity-delta.js.map +0 -1
  342. package/dist-server/engine/kpi-broadcast.js.map +0 -1
  343. package/dist-server/engine/twin-level.js.map +0 -1
  344. package/dist-server/service/twin-event/backfill-keys.d.ts +0 -11
  345. package/dist-server/service/twin-event/backfill-keys.js +0 -63
  346. package/dist-server/service/twin-event/backfill-keys.js.map +0 -1
  347. package/dist-server/tsconfig.tsbuildinfo +0 -1
  348. package/server/service/twin-event/backfill-keys.ts +0 -72
  349. /package/{dist-server/engine → dist-shared}/kpi-broadcast.d.ts +0 -0
  350. /package/{dist-server/engine → dist-shared}/kpi-broadcast.js +0 -0
  351. /package/{dist-server/engine → dist-shared}/twin-level.d.ts +0 -0
  352. /package/{dist-server/engine → dist-shared}/twin-level.js +0 -0
  353. /package/{server/engine → shared}/kpi-broadcast.ts +0 -0
  354. /package/{server/engine → shared}/twin-level.ts +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"structure-diff.js","sourceRoot":"","sources":["../../server/engine/structure-diff.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * 구조 이력의 **차이** — \"2번째에 도장 부스가 넷 늘었다\" 를 말할 수 있게.\n *\n * 리비전은 그 시절 공장을 통째로 담는다(재생하려면 전체 위상이 필요하다). 그런데 사람이 보고 싶은\n * 것은 통째가 아니라 **무엇이 달라졌나** 다 — 62KB 짜리 보드 두 개를 나란히 놓고 눈으로 비교할 수는\n * 없다. 그 한 줄을 여기서 만든다.\n *\n * 순수 함수인 이유: 같은 문장을 화면과 AI 가 함께 써야 한다. 한쪽에서만 계산하면 둘이 다른 말을 한다.\n */\n\n/** 종류별 증감 — \"paint-booth +4\" 처럼 읽힌다. */\nexport interface StructureCountChange {\n key: string\n before: number\n after: number\n delta: number\n}\n\nexport interface StructureDiff {\n /** 자리 종류별 증감(0 인 것은 빼고). */\n locationTypes: StructureCountChange[]\n /** 설비 종류별 증감(0 인 것은 빼고). */\n equipmentKinds: StructureCountChange[]\n locationsAdded: number\n locationsRemoved: number\n equipmentAdded: number\n equipmentRemoved: number\n /** 개수는 같은데 내용이 바뀐 경우(용량 조정·자리 이동 등)가 있는가. */\n changedInPlace: boolean\n}\n\nconst countBy = <T>(rows: readonly T[] | undefined, key: (r: T) => string | undefined): Map<string, number> => {\n const out = new Map<string, number>()\n for (const r of rows ?? []) {\n const k = key(r)\n if (k) out.set(k, (out.get(k) ?? 0) + 1)\n }\n return out\n}\n\nconst idsOf = (rows: readonly { id?: string }[] | undefined): Set<string> => new Set((rows ?? []).map(r => r.id).filter((x): x is string => !!x))\n\nfunction changes(before: Map<string, number>, after: Map<string, number>): StructureCountChange[] {\n const keys = [...new Set([...before.keys(), ...after.keys()])].sort()\n return keys\n .map(key => ({ key, before: before.get(key) ?? 0, after: after.get(key) ?? 0, delta: (after.get(key) ?? 0) - (before.get(key) ?? 0) }))\n .filter(c => c.delta !== 0)\n}\n\n/**\n * 두 구조의 차이. `before` 가 없으면 **최초 리비전**이라 비교 대상이 없다 — 전부 새로 생긴 것으로 센다.\n *\n * 아이디는 **집합으로** 비교한다(수만 세면 넷이 사라지고 넷이 생긴 교체를 \"변화 없음\" 으로 답한다).\n */\nexport function diffStructures(before: any | undefined, after: any): StructureDiff {\n const beforeLocations = before?.locations ?? []\n const beforeEquipment = before?.equipment ?? []\n const afterLocations = after?.locations ?? []\n const afterEquipment = after?.equipment ?? []\n\n const beforeLocationIds = idsOf(beforeLocations)\n const afterLocationIds = idsOf(afterLocations)\n const beforeEquipmentIds = idsOf(beforeEquipment)\n const afterEquipmentIds = idsOf(afterEquipment)\n\n const added = <T>(a: Set<T>, b: Set<T>) => [...b].filter(x => !a.has(x)).length\n const locationsAdded = added(beforeLocationIds, afterLocationIds)\n const locationsRemoved = added(afterLocationIds, beforeLocationIds)\n const equipmentAdded = added(beforeEquipmentIds, afterEquipmentIds)\n const equipmentRemoved = added(afterEquipmentIds, beforeEquipmentIds)\n\n /*\n * 아이디는 그대로인데 속성이 바뀐 경우 — 용량을 늘렸거나 설비를 옮겼다. 지문이 달라 새 리비전이\n * 생겼는데 증감이 전부 0 이면, 화면이 \"바뀐 게 없다\" 고 답하게 된다. 그런 침묵을 막는다.\n */\n const changedInPlace =\n !locationsAdded && !locationsRemoved && !equipmentAdded && !equipmentRemoved && !!before\n\n return {\n locationTypes: changes(countBy(beforeLocations, (n: any) => n.type), countBy(afterLocations, (n: any) => n.type)),\n equipmentKinds: changes(countBy(beforeEquipment, (m: any) => m.kind), countBy(afterEquipment, (m: any) => m.kind)),\n locationsAdded,\n locationsRemoved,\n equipmentAdded,\n equipmentRemoved,\n changedInPlace\n }\n}\n"]}
1
+ {"version":3,"file":"structure-diff.js","sourceRoot":"","sources":["../../server/engine/structure-diff.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * 구조 이력의 **차이** — \"2번째에 도장 부스가 넷 늘었다\" 를 말할 수 있게.\n *\n * 리비전은 그 시절 공장을 통째로 담는다(재생하려면 전체 위상이 필요하다). 그런데 사람이 보고 싶은\n * 것은 통째가 아니라 **무엇이 달라졌나** 다 — 62KB 짜리 모델 두 개를 나란히 놓고 눈으로 비교할 수는\n * 없다. 그 한 줄을 여기서 만든다.\n *\n * 순수 함수인 이유: 같은 문장을 화면과 AI 가 함께 써야 한다. 한쪽에서만 계산하면 둘이 다른 말을 한다.\n */\n\n/** 종류별 증감 — \"paint-booth +4\" 처럼 읽힌다. */\nexport interface StructureCountChange {\n key: string\n before: number\n after: number\n delta: number\n}\n\nexport interface StructureDiff {\n /** 자리 종류별 증감(0 인 것은 빼고). */\n locationTypes: StructureCountChange[]\n /** 설비 종류별 증감(0 인 것은 빼고). */\n equipmentKinds: StructureCountChange[]\n locationsAdded: number\n locationsRemoved: number\n equipmentAdded: number\n equipmentRemoved: number\n /** 개수는 같은데 내용이 바뀐 경우(용량 조정·자리 이동 등)가 있는가. */\n changedInPlace: boolean\n}\n\nconst countBy = <T>(rows: readonly T[] | undefined, key: (r: T) => string | undefined): Map<string, number> => {\n const out = new Map<string, number>()\n for (const r of rows ?? []) {\n const k = key(r)\n if (k) out.set(k, (out.get(k) ?? 0) + 1)\n }\n return out\n}\n\nconst idsOf = (rows: readonly { id?: string }[] | undefined): Set<string> => new Set((rows ?? []).map(r => r.id).filter((x): x is string => !!x))\n\nfunction changes(before: Map<string, number>, after: Map<string, number>): StructureCountChange[] {\n const keys = [...new Set([...before.keys(), ...after.keys()])].sort()\n return keys\n .map(key => ({ key, before: before.get(key) ?? 0, after: after.get(key) ?? 0, delta: (after.get(key) ?? 0) - (before.get(key) ?? 0) }))\n .filter(c => c.delta !== 0)\n}\n\n/**\n * 두 구조의 차이. `before` 가 없으면 **최초 리비전**이라 비교 대상이 없다 — 전부 새로 생긴 것으로 센다.\n *\n * 아이디는 **집합으로** 비교한다(수만 세면 넷이 사라지고 넷이 생긴 교체를 \"변화 없음\" 으로 답한다).\n */\nexport function diffStructures(before: any | undefined, after: any): StructureDiff {\n const beforeLocations = before?.locations ?? []\n const beforeEquipment = before?.equipment ?? []\n const afterLocations = after?.locations ?? []\n const afterEquipment = after?.equipment ?? []\n\n const beforeLocationIds = idsOf(beforeLocations)\n const afterLocationIds = idsOf(afterLocations)\n const beforeEquipmentIds = idsOf(beforeEquipment)\n const afterEquipmentIds = idsOf(afterEquipment)\n\n const added = <T>(a: Set<T>, b: Set<T>) => [...b].filter(x => !a.has(x)).length\n const locationsAdded = added(beforeLocationIds, afterLocationIds)\n const locationsRemoved = added(afterLocationIds, beforeLocationIds)\n const equipmentAdded = added(beforeEquipmentIds, afterEquipmentIds)\n const equipmentRemoved = added(afterEquipmentIds, beforeEquipmentIds)\n\n /*\n * 아이디는 그대로인데 속성이 바뀐 경우 — 용량을 늘렸거나 설비를 옮겼다. 지문이 달라 새 리비전이\n * 생겼는데 증감이 전부 0 이면, 화면이 \"바뀐 게 없다\" 고 답하게 된다. 그런 침묵을 막는다.\n */\n const changedInPlace =\n !locationsAdded && !locationsRemoved && !equipmentAdded && !equipmentRemoved && !!before\n\n return {\n locationTypes: changes(countBy(beforeLocations, (n: any) => n.type), countBy(afterLocations, (n: any) => n.type)),\n equipmentKinds: changes(countBy(beforeEquipment, (m: any) => m.kind), countBy(afterEquipment, (m: any) => m.kind)),\n locationsAdded,\n locationsRemoved,\n equipmentAdded,\n equipmentRemoved,\n changedInPlace\n }\n}\n"]}
@@ -1,4 +1,11 @@
1
1
  import type { MeasuredEstimate } from './measured-estimator.js';
2
+ /**
3
+ * UN/CEFACT 권고 20 공통코드 → m/s 변환. 모르는 코드는 변환하지 않는다(발명 금지).
4
+ *
5
+ * **내보내는 이유**: 선언 화면·AI 가 「어떤 단위를 받나」를 말해야 하고, 그 목록이 두 곳에 적히면
6
+ * 화면이 받아 준 단위를 추정기가 모르는 일이 생긴다(그때 공정 시간이 조용히 사라진다).
7
+ */
8
+ export declare const SPEED_TO_MPS: Record<string, number>;
2
9
  /** 우리가 읽는 canonical 설비 속성 ID — 표준이 속성 ID 어휘를 정하지 않으므로 한 곳에서 정한다. */
3
10
  export declare const EQUIPMENT_PROPERTY: {
4
11
  readonly speed: "speed";
@@ -18,12 +25,12 @@ export interface DurationEstimatorLike {
18
25
  estimate(ctx: DurationCtx): number | MeasuredEstimate | undefined;
19
26
  }
20
27
  export interface TravelEstimatorInput {
21
- /** 노드 중심 좌표(masterToTwin 산출 `board.layout`). */
28
+ /** 노드 중심 좌표(masterToTwin 산출 `model.layout`). */
22
29
  layout?: Record<string, {
23
30
  x: number;
24
31
  y: number;
25
32
  }>;
26
- /** 무버(자원) — kind 와 속성. `board.equipment`. */
33
+ /** 무버(자원) — kind 와 속성. `model.equipment`. */
27
34
  equipment?: {
28
35
  id: string;
29
36
  kind: string;
@@ -5,7 +5,7 @@
5
5
  * 커널은 좌표를 모른다(설계: 좌표-free — "얼마 걸리나" 만 소비하고 "어떤 경로로" 는 씬 소관).
6
6
  * 그래서 거리 기반 계산은 **호스트가 추정기로 주입**한다(`DurationEstimator` 시임).
7
7
  *
8
- * 좌표는 이미 있다: 마스터의 `RefLocation.footprint` → `masterToTwin` 이 `board.layout`(노드 중심)으로
8
+ * 좌표는 이미 있다: 마스터의 `RefLocation.footprint` → `masterToTwin` 이 `model.layout`(노드 중심)으로
9
9
  * 낸다. 없던 것은 **속도**다 — 속도 없이 거리만으로는 시간이 나오지 않는다. 그래서 설비 속성
10
10
  * (ISA-95 `EquipmentSpecificationProperty`)으로 받는다.
11
11
  *
@@ -15,11 +15,16 @@
15
15
  * 만들면 공정 시간이 사라진다.
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.EQUIPMENT_PROPERTY = void 0;
18
+ exports.EQUIPMENT_PROPERTY = exports.SPEED_TO_MPS = void 0;
19
19
  exports.buildTravelEstimator = buildTravelEstimator;
20
20
  exports.chainEstimators = chainEstimators;
21
- /** UN/CEFACT 권고 20 공통코드 → m/s 변환. 모르는 코드는 변환하지 않는다(발명 금지). */
22
- const SPEED_TO_MPS = {
21
+ /**
22
+ * UN/CEFACT 권고 20 공통코드 → m/s 변환. 모르는 코드는 변환하지 않는다(발명 금지).
23
+ *
24
+ * **내보내는 이유**: 선언 화면·AI 가 「어떤 단위를 받나」를 말해야 하고, 그 목록이 두 곳에 적히면
25
+ * 화면이 받아 준 단위를 추정기가 모르는 일이 생긴다(그때 공정 시간이 조용히 사라진다).
26
+ */
27
+ exports.SPEED_TO_MPS = {
23
28
  MTS: 1, // metre per second
24
29
  KMH: 1000 / 3600, // kilometre per hour
25
30
  '2M': 0.3048, // foot per second
@@ -46,7 +51,7 @@ function readSpeeds(equipment, reasons) {
46
51
  reasons.push(`equipment "${m.id}": speed has no unit of measure (expected UN/CEFACT code such as MTS or KMH)`);
47
52
  continue;
48
53
  }
49
- const factor = SPEED_TO_MPS[p.uom];
54
+ const factor = exports.SPEED_TO_MPS[p.uom];
50
55
  if (factor === undefined) {
51
56
  reasons.push(`equipment "${m.id}": unknown speed unit "${p.uom}"`);
52
57
  continue;
@@ -66,7 +71,7 @@ function buildTravelEstimator(input) {
66
71
  if (unit !== 'm')
67
72
  reasons.push(`space unit is "${unit}", not metres — travel time is not computed (no assumed conversion)`);
68
73
  if (!layout || !Object.keys(layout).length)
69
- reasons.push('no location coordinates (board.layout empty) — travel time cannot be derived from distance');
74
+ reasons.push('no location coordinates (model.layout empty) — travel time cannot be derived from distance');
70
75
  const speedsByKind = readSpeeds(input.equipment, reasons);
71
76
  if (!Object.keys(speedsByKind).length)
72
77
  reasons.push('no resource declares a speed property — distance alone cannot produce a duration');
@@ -1 +1 @@
1
- {"version":3,"file":"travel-estimator.js","sourceRoot":"","sources":["../../server/engine/travel-estimator.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * 이동시간 추정기 — **거리 × 속도.** 커널의 `TRAVEL_MS` 상수를 대체하는 유일한 정당한 길.\n *\n * 커널은 좌표를 모른다(설계: 좌표-free — \"얼마 걸리나\" 만 소비하고 \"어떤 경로로\" 는 씬 소관).\n * 그래서 거리 기반 계산은 **호스트가 추정기로 주입**한다(`DurationEstimator` 시임).\n *\n * 좌표는 이미 있다: 마스터의 `RefLocation.footprint` → `masterToTwin` 이 `board.layout`(노드 중심)으로\n * 낸다. 없던 것은 **속도**다 — 속도 없이 거리만으로는 시간이 나오지 않는다. 그래서 설비 속성\n * (ISA-95 `EquipmentSpecificationProperty`)으로 받는다.\n *\n * 정직 규율: **셋 중 하나라도 모르면 답하지 않는다**(undefined → 커널이 명세·상수로 떨어진다).\n * ① 두 노드의 좌표 ② 그 작업을 할 자원 종류의 속도 ③ 좌표의 단위가 미터인지\n * 그리고 같은 노드 안의 작업(처리·체류)은 이동이 아니므로 다루지 않는다 — 거리 0 을 \"0초\" 로\n * 만들면 공정 시간이 사라진다.\n */\n\nimport type { MeasuredEstimate } from './measured-estimator.js'\n\n/** UN/CEFACT 권고 20 공통코드 → m/s 변환. 모르는 코드는 변환하지 않는다(발명 금지). */\nconst SPEED_TO_MPS: Record<string, number> = {\n MTS: 1, // metre per second\n KMH: 1000 / 3600, // kilometre per hour\n '2M': 0.3048, // foot per second\n HM: 0.44704 // mile per hour\n}\n\n/** 우리가 읽는 canonical 설비 속성 ID — 표준이 속성 ID 어휘를 정하지 않으므로 한 곳에서 정한다. */\nexport const EQUIPMENT_PROPERTY = { speed: 'speed' } as const\n\n/** 추정기 문맥 — 커널 `DurationContext` 와 같은 모양(커널 타입에 의존하지 않기 위해 구조로 맞춘다). */\nexport interface DurationCtx {\n kind: string\n fromNode: string\n toNode: string\n resourceKind?: string\n}\n\n/**\n * 추정기 — 숫자(평균만) 또는 추정치 객체(퍼짐까지). 커널 `DurationEstimator` 와 같은 모양.\n * 거리 계산은 숫자를 내고, 실측은 관측된 퍼짐을 함께 낸다.\n */\nexport interface DurationEstimatorLike {\n estimate(ctx: DurationCtx): number | MeasuredEstimate | undefined\n}\n\nexport interface TravelEstimatorInput {\n /** 노드 중심 좌표(masterToTwin 산출 `board.layout`). */\n layout?: Record<string, { x: number; y: number }>\n /** 무버(자원) — kind 와 속성. `board.equipment`. */\n equipment?: { id: string; kind: string; properties?: { id: string; value: string; uom?: string }[] }[]\n /** 좌표 단위(공간 `content.unit`). 미터가 아니면 계산하지 않는다(환산을 추측하지 않는다). */\n unit?: string\n}\n\nexport interface TravelEstimatorResult {\n estimator?: { estimate(ctx: DurationCtx): number | undefined }\n /** 왜 못 만들었나(만들었으면 비어 있음) — 조용히 없는 상태로 두지 않는다. */\n reasons: string[]\n /** 속도를 읽어낸 자원 종류들 — 무엇이 계산 대상인지 드러낸다. */\n speedsByKind: Record<string, number>\n}\n\n/** 자원 종류별 속도(m/s) — 같은 종류에 값이 여럿이면 첫 유효값. 단위 없는 속도는 받지 않는다. */\nfunction readSpeeds(equipment: TravelEstimatorInput['equipment'], reasons: string[]): Record<string, number> {\n const out: Record<string, number> = {}\n for (const m of equipment ?? []) {\n if (out[m.kind] !== undefined) continue\n const p = m.properties?.find(x => x.id === EQUIPMENT_PROPERTY.speed)\n if (!p) continue\n const n = Number(p.value)\n if (!Number.isFinite(n) || n <= 0) { reasons.push(`equipment \"${m.id}\": speed \"${p.value}\" is not a positive number`); continue }\n /* 단위가 없으면 m/s 라고 **가정하지 않는다** — 3 이 초속 3m 인지 시속 3km 인지 뜻이 완전히 다르다. */\n if (!p.uom) { reasons.push(`equipment \"${m.id}\": speed has no unit of measure (expected UN/CEFACT code such as MTS or KMH)`); continue }\n const factor = SPEED_TO_MPS[p.uom]\n if (factor === undefined) { reasons.push(`equipment \"${m.id}\": unknown speed unit \"${p.uom}\"`); continue }\n out[m.kind] = n * factor\n }\n return out\n}\n\n/**\n * 이동시간 추정기를 만든다 — 만들 수 없으면 **이유와 함께** 비운다.\n * `estimator` 가 undefined 면 커널은 명세·상수로 굴러가고, `reasons` 가 왜 그런지 말한다.\n */\nexport function buildTravelEstimator(input: TravelEstimatorInput): TravelEstimatorResult {\n const reasons: string[] = []\n const layout = input.layout\n const unit = input.unit ?? 'm'\n if (unit !== 'm') reasons.push(`space unit is \"${unit}\", not metres — travel time is not computed (no assumed conversion)`)\n if (!layout || !Object.keys(layout).length) reasons.push('no location coordinates (board.layout empty) — travel time cannot be derived from distance')\n const speedsByKind = readSpeeds(input.equipment, reasons)\n if (!Object.keys(speedsByKind).length) reasons.push('no resource declares a speed property — distance alone cannot produce a duration')\n if (reasons.length) return { reasons, speedsByKind }\n\n const lay = layout as Record<string, { x: number; y: number }>\n return {\n reasons,\n speedsByKind,\n estimator: {\n estimate(ctx) {\n /* 같은 자리에서 벌어지는 일(처리·체류)은 이동이 아니다 — 다루지 않고 넘긴다. */\n if (!ctx.fromNode || !ctx.toNode || ctx.fromNode === ctx.toNode) return undefined\n const a = lay[ctx.fromNode]\n const b = lay[ctx.toNode]\n if (!a || !b) return undefined // 좌표를 모르는 노드(관측으로 알게 된 자리 등)\n const speed = ctx.resourceKind ? speedsByKind[ctx.resourceKind] : undefined\n if (!speed) return undefined // 자원 종류를 모르거나 그 종류의 속도가 없다\n const dist = Math.hypot(b.x - a.x, b.y - a.y)\n if (!Number.isFinite(dist) || dist <= 0) return undefined\n return Math.round((dist / speed) * 1000)\n }\n }\n }\n}\n\n/**\n * 추정기 사슬 — 앞선 것이 답하면 그 값, 아니면 다음. **실측 → 계산 → (커널이) 명세 → 상수** 순서를\n * 이 사슬과 커널 `durationOf` 가 함께 만든다. 앞에 둘수록 강한 근거다.\n */\nexport function chainEstimators(estimators: (DurationEstimatorLike | undefined)[]): DurationEstimatorLike | undefined {\n const live = estimators.filter(Boolean) as DurationEstimatorLike[]\n if (!live.length) return undefined\n if (live.length === 1) return live[0]\n return {\n estimate(ctx) {\n for (const e of live) {\n const v = e.estimate(ctx)\n if (v !== undefined) return v\n }\n return undefined\n }\n }\n}\n"]}
1
+ {"version":3,"file":"travel-estimator.js","sourceRoot":"","sources":["../../server/engine/travel-estimator.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * 이동시간 추정기 — **거리 × 속도.** 커널의 `TRAVEL_MS` 상수를 대체하는 유일한 정당한 길.\n *\n * 커널은 좌표를 모른다(설계: 좌표-free — \"얼마 걸리나\" 만 소비하고 \"어떤 경로로\" 는 씬 소관).\n * 그래서 거리 기반 계산은 **호스트가 추정기로 주입**한다(`DurationEstimator` 시임).\n *\n * 좌표는 이미 있다: 마스터의 `RefLocation.footprint` → `masterToTwin` 이 `model.layout`(노드 중심)으로\n * 낸다. 없던 것은 **속도**다 — 속도 없이 거리만으로는 시간이 나오지 않는다. 그래서 설비 속성\n * (ISA-95 `EquipmentSpecificationProperty`)으로 받는다.\n *\n * 정직 규율: **셋 중 하나라도 모르면 답하지 않는다**(undefined → 커널이 명세·상수로 떨어진다).\n * ① 두 노드의 좌표 ② 그 작업을 할 자원 종류의 속도 ③ 좌표의 단위가 미터인지\n * 그리고 같은 노드 안의 작업(처리·체류)은 이동이 아니므로 다루지 않는다 — 거리 0 을 \"0초\" 로\n * 만들면 공정 시간이 사라진다.\n */\n\nimport type { MeasuredEstimate } from './measured-estimator.js'\n\n/**\n * UN/CEFACT 권고 20 공통코드 → m/s 변환. 모르는 코드는 변환하지 않는다(발명 금지).\n *\n * **내보내는 이유**: 선언 화면·AI 가 「어떤 단위를 받나」를 말해야 하고, 그 목록이 두 곳에 적히면\n * 화면이 받아 준 단위를 추정기가 모르는 일이 생긴다(그때 공정 시간이 조용히 사라진다).\n */\nexport const SPEED_TO_MPS: Record<string, number> = {\n MTS: 1, // metre per second\n KMH: 1000 / 3600, // kilometre per hour\n '2M': 0.3048, // foot per second\n HM: 0.44704 // mile per hour\n}\n\n/** 우리가 읽는 canonical 설비 속성 ID — 표준이 속성 ID 어휘를 정하지 않으므로 한 곳에서 정한다. */\nexport const EQUIPMENT_PROPERTY = { speed: 'speed' } as const\n\n/** 추정기 문맥 — 커널 `DurationContext` 와 같은 모양(커널 타입에 의존하지 않기 위해 구조로 맞춘다). */\nexport interface DurationCtx {\n kind: string\n fromNode: string\n toNode: string\n resourceKind?: string\n}\n\n/**\n * 추정기 — 숫자(평균만) 또는 추정치 객체(퍼짐까지). 커널 `DurationEstimator` 와 같은 모양.\n * 거리 계산은 숫자를 내고, 실측은 관측된 퍼짐을 함께 낸다.\n */\nexport interface DurationEstimatorLike {\n estimate(ctx: DurationCtx): number | MeasuredEstimate | undefined\n}\n\nexport interface TravelEstimatorInput {\n /** 노드 중심 좌표(masterToTwin 산출 `model.layout`). */\n layout?: Record<string, { x: number; y: number }>\n /** 무버(자원) — kind 와 속성. `model.equipment`. */\n equipment?: { id: string; kind: string; properties?: { id: string; value: string; uom?: string }[] }[]\n /** 좌표 단위(공간 `content.unit`). 미터가 아니면 계산하지 않는다(환산을 추측하지 않는다). */\n unit?: string\n}\n\nexport interface TravelEstimatorResult {\n estimator?: { estimate(ctx: DurationCtx): number | undefined }\n /** 왜 못 만들었나(만들었으면 비어 있음) — 조용히 없는 상태로 두지 않는다. */\n reasons: string[]\n /** 속도를 읽어낸 자원 종류들 — 무엇이 계산 대상인지 드러낸다. */\n speedsByKind: Record<string, number>\n}\n\n/** 자원 종류별 속도(m/s) — 같은 종류에 값이 여럿이면 첫 유효값. 단위 없는 속도는 받지 않는다. */\nfunction readSpeeds(equipment: TravelEstimatorInput['equipment'], reasons: string[]): Record<string, number> {\n const out: Record<string, number> = {}\n for (const m of equipment ?? []) {\n if (out[m.kind] !== undefined) continue\n const p = m.properties?.find(x => x.id === EQUIPMENT_PROPERTY.speed)\n if (!p) continue\n const n = Number(p.value)\n if (!Number.isFinite(n) || n <= 0) { reasons.push(`equipment \"${m.id}\": speed \"${p.value}\" is not a positive number`); continue }\n /* 단위가 없으면 m/s 라고 **가정하지 않는다** — 3 이 초속 3m 인지 시속 3km 인지 뜻이 완전히 다르다. */\n if (!p.uom) { reasons.push(`equipment \"${m.id}\": speed has no unit of measure (expected UN/CEFACT code such as MTS or KMH)`); continue }\n const factor = SPEED_TO_MPS[p.uom]\n if (factor === undefined) { reasons.push(`equipment \"${m.id}\": unknown speed unit \"${p.uom}\"`); continue }\n out[m.kind] = n * factor\n }\n return out\n}\n\n/**\n * 이동시간 추정기를 만든다 — 만들 수 없으면 **이유와 함께** 비운다.\n * `estimator` 가 undefined 면 커널은 명세·상수로 굴러가고, `reasons` 가 왜 그런지 말한다.\n */\nexport function buildTravelEstimator(input: TravelEstimatorInput): TravelEstimatorResult {\n const reasons: string[] = []\n const layout = input.layout\n const unit = input.unit ?? 'm'\n if (unit !== 'm') reasons.push(`space unit is \"${unit}\", not metres — travel time is not computed (no assumed conversion)`)\n if (!layout || !Object.keys(layout).length) reasons.push('no location coordinates (model.layout empty) — travel time cannot be derived from distance')\n const speedsByKind = readSpeeds(input.equipment, reasons)\n if (!Object.keys(speedsByKind).length) reasons.push('no resource declares a speed property — distance alone cannot produce a duration')\n if (reasons.length) return { reasons, speedsByKind }\n\n const lay = layout as Record<string, { x: number; y: number }>\n return {\n reasons,\n speedsByKind,\n estimator: {\n estimate(ctx) {\n /* 같은 자리에서 벌어지는 일(처리·체류)은 이동이 아니다 — 다루지 않고 넘긴다. */\n if (!ctx.fromNode || !ctx.toNode || ctx.fromNode === ctx.toNode) return undefined\n const a = lay[ctx.fromNode]\n const b = lay[ctx.toNode]\n if (!a || !b) return undefined // 좌표를 모르는 노드(관측으로 알게 된 자리 등)\n const speed = ctx.resourceKind ? speedsByKind[ctx.resourceKind] : undefined\n if (!speed) return undefined // 자원 종류를 모르거나 그 종류의 속도가 없다\n const dist = Math.hypot(b.x - a.x, b.y - a.y)\n if (!Number.isFinite(dist) || dist <= 0) return undefined\n return Math.round((dist / speed) * 1000)\n }\n }\n }\n}\n\n/**\n * 추정기 사슬 — 앞선 것이 답하면 그 값, 아니면 다음. **실측 → 계산 → (커널이) 명세 → 상수** 순서를\n * 이 사슬과 커널 `durationOf` 가 함께 만든다. 앞에 둘수록 강한 근거다.\n */\nexport function chainEstimators(estimators: (DurationEstimatorLike | undefined)[]): DurationEstimatorLike | undefined {\n const live = estimators.filter(Boolean) as DurationEstimatorLike[]\n if (!live.length) return undefined\n if (live.length === 1) return live[0]\n return {\n estimate(ctx) {\n for (const e of live) {\n const v = e.estimate(ctx)\n if (v !== undefined) return v\n }\n return undefined\n }\n }\n}\n"]}