@things-factory/headless-twin 10.0.8 โ†’ 10.0.10

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 (381) hide show
  1. package/dist-server/engine/attention-digest.d.ts +52 -0
  2. package/dist-server/engine/attention-digest.js +76 -0
  3. package/dist-server/engine/attention-digest.js.map +1 -0
  4. package/dist-server/engine/canonical-ingest.d.ts +2 -2
  5. package/dist-server/engine/canonical-ingest.js +24 -2
  6. package/dist-server/engine/canonical-ingest.js.map +1 -1
  7. package/dist-server/engine/command-routing.d.ts +33 -0
  8. package/dist-server/engine/command-routing.js +53 -0
  9. package/dist-server/engine/command-routing.js.map +1 -0
  10. package/dist-server/engine/energy-topology.d.ts +86 -0
  11. package/dist-server/engine/energy-topology.js +144 -0
  12. package/dist-server/engine/energy-topology.js.map +1 -0
  13. package/dist-server/engine/index.d.ts +11 -0
  14. package/dist-server/engine/index.js +17 -0
  15. package/dist-server/engine/index.js.map +1 -1
  16. package/dist-server/engine/kpi-baseline.d.ts +78 -0
  17. package/dist-server/engine/kpi-baseline.js +123 -0
  18. package/dist-server/engine/kpi-baseline.js.map +1 -0
  19. package/dist-server/engine/kpi-fold.d.ts +137 -1
  20. package/dist-server/engine/kpi-fold.js +225 -0
  21. package/dist-server/engine/kpi-fold.js.map +1 -1
  22. package/dist-server/engine/kpi-query.d.ts +32 -1
  23. package/dist-server/engine/kpi-query.js +262 -20
  24. package/dist-server/engine/kpi-query.js.map +1 -1
  25. package/dist-server/engine/kpi-target.d.ts +17 -0
  26. package/dist-server/engine/kpi-target.js +24 -2
  27. package/dist-server/engine/kpi-target.js.map +1 -1
  28. package/dist-server/engine/live-attentions.d.ts +1 -0
  29. package/dist-server/engine/live-attentions.js +7 -1
  30. package/dist-server/engine/live-attentions.js.map +1 -1
  31. package/dist-server/engine/live-feed-registry.d.ts +25 -0
  32. package/dist-server/engine/live-feed-registry.js +51 -0
  33. package/dist-server/engine/live-feed-registry.js.map +1 -0
  34. package/dist-server/engine/load-meter.d.ts +181 -0
  35. package/dist-server/engine/load-meter.js +267 -0
  36. package/dist-server/engine/load-meter.js.map +1 -0
  37. package/dist-server/engine/local-declarations.d.ts +262 -0
  38. package/dist-server/engine/local-declarations.js +528 -0
  39. package/dist-server/engine/local-declarations.js.map +1 -0
  40. package/dist-server/engine/model-basis.d.ts +39 -6
  41. package/dist-server/engine/model-basis.js +69 -9
  42. package/dist-server/engine/model-basis.js.map +1 -1
  43. package/dist-server/engine/model-vocabulary.d.ts +17 -0
  44. package/dist-server/engine/model-vocabulary.js +81 -0
  45. package/dist-server/engine/model-vocabulary.js.map +1 -0
  46. package/dist-server/engine/oee-accumulator.d.ts +28 -0
  47. package/dist-server/engine/oee-accumulator.js +26 -1
  48. package/dist-server/engine/oee-accumulator.js.map +1 -1
  49. package/dist-server/engine/operation-basis.d.ts +32 -0
  50. package/dist-server/engine/operation-basis.js +87 -0
  51. package/dist-server/engine/operation-basis.js.map +1 -0
  52. package/dist-server/engine/property-effects.d.ts +30 -0
  53. package/dist-server/engine/property-effects.js +192 -0
  54. package/dist-server/engine/property-effects.js.map +1 -0
  55. package/dist-server/engine/runtime-key.d.ts +15 -0
  56. package/dist-server/engine/runtime-key.js +64 -0
  57. package/dist-server/engine/runtime-key.js.map +1 -0
  58. package/dist-server/engine/spec-coverage.js +3 -3
  59. package/dist-server/engine/spec-coverage.js.map +1 -1
  60. package/dist-server/engine/state-axes.d.ts +21 -0
  61. package/dist-server/engine/state-axes.js +59 -0
  62. package/dist-server/engine/state-axes.js.map +1 -0
  63. package/dist-server/engine/structure-diff.js +1 -1
  64. package/dist-server/engine/structure-diff.js.map +1 -1
  65. package/dist-server/engine/travel-estimator.d.ts +9 -2
  66. package/dist-server/engine/travel-estimator.js +11 -6
  67. package/dist-server/engine/travel-estimator.js.map +1 -1
  68. package/dist-server/engine/twin-engine.d.ts +418 -57
  69. package/dist-server/engine/twin-engine.js +1599 -306
  70. package/dist-server/engine/twin-engine.js.map +1 -1
  71. package/dist-server/engine/warm-start.d.ts +93 -13
  72. package/dist-server/engine/warm-start.js +114 -14
  73. package/dist-server/engine/warm-start.js.map +1 -1
  74. package/dist-server/index.d.ts +1 -0
  75. package/dist-server/index.js +17 -11
  76. package/dist-server/index.js.map +1 -1
  77. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.d.ts +5 -0
  78. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js +48 -0
  79. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js.map +1 -0
  80. package/dist-server/migrations/index.d.ts +2 -0
  81. package/dist-server/migrations/index.js +10 -0
  82. package/dist-server/migrations/index.js.map +1 -0
  83. package/dist-server/service/index.d.ts +3 -2
  84. package/dist-server/service/index.js +25 -17
  85. package/dist-server/service/index.js.map +1 -1
  86. package/dist-server/service/reference/discovery-result.d.ts +34 -0
  87. package/dist-server/service/reference/discovery-result.js +84 -0
  88. package/dist-server/service/reference/discovery-result.js.map +1 -0
  89. package/dist-server/service/reference/ingest-space.d.ts +53 -0
  90. package/dist-server/service/reference/ingest-space.js +79 -0
  91. package/dist-server/service/reference/ingest-space.js.map +1 -0
  92. package/dist-server/service/reference/knob-defaults.d.ts +20 -0
  93. package/dist-server/service/reference/knob-defaults.js +59 -0
  94. package/dist-server/service/reference/knob-defaults.js.map +1 -0
  95. package/dist-server/service/reference/reference-live.d.ts +23 -0
  96. package/dist-server/service/reference/reference-live.js +123 -6
  97. package/dist-server/service/reference/reference-live.js.map +1 -1
  98. package/dist-server/service/reference/reference-master.d.ts +227 -11
  99. package/dist-server/service/reference/reference-master.js +206 -25
  100. package/dist-server/service/reference/reference-master.js.map +1 -1
  101. package/dist-server/service/reference/reference-resolver.d.ts +33 -3
  102. package/dist-server/service/reference/reference-resolver.js +290 -23
  103. package/dist-server/service/reference/reference-resolver.js.map +1 -1
  104. package/dist-server/service/reference/template-registry.d.ts +19 -3
  105. package/dist-server/service/reference/template-registry.js.map +1 -1
  106. package/dist-server/service/twin-attention/twin-attention-query.d.ts +8 -1
  107. package/dist-server/service/twin-attention/twin-attention-query.js +39 -8
  108. package/dist-server/service/twin-attention/twin-attention-query.js.map +1 -1
  109. package/dist-server/service/twin-audit/command-audit.d.ts +37 -0
  110. package/dist-server/service/twin-audit/command-audit.js +53 -0
  111. package/dist-server/service/twin-audit/command-audit.js.map +1 -0
  112. package/dist-server/service/twin-audit/index.d.ts +4 -0
  113. package/dist-server/service/twin-audit/index.js +8 -0
  114. package/dist-server/service/twin-audit/index.js.map +1 -0
  115. package/dist-server/service/twin-audit/twin-audit-event.d.ts +24 -0
  116. package/dist-server/service/twin-audit/twin-audit-event.js +125 -0
  117. package/dist-server/service/twin-audit/twin-audit-event.js.map +1 -0
  118. package/dist-server/service/twin-audit/twin-audit-query.d.ts +4 -0
  119. package/dist-server/service/twin-audit/twin-audit-query.js +76 -0
  120. package/dist-server/service/twin-audit/twin-audit-query.js.map +1 -0
  121. package/dist-server/service/twin-control/twin-control-mutation.d.ts +2 -0
  122. package/dist-server/service/twin-control/twin-control-mutation.js +50 -11
  123. package/dist-server/service/twin-control/twin-control-mutation.js.map +1 -1
  124. package/dist-server/service/twin-event/twin-event-keys.d.ts +1 -1
  125. package/dist-server/service/twin-event/twin-event-keys.js +1 -1
  126. package/dist-server/service/twin-event/twin-event-keys.js.map +1 -1
  127. package/dist-server/service/twin-event/twin-event.d.ts +14 -5
  128. package/dist-server/service/twin-event/twin-event.js +46 -14
  129. package/dist-server/service/twin-event/twin-event.js.map +1 -1
  130. package/dist-server/service/twin-forecast/forecast-metrics.d.ts +13 -0
  131. package/dist-server/service/twin-forecast/forecast-metrics.js +57 -0
  132. package/dist-server/service/twin-forecast/forecast-metrics.js.map +1 -0
  133. package/dist-server/service/twin-forecast/forecast-tuning.d.ts +12 -0
  134. package/dist-server/service/twin-forecast/forecast-tuning.js +44 -0
  135. package/dist-server/service/twin-forecast/forecast-tuning.js.map +1 -0
  136. package/dist-server/service/twin-forecast/gap-analytics.d.ts +28 -2
  137. package/dist-server/service/twin-forecast/gap-analytics.js +43 -17
  138. package/dist-server/service/twin-forecast/gap-analytics.js.map +1 -1
  139. package/dist-server/service/twin-forecast/twin-forecast-query.js +219 -39
  140. package/dist-server/service/twin-forecast/twin-forecast-query.js.map +1 -1
  141. package/dist-server/service/twin-instance/twin-instance.d.ts +38 -5
  142. package/dist-server/service/twin-instance/twin-instance.js +66 -18
  143. package/dist-server/service/twin-instance/twin-instance.js.map +1 -1
  144. package/dist-server/service/twin-journal/twin-journal-query.d.ts +11 -4
  145. package/dist-server/service/twin-journal/twin-journal-query.js +95 -15
  146. package/dist-server/service/twin-journal/twin-journal-query.js.map +1 -1
  147. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.d.ts +11 -5
  148. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js +46 -27
  149. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +1 -1
  150. package/dist-server/service/twin-metrics/twin-metrics-query.d.ts +1 -0
  151. package/dist-server/service/twin-metrics/twin-metrics-query.js +63 -1
  152. package/dist-server/service/twin-metrics/twin-metrics-query.js.map +1 -1
  153. package/dist-server/service/twin-model/epcis-coverage.d.ts +14 -0
  154. package/dist-server/service/twin-model/epcis-coverage.js +174 -0
  155. package/dist-server/service/twin-model/epcis-coverage.js.map +1 -0
  156. package/dist-server/service/twin-model/iec61850-coverage.d.ts +14 -0
  157. package/dist-server/service/twin-model/iec61850-coverage.js +98 -0
  158. package/dist-server/service/twin-model/iec61850-coverage.js.map +1 -0
  159. package/dist-server/service/twin-model/index.d.ts +13 -0
  160. package/dist-server/service/twin-model/index.js +29 -0
  161. package/dist-server/service/twin-model/index.js.map +1 -0
  162. package/dist-server/service/twin-model/isa95-coverage.d.ts +48 -0
  163. package/dist-server/service/twin-model/isa95-coverage.js +155 -0
  164. package/dist-server/service/twin-model/isa95-coverage.js.map +1 -0
  165. package/dist-server/service/twin-model/project-structure.d.ts +16 -0
  166. package/dist-server/service/twin-model/project-structure.js +173 -0
  167. package/dist-server/service/twin-model/project-structure.js.map +1 -0
  168. package/dist-server/service/twin-model/standard-coverage.d.ts +9 -0
  169. package/dist-server/service/twin-model/standard-coverage.js +37 -0
  170. package/dist-server/service/twin-model/standard-coverage.js.map +1 -0
  171. package/dist-server/service/twin-model/twin-equipment.d.ts +64 -0
  172. package/dist-server/service/twin-model/twin-equipment.js +134 -0
  173. package/dist-server/service/twin-model/twin-equipment.js.map +1 -0
  174. package/dist-server/service/twin-model/twin-lineage-query.d.ts +3 -0
  175. package/dist-server/service/twin-model/twin-lineage-query.js +206 -0
  176. package/dist-server/service/twin-model/twin-lineage-query.js.map +1 -0
  177. package/dist-server/service/twin-model/twin-location.d.ts +58 -0
  178. package/dist-server/service/twin-model/twin-location.js +130 -0
  179. package/dist-server/service/twin-model/twin-location.js.map +1 -0
  180. package/dist-server/service/twin-model/twin-model-item-query.d.ts +141 -0
  181. package/dist-server/service/twin-model/twin-model-item-query.js +852 -0
  182. package/dist-server/service/twin-model/twin-model-item-query.js.map +1 -0
  183. package/dist-server/service/twin-model/twin-model-mutation.d.ts +57 -0
  184. package/dist-server/service/twin-model/twin-model-mutation.js +490 -0
  185. package/dist-server/service/twin-model/twin-model-mutation.js.map +1 -0
  186. package/dist-server/service/twin-model/twin-model-query.d.ts +43 -0
  187. package/dist-server/service/twin-model/twin-model-query.js +551 -0
  188. package/dist-server/service/twin-model/twin-model-query.js.map +1 -0
  189. package/dist-server/service/twin-model/twin-model-tree-query.d.ts +3 -0
  190. package/dist-server/service/twin-model/twin-model-tree-query.js +158 -0
  191. package/dist-server/service/twin-model/twin-model-tree-query.js.map +1 -0
  192. package/dist-server/service/twin-model/twin-operation.d.ts +61 -0
  193. package/dist-server/service/twin-model/twin-operation.js +137 -0
  194. package/dist-server/service/twin-model/twin-operation.js.map +1 -0
  195. package/dist-server/service/twin-space/move-space.d.ts +65 -0
  196. package/dist-server/service/twin-space/move-space.js +166 -0
  197. package/dist-server/service/twin-space/move-space.js.map +1 -0
  198. package/dist-server/service/twin-space/space-integrity.d.ts +97 -0
  199. package/dist-server/service/twin-space/space-integrity.js +182 -0
  200. package/dist-server/service/twin-space/space-integrity.js.map +1 -0
  201. package/dist-server/service/twin-space/twin-space-area.js +4 -4
  202. package/dist-server/service/twin-space/twin-space-area.js.map +1 -1
  203. package/dist-server/service/twin-space/twin-space-representation.js +6 -6
  204. package/dist-server/service/twin-space/twin-space-representation.js.map +1 -1
  205. package/dist-server/service/twin-space/twin-space-resolver.d.ts +63 -1
  206. package/dist-server/service/twin-space/twin-space-resolver.js +365 -18
  207. package/dist-server/service/twin-space/twin-space-resolver.js.map +1 -1
  208. package/dist-server/service/twin-space/twin-space.d.ts +17 -1
  209. package/dist-server/service/twin-space/twin-space.js +15 -5
  210. package/dist-server/service/twin-space/twin-space.js.map +1 -1
  211. package/dist-server/service/twin-state/twin-state-subscription.js +1 -1
  212. package/dist-server/service/twin-state/twin-state-subscription.js.map +1 -1
  213. package/dist-server/service/twin-structure/twin-structure.d.ts +1 -1
  214. package/dist-server/service/twin-structure/twin-structure.js +8 -7
  215. package/dist-server/service/twin-structure/twin-structure.js.map +1 -1
  216. package/dist-server/service/twin-target/twin-target-resolver.js +21 -4
  217. package/dist-server/service/twin-target/twin-target-resolver.js.map +1 -1
  218. package/dist-shared/axis-read.d.ts +12 -0
  219. package/dist-shared/axis-read.js +32 -0
  220. package/dist-shared/axis-read.js.map +1 -0
  221. package/dist-shared/entity-delta.d.ts +29 -0
  222. package/dist-shared/entity-delta.js +287 -0
  223. package/dist-shared/entity-delta.js.map +1 -0
  224. package/dist-shared/kpi-broadcast.d.ts +4 -0
  225. package/dist-shared/kpi-broadcast.js +16 -0
  226. package/dist-shared/kpi-broadcast.js.map +1 -0
  227. package/dist-shared/twin-level.d.ts +23 -0
  228. package/dist-shared/twin-level.js +52 -0
  229. package/dist-shared/twin-level.js.map +1 -0
  230. package/package.json +14 -12
  231. package/server/engine/attention-digest.ts +102 -0
  232. package/server/engine/canonical-ingest.ts +36 -4
  233. package/server/engine/command-routing.ts +67 -0
  234. package/server/engine/energy-topology.ts +189 -0
  235. package/server/engine/index.ts +17 -0
  236. package/server/engine/kpi-baseline.ts +202 -0
  237. package/server/engine/kpi-fold.ts +389 -1
  238. package/server/engine/kpi-query.ts +295 -22
  239. package/server/engine/kpi-target.ts +24 -2
  240. package/server/engine/live-attentions.ts +7 -2
  241. package/server/engine/live-feed-registry.ts +58 -0
  242. package/server/engine/load-meter.ts +384 -0
  243. package/server/engine/local-declarations.ts +700 -0
  244. package/server/engine/model-basis.ts +78 -10
  245. package/server/engine/model-vocabulary.ts +82 -0
  246. package/server/engine/oee-accumulator.ts +34 -1
  247. package/server/engine/operation-basis.ts +100 -0
  248. package/server/engine/property-effects.ts +199 -0
  249. package/server/engine/runtime-key.ts +58 -0
  250. package/server/engine/spec-coverage.ts +3 -3
  251. package/server/engine/state-axes.ts +60 -0
  252. package/server/engine/structure-diff.ts +1 -1
  253. package/server/engine/travel-estimator.ts +11 -6
  254. package/server/engine/twin-engine.ts +1710 -297
  255. package/server/engine/warm-start.ts +207 -22
  256. package/server/index.ts +13 -10
  257. package/server/migrations/1786000000000-RenameTwinInstanceBoardToModel.ts +43 -0
  258. package/server/migrations/index.ts +7 -0
  259. package/server/service/index.ts +9 -1
  260. package/server/service/reference/discovery-result.ts +95 -0
  261. package/server/service/reference/ingest-space.ts +104 -0
  262. package/server/service/reference/knob-defaults.ts +59 -0
  263. package/server/service/reference/reference-live.ts +121 -6
  264. package/server/service/reference/reference-master.ts +362 -35
  265. package/server/service/reference/reference-resolver.ts +307 -23
  266. package/server/service/reference/template-registry.ts +20 -5
  267. package/server/service/twin-attention/twin-attention-query.ts +43 -6
  268. package/server/service/twin-audit/command-audit.ts +81 -0
  269. package/server/service/twin-audit/index.ts +5 -0
  270. package/server/service/twin-audit/twin-audit-event.ts +112 -0
  271. package/server/service/twin-audit/twin-audit-query.ts +72 -0
  272. package/server/service/twin-control/twin-control-mutation.ts +53 -13
  273. package/server/service/twin-event/twin-event-keys.ts +1 -1
  274. package/server/service/twin-event/twin-event.ts +52 -15
  275. package/server/service/twin-forecast/forecast-metrics.ts +60 -0
  276. package/server/service/twin-forecast/forecast-tuning.ts +40 -0
  277. package/server/service/twin-forecast/gap-analytics.ts +48 -9
  278. package/server/service/twin-forecast/twin-forecast-query.ts +211 -38
  279. package/server/service/twin-instance/twin-instance.ts +127 -22
  280. package/server/service/twin-journal/twin-journal-query.ts +108 -14
  281. package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +40 -23
  282. package/server/service/twin-metrics/twin-metrics-query.ts +60 -3
  283. package/server/service/twin-model/epcis-coverage.ts +195 -0
  284. package/server/service/twin-model/iec61850-coverage.ts +117 -0
  285. package/server/service/twin-model/index.ts +25 -0
  286. package/server/service/twin-model/isa95-coverage.ts +190 -0
  287. package/server/service/twin-model/project-structure.ts +199 -0
  288. package/server/service/twin-model/standard-coverage.ts +35 -0
  289. package/server/service/twin-model/twin-equipment.ts +150 -0
  290. package/server/service/twin-model/twin-lineage-query.ts +193 -0
  291. package/server/service/twin-model/twin-location.ts +140 -0
  292. package/server/service/twin-model/twin-model-item-query.ts +848 -0
  293. package/server/service/twin-model/twin-model-mutation.ts +503 -0
  294. package/server/service/twin-model/twin-model-query.ts +537 -0
  295. package/server/service/twin-model/twin-model-tree-query.ts +180 -0
  296. package/server/service/twin-model/twin-operation.ts +150 -0
  297. package/server/service/twin-space/move-space.ts +262 -0
  298. package/server/service/twin-space/space-integrity.ts +293 -0
  299. package/server/service/twin-space/twin-space-area.ts +4 -4
  300. package/server/service/twin-space/twin-space-representation.ts +6 -6
  301. package/server/service/twin-space/twin-space-resolver.ts +365 -22
  302. package/server/service/twin-space/twin-space.ts +40 -6
  303. package/server/service/twin-state/twin-state-subscription.ts +1 -1
  304. package/server/service/twin-structure/twin-structure.ts +10 -7
  305. package/server/service/twin-target/twin-target-resolver.ts +22 -4
  306. package/shared/axis-read.ts +28 -0
  307. package/shared/entity-delta.ts +286 -0
  308. package/shared/kpi-broadcast.ts +13 -0
  309. package/shared/twin-level.ts +48 -0
  310. package/test/adopt-structure-live.test.ts +133 -0
  311. package/test/attention-digest.test.ts +135 -0
  312. package/test/axis-read.test.ts +87 -0
  313. package/test/boot-resume.test.ts +205 -0
  314. package/test/canonical-ingest-vocabularies.test.ts +118 -0
  315. package/test/capability-mapping.test.ts +5 -5
  316. package/test/command-routing.test.ts +61 -0
  317. package/test/declaration-reaches-model.test.ts +178 -0
  318. package/test/discovery-result.test.ts +75 -0
  319. package/test/energy-topology.test.ts +113 -0
  320. package/test/entity-delta.test.ts +195 -25
  321. package/test/event-time-column.test.ts +67 -0
  322. package/test/forecast-metrics.test.ts +71 -0
  323. package/test/forecast-tuning.test.ts +42 -0
  324. package/test/gap-analytics.test.ts +34 -7
  325. package/test/ingest-bench.test.ts +9 -9
  326. package/test/ingest-running-guard.test.ts +136 -0
  327. package/test/ingest-space.test.ts +78 -0
  328. package/test/instance-cache-lifecycle.test.ts +110 -0
  329. package/test/kernel-kind-guard.test.ts +96 -0
  330. package/test/knob-defaults.test.ts +72 -0
  331. package/test/kpi-baseline-db.test.ts +216 -0
  332. package/test/kpi-baseline.test.ts +196 -0
  333. package/test/kpi-fold.test.ts +393 -2
  334. package/test/kpi-query-bench.test.ts +130 -0
  335. package/test/lineage-survives-restart.test.ts +203 -0
  336. package/test/live-feed-registry.test.ts +67 -0
  337. package/test/live-kernel-facts.test.ts +161 -0
  338. package/test/live-mirror-parity.test.ts +54 -14
  339. package/test/load-meter.test.ts +314 -0
  340. package/test/local-declarations.test.ts +554 -0
  341. package/test/master-to-twin.test.ts +128 -36
  342. package/test/model-basis.test.ts +56 -1
  343. package/test/model-vocabulary.test.ts +114 -0
  344. package/test/move-space.test.ts +149 -0
  345. package/test/mutation-gate.test.ts +122 -0
  346. package/test/oee-accumulator.test.ts +90 -7
  347. package/test/operation-basis.test.ts +100 -0
  348. package/test/operations-capability-db.test.ts +165 -0
  349. package/test/project-structure-db.test.ts +226 -0
  350. package/test/projection-reaches-screen.test.ts +272 -0
  351. package/test/property-effects.test.ts +96 -0
  352. package/test/registry-key-guard.test.ts +80 -0
  353. package/test/resync-origin-site.test.ts +77 -0
  354. package/test/runtime-key.test.ts +66 -0
  355. package/test/scale-twin-bench.test.ts +7 -7
  356. package/test/snapshot-freshness.test.ts +60 -0
  357. package/test/space-integrity.test.ts +223 -0
  358. package/test/standard-coverage.test.ts +94 -0
  359. package/test/state-axes.test.ts +74 -0
  360. package/test/streamline-e2e.test.ts +16 -16
  361. package/test/structure-revision-db.test.ts +16 -15
  362. package/test/tenant-registry-db.test.ts +149 -0
  363. package/test/twin-audit.test.ts +83 -0
  364. package/test/twin-model-item-db.test.ts +275 -0
  365. package/test/twin-model-tree-db.test.ts +176 -0
  366. package/test/twin-origin-resync.test.ts +114 -0
  367. package/test/warm-start-seam.test.ts +140 -0
  368. package/test/warm-start.test.ts +223 -4
  369. package/tsconfig.json +6 -1
  370. package/tsconfig.shared.json +23 -0
  371. package/tsconfig.shared.tsbuildinfo +1 -0
  372. package/tsconfig.tsbuildinfo +1 -0
  373. package/dist-server/engine/entity-delta.d.ts +0 -19
  374. package/dist-server/engine/entity-delta.js +0 -161
  375. package/dist-server/engine/entity-delta.js.map +0 -1
  376. package/dist-server/service/twin-event/backfill-keys.d.ts +0 -11
  377. package/dist-server/service/twin-event/backfill-keys.js +0 -63
  378. package/dist-server/service/twin-event/backfill-keys.js.map +0 -1
  379. package/dist-server/tsconfig.tsbuildinfo +0 -1
  380. package/server/engine/entity-delta.ts +0 -169
  381. package/server/service/twin-event/backfill-keys.ts +0 -72
@@ -28,14 +28,22 @@ const twin_space_js_1 = require("../service/twin-space/twin-space.js");
28
28
  const twin_target_js_1 = require("../service/twin-target/twin-target.js");
29
29
  const kpi_target_js_1 = require("./kpi-target.js");
30
30
  const twin_engine_js_1 = require("./twin-engine.js");
31
+ const energy_topology_js_1 = require("./energy-topology.js");
31
32
  const kpi_fold_js_1 = require("./kpi-fold.js");
32
- /** ์—…๋ฌด ์ „์ด๋งŒ ์ฝ๋Š”๋‹ค โ€” ์„ค๋น„ ์ƒํƒœ(equipment.status)๋Š” OEE ๋ˆ„์ ๊ธฐ์˜ ๋ชซ์ด๊ณ  ์—ฌ๊ธฐ์„  ์“ฐ์ง€ ์•Š๋Š”๋‹ค. */
33
- const BUSINESS_EVENTS = ['task.status', 'order.status'];
33
+ const kpi_baseline_js_1 = require("./kpi-baseline.js");
34
+ /**
35
+ * ์—…๋ฌด ์ „์ด๋งŒ ์ฝ๋Š”๋‹ค โ€” ์„ค๋น„ ์ƒํƒœ(equipment.status)๋Š” OEE ๋ˆ„์ ๊ธฐ์˜ ๋ชซ์ด๊ณ  ์—ฌ๊ธฐ์„  ์“ฐ์ง€ ์•Š๋Š”๋‹ค.
36
+ *
37
+ * **์—๋„ˆ์ง€ ๊ตฌ๊ฐ„ ๋งˆ๊ฐ**์€ ํ•จ๊ป˜ ์ฝ๋Š”๋‹ค(2026-08-14): ์›๋‹จ์œ„๋Š” ๋ถ„์ž(์ „๋ ฅ๋Ÿ‰)์™€ ๋ถ„๋ชจ(์‚ฐ์ถœ)๋ฅผ **๊ฐ™์€ ์ฐฝ**์—์„œ
38
+ * ๋‚˜๋ˆˆ ๊ฐ’์ด๋ผ, ๋‘ ์‚ฌ์‹ค์ด ํ•œ ํด๋“œ์— ๋“ค์–ด์™€์•ผ ์ฐฝ์ด ์–ด๊ธ‹๋‚  ์ˆ˜ ์—†๋‹ค. ํ‘œ๋ณธ(`energy.measured`)์€ ์ฝ์ง€ ์•Š๋Š”๋‹ค โ€”
39
+ * ์ €๋„์— ์—†๊ณ (ยง4.1 ์ธ์ œ์ŠคํŠธ ๊ณ„์•ฝ) ์—ฌ๊ธฐ์„œ ํ•„์š”ํ•œ ๊ฒƒ์€ ๋งˆ๊ฐ๋œ ๊ตฌ๊ฐ„๋ฟ์ด๋‹ค.
40
+ */
41
+ const BUSINESS_EVENTS = ['task.status', 'order.status', 'energy.demand.window'];
34
42
  /** ํ•œ ๋ฒˆ์— ์ ‘์„ ์ด๋ฒคํŠธ ์ƒํ•œ โ€” ํฐ ๊ตฌ๊ฐ„์ด ์„œ๋ฒ„๋ฅผ ๋ถ™์žก์ง€ ์•Š๊ฒŒ. */
35
43
  const MAX_EVENTS = 20000;
36
44
  /**
37
- * ๋…ธ๋“œ โ†’ ๊ตฌ์—ญ ์ง€๋„. **์ €๋„์—๋Š” ๊ตฌ์—ญ์ด ์—†๋‹ค**(๋…ธ๋“œ๊นŒ์ง€๋งŒ ์žˆ๋‹ค) โ€” ๋ณด๋“œ ์ •์˜์˜ `locations[].parentId` ๊ฐ€
38
- * ๋งˆ์Šคํ„ฐ ๊ณ„์ธต์—์„œ ์˜จ ์†Œ์†์ด๋‹ค. ๊ธฐ๋™ํ•˜์ง€ ์•Š์€ ํŠธ์œˆ๋„ ๋ณด๋“œ๋Š” ๋‚จ์•„ ์žˆ์–ด ์ด ๊ฒฝ๋กœ๊ฐ€ ๊ฐ€์žฅ ํŠผํŠผํ•˜๋‹ค.
45
+ * ๋…ธ๋“œ โ†’ ๊ตฌ์—ญ ์ง€๋„. **์ €๋„์—๋Š” ๊ตฌ์—ญ์ด ์—†๋‹ค**(๋…ธ๋“œ๊นŒ์ง€๋งŒ ์žˆ๋‹ค) โ€” ๋ชจ๋ธ ์ •์˜์˜ `locations[].parentId` ๊ฐ€
46
+ * ๋งˆ์Šคํ„ฐ ๊ณ„์ธต์—์„œ ์˜จ ์†Œ์†์ด๋‹ค. ๊ธฐ๋™ํ•˜์ง€ ์•Š์€ ํŠธ์œˆ๋„ ๋ชจ๋ธ์€ ๋‚จ์•„ ์žˆ์–ด ์ด ๊ฒฝ๋กœ๊ฐ€ ๊ฐ€์žฅ ํŠผํŠผํ•˜๋‹ค.
39
47
  *
40
48
  * **ํ•œ ํ™‰๋งŒ ๋ณด๋ฉด ์•ˆ ๋œ๋‹ค.** `parentId` ๋Š” ๊ตฌ์—ญ์ผ ์ˆ˜๋„ ์žˆ๊ณ  ์ค‘๊ฐ„ ๋‹จ(๋ผ์ธยท์…€)์ผ ์ˆ˜๋„ ์žˆ๋‹ค. ๋ผ์ธ์ด ๋ผ๋ฉด
41
49
  * ํ•œ ํ™‰์งœ๋ฆฌ ์ฝ”๋“œ๋Š” "๊ตฌ์—ญ์ด LINE-1" ์ด๋ผ๊ณ  ๋‹ตํ•˜๊ณ , ๊ทธ id ๋Š” ๊ตฌ์—ญ ๋ชฉ๋ก์— ์—†์œผ๋ฏ€๋กœ ๊ทธ ์•„๋ž˜ ์Šคํ…Œ์ด์…˜์ด
@@ -48,11 +56,11 @@ const MAX_EVENTS = 20000;
48
56
  * ์ €๋„์—๋Š” ์‹œ๊ฐ๋งŒ ์žˆ๊ณ  ๊ต๋Œ€๊ฐ€ ์—†๋‹ค(์ผ๋ถ€๋Ÿฌ ๊ทธ๋ ‡๊ฒŒ ๋’€๋‹ค โ€” ๊ต๋Œ€๋Š” ํŒŒ์ƒ์ด๋ผ ์ฐ์–ด ๋‘๋ฉด ๋‚˜์ค‘์— ๊ต๋Œ€ ์‹œ๊ฐ„์„
49
57
  * ๊ณ ์ณค์„ ๋•Œ ๊ณผ๊ฑฐ๊ฐ€ ์˜› ๊ตฌ๋ถ„์œผ๋กœ ๊ตณ๋Š”๋‹ค). ๊ทธ๋ž˜์„œ ํด๋“œ๊ฐ€ ๊ณ„์‚ฐํ•  ์žฌ๋ฃŒ๋ฅผ ์—ฌ๊ธฐ์„œ ๋ชจ์€๋‹ค.
50
58
  *
51
- * ์„ ์–ธ์˜ ์ถœ์ฒ˜๋Š” **๋ณด๋“œ์˜ ์„ค๋น„**๋‹ค. ์—ฌ๋Ÿฌ ์„ค๋น„๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ๊ต๋Œ€๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ, ์ถ•์€ ํ•˜๋‚˜์—ฌ์•ผ ํ•˜๋ฏ€๋กœ
59
+ * ์„ ์–ธ์˜ ์ถœ์ฒ˜๋Š” **๋ชจ๋ธ์˜ ์„ค๋น„**๋‹ค. ์—ฌ๋Ÿฌ ์„ค๋น„๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ๊ต๋Œ€๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ, ์ถ•์€ ํ•˜๋‚˜์—ฌ์•ผ ํ•˜๋ฏ€๋กœ
52
60
  * **๊ฐ€์žฅ ๋งŽ์ด ์“ฐ์ด๋Š” ์„ ์–ธ ํ•œ ๋ฒŒ**์„ ์“ด๋‹ค โ€” 3๊ต๋Œ€ ๊ณต์žฅ์€ ์ „ ์„ค๋น„๊ฐ€ ๊ฐ™์€ ๊ต๋Œ€์ด๋ฏ€๋กœ ์ด๊ฒƒ์ด ๊ณง ์ •๋‹ต์ด๊ณ ,
53
61
  * ์ž์›๋งˆ๋‹ค ๊ต๋Œ€๊ฐ€ ๋‹ค๋ฅธ ํ˜„์žฅ์—์„œ๋Š” ์ด ์ถ•์ด ๊ฑฐ์น ๋‹ค๋Š” ๋œป์ด๋‹ค(๊ทธ ์‚ฌ์‹ค์„ ์—ฌ๊ธฐ ์ ์–ด ๋‘”๋‹ค).
54
62
  *
55
- * ์‹œ๊ฐ ๊ธฐ์ค€์€ ๋ณด๋“œ์— ์‹ค๋ ค ์žˆ๋‹ค(`utcOffsetMinutes` โ€” ๊ณต๊ฐ„์ด ๊ฐ–๋Š” ๊ฐ’์„ ๊ธฐ๋™ ์‹œ ํ˜ธ์ŠคํŠธ๊ฐ€ ํ’€์–ด ๋„ฃ๋Š”๋‹ค).
63
+ * ์‹œ๊ฐ ๊ธฐ์ค€์€ ๋ชจ๋ธ์— ์‹ค๋ ค ์žˆ๋‹ค(`utcOffsetMinutes` โ€” ๊ณต๊ฐ„์ด ๊ฐ–๋Š” ๊ฐ’์„ ๊ธฐ๋™ ์‹œ ํ˜ธ์ŠคํŠธ๊ฐ€ ํ’€์–ด ๋„ฃ๋Š”๋‹ค).
56
64
  * ์—†์œผ๋ฉด UTC ๋กœ ์ฝ๊ณ , ๊ทธ ๊ธฐ๋ณธ๊ฐ’์€ ์ปค๋„ ๊ณ„์•ฝ์— ๋ฐํ˜€์ ธ ์žˆ๋‹ค.
57
65
  */
58
66
  /**
@@ -74,10 +82,10 @@ async function shiftContext(domainId, instanceIds) {
74
82
  const tally = new Map();
75
83
  let utcOffsetMinutes;
76
84
  for (const row of rows) {
77
- const board = row.board;
78
- if (utcOffsetMinutes === undefined && typeof board?.utcOffsetMinutes === 'number')
79
- utcOffsetMinutes = board.utcOffsetMinutes;
80
- for (const e of (board?.equipment ?? [])) {
85
+ const model = row.model;
86
+ if (utcOffsetMinutes === undefined && typeof model?.utcOffsetMinutes === 'number')
87
+ utcOffsetMinutes = model.utcOffsetMinutes;
88
+ for (const e of (model?.equipment ?? [])) {
81
89
  const decl = e?.workCalendar;
82
90
  if (!Array.isArray(decl) || !decl.length)
83
91
  continue;
@@ -102,13 +110,18 @@ async function locationAreaMap(domainId, instanceIds, spaceId) {
102
110
  where: { domain: { id: domainId }, instanceId: (0, typeorm_1.In)(instanceIds) }
103
111
  });
104
112
  for (const row of rows) {
105
- const locations = (row.board?.locations ?? []).filter(n => n?.id);
113
+ const locations = (row.model?.locations ?? []).filter(n => n?.id);
106
114
  if (!locations.length)
107
115
  continue;
108
116
  /* ์ˆœํ™˜์€ hierarchyOf ๊ฐ€ ๋˜์ง„๋‹ค โ€” ํ•œ ํŠธ์œˆ์˜ ์ž˜๋ชป๋œ ๊ณ„์ธต์ด ๋‹ค๋ฅธ ํŠธ์œˆ์˜ ์ง‘๊ณ„๊นŒ์ง€ ์ฃฝ์ด์ง€ ์•Š๊ฒŒ ์—ฌ๊ธฐ์„œ ๊ฐ€๋‘”๋‹ค. */
109
117
  let h;
110
118
  try {
111
- h = (0, twin_kernel_1.hierarchyOf)({ locations });
119
+ /*
120
+ * ๋‹จ ํ•ด์„๊ธฐ๋ฅผ ํ•จ๊ป˜ ๋„˜๊ธด๋‹ค โ€” ์ž๋ฆฌ๊ฐ€ `level` ์„ ์ ์ง€ ์•Š์œผ๋ฉด **ํƒ€์ž…์ด ๋‹ตํ•œ๋‹ค**(์นดํƒˆ๋กœ๊ทธ ์„ ์–ธ).
121
+ * ์ด ์ง‘๊ณ„๋Š” ์ง€๊ธˆ ๊ตฌ์—ญ ๋กค์—…(`rollupOf`)๋งŒ ์“ฐ๋ฏ€๋กœ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ฌ๋ผ์ง€์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ž˜๋„ ์—ฌ๊ธฐ์„œ
122
+ * ์ž‡๋Š”๋‹ค: ๋‹จ์œผ๋กœ ๋ฌป๋Š” ์งˆ์˜(`ancestorOfLevel`)๊ฐ€ ์ƒ๊ธธ ๋•Œ ๋ฐฐ์„ ์„ ๋‹ค์‹œ ์ฐพ์ง€ ์•Š๊ฒŒ ํ•œ๋‹ค.
123
+ */
124
+ h = (0, twin_kernel_1.hierarchyOf)({ locations }, t => (0, twin_kernel_1.levelOfLocationType)(t, row.kind));
112
125
  }
113
126
  catch (e) {
114
127
  console.warn(`[twin-kpi] "${row.instanceId}": location hierarchy is broken โ€” area rollup skipped for this twin: ${e?.message}`);
@@ -136,6 +149,150 @@ async function locationAreaMap(domainId, instanceIds, spaceId) {
136
149
  }
137
150
  return { locationArea, labels };
138
151
  }
152
+ /**
153
+ * ์ž์› โ†’ **๋ฐฐ์ „ ๊ณ„ํ†ต์˜ ์ž๋ฆฌ**(๋ถ„๊ธฐยท์ˆ˜์ „) ์ง€๋„์™€ ๊ทธ ์ž๋ฆฌ์˜ ์ด๋ฆ„.
154
+ *
155
+ * โ”€โ”€ ๋ฌด์—‡์„ ์ฝ๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
156
+ * ์—๋„ˆ์ง€ ํŠธ์œˆ์˜ ๋ชจ๋ธ์ด ใ€Œ์ด ์„ค๋น„๊ฐ€ ์–ด๋А ์ž๋ฆฌ์— ๋งค๋‹ฌ๋ ธ๋‚˜ใ€๋ฅผ ์„ ์–ธํ•œ๋‹ค(`homeLocation`). ๊ทธ ์ž๋ฆฌ๊ฐ€ ๋ถ„๊ธฐ๊ฐ€
157
+ * ์•„๋‹ˆ๋ผ ํ•˜์œ„ ์ž๋ฆฌ๋ผ๋ฉด ๋ถ€๋ชจ๋ฅผ ํƒ€๊ณ  ์˜ฌ๋ผ๊ฐ€ **์ „๊ธฐ ๊ณ„ํ†ต์˜ ์ž๋ฆฌ**๋ฅผ ์ฐพ๋Š”๋‹ค โ€” ์ „๊ธฐ์˜ ๊ณ„ํ†ต์€ ๋ฌผ๋ฆฌ ๊ตฌ์—ญ๊ณผ
158
+ * ๋‹ค๋ฅธ ๋‚˜๋ฌด์ด๋ฏ€๋กœ ๊ตฌ์—ญ ๋กค์—…(`locationAreaMap`)์„ ์“ธ ์ˆ˜ ์—†๋‹ค.
159
+ *
160
+ * โ”€โ”€ ์™œ ์—๋„ˆ์ง€ ํŠธ์œˆ๋งŒ ์ฝ๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
161
+ * ๊ฐ™์€ ์„ค๋น„๊ฐ€ ๊ณต์žฅ ํŠธ์œˆ์—์„œ๋Š” ์ž์›(์ž‘์—…์„ ํ•œ๋‹ค)์ด๊ณ  ์—๋„ˆ์ง€ ํŠธ์œˆ์—์„œ๋Š” ๋ถ€ํ•˜(์ „๊ธฐ๋ฅผ ๋จน๋Š”๋‹ค)๋‹ค โ€” ์‚ฌ์‹ค ๋‘˜,
162
+ * id ํ•˜๋‚˜. ๊ฐ€๋™์‹œ๊ฐ„์€ ๊ณต์žฅ ํŠธ์œˆ์˜ ์ €๋„์—์„œ ์˜ค๊ณ , ์ „๊ธฐ ๊ณ„ํ†ต์˜ ์†Œ์†์€ ์ด ๋ชจ๋ธ์—์„œ ์˜จ๋‹ค. ๊ทธ ๋‘˜์„ id ๋กœ
163
+ * ์ž‡๋Š” ๊ฒƒ์ด ์ด ์ง€๋„์˜ ์ผ์ด๋‹ค.
164
+ *
165
+ * ์ž๋ฆฌ๋ฅผ ๋งํ•˜์ง€ ์•Š๋Š” ์„ค๋น„๋Š” **๋„ฃ์ง€ ์•Š๋Š”๋‹ค** โ€” ์—†๋Š” ์†Œ์†์„ ๋งŒ๋“ค๋ฉด ๊ทธ ๋ชซ์ด ์—‰๋šฑํ•œ ๋ถ„๊ธฐ์˜ ๊ฒƒ์ด ๋œ๋‹ค.
166
+ */
167
+ /**
168
+ * ์„ ์–ธ๋œ **์ „๊ธฐ์š”๊ธˆ ๋‹จ๊ฐ€** โ€” ์—๋„ˆ์ง€ ํŠธ์œˆ์˜ ์ž๋ฆฌ ์†์„ฑ์—์„œ ์ฝ๋Š”๋‹ค(๊ณ„์•ฝ์ „๋ ฅ๊ณผ ๊ฐ™์€ ์ž๋ฆฌ).
169
+ *
170
+ * ์—ฌ๋Ÿฌ ์—๋„ˆ์ง€ ํŠธ์œˆ์ด ํ•œ ํ˜„์žฅ์— ์žˆ์œผ๋ฉด **์ฒ˜์Œ ์„ ์–ธ๋œ ๊ฒƒ ํ•˜๋‚˜**๋ฅผ ์“ด๋‹ค. ํ‰๊ท ์„ ๋‚ด๊ฑฐ๋‚˜ ํ•ฉ์น˜์ง€ ์•Š๋Š”๋‹ค:
171
+ * ์š”๊ธˆ์€ ๊ณ„์•ฝ์ด๊ณ , ๋‘ ๊ณ„์•ฝ์„ ์„ž์€ ๋‹จ๊ฐ€๋Š” ์–ด๋А ๊ณ„์•ฝ๋„ ์•„๋‹ˆ๋‹ค. ์„œ๋กœ ๋‹ค๋ฅธ ๋‹จ๊ฐ€๊ฐ€ ์„ ์–ธ๋ผ ์žˆ์œผ๋ฉด ๊ทธ๊ฒƒ์„
172
+ * ๋ฐํžŒ๋‹ค(์กฐ์šฉํžˆ ํ•˜๋‚˜๋ฅผ ๊ณ ๋ฅด๋ฉด ์™œ ๊ทธ ๊ธˆ์•ก์ธ์ง€ ์•„๋ฌด๋„ ์„ค๋ช…ํ•  ์ˆ˜ ์—†๋‹ค).
173
+ */
174
+ async function tariffOf(domainId, instanceIds) {
175
+ if (!instanceIds.length)
176
+ return {};
177
+ const rows = await (0, shell_1.getRepository)(twin_instance_js_1.TwinInstance).find({ where: { domain: { id: domainId }, instanceId: (0, typeorm_1.In)(instanceIds) } });
178
+ const found = [];
179
+ for (const row of rows) {
180
+ if (row.kind !== 'ems')
181
+ continue;
182
+ for (const loc of (row.model?.locations ?? [])) {
183
+ const props = new Map((loc?.properties ?? []).map(p => [String(p?.id), p?.value]));
184
+ const num = (id) => {
185
+ const v = Number(props.get(id));
186
+ return Number.isFinite(v) && v > 0 ? v : undefined;
187
+ };
188
+ const d = num(twin_kernel_1.EMS_PROPERTY.demandChargePerKW);
189
+ const e = num(twin_kernel_1.EMS_PROPERTY.energyChargePerKWh);
190
+ const cur = props.get(twin_kernel_1.EMS_PROPERTY.currency);
191
+ if (d === undefined && e === undefined)
192
+ continue;
193
+ found.push({
194
+ ...(d !== undefined ? { demandChargePerKW: d } : {}),
195
+ ...(e !== undefined ? { energyChargePerKWh: e } : {}),
196
+ ...(cur ? { currency: String(cur) } : {})
197
+ });
198
+ }
199
+ }
200
+ if (!found.length)
201
+ return {};
202
+ const first = found[0];
203
+ const same = found.every(t => t.demandChargePerKW === first.demandChargePerKW && t.energyChargePerKWh === first.energyChargePerKWh && t.currency === first.currency);
204
+ return { tariff: first, ...(same ? {} : { conflict: true }) };
205
+ }
206
+ async function resourceFeederMap(domainId, instanceIds) {
207
+ const resourceFeeder = {};
208
+ /** ๊ณ„๋Ÿ‰ ์ง€์  โ†’ ๊ทธ๊ฒƒ์ด ์žฌ๋Š” ๋ถ„๊ธฐ. ์žˆ์œผ๋ฉด ๊ทธ ๋ถ„๊ธฐ ๊ฐ’์€ **์ธก์ •**์ด๋‹ค(๋ฐฐ๋ถ„๋ณด๋‹ค ๊ฐ•ํ•œ ๊ทผ๊ฑฐ). */
209
+ const meterFeeder = {};
210
+ const labels = {};
211
+ if (!instanceIds.length)
212
+ return { resourceFeeder, meterFeeder, labels };
213
+ const rows = await (0, shell_1.getRepository)(twin_instance_js_1.TwinInstance).find({ where: { domain: { id: domainId }, instanceId: (0, typeorm_1.In)(instanceIds) } });
214
+ for (const row of rows) {
215
+ if (row.kind !== 'ems')
216
+ continue; // ์ „๊ธฐ ๊ณ„ํ†ต์„ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์€ ์—๋„ˆ์ง€ ํŠธ์œˆ์ด๋‹ค
217
+ const model = row.model ?? {};
218
+ const locations = (model.locations ?? []).filter((n) => n?.id);
219
+ const byId = new Map(locations.map((n) => [String(n.id), n]));
220
+ const electrical = new Set(twin_kernel_1.EMS_LOCATION_TYPES);
221
+ /**
222
+ * ์ด ์ž๋ฆฌ์—์„œ **์ „๊ธฐ ์ƒ๋ฅ˜**๋กœ ์˜ฌ๋ผ๊ฐ€ ์ฒ˜์Œ ๋งŒ๋‚˜๋Š” ๊ณ„ํ†ต์˜ ์ž๋ฆฌ. ์—†์œผ๋ฉด undefined.
223
+ *
224
+ * ์ƒ๋ฅ˜์˜ ๋œป์€ ์ปค๋„์ด ์ฝ๋Š”๋‹ค(`electricalUpstreamOf`) โ€” ๊ณต๊ฐ„ ๋ถ€๋ชจ(๊ณต์žฅยท๊ตฌ์—ญ)๋ฅผ ๋”ฐ๋ผ ์˜ฌ๋ผ๊ฐ€๋ฉด ์ „๊ธฐ์ ์œผ๋กœ
225
+ * ๋œป์ด ์—†๋Š” ๊ธธ์„ ๊ฑท๊ฒŒ ๋˜๊ณ , ์˜› ์„ธ๋Œ€(๋ถ„๊ธฐ์˜ `parentId` ์— ์ˆ˜์ „)์™€ ์ƒˆ ์„ธ๋Œ€(`upstreamId`)๊ฐ€ ์„ž์—ฌ ์žˆ์œผ๋ฏ€๋กœ
226
+ * ๊ทธ ํŒ์ •์„ ์—ฌ๊ธฐ์„œ ๋‹ค์‹œ ์“ฐ๋ฉด ๋‘ ๋ฒŒ์ด ๋œ๋‹ค.
227
+ */
228
+ const feederOf = (startId) => {
229
+ const seen = new Set();
230
+ let cur = byId.get(startId);
231
+ while (cur && !seen.has(String(cur.id))) {
232
+ seen.add(String(cur.id)); // ์ž˜๋ชป๋œ ๋ชจ๋ธ์˜ ์ˆœํ™˜์ด ์—ฌ๊ธฐ์„œ ๋ฉˆ์ถ˜๋‹ค
233
+ if (electrical.has(String(cur.type)))
234
+ return String(cur.id);
235
+ const up = (0, twin_kernel_1.electricalUpstreamOf)(locations, String(cur.id));
236
+ cur = up ? byId.get(up) : cur.parentId ? byId.get(String(cur.parentId)) : undefined;
237
+ }
238
+ return undefined;
239
+ };
240
+ for (const e of (model.equipment ?? [])) {
241
+ const home = e?.homeLocation ?? e?.homeLocationId;
242
+ if (!e?.id || !home)
243
+ continue;
244
+ /*
245
+ * ๊ณ„๋Ÿ‰๊ธฐ๋Š” ๋ถ€ํ•˜๊ฐ€ ์•„๋‹ˆ๋‹ค โ€” ๊ทธ๊ฒƒ์˜ ใ€Œ๋ชซใ€์„ ์„ธ๋ฉด ์ด๋Ÿ‰์ด ์ด์ค‘์œผ๋กœ ๋‚˜๋‰œ๋‹ค. ๋Œ€์‹  **์–ด๋””๋ฅผ ์žฌ๋Š”์ง€**๋ฅผ
246
+ * ๋”ฐ๋กœ ๋ชจ์€๋‹ค: ๊ณ„๋Ÿ‰๊ธฐ๊ฐ€ ๋ถ„๊ธฐ์— ์žˆ์œผ๋ฉด ๊ทธ ๋ถ„๊ธฐ ๊ฐ’์€ ๋ฐฐ๋ถ„์ด ์•„๋‹ˆ๋ผ **์ธก์ •**์ด๋‹ค(๊ฐ€์žฅ ๊ฐ•ํ•œ ๊ทผ๊ฑฐ).
247
+ */
248
+ if (e.kind === 'meter') {
249
+ const at = feederOf(String(home));
250
+ /* ๋ฟŒ๋ฆฌ(์ˆ˜์ „)๋ฅผ ์žฌ๋Š” ๊ณ„๋Ÿ‰๊ธฐ๋Š” ๋ถ„๊ธฐ์˜ ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค โ€” ๊ทธ ๊ฐ’์€ ์ด๋Ÿ‰์ด๊ณ , ๋‚˜๋จธ์ง€๋Š” ๋บ„์…ˆ์œผ๋กœ ๋‚˜์˜จ๋‹ค. */
251
+ if (at && String(byId.get(at)?.type) !== 'incoming')
252
+ meterFeeder[String(e.id)] = at;
253
+ continue;
254
+ }
255
+ /* ์ฐจ๋‹จ๊ธฐยทํƒœ์–‘๊ด‘ยท์ถ•์ „์ง€๋„ ๋ถ€ํ•˜๊ฐ€ ์•„๋‹ˆ๋‹ค. */
256
+ if (e.kind === 'breaker' || e.kind === 'pv-array' || e.kind === 'battery')
257
+ continue;
258
+ const feeder = feederOf(String(home));
259
+ if (feeder)
260
+ resourceFeeder[String(e.id)] = feeder;
261
+ }
262
+ for (const n of locations)
263
+ if (electrical.has(String(n.type)) && n.name)
264
+ labels[String(n.id)] = String(n.name);
265
+ }
266
+ return { resourceFeeder, meterFeeder, labels };
267
+ }
268
+ /**
269
+ * ์ด ๊ณต๊ฐ„์˜ ์—๋„ˆ์ง€ ํŠธ์œˆ๋“ค์˜ ๊ณ„ํ†ต๋„ โ€” ๋ชจ๋ธ์„ ์ฝ์–ด ํŠธ๋ฆฌ๋กœ ์ ‘๋Š”๋‹ค.
270
+ *
271
+ * ์—ฌ๋Ÿฌ ํŠธ์œˆ์ด ํ•œ ๊ณต๊ฐ„์— ์žˆ์œผ๋ฉด **๊ฐ ํŠธ์œˆ์˜ ๋ฟŒ๋ฆฌ๋ฅผ ๋‚˜๋ž€ํžˆ** ๋‘”๋‹ค(ํ•˜๋‚˜๋กœ ํ•ฉ์น˜๋ฉด ์—†๋Š” ๊ฒฐ์„ ์„ ๊ทธ๋ฆฌ๊ฒŒ ๋œ๋‹ค).
272
+ * ์—๋„ˆ์ง€ ํŠธ์œˆ์ด ์—†์œผ๋ฉด ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค โ€” ๋นˆ ๊ทธ๋ฆผ์€ ๊ณ ์žฅ์œผ๋กœ ์ฝํžŒ๋‹ค.
273
+ */
274
+ async function energyTopologyOf(domainId, instanceIds, energy) {
275
+ if (!instanceIds.length)
276
+ return undefined;
277
+ const rows = await (0, shell_1.getRepository)(twin_instance_js_1.TwinInstance).find({ where: { domain: { id: domainId }, instanceId: (0, typeorm_1.In)(instanceIds) } });
278
+ const ems = rows.filter(r => r.kind === 'ems' && r.model);
279
+ if (!ems.length)
280
+ return undefined;
281
+ const merged = { roots: [], unplaced: [], unmetered: [], loadsOnIncoming: 0 };
282
+ for (const row of ems) {
283
+ /*
284
+ * ์ง€๊ธˆ์˜ ์„ค๋น„ ์ƒํƒœ๋ฅผ ํ•จ๊ป˜ ๋„˜๊ธด๋‹ค โ€” ๋ฐœ์ „ยท์ €์žฅ์˜ **์ง€๊ธˆ ๊ฐ’**์€ ๊ตฌ๊ฐ„ ํด๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ ์Šค๋ƒ…์ƒท์ด ์•ˆ๋‹ค.
285
+ * ์—†์œผ๋ฉด(์ •์ง€๋œ ํŠธ์œˆ) ๊ตฌ์กฐ๋งŒ ๊ทธ๋ฆฐ๋‹ค.
286
+ */
287
+ const snap = twin_engine_js_1.TwinEngine.snapshot(domainId, row.instanceId);
288
+ const t = (0, energy_topology_js_1.buildEnergyTopology)(row.model, energy, snap?.equipment);
289
+ merged.roots.push(...t.roots);
290
+ merged.unplaced.push(...t.unplaced);
291
+ merged.unmetered.push(...t.unmetered);
292
+ merged.loadsOnIncoming += t.loadsOnIncoming;
293
+ }
294
+ return merged.roots.length ? merged : undefined;
295
+ }
139
296
  /** ์ด ๋Œ€์ƒ๋“ค์˜ ๋งˆ์ง€๋ง‰ ์—…๋ฌด ๊ธฐ๋ก ์‹œ๊ฐ(ISO). ๊ธฐ๋ก์ด ์—†์œผ๋ฉด null. */
140
297
  async function latestEventTime(domainId, instanceIds) {
141
298
  if (instanceIds.length === 0)
@@ -144,13 +301,14 @@ async function latestEventTime(domainId, instanceIds) {
144
301
  where: { domain: { id: domainId }, instanceId: (0, typeorm_1.In)(instanceIds), eventType: (0, typeorm_1.In)(BUSINESS_EVENTS) },
145
302
  order: { revision: 'DESC' }
146
303
  });
147
- return row?.eventTime ?? null;
304
+ /* ์†Œ๋น„์ฒ˜๋Š” ISO ๋ฌธ์ž์—ด์„ ๊ธฐ๋Œ€ํ•œ๋‹ค(์‹œ๊ฐ ์ถ•์˜ ๊ณต์šฉ ํ‘œ๊ธฐ) โ€” ์ปฌ๋Ÿผ์ด ๋‚ ์งœ๊ฐ€ ๋์œผ๋ฏ€๋กœ ์—ฌ๊ธฐ์„œ ์˜ฎ๊ธด๋‹ค. */
305
+ return row?.eventTime ? row.eventTime.toISOString() : null;
148
306
  }
149
307
  /**
150
308
  * ์ฐฝ ๊ตฌ๊ฐ„์˜ ์—…๋ฌด ์ด๋ฒคํŠธ โ€” ์ฐฝ๋ณด๋‹ค `lookbackMs` ๋งŒํผ ์•ž๊นŒ์ง€ ์ฝ๋Š”๋‹ค(์™„๋ฃŒ๋œ ์ž‘์—…์˜ ์‹œ์ž‘์ด ์ฐฝ ๋ฐ–์ผ ์ˆ˜ ์žˆ๋‹ค).
151
309
  *
152
- * eventTime ์€ ISO ๋ฌธ์ž์—ด ์ปฌ๋Ÿผ์ด๋ผ ์‚ฌ์ „์‹ ๋น„๊ต๊ฐ€ ์„ฑ๋ฆฝํ•œ๋‹ค(๊ฐ™์€ ํŒŒ์ผ๊ตฐ์˜ ์‹œ๊ฐ ์ปค์„œ์™€ ๋™์ผ ์ „์ œ).
153
- * ๋น„๊ต ๊ตฌ๊ฐ„๋„ ๊ฐ™์€ ๊ทœ์น™์œผ๋กœ ์ฝ์–ด์•ผ ํ•˜๋ฏ€๋กœ ํ•จ์ˆ˜๋กœ ๋‘”๋‹ค โ€” ๋‘ ๊ณณ์— ์ ์œผ๋ฉด ๊ทœ์น™์ด ๊ฐˆ๋ผ์ง„๋‹ค.
310
+ * eventTime ์€ ๋‚ ์งœ ์ปฌ๋Ÿผ์ด๋ผ DB ๊ฐ€ ์‹œ๊ฐ์œผ๋กœ ๋น„๊ตํ•œ๋‹ค โ€” ์˜ˆ์ „ ๋ฌธ์ž์—ด ์ปฌ๋Ÿผ ์‹œ์ ˆ์˜ "UTC ISO ๋งŒ ๋“ค์–ด์˜ค๋ฉด
311
+ * ์‚ฌ์ „์‹ ๋น„๊ต๊ฐ€ ๋งž๋Š”๋‹ค" ๋Š” ์ „์ œ๊ฐ€ ํ•„์š” ์—†๋‹ค.
154
312
  */
155
313
  async function fetchEvents(domainId, instanceIds, fromMs, toMs, lookbackMs) {
156
314
  if (instanceIds.length === 0)
@@ -160,7 +318,7 @@ async function fetchEvents(domainId, instanceIds, fromMs, toMs, lookbackMs) {
160
318
  domain: { id: domainId },
161
319
  instanceId: (0, typeorm_1.In)(instanceIds),
162
320
  eventType: (0, typeorm_1.In)(BUSINESS_EVENTS),
163
- eventTime: (0, typeorm_1.Between)(new Date(fromMs - lookbackMs).toISOString(), new Date(toMs).toISOString())
321
+ eventTime: (0, typeorm_1.Between)(new Date(fromMs - lookbackMs), new Date(toMs))
164
322
  },
165
323
  order: { revision: 'ASC' },
166
324
  take: MAX_EVENTS
@@ -168,7 +326,8 @@ async function fetchEvents(domainId, instanceIds, fromMs, toMs, lookbackMs) {
168
326
  /* ์ƒํ•œ์— ์ •ํ™•ํžˆ ๋‹ฟ์œผ๋ฉด **๋” ์žˆ์—ˆ์„ ์ˆ˜ ์žˆ๋‹ค** โ€” ๊ทธ ์‚ฌ์‹ค์„ ๋Œ๋ ค์ค€๋‹ค. ์กฐ์šฉํžˆ ์ž˜๋ผ๋‚ด๋ฉด ์ˆซ์ž๊ฐ€ ์กฐ์šฉํžˆ
169
327
  * ์ž‘์•„์ง€๊ณ , ์‚ฌ์šฉ์ž๋Š” ๊ทธ๊ฒƒ์„ ์„ฑ๊ณผ ํ•˜๋ฝ์œผ๋กœ ์ฝ๋Š”๋‹ค(๊ฐ€์žฅ ๋‚˜์œ ์ข…๋ฅ˜์˜ ๊ฑฐ์ง“์ด๋‹ค). */
170
328
  return {
171
- events: rows.map(r => ({ eventType: r.eventType, eventTime: r.eventTime, payload: r.payload })),
329
+ /* ํด๋“œ๋Š” ISO ๋ฌธ์ž์—ด ์ถ•์œผ๋กœ ์ˆ˜ํ–‰๋œ๋‹ค(kpi-fold) โ€” ๊ฒฝ๊ณ„์—์„œ ํ•œ ๋ฒˆ๋งŒ ์˜ฎ๊ธด๋‹ค. */
330
+ events: rows.map(r => ({ eventType: r.eventType, eventTime: r.eventTime?.toISOString(), payload: r.payload })),
172
331
  capped: rows.length >= MAX_EVENTS
173
332
  };
174
333
  }
@@ -187,7 +346,8 @@ async function resolveTargets(input) {
187
346
  : list.filter((x) => x?.running && x.spaceId === input.spaceId && x.purpose !== 'bench' && x.instanceId);
188
347
  /* ๋ชฉ๋ก์—์„œ ๋ชป ์ฐพ์•„๋„(์ •์ง€ยท๋น„๋“ฑ๋ก) ์ง€์ •๋œ ํŠธ์œˆ์€ ๊ทธ๋Œ€๋กœ ์กฐํšŒํ•œ๋‹ค โ€” ์ €๋„์€ ๋‚จ์•„ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. */
189
348
  const instanceIds = rows.length ? rows.map((x) => x.instanceId) : input.instanceId ? [input.instanceId] : [];
190
- const realityModes = [...new Set(rows.map((x) => String(x.realityMode ?? 'unknown')))];
349
+ /* ์ปฌ๋Ÿผ์ด NOT NULL ์ด๋ผ 'unknown' ์œผ๋กœ ๋ฉ”์šธ ์ผ์ด ์—†๋‹ค โ€” ๋น„๋ฉด ๊ณ„์•ฝ์ด ๊นจ์ง„ ๊ฒƒ์ด์ง€ ๋ชจ๋ฅด๋Š” ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๋‹ค. */
350
+ const realityModes = [...new Set(rows.map((x) => String(x.realityMode)))];
191
351
  return { instanceIds, realityModes };
192
352
  }
193
353
  /**
@@ -242,9 +402,19 @@ async function computeTwinKpi(input) {
242
402
  /* ๊ตฌ์—ญยท๊ต๋Œ€ ์ถ•์€ **์ด๋ฒคํŠธ ๋ฐ–์˜ ์ง€์‹**์„ ํ•„์š”๋กœ ํ•œ๋‹ค โ€” ๋‹ค๋ฅธ ์ถ•์€ payload ์—์„œ ๋ฐ”๋กœ ๋‚˜์˜จ๋‹ค. */
243
403
  const areaMap = input.groupBy === 'area' ? await locationAreaMap(input.domainId, instanceIds, input.spaceId) : { locationArea: {}, labels: {} };
244
404
  const shiftCtx = input.groupBy === 'shift' ? await shiftContext(input.domainId, instanceIds) : {};
405
+ /*
406
+ * ์ „๊ธฐ ๊ณ„ํ†ต ์†Œ์†์€ **์ถ•๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ** ์ฝ๋Š”๋‹ค โ€” ๋ถ„๊ธฐ๋ณ„ ๋ชซ์€ ๊ด€์  ์ถ•์ด ์•„๋‹ˆ๋ผ ์—๋„ˆ์ง€ ์‚ฌ์‹ค์˜ ์ผ๋ถ€๋ผ
407
+ * (๊ฐ™์€ ์ฐฝ์˜ ์ด๋Ÿ‰์„ ๋‚˜๋ˆˆ ๊ฒƒ) ์–ด๋А ์ถ•์„ ๋ณด๊ณ  ์žˆ๋“  ํ•จ๊ป˜ ๋‚˜๊ฐ€์•ผ ํ•œ๋‹ค.
408
+ */
409
+ const feederMap = await resourceFeederMap(input.domainId, instanceIds);
410
+ /* ์š”๊ธˆ ๋‹จ๊ฐ€๋„ ์ถ•๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ์ฝ๋Š”๋‹ค โ€” ๊ธˆ์•ก์€ ๊ฐ™์€ ์ฐฝ์˜ ์ „๋ ฅ๋Ÿ‰ยท์ตœ๋Œ€์ˆ˜์š”์—์„œ ๋‚˜์˜ค๋Š” ์‚ฌ์‹ค์ด๋‹ค. */
411
+ const tariffFound = await tariffOf(input.domainId, instanceIds);
245
412
  const kpi = (0, kpi_fold_js_1.foldKpi)(events, { fromMs, toMs }, {
246
413
  groupBy: input.groupBy,
247
414
  locationArea: areaMap.locationArea,
415
+ resourceFeeder: feederMap.resourceFeeder,
416
+ meterFeeder: feederMap.meterFeeder,
417
+ ...(tariffFound.tariff ? { tariff: tariffFound.tariff } : {}),
248
418
  ...shiftCtx,
249
419
  groupLimit: input.groupLimit
250
420
  });
@@ -261,12 +431,47 @@ async function computeTwinKpi(input) {
261
431
  minutes: Math.round((toMs - fromMs) / 60_000),
262
432
  basis
263
433
  };
434
+ /**
435
+ * ์—ฌ๋Ÿฌ ๊ตฌ๊ฐ„ ๋ถ„ํฌ๋ฅผ ๋งŒ๋“ ๋‹ค โ€” **ํ˜„์žฌ ์ฐฝ์— ๊ธฐ๋ก์ด ์—†์–ด๋„ ๋‚ธ๋‹ค.**
436
+ *
437
+ * ๊ทธ๋•Œ๊ฐ€ ์˜คํžˆ๋ ค ๊ฐ€์žฅ ์•Œ๊ณ  ์‹ถ์€ ์ˆœ๊ฐ„์ด๋‹ค("์ง€๊ธˆ ์•„๋ฌด ๊ธฐ๋ก์ด ์—†๋Š”๋ฐ ํ‰์†Œ์—” 60๊ฑด์ด์—ˆ๋‹ค" = ๋ฉˆ์ถ˜ ์‹ ํ˜ธ).
438
+ * ๊ทธ๋ž˜์„œ ์กฐ๊ธฐ ๋ฐ˜ํ™˜๋ณด๋‹ค ์•ž์— ๋‘๊ณ  ๋‘ ๊ฒฝ๋กœ๊ฐ€ ํ•จ๊ป˜ ์“ด๋‹ค.
439
+ */
440
+ const computeBaseline = async () => {
441
+ if (!input.baseline || !(input.baseline.periods > 0))
442
+ return undefined;
443
+ const stride = input.baseline.stride ?? 'day';
444
+ const windows = (0, kpi_baseline_js_1.baselineWindows)(fromMs, toMs, input.baseline.periods, stride);
445
+ let baseCapped = false;
446
+ const samples = [];
447
+ for (const w of windows) {
448
+ const { events: pastEvents, capped: pastCapped } = await fetchEvents(input.domainId, instanceIds, w.fromMs, w.toMs, lookbackMs);
449
+ baseCapped = baseCapped || pastCapped;
450
+ /* ์ถ• ์—†์ด, **๊ฐ™์€ ๊ต๋Œ€ ์ •์˜**๋กœ ์ ‘๋Š”๋‹ค(์ •์˜๊ฐ€ ๋‹ค๋ฅด๋ฉด ๊ฐ™์€ ์‹œ๊ฐ„๋Œ€๊ฐ€ ์•„๋‹ˆ๊ฒŒ ๋œ๋‹ค). */
451
+ const past = (0, kpi_fold_js_1.foldKpi)(pastEvents, w, { locationArea: areaMap.locationArea, ...shiftCtx });
452
+ const values = {};
453
+ for (const metric of Object.keys(kpi_target_js_1.TWIN_METRIC))
454
+ values[metric] = kpi_target_js_1.TWIN_METRIC[metric].of(past);
455
+ samples.push({ fromMs: w.fromMs, toMs: w.toMs, values });
456
+ }
457
+ const current = {};
458
+ for (const metric of Object.keys(kpi_target_js_1.TWIN_METRIC))
459
+ current[metric] = kpi_target_js_1.TWIN_METRIC[metric].of(kpi);
460
+ return {
461
+ stride,
462
+ periods: windows.length,
463
+ metrics: (0, kpi_baseline_js_1.summarizeBaseline)(kpi_target_js_1.TWIN_METRIC, current, samples),
464
+ ...(baseCapped ? { capped: true } : {})
465
+ };
466
+ };
264
467
  if (kpi.eventsInWindow === 0) {
468
+ const baseline = await computeBaseline();
265
469
  return {
266
470
  window,
267
471
  measured: false,
268
472
  scope,
269
- note: 'no operational events in this window โ€” nothing to measure (this is NOT "zero throughput").'
473
+ note: 'no operational events in this window โ€” nothing to measure (this is NOT "zero throughput").',
474
+ ...(baseline ? { baseline } : {})
270
475
  };
271
476
  }
272
477
  /* ๊ตฌ๊ฐ„๋ณ„ ๊ฐ’ โ€” ์ชผ๊ฐœ๊ธฐ ๊ทœ์น™์€ ์ˆœ์ˆ˜ ๋ชจ๋“ˆ์ด ์†Œ์œ ํ•œ๋‹ค(ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ). ์—ฌ๊ธฐ์„œ๋Š” ์‹œ๊ฐ์„ ISO ๋กœ ์˜ฎ๊ธฐ๊ธฐ๋งŒ. */
@@ -326,6 +531,15 @@ async function computeTwinKpi(input) {
326
531
  }
327
532
  };
328
533
  }
534
+ /*
535
+ * ์—ฌ๋Ÿฌ ๊ตฌ๊ฐ„ ๋™์‹œ ๋น„๊ต โ€” **๊ฐ™์€ ์‹œ๊ฐ„๋Œ€๋ฅผ ๋ฉฐ์น  ๋’ค๋กœ** ์˜ฎ๊ฒจ ๋ถ„ํฌ๋ฅผ ๋งŒ๋“ ๋‹ค(์„ฑ๊ณผ ๋งต โ‘ข).
536
+ *
537
+ * ์ฐฝ๋งˆ๋‹ค ์กฐํšŒ๊ฐ€ ํ•œ ๋ฒˆ ๋” ๋ถ™์ง€๋งŒ ๊ฐ ์ฐฝ์€ ํ˜„์žฌ ์ฐฝ๊ณผ ๊ฐ™์€ ๊ธธ์ด๋ผ(๋ณดํ†ต 1~24h) ๊ฐ’์‹ธ๋‹ค. ์ถ•(groupBy)์€
538
+ * ๋„˜๊ธฐ์ง€ ์•Š๋Š”๋‹ค โ€” ๋ถ„ํฌ๋Š” **์ „์ฒด ์ง€ํ‘œ**์˜ ์งˆ๋ฌธ์ด๊ณ , ์ถ•๋ณ„ ๋ถ„ํฌ๊นŒ์ง€ ๋‚ด๋ฉด ์‘๋‹ต์ด ์ถ• ์ˆ˜๋งŒํผ ๋ถ€ํ‘ผ๋‹ค
539
+ * (ํ•„์š”ํ•ด์ง€๋ฉด ๊ทธ๋•Œ ์ถ•์„ ์ง€์ •ํ•ด ๋‹ค์‹œ ๋ฌป๋Š” ๊ฒƒ์ด ์ •์งํ•˜๋‹ค).
540
+ *
541
+ * ์ง€ํ‘œ ์–ดํœ˜๋Š” `TWIN_METRIC` ์ด ๊ณ„์† ์†Œ์œ ํ•˜๊ณ , ์—ฌ๊ธฐ์„œ๋Š” **๊ฐ’๋งŒ ๊บผ๋‚ด** ๋ถ„ํฌ ๋ชจ๋“ˆ์— ๋„˜๊ธด๋‹ค.
542
+ */
329
543
  /* ๊ด€์  ๊ฐ’์€ ์‹œ๊ฐ ๋ณ€ํ™˜์ด ์—†์–ด ๊ทธ๋Œ€๋กœ ํ†ต๊ณผํ•œ๋‹ค. ๋ถ™์ด๋Š” ๊ฒƒ์€ โ‘  ์‚ฌ๋žŒ์ด ์ฝ๋Š” ์ด๋ฆ„๊ณผ โ‘ก ์ถ•์ด ํ†ต์งธ๋กœ
330
544
  * ๋น„์—ˆ์„ ๋•Œ์˜ ์ด์œ ๋‹ค โ€” "๊ตฌ์—ญ๋ณ„ 0๊ฑด" ๊ณผ "๋…ธ๋“œ์— ๊ตฌ์—ญ์ด ์•ˆ ๋ถ™์–ด ์žˆ๋‹ค" ๋Š” ์™„์ „ํžˆ ๋‹ค๋ฅธ ์ƒํ™ฉ์ด๋‹ค. */
331
545
  const groups = kpi.groups
@@ -369,8 +583,35 @@ async function computeTwinKpi(input) {
369
583
  * **๋ชฉํ‘œ๊ฐ€ ์—†์œผ๋ฉด ํŒ์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค** โ€” ํ•„๋“œ ์ž์ฒด๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค. ์ „๋ถ€ "๋ชฉํ‘œ ์—†์Œ" ์œผ๋กœ ์ฑ„์šฐ๋ฉด
370
584
  * ํ™”๋ฉด์ด ํšŒ์ƒ‰ ๋…ธ์ด์ฆˆ๊ฐ€ ๋˜๊ณ , ๋ชฉํ‘œ๊ฐ€ ์žˆ๋Š” ์ง€ํ‘œ๊ฐ€ ๋ฌปํžŒ๋‹ค.
371
585
  */
586
+ /* ๋ถ„ํฌ๋Š” **ํ•œ ๋ฒˆ๋งŒ** ๊ณ„์‚ฐํ•œ๋‹ค โ€” ์ฐฝ๋งˆ๋‹ค ์กฐํšŒ๊ฐ€ ๋ถ™์œผ๋ฏ€๋กœ ๋‘ ๋ฒˆ ๋ถ€๋ฅด๋ฉด ์กฐํšŒ๊ฐ€ ๋‘ ๋ฐฐ๊ฐ€ ๋œ๋‹ค. */
587
+ const baseline = await computeBaseline();
372
588
  /* ํด๋“œ๊ฐ€ ๋Œ๋ ค์ค€ raw ์ฐฝ(ms)์€ ๋ฒ„๋ฆฐ๋‹ค โ€” ์œ„์˜ ISO ์ฐฝ์ด ์‚ฌ๋žŒ์ด ์ฝ์„ ์ •๋ณธ์ด๋‹ค. */
373
589
  const { window: _rawWindow, groups: _rawGroups, ...rest } = kpi;
590
+ /*
591
+ * ์ž๋ฆฌ์— **๋ถ€๋ฅด๋Š” ์ด๋ฆ„**์„ ๋ถ™์ธ๋‹ค โ€” `feeder-2` ๋Š” id ์ด๊ณ  ์‚ฌ๋žŒ์€ ใ€Œ๊ฐ€๊ณต ๋ผ์ธใ€์œผ๋กœ ๋ถ€๋ฅธ๋‹ค.
592
+ * ์ด๋ฆ„์„ ๋ชจ๋ฅด๋Š” ์ž๋ฆฌ๋Š” id ๊ทธ๋Œ€๋กœ ๋‘”๋‹ค(์ง€์–ด๋‚ด์ง€ ์•Š๋Š”๋‹ค).
593
+ */
594
+ /* ๋‹จ๊ฐ€๊ฐ€ ๊ฐˆ๋ ค ์žˆ์œผ๋ฉด ๋ฐํžŒ๋‹ค โ€” ์šฐ๋ฆฌ๊ฐ€ ๊ณ ๋ฅธ ํ•˜๋‚˜๋กœ ๋‚ธ ๊ธˆ์•ก์ด๋ผ๋Š” ์‚ฌ์‹ค์„ ํ™”๋ฉด์ด ๋งํ•  ์ˆ˜ ์žˆ๊ฒŒ. */
595
+ if (rest.energy?.cost && tariffFound.conflict)
596
+ rest.energy = { ...rest.energy, tariffConflict: true };
597
+ if (rest.energy?.byFeeder?.length) {
598
+ rest.energy = {
599
+ ...rest.energy,
600
+ byFeeder: rest.energy.byFeeder.map(row => ({ ...row, ...(feederMap.labels[row.key] ? { label: feederMap.labels[row.key] } : {}) }))
601
+ };
602
+ }
603
+ /*
604
+ * ๊ณ„ํ†ต๋„ โ€” **์„ ์–ธ๋œ ๊ด€๊ณ„์™€ ๊ณ„๋Ÿ‰์ด ๋ฎ๋Š” ๋ฒ”์œ„**๋ฅผ ํ•จ๊ป˜ ๋‚ธ๋‹ค.
605
+ *
606
+ * ๊ฐ’์€ ์—ฌ๊ธฐ์„œ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜์ง€ ์•Š๋Š”๋‹ค(ํด๋“œ๊ฐ€ ๋‚ธ ๋ถ„๊ธฐ๋ณ„ ๋ชซ์„ ๊ทธ๋Œ€๋กœ ๋…ธ๋“œ์— ์–น๋Š”๋‹ค). ๊ณ„ํ†ต์€ ๋ชจ๋ธ์ด ์•„๋Š”
607
+ * ์‚ฌ์‹ค์ด๋ฏ€๋กœ ์ €๋„๋งŒ ๋ณด๋Š” ํด๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ ์—ฌ๊ธฐ์„œ ์กฐ๋ฆฝํ•œ๋‹ค โ€” ํ™”๋ฉด์ด ๋ชจ๋ธ์„ ๋”ฐ๋กœ ๋˜ ์กฐํšŒํ•˜์ง€ ์•Š์•„๋„ ๋˜๊ณ ,
608
+ * AI ๋„ ๊ฐ™์€ ๊ฐ’์„ ์ฝ๋Š”๋‹ค(๊ทœ์น™ ํ•œ ๋ฒŒ).
609
+ */
610
+ if (rest.energy) {
611
+ const topo = await energyTopologyOf(input.domainId, instanceIds, rest.energy);
612
+ if (topo)
613
+ rest.energy = { ...rest.energy, topology: topo };
614
+ }
374
615
  return {
375
616
  window,
376
617
  measured: true,
@@ -380,7 +621,8 @@ async function computeTwinKpi(input) {
380
621
  ...(buckets ? { buckets } : {}),
381
622
  ...(groups ? { groups } : {}),
382
623
  ...(verdicts.length ? { targets: verdicts } : {}),
383
- ...(comparison ? { comparison } : {})
624
+ ...(comparison ? { comparison } : {}),
625
+ ...(baseline ? { baseline } : {})
384
626
  };
385
627
  }
386
628
  //# sourceMappingURL=kpi-query.js.map