@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
@@ -0,0 +1,384 @@
1
+ /*
2
+ * 부하 계기판 — **어떤 작업이 이벤트 루프를 얼마나 쓰는지** 작업별로 잰다. 순수(import 없음).
3
+ *
4
+ * ── 왜 필요한가 (2026-08-07) ───────────────────────────────────────────────
5
+ * 시뮬 틱은 트윈마다 `setInterval(1000ms)` 로 **메인 이벤트 루프에서 동기로** 수행된다. 부팅 시 16개가
6
+ * 자동 프로비저닝되므로 초당 16번이 같은 루프에서 차례로 실행된다. 한 주기가 예산을 넘기면 타이머가
7
+ * 밀려 쌓이고, 같은 루프에 있는 HTTP·GraphQL·웹소켓이 **함께 멈춘다.**
8
+ *
9
+ * 실제로 그런 상태를 만났다: 포트는 LISTEN 이고 webpack 은 `compiled successfully` 인데 요청이 하나도
10
+ * 처리되지 않고 CPU 만 99% 였다. **터지면 알지만 느려지면 몰랐다** — `tickGuarded` 는 예외만 잡고
11
+ * 시간은 재지 않았고, `TwinMetrics` 에는 라이브 지표(유입·방송·저널)뿐이라 시뮬 틱은 아무도 안 봤다.
12
+ *
13
+ * ── 총량만으로는 부족하다 ─────────────────────────────────────────────────
14
+ * "틱이 800ms 걸렸다" 는 어디를 고칠지 알려 주지 않는다. 한 주기는 여러 작업으로 이뤄진다 —
15
+ * 커널 틱 · 상태 투영(snapshot) · 방송 payload 만들기 · 발행 · 저널 기록 · 유입 흡수. 그래서
16
+ * **작업마다 따로** 잰다. 어느 작업이 총 시간의 몇 %인지 보이면 손댈 곳이 정해진다.
17
+ *
18
+ * 재고 말하는 것이 먼저다. 워커 스레드로 옮기는 것은 그다음이다 — 무엇이 느린지 모른 채 옮기면
19
+ * 느린 채로 옮겨진다.
20
+ */
21
+
22
+ /** 작업 이름 — 새 작업을 재기 시작하면 여기 늘린다(문자열을 자유롭게 쓰지 않는다: 오타가 새 칸이 된다). */
23
+ export const LOAD_PHASES = ['tick', 'snapshot', 'deltas', 'publish', 'journal', 'ingest', 'forecast', 'forkTick'] as const
24
+ export type LoadPhase = (typeof LOAD_PHASES)[number]
25
+
26
+ export interface PhaseStats {
27
+ /** 잰 횟수. */
28
+ count: number
29
+ /** 마지막 소요(ms). */
30
+ lastMs: number
31
+ /** 가장 오래 걸린 것(ms) — 평균은 순간 정체를 가린다. */
32
+ maxMs: number
33
+ /** 소요 합(ms). 나눗셈은 읽는 쪽에서 한다. */
34
+ totalMs: number
35
+ }
36
+
37
+ /** 창(window) 하나의 누적 — "지금 얼마나 쓰고 있나" 를 답한다. */
38
+ interface Window {
39
+ /** 창이 열린 시각. **아직 안 열렸으면 `-1`** — 0 으로 두면 시각 0 과 구별이 안 된다(검사가 잡았다). */
40
+ startMs: number
41
+ phases: Partial<Record<LoadPhase, PhaseStats>>
42
+ }
43
+
44
+ export interface LoadMeter {
45
+ /** **누적** — 프로세스가 뜬 뒤 전부. 총량과 최악값을 본다. */
46
+ phases: Partial<Record<LoadPhase, PhaseStats>>
47
+ /** 지금 쌓고 있는 창. */
48
+ window: Window
49
+ /** **마지막으로 닫힌 창** — 이것이 "실시간" 이다. 없으면 아직 한 창도 안 지났다. */
50
+ recent: (Window & { endMs: number }) | null
51
+ /** 이 트윈에서 만들어진 fork 수(누적) — 예측 한 번이 수십 개를 만든다. */
52
+ forksCreated: number
53
+ /** 한 주기(틱)가 예산을 넘긴 횟수. */
54
+ overBudget: number
55
+ /**
56
+ * 마지막 경고 시각(ms). **한 번도 안 했으면 `-Infinity`** — 0 으로 두면 "0 시점에 경고했다" 가 되어
57
+ * 첫 느린 틱이 조용히 지나간다(검사가 그것을 잡았다).
58
+ */
59
+ lastWarnMs: number
60
+ }
61
+
62
+ export function newLoadMeter(): LoadMeter {
63
+ return { phases: {}, window: { startMs: -1, phases: {} }, recent: null, forksCreated: 0, overBudget: 0, lastWarnMs: -Infinity }
64
+ }
65
+
66
+ /**
67
+ * 예산 — 틱 간격의 절반. 넘으면 루프의 절반을 이 트윈 하나가 쓰고 있다는 뜻이다.
68
+ *
69
+ * 절반인 이유: 트윈이 여럿이라 각자 간격을 다 쓰면 이미 포화다. 절반에서 알아야 손 쓸 틈이 있다.
70
+ */
71
+ export const TICK_BUDGET_RATIO = 0.5
72
+
73
+ /** 경고를 다시 낼 때까지의 최소 간격(ms) — 느린 트윈은 매 틱 느리므로, 그대로 두면 로그가 원인을 덮는다. */
74
+ export const WARN_COOLDOWN_MS = 30_000
75
+
76
+ /**
77
+ * 한 작업의 소요를 기록한다. **누적만 하고 판단하지 않는다.**
78
+ *
79
+ * 음수·NaN 은 기록하지 않는다(시계가 뒤로 간 경우). 없는 값을 0 으로 세면 평균이 거짓이 된다.
80
+ */
81
+ export function recordPhase(meter: LoadMeter, phase: LoadPhase, tookMs: number, nowMs = Date.now()): void {
82
+ if (!Number.isFinite(tookMs) || tookMs < 0) return
83
+
84
+ rollWindow(meter, nowMs)
85
+ for (const bucket of [meter.phases, meter.window.phases]) {
86
+ const s = bucket[phase] ?? (bucket[phase] = { count: 0, lastMs: 0, maxMs: 0, totalMs: 0 })
87
+ s.count += 1
88
+ s.lastMs = tookMs
89
+ s.totalMs += tookMs
90
+ if (tookMs > s.maxMs) s.maxMs = tookMs
91
+ }
92
+ }
93
+
94
+ /** fork 하나가 만들어졌다 — 예측 한 번이 수십 개를 만든다. 수를 알아야 부하의 출처를 짚는다. */
95
+ export function recordFork(meter: LoadMeter, count = 1): void {
96
+ meter.forksCreated += count
97
+ }
98
+
99
+ /** 실시간 창의 길이(ms) — 이보다 길게 보려면 누적을 본다. */
100
+ export const WINDOW_MS = 10_000
101
+
102
+ /** 창이 다 찼으면 닫고 새로 연다. **닫힌 창만 "최근" 으로 읽는다** — 채우는 중인 창은 과소 집계다. */
103
+ export function rollWindow(meter: LoadMeter, nowMs: number, windowMs = WINDOW_MS): void {
104
+ if (meter.window.startMs < 0) {
105
+ meter.window.startMs = nowMs
106
+ return
107
+ }
108
+ if (nowMs - meter.window.startMs < windowMs) return
109
+
110
+ meter.recent = { ...meter.window, endMs: nowMs }
111
+ meter.window = { startMs: nowMs, phases: {} }
112
+ }
113
+
114
+ /**
115
+ * 이 주기가 예산을 넘었나 — 넘었으면 세고, **말할 때인지**까지 답한다.
116
+ */
117
+ export function judgeCycle(
118
+ meter: LoadMeter,
119
+ tookMs: number,
120
+ tickMs: number,
121
+ nowMs: number,
122
+ budgetRatio = TICK_BUDGET_RATIO,
123
+ cooldownMs = WARN_COOLDOWN_MS
124
+ ): { over: boolean; warn: boolean; budgetMs: number } {
125
+ const budgetMs = tickMs * budgetRatio
126
+ const over = Number.isFinite(tookMs) && tookMs > budgetMs
127
+ if (!over) return { over: false, warn: false, budgetMs }
128
+
129
+ meter.overBudget += 1
130
+ const warn = nowMs - meter.lastWarnMs >= cooldownMs
131
+ if (warn) meter.lastWarnMs = nowMs
132
+
133
+ return { over: true, warn, budgetMs }
134
+ }
135
+
136
+ const round2 = (v: number) => Math.round(v * 100) / 100
137
+ /**
138
+ * 비율은 자릿수를 더 준다 — **작은 값이 0 이 되면 "안 쓴다" 로 읽힌다.**
139
+ *
140
+ * 24ms/11초 = 0.0022 인데 소수 둘째 자리로 반올림하면 0 이 되어, 재서 나온 값과 없는 값이 같아진다.
141
+ * 오늘 겪은 착각(0 과 없음을 구별 못 함)과 같은 종류라 여기서 막는다.
142
+ */
143
+ const round4 = (v: number) => Math.round(v * 10000) / 10000
144
+
145
+ export interface PhaseRow {
146
+ phase: LoadPhase
147
+ count: number
148
+ lastMs: number
149
+ maxMs: number
150
+ avgMs: number
151
+ totalMs: number
152
+ /** 잰 작업 전체 시간 중 이 작업의 몫(0~1). 어디를 고칠지 이 값이 정한다. */
153
+ share: number
154
+ }
155
+
156
+ export interface LoadView {
157
+ phases: PhaseRow[]
158
+ measuredTotalMs: number
159
+ /** 이 구간의 길이(ms). 누적은 프로세스 기동 이후라 알 수 없으므로 `null`. */
160
+ spanMs: number | null
161
+ /** 구간 중 몇 %를 이 트윈이 썼나(0~1+). 구간을 모르면 `null` — **0 이 아니다.** */
162
+ busyRatio: number | null
163
+ }
164
+
165
+ function toRows(phases: Partial<Record<LoadPhase, PhaseStats>>): { rows: PhaseRow[]; totalMs: number } {
166
+ const entries = (Object.entries(phases) as [LoadPhase, PhaseStats][]).filter(([, s]) => s.count > 0)
167
+ const totalMs = entries.reduce((sum, [, s]) => sum + s.totalMs, 0)
168
+ const rows = entries
169
+ .map(([phase, s]) => ({
170
+ phase,
171
+ count: s.count,
172
+ lastMs: round2(s.lastMs),
173
+ maxMs: round2(s.maxMs),
174
+ avgMs: round2(s.totalMs / s.count),
175
+ totalMs: round2(s.totalMs),
176
+ share: totalMs > 0 ? round4(s.totalMs / totalMs) : 0
177
+ }))
178
+ .sort((a, b) => b.totalMs - a.totalMs)
179
+
180
+ return { rows, totalMs }
181
+ }
182
+
183
+ function toView(phases: Partial<Record<LoadPhase, PhaseStats>>, spanMs: number | null): LoadView | null {
184
+ const { rows, totalMs } = toRows(phases)
185
+ if (!rows.length) return null
186
+
187
+ return {
188
+ phases: rows,
189
+ measuredTotalMs: round2(totalMs),
190
+ spanMs,
191
+ busyRatio: spanMs && spanMs > 0 ? round4(totalMs / spanMs) : null
192
+ }
193
+ }
194
+
195
+ /**
196
+ * 읽기용 요약 — **실시간과 누적을 함께** 낸다.
197
+ *
198
+ * · `recent` — 마지막으로 **닫힌** 창. 지금 이 트윈이 루프를 얼마나 쓰고 있나. 채우는 중인 창은
199
+ * 과소 집계라 쓰지 않는다.
200
+ * · `total` — 기동 이후 전부. 총량과 최악값.
201
+ *
202
+ * 잰 적이 없으면 **`null` 이다.** 0 으로 채우면 "0ms 다"(= 아주 빠르다)로 읽혀, 재지 않은 것과 정반대의
203
+ * 뜻이 된다. 몫(`share`)도 잰 작업들 사이의 비율일 뿐 — **재지 않은 작업은 분모에 없다.**
204
+ */
205
+ export function loadSummary(meter: LoadMeter | undefined, tickMs: number): {
206
+ recent: LoadView | null
207
+ total: LoadView | null
208
+ forksCreated: number
209
+ overBudget: number
210
+ budgetMs: number
211
+ /** 마지막 틱이 간격을 얼마나 썼나(0~1+). 1 이면 간격을 통째로 쓴다. */
212
+ loadRatio: number | null
213
+ } | null {
214
+ if (!meter) return null
215
+
216
+ const total = toView(meter.phases, null)
217
+ const recent = meter.recent ? toView(meter.recent.phases, meter.recent.endMs - meter.recent.startMs) : null
218
+ if (!total && !recent && !meter.forksCreated) return null
219
+
220
+ const tick = meter.phases.tick
221
+ return {
222
+ recent,
223
+ total,
224
+ forksCreated: meter.forksCreated,
225
+ overBudget: meter.overBudget,
226
+ budgetMs: tickMs * TICK_BUDGET_RATIO,
227
+ loadRatio: tick && tick.count > 0 ? round4(tick.lastMs / tickMs) : null
228
+ }
229
+ }
230
+
231
+ /**
232
+ * 경고 한 줄 — **무엇이 느린지까지 말한다.** "틱이 800ms" 만으로는 어디를 볼지 알 수 없다.
233
+ *
234
+ * 가장 무거운 작업 셋을 몫과 함께 적는다.
235
+ */
236
+ export function slowTickMessage(instanceId: string, tookMs: number, budgetMs: number, meter: LoadMeter): string {
237
+ const { rows } = toRows(meter.recent?.phases ?? meter.phases)
238
+ const top = rows
239
+ .slice(0, 3)
240
+ .map(p => `${p.phase} ${p.avgMs}ms(${Math.round(p.share * 100)}%)`)
241
+ .join(' · ')
242
+
243
+ return (
244
+ `[twin-engine] "${instanceId}" 틱 ${round2(tookMs)}ms — 예산 ${round2(budgetMs)}ms 초과. ` +
245
+ (top ? `무거운 작업: ${top}. ` : '') +
246
+ `시뮬 틱이 메인 이벤트 루프에서 수행됩니다 — 이 상태가 이어지면 HTTP·구독이 함께 느려집니다.`
247
+ )
248
+ }
249
+
250
+ /**
251
+ * 전체 한눈에 — **누가 루프를 점유하고 있나.**
252
+ *
253
+ * 인스턴스 목록을 받아 대수·모드별 수·fork 총수를 세고, **최근 창의 부하가 큰 순서**로 줄을 세운다.
254
+ * 누적이 아니라 최근으로 세우는 이유: 지금 아픈 것을 먼저 봐야 한다(누적 1위는 오래 떠 있던 것일 뿐일
255
+ * 수 있다).
256
+ */
257
+ export function fleetLoad(
258
+ rows: { instanceId: string; mode: string; domainId?: string; domainLabel?: string; meter?: LoadMeter }[],
259
+ tickMs: number
260
+ ): {
261
+ instances: number
262
+ byMode: Record<string, number>
263
+ /**
264
+ * **테넌트별 몫** — 운영자가 먼저 묻는 것은 "어느 테넌트가 루프를 먹나" 다.
265
+ *
266
+ * 실측으로 필요해졌다: 한 도메인 트윈 22개가 CPU 를 110% 쓰는 동안 다른 도메인 화면은 0 이었다.
267
+ * 무거운 순으로 낸다. 몫은 **잰 트윈들 사이의 비율**이다(안 잰 트윈은 분모에 없다).
268
+ */
269
+ byDomain: { domainId: string; label: string; instances: number; recentBusyMs: number; share: number }[]
270
+ forksCreated: number
271
+ /** 최근 창에서 트윈들이 쓴 시간의 합(ms) — 창 길이를 넘으면 루프가 이미 밀리고 있다. */
272
+ recentBusyMs: number
273
+ /** 그 창의 길이(ms). 창이 하나도 안 닫혔으면 `null`. */
274
+ recentSpanMs: number | null
275
+ /** 전체가 루프를 얼마나 쓰나(0~1+). 1 을 넘으면 **한 틱 안에 다 못 끝낸다.** */
276
+ fleetBusyRatio: number | null
277
+ slowest: { instanceId: string; mode: string; domainId?: string; domainLabel?: string; recentBusyMs: number; topPhase: LoadPhase | null; overBudget: number }[]
278
+ } {
279
+ const byMode: Record<string, number> = {}
280
+ const domains = new Map<string, { label: string; instances: number; recentBusyMs: number }>()
281
+ let forksCreated = 0
282
+ let recentBusyMs = 0
283
+ let recentSpanMs: number | null = null
284
+
285
+ const slowest = rows.map(r => {
286
+ byMode[r.mode] = (byMode[r.mode] ?? 0) + 1
287
+ forksCreated += r.meter?.forksCreated ?? 0
288
+
289
+ const recent = r.meter?.recent
290
+ const { rows: phaseRows, totalMs } = toRows(recent?.phases ?? {})
291
+ /*
292
+ * **잎에서 한 번만 반올림한다.** 도메인 합계와 전체 합계는 이 값을 더해서 만든다.
293
+ *
294
+ * 전에는 트윈·도메인·전체를 각자 원값에서 반올림했다. 그래서 화면의 숫자가 서로 안 맞았다:
295
+ * system 도메인 0.08ms 인데 그 도메인의 트윈 둘은 0.08 + 0.01 = 0.09ms (2026-08-07 지적).
296
+ * 보이는 부분들의 합이 보이는 합계와 달라지면 계기판을 믿을 수 없다.
297
+ */
298
+ const busyMs = round2(totalMs)
299
+ if (recent) {
300
+ recentBusyMs += busyMs
301
+ const span = recent.endMs - recent.startMs
302
+ /* 창 길이는 트윈마다 조금씩 다를 수 있다 — 가장 긴 것을 쓴다(짧은 것을 쓰면 비율이 부풀려진다). */
303
+ if (span > 0 && (recentSpanMs === null || span > recentSpanMs)) recentSpanMs = span
304
+ }
305
+
306
+ /* 테넌트별 합산 — 라벨을 모르면 id 를 그대로 쓴다(지어내지 않는다). */
307
+ const key = r.domainId ?? '(unknown)'
308
+ const dom = domains.get(key) ?? { label: r.domainLabel || key, instances: 0, recentBusyMs: 0 }
309
+ dom.instances += 1
310
+ dom.recentBusyMs += busyMs
311
+ domains.set(key, dom)
312
+
313
+ return {
314
+ instanceId: r.instanceId,
315
+ mode: r.mode,
316
+ domainId: r.domainId,
317
+ domainLabel: r.domainLabel,
318
+ recentBusyMs: busyMs,
319
+ topPhase: phaseRows[0]?.phase ?? null,
320
+ overBudget: r.meter?.overBudget ?? 0
321
+ }
322
+ })
323
+
324
+ slowest.sort((a, b) => b.recentBusyMs - a.recentBusyMs)
325
+
326
+ const byDomain = [...domains.entries()]
327
+ .map(([domainId, d]) => ({
328
+ domainId,
329
+ label: d.label,
330
+ instances: d.instances,
331
+ recentBusyMs: round2(d.recentBusyMs),
332
+ share: recentBusyMs > 0 ? round4(d.recentBusyMs / recentBusyMs) : 0
333
+ }))
334
+ .sort((a, b) => b.recentBusyMs - a.recentBusyMs)
335
+
336
+ return {
337
+ instances: rows.length,
338
+ byMode,
339
+ byDomain,
340
+ forksCreated,
341
+ recentBusyMs: round2(recentBusyMs),
342
+ recentSpanMs,
343
+ fleetBusyRatio: recentSpanMs && recentSpanMs > 0 ? round4(recentBusyMs / recentSpanMs) : null,
344
+ slowest
345
+ }
346
+ }
347
+
348
+ /**
349
+ * 프로세스가 실제로 쓴 CPU — **계기판의 다른 숫자들과 뜻이 다르다.**
350
+ *
351
+ * 이 파일의 다른 값들은 트윈의 **계측된 8개 작업**만 잰 것이다. 그런데 프로세스는 그 밖에도 일한다:
352
+ * GraphQL·TypeORM·GC·webpack·HTTP. 그래서 "루프 점유 <1%" 인데 CPU 는 110% 일 수 있고, 실제로 그런
353
+ * 상태를 겪었다. 두 숫자를 나란히 두면 **트윈이 범인인지 아닌지**를 바로 가릴 수 있다.
354
+ *
355
+ * 코어 여러 개를 쓰면 1 을 넘을 수 있다(운영체제의 `%CPU` 와 같은 뜻).
356
+ */
357
+ export type CpuSampler = { lastMicros: number; lastMs: number }
358
+
359
+ /** 첫 표본은 비교 대상이 없다 — `-1` 로 두어 "아직 모른다" 와 0 을 구별한다. */
360
+ export function newCpuSampler(): CpuSampler {
361
+ return { lastMicros: -1, lastMs: -1 }
362
+ }
363
+
364
+ /**
365
+ * 두 표본 사이의 CPU 점유율. 처음 부르면 `null`(0 이 아니다 — 잰 구간이 없다).
366
+ *
367
+ * @param totalMicros `process.cpuUsage()` 의 user + system (마이크로초 누적)
368
+ */
369
+ export function sampleCpu(s: CpuSampler, totalMicros: number, nowMs: number): { ratio: number; spanMs: number } | null {
370
+ const prevMicros = s.lastMicros
371
+ const prevMs = s.lastMs
372
+ s.lastMicros = totalMicros
373
+ s.lastMs = nowMs
374
+
375
+ if (prevMicros < 0 || prevMs < 0) return null
376
+
377
+ const spanMs = nowMs - prevMs
378
+ if (spanMs <= 0) return null
379
+
380
+ const usedMs = (totalMicros - prevMicros) / 1000
381
+ if (usedMs < 0) return null
382
+
383
+ return { ratio: round4(usedMs / spanMs), spanMs: Math.round(spanMs) }
384
+ }