@things-factory/headless-twin 10.0.12 โ†’ 10.0.13

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 (312) hide show
  1. package/dist-server/engine/canonical-ingest.d.ts +57 -2
  2. package/dist-server/engine/canonical-ingest.js +43 -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/index.d.ts +3 -0
  7. package/dist-server/engine/index.js +4 -0
  8. package/dist-server/engine/index.js.map +1 -1
  9. package/dist-server/engine/ingest-health.d.ts +335 -0
  10. package/dist-server/engine/ingest-health.js +434 -0
  11. package/dist-server/engine/ingest-health.js.map +1 -0
  12. package/dist-server/engine/integration-coverage.d.ts +76 -0
  13. package/dist-server/engine/integration-coverage.js +73 -0
  14. package/dist-server/engine/integration-coverage.js.map +1 -0
  15. package/dist-server/engine/integration-probes.d.ts +65 -0
  16. package/dist-server/engine/integration-probes.js +100 -0
  17. package/dist-server/engine/integration-probes.js.map +1 -0
  18. package/dist-server/engine/integration-runner.d.ts +45 -0
  19. package/dist-server/engine/integration-runner.js +59 -0
  20. package/dist-server/engine/integration-runner.js.map +1 -0
  21. package/dist-server/engine/integration-target-profile.d.ts +57 -0
  22. package/dist-server/engine/integration-target-profile.js +79 -0
  23. package/dist-server/engine/integration-target-profile.js.map +1 -0
  24. package/dist-server/engine/kpi-fold.d.ts +27 -0
  25. package/dist-server/engine/kpi-fold.js +47 -4
  26. package/dist-server/engine/kpi-fold.js.map +1 -1
  27. package/dist-server/engine/kpi-query.js +128 -14
  28. package/dist-server/engine/kpi-query.js.map +1 -1
  29. package/dist-server/engine/live-feed-registry.js +2 -16
  30. package/dist-server/engine/live-feed-registry.js.map +1 -1
  31. package/dist-server/engine/load-meter.d.ts +1 -1
  32. package/dist-server/engine/load-meter.js +12 -3
  33. package/dist-server/engine/load-meter.js.map +1 -1
  34. package/dist-server/engine/log.d.ts +18 -0
  35. package/dist-server/engine/log.js +80 -0
  36. package/dist-server/engine/log.js.map +1 -0
  37. package/dist-server/engine/loop-lag.d.ts +54 -0
  38. package/dist-server/engine/loop-lag.js +87 -0
  39. package/dist-server/engine/loop-lag.js.map +1 -0
  40. package/dist-server/engine/model-gap.d.ts +108 -0
  41. package/dist-server/engine/model-gap.js +95 -0
  42. package/dist-server/engine/model-gap.js.map +1 -0
  43. package/dist-server/engine/restart-policy.d.ts +3 -3
  44. package/dist-server/engine/restart-policy.js +4 -4
  45. package/dist-server/engine/restart-policy.js.map +1 -1
  46. package/dist-server/engine/runtime-key.js +1 -1
  47. package/dist-server/engine/runtime-key.js.map +1 -1
  48. package/dist-server/engine/stage-path.d.ts +83 -0
  49. package/dist-server/engine/stage-path.js +118 -0
  50. package/dist-server/engine/stage-path.js.map +1 -0
  51. package/dist-server/engine/twin-engine.d.ts +352 -16
  52. package/dist-server/engine/twin-engine.js +1037 -166
  53. package/dist-server/engine/twin-engine.js.map +1 -1
  54. package/dist-server/index.js +34 -2
  55. package/dist-server/index.js.map +1 -1
  56. package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.d.ts +5 -0
  57. package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js +58 -0
  58. package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js.map +1 -0
  59. package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.d.ts +5 -0
  60. package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js +55 -0
  61. package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js.map +1 -0
  62. package/dist-server/migrations/index.js +7 -1
  63. package/dist-server/migrations/index.js.map +1 -1
  64. package/dist-server/service/index.d.ts +5 -2
  65. package/dist-server/service/index.js +18 -7
  66. package/dist-server/service/index.js.map +1 -1
  67. package/dist-server/service/reference/discovery-result.d.ts +1 -1
  68. package/dist-server/service/reference/discovery-result.js +1 -1
  69. package/dist-server/service/reference/discovery-result.js.map +1 -1
  70. package/dist-server/service/reference/index.d.ts +4 -1
  71. package/dist-server/service/reference/index.js +6 -1
  72. package/dist-server/service/reference/index.js.map +1 -1
  73. package/dist-server/service/reference/reference-adapter.d.ts +184 -3
  74. package/dist-server/service/reference/reference-adapter.js +28 -4
  75. package/dist-server/service/reference/reference-adapter.js.map +1 -1
  76. package/dist-server/service/reference/reference-assessment.d.ts +68 -0
  77. package/dist-server/service/reference/reference-assessment.js +136 -0
  78. package/dist-server/service/reference/reference-assessment.js.map +1 -0
  79. package/dist-server/service/reference/reference-live.d.ts +12 -1
  80. package/dist-server/service/reference/reference-live.js +116 -11
  81. package/dist-server/service/reference/reference-live.js.map +1 -1
  82. package/dist-server/service/reference/reference-master.d.ts +47 -1
  83. package/dist-server/service/reference/reference-master.js +34 -4
  84. package/dist-server/service/reference/reference-master.js.map +1 -1
  85. package/dist-server/service/reference/reference-probe.d.ts +92 -0
  86. package/dist-server/service/reference/reference-probe.js +186 -0
  87. package/dist-server/service/reference/reference-probe.js.map +1 -0
  88. package/dist-server/service/reference/reference-progress-subscription.d.ts +17 -0
  89. package/dist-server/service/reference/reference-progress-subscription.js +94 -0
  90. package/dist-server/service/reference/reference-progress-subscription.js.map +1 -0
  91. package/dist-server/service/reference/reference-progress.d.ts +38 -0
  92. package/dist-server/service/reference/reference-progress.js +71 -0
  93. package/dist-server/service/reference/reference-progress.js.map +1 -0
  94. package/dist-server/service/reference/reference-resolver.js +210 -43
  95. package/dist-server/service/reference/reference-resolver.js.map +1 -1
  96. package/dist-server/service/reference/twin-reference.d.ts +32 -0
  97. package/dist-server/service/reference/twin-reference.js +10 -0
  98. package/dist-server/service/reference/twin-reference.js.map +1 -1
  99. package/dist-server/service/twin-control/twin-control-mutation.js +4 -3
  100. package/dist-server/service/twin-control/twin-control-mutation.js.map +1 -1
  101. package/dist-server/service/twin-event/journal-count.d.ts +21 -0
  102. package/dist-server/service/twin-event/journal-count.js +26 -0
  103. package/dist-server/service/twin-event/journal-count.js.map +1 -0
  104. package/dist-server/service/twin-event/twin-event-keys.d.ts +9 -0
  105. package/dist-server/service/twin-event/twin-event-keys.js +15 -18
  106. package/dist-server/service/twin-event/twin-event-keys.js.map +1 -1
  107. package/dist-server/service/twin-event/twin-event-type.d.ts +3 -1
  108. package/dist-server/service/twin-event/twin-event-type.js +18 -1
  109. package/dist-server/service/twin-event/twin-event-type.js.map +1 -1
  110. package/dist-server/service/twin-event/twin-event.d.ts +1 -0
  111. package/dist-server/service/twin-event/twin-event.js +9 -1
  112. package/dist-server/service/twin-event/twin-event.js.map +1 -1
  113. package/dist-server/service/twin-forecast/twin-forecast-query.js +2 -1
  114. package/dist-server/service/twin-forecast/twin-forecast-query.js.map +1 -1
  115. package/dist-server/service/twin-ingest-window/index.d.ts +5 -0
  116. package/dist-server/service/twin-ingest-window/index.js +10 -0
  117. package/dist-server/service/twin-ingest-window/index.js.map +1 -0
  118. package/dist-server/service/twin-ingest-window/twin-ingest-window-query.d.ts +12 -0
  119. package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js +123 -0
  120. package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js.map +1 -0
  121. package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.d.ts +1 -0
  122. package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js +51 -0
  123. package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js.map +1 -0
  124. package/dist-server/service/twin-ingest-window/twin-ingest-window.d.ts +16 -0
  125. package/dist-server/service/twin-ingest-window/twin-ingest-window.js +108 -0
  126. package/dist-server/service/twin-ingest-window/twin-ingest-window.js.map +1 -0
  127. package/dist-server/service/twin-instance/twin-instance.js.map +1 -1
  128. package/dist-server/service/twin-journal/twin-journal-query.js +58 -5
  129. package/dist-server/service/twin-journal/twin-journal-query.js.map +1 -1
  130. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.d.ts +14 -0
  131. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js +72 -2
  132. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +1 -1
  133. package/dist-server/service/twin-metrics/twin-metrics-query.d.ts +1 -0
  134. package/dist-server/service/twin-metrics/twin-metrics-query.js +78 -3
  135. package/dist-server/service/twin-metrics/twin-metrics-query.js.map +1 -1
  136. package/dist-server/service/twin-model/axis-journal-evidence.d.ts +2 -0
  137. package/dist-server/service/twin-model/axis-journal-evidence.js +89 -0
  138. package/dist-server/service/twin-model/axis-journal-evidence.js.map +1 -0
  139. package/dist-server/service/twin-model/epcis-coverage.d.ts +1 -1
  140. package/dist-server/service/twin-model/epcis-coverage.js +19 -7
  141. package/dist-server/service/twin-model/epcis-coverage.js.map +1 -1
  142. package/dist-server/service/twin-model/iec61850-coverage.d.ts +1 -1
  143. package/dist-server/service/twin-model/iec61850-coverage.js +18 -7
  144. package/dist-server/service/twin-model/iec61850-coverage.js.map +1 -1
  145. package/dist-server/service/twin-model/isa95-coverage.d.ts +14 -0
  146. package/dist-server/service/twin-model/isa95-coverage.js +23 -9
  147. package/dist-server/service/twin-model/isa95-coverage.js.map +1 -1
  148. package/dist-server/service/twin-model/item-ref.d.ts +24 -0
  149. package/dist-server/service/twin-model/item-ref.js +88 -0
  150. package/dist-server/service/twin-model/item-ref.js.map +1 -0
  151. package/dist-server/service/twin-model/name-index.d.ts +36 -0
  152. package/dist-server/service/twin-model/name-index.js +116 -0
  153. package/dist-server/service/twin-model/name-index.js.map +1 -0
  154. package/dist-server/service/twin-model/project-structure.js +1 -1
  155. package/dist-server/service/twin-model/project-structure.js.map +1 -1
  156. package/dist-server/service/twin-model/status-tally.d.ts +9 -0
  157. package/dist-server/service/twin-model/status-tally.js +37 -0
  158. package/dist-server/service/twin-model/status-tally.js.map +1 -0
  159. package/dist-server/service/twin-model/twin-lineage-query.js +40 -12
  160. package/dist-server/service/twin-model/twin-lineage-query.js.map +1 -1
  161. package/dist-server/service/twin-model/twin-model-item-query.js +38 -39
  162. package/dist-server/service/twin-model/twin-model-item-query.js.map +1 -1
  163. package/dist-server/service/twin-model/twin-model-query.js +156 -4
  164. package/dist-server/service/twin-model/twin-model-query.js.map +1 -1
  165. package/dist-server/service/twin-model/twin-model-tree-query.js +7 -0
  166. package/dist-server/service/twin-model/twin-model-tree-query.js.map +1 -1
  167. package/dist-server/service/twin-readiness/index.d.ts +2 -0
  168. package/dist-server/service/twin-readiness/index.js +6 -0
  169. package/dist-server/service/twin-readiness/index.js.map +1 -0
  170. package/dist-server/service/twin-readiness/twin-readiness-query.d.ts +3 -0
  171. package/dist-server/service/twin-readiness/twin-readiness-query.js +103 -0
  172. package/dist-server/service/twin-readiness/twin-readiness-query.js.map +1 -0
  173. package/dist-server/service/twin-space/twin-space-resolver.d.ts +2 -2
  174. package/dist-server/service/twin-space/twin-space-resolver.js +5 -4
  175. package/dist-server/service/twin-space/twin-space-resolver.js.map +1 -1
  176. package/dist-shared/entity-delta.d.ts +23 -3
  177. package/dist-shared/entity-delta.js +12 -8
  178. package/dist-shared/entity-delta.js.map +1 -1
  179. package/dist-shared/kpi-broadcast.js +1 -1
  180. package/dist-shared/kpi-broadcast.js.map +1 -1
  181. package/dist-shared/touched-items.d.ts +7 -0
  182. package/dist-shared/touched-items.js +80 -0
  183. package/dist-shared/touched-items.js.map +1 -0
  184. package/package.json +7 -7
  185. package/server/engine/canonical-ingest.ts +92 -7
  186. package/server/engine/command-routing.ts +1 -1
  187. package/server/engine/index.ts +4 -0
  188. package/server/engine/ingest-health.ts +704 -0
  189. package/server/engine/integration-coverage.ts +147 -0
  190. package/server/engine/integration-probes.ts +144 -0
  191. package/server/engine/integration-runner.ts +95 -0
  192. package/server/engine/integration-target-profile.ts +103 -0
  193. package/server/engine/kpi-fold.ts +72 -4
  194. package/server/engine/kpi-query.ts +129 -15
  195. package/server/engine/live-feed-registry.ts +2 -1
  196. package/server/engine/load-meter.ts +12 -3
  197. package/server/engine/log.ts +72 -0
  198. package/server/engine/loop-lag.ts +120 -0
  199. package/server/engine/model-gap.ts +168 -0
  200. package/server/engine/restart-policy.ts +4 -4
  201. package/server/engine/runtime-key.ts +1 -1
  202. package/server/engine/stage-path.ts +172 -0
  203. package/server/engine/twin-engine.ts +1135 -162
  204. package/server/index.ts +35 -2
  205. package/server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.ts +54 -0
  206. package/server/migrations/1786200000000-CarryLiveFeedCursor.ts +53 -0
  207. package/server/migrations/index.ts +7 -1
  208. package/server/service/index.ts +11 -0
  209. package/server/service/reference/discovery-result.ts +1 -1
  210. package/server/service/reference/index.ts +6 -1
  211. package/server/service/reference/reference-adapter.ts +197 -5
  212. package/server/service/reference/reference-assessment.ts +215 -0
  213. package/server/service/reference/reference-live.ts +123 -11
  214. package/server/service/reference/reference-master.ts +64 -4
  215. package/server/service/reference/reference-probe.ts +264 -0
  216. package/server/service/reference/reference-progress-subscription.ts +73 -0
  217. package/server/service/reference/reference-progress.ts +95 -0
  218. package/server/service/reference/reference-resolver.ts +200 -12
  219. package/server/service/reference/twin-reference.ts +39 -1
  220. package/server/service/twin-control/twin-control-mutation.ts +4 -3
  221. package/server/service/twin-event/journal-count.ts +53 -0
  222. package/server/service/twin-event/twin-event-keys.ts +16 -1
  223. package/server/service/twin-event/twin-event-type.ts +26 -2
  224. package/server/service/twin-event/twin-event.ts +7 -0
  225. package/server/service/twin-forecast/twin-forecast-query.ts +2 -1
  226. package/server/service/twin-ingest-window/index.ts +7 -0
  227. package/server/service/twin-ingest-window/twin-ingest-window-query.ts +125 -0
  228. package/server/service/twin-ingest-window/twin-ingest-window-writer.ts +57 -0
  229. package/server/service/twin-ingest-window/twin-ingest-window.ts +113 -0
  230. package/server/service/twin-instance/twin-instance.ts +1 -1
  231. package/server/service/twin-journal/twin-journal-query.ts +59 -5
  232. package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +77 -3
  233. package/server/service/twin-metrics/twin-metrics-query.ts +81 -3
  234. package/server/service/twin-model/axis-journal-evidence.ts +57 -0
  235. package/server/service/twin-model/epcis-coverage.ts +2 -8
  236. package/server/service/twin-model/iec61850-coverage.ts +2 -8
  237. package/server/service/twin-model/isa95-coverage.ts +22 -9
  238. package/server/service/twin-model/item-ref.ts +80 -0
  239. package/server/service/twin-model/name-index.ts +94 -0
  240. package/server/service/twin-model/project-structure.ts +1 -1
  241. package/server/service/twin-model/status-tally.ts +37 -0
  242. package/server/service/twin-model/twin-lineage-query.ts +38 -9
  243. package/server/service/twin-model/twin-model-item-query.ts +26 -27
  244. package/server/service/twin-model/twin-model-query.ts +155 -4
  245. package/server/service/twin-model/twin-model-tree-query.ts +7 -0
  246. package/server/service/twin-readiness/index.ts +3 -0
  247. package/server/service/twin-readiness/twin-readiness-query.ts +96 -0
  248. package/server/service/twin-space/twin-space-resolver.ts +5 -4
  249. package/shared/entity-delta.ts +31 -7
  250. package/shared/kpi-broadcast.ts +1 -1
  251. package/shared/touched-items.ts +73 -0
  252. package/test/axis-journal-evidence.test.ts +71 -0
  253. package/test/axis-read.test.ts +101 -1
  254. package/test/boot-resume.test.ts +92 -26
  255. package/test/broadcast-cost-baseline.test.ts +200 -0
  256. package/test/broadcast-period.test.ts +58 -0
  257. package/test/canonical-ingest-vocabularies.test.ts +36 -1
  258. package/test/canonical-quantity-door.test.ts +61 -0
  259. package/test/command-routing.test.ts +1 -1
  260. package/test/declared-location-types.test.ts +89 -0
  261. package/test/discovery-result.test.ts +1 -1
  262. package/test/duration-estimators.test.ts +1 -1
  263. package/test/entity-delta.test.ts +2 -2
  264. package/test/ingest-bench.test.ts +3 -3
  265. package/test/ingest-health-engine.test.ts +248 -0
  266. package/test/ingest-health-wiring.test.ts +119 -0
  267. package/test/ingest-health.test.ts +306 -0
  268. package/test/ingest-history.test.ts +247 -0
  269. package/test/integration-probes.test.ts +103 -0
  270. package/test/integration-runner.test.ts +95 -0
  271. package/test/item-ref.test.ts +78 -0
  272. package/test/journal-read-discipline.test.ts +177 -0
  273. package/test/journal-retention.test.ts +133 -0
  274. package/test/journal-sort-axis.test.ts +142 -0
  275. package/test/journal-write-door.test.ts +110 -0
  276. package/test/journal-write-trend.test.ts +115 -0
  277. package/test/kernel-kind-guard.test.ts +4 -4
  278. package/test/kpi-fold.test.ts +90 -3
  279. package/test/kpi-query-bench.test.ts +2 -2
  280. package/test/lineage-survives-restart.test.ts +17 -1
  281. package/test/live-cursor-wiring.test.ts +87 -0
  282. package/test/live-feed-registry.test.ts +9 -1
  283. package/test/live-kernel-facts.test.ts +7 -7
  284. package/test/live-mirror-parity.test.ts +6 -0
  285. package/test/load-meter.test.ts +29 -15
  286. package/test/local-declarations.test.ts +1 -1
  287. package/test/log-stamp.test.ts +59 -0
  288. package/test/loop-lag.test.ts +82 -0
  289. package/test/model-gap.test.ts +153 -0
  290. package/test/oee-accumulator.test.ts +4 -0
  291. package/test/operational-vocabulary.test.ts +4 -4
  292. package/test/read-failure-visible.test.ts +145 -0
  293. package/test/reference-grounding.test.ts +70 -0
  294. package/test/resolve-ts-siblings.mjs +52 -0
  295. package/test/restart-policy.test.ts +7 -7
  296. package/test/revision-axis.test.ts +93 -0
  297. package/test/runtime-key.test.ts +2 -2
  298. package/test/scale-twin-bench.test.ts +2 -2
  299. package/test/spec-coverage.test.ts +1 -1
  300. package/test/stage-path.test.ts +95 -0
  301. package/test/standard-coverage.test.ts +15 -3
  302. package/test/status-tally.test.ts +55 -0
  303. package/test/structure-revision-db.test.ts +4 -0
  304. package/test/tenant-registry-db.test.ts +1 -1
  305. package/test/time-range.test.ts +152 -0
  306. package/test/touched-items.test.ts +61 -0
  307. package/test/twin-event-keys.test.ts +10 -2
  308. package/test/twin-model-item-db.test.ts +2 -0
  309. package/test/warm-start-seam.test.ts +4 -0
  310. package/test/yield-loop.test.ts +57 -2
  311. package/tsconfig.shared.tsbuildinfo +1 -1
  312. package/tsconfig.tsbuildinfo +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"twin-engine.js","sourceRoot":"","sources":["../../server/engine/twin-engine.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * TwinEngine โ€” operato-twin ์ปค๋„ ์ธ์Šคํ„ด์Šค๋ฅผ things-factory ์œ„์—์„œ ํ˜ธ์ŠคํŒ….\n * integration-base ์˜ ScenarioEngine ํŒจํ„ด ๋ฏธ๋Ÿฌ: ๋ฉ”๋ชจ๋ฆฌ ์ธ์Šคํ„ด์Šค ๋งต + ๋ฐฑ๊ทธ๋ผ์šด๋“œ tick + pubsub ์ƒํƒœ ๋ฐœํ–‰.\n *\n * ์ปค๋„(zero-dep, ESM+CJS ์ด์ค‘๋ฐฐํฌ)์€ CJS require ๋กœ ๋กœ๋“œ(Node 20 CommonJS ์†Œ๋น„ โ€” require(ESM) ํšŒํ”ผ). (vocabulary-guard: allow โ€” Node ๋Ÿฐํƒ€์ž„ ๋ฒ„์ „ ํ‘œ๊ธฐ)\n * ์ปค๋„์€ ๊ฒฐ์ •์  ๋…ผ๋ฆฌ ์—ฐ์‚ฐ ์ฝ”์–ด โ€” ์ด host ๊ฐ€ ์ „์†ก(pubsub)ยท์˜์†(TypeORM)ยท์Šค์ผ€์ค„(tick)ยท๋ณต๊ตฌ(replay)๋งŒ ์–‡๊ฒŒ ๋ž˜ํ•‘.\n * (์„ค๊ณ„ SoT: operato-twin/design/integration/things-factory-host.md)\n */\n\nimport { pubsub, getRepository, Domain } from '@things-factory/shell'\n/* ์ €๋„์„ ์ž๋ฅผ ์กฐ๊ฑด์€ SQL ์ด ์•ˆ๋‹ค โ€” ๊ด€์šฉ๊ตฌ๋งŒ ์“ด๋‹ค(์›์‹œ SQL ์€ 5๊ฐœ ๋“œ๋ผ์ด๋ฒ„์—์„œ ๊ฐˆ๋ผ์ง„๋‹ค). */\nimport { And, IsNull, LessThanOrEqual, MoreThan } from 'typeorm'\nimport { cacheService } from '@things-factory/cache-service'\n\nimport type { ReducerCheckpoint } from '@operato/twin-kernel'\nimport type { OeeCheckpoint } from './oee-accumulator.js'\nimport { TwinEvent } from '../service/twin-event/twin-event.js'\nimport { twinEventKeys } from '../service/twin-event/twin-event-keys.js'\nimport { planLiveContinuity, planWarmStart, unwrapState } from './warm-start.js'\nimport { applyDeclarationLayers } from './local-declarations.js'\nimport { isOfDomain, parseRuntimeKey, runtimeKey } from './runtime-key.js'\nimport { routeCommand } from './command-routing.js'\nimport { TwinInstance } from '../service/twin-instance/twin-instance.js'\n/* ์ž๊ทน์˜ ์ง‘์€ ์›๋ณธ์ด๋‹ค(ADR-0029) โ€” ๊ทธ ํ–‰์„ ์ฝ๊ณ  ์“ด๋‹ค. */\nimport { TwinReference } from '../service/reference/twin-reference.js'\nimport { TwinStructure } from '../service/twin-structure/twin-structure.js'\nimport { TwinSpace } from '../service/twin-space/twin-space.js'\nimport { utcOffsetOf } from '../service/reference/reference-master.js'\nimport { TwinSpaceRepresentation } from '../service/twin-space/twin-space-representation.js'\nimport { TwinSpaceArea } from '../service/twin-space/twin-space-area.js'\nimport { TwinArea } from '../service/twin-space/twin-area.js'\nimport { masterToTwin, type ReferenceMaster } from '../service/reference/reference-master.js'\nimport { resolveIngestSpace } from '../service/reference/ingest-space.js'\nimport { type IngestWarning, describeWarnings, unresolvedReference, projectionFailed, structureAdopted, generationWithoutTimeZone } from '../service/reference/reference-master.js'\nimport { projectStructure } from '../service/twin-model/project-structure.js'\nimport { buildTravelEstimator, chainEstimators } from './travel-estimator.js'\nimport { buildMeasuredEstimator } from './measured-estimator.js'\nimport { buildYieldEstimator } from './measured-yield.js'\nimport { planStimulus, withStimulus } from './declared-stimulus.js'\nimport { readRestartPolicy, type RestartPolicy } from './restart-policy.js'\nimport { describeModelBasis, type ModelBasis } from './model-basis.js'\nimport { computeTwinKpi } from './kpi-query.js'\nimport { createHash } from 'node:crypto'\n\nimport { buildEntityDeltas } from '@things-factory/headless-twin/dist-shared/entity-delta.js'\nimport { fleetLoad, judgeCycle, loadSummary, newLoadMeter, recordFork, recordPhase, slowTickMessage, type LoadMeter, type LoadPhase } from './load-meter.js'\nimport { diffStructures, type StructureDiff } from './structure-diff.js'\nimport { OeeAccumulator, withLiveOee } from './oee-accumulator.js'\nimport { withLiveAttentions } from './live-attentions.js'\nimport { digestAttentions, mergeLensAttentions } from './attention-digest.js'\n\nimport { liveFeedStateOf } from './live-feed-registry.js'\nimport { EMS_PROPERTY } from '@operato/twin-kernel'\nimport type { TwinKernel, TwinModelDef, StructureShift, SubscriptionMessage, TwinRuntime as TwinRuntimeType, CanonicalEnvelope } from '@operato/twin-kernel'\n\n/* ์ปค๋„ ๋Ÿฐํƒ€์ž„ ๋กœ๋“œ โ€” CJS ๋ฒˆ๋“ค(dist-cjs). ํƒ€์ž…์€ ์œ„ import type ๋กœ. replay = ์ด๋ฒคํŠธ์—ดโ†’์ƒํƒœ ์žฌ๊ตฌ์„ฑ(๋ณต๊ตฌยท์‹œ๊ฐ„์—ฌํ–‰). */\nconst { WmsKernel, YmsKernel, MesKernel, EmsKernel, TwinRuntime, StateProjector, replay, replayFrom, replayWithCheckpoint, replaySegments, readBoardLocations, readBoardEquipment, DOMAIN_CATALOG, OP_EVENT, validateScenario } = require('@operato/twin-kernel')\n\nconst KERNELS: Record<string, any> = { wms: WmsKernel, yms: YmsKernel, mes: MesKernel, ems: EmsKernel }\n\n/**\n * ์ข…๋ฅ˜ ๋ฌธ์ž์—ด โ†’ ์ปค๋„. **๋ชจ๋ฅด๋Š” ๊ฐ’์ด๋ฉด ๋˜์ง„๋‹ค.**\n *\n * ์˜ˆ์ „์—๋Š” ํ‘œ๋ฅผ ์ฐพ๊ณ  ์—†์œผ๋ฉด WmsKernel ๋กœ ๋–จ์–ด์กŒ๋‹ค. `kind` ๋Š” ๊ฒ€์ฆ ์—†๋Š” ์ž์œ  ๋ฌธ์ž์—ด(`@Arg('kind') kind: string`)\n * ์ด๋ผ ์˜คํƒ€ ํ•˜๋‚˜ยท๋Œ€์†Œ๋ฌธ์ž ํ•˜๋‚˜๋กœ ์•ผ๋“œ/์ƒ์‚ฐ ํŠธ์œˆ์ด **์กฐ์šฉํžˆ ์ฐฝ๊ณ  ์ปค๋„๋กœ ๋Œ์•˜๋‹ค.** ์˜ค๋ฅ˜๊ฐ€ ์—†์œผ๋‹ˆ ํ™”๋ฉด์—๋Š”\n * ํŠธ์œˆ์ด ์ •์ƒ์œผ๋กœ ๋ณด์ด๊ณ , ์•ˆ์—์„œ ๋„๋Š” ๊ทœ์น™๋งŒ ๋‹ค๋ฅธ ๋„๋ฉ”์ธ์˜ ๊ฒƒ์ด๋‹ค. ์˜ˆ์ธก ๊ฒฝ๋กœ๊ฐ€ ๊ฐ€์žฅ ๋‚˜์˜๋‹ค โ€”\n * ์•ผ๋“œ์˜ ๋ฏธ๋ž˜๋ฅผ ์ฐฝ๊ณ  ๊ทœ์น™์œผ๋กœ ์‹คํ–‰ํ•ด ๋†“๊ณ  ์ˆซ์ž๋งŒ ๋œฌ๋‹ค.\n *\n * ํ‹€๋ฆฐ ๊ณต์žฅ์„ ์กฐ์šฉํžˆ ๋„์šฐ๋Š” ๊ฒƒ๋ณด๋‹ค ๋œจ์ง€ ์•Š๋Š” ํŽธ์ด ๋‚ซ๋‹ค.\n */\nfunction kernelFor(kind: string): any {\n const K = KERNELS[kind]\n if (!K) throw new Error(`unknown twin kind \"${kind}\" โ€” expected one of ${Object.keys(KERNELS).join(' | ')}`)\n return K\n}\n\n/* ๋ผ์ด๋ธŒ ์ฒ˜๋ฆฌ๋Ÿ‰ ๊ณ„์ธก(๋ชจ๋‹ˆํ„ฐ) โ€” ์œ ์ž…/๋ฐฉ์†ก/์ €๋„๋ฅ ยท๋ฐฑ๋กœ๊ทธ. ์‹ค ๋™๊ธฐ ์ธํ„ฐํŽ˜์ด์Šค ๋ถ€ํ•˜๋ฅผ ์ฝ๋Š” ์ผ๊ธ‰ ์ง€ํ‘œ. */\ninterface TwinMetrics {\n ingestedTotal: number // ๋ˆ„์  ์œ ์ž… ์ด๋ฒคํŠธ\n broadcastTotal: number // ๋ˆ„์  ๋ฐฉ์†ก ํšŸ์ˆ˜\n journaledTotal: number // ๋ˆ„์  ์ €๋„ ๊ธฐ๋ก ์ด๋ฒคํŠธ\n ingestRate: number // ์ตœ๊ทผ ์œ ์ž…๋ฅ (ev/s)\n broadcastRate: number // ์ตœ๊ทผ ๋ฐฉ์†ก๋ฅ (ํšŒ/s)\n journalRate: number // ์ตœ๊ทผ ์ €๋„๋ฅ (ev/s)\n backlog: number // ๋งˆ์ง€๋ง‰ flush ์‹œ ๋Œ€๊ธฐ ์ €๋„ ํฌ๊ธฐ(๋ฐฑํ”„๋ ˆ์…” ์‹ ํ˜ธ)\n // ์ฐฝ(window) ์ง‘๊ณ„์šฉ ๋‚ด๋ถ€ ๋ˆ„์ \n _accIngest: number\n _accBroadcast: number\n _accJournal: number\n _windowStartMs: number\n}\n\n/*\n * ์žฌ๊ธฐ๋™ ์ •์ฑ…์€ **์„ ์–ธ์ด๊ณ  ๊ธฐ๋ณธ๊ฐ’์ด ์—†๋‹ค** โ€” ์ •์˜ยทํŒ์ •์€ `engine/restart-policy.ts` ๊ฐ€ ๋“ ๋‹ค(ADR-0029 ยง2).\n *\n * ์˜ˆ์ „์—๋Š” ์—ฌ๊ธฐ์— `DEFAULT_REALITY_MODE = 'sim-experiment'` ๊ฐ€ ์žˆ์—ˆ๊ณ , ๋ฏธ์„ ์–ธ์ด ์กฐ์šฉํžˆ **์ €๋„ ์ดˆ๊ธฐํ™”**๋กœ\n * ๋–จ์–ด์กŒ๋‹ค. ๊ทธ ๊ด€์šฉ์€ ๊ฐ’์ด ํ•˜๋‚˜ ์–ด๊ธ‹๋‚˜๋Š” ์ˆœ๊ฐ„ ์ด๋ ฅ์„ ์ง€์šฐ๋Š” ๊ธธ์ด ๋œ๋‹ค โ€” ๊ทธ๋ž˜์„œ ์—†์•ด๋‹ค.\n */\nexport type { RestartPolicy } from './restart-policy.js'\n\n/* ์ธ๋ฉ”๋ชจ๋ฆฌ ๋ผ์ด๋ธŒ ๋Ÿฐํƒ€์ž„ ํ™€๋”(์˜์† ์—”ํ‹ฐํ‹ฐ TwinInstance ์™€ ๊ตฌ๋ถ„). */\ninterface InstanceRuntime {\n /** ๋ถ€ํ•˜ ๊ณ„๊ธฐํŒ โ€” ์ž‘์—…๋ณ„ ์†Œ์š”. ์‹œ๋ฎฌยท๋ผ์ด๋ธŒ ๋ชจ๋‘ ๋ถ™๋Š”๋‹ค(๋ˆ„๊ฐ€ ๋ฃจํ”„๋ฅผ ์ ์œ ํ•˜๋Š”์ง€ ๋ณด๋ ค๋ฉด ๋‘˜ ๋‹ค ํ•„์š”ํ•˜๋‹ค). */\n load?: LoadMeter\n /** ํ˜„์‹ค ์ถœ์ฒ˜ ์„ ์–ธ(ยง0 ํ”„๋ ˆ์ž„ โ‘ ). ๋ถ€ํŒ… ๊ฑฐ๋™(reset/resume/resync)์˜ ๊ทผ๊ฑฐ. */\n restartPolicy?: RestartPolicy\n id: string\n domainId: string\n domain?: any // ๋ผ์ด๋ธŒ ๋ฐ”์ธ๋”ฉ(data ์ฑ„๋„)์šฉ Domain ๊ฐ์ฒด(subdomain ํ•„ํ„ฐ). start ์‹œ ๋น„๋™๊ธฐ ํ•ด์„.\n runtime?: TwinRuntimeType // sim: ์ปค๋„ ๋Ÿฐํƒ€์ž„(tick/subscribe/dispatch). live ๋Š” projector ์‚ฌ์šฉ.\n kernel?: any // sim: ForecastTwin(fork/getSnapshot/tick/scenario). live ๋ฏธ์‚ฌ์šฉ.\n mode?: 'sim' | 'live' // ์ƒํƒœ ๋“œ๋ผ์ด๋ฒ„ โ€” sim=์ปค๋„ tick / live=projector ๋ฏธ๋Ÿฌ(face2-inbound-live). ๋ฏธ์ง€์ •=sim.\n /** ์ด ํŠธ์œˆ์ด ์„  ํ˜„์žฅ โ€” ๊ฐ™์€ ํ˜„์žฅ์˜ ํŠธ์œˆ๋ผ๋ฆฌ ์„œ๋กœ์˜ ์„ค๋น„ ์ƒํƒœ๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ์—ด์‡ . */\n spaceId?: string\n /**\n * live ์˜ ์ƒํƒœ ์ ‘๊ทผ ์–ด๋Œ‘ํ„ฐ โ€” ์ด์ œ **๊ด€์ธก ๋ชจ๋“œ ์ปค๋„**์„ ๊ฐ€๋ฆฌํ‚จ๋‹ค(`kernel` ๊ณผ ๊ฐ™์€ ๊ฒƒ).\n * ์ด๋ฆ„์€ ์†Œ๋น„์ฒ˜ ํ˜ธํ™˜์œผ๋กœ ๋‚จ์•˜๊ณ , P3 ์—์„œ ์ปค๋„ ์–ดํœ˜๋กœ ์ •๋ฆฌํ•˜๋ฉด ์‚ฌ๋ผ์ง„๋‹ค.\n */\n projector?: any\n oee?: OeeAccumulator // live: OEE ๊ณ„์‚ฐ ์ธต(์ด๋ฒคํŠธ ๋ˆ„์  โ†’ equipment payload ๋ณด๊ฐ•). sim ์€ ์ปค๋„์ด ๊ณ„์‚ฐ.\n unsub: () => void\n /**\n * ๋ฐฉ๊ธˆ ์ธ์ž…ํ•œ ๋ด‰ํˆฌ๋“ค โ€” ์ปค๋„์ด ๊ทธ๊ฒƒ์„ ์žฌ๋ฐฉ์ถœํ•  ๋•Œ **์ €๋„์— ๋‘ ๋ฒˆ ์ ์ง€ ์•Š๊ธฐ** ์œ„ํ•œ ํ‘œ์‹œ.\n * ๋ผ์ด๋ธŒ๋งŒ ์“ด๋‹ค(sim ์€ ์ปค๋„์ด ์Šค์Šค๋กœ ๋‚ธ ๊ฒƒ๋งŒ ํ˜๋ฆฐ๋‹ค). ์•ฝํ•œ ์ฐธ์กฐ๋ผ ๋”ฐ๋กœ ๋น„์šธ ๊ฒƒ์ด ์—†๋‹ค.\n */\n applying?: WeakSet<object>\n timer?: any\n /** ์—”ํ‹ฐํ‹ฐ๋ณ„ ๋งˆ์ง€๋ง‰ ๋ฐœํ–‰ ์‹œ๊ทธ๋‹ˆ์ฒ˜ โ€” ๊ฐ’์ด ๋ฐ”๋€ ์—”ํ‹ฐํ‹ฐ๋งŒ ์žฌ๋ฐœํ–‰(๋ฌด๋ณ€ํ™” ๋ฐ˜๋ณต push ๋ฐฉ์ง€). */\n entitySigs?: Map<string, string>\n /** live ๋ฐฉ์†ก ๋ณ‘ํ•ฉ(ingest-scale ยง4.4) โ€” ingest ๋งˆ๋‹ค ๋ฐฉ์†กํ•˜์ง€ ์•Š๊ณ  dirty ํ‘œ์‹œ โ†’ coalescer tick ์ด ์ฃผ๊ธฐ ๋ฐฉ์†ก. */\n dirty?: boolean\n /** live ์ €๋„ ๊ฒฐ์„  โ€” ingest ์ด๋ฒคํŠธ๋ฅผ ๋ชจ์•˜๋‹ค๊ฐ€ coalescer tick ์—์„œ ๋ฐฐ์น˜ ๊ธฐ๋ก(์ด๋ฒคํŠธ๋งˆ๋‹ค DB write ๊ธˆ์ง€). */\n pendingJournal?: any[]\n /** live ์ €๋„ revision ์นด์šดํ„ฐ(sim ์˜ delta revision ๋Œ€์‘ โ€” ์‹œ๊ฐ„์—ฌํ–‰ยทํžˆ์Šคํ† ๋ฆฌ ๋…ธ๋ธŒ ์•ต์ปค). */\n revision?: number\n /** live ์ฒ˜๋ฆฌ๋Ÿ‰ ๊ณ„์ธก(๋ชจ๋‹ˆํ„ฐ, โ‘ฃ-1). */\n metrics?: TwinMetrics\n}\n\n/**\n * ํŠธ์œˆ์ด **์Šค์Šค๋กœ ๋ฉˆ์ถ˜ ์ด์œ ** โ€” ๋ฌธ์žฅ์ด ์•„๋‹ˆ๋ผ ์ฝ”๋“œ๋‹ค.\n *\n * ์„œ๋ฒ„๊ฐ€ ๋งŒ๋“  ์˜์–ด ๋ฌธ์žฅ์„ ๊ทธ๋Œ€๋กœ ์‹ค์œผ๋ฉด ํ•œ๊ตญ์–ดยท์ผ๋ณธ์–ด ํ™”๋ฉด์— ๊ทธ ์˜์–ด๊ฐ€ ๋œฌ๋‹ค. ์ด ์‹œ์Šคํ…œ์€ ๊ฑฐ์ ˆ ๋ฉ”์‹œ์ง€์—์„œ\n * ๊ฐ™์€ ๊ฒฐ๋ก ์— ์ด๋ฅด๋ €๋‹ค(์ฝ”๋“œ+ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋‚ด๊ณ  ํ™”๋ฉด์ด ์˜ฎ๊ธด๋‹ค). `reason` ๋งŒ์€ ์›๋ฌธ ๊ทธ๋Œ€๋กœ๋‹ค โ€” ์ปค๋„ยท๋Ÿฐํƒ€์ž„์ด\n * ๋‚ธ ์˜ค๋ฅ˜ ๋ฌธ๊ตฌ๋Š” ์˜ฎ๊ธธ ์ˆ˜ ์žˆ๋Š” ์–ดํœ˜๊ฐ€ ์•„๋‹ˆ๊ณ , ์˜ฎ๊ธฐ๋ ค ๋“ค๋ฉด ์›์ธ์„ ์žƒ๋Š”๋‹ค.\n */\nexport interface StopNote {\n code: 'starved' | 'tick-failed'\n params: Record<string, string | number>\n}\n\nexport class TwinEngine {\n /*\n * ๊ธฐ๋™ ์ค‘์ธ ๋Ÿฐํƒ€์ž„ โ€” **ํ‚ค๋Š” `runtimeKey(domainId, instanceId)`** ๋‹ค(`runtime-key.ts` ์— ์ด์œ ).\n *\n * ์˜ˆ์ „์—” `instanceId` ํ•˜๋‚˜๋กœ ํ‚ค๋ฅผ ์žก์•˜๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ •์ฒด์„ฑ์€ `(domain, instanceId)` ์ด๊ณ  DB ์œ ์ผ์„ฑ๋„\n * ๊ทธ์ชฝ์ด๋ผ, ๋‘ ํ…Œ๋„ŒํŠธ๊ฐ€ ๊ฐ™์€ id ๋ฅผ ์“ฐ๋ฉด(๋ ˆํผ๋Ÿฐ์Šค ๊ฒฝ๋กœ๊ฐ€ ์†Œ์Šค ์ด๋ฆ„์„ id ๋กœ ์“ด๋‹ค) ํ•œ ์ž๋ฆฌ๋ฅผ ๋‹คํ‰œ๋‹ค.\n * **์—”์ง„ ๋ฐ–์—์„œ ์ด ๋งต์„ ์ง์ ‘ ์ƒ‰์ธํ•˜์ง€ ์•Š๋Š”๋‹ค** โ€” `owns`ยท`runtime`ยท`kernel` ๊ฐ™์€ ์ ‘๊ทผ์ž๋ฅผ ์“ด๋‹ค.\n */\n static instances: Record<string, InstanceRuntime> = {}\n /** ๋ผ์ด๋ธŒ ๋Ÿฐํƒ€์ž„์ด ์—†์„ ๋•Œ(๋ณต๊ตฌ ํ›„ ๋ฏธ๊ธฐ๋™) ์ €๋„์—์„œ ์žฌ๊ตฌ์„ฑํ•œ ์ƒํƒœ ์บ์‹œ. */\n /** ์›œ์Šคํƒ€ํŠธ ์”จ์•— โ€” `instances` ์™€ **๊ฐ™์€ ํ‚ค**(๊ฒน์น˜๋ฉด ๋‚จ์˜ ์Šค๋ƒ…์ƒท์œผ๋กœ ์žฌ๊ณ ๊ฐ€ ์„ž์ธ๋‹ค). */\n static recovered: Record<string, any> = {}\n static TICK_MS = 1000\n\n /*\n * โ”€โ”€ ๊ตถ๊น€ ์•ˆ์ „๋ง (2026-08-14) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์‹œ๋ฎฌ ํ‹ฑ์€ **๋ฉ”์ธ ์ด๋ฒคํŠธ ๋ฃจํ”„**์—์„œ ๋ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํ•œ ํŠธ์œˆ์˜ ํ‹ฑ์ด ๊ธธ์–ด์ง€๋ฉด ๊ทธ ์‹œ๊ฐ„๋งŒํผ ํ˜ธ์ŠคํŠธ ์ „์ฒด๊ฐ€\n * ๋ฉˆ์ถ˜๋‹ค โ€” HTTPยท๊ตฌ๋…ยท๋‹ค๋ฅธ ํŠธ์œˆ์˜ ํ‹ฑ๊นŒ์ง€. ์‹ค์ธก์œผ๋กœ `order-check` ์˜ ํ‹ฑ ํ•˜๋‚˜๊ฐ€ 34.9์ดˆ์˜€๊ณ , ๊ทธ ์‚ฌ์ด\n * ๊ตฌ๋…์ž๊ฐ€ ์•„๋ฌด๊ฒƒ๋„ ๋นผ๋‚ด์ง€ ๋ชปํ•ด pubsub ์ด ๋„˜์ณ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ฃฝ์—ˆ๋‹ค.\n *\n * ๋ฐฉ์†ก ๋ฐ˜๋ณต์€ ๊ฑท์–ด๋ƒˆ์ง€๋งŒ(`flushLiveBroadcasts` ๋กœ ๋ณ‘ํ•ฉ) **์ปค๋„ ํ‹ฑ ์ž์ฒด๋Š” ์—ฌ์ „ํžˆ ๋ฉ”์ธ ๋ฃจํ”„์— ์žˆ๋‹ค.**\n * ๊ทผ๋ณธ ํ•ด๊ฒฐ์€ ๋ถ„์‚ฐ์ด๊ณ  ๊ทธ๊ฒƒ์€ ์ด์—ฐ๋๋‹ค โ€” ๊ทธ๋•Œ๊นŒ์ง€์˜ ์•ˆ์ „๋ง์ด ์ด ์…‹์ด๋‹ค.\n *\n * ํŒ์ •์„ ์˜ˆ์‚ฐ(500ms)์ด ์•„๋‹ˆ๋ผ **๊ตถ๊น€ ๋ฌธํ„ฑ**์œผ๋กœ ๋”ฐ๋กœ ๋‘”๋‹ค: ์กฐ๊ธˆ ๋А๋ฆฐ ํŠธ์œˆ์€ ๊ณ„๊ธฐํŒ์ด ๋งํ•˜๊ฒŒ ๋‘๊ณ \n * (๊ฒฝ๊ณ ), ํ˜ธ์ŠคํŠธ๋ฅผ ๊ตถ๊ธฐ๋Š” ํŠธ์œˆ๋งŒ ๋ฉˆ์ถ˜๋‹ค. ํ•œ ๋ฒˆ์œผ๋กœ ๋ฉˆ์ถ”์ง€ ์•Š๋Š”๋‹ค โ€” ์›œ์Šคํƒ€ํŠธ ์งํ›„์˜ ์ฒซ ํ‹ฑ์€ ์›๋ž˜\n * ๋ฌด๊ฒ๋‹ค(๋ณต๊ตฌํ•œ ์ƒํƒœ๋ฅผ ์ฒ˜์Œ ์ ‘๋Š”๋‹ค). **์—ฐ์†**์œผ๋กœ ์ด์–ด์งˆ ๋•Œ๊ฐ€ ๊ตฌ์กฐ์ ์œผ๋กœ ๋А๋ฆฐ ๊ฒƒ์ด๋‹ค.\n */\n /** ๊ตถ๊น€ ๋ฌธํ„ฑ โ€” ํ‹ฑ ๊ฐ„๊ฒฉ์˜ ๋ฐฐ์ˆ˜(1์ดˆ ๊ฐ„๊ฒฉ์ด๋ฉด 5์ดˆ). ์ด ์‹œ๊ฐ„๋งŒํผ ํ˜ธ์ŠคํŠธ๊ฐ€ ๋ฉˆ์ถ˜๋‹ค. */\n static STARVE_FACTOR = 5\n /** ์—ฐ์† ๋ช‡ ๋ฒˆ์ด๋ฉด ๋ฉˆ์ถ”๋‚˜ โ€” 3๋ฒˆ์ด๋ฉด 15์ดˆ๋ฅผ ๊ตถ๊ธด ์…ˆ์ด๊ณ , ๊ทธ๊ฑด ์šฐ์—ฐ์ด ์•„๋‹ˆ๋‹ค. */\n static STARVE_STREAK = 3\n private static starveStreak = new Map<string, number>()\n /**\n * ์™œ ๋ฉˆ์ท„๋‚˜ โ€” **ํ™”๋ฉด์ด ๊ทธ๋Œ€๋กœ ๋งํ•  ์ˆ˜ ์žˆ๊ฒŒ.** ์Šค์Šค๋กœ ๋ฉˆ์ถ˜ ํŠธ์œˆ์ด ์ด์œ  ์—†์ด ใ€Œ์ •์ง€ใ€๋กœ๋งŒ ๋ณด์ด๋ฉด\n * ์‚ฌ๋žŒ์€ ์ž๊ธฐ๊ฐ€ ๋ฉˆ์ถ˜ ์ค„ ์•ˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ์—๋งŒ ๋‘”๋‹ค(์žฌ๊ธฐ๋™ํ•˜๋ฉด ์‚ฌ๋ผ์ง„๋‹ค โ€” ๊ทธ๋•Œ๋Š” ใ€Œ๋ชจ๋ฅธ๋‹คใ€๊ฐ€ ์‚ฌ์‹ค์ด๋‹ค).\n */\n private static stopNotes = new Map<string, StopNote>()\n\n /* ์ตœ์‹  ์Šค๋ƒ…์ƒท ์˜์†(warm-start) โ€” ์žฌ๊ธฐ๋™ ์‹œ ์ €๋„ fold-from-0 replay ๋Œ€์‹  ๋งˆ์ง€๋ง‰ ๋ผ์ด๋ธŒ ์Šค๋ƒ…์ƒท์œผ๋กœ ๋ณต์›.\n * ํ”„๋ ˆ์ž„์›Œํฌ ๊ณตํ†ต cache-service(@things-factory/cache-service) ์žฌ์‚ฌ์šฉ(์žฌ๋ฐœ๋ช… ๊ธˆ์ง€, framework-leverage ยง4).\n * ์ €๋„์€ ๊ทธ๋Œ€๋กœ ์ง„์‹ค(์‹œ๊ฐ„์—ฌํ–‰/history replay ๋ฌด๋ณ€๊ฒฝ) โ€” ์บ์‹œ๋Š” display-only ์›œ์Šคํƒ€ํŠธ ์ตœ์ ํ™”. */\n static SNAPSHOT_CACHE_ID = 'twin-snapshot'\n /*\n * โ”€โ”€ ์žฌ๊ฐœ์  **์‚ฌ์Šฌ** โ€” ๊ณผ๊ฑฐ๋ฅผ ๋ฌผ์—ˆ์„ ๋•Œ ๋ชฉํ‘œ ์ง์ „์—์„œ ์ ‘๊ธฐ ์œ„ํ•ด (2026-08-18) โ”€โ”€\n *\n * ์ตœ์‹  ์žฌ๊ฐœ์  ํ•˜๋‚˜๋กœ๋Š” ์‹œ๊ฐ„์—ฌํ–‰์„ ๋„์šธ ์ˆ˜ ์—†๋‹ค: ๊ทธ๊ฒƒ์€ ์–ธ์ œ๋‚˜ ๋ชฉํ‘œ๋ณด๋‹ค **๋’ค**์— ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ง€์ ์„\n * ์—ฌ๋Ÿฌ ๊ฐœ ๋‚จ๊ธด๋‹ค. ๋‹ค๋งŒ ๊ทธ๊ฒƒ๋“ค์€ ๊ฐ๊ฐ ์ƒํƒœ ์ „์ฒด๋ฅผ ๋“ค๊ณ  ์žˆ์–ด ๋ฌด๊ฒ๋‹ค โ€” ํ•œ ํ–‰์— ๋ชฐ์•„ ๋„ฃ์œผ๋ฉด ๊ฑฐ๋Œ€ํ•œ\n * JSON ์ด ๋˜๋ฏ€๋กœ **์ง€์ ๋งˆ๋‹ค ๋”ฐ๋กœ ๋‘๊ณ  ์ƒ‰์ธ์„ ๋‘”๋‹ค**(cache-service ๋Š” ํ•ด์‹œ ํ‚ค ์กฐํšŒ๋ผ ์—ด๊ฑฐ๊ฐ€ ์•ˆ ๋œ๋‹ค).\n *\n * ๊ฐ„๊ฒฉ์€ ๋ฆฌ๋น„์ „ ๋ˆˆ๊ธˆ์œผ๋กœ ์žก๋Š”๋‹ค(`CHAIN_STRIDE`): ๋ˆˆ๊ธˆ์„ ๋„˜์„ ๋•Œ๋งŒ ํ•œ ์ง€์ ์„ ๋‚จ๊ธฐ๋ฏ€๋กœ, ์ €๋„์ด ๋น ๋ฅด๊ฒŒ\n * ์ž๋ผ๋Š” ํŠธ์œˆ์—์„œ๋„ ์ง€์  ์ˆ˜๊ฐ€ ํญ๋ฐœํ•˜์ง€ ์•Š๋Š”๋‹ค. ์˜ค๋ž˜๋œ ๊ฒƒ๋ถ€ํ„ฐ ๋ฒ„๋ฆฌ๊ณ  ์ตœ๊ทผ `CHAIN_KEEP` ๊ฐœ๋งŒ ๋“ ๋‹ค โ€”\n * ๊ณผ๊ฑฐ๋กœ ๊นŠ์ด ๊ฐˆ์ˆ˜๋ก ์ง€์ ์ด ์—†์–ด 0๋ถ€ํ„ฐ ์ ‘๋Š” ๊ฒƒ์€ **์•Œ๋ ค์ง„ ํ•œ๊ณ„**๋‹ค(๋ฌดํ•œ ๋ณด๊ด€๋ณด๋‹ค ์ •์งํ•˜๋‹ค).\n */\n static CHAIN_CACHE_ID = 'twin-fold-chain'\n static CHAIN_INDEX_CACHE_ID = 'twin-fold-chain-index'\n static CHAIN_STRIDE = 5000 // ๋ฆฌ๋น„์ „ ๋ˆˆ๊ธˆ โ€” ์ด ๊ฐ„๊ฒฉ์„ ๋„˜์„ ๋•Œ๋งŒ ํ•œ ์ง€์ ์„ ๋‚จ๊ธด๋‹ค\n static CHAIN_KEEP = 5 // ์ตœ๊ทผ ๋ช‡ ์ง€์ ์„ ๋“ค๊ณ  ์žˆ๋‚˜(๊ทธ๋ณด๋‹ค ๊ณผ๊ฑฐ๋Š” 0๋ถ€ํ„ฐ ์ ‘๋Š”๋‹ค)\n static SNAPSHOT_TTL_S = 7 * 24 * 3600 // 7์ผ โ€” ์ •์ƒ ๋‹ค์šดํƒ€์ž„ ์ƒ์กด, ๋งŒ๋ฃŒ ์‹œ ์ €๋„ replay ํด๋ฐฑ\n static CHECKPOINT_MS = 20000 // ์ฒดํฌํฌ์ธํŠธ ์ฃผ๊ธฐ(ํ•ซ ๋ธŒ๋กœ๋“œ์บ์ŠคํŠธ ๊ฒฝ๋กœ์™€ ๋ถ„๋ฆฌ, O(state) ์Šค๋กœํ‹€)\n private static checkpointTimer?: any\n\n /** ์ตœ์‹  ์Šค๋ƒ…์ƒท์„ cache-service ์— ์ฒดํฌํฌ์ธํŠธ(๋„๋ฉ”์ธ+instanceId ํ‚ค). display-onlyยท๋น„์ฐจ๋‹จยท์˜ค๋ฅ˜ํก์ˆ˜. */\n static async persistSnapshot(domainId: string, instanceId: string): Promise<void> {\n const inst = this.instances[runtimeKey(domainId, instanceId)]\n if (!inst) return\n /*\n * **๋ด‰ํˆฌ๊ฐ€ ์•„๋‹ˆ๋ผ ์ƒํƒœ๋ฅผ ์ €์žฅํ•œ๋‹ค.** `snapshot()` ์€ ์‹œ๋ฎฌ์—์„œ `runtime.resync()` ๋ด‰ํˆฌ๋ฅผ ์ฃผ๋Š”๋ฐ,\n * ๊ทธ๊ฒƒ์„ ๋‹ค์‹œ `{revision, state}` ๋กœ ๊ฐ์‹ธ ๋„ฃ์–ด ์™”๋‹ค โ†’ ๊บผ๋‚ธ ๊ฐ’์— ์ถ•์ด ํ•˜๋‚˜๋„ ์—†์–ด ์›œ์Šคํƒ€ํŠธ๊ฐ€\n * ์กฐ์šฉํžˆ ๋„˜์–ด๊ฐ”๋‹ค(์ €๋„์— ์ˆ˜์ฒœ ๊ฑด์ด ์žˆ์–ด๋„ ํŠธ์œˆ์ด ๋นˆ ์ฑ„๋กœ ๋–ด๋‹ค).\n */\n const state = unwrapState(this.snapshot(domainId, instanceId))\n if (!state) return\n const revision = inst.revision ?? state.revision ?? 0\n /* ๊ตฌ์กฐ ๋ฆฌ๋น„์ „๋„ ํ•จ๊ป˜ โ€” ์ฝ๋Š” ์ชฝ์ด \"์ด ์ƒํƒœ๊ฐ€ ์ง€๊ธˆ์˜ ๊ณต์žฅ์ธ๊ฐ€\" ๋ฅผ ๊ฐ€๋ฆด ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. */\n const { structureRev } = await this.tipOf(domainId, instanceId).catch(() => ({ structureRev: null }) as any)\n await cacheService.setInCache(this.SNAPSHOT_CACHE_ID, { domainId, instanceId }, { revision, state, structureRev }, this.SNAPSHOT_TTL_S)\n }\n\n /**\n * ์ ‘๊ธฐ์˜ **์žฌ๊ฐœ์ ** โ€” ๋ฆฌ๋“€์„œ ๋‚ด๋ถ€ ์ƒํƒœ ์ „๋ถ€ + ๊ฐ€๋™ ๋ˆ„์ ๊ธฐ.\n *\n * ์Šค๋ƒ…์ƒท(`state`)์€ ์†Œ๋น„์ฒ˜๊ฐ€ ๋ณด๋Š” ๊ฐ’์ด๋ผ ์ด์–ด ์ ‘๊ธฐ์˜ ์”จ์•—์ด ๋˜์ง€ ๋ชปํ•œ๋‹ค(๋ณด๋ฅ˜๋œ ๋‹ด๊น€ยท์ง‘ํ•ฉยท๋ฐ˜์˜ ๋ชป ํ•œ\n * ์‚ฌ๊ฑด ์ง‘๊ณ„๊ฐ€ ์—†๋‹ค โ€” ๊ทธ ์ƒํƒœ๋กœ ๋’ค๋ฅผ ์ ‘์œผ๋ฉด 0๋ถ€ํ„ฐ ์ ‘์€ ๊ฒฐ๊ณผ์™€ ์กฐ์šฉํžˆ ๋‹ฌ๋ผ์ง„๋‹ค). ๊ทธ๋ž˜์„œ ์”จ์•—์€ ๋”ฐ๋กœ ๋“ ๋‹ค.\n */\n private static readonly FOLD_NOTE = 'reducer + oee checkpoint โ€” the seed for folding only the tail'\n\n /** ์ฒดํฌํฌ์ธํŠธ๋œ ์ตœ์‹  ์Šค๋ƒ…์ƒท ๋กœ๋“œ(์—†์œผ๋ฉด null). getFromCache ๋Š” CacheStore ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ฐ˜ํ™˜ โ†’ ํŽ˜์ด๋กœ๋“œ๋Š” .value. */\n static async loadSnapshot(\n domainId: string,\n instanceId: string\n ): Promise<{ revision: number; state: any; structureRev?: number | null; fold?: { reducer: ReducerCheckpoint; oee: OeeCheckpoint } } | null> {\n const entry = await cacheService.getFromCache(this.SNAPSHOT_CACHE_ID, { domainId, instanceId })\n return (entry as any)?.value ?? null\n }\n\n /**\n * ์ ‘์€ ์ƒํƒœ๋ฅผ ์Šค๋ƒ…์ƒท์œผ๋กœ ๋‚จ๊ธด๋‹ค โ€” **๋ผ์ด๋ธŒ๊ฐ€ ์•„๋‹ˆ์–ด๋„.**\n *\n * `persistSnapshot` ์€ ๊ธฐ๋™ ์ค‘์ธ ์ธ์Šคํ„ด์Šค์—์„œ๋งŒ ๋œฌ๋‹ค(๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ง„์‹ค์ด๋ฏ€๋กœ ์˜ณ๋‹ค). ๊ทธ๋Ÿฐ๋ฐ **๋ฉˆ์ถ˜**\n * ํŠธ์œˆ์„ ์กฐํšŒํ•  ๋•Œ๋งˆ๋‹ค ์ €๋„์„ ์ „๋Ÿ‰ ๋‹ค์‹œ ์ ‘๊ณ  ์žˆ์—ˆ๋‹ค(23,731๊ฑด์งœ๋ฆฌ ํŠธ์œˆ์—์„œ 4.6์ดˆ). ๊ทธ ํด๋“œ์˜ ๊ฒฐ๊ณผ๋ฅผ\n * ๋‚จ๊ฒจ ๋‘๋ฉด **์ฒ˜์Œ ํ•œ ๋ฒˆ๋งŒ ๋А๋ฆฌ๋‹ค.**\n *\n * `structureRev` ๋ฅผ ํ•จ๊ป˜ ์ ๋Š”๋‹ค: ์ด๋ฒคํŠธ๊ฐ€ ํ•˜๋‚˜๋„ ์•ˆ ๋Š˜์–ด๋„ ๊ตฌ์กฐ๋ฅผ ๊ฐˆ์•„์น˜์šฐ๋ฉด(์žฌํ”„๋กœ๋น„์ €๋‹) ๊ทธ\n * ์ƒํƒœ๋Š” ๋‚ก์€ ๊ฒƒ์ด๋‹ค. ๋ฆฌ๋น„์ „๋งŒ ๋ณด๋ฉด ์ƒˆ ์„ค๋น„๊ฐ€ ์—†๋Š” ์˜› ์ƒํƒœ๋ฅผ \"์ง€๊ธˆ\" ์œผ๋กœ ๋‚ด๊ฒŒ ๋œ๋‹ค.\n */\n static async saveFoldedSnapshot(\n domainId: string,\n instanceId: string,\n value: { revision: number; state: any; structureRev?: number | null; fold?: { reducer: ReducerCheckpoint; oee: OeeCheckpoint } }\n ): Promise<void> {\n if (!value?.state) return\n await cacheService\n .setInCache(this.SNAPSHOT_CACHE_ID, { domainId, instanceId }, value, this.SNAPSHOT_TTL_S)\n .catch((err: any) => console.error(`[twin-engine] snapshot save fail \"${instanceId}\"`, err?.message ?? err))\n }\n\n\n /** ์‚ฌ์Šฌ ์ƒ‰์ธ โ€” ์–ด๋–ค ๋ฆฌ๋น„์ „ ์ง€์ ์„ ๋“ค๊ณ  ์žˆ๋‚˜(์ตœ์‹ ์ˆœ ์•„๋‹˜, ์˜ค๋ฆ„์ฐจ์ˆœ). */\n private static async chainIndex(domainId: string, instanceId: string): Promise<number[]> {\n const entry = await cacheService.getFromCache(this.CHAIN_INDEX_CACHE_ID, { domainId, instanceId }).catch(() => null)\n const revs = (entry as any)?.value?.revisions\n return Array.isArray(revs) ? revs.filter((r: any) => Number.isFinite(r)).sort((a: number, b: number) => a - b) : []\n }\n\n /**\n * ๋ชฉํ‘œ ์ด์ „์˜ **๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ์ง€์ **์„ ๊ณ ๋ฅธ๋‹ค โ€” ์—†์œผ๋ฉด `null`(0๋ถ€ํ„ฐ ์ ‘๋Š”๋‹ค).\n *\n * ์‹œ๊ฐ์œผ๋กœ ๋ฌผ์—ˆ์œผ๋ฉด ๊ทธ ์ง€์ ์˜ ๋งˆ์ง€๋ง‰ ์‚ฌ์‹ค ์‹œ๊ฐ์ด ๋ชฉํ‘œ ์ด๋‚ด์—ฌ์•ผ ํ•œ๋‹ค(๋ฆฌ๋น„์ „๋งŒ ๋ณด๋ฉด ๋ชฉํ‘œ๋ณด๋‹ค ๋’ค์˜\n * ์‚ฌ์‹ค์ด ์”จ์•—์— ์„ž์ธ๋‹ค). ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€ ํŠธ์œˆ์—์„œ๋Š” ์“ฐ์ง€ ์•Š๋Š”๋‹ค โ€” ๋งˆ๋””๋ฅผ ๊ฑด๋„ˆ๋›ด ์”จ์•—์€ ๊ทธ ๊ฒฝ๊ณ„์˜\n * ํŒ์ •์„ ์žƒ๋Š”๋‹ค(๊ทธ ๊ฒฝ์šฐ๋Š” 0๋ถ€ํ„ฐ ์ ‘๋Š” ๊ฒƒ์ด ์˜ณ๋‹ค).\n */\n private static async chainSeedFor(\n domainId: string,\n instanceId: string,\n target: { revision?: number; timeMs?: number }\n ): Promise<{ revision: number; eventTime?: string; structureRev?: number | null; fold?: { reducer: ReducerCheckpoint; oee: OeeCheckpoint } } | null> {\n const revs = await this.chainIndex(domainId, instanceId)\n if (!revs.length) return null\n for (const revision of [...revs].reverse()) {\n if (target.revision != null && revision > target.revision) continue\n const entry = await cacheService.getFromCache(this.CHAIN_CACHE_ID, { domainId, instanceId, revision }).catch(() => null)\n const value = (entry as any)?.value\n if (!value?.fold?.reducer) continue\n if (target.timeMs != null) {\n const t = value.eventTime ? Date.parse(String(value.eventTime)) : NaN\n /* ์‹œ๊ฐ์„ ๋ชจ๋ฅด๋Š” ์ง€์ ์€ ์“ฐ์ง€ ์•Š๋Š”๋‹ค โ€” ๋ชฉํ‘œ ์ด๋‚ด์ธ์ง€ ๊ฐ€๋ฆด ์ˆ˜ ์—†๋‹ค(์ง์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค). */\n if (!Number.isFinite(t) || t > target.timeMs) continue\n }\n return value\n }\n return null\n }\n\n /** ๋ˆˆ๊ธˆ์„ ๋„˜์—ˆ์œผ๋ฉด ํ•œ ์ง€์ ์„ ๋‚จ๊ธด๋‹ค โ€” ์˜ค๋ž˜๋œ ๊ฒƒ์€ ๋ฒ„๋ฆฐ๋‹ค(์ƒ‰์ธ๋„ ํ•จ๊ป˜ ์ค„์ธ๋‹ค). */\n private static async keepChainPoint(\n domainId: string,\n instanceId: string,\n /*\n * **๋ณด๊ธฐ(state)๋Š” ๋‹ด์ง€ ์•Š๋Š”๋‹ค** (2026-08-18 ์‹ค์ธก์œผ๋กœ ๊ณ ์นจ).\n *\n * ์ฒ˜์Œ์—๋Š” ์ƒํƒœ๊นŒ์ง€ ๋‹ด์•˜๋”๋‹ˆ ์ง€์  ํ•˜๋‚˜๊ฐ€ **11.4 MB** ์˜€๋‹ค(27๋งŒ ๊ฑด ํŠธ์œˆ). ์‚ฌ์Šฌ์ด ํ•„์š”ํ•œ ๊ฒƒ์€ ์”จ์•—\n * (์žฌ๊ฐœ์ )๋ฟ์ด๊ณ , ์†Œ๋น„์ฒ˜๊ฐ€ ๋ณด๋Š” ๊ฐ’์€ ๊ทธ ์”จ์•—์—์„œ ๋‹ค์‹œ ๋งŒ๋“ค์–ด์ง„๋‹ค โ€” ๊ฐ™์€ ์‚ฌ์‹ค์„ ๋‘ ๋ฒˆ ์ €์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค.\n */\n value: { revision: number; eventTime?: string; structureRev?: number | null; fold: { reducer: ReducerCheckpoint; oee: OeeCheckpoint } }\n ): Promise<void> {\n const revs = await this.chainIndex(domainId, instanceId)\n const newest = revs.length ? revs[revs.length - 1] : -Infinity\n if (value.revision - newest < this.CHAIN_STRIDE) return // ์•„์ง ๋ˆˆ๊ธˆ์„ ๋„˜์ง€ ์•Š์•˜๋‹ค\n const next = [...revs, value.revision].slice(-this.CHAIN_KEEP)\n const dropped = revs.filter(r => !next.includes(r))\n await cacheService.setInCache(this.CHAIN_CACHE_ID, { domainId, instanceId, revision: value.revision }, value, this.SNAPSHOT_TTL_S)\n await cacheService.setInCache(this.CHAIN_INDEX_CACHE_ID, { domainId, instanceId }, { revisions: next }, this.SNAPSHOT_TTL_S)\n /*\n * ๋ฒ„๋ฆฐ ์ง€์ ์€ **์ƒ‰์ธ์—์„œ๋งŒ** ๋น ์ง„๋‹ค โ€” ๊ณต์šฉ ์บ์‹œ์— ์‚ญ์ œ API ๊ฐ€ ์—†๋‹ค(`ICacheService` ๋Š” getยทsetยท\n * clearStaleCache ๋ฟ์ด๋‹ค). ๊ทธ๋ž˜์„œ ๊ฐ’์€ TTL(7์ผ)๊นŒ์ง€ ๋‚จ๋Š”๋‹ค: ์•„๋ฌด๋„ ๋‹ฟ์ง€ ๋ชปํ•˜์ง€๋งŒ ์ž๋ฆฌ๋Š” ์ฐจ์ง€ํ•œ๋‹ค.\n * ์ง€๊ธˆ ๊ทœ๋ชจ์—์„œ ๊ฐ๋‹นํ•  ์ˆ˜ ์žˆ๋Š” ๋‚ญ๋น„์ด๊ณ , ๊ณต์šฉ ๋ชจ๋“ˆ์— ์‚ญ์ œ๋ฅผ ์—ฌ๋Š” ๊ฒƒ์€ ๋‹ค๋ฅธ ์†Œ๋น„์ฒ˜๊นŒ์ง€ ํ•จ๊ป˜ ๋ณผ\n * ์ผ์ด๋ผ ์—ฌ๊ธฐ์„œ ๋ชฐ๋ž˜ ํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” **์•Œ๋ ค์ง„ ํ•œ๊ณ„๋กœ ์ ์–ด ๋‘”๋‹ค.**\n */\n if (dropped.length) console.info(`[twin-engine] \"${instanceId}\" fold chain dropped ${dropped.join(', ')} from the index (values expire with the cache TTL).`)\n }\n\n /** ์ด ํŠธ์œˆ ์ €๋„์˜ ๋ ๋ฆฌ๋น„์ „ ยท ์ตœ์‹  ๊ตฌ์กฐ ๋ฆฌ๋น„์ „ โ€” ์Šค๋ƒ…์ƒท์ด ์ง€๊ธˆ์˜ ์‚ฌ์‹ค์ธ์ง€ ๊ฐ€๋ฆฌ๋Š” ๋‘ ๊ฐ’. */\n private static async tipOf(domainId: string, instanceId: string): Promise<{ revision: number; structureRev: number | null }> {\n const [tip, newest] = await Promise.all([\n getRepository(TwinEvent).findOne({ where: { domain: { id: domainId }, instanceId }, order: { revision: 'DESC' } }),\n getRepository(TwinStructure).findOne({ where: { domain: { id: domainId }, instanceId }, order: { rev: 'DESC' } })\n ])\n return { revision: tip?.revision ?? 0, structureRev: newest?.rev ?? null }\n }\n\n /** ์ฒดํฌํฌ์ธํŠธ ๋ฃจํ”„ ๊ธฐ๋™(1ํšŒ) โ€” ๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค๋“ค์˜ ์ตœ์‹  ์Šค๋ƒ…์ƒท์„ ์ฃผ๊ธฐ ์˜์†. */\n static startCheckpointLoop(): void {\n if (this.checkpointTimer) return\n this.checkpointTimer = setInterval(() => {\n for (const [key, inst] of Object.entries(this.instances)) {\n const { instanceId } = parseRuntimeKey(key)\n this.persistSnapshot(inst.domainId, instanceId).catch(err =>\n console.error(`[twin-engine] snapshot checkpoint fail \"${instanceId}\"`, err?.message ?? err)\n )\n }\n }, this.CHECKPOINT_MS)\n if (typeof this.checkpointTimer?.unref === 'function') this.checkpointTimer.unref()\n }\n\n /**\n * ๋ถ€ํŒ… ํ›… โ€” DB ์— status='running' ์œผ๋กœ ๋‚จ์€ ์ธ์Šคํ„ด์Šค๋ฅผ ์ €๋„์—์„œ ์ƒํƒœ ์žฌ๊ตฌ์„ฑ(DBโ†’replay).\n * ๋ผ์ด๋ธŒ tick ์žฌ๊ฐœ(sim ๊ฒฐ์ •์  re-run / live ์ธ์ œ์ŠคํŠธ ์ง€์†)๋Š” ํ›„์†. ์—ฌ๊ธฐ์„  ์ƒํƒœ ๋ณต์› + ๋…ธ์ถœ.\n */\n static async bootstrap(): Promise<void> {\n try {\n const repo = getRepository(TwinInstance)\n const rows = await repo.find({ where: { status: 'running' } })\n for (const row of rows) {\n if (!row.domainId || !row.instanceId) continue\n // ์›œ์Šคํƒ€ํŠธ: ์บ์‹œ๋œ ์ตœ์‹  ์Šค๋ƒ…์ƒท ์šฐ์„ (O(1) + attentions/OEE ๋“ฑ ๋ผ์ด๋ธŒ ํŒŒ์ƒ์ƒํƒœ ๋ณด์กด).\n // ์—†์œผ๋ฉด ์ €๋„ fold-from-0 replay(์ง„์‹ค ํด๋ฐฑ โ€” replay ๋Š” ๋ผ์ด๋ธŒ ํŒŒ์ƒ์ƒํƒœ๋ฅผ ๋ชป ๋‹ด์œผ๋ฏ€๋กœ ์บ์‹œ๊ฐ€ ๋” ์ถฉ์‹ค).\n const cached = await this.loadSnapshot(row.domainId, row.instanceId).catch(() => null)\n if (cached?.state) {\n /* ์˜ˆ์ „์— ๊ฒนํฌ์žฅ์œผ๋กœ ์ €์žฅ๋œ ๊ฐ’์ด ๋‚จ์•„ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค โ€” ์ฝ๋Š” ์ชฝ์—์„œ๋„ ๋ฒ—๊ธด๋‹ค(ํ•œ ๋ฒˆ์€ ๋ฐ˜๋“œ์‹œ ๋งŒ๋‚œ๋‹ค). */\n this.recovered[runtimeKey(row.domainId, row.instanceId)] = { revision: cached.revision, state: unwrapState(cached.state) }\n /*\n * **ใ€Œ์›œ์Šคํƒ€ํŠธํ–ˆ๋‹คใ€๊ณ  ๋งํ•˜์ง€ ์•Š๋Š”๋‹ค** โ€” ์—ฌ๊ธฐ์„œ๋Š” ์ƒํƒœ๋ฅผ **์ฐพ์•„ ๋‘” ๊ฒƒ**๋ฟ์ด๋‹ค.\n *\n * ์‹ค์ œ ์ฃผ์ž…์€ ๊ธฐ๋™ ๋•Œ ์ผ์–ด๋‚˜๊ณ (`warmStart` ๊ฐ€ ๊ทธ๋•Œ ๋ฌด์—‡์„ ์‹ฌ์—ˆ๋Š”์ง€ ๋งํ•œ๋‹ค), ๋ฏธ๋Ÿฌ(live) ํŠธ์œˆ์€\n * ๊ทธ ์”จ์•—์„ ์•„์˜ˆ ์“ฐ์ง€ ์•Š๋Š”๋‹ค(`startLive` ๊ฐ€ ๋ฒ„๋ฆฐ๋‹ค). ๊ทธ๋Ÿฐ๋ฐ ์ด ์ค„์ด ใ€Œwarm-startedใ€๋ผ๊ณ  ๋งํ•ด\n * ๋กœ๊ทธ๋งŒ ์ฝ์œผ๋ฉด ์‹ฌ๊ธด ์ค„ ์•Œ๊ฒŒ ๋œ๋‹ค โ€” ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ์ฝ๊ณ  ์žฌ๊ธฐ๋™ ๋’ค ์ง€์†์‹œ๊ฐ„์ด ์‚ฌ๋ผ์ง„ ๊ฒƒ์„\n * ๋ฐ์ดํ„ฐ ๋ฌธ์ œ๋กœ ์˜ค์ง„ํ•  ๋ป”ํ–ˆ๋‹ค.\n */\n console.log(`[twin-engine] found cached state for \"${row.instanceId}\" โ†’ revision ${cached.revision} (seeded at start).`)\n continue\n }\n const state = await this.recover(row.domainId, row.instanceId).catch(() => null)\n if (state) {\n this.recovered[runtimeKey(row.domainId, row.instanceId)] = { revision: state.revision, state }\n console.log(`[twin-engine] recovered \"${row.instanceId}\" from journal โ†’ revision ${state.revision}.`)\n }\n }\n /* ์ƒํƒœ๋งŒ ๋˜์ฐพ๋Š” ๊ฒƒ์œผ๋กœ๋Š” **๋„๋Š” ํŠธ์œˆ์ด ๋˜์ง€ ์•Š๋Š”๋‹ค** โ€” ๋Ÿฐํƒ€์ž„๊นŒ์ง€ ๋˜์‚ด๋ฆฐ๋‹ค(์•„๋ž˜). */\n for (const row of rows) await this.resumeRow(row)\n this.startCheckpointLoop() // ์ดํ›„ ๊ธฐ๋™๋˜๋Š” ๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค์˜ ์ตœ์‹  ์Šค๋ƒ…์ƒท์„ ์ฃผ๊ธฐ ์˜์†\n } catch (err) {\n console.error('[twin-engine] recovery scan failed', err)\n }\n }\n\n /**\n * ๋ถ€ํŒ… ๋•Œ **๋„๋Š” ํŠธ์œˆ์„ ์‹ค์ œ๋กœ ๋˜์‚ด๋ฆฐ๋‹ค** โ€” ใ€Œ๋„๋Š” ์ค‘ใ€์ด ์‚ฌ์‹ค์ด ๋˜๊ฒŒ.\n *\n * โ”€โ”€ ๋ฌด์—‡์ด ๊ฑฐ์ง“๋ง์ด์—ˆ๋‚˜ (2026-08-14) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * `bootstrap()` ์€ ์ƒํƒœ๋งŒ ๋˜์ฐพ์•„ `recovered` ์— ๋‹ด์•˜๊ณ , ์ปค๋„์„ ์„ธ์šฐ๋Š” ๊ฒƒ์€ **๋ช…์‹œ mutation ๋ฟ**์ด์—ˆ๋‹ค\n * (์ด ํŒŒ์ผ ์œ„์ชฝ ์ฃผ์„์ด ใ€Œํ–ฅํ›„ใ€๋ผ๊ณ  ์ ์–ด ๋‘” ๊ทธ ์ž๋ฆฌ๋‹ค). ๊ทธ๋ž˜์„œ ์„œ๋ฒ„๋ฅผ ํ•œ ๋ฒˆ ์žฌ๊ธฐ๋™ํ•˜๋ฉด ๋“ฑ๋ก๋ถ€๋Š”\n * `running` ์ด๋ผ ๋งํ•˜๋Š”๋ฐ **์•„๋ฌด ์ปค๋„๋„ ๋Œ์ง€ ์•Š์•˜๋‹ค** โ€” ํ™”๋ฉด์€ ๋„๋Š” ํŠธ์œˆ์„, ์‹ค์ œ๋กœ๋Š” ๋ฉˆ์ถ˜ ํŠธ์œˆ์„.\n * ๋ฏธ๋Ÿฌ ํŠธ์œˆ์—์„œ๋Š” ๋” ๋‚˜์˜๋‹ค: ๊ณ„์ธก์ด ์กฐ์šฉํžˆ ๋Š๊ธฐ๊ณ , ์‚ฌ๋žŒ์€ ใ€Œ๊ฐ’์ด ์•ˆ ๋ณ€ํ•˜๋„คใ€๋กœ ์•Œ๊ฒŒ ๋œ๋‹ค.\n *\n * โ”€โ”€ ๋ชจ๋“œ๋ฅผ ์ง€์–ด๋‚ด์ง€ ์•Š๋Š”๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๋ฏธ๋Ÿฌ์˜€๋˜ ํŠธ์œˆ์„ ์‹œ๋ฎฌ๋กœ ๋˜์‚ด๋ฆฌ๋ฉด **์—†๋˜ ์›€์ง์ž„์„ ๋งŒ๋“ค์–ด ๋‚ธ๋‹ค**(๊ด€์ธก ํŠธ์œˆ์ด ์Šค์Šค๋กœ ๋ฌผ๊ฑด์„ ์˜ฎ๊ธด๋‹ค).\n * ๊ทธ๋ž˜์„œ ์„ ์–ธ๋œ `restartPolicy` ๊ทธ๋Œ€๋กœ ๋˜์‚ด๋ฆฐ๋‹ค โ€” ๋ฏธ๋Ÿฌ๋Š” ๊ด€์ธก ๊ตฌ๋™์œผ๋กœ, ์‹œ๋ฎฌ์€ ์‹œ๋ฎฌ๋กœ.\n *\n * โ”€โ”€ ๋˜์‚ด๋ฆด ์ˆ˜ ์—†์œผ๋ฉด ๊ทธ๋ ‡๊ฒŒ ์ ๋Š”๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์‹คํŒจ๋ฅผ ์‚ผํ‚ค๋ฉด ๋“ฑ๋ก๋ถ€๊ฐ€ ๊ณ„์† `running` ์ด๋ผ ๋งํ•œ๋‹ค โ€” ์šฐ๋ฆฌ๊ฐ€ ๊ณ ์น˜๋ ค๋˜ ๊ทธ ๊ฑฐ์ง“๋ง์ด๋‹ค. ๊ทธ๋ž˜์„œ ์‹คํŒจํ•œ\n * ํ–‰์€ `stopped` ๋กœ ์ ๊ณ  ์ด์œ ๋ฅผ ๋‚จ๊ธด๋‹ค. ใ€Œ๋ฉˆ์ท„๋‹คใ€๋Š” ์‚ฌ์‹ค์ด๊ณ , ใ€Œ๋„๋Š” ์ค‘ใ€์€ ์‚ฌ์‹ค์ด ์•„๋‹ˆ์—ˆ๋‹ค.\n */\n private static async resumeRow(row: TwinInstance): Promise<void> {\n const { domainId, instanceId } = row\n if (!domainId || !instanceId) return\n if (this.instances[runtimeKey(domainId, instanceId)]) return // ์ด๋ฏธ ์„ธ์›Œ์กŒ๋‹ค(๋ฐ๋ชจ ์‹œ๋“œ ๋“ฑ)\n\n /*\n * ๋ฒค์น˜ ์‚ฌ๋ณธ์€ ๋˜์‚ด๋ฆฌ์ง€ ์•Š๋Š”๋‹ค โ€” ๊ทธ๊ฒƒ์€ **๋ˆ„๊ตฐ๊ฐ€ ์ง€์ผœ๋ณด๋˜ ์‹คํ—˜**์ด๊ณ , ๋ฌด์ธ์œผ๋กœ ๋˜์‚ด์•„๋‚˜๋ฉด ํ˜ธ์ŠคํŠธ๋ฅผ\n * ๊ทธ๋Œ€๋กœ ๋‘๋“ค๊ธด๋‹ค(๊ฒฉ๋ฆฌ ์‚ฌ๋ณธ์˜ ๋œป์€ ใ€Œ์šด์˜๊ณผ ์„ž์ด์ง€ ์•Š๋Š”๋‹คใ€์ด์ง€ ใ€Œ์˜์›ํžˆ ๋ˆ๋‹คใ€๊ฐ€ ์•„๋‹ˆ๋‹ค).\n * ์‹คํ—˜์€ ์žฌ๊ธฐ๋™์„ ๋„˜๊ธฐ์ง€ ๋ชปํ–ˆ์œผ๋ฏ€๋กœ ๋“ฑ๋ก๋ถ€๋„ ๊ทธ๋ ‡๊ฒŒ ์ ๋Š”๋‹ค.\n */\n if (row.purpose === 'bench') {\n await this.markStopped(row, 'bench copy โ€” an experiment does not survive a restart unattended')\n return\n }\n\n try {\n if (row.restartPolicy === 'resync') {\n if (!row.model) throw new Error('no model')\n /* ์‹œ๊ฐ ๊ธฐ์ค€์€ **๊ณต๊ฐ„**์ด ๊ฐ–๋Š”๋‹ค โ€” ๊ต๋Œ€์˜ HH:MM ์„ ์–ด๋А ๊ธฐ์ค€์œผ๋กœ ์ฝ๋‚˜(๋ผ์ด๋ธŒ ๊ธฐ๋™๊ณผ ๊ฐ™์€ ๊ทœ์น™). */\n this.startLive(instanceId, domainId, row.kind, await this.withSpaceTimeBase(row.model as TwinModelDef, domainId))\n /* ๊ณ„์ธก์„ ๋‚˜๋ฅด๋Š” ํ”ผ๋“œ๋Š” ์ปค๋„ฅํ„ฐ์˜ ๊ฒƒ์ด๋‹ค โ€” ๋ ˆํผ๋Ÿฐ์Šค ๊ณ„์ธต์ด ๋ถ€ํŒ… ํ›…์—์„œ ๋‹ค์‹œ ๋ถ™์ธ๋‹ค\n (`resumeReferenceLiveFeeds`). ์—ฌ๊ธฐ์„œ ์–ด๋Œ‘ํ„ฐ๋ฅผ ์•„๋Š” ๊ฒƒ์€ ๊ณ„์ธต์„ ๊ฑฐ๊พธ๋กœ ์ž‡๋Š” ๊ฒƒ์ด๋‹ค. */\n console.log(`[twin-engine] resumed mirror \"${instanceId}\" โ€” feed reattach is the reference layer's job.`)\n } else {\n await this.startFromRegistry(domainId, instanceId)\n console.log(`[twin-engine] resumed ${row.restartPolicy} \"${instanceId}\".`)\n }\n } catch (err: any) {\n await this.markStopped(row, err?.message ?? 'resume failed')\n }\n }\n\n /** ๋˜์‚ด๋ฆฌ์ง€ ๋ชปํ•œ ํ–‰์„ ์ •์งํ•˜๊ฒŒ ์ ๋Š”๋‹ค โ€” ใ€Œ๋„๋Š” ์ค‘ใ€์ด๋ผ ๋งํ•˜๋Š” ์ฑ„๋กœ ๋‘์ง€ ์•Š๋Š”๋‹ค. */\n private static async markStopped(row: TwinInstance, why: string): Promise<void> {\n console.warn(`[twin-engine] \"${row.instanceId}\" not resumed (${why}) โ€” registry says stopped now.`)\n try {\n await getRepository(TwinInstance).update({ id: row.id }, { status: 'stopped' })\n } catch (e: any) {\n console.error(`[twin-engine] could not mark \"${row.instanceId}\" stopped โ€” registry now lies about it.`, e?.message)\n }\n }\n\n /**\n * ์›œ์Šคํƒ€ํŠธ โ€” ๊ธฐ๋™ํ•˜๋Š” ์ปค๋„์— **์ง์ „ ๊ด€์ธก ์ƒํƒœ**๋ฅผ ์ฃผ์ž…ํ•œ๋‹ค.\n *\n * โ”€โ”€ ์™œ ํ•„์š”ํ•œ๊ฐ€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * `loadTwinModel` ๋Š” **๊ตฌ์กฐ๋งŒ** ์‹ฃ๋Š”๋‹ค(์ž๋ฆฌยท์„ค๋น„). ์ƒํƒœ(๋ฌด์—‡์ด ์–ด๋””์— ์–ผ๋งˆ๋‚˜)๋Š” ์—†๋‹ค. ๊ทธ๋ž˜์„œ ์žฌ๊ธฐ๋™ํ•œ\n * ํŠธ์œˆ์€ ์ €๋„์— ์ž…๊ณ  540๊ฑด์ด ๋‚จ์•„ ์žˆ์–ด๋„ ์žฌ๊ณ ๊ฐ€ 0 ์ด์—ˆ๊ณ , ํ™”๋ฉด์€ \"๋ณด์œ  ์ค‘์ธ ๊ฒƒ์ด ์—†์Šต๋‹ˆ๋‹ค\" ๋ผ๊ณ \n * ๋งํ–ˆ๋‹ค โ€” ์žˆ๋Š” ์žฌ๊ณ ๋ฅผ ์—†๋‹ค๊ณ  ํ•˜๋Š” ์…ˆ์ด๋‹ค(2026-07-31 hatiolab-wms ์‹ค์ธก์œผ๋กœ ํ™•์ธ).\n * `bootstrap()` ์ด ์ด๋ฏธ ์ฒดํฌํฌ์ธํŠธ ์บ์‹œ(์—†์œผ๋ฉด ์ €๋„ replay)๋กœ ์ƒํƒœ๋ฅผ ๋ณต๊ตฌํ•ด `recovered` ์— ๋‹ด์•„ ๋‘๋Š”๋ฐ,\n * ๊ธฐ๋™ ์ˆœ๊ฐ„ ๊ทธ๊ฑธ **๋ฒ„๋ฆฌ๊ณ ** ์žˆ์—ˆ๋‹ค. ๋ฐ˜๋งŒ ์—ฐ๊ฒฐ๋ผ ์žˆ๋˜ ์žฅ์น˜๋ฅผ ์ž‡๋Š”๋‹ค.\n *\n * โ”€โ”€ ๋ฐ˜์ชฝ์ด๋˜ ๋ณต๊ตฌ๋ฅผ ๋งˆ๋ฌด๋ฆฌํ•œ๋‹ค (2026-08-05) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์žฌ๊ณ ๋Š” ์‚ด์•„๋‚ฌ๋Š”๋ฐ **์ง„ํ–‰ ์ค‘ ์ฃผ๋ฌธ์ด ํ†ต์งธ๋กœ ์‚ฌ๋ผ์ง„** ํ™”๋ฉด์ด ๋‚จ์•„ ์žˆ์—ˆ๋‹ค. ์”จ์•—์ด ์ž๋ฆฌยท๋ฌผํ’ˆยท์„ค๋น„\n * ์…‹๋งŒ ๋„˜๊ฒผ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ ๊ทผ๊ฑฐ๋Š” \"์Šค๋ƒ…์ƒท ์˜ค๋”์— progress ๋ฐ–์— ์—†๋‹ค\" ์˜€๊ณ , ๊ทธ๋•Œ๋Š” ๋งž์•˜๋‹ค โ€”\n * ๊ทธ๋Ÿฌ๋‚˜ ์ปค๋„ `OrderState` ๊ฐ€ ์›๊ฐ’(`requested`ยท`fulfilled`ยท`lines`)์„ ๋˜์ฐพ์€ ๋’ค์—๋„ ์ด ์ž๋ฆฌ๋งŒ\n * ๊ทธ๋Œ€๋กœ ๋‚จ์•˜๋‹ค. ์˜ค๋ฅ˜๋ฅผ ๋‚ด์ง€ ์•Š๋Š” ์ข…๋ฅ˜๋ผ ์˜ค๋ž˜ ๋ฒ„ํ…ผ๋‹ค.\n *\n * ์ง€๊ธˆ์€ **๊ด€์ธก ์Šค๋ƒ…์ƒท ์ „์ฒด**๋ฅผ ๋„˜๊ธด๋‹ค(์˜ค๋”ยท์ž‘์—…ยท์‚ฌ๋žŒยท์ž์‚ฐ ํฌํ•จ). ์‹œ๋ฎฌ์€ ์ปค๋„ `snapshot()`,\n * ๋ผ์ด๋ธŒ๋Š” `StateProjector` ๊ฐ€ ๊ทธ ์ผ๊ณฑ ์ถ•์„ ๋ชจ๋‘ ๋‹ด๋Š”๋‹ค. ๋ฌด์—‡์„ ์‹ฌ์„ ์ˆ˜ ์žˆ๋Š”์ง€ ํŒ์ •ํ•˜๋Š” ๊ทœ์น™\n * (์ดํ–‰ ์™„๋ฃŒ ์˜ค๋” ์ œ์™ธยท๊ณ ์•„ ์ž‘์—… ์ œ์™ธ)์€ ์ปค๋„์— ์žˆ๊ณ , ํ˜ธ์ŠคํŠธ๊ฐ€ ๋ฏธ๋ฆฌ ๊ณจ๋ผ๋‚ด์ง€ ์•Š๋Š”๋‹ค.\n *\n * โ”€โ”€ ๋‚จ์€ ํ•œ๊ณ„๋Š” ์ˆจ๊ธฐ์ง€ ์•Š๊ณ  ์„ผ๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ยท ์›๊ฐ’์ด ์—†๋Š” ์˜ค๋”(progress ๋งŒ ์žˆ๋Š” ๊ฒƒ)๋Š” ๋‚จ์€ ์ˆ˜๋Ÿ‰์„ ์•Œ ์ˆ˜ ์—†์–ด ์ฃผ์ž…ํ•˜์ง€ ์•Š๋Š”๋‹ค. **์ง€์–ด๋‚ด์ง€ ์•Š๋Š”\n * ๋Œ€์‹  ๋ช‡ ๊ฑด์ธ์ง€ ๋งํ•œ๋‹ค** โ€” ์„ธ์ง€ ์•Š์œผ๋ฉด \"์ฃผ๋ฌธ์ด ์—†๋‹ค\" ์™€ \"์ฃผ๋ฌธ์„ ๋ชป ์‹ฌ์—ˆ๋‹ค\" ๊ฐ€ ํ™”๋ฉด์—์„œ ๊ฐ™์•„์ง„๋‹ค.\n * ยท ์ง„ํ–‰ ์ค‘ ๊ฐœ๋ณ„ ์ž‘์—…์˜ ๋‚ด๋ถ€ ์ƒํƒœ๋Š” ๊ด€์ธก๋งŒ์œผ๋กœ ์™„์ „ํžˆ ๋ณต์›๋˜์ง€ ์•Š๋Š”๋‹ค(์ปค๋„์ด ๋ช…์‹œํ•œ ํ•œ๊ณ„, ์žฌ๊ณ„ํš์— ๋งก๊น€).\n *\n * โ”€โ”€ ๋ฒค์น˜๋Š” ์‹œ๋“œํ•˜์ง€ ์•Š๋Š”๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๋ถ€ํ•˜ ๋ฒค์น˜๋Š” **์ƒˆ ์‹œ์ž‘์—์„œ ์šฉ๋Ÿ‰์„ ์žฌ๋Š” ๊ฒƒ**์ด ๋ชฉ์ ์ด๋ผ ํ˜„์žฌ ์ƒํƒœ๋ฅผ ์ฃผ์ž…ํ•˜๋ฉด ์ธก์ •์ด ์˜ค์—ผ๋œ๋‹ค.\n */\n private static warmStart(domainId: string, id: string, kernel: TwinKernel, purpose?: string): void {\n const hydrate = (kernel as any).hydrateObserved\n const plan = planWarmStart(this.recovered[runtimeKey(domainId, id)]?.state, purpose, typeof hydrate === 'function')\n\n if (plan.action === 'skip') {\n if (plan.reason === 'bench') {\n console.log(`[twin-engine] \"${id}\" is a bench twin โ€” starting empty on purpose (seeding would skew the measurement).`)\n } else if (plan.reason === 'unsupported') {\n console.warn(\n `[twin-engine] kernel for \"${id}\" cannot be warm-started (no hydrateObserved) โ€” it starts with structure only, so held stock will read as zero.`\n )\n }\n return\n }\n\n hydrate.call(kernel, plan.seed)\n const restored = [\n `${plan.itemCount} item(s)`,\n `${plan.equipmentCount} equipment`,\n `${plan.orderCount} open order(s)`,\n `${plan.taskCount} task(s)`,\n ...(plan.personCount ? [`${plan.personCount} person(s)`] : []),\n ...(plan.assetCount ? [`${plan.assetCount} asset(s)`] : []),\n /* ํ™•์ธํ•ด ๋‘” ์‹ ํ˜ธ๋ฅผ ์ด์–ด๋ฐ›์•˜๋‹ค๋Š” ์‚ฌ์‹ค๋„ ๋งํ•œ๋‹ค โ€” ์žƒ์œผ๋ฉด ํ™•์ธ ์ฒ˜๋ฆฌ๊ฐ€ ๋‹ค์‹œ ๋นจ๊ฐœ์ง€๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ธ๋‹ค. */\n ...(plan.ackedCount ? [`${plan.ackedCount} acknowledged attention(s)`] : []),\n /* ใ€Œ์–ธ์ œ๋ถ€ํ„ฐ์ธ๊ฐ€ใ€๋„ ๋งํ•œ๋‹ค โ€” ์žƒ์œผ๋ฉด ์ง€์†๋œ ์กฐ๊ฑด์ด ๋ชจ๋‘ ใ€Œ๋ฐฉ๊ธˆใ€์œผ๋กœ ๋ณด์ธ๋‹ค. */\n ...(plan.attentionSinceCount ? [`${plan.attentionSinceCount} attention start time(s)`] : [])\n ].join(', ')\n console.log(`[twin-engine] warm-started \"${id}\" โ€” restored ${restored}.`)\n /* ๋บ€ ๊ฒƒ์€ ์กฐ์šฉํžˆ ๋„˜๊ธฐ์ง€ ์•Š๋Š”๋‹ค โ€” ์ง€์–ด๋‚ด์ง€ ์•Š์•˜๋‹ค๋Š” ์‚ฌ์‹ค ์ž์ฒด๋ฅผ ๋งํ•ด์•ผ ํ™”๋ฉด์˜ ๋นˆ์นธ์ด ์ฝํžŒ๋‹ค. */\n if (plan.ordersWithoutDemand > 0) {\n console.warn(\n `[twin-engine] \"${id}\": ${plan.ordersWithoutDemand} order(s) could not be restored โ€” they carry progress only, ` +\n 'with no requested/fulfilled counts, so the remaining demand is unknown. They are left out rather than guessed.'\n )\n }\n }\n\n /** ํŠธ์œˆ ์ธ์Šคํ„ด์Šค ์‹œ์ž‘ โ€” ์ปค๋„ ์ƒ์„ฑ + ๋ชจ๋ธ ๋กœ๋“œ + ์ง์ „ ์ƒํƒœ ์›œ์Šคํƒ€ํŠธ + State ์ŠคํŠธ๋ฆผ ๋ธŒ๋ฆฌ์ง€ + ์›Œ์ปค tick + ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์˜์†. */\n /**\n * ๊ณต์ • ๋ช…์„ธ๋ฅผ ์ปค๋„์— ์‹ฃ๋Š”๋‹ค โ€” **์‹œ๋ฎฌ๋ ˆ์ด์…˜์˜ ์‹œ๊ฐ„์„ ๋ฐ์ดํ„ฐ๊ฐ€ ๋งํ•˜๊ฒŒ ํ•˜๋Š” ๋งˆ์ง€๋ง‰ ํ•œ ์นธ.**\n *\n * `model.operations`(๋งˆ์Šคํ„ฐ ์ธ์ œ์ŠคํŠธ๊ฐ€ ํ†ต๊ณผ์‹œํ‚จ ISA-95 OperationsSegment ๋ช…์„ธ)๋ฅผ ์ปค๋„์ด ์†Œ๋น„ํ•œ๋‹ค.\n * ์—†์œผ๋ฉด ์ปค๋„ ๊ธฐ๋ณธ ์ƒ์ˆ˜๋กœ ๊ตด๋Ÿฌ๊ฐ€๊ณ , ์ปค๋„ `specCoverage()` ๊ฐ€ ๋ฌด์—‡์„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ผ๋Š”์ง€ ๋ณด๊ณ ํ•œ๋‹ค.\n *\n * ์ปค๋„์ด ์•„์ง ์ด API ๋ฅผ ๊ฐ–์ง€ ์•Š์€ ๋ฒ„์ „์ด๋ฉด(๋ฐœํ–‰ ์ด์ „) **์กฐ์šฉํžˆ ๋„˜์–ด๊ฐ€์ง€ ์•Š๊ณ  ๊ฒฝ๊ณ ํ•œ๋‹ค** โ€” ๋ช…์„ธ๋ฅผ\n * ์„ ์–ธํ–ˆ๋Š”๋ฐ ๋ฐ˜์˜๋˜์ง€ ์•Š๋Š” ์ƒํƒœ๋ฅผ ๋ชจ๋ฅด๊ณ  ์ง€๋‚˜๊ฐ€๋ฉด, ์˜ˆ์ธก์ด ์ƒ์ˆ˜๋กœ ๋Œ์•„๊ฐ„ ๊ฒƒ์„ ์•„๋ฌด๋„ ์•Œ ์ˆ˜ ์—†๋‹ค.\n */\n private static applyOperations(kernel: any, model: any, id: string): void {\n /*\n * ํ˜„์žฅ์ด ์ •ํ•œ ๊ณต์ • ์‹œ๊ฐ„ โ€” ๋ช…์„ธ ํ–‰๊ณผ **๋”ฐ๋กœ** ์‹ฃ๋Š”๋‹ค(`declareDurations`).\n *\n * ํ–‰์ด ์—†๋Š” ์ข…๋ฅ˜์—๋„ ์‹œ๊ฐ„์„ ์ค„ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค: ์‹ค์ธก์œผ๋กœ ์ฐฝ๊ณ ยท์•ผ๋“œ ํŠธ์œˆ์—๋Š” ๊ณต์ • ๋ช…์„ธ ํ–‰์ด 0๊ฐœ์˜€๊ณ ,\n * ๊ทธ ํŠธ์œˆ๋“ค์˜ ์‹œ๊ฐ„์€ ์ „๋ถ€ ์ปค๋„ ์ƒ์ˆ˜์—์„œ ์™”๋‹ค. ํ–‰์„ ์ง€์–ด ๋งŒ๋“œ๋Š” ๊ธธ์€ ๋ง‰์•˜๋‹ค(`label`ยท`intent` ๋ฅผ\n * ์ง€์–ด๋‚ด๋ฉด ๋Šฅ๋ ฅ ๊ณ„์‚ฐ๊นŒ์ง€ ์˜ค์—ผ๋œ๋‹ค) โ€” ๊ทธ๋ž˜์„œ ์‹œ๊ฐ„๋งŒ ๋ฐ›๋Š” ์ฐฝ๊ตฌ๊ฐ€ ์ปค๋„์— ์žˆ๋‹ค.\n */\n const declared = model?.localDurations as Record<string, string> | undefined\n if (declared && Object.keys(declared).length) {\n if (typeof kernel?.declareDurations !== 'function') {\n console.warn(\n `[twin-engine] \"${id}\": this facility declared ${Object.keys(declared).length} operation duration(s) but the kernel cannot consume them ` +\n '(declareDurations missing โ€” kernel needs publishing). The simulation keeps running on built-in constants, and specCoverage() will keep reporting \"default\".'\n )\n } else {\n try {\n kernel.declareDurations(declared)\n } catch (err: any) {\n /* ์ปค๋„์ด ๊ฑฐ์ ˆํ•œ ๊ฐ’์€ ์กฐ์šฉํžˆ ๋„˜๊ธฐ์ง€ ์•Š๋Š”๋‹ค โ€” ํ™”๋ฉด์€ ใ€Œ๋„ฃ์—ˆ์Šต๋‹ˆ๋‹คใ€๋ผ๊ณ  ๋งํ•œ ๊ฐ’์ด๋‹ค. */\n console.warn(`[twin-engine] \"${id}\": declared operation duration rejected by the kernel โ€” ${err?.message ?? err}`)\n }\n }\n }\n /* ๊ณต์ • ๋ชจ์ˆ˜(์ˆ˜์œจยท์…‹์—…)๋„ ๊ฐ™์€ ๊ทœ์œจ๋กœ ์‹ฃ๋Š”๋‹ค โ€” ์ปค๋„์ด ๊ทธ ์ฐฝ๊ตฌ๋ฅผ ๊ฐ–์ง€ ์•Š์œผ๋ฉด ๊ทธ ์‚ฌ์‹ค์„ ๋งํ•œ๋‹ค. */\n const params = model?.localParams as Record<string, Record<string, string>> | undefined\n if (params && Object.keys(params).length) {\n if (typeof kernel?.declareParameters !== 'function') {\n console.warn(\n `[twin-engine] \"${id}\": this facility declared operation parameters for ${Object.keys(params).length} operation(s) but the kernel cannot consume them ` +\n '(declareParameters missing โ€” kernel needs publishing). Yield and setup keep running on built-in constants.'\n )\n } else {\n try {\n kernel.declareParameters(params)\n } catch (err: any) {\n console.warn(`[twin-engine] \"${id}\": declared operation parameter rejected by the kernel โ€” ${err?.message ?? err}`)\n }\n }\n }\n const ops = model?.operations\n if (!ops?.length) return\n if (typeof kernel?.loadOperations !== 'function') {\n console.warn(`[twin-engine] \"${id}\": model declares ${ops.length} operation spec(s) but the kernel cannot consume them (loadOperations missing โ€” kernel needs publishing). Simulation will use built-in default durations.`)\n return\n }\n kernel.loadOperations(ops)\n }\n\n /**\n * ์†Œ์š”์‹œ๊ฐ„ ์ถ”์ •๊ธฐ ์ฃผ์ž… โ€” **์ƒ์ˆ˜๋ฅผ ๋ฐ์ดํ„ฐ๋กœ ๋ฐ”๊พธ๋Š” ๋‘ ๋ฒˆ์งธยท์„ธ ๋ฒˆ์งธ ์ธต.**\n *\n * ์ปค๋„ `durationOf` ์˜ ์šฐ์„ ์ˆœ์œ„๋Š” ์ถ”์ •๊ธฐ > ๋ช…์„ธ > ์ƒ์ˆ˜๋‹ค. ๊ทธ ์ถ”์ •๊ธฐ ์ž๋ฆฌ์— ๋‘ ๊ฐ€์ง€๋ฅผ ์‚ฌ์Šฌ๋กœ ๋„ฃ๋Š”๋‹ค:\n * โ‘  **์‹ค์ธก**(์ €๋„์˜ ์ž‘์—… ์ข…๋ฅ˜๋ณ„ ์ž‘์—…์‹œ๊ฐ„ p50) โ€” ๊ทธ ํ˜„์žฅ์—์„œ ์‹ค์ œ๋กœ ์–ผ๋งˆ ๊ฑธ๋ ธ๋‚˜. ๊ฐ€์žฅ ๊ฐ•ํ•œ ๊ทผ๊ฑฐ.\n * โ‘ก **๊ฑฐ๋ฆฌ ร— ์†๋„**(model.layout + ์„ค๋น„ ์†๋„ ์†์„ฑ) โ€” ์ด๋™์€ ๊ฑฐ๋ฆฌ์— ๋น„๋ก€ํ•œ๋‹ค. ์ปค๋„์€ ์ขŒํ‘œ๋ฅผ ๋ชจ๋ฅด๋ฏ€๋กœ\n * ํ˜ธ์ŠคํŠธ๊ฐ€ ๊ณ„์‚ฐํ•ด ๋„ฃ๋Š”๋‹ค.\n * ๋‘˜ ๋‹ค ๋ชป ๋งŒ๋“ค๋ฉด ์ฃผ์ž…ํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” ์ปค๋„์ด ๋ช…์„ธยท์ƒ์ˆ˜๋กœ ๊ตด๋Ÿฌ๊ฐ€๊ณ  `specCoverage()` ๊ฐ€ ๊ทธ ์‚ฌ์‹ค์„ ๋‚จ๊ธด๋‹ค.\n *\n * ์‹ค์ธก์€ DB ์กฐํšŒ๋ผ ๋น„๋™๊ธฐ๋‹ค. ๊ทธ๋ž˜์„œ ์ด ํ•จ์ˆ˜๋Š” **await ํ•˜์ง€ ์•Š๋Š” ์ชฝ์—์„œ๋„ ์•ˆ์ „**ํ•˜๋„๋ก ์‹คํŒจ๋ฅผ ์‚ผํ‚ค๋˜,\n * ๋ฌด์—‡์„ ์™œ ๋ชป ๋„ฃ์—ˆ๋Š”์ง€๋Š” ๋กœ๊ทธ๋กœ ๋‚จ๊ธด๋‹ค(์กฐ์šฉํ•œ ๋ฌดํšจํ™” ๊ธˆ์ง€).\n */\n static async installEstimators(kernel: any, domainId: string, instanceId: string, model: any): Promise<void> {\n if (!kernel || typeof kernel !== 'object') return\n const travel = buildTravelEstimator({ layout: model?.layout, equipment: model?.equipment, unit: model?.unit })\n const measured = await this.measuredEstimator(domainId, instanceId)\n const chained = chainEstimators([measured?.estimator, travel.estimator])\n if (!chained) {\n /* ์™œ ๋ชป ๋„ฃ์—ˆ๋Š”์ง€ ํ•œ ๋ฒˆ๋งŒ ์•Œ๋ฆฐ๋‹ค โ€” ์ด๋™์‹œ๊ฐ„์ด ์ƒ์ˆ˜๋กœ ๋‚จ์€ ์ด์œ ๋ฅผ ๋ชจ๋ฅด๊ณ  ์ง€๋‚˜๊ฐ€์ง€ ์•Š๊ฒŒ. */\n if (travel.reasons.length) console.warn(`[twin-engine] \"${instanceId}\": no duration estimator installed โ€” ${travel.reasons.join('; ')}`)\n return\n }\n kernel.durationEstimator = chained\n /*\n * **์–‘ํ’ˆ๋ฅ ๋„ ์ด๋ ฅ์—์„œ ๋ฐฐ์šด๋‹ค** (2026-08-19) โ€” ์†Œ์š”์™€ ๊ฐ™์€ ์ž๋ฆฌ์—์„œ ๋ถ™์ธ๋‹ค.\n *\n * ์ปค๋„์ด ๊ทธ ์‹œ์ž„์„ ๊ฐ–์ง€ ์•Š์€ ๋ฒ„์ „์ด๋ฉด(๋ฐœํ–‰ ์ด์ „) ์กฐ์šฉํžˆ ๋„˜์–ด๊ฐ€์ง€ ์•Š๊ณ  ๋งํ•œ๋‹ค: ์ˆ˜์œจ์ด ์ƒ์ˆ˜๋กœ ๋‚จ์€\n * ์ด์œ ๋ฅผ ๋ชจ๋ฅด๊ณ  ์ง€๋‚˜๊ฐ€๋ฉด, ํ™”๋ฉด์˜ ๋ถˆ๋Ÿ‰ ํŒ์ •์ด ๊ทธ ํ˜„์žฅ์˜ ์‚ฌ์‹ค์ด ์•„๋‹ˆ๋ผ ์šฐ๋ฆฌ ์ƒ์ˆ˜์˜ ๊ฒฐ๊ณผ๋‹ค.\n */\n const yields = await this.measuredYield(domainId, instanceId)\n if (yields?.estimator) {\n if (typeof kernel.yieldOf !== 'function') {\n console.warn(\n `[twin-engine] \"${instanceId}\": learned yield for ${Object.keys(yields.learned).length} operation kind(s) but the kernel cannot consume it ` +\n '(yieldOf missing โ€” kernel needs publishing). Yield keeps running on the declared value or the built-in constant.'\n )\n } else {\n kernel.yieldEstimator = yields.estimator\n console.log(\n `[twin-engine] \"${instanceId}\": measured yield installed โ€” ${Object.entries(yields.learned)\n .map(([k, v]) => `${k}=${Math.round(v * 1000) / 10}%(${yields.samples[k].good + yields.samples[k].scrap}๊ฑด)`)\n .join(', ')}${yields.skipped.length ? ` ยท ํ‘œ๋ณธ ๋ถ€์กฑ์œผ๋กœ ๋บ€ ์ข…๋ฅ˜: ${yields.skipped.map(s => `${s.kind}(${s.judged})`).join(', ')}` : ''}`\n )\n }\n } else if (yields?.skipped.length) {\n /* ๋ฐฐ์šด ๊ฒƒ์ด ์—†๊ณ  ๋ฒ„๋ฆฐ ๊ฒƒ๋งŒ ์žˆ์œผ๋ฉด ๊ทธ ์‚ฌ์‹ค๋„ ๋งํ•œ๋‹ค โ€” ใ€Œ์ด๋ ฅ์ด ์—†๋‹คใ€์™€ ใ€Œํ‘œ๋ณธ์ด ๋ชจ์ž๋ผ๋‹คใ€๋Š” ๋‹ค๋ฅด๋‹ค. */\n console.log(\n `[twin-engine] \"${instanceId}\": no measured yield yet โ€” samples below ${yields.minSamples}: ${yields.skipped\n .map(s => `${s.kind}(${s.judged})`)\n .join(', ')}`\n )\n }\n const learned = Object.keys(measured?.learned ?? {})\n const spread = Object.keys(measured?.spreads ?? {})\n console.log(\n `[twin-engine] \"${instanceId}\": duration estimator installed โ€” measured kinds: ${learned.length ? learned.join(',') : 'none'}` +\n ` (with observed spread: ${spread.length ? spread.join(',') : 'none'})` +\n `${travel.estimator ? `, travel from distance (speeds: ${Object.keys(travel.speedsByKind).join(',')})` : `, travel not derived (${travel.reasons.join('; ')})`}`\n )\n }\n\n /**\n * ์‹ค์ธก ์ถ”์ •๊ธฐ โ€” **์˜ˆ์ธก ์š”์ฒญ๋งˆ๋‹ค ์ €๋„์„ ๋‹ค์‹œ ์ ‘์ง€ ์•Š๋Š”๋‹ค.**\n *\n * ์˜ˆ์ธก ์ปค๋„์€ ์š”์ฒญ๋งˆ๋‹ค ์ƒˆ๋กœ ์„ธ์›Œ์ง€๊ณ (๋ฏธ๋Ÿฌ ์˜ˆ์ธกยท๋ฐฑํ…Œ์ŠคํŠธ), ํ™”๋ฉด์€ ์‹œ๊ฐ์„ ๊ธ์œผ๋ฉด ๊ณ„์† ์žฌ์˜ˆ์ธกํ•œ๋‹ค.\n * ๊ฑฐ๊ธฐ์— KPI ์กฐํšŒ๋ฅผ ๊ทธ๋Œ€๋กœ ๋‹ฌ๋ฉด ์š”์ฒญ๋‹น ์ €๋„ ์Šค์บ”์ด ํ•˜๋‚˜์”ฉ ๋ถ™๋Š”๋‹ค โ€” ์‹ค์ธก์€ ๋ถ„ ๋‹จ์œ„๋กœ ๋ฐ”๋€Œ์ง€ ์•Š์œผ๋ฏ€๋กœ\n * ์งง์€ TTL ๋กœ ์žฌ์‚ฌ์šฉํ•œ๋‹ค. ์บ์‹œ๋Š” ์ธ์Šคํ„ด์Šค๋ณ„์ด๊ณ , ๋งŒ๋ฃŒ ์ „์—๋Š” ๊ฐ™์€ ๊ฐ’์„ ์“ด๋‹ค(์˜ˆ์ธก ๊ฐ„ ์ผ๊ด€์„ฑ๋„ ์–ป๋Š”๋‹ค).\n */\n private static measuredCache = new Map<\n string,\n {\n at: number\n value: ReturnType<typeof buildMeasuredEstimator> | undefined\n /** ๊ฐ™์€ ํด๋“œ์—์„œ ๋‚˜์˜จ ์–‘ํ’ˆ๋ฅ  โ€” **์ €๋„์„ ๋‘ ๋ฒˆ ์ ‘์ง€ ์•Š๋Š”๋‹ค**(์†Œ์š”์™€ ์ˆ˜์œจ์€ ๊ฐ™์€ ์ฐฝ์˜ ๊ฐ™์€ ์‚ฌ์‹ค์ด๋‹ค). */\n yields?: ReturnType<typeof buildYieldEstimator>\n }\n >()\n private static readonly MEASURED_TTL_MS = 60_000\n /**\n * ์บ์‹œ ํ•ญ๋ชฉ ์ƒํ•œ โ€” **๋ผ์ดํ”„์‚ฌ์ดํด์ด ๋†“์นœ ๊ฒƒ๊นŒ์ง€ ๋ง‰๋Š” ๋‘ ๋ฒˆ์งธ ๋ฐฉ์–ด.**\n *\n * ์ง€์›€์€ `forgetInstance` ๊ฐ€ ํ•œ๋‹ค(๊ทธ๊ฒƒ์ด ์ฒซ ๋ฒˆ์งธ ๋ฐฉ์–ด์ด๊ณ  ์ •ํ™•ํ•œ ์ชฝ์ด๋‹ค). ๊ทธ๋Ÿฐ๋ฐ ํŠธ์œˆ์ด ์šฐ๋ฆฌ API ๋ฅผ\n * ์ง€๋‚˜์ง€ ์•Š๊ณ  ์‚ฌ๋ผ์ง€๋Š” ๊ธธ์ด ์žˆ๋‹ค: ๋„๋ฉ”์ธ(ํ…Œ๋„ŒํŠธ)์งธ๋กœ ์ง€์›Œ์ง€๊ฑฐ๋‚˜ DB ๋ฅผ ์ง์ ‘ ์†๋Œ€๋Š” ๊ฒฝ์šฐ๋‹ค. ๊ทธ๋•Œ\n * ๋‚จ์€ ํ•ญ๋ชฉ์„ ์ง€์šธ ์ฃผ์ธ์ด ์—†์œผ๋ฏ€๋กœ ์ƒํ•œ์ด ํ•„์š”ํ•˜๋‹ค.\n *\n * ๋„˜์น˜๋ฉด **๊ฐ€์žฅ ์˜ค๋ž˜ ์†๋Œ€์ง€ ์•Š์€ ๊ฒƒ**๋ถ€ํ„ฐ ๋ฒ„๋ฆฐ๋‹ค(Map ์˜ ์‚ฝ์ž… ์ˆœ์„œ๊ฐ€ ๊ณง ๊ทธ ์ˆœ์„œ๋‹ค โ€” ๊ฐ’์„ ์“ธ ๋•Œ๋งˆ๋‹ค\n * ๋‹ค์‹œ ๋„ฃ์œผ๋ฏ€๋กœ). ๋ฒ„๋ฆฌ๋Š” ๊ฒƒ์ด ์†ํ•ด๊ฐ€ ์•„๋‹Œ ์ด์œ : ์ด ๊ฐ’์€ ์บ์‹œ์ด๊ณ , ์—†์œผ๋ฉด ๋‹ค์‹œ ๊ณ„์‚ฐํ•œ๋‹ค.\n *\n * ์ˆ˜๋ฅผ ํฌ๊ฒŒ ์žก๋Š”๋‹ค โ€” ํŠธ์œˆ ๊ทœ๋ชจ๋Š” ๋Š˜ ํฌ๊ณ , ํ•ญ๋ชฉ ํ•˜๋‚˜๋Š” ์ž‘์—… ์ข…๋ฅ˜๋ณ„ ์†Œ์š” ๋ช‡ ์ค„์ด๋‹ค. ์ƒํ•œ์ด ์ž‘์œผ๋ฉด\n * ์ •์ƒ ๊ทœ๋ชจ์—์„œ ์„œ๋กœ ๋ฐ€์–ด๋‚ด๋ฉฐ ์บ์‹œ๊ฐ€ ๋ฌด์˜๋ฏธํ•ด์ง„๋‹ค(๊ทธ๊ฒŒ ๋” ๋‚˜์˜๋‹ค: ์กฐ์šฉํžˆ ๋А๋ ค์ง„๋‹ค).\n */\n private static readonly MEASURED_MAX = 5_000\n\n /** ์ด ํŠธ์œˆ์ด ์ด๋ ฅ์—์„œ ๋ฐฐ์šด ์–‘ํ’ˆ๋ฅ  โ€” ์†Œ์š”์™€ **๊ฐ™์€ ํด๋“œยท๊ฐ™์€ ์บ์‹œ**์—์„œ ์˜จ๋‹ค(์ €๋„์„ ๋‘ ๋ฒˆ ์ ‘์ง€ ์•Š๋Š”๋‹ค). */\n private static async measuredYield(domainId: string, instanceId: string) {\n await this.measuredEstimator(domainId, instanceId)\n return this.measuredCache.get(runtimeKey(domainId, instanceId))?.yields\n }\n\n private static async measuredEstimator(domainId: string, instanceId: string) {\n /* ํ‚ค๋Š” `runtimeKey` ํ•˜๋‚˜๋กœ โ€” ์†์œผ๋กœ ์กฐ๋ฆฝํ•˜๋ฉด ์ง€์šฐ๋Š” ์ชฝ๊ณผ ์–ด๊ธ‹๋‚˜ ๋ชป ์ง€์šฐ๋Š” ํ•ญ๋ชฉ์ด ์ƒ๊ธด๋‹ค. */\n const key = runtimeKey(domainId, instanceId)\n const hit = this.measuredCache.get(key)\n if (hit && Date.now() - hit.at < this.MEASURED_TTL_MS) return hit.value\n let value: ReturnType<typeof buildMeasuredEstimator> | undefined\n let yields: ReturnType<typeof buildYieldEstimator> | undefined\n try {\n /* ์ž‘์—… ์ข…๋ฅ˜๋ณ„ ์‹ค์ธก โ€” ์ฐฝ์€ ๋„‰๋„‰ํžˆ(ํ•˜๋ฃจ) ๋‘๊ณ  ํ‘œ๋ณธ์ด ๋ชจ์ž๋ž€ ์ข…๋ฅ˜๋Š” ์ถ”์ •๊ธฐ๊ฐ€ ์Šค์Šค๋กœ ๋บ€๋‹ค. */\n const kpi: any = await computeTwinKpi({ domainId, instanceId, windowMinutes: 24 * 60, groupBy: 'taskKind' })\n value = buildMeasuredEstimator(kpi?.groups?.items, {})\n /* ๊ฐ™์€ ๊ทธ๋ฃน์—์„œ ์–‘ํ’ˆ๋ฅ ๋„ ๋ฐฐ์šด๋‹ค โ€” ํ•œ ๋ฒˆ ์ ‘์€ ์ €๋„์„ ๋‘˜์ด ๋‚˜๋ˆ  ์“ด๋‹ค. */\n yields = buildYieldEstimator(kpi?.groups?.items, {})\n } catch (err) {\n console.warn(`[twin-engine] \"${instanceId}\": measured duration lookup failed โ€” falling back to declared/default durations.`, (err as any)?.message)\n }\n /* ๋‹ค์‹œ ๋„ฃ์–ด **์ตœ๊ทผ ์“ด ๊ฒƒ**์œผ๋กœ ๋งŒ๋“ ๋‹ค โ€” ์‚ฝ์ž… ์ˆœ์„œ๊ฐ€ ๊ณง ๋ฒ„๋ฆด ์ˆœ์„œ์ด๋ฏ€๋กœ ์ด ํ•œ ์ค„์ด LRU ๋ฅผ ๋งŒ๋“ ๋‹ค. */\n this.measuredCache.delete(key)\n this.measuredCache.set(key, { at: Date.now(), value, yields })\n if (this.measuredCache.size > this.MEASURED_MAX) {\n const oldest = this.measuredCache.keys().next()\n if (!oldest.done) this.measuredCache.delete(oldest.value)\n }\n return value\n }\n\n /**\n * **์›๋ณธ์ด ์„ ์–ธํ•œ ์ž๊ทน์„ ์‹ฃ๋Š”๋‹ค** โ€” ์žฌ๊ธฐ๋™ํ•ด๋„ ์‚ด์•„ ์žˆ๊ฒŒ (2026-08-19).\n *\n * โ”€โ”€ ๋ฌด์—‡์ด ๋‚ฌ๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๋ฐ๋ชจ์˜ ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ์‹œ๋“œ ์ฝ”๋“œ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์—๋งŒ ์‹ค์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํŠธ์œˆ์„ ์žฌ๊ธฐ๋™ํ•˜๋ฉด ์ž๊ทน์ด ์‚ฌ๋ผ์ง€๊ณ  ๊ตฌ์กฐ๋งŒ\n * ์„œ ์žˆ๋Š” ํŠธ์œˆ์ด ๋‚จ์•˜๋‹ค(์ž‘์—… 0ยท์˜ค๋” 0) โ€” ใ€Œ์‚ด์•„ ์žˆ๋Š” ๋ฐ๋ชจใ€๊ฐ€ **์ฒซ ์žฌ๊ธฐ๋™๊นŒ์ง€๋งŒ** ์‚ด์•˜๋‹ค.\n *\n * ์ž๊ทน์˜ ์ง‘์€ **์›๋ณธ**์ด๋‹ค(`TwinReference.connectionConfig.scenario`, ADR-0029 ยท\n * `plans/simulator-as-source.md` ยง4): ๋ฌด์—‡์ด ๋“ค์–ด์˜ค๊ณ  ๋ฌด์Šจ ์ฃผ๋ฌธ์ด ๋‚˜๋Š”์ง€๋Š” ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ๊ฐ€ ์ •ํ•˜๋Š” ์‚ฌ์‹ค์ด๊ณ \n * ํŠธ์œˆ์€ ๋ฐ˜์˜ํ•œ๋‹ค. ํŠธ์œˆ์— ์ƒˆ ์ถ•์„ ๋งŒ๋“ค๋ฉด ADR-0029 ๊ฐ€ ๊ฑท์–ด๋‚ด์•ผ ํ•  ํ‘œ๋ฉด์ด ํ•˜๋‚˜ ๋Š˜์–ด๋‚œ๋‹ค.\n *\n * ํŒ์ •์€ ์ˆœ์ˆ˜ ํ•จ์ˆ˜๊ฐ€ ํ•œ๋‹ค(`planStimulus`) โ€” ๋ฏธ๋Ÿฌ์— ์‹ฃ์ง€ ์•Š๊ณ , ๊ฒ€์‚ฌ๋ฅผ ํ†ต๊ณผํ•˜์ง€ ๋ชปํ•œ ์„ ์–ธ์€ ํƒœ์šฐ์ง€ ์•Š๊ณ \n * (๊ทธ ์ด๋ ฅ์ด ์žˆ๋‹ค: ์ž˜๋ชป๋œ ์„ ์–ธ ํ•˜๋‚˜๊ฐ€ ๋‹ค์Œ ํ‹ฑ์—์„œ ์„œ๋ฒ„๋ฅผ ๋‚ด๋ ธ๋‹ค), ๋ชป ์‹ค์€ ์ด์œ ๋Š” **๋งํ•œ๋‹ค.**\n */\n private static async installStimulus(domainId: string, instanceId: string, inst: InstanceRuntime): Promise<void> {\n let config: any\n try {\n const ref = await getRepository(TwinReference).findOne({ where: { domain: { id: domainId }, source: instanceId } })\n config = ref?.connectionConfig\n } catch (err: any) {\n console.warn(`[twin-engine] \"${instanceId}\": could not read the declared stimulus โ€” ${err?.message ?? err}`)\n return\n }\n const plan = planStimulus(config, { hasScenarioEngine: !!inst.runtime?.scenario, mode: inst.mode }, validateScenario as any)\n if (plan.action === 'skip') {\n /* ์„ ์–ธ์ด ์—†๋Š” ๊ฒƒ์€ ์ •์ƒ์ด๋ฏ€๋กœ ์กฐ์šฉํžˆ ์ง€๋‚œ๋‹ค. ๋‚˜๋จธ์ง€ ์…‹์€ **๋งํ•œ๋‹ค** โ€” ์„ ์–ธํ–ˆ๋Š”๋ฐ ์•ˆ ์‹ค๋ฆฐ ์ƒํƒœ๋‹ค. */\n if (plan.reason !== 'none') {\n console.warn(\n `[twin-engine] \"${instanceId}\": a stimulus is declared on its source but was not loaded (${plan.reason}${plan.detail ? `: ${plan.detail}` : ''}).` +\n (plan.reason === 'observed' ? ' This twin runs on observation โ€” we do not manufacture arrivals for it.' : '')\n )\n }\n return\n }\n try {\n inst.runtime!.scenario.load(plan.scenario)\n inst.runtime!.scenario.start()\n const kinds = (plan.scenario.generators ?? []).map((g: any) => g?.kind).filter(Boolean)\n console.log(`[twin-engine] \"${instanceId}\": stimulus from its source started โ€” ${kinds.length ? kinds.join(', ') : 'no generators'}.`)\n } catch (err: any) {\n console.warn(`[twin-engine] \"${instanceId}\": the declared stimulus was rejected at load โ€” ${err?.message ?? err}`)\n }\n }\n\n /**\n * ์ž๊ทน์„ **์›๋ณธ์— ์„ ์–ธํ•œ๋‹ค** โ€” ํ”„๋กœ๋น„์ €๋‹ยท๋ฐ๋ชจ ์‹œ๋“œ๊ฐ€ ๋ถ€๋ฅด๋Š” ๋ฌธ.\n *\n * ํŠธ์œˆ์ด ์•„๋‹ˆ๋ผ ์›๋ณธ์— ์ ๋Š” ์ด์œ ๋Š” ์œ„์™€ ๊ฐ™๋‹ค(ADR-0029). ์›๋ณธ ํ–‰์ด ์—†์œผ๋ฉด ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค โ€” ์–ด๋–ค ์›๋ณธ์—์„œ\n * ์˜จ ํŠธ์œˆ์ธ์ง€ ๋ชจ๋ฅด๋Š” ์ฑ„ ์ž๊ทน์„ ์ง€์–ด ๋ถ™์ด๋ฉด, ๊ทธ ์ž๊ทน์ด ์–ด๋””์„œ ์™”๋Š”์ง€ ์•„๋ฌด๋„ ๋˜์งš์„ ์ˆ˜ ์—†๋‹ค.\n */\n static async declareStimulus(domainId: string, instanceId: string, scenario: any): Promise<boolean> {\n const repo = getRepository(TwinReference)\n const ref = await repo.findOne({ where: { domain: { id: domainId }, source: instanceId } })\n if (!ref) {\n console.warn(`[twin-engine] \"${instanceId}\": no source reference โ€” a stimulus has nowhere to be declared.`)\n return false\n }\n ref.connectionConfig = withStimulus(ref.connectionConfig, scenario)\n await repo.save(ref)\n return true\n }\n\n /**\n * ์ด ํŠธ์œˆ์ด **์ด๋ ฅ์—์„œ ์‹œ๊ฐ„์„ ๋ฐฐ์šด ์ž‘์—… ์ข…๋ฅ˜๋“ค** โ€” ์žฌ๊ธฐ๋™์—๋„ ๋‚จ๋Š” ๊ทผ๊ฑฐ.\n *\n * โ”€โ”€ ์™œ ํ•„์š”ํ•œ๊ฐ€ (2026-08-18 ์‹ค์ธก) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ปค๋„์˜ ์ž๊ธฐ๋ณด๊ณ (`specCoverage()`)๋Š” **์ž‘์—…์ด ์ƒˆ๋กœ ์ƒ๊ธธ ๋•Œ** ์ฑ„์›Œ์ง„๋‹ค. ๊ทธ๋ž˜์„œ ์žฌ๊ธฐ๋™ ์งํ›„์—๋Š” ์ด๋ ฅ์ด\n * ํ’๋ถ€ํ•œ ํŠธ์œˆ์—์„œ๋„ ๋ชฉ๋ก์ด ๋น„๊ณ , ใ€Œ์ด ํŠธ์œˆ์ด ๋ฌด์Šจ ๊ณต์ •์„ ๋Œ๋ฆฌ๋‚˜ใ€ ํ™”๋ฉด์ด ๋นˆ์นธ์ด ๋œ๋‹ค โ€” ๊ฐ’์„ ์ฑ„์šธ ๊ณณ์„\n * ๋ณด์—ฌ์•ผ ํ•˜๋Š” ํ™”๋ฉด์ด ์ •์ž‘ ๊ทธ๋•Œ ์•„๋ฌด ๋ง๋„ ๋ชป ํ•œ๋‹ค.\n *\n * ๊ทธ ๋นˆ์นธ์„ ์ด๋ ฅ๋กœ ๋ฉ”์šด๋‹ค: ์ €๋„์—์„œ ๋ฐฐ์šด ์ข…๋ฅ˜๋Š” **์ถ”์ •๊ธฐ๊ฐ€ ์ด๋ฏธ ๋‹ตํ•  ์ˆ˜ ์žˆ๋Š” ์ข…๋ฅ˜**์ด๋ฏ€๋กœ, ์ง€์–ด๋‚ด๋Š”\n * ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์žˆ๋Š” ์‚ฌ์‹ค์„ ๊บผ๋‚ด๋Š” ๊ฒƒ์ด๋‹ค. ๊ฐ™์€ ์บ์‹œ(60์ดˆ)๋ฅผ ์“ฐ๋ฏ€๋กœ ์กฐํšŒ๋งˆ๋‹ค ์ €๋„์„ ๋‹ค์‹œ ์ ‘์ง€ ์•Š๋Š”๋‹ค.\n */\n static async measuredOperationKinds(domainId: string, instanceId: string): Promise<string[]> {\n const measured = await this.measuredEstimator(domainId, instanceId)\n return Object.keys((measured as any)?.learned ?? {})\n }\n\n /**\n * ์ง€๊ธˆ ์ด ํŠธ์œˆ์ด ์–ด๋–ค ๋ชจ๋ธ๋กœ ๊ตด๋Ÿฌ๊ฐ€๋Š”๊ฐ€ โ€” ์˜ˆ์ธก ์ถœ๋ ฅ ๋ณด์ •์ด **์ž๊ธฐ๊ฐ€ ๋ฐฐ์šด ๋ชจ๋ธ**์—๋งŒ ์ ์šฉ๋˜๋„๋ก\n * ๋น„๊ตํ•˜๋Š” ์ง€๋ฌธ. ์žฌ๋ฃŒ๋Š” ํ˜ธ์ŠคํŠธ๊ฐ€ ์•„๋Š” ๊ฒƒ(์‹ค์ธกยท์†๋„ยท์„ ์–ธ ๋ช…์„ธ)์ด๋ผ ์ปค๋„ ๋ฐœํ–‰ ์ƒํƒœ์™€ ๋ฌด๊ด€ํ•˜๋‹ค.\n * ์‹คํŒจํ•˜๋ฉด undefined โ€” ๊ทธ๋•Œ๋Š” ๋น„๊ต๋ฅผ ํ•˜์ง€ ์•Š๋Š”๋‹ค(๋ชจ๋ฅด๋Š” ๊ฒƒ์„ ๊ทผ๊ฑฐ๋กœ ๋ณด์ •์„ ๋Š์ง€ ์•Š๋Š”๋‹ค).\n */\n static async modelBasis(domainId: string, instanceId: string): Promise<ModelBasis | undefined> {\n try {\n const reg = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n const model: any = reg?.model\n const measured = await this.measuredEstimator(domainId, instanceId)\n const travel = buildTravelEstimator({ layout: model?.layout, equipment: model?.equipment, unit: model?.unit })\n return { measured: measured?.learned, speeds: travel.speedsByKind, declared: model?.operations }\n } catch {\n return undefined\n }\n }\n\n /**\n * **์ด ํŠธ์œˆ์ด ํ•˜๋ฃจ ๋ช‡ ๋Œ€๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ๋Š”๊ฐ€** โ€” ์‹คํ–‰ํ•ด ๋ณด์ง€ ์•Š๊ณ  ๋‹ตํ•œ๋‹ค.\n *\n * ๊ณ„์‚ฐ์€ ์ปค๋„์ด ์ž๊ธฐ ์ƒํƒœ์—์„œ ํ•œ๋‹ค(`kernel.capacity`). ์—ฌ๊ธฐ์„œ ํ•˜๋Š” ์ผ์€ **๊ธฐ์ค€ ์ฃผ๋ฅผ ์ •ํ•ด ์ฃผ๋Š”\n * ๊ฒƒ**๋ฟ์ด๋‹ค: ๊ณตํœด์ผ์ด ์—†๋Š” ํ‰์ƒ์ฃผ์—ฌ์•ผ ํ•œ๋‹ค โ€” ๊ณตํœด์ผ์€ ์—ฐ๊ฐ„ ๊ฐ€์šฉ๋Ÿ‰์„ ๋”ฐ๋กœ ๊นŽ์ง€, ์ด ๊ณต์žฅ์˜ ํ‰์ƒ์‹œ\n * ์ƒํ•œ์„ ์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ปค๋„์ด ์ž„์˜๋กœ ๊ณ ๋ฅด๊ฒŒ ๋‘๋ฉด ๊ทธ ์ฃผ์— ๊ณตํœด์ผ์ด ๋ผ์—ˆ์„ ๋•Œ ์ƒํ•œ์ด ์กฐ์šฉํžˆ ๋‚ฎ์•„์ง„๋‹ค.\n *\n * ํŠธ์œˆ์ด ๊ธฐ๋™ ์ค‘์ด ์•„๋‹ˆ๋ฉด `undefined` ๋‹ค โ€” 0 ์ด ์•„๋‹ˆ๋‹ค. ๊ธฐ๋™ํ•˜์ง€ ์•Š์€ ํŠธ์œˆ์˜ ์ƒํ•œ์„ 0 ์ด๋ผ๊ณ  ๋‹ตํ•˜๋ฉด ํ™”๋ฉด์€\n * \"์ด ๊ณต์žฅ์€ ์•„๋ฌด๊ฒƒ๋„ ๋ชป ๋งŒ๋“ ๋‹ค\" ๊ณ  ๋งํ•œ๋‹ค.\n */\n static async capacity(\n domainId: string,\n target: { instanceId?: string; spaceId?: string },\n unitsPerDay: number,\n sampleWeekStartMs: number\n ): Promise<{ instanceId: string; kind?: string; analysis?: any; reason?: 'not-running' | 'no-operations' }[]> {\n /* ๋Œ€์ƒ์€ **๋“ฑ๋ก๋ถ€**๊ฐ€ ์ •ํ•œ๋‹ค โ€” ๊ธฐ๋™ ์ค‘์ธ ๋Ÿฐํƒ€์ž„๋งŒ ํ›‘์œผ๋ฉด \"์•ˆ ๋–  ์žˆ์–ด์„œ ์•ˆ ๋ณด์ด๋Š” ๊ฒƒ\" ๊ณผ \"์—†๋Š” ๊ฒƒ\" ์ด\n ๊ตฌ๋ณ„๋˜์ง€ ์•Š๋Š”๋‹ค. ํ™”๋ฉด์€ ๊ทธ ๋‘˜์„ ๋‹ค๋ฅด๊ฒŒ ๋งํ•ด์•ผ ํ•œ๋‹ค. */\n const where: any = { domain: { id: domainId } }\n if (target.instanceId) where.instanceId = target.instanceId\n else where.spaceId = target.spaceId\n const registered = await getRepository(TwinInstance).find({ where })\n\n return registered.map(reg => {\n const rt = this.instances[runtimeKey(domainId, reg.instanceId)]\n const kernel: any = rt?.kernel // ํ‚ค์— ๋„๋ฉ”์ธ์ด ์žˆ์œผ๋ฏ€๋กœ ๋‚จ์˜ ๋Ÿฐํƒ€์ž„์„ ์ง‘์„ ์ˆ˜ ์—†๋‹ค\n if (typeof kernel?.capacity !== 'function') return { instanceId: reg.instanceId, kind: reg.kind, reason: 'not-running' as const }\n\n const analysis = kernel.capacity({ unitsPerDay, sampleWeekStartMs })\n /* ๊ณต์ •์„ ์„ ์–ธํ•˜์ง€ ์•Š์€ ํŠธ์œˆ(๋Œ€๊ฐœ YMSยทWMS)์€ **ํŒ์ • ๋Œ€์ƒ์ด ์•„๋‹ˆ๋‹ค.** 0 ์œผ๋กœ ์ฑ„์›Œ ๋„ฃ์œผ๋ฉด\n \"์•ผ๋“œ๊ฐ€ ๋ณ‘๋ชฉ\" ์ด๋ผ๋Š” ์—†๋Š” ์‚ฌ์‹ค์ด ์ƒ๊ธด๋‹ค โ€” ์žด ๊ฒƒ์ด ์—†๋‹ค๊ณ  ๋งํ•œ๋‹ค. */\n if (!analysis?.operations?.length) return { instanceId: reg.instanceId, kind: reg.kind, reason: 'no-operations' as const }\n return { instanceId: reg.instanceId, kind: reg.kind, analysis }\n })\n }\n\n /**\n * **์ƒ์‚ฐ ๋Šฅ๋ ฅ ๋ณด๊ณ ์„œ** โ€” ISA-95 Part 4 `OperationsCapability`. ๊ตฌ๊ฐ„์˜ ์–‘์„ ์ข…๋ฅ˜๋กœ ๊ตฌ๋ถ„ํ•œ๋‹ค\n * (์•ฝ์ •ยท๊ฐ€์šฉยท๋‹ฌ์„ฑ๋ถˆ๊ฐ€). ์šฉ๋Ÿ‰(`capacity`)์€ ๋น„์œจ์„ ๋‚ด๊ณ  ์ด๊ฒƒ์€ **๊ตฌ๊ฐ„์˜ ์–‘**์„ ๋‚ธ๋‹ค.\n *\n * ๋Œ€์ƒ ์„ ์ •ยท๊ฑฐ์ ˆ ์‚ฌ์œ ๋Š” `capacity` ์™€ **๊ฐ™์€ ๊ทœ์œจ**์ด๋‹ค: ๋“ฑ๋ก๋ถ€๊ฐ€ ๋Œ€์ƒ์„ ์ •ํ•˜๊ณ (์•ˆ ๊ธฐ๋™ ์ค‘์ธ ๊ฒƒ๊ณผ\n * ์—†๋Š” ๊ฒƒ์„ ๊ตฌ๋ณ„ํ•œ๋‹ค), ๊ณต์ •์„ ์„ ์–ธํ•˜์ง€ ์•Š์€ ํŠธ์œˆ์€ ํŒ์ • ๋Œ€์ƒ์ด ์•„๋‹ˆ๋ผ๊ณ  ๋งํ•œ๋‹ค(0 ์œผ๋กœ ์ฑ„์šฐ๋ฉด\n * \"์•ผ๋“œ๊ฐ€ ๋ณ‘๋ชฉ\" ์ด๋ผ๋Š” ์—†๋Š” ์‚ฌ์‹ค์ด ์ƒ๊ธด๋‹ค).\n */\n static async operationsCapability(\n domainId: string,\n target: { instanceId?: string; spaceId?: string },\n unitsPerDay: number,\n sampleWeekStartMs: number,\n window: { fromTime: string; toTime: string }\n ): Promise<{ instanceId: string; kind?: string; report?: any; reason?: 'not-running' | 'no-operations' }[]> {\n const where: any = { domain: { id: domainId } }\n if (target.instanceId) where.instanceId = target.instanceId\n else where.spaceId = target.spaceId\n const registered = await getRepository(TwinInstance).find({ where })\n\n return registered.map(reg => {\n const rt = this.instances[runtimeKey(domainId, reg.instanceId)]\n const kernel: any = rt?.kernel\n if (typeof kernel?.operationsCapability !== 'function') {\n return { instanceId: reg.instanceId, kind: reg.kind, reason: 'not-running' as const }\n }\n const report = kernel.operationsCapability({ unitsPerDay, sampleWeekStartMs, window })\n if (!report?.perOperation?.length) return { instanceId: reg.instanceId, kind: reg.kind, reason: 'no-operations' as const }\n return { instanceId: reg.instanceId, kind: reg.kind, report }\n })\n }\n\n /**\n * ๋ฏธ๋Ÿฌ ๊ธฐ๋™์˜ ์—ฐ์†์„ฑ ์”จ์•— โ€” ์ด์–ด๋ฐ›์€ ๊ฒƒ์€ **๋งํ•œ๋‹ค**(์กฐ์šฉํžˆ ์ž‡์ง€ ์•Š๋Š”๋‹ค).\n *\n * ์ปค๋„์ด ๊ทธ ๋ฌธ์„ ์—ด์–ด ๋‘์ง€ ์•Š์•˜์œผ๋ฉด ๊ทธ ์‚ฌ์‹ค๋„ ๋งํ•œ๋‹ค: ๊ทธ ํŠธ์œˆ์€ ์žฌ๊ธฐ๋™๋งˆ๋‹ค ์—ด๋ฆฐ ๊ตฌ๊ฐ„์„ ์žƒ๋Š”๋‹ค.\n */\n private static seedLiveContinuity(domainId: string, id: string, kernel: any): void {\n const cached = this.recovered[runtimeKey(domainId, id)]?.state\n if (!cached) return\n const plan = planLiveContinuity(cached)\n if (!plan.ackedCount && !plan.attentionSinceCount && !plan.energy) return\n if (typeof kernel.hydrateContinuity !== 'function') {\n console.warn(\n `[twin-engine] kernel for \"${id}\" cannot carry continuity (no hydrateContinuity) โ€” the open demand window, ` +\n 'its peak and the attention start times are lost on every restart.'\n )\n return\n }\n try {\n kernel.hydrateContinuity(plan.seed)\n } catch (err: any) {\n /* ์ด์–ด๋ฐ›๊ธฐ๊ฐ€ ์‹คํŒจํ•ด๋„ ๋ฏธ๋Ÿฌ๋Š” ๋Œ์•„์•ผ ํ•œ๋‹ค โ€” ๋‹ค๋งŒ ๋ฌด์—‡์„ ์žƒ์—ˆ๋Š”์ง€ ๋งํ•œ๋‹ค. */\n console.warn(`[twin-engine] continuity seed failed for \"${id}\" โ€” starting without it: ${err?.message ?? err}`)\n return\n }\n const carried = [\n ...(plan.energy ? ['energy accumulation (open window, totalizer baselines, peak)'] : []),\n ...(plan.ackedCount ? [`${plan.ackedCount} acknowledged attention(s)`] : []),\n ...(plan.attentionSinceCount ? [`${plan.attentionSinceCount} attention start time(s)`] : [])\n ].join(', ')\n console.log(`[twin-engine] mirror \"${id}\" carried over ${carried} โ€” observation axes come from the source.`)\n }\n\n static start(id: string, domainId: string, kind: string, model: TwinModelDef, restartPolicy?: RestartPolicy, purpose?: string, resumeFrom?: number): InstanceRuntime {\n const key = runtimeKey(domainId, id)\n if (this.instances[key]) return this.instances[key]\n\n const Kernel = kernelFor(kind)\n const kernel: TwinKernel = new Kernel(domainId, undefined, this.productionSpecOf(model))\n kernel.loadTwinModel(model) // ๊ตฌ์กฐ๋งŒ. ์ƒํƒœ๋Š” ์•„๋ž˜ ์›œ์Šคํƒ€ํŠธ๊ฐ€ ์ฃผ์ž…ํ•œ๋‹ค.\n this.applyOperations(kernel, model, id) // ์‹œ๊ฐ„ยท์ˆ˜์œจ ๋ช…์„ธ(์žˆ์œผ๋ฉด) โ€” ์—†์œผ๋ฉด ์ปค๋„ ๊ธฐ๋ณธ๊ฐ’\n /* ์ถ”์ •๊ธฐ๋Š” DB ์กฐํšŒ๋ฅผ ํฌํ•จํ•ด ๋น„๋™๊ธฐ โ€” ๊ธฐ๋™์„ ๋ง‰์ง€ ์•Š๊ณ  ๋ถ™๋Š”๋‹ค(๋ถ™๊ธฐ ์ „ ์ž‘์—…์€ ๋ช…์„ธยท์ƒ์ˆ˜๋กœ ์‚ฐ์ถœ). */\n this.installEstimators(kernel, domainId, id, model).catch(err => console.warn('[twin-engine] estimator install failed', err?.message))\n this.warmStart(domainId, id, kernel, purpose)\n /*\n * **๋ฒˆํ˜ธ๋ฅผ ์ด์–ด ์„ผ๋‹ค** โ€” ์ €๋„์— ์ด๋ฏธ ์žˆ๋Š” ๋ฒˆํ˜ธ์™€ ๊ฒน์น˜์ง€ ์•Š๊ฒŒ.\n *\n * ์ €๋„์ด ๋น„์–ด ์žˆ์œผ๋ฉด(0) ์•„๋ฌด ์ผ๋„ ์•ˆ ํ•œ๋‹ค. ๋น„์–ด ์žˆ์ง€ ์•Š์€๋ฐ 0๋ถ€ํ„ฐ ๋‹ค์‹œ ์„ธ๋ฉด ๊ฐ™์€ ํŠธ์œˆ์— ๊ฐ™์€\n * ๋ฆฌ๋น„์ „์ด ๋‘˜ ์ƒ๊ธฐ๊ณ , ์žฌ์ƒ ์ˆœ์„œ๊ฐ€ ๋’ค์„ž์ด๋ฉฐ, ์‹œ๊ฐ„์—ฌํ–‰์ด ์—‰๋šฑํ•œ ์‹œ์ ์„ ๋‹ตํ•œ๋‹ค โ€” ์˜ค๋ฅ˜๋Š” ์•ˆ ๋‚œ๋‹ค.\n */\n if (resumeFrom && typeof (kernel as any).resumeRevision === 'function') (kernel as any).resumeRevision(resumeFrom)\n /*\n * โ”€โ”€ ์ด ํŠธ์œˆ์˜ ์‹œ๊ณ„๋ฅผ **์ง€๊ธˆ**์— ๋งž์ถ˜๋‹ค (2026-08-15) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ปค๋„์˜ ๊ธฐ๋ณธ ๊ธฐ์ค€์ ์€ ์ƒ์ˆ˜(2026-01-01)๋‹ค. ๊ทธ๋Œ€๋กœ ๋‘๋ฉด ์‹œ๋ฎฌ ํŠธ์œˆ์˜ ์ €๋„ ์‹œ๊ฐ์ด **์žฌ๊ธฐ๋™๋งˆ๋‹ค\n * ๋˜๊ฐ๊ฒจ** ๋ฉฐ์น  ์น˜ ์‚ฌ๊ฑด์ด ์ „๋ถ€ ๊ฐ™์€ ๋ถ„์— ๋ชฐ๋ฆฐ๋‹ค โ€” ใ€Œ์–ธ์ œ ์žˆ์—ˆ๋˜ ์ผ์ธ๊ฐ€ใ€๋ฅผ ๋˜์งš์„ ์ˆ˜ ์—†๊ณ ,\n * ์‹ค ์‹œ๊ฐ์œผ๋กœ ์ฐฝ์„ ์ž๋ฅด๋Š” ์„ฑ๊ณผยท์ด๋ ฅ ์งˆ์˜์—๋Š” ๊ทธ ํŠธ์œˆ์ด ์•„์˜ˆ ๋ณด์ด์ง€ ์•Š๋Š”๋‹ค.\n *\n * ์žฌ๊ธฐ๋™ํ•˜๋ฉด ๊ทธ๋งŒํผ ์‹œ๊ณ„๊ฐ€ ์•ž์œผ๋กœ ๋›ฐ๋Š”๋ฐ, ๊ทธ๊ฒƒ์ด ์‚ฌ์‹ค์ด๋‹ค: ๊ทธ ์‚ฌ์ด ์ด ํŠธ์œˆ์€ ๋Œ์ง€ ์•Š์•˜๊ณ \n * ์ €๋„์˜ ๋นˆ ๊ตฌ๊ฐ„์ด ๊ทธ ์‚ฌ์‹ค์„ ๋งํ•œ๋‹ค.\n */\n kernel.setClockOrigin?.(Date.now())\n const runtime: TwinRuntimeType = new TwinRuntime(kernel)\n\n /* subscribe ๋Š” RuntimeSubscription({ unsubscribe() }) ๋ฐ˜ํ™˜ โ†’ () => void ๋กœ ๊ฐ์Œˆ. */\n /*\n * **๋ชจ๋“œ๋ฅผ ์ ์–ด ๋‘”๋‹ค** (2026-08-18 ์‹ค์ธก์œผ๋กœ ๊ณ ์นจ).\n *\n * ์‹œ๋ฎฌ ๊ฒฝ๋กœ๋Š” `mode` ๋ฅผ ๋น„์›Œ ๋‘์—ˆ๊ณ (ใ€Œ๋ฏธ์ง€์ •=simใ€์ด๋ผ๋Š” ๊ทœ์•ฝ์— ๊ธฐ๋Œ€), ๋ผ์ด๋ธŒ๋งŒ ์ ์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ\n * `modeOf()` ๊ฐ€ **๋„๋Š” ์‹œ๋ฎฌ๋ ˆ์ด์…˜์— undefined** ๋ฅผ ๋‹ตํ–ˆ๊ณ , ์„ ์–ธยท์ฒ ํšŒ์˜ ๋‹ต์ด ใ€Œ์ €์žฅํ–ˆ๋‹คใ€๋กœ ๋‚˜๊ฐ”๋‹ค โ€”\n * ์‹ค์ œ๋กœ๋Š” ๋„๋Š” ์ปค๋„์ด ์˜› ์ˆ˜๋ฅผ ๊ทธ๋Œ€๋กœ ์“ฐ๊ณ  ์žฌ๊ธฐ๋™ ๋•Œ ๋ฐ›๋Š”๋ฐ, ๊ทธ ์‚ฌ์‹ค์ด ๋‹ต์—์„œ ์‚ฌ๋ผ์ง„ ๊ฒƒ์ด๋‹ค.\n * ๊ทœ์•ฝ์— ๊ธฐ๋Œ€๋Š” ๋Œ€์‹  ์‚ฌ์‹ค์„ ์ ๋Š”๋‹ค: ใ€Œ๋Œ๊ณ  ์žˆ๋‚˜ใ€๋ฅผ ๋ฌป๋Š” ์ชฝ์ด ๊ทธ ๋‹ต์„ ๋ฐ›์•„์•ผ ํ•œ๋‹ค.\n */\n const inst: InstanceRuntime = {\n id,\n domainId,\n mode: 'sim',\n runtime,\n kernel,\n /* ์ •์ฑ…์€ ๋ถ€๋ฅด๋Š” ์ชฝ์ด ์„ ์–ธํ•œ๋‹ค โ€” ์—ฌ๊ธฐ์„œ ๊ณ ๋ฅด๋ฉด ๊ฐ™์€ ํŠธ์œˆ์ด ๋ถ€๋ฅด๋Š” ์ž๋ฆฌ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ์žฌ๊ธฐ๋™ํ•œ๋‹ค. */\n restartPolicy: readRestartPolicy(restartPolicy, `start(\"${id}\")`),\n spaceId: (model as any)?.spaceId,\n unsub: () => {}\n }\n this.instances[key] = inst\n /* ๋‹ค์‹œ ์„ธ์› ์œผ๋ฏ€๋กœ ์ง€๋‚œ ์ •์ง€ ์ด์œ ๋Š” ์‚ฌ์‹ค์ด ์•„๋‹ˆ๋‹ค โ€” ๋‚จ๊ฒจ ๋‘๋ฉด ๋„๋Š” ํŠธ์œˆ์ด ใ€Œ๊ตถ๊ฒจ์„œ ๋ฉˆ์ท„๋‹คใ€๊ณ  ๋งํ•œ๋‹ค. */\n this.stopNotes.delete(key)\n delete this.recovered[key] // ์›œ์Šคํƒ€ํŠธ๋กœ ์ปค๋„์— ์˜ฎ๊ฒจ ์‹ฌ์—ˆ๋‹ค โ€” ์ด์ œ ๋ผ์ด๋ธŒ๊ฐ€ ์ง„์‹ค์ด๋‹ค.\n /* ์›๋ณธ์ด ์„ ์–ธํ•œ ์ž๊ทน โ€” ๊ธฐ๋™์„ ๋ง‰์ง€ ์•Š๋Š”๋‹ค(์ถ”์ •๊ธฐ์™€ ๊ฐ™์€ ๊ทœ์œจ). ๋ชป ์‹ค์—ˆ์œผ๋ฉด ๊ทธ ์‚ฌ์‹ค์„ ๋งํ•œ๋‹ค. */\n this.installStimulus(domainId, id, inst).catch(err => console.warn(`[twin-engine] \"${id}\": stimulus install failed โ€” ${err?.message ?? err}`))\n\n /* ๋ผ์ด๋ธŒ ๋ฐ”์ธ๋”ฉ(P3): data ์ฑ„๋„ ํ•„ํ„ฐ๊ฐ€ subdomain ์„ ๋ณด๋ฏ€๋กœ Domain ๊ฐ์ฒด๋ฅผ 1ํšŒ ํ•ด์„ํ•ด ๋‘”๋‹ค. */\n getRepository(Domain).findOne({ where: { id: domainId } }).then(d => (inst.domain = d)).catch(() => {})\n\n /* State ์ฑ„๋„: runtime.subscribe(snapshotโ†’deltaโ†’clock) โ†’ pubsub ๋ฐฉ์†ก(๊ตฌ๋… ๋ฆฌ์กธ๋ฒ„๊ฐ€ instanceId ํ•„ํ„ฐ). */\n const sub = runtime.subscribe((msg: SubscriptionMessage) => {\n this.publishGuarded(\n 'twin-state',\n { twinState: { instanceId: id, kind: msg.kind, revision: (msg as any).revision, payload: msg } },\n `twin-state:${id}`\n )\n /* ์˜์† + ๋ผ์ด๋ธŒ ๋ฐ”์ธ๋”ฉ ๋ธŒ๋ฆฌ์ง€: delta ๋งˆ๋‹ค ์ €๋„ ์ €์žฅ + ์—”ํ‹ฐํ‹ฐ๋ณ„ data(tag:) publish โ†’ ๋ณด๋“œ ์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ. */\n if (msg.kind === 'delta') {\n this.persist(domainId, id, msg).catch(err => console.error('twin persist fail', err))\n /*\n * โ”€โ”€ ๋ฐฉ์†ก์€ **๋ชจ์•„์„œ** ํ•œ ๋ฒˆ (2026-08-14 ์‹ค์ธก์œผ๋กœ ์žก์Œ) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์—ฌ๊ธฐ์„œ ๊ณง๋ฐ”๋กœ ๋ฐฉ์†กํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ปค๋„์€ ํ•œ ๋ฒˆ์˜ tick ์—์„œ ์‚ฌ์‹ค์„ **์—ฌ๋Ÿฌ ๊ฐœ** ๋‚ธ๋‹ค\n * (์˜ˆ์•ฝยท๋ฐฐ์น˜ยท์™„๋ฃŒโ€ฆ). ๊ทธ๋ž˜์„œ tick ํ•˜๋‚˜๊ฐ€ ์ „ ์ƒํƒœ ํˆฌ์˜์„ ์ˆ˜๋ฐฑ ๋ฒˆ ๋ฐ˜๋ณตํ–ˆ๋‹ค โ€” `order-check`\n * ํŠธ์œˆ์—์„œ **ํ‹ฑ ํ•˜๋‚˜๊ฐ€ 35์ดˆ**๋ฅผ ๋จน๊ณ (๋‹จ๊ณ„ ํ•ฉ์€ 32ms ์˜€๋‹ค: ์‹œ๊ฐ„์€ ๋ฐ˜๋ณต ํšŸ์ˆ˜์— ์žˆ์—ˆ๋‹ค) ๊ทธ\n * 35์ดˆ ๋™์•ˆ ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ๋ง‰ํ˜€ ๊ตฌ๋…์ž๊ฐ€ ์•„๋ฌด๊ฒƒ๋„ ๋นผ๋‚ด์ง€ ๋ชปํ–ˆ๋‹ค. ๋ฐ€๋ฆฐ push ๊ฐ€ 1024๋ฅผ ๋„˜๋Š”\n * ์ˆœ๊ฐ„ pubsub ์ด ๋˜์ง€๊ณ , ๊ทธ ์˜ˆ์™ธ๊ฐ€ ํƒ€์ด๋จธ ์ฝœ๋ฐฑ์„ ํƒ€๊ณ  ์˜ฌ๋ผ์™€ **ํ˜ธ์ŠคํŠธ๊ฐ€ ์ฃฝ์—ˆ๋‹ค.**\n *\n * ๋ผ์ด๋ธŒ๋Š” ์ด๋ฏธ dirty ํ‘œ์‹œ + ์ฃผ๊ธฐ flush ๋กœ ์ด ๋ฌธ์ œ๋ฅผ ํ’€์–ด ๋‘์—ˆ๋‹ค(BROADCAST_COALESCE_MS).\n * ์‹œ๋ฎฌ๋งŒ ๊ทธ ๊ทœ์œจ ๋ฐ–์— ์žˆ์—ˆ๋‹ค โ€” ๊ฐ™์€ ๊ทœ์œจ๋กœ ๋“ค์ธ๋‹ค(์ตœ์‹ -์ƒํƒœ ์ฑ„๋„์ด๋ผ ์ค‘๊ฐ„ ์ƒํƒœ๋ฅผ ๋ชจ๋‘\n * ๋ณด๋‚ผ ์ด์œ ๊ฐ€ ์—†๋‹ค: 200ms ๋งˆ๋‹ค ๋งˆ์ง€๋ง‰ ๊ฒƒ ํ•˜๋‚˜๋ฉด ํ™”๋ฉด์€ ๊ฐ™๋‹ค).\n */\n inst.dirty = true\n this.ensureBroadcastCoalescer()\n }\n })\n inst.unsub = () => sub.unsubscribe()\n\n /* ๋ณต๊ตฌ ์•ต์ปค: ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— model/kind/status/restartPolicy ์˜์†(์žฌ๋ถ€ํŒ… ์‹œ ์ด๊ฒŒ ์žˆ์–ด์•ผ replayยท์„ ์–ธ ๊ฑฐ๋™ ๊ฐ€๋Šฅ). */\n this.register(domainId, id, kind, model, 'running', inst.restartPolicy).catch(err => console.error('twin register fail', err))\n\n /* ์›Œ์ปค tick โ€” ์Šค์ผˆ๋ ˆํ†ค์€ setInterval(๋ฉ”์ธ ๋ฃจํ”„). ๊ธด ์‹œ๋ฎฌ ์˜คํ”„-๋ฃจํ”„(worker thread)๋Š” ์Šค์ผ€์ผ ํ•˜๋“œ๋‹(ํ–ฅํ›„, ยงhost ๊ฒฝ๊ณ„). */\n inst.timer = setInterval(() => this.tickGuarded(domainId, id, runtime), this.TICK_MS)\n return inst\n }\n\n /**\n * live-๋ชจ๋“œ ๊ธฐ๋™ โ€” **๊ด€์ธก ๋ชจ๋“œ ์ปค๋„**๋กœ ์‹ค ์ด๋ฒคํŠธ๋ฅผ ๋ฏธ๋Ÿฌํ•œ๋‹ค(ํ†ตํ•ฉ P2).\n *\n * ์˜ˆ์ „์—๋Š” `StateProjector` ๋ฅผ ์„ธ์› ๋‹ค. ๊ทธ๋ž˜์„œ ๋ผ์ด๋ธŒ์—๋Š” **์ปค๋„์ด ์—†์—ˆ๊ณ **, ๊ทธ ํ•˜๋‚˜ ๋•Œ๋ฌธ์— ์šฐํšŒ๊ฐ€\n * ์ค„์ค„์ด ์ƒ๊ฒผ๋‹ค: ์˜ˆ์ธกํ•˜๋ ค๋ฉด ์ž„์‹œ ์ปค๋„์„ ์„ธ์›Œ์•ผ ํ–ˆ๊ณ (`buildForecastKernel`), ์ฃผ๋ชฉ ์‹ ํ˜ธ๋ฅผ ํ˜ธ์ŠคํŠธ๊ฐ€\n * ๋ง๋ถ™์—ฌ์•ผ ํ–ˆ๊ณ (`withLiveAttentions`), AI ์˜ˆ์ธก ๋„๊ตฌ๋Š” ๋ฏธ๋Ÿฌ์—์„œ \"์ฐพ์„ ์ˆ˜ ์—†๋‹ค\" ๋กœ ๋๋‚ฌ๋‹ค.\n *\n * ์ด์ œ ๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค๋„ **์ปค๋„์ด๋‹ค.** ๊ฐ™์€ ๊ทœ์น™(`ObservedReducer`)์œผ๋กœ ์ด๋ฒคํŠธ๋ฅผ ์ ‘๊ณ , ์ฃผ๋ชฉ ์‹ ํ˜ธ๋ฅผ\n * ์Šค์Šค๋กœ ๋‚ด๊ณ , ๊ทธ ์ž๋ฆฌ์—์„œ `fork` ํ•ด ์˜ˆ์ธกํ•œ๋‹ค. ๊ตฌ๋™๋งŒ ๋‹ค๋ฅด๋‹ค โ€” sim ์€ `tick`, live ๋Š” `apply`.\n *\n * ์‹ค ์ด๋ฒคํŠธ์› = reference ์–ด๋Œ‘ํ„ฐ openLiveFeed โ†’ face2-adapter.ingest โ†’ CanonicalEnvelope โ†’ ingestLive().\n */\n /**\n * ๋ชจ๋ธ์ด ์‹ค์€ **์ƒ์‚ฐ ์ •์˜**(๋ ˆ์‹œํ”ผยท๋ผ์šฐํŠธยท๋ฐ”์ธ๋”ฉ)๋ฅผ ๊บผ๋‚ธ๋‹ค โ€” ์ปค๋„์˜ ์ •์˜-๊ตฌ๋™ ๋ชจ๋“œ ์ž…๊ตฌ.\n *\n * โ”€โ”€ ์—†์„ ๋•Œ ๋ฌด์—‡์ด ์ผ์–ด๋‚ฌ๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ปค๋„์—๋Š” ์ •์˜-๊ตฌ๋™ MES ๊ฒฝ๋กœ๊ฐ€ ์žˆ๋Š”๋ฐ **ํ˜ธ์ŠคํŠธ๊ฐ€ ๊ทธ๊ฒƒ์„ ํ•œ ๋ฒˆ๋„ ๋„˜๊ธฐ์ง€ ์•Š์•˜๋‹ค.** ๊ทธ๋ž˜์„œ ๋ชจ๋“  MES\n * ํŠธ์œˆ์ด **ํ•˜๋“œ์ฝ”๋”ฉ๋œ ๋ ˆ๊ฑฐ์‹œ ํ๋ฆ„**์œผ๋กœ ๋Œ์•˜๋‹ค โ€” ํ˜„์žฅ ๋ ˆ์‹œํ”ผ๋ฅผ ์•„๋ฌด๋ฆฌ ์ •์„ฑ๊ป ์ ์–ด๋„ ์ปค๋„์€ ๊ทธ๊ฒƒ์„\n * ๋ณด์ง€ ๋ชปํ•˜๊ณ  ํ† ์ด ๋ถ€ํ’ˆ์œผ๋กœ ํ† ์ด ์ œํ’ˆ์„ ๋งŒ๋“ค์—ˆ๋‹ค. ์„ ์–ธ๊ณผ ์‹คํ–‰์ด ๊ฐˆ๋ผ์ ธ ์žˆ๋˜ ์ž๋ฆฌ๋‹ค.\n *\n * ๋ชจ๋ธ์— ์—†์œผ๋ฉด `undefined` โ€” ๋ ˆ๊ฑฐ์‹œ ๊ฒฝ๋กœ ๊ทธ๋Œ€๋กœ๋‹ค(๊ธฐ์กด ํŠธ์œˆ์˜ ๊ฑฐ๋™์„ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค).\n */\n /**\n * ์ƒ์‚ฐ ์„ ์–ธ์„ ๊บผ๋‚ธ๋‹ค โ€” ์ปค๋„ ์ƒ์„ฑ์ž์— ๋„˜๊ธด๋‹ค.\n *\n * **์˜› ์ด๋ฆ„(`mesSpec`)์€ ์ฝ์ง€ ์•Š๋Š”๋‹ค.** ๊ทธ๊ฒƒ์€ ๊ณ„์•ฝ์— ์„ ์–ธ์กฐ์ฐจ ์—†๋˜ ํ•„๋“œ์˜€๊ณ (MES ์ปค๋„ ์ƒ์„ฑ์ž ์ธ์ž\n * ์ด๋ฆ„์ด ๊ทธ๋Œ€๋กœ ๊ตณ์€ ๊ฒƒ), ์ผ๋ฐ˜ ๊ธฐ์ œ์— ํ•œ ์‹œ์Šคํ…œ ์ด๋ฆ„์ด ๋ถ™์–ด ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฐฝ๊ณ  ํŠธ์œˆ์ด ์ด ์ž๋ฆฌ๋ฅผ\n * ์“ฐ์ง€ ๋ชปํ–ˆ๋‹ค. ๋ณ„๋ช…์œผ๋กœ ๋‚จ๊ฒจ ๋‘๋ฉด ๊ทธ ํ˜ผ๋™์ด ๊ณ„์†๋˜๋ฏ€๋กœ ํ•˜๋‚˜๋กœ ํ†ต์ผํ–ˆ๋‹ค.\n *\n * ์˜› ์ด๋ฆ„๋งŒ ๊ฐ€์ง„ ๋ชจ๋ธ์ด ์žˆ์œผ๋ฉด **์กฐ์šฉํžˆ ์ƒ์‚ฐ ์„ ์–ธ์„ ์žƒ๋Š” ๋Œ€์‹  ๋ถ„๋ช…ํžˆ ๋ฉˆ์ถ˜๋‹ค** โ€” ๊ทธ ํŠธ์œˆ์€ ๊ณต์ •์ด\n * ์—†๋Š” ์ฑ„๋กœ ๋Œ๊ฒŒ ๋˜๊ณ (๋ผ์ธ์ด ์„œ ์žˆ๋Š” ์ฐฝ๊ณ ), ์›์ธ์„ ์ฐพ๊ธฐ ์–ด๋ ต๋‹ค.\n */\n private static productionSpecOf(model: TwinModelDef | undefined): any {\n const legacy = (model as any)?.mesSpec\n if (legacy && !(model as any)?.productionSpec) {\n throw new Error(\n 'the twin model carries the retired `mesSpec` field โ€” rename it to `productionSpec` ' +\n '(same shape; the name was tied to one kernel while the declaration is ISA-95 operations + BOM)'\n )\n }\n return (model as any)?.productionSpec\n }\n\n /**\n * ํ˜„์žฅ(๊ณต๊ฐ„)์˜ **์‹œ๊ฐ ๊ธฐ์ค€**์„ ๋ชจ๋ธ์— ์–น๋Š”๋‹ค โ€” ์ปค๋„์ด ๊ต๋Œ€์˜ `HH:MM` ์„ ์ฝ์„ ๊ธฐ์ค€.\n *\n * **ํ…Œ๋„ŒํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ ๊ณต๊ฐ„์ด ๊ถŒ์œ„๋‹ค.** ํ•œ ํ…Œ๋„ŒํŠธ๊ฐ€ Rosarito(ํƒœํ‰์–‘)์™€ ํ•œ๊ตญ ๊ณต์žฅ์„ ํ•จ๊ป˜ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ณ ,\n * ํ…Œ๋„ŒํŠธ ๋‹จ์œ„(`Domain.timezone`)๋กœ ๋‘๋ฉด ๋‘˜ ์ค‘ ํ•˜๋‚˜๋Š” ๋ฐ˜๋“œ์‹œ ํ‹€๋ฆฐ๋‹ค. ๊ทธ๋ž˜์„œ ์ธ์Šคํ„ด์Šค๊ฐ€ ์—ฐ๊ฒฐ๋œ ๊ณต๊ฐ„์˜\n * `timezone` ์„ ์ฝ๋Š”๋‹ค. ๊ณต๊ฐ„์ด ๋งํ•˜์ง€ ์•Š์œผ๋ฉด **ํ…Œ๋„ŒํŠธ๋กœ ๋‚ด๋ ค๊ฐ€์ง€ ์•Š๋Š”๋‹ค** โ€” ์ž˜๋ชป๋œ ์ž…์ž๋กœ ๋‹ตํ•˜๋Š” ๊ฒƒ์ด\n * ๋ชจ๋ฅด๋Š” ๊ฒƒ๋ณด๋‹ค ๋‚˜์˜๋‹ค(๊ทธ๋•Œ๋Š” ์ปค๋„์ด UTC ๋กœ ์ฝ๊ณ , ๊ทธ ๊ธฐ๋ณธ๊ฐ’์€ ๊ณ„์•ฝ์— ๋ฐํ˜€์ ธ ์žˆ๋‹ค).\n *\n * ์ปค๋„์€ zero-dep ์ด๋ผ ์‹œ๊ฐ„๋Œ€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๊ฐ–์ง€ ์•Š์œผ๋ฏ€๋กœ **๋ถ„ ์˜คํ”„์…‹**์œผ๋กœ ํ’€์–ด ๋„˜๊ธด๋‹ค. ๊ทธ ๊ฐ’์€\n * ์ง€๊ธˆ ๊ณ„์ ˆ์˜ ๊ฒƒ์ด๋‹ค(์ผ๊ด‘์ ˆ์•ฝ์‹œ๊ฐ„) โ€” ๊ณ„์ ˆ์„ ๋„˜๋Š” ๊ธด ์˜ˆ์ธก์€ ํ•œ ์‹œ๊ฐ„ ์–ด๊ธ‹๋‚œ๋‹ค(๊ณ„์•ฝ์— ๋ช…์‹œ).\n */\n static async withSpaceTimeBase(model: TwinModelDef, domainId: string, spaceId?: string): Promise<TwinModelDef> {\n const sid = spaceId ?? (model as any)?.spaceId\n if (!sid) return model\n const space = await getRepository(TwinSpace).findOne({ where: { domain: { id: domainId }, spaceId: sid } }).catch(() => null)\n const offset = utcOffsetOf(space?.timezone)\n if (offset === undefined) {\n if (space?.timezone) console.warn(`[twin-engine] space \"${sid}\" declares time zone \"${space.timezone}\" but it is not a known IANA zone โ€” times will be read as UTC.`)\n return model\n }\n return { ...model, utcOffsetMinutes: offset }\n }\n\n static startLive(id: string, domainId: string, kind: string, model: TwinModelDef): InstanceRuntime {\n const key = runtimeKey(domainId, id)\n if (this.instances[key]) return this.instances[key]\n const Kernel = kernelFor(kind)\n const kernel: any = new Kernel(domainId, undefined, this.productionSpecOf(model))\n kernel.loadTwinModel(model)\n /* **์„ธ์šฐ๋Š” ์ชฝ์ด ์•„๋Š” ์‚ฌ์‹ค์€ ์„ธ์šธ ๋•Œ ๋งํ•œ๋‹ค.** ์˜ˆ์ „์—๋Š” ์ฒซ ์ด๋ฒคํŠธ๊ฐ€ ๋„์ฐฉํ•ด์•ผ ์ปค๋„์ด ์Šค์Šค๋กœ๋ฅผ\n ๊ด€์ธก ๊ตฌ๋™์œผ๋กœ ์—ฌ๊ฒผ๊ณ , ๊ทธ๋ž˜์„œ ์•„์ง ์•„๋ฌด๊ฒƒ๋„ ๋ชป ๋ฐ›์€ ๋ฏธ๋Ÿฌ๋Š” ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ์ทจ๊ธ‰์„ ๋ฐ›์•˜๋‹ค. */\n kernel.observe?.()\n this.applyOperations(kernel, model, id) // ๋ช…์„ธ๋Š” ๋ผ์ด๋ธŒ์—๋„ ์‹ค๋ฆฐ๋‹ค(์˜ˆ์ธก ์ž๊ฒฉ์ด sim ๊ณผ ๊ฐ™์•„์ง„๋‹ค)\n /* `projector` ํ•„๋“œ๋Š” ์˜› ์ด๋ฆ„์œผ๋กœ ๋‚จ๊ธด๋‹ค โ€” ์†Œ๋น„์ฒ˜๊ฐ€ `snapshot()` ์„ ๋ถ€๋ฅด๋ฏ€๋กœ ์–‡์€ ์–ด๋Œ‘ํ„ฐ๋กœ ์ž‡๋Š”๋‹ค.\n * (P3 ์—์„œ ์†Œ๋น„์ฒ˜๋ฅผ ์ปค๋„ ์–ดํœ˜๋กœ ๋ฐ”๊พธ๋ฉด ์‚ฌ๋ผ์ง„๋‹ค.) */\n const projector = { apply: (e: CanonicalEnvelope) => kernel.apply(e), snapshot: () => kernel.getSnapshot() }\n const inst: InstanceRuntime = { id, domainId, mode: 'live', restartPolicy: 'resync', kernel, projector, oee: new OeeAccumulator(), spaceId: (model as any)?.spaceId, unsub: () => {} }\n /*\n * โ”€โ”€ ์ปค๋„์ด **ํŒ์ •์œผ๋กœ ๋‚ธ ์‚ฌ์‹ค**๋„ ์ €๋„์— ๋‚จ๋Š”๋‹ค (2026-08-14 ์‹ค์ธก์œผ๋กœ ์žก์Œ) โ”€โ”€โ”€โ”€\n *\n * ๋ผ์ด๋ธŒ๋Š” ์ธ์ž… ๋ด‰ํˆฌ๋งŒ ์ €๋„์— ์ ๊ณ  ์žˆ์—ˆ๋‹ค(`ingestLive`). ๊ทธ๋Ÿฐ๋ฐ ์ปค๋„์€ ๊ด€์ธก์„ ์ ‘๋‹ค๊ฐ€ **์ž๊ธฐ ์‚ฌ์‹ค**์„\n * ๋‚ธ๋‹ค โ€” ์—๋„ˆ์ง€์˜ ์ˆ˜์š” ๊ตฌ๊ฐ„ ๋งˆ๊ฐยทํ”ผํฌ ๊ฒฝ์‹ ยท๊ฐ์ถ• ์ œ์•ˆ์ด ๊ทธ๋ ‡๋‹ค(`emitOp`). ๊ทธ๊ฒƒ์„ ๊ตฌ๋…ํ•˜๋Š” ๊ณณ์ด\n * ์—†์–ด์„œ ๊ทธ ์‚ฌ์‹ค๋“ค์ด **์ปค๋„ ์•ˆ์—์„œ ์‚ฌ๋ผ์กŒ๋‹ค**: ํ‘œ๋ณธ 48๊ฑด์ด ์ €๋„์— ์Œ“์˜€๋Š”๋ฐ ๊ตฌ๊ฐ„ ๋งˆ๊ฐ์€ 0๊ฑด์ด์—ˆ๊ณ ,\n * ์ €๋„์„ ์ฝ๋Š” ์„ฑ๊ณผ ํ™”๋ฉด์˜ ์ „๋ ฅ ํƒ€์ผ์€ ์˜์›ํžˆ ๋‚˜์˜ค์ง€ ์•Š์•˜๋‹ค.\n *\n * sim ์€ `runtime.subscribe` ๋กœ ๊ฐ™์€ ์ผ์„ ํ•œ๋‹ค โ€” ๋ผ์ด๋ธŒ์—๋งŒ ๊ทธ ๋ฐฐ์„ ์ด ์—†์—ˆ๋‹ค.\n *\n * **์ธ์ž…์˜ ์žฌ๋ฐฉ์ถœ์€ ๊ฑธ๋Ÿฌ๋‚ธ๋‹ค**: `apply()` ๋Š” ๋ฐ›์€ ๋ด‰ํˆฌ๋ฅผ ๊ตฌ๋…์ž์—๊ฒŒ ๊ทธ๋Œ€๋กœ ํ˜๋ฆฐ๋‹ค(ํ˜ธ์ŠคํŠธ๊ฐ€ ๋‘ ๋ชจ๋“œ์—์„œ\n * ๊ฐ™์€ ๋ฐฐ์„ ์„ ์“ฐ๊ฒŒ ํ•˜๋ ค๊ณ ). ๊ทธ๊ฒƒ๊นŒ์ง€ ์ ์œผ๋ฉด ์ธ์ž…์ด ์ €๋„์— ๋‘ ๋ฒˆ ๋“ค์–ด๊ฐ„๋‹ค โ€” ๊ทธ๋ž˜์„œ ๋ฐฉ๊ธˆ ๋„ฃ์€ ๊ฒƒ๊ณผ\n * **๊ฐ™์€ ๊ฐ์ฒด**์ธ์ง€ ๋ณด๊ณ  ๊ฑด๋„ˆ๋›ด๋‹ค(id ๋น„๊ต๋Š” ์–ด๋Œ‘ํ„ฐ๊ฐ€ id ๋ฅผ ์–ด๋–ป๊ฒŒ ๋งŒ๋“œ๋Š”์ง€์— ๊ธฐ๋Œ€๊ฒŒ ๋˜์–ด ์•ฝํ•˜๋‹ค).\n */\n const applying = new WeakSet<object>()\n inst.applying = applying\n inst.unsub = kernel.onEvent?.((e: CanonicalEnvelope) => {\n if (e && typeof e === 'object' && applying.has(e as object)) return // ์ธ์ž…์˜ ์žฌ๋ฐฉ์ถœ โ€” ์ €๋„์€ ์ธ์ž…์—์„œ ํ•œ ๋ฒˆ๋งŒ\n ;(inst.pendingJournal ?? (inst.pendingJournal = [])).push(e)\n /* ์ปค๋„์ด ๋‚ธ ์‚ฌ์‹ค๋„ ์ƒํƒœ๋ฅผ ๋ฐ”๊พผ๋‹ค(ํ”ผํฌยท๋งˆ๊ฐ) โ€” ๋‹ค์Œ ๋ฐฉ์†ก ์ฃผ๊ธฐ์— ์‹ค๋ฆฐ๋‹ค. */\n inst.dirty = true\n this.ensureBroadcastCoalescer()\n }) ?? (() => {})\n /* ์ถ”์ •๊ธฐ(์‹ค์ธกยท๊ฑฐ๋ฆฌ)๋„ ๋ผ์ด๋ธŒ์— ๋ถ™์ธ๋‹ค โ€” ์˜ˆ์ธก์ด ์ƒ์ˆ˜๋กœ ๊ณ„์‚ฐ๋˜์ง€ ์•Š๊ฒŒ. ๊ธฐ๋™์„ ๋ง‰์ง€ ์•Š๋Š”๋‹ค. */\n this.installEstimators(kernel, domainId, id, model).catch(err => console.warn('[twin-engine] estimator install failed', err?.message))\n inst.metrics = { ingestedTotal: 0, broadcastTotal: 0, journaledTotal: 0, ingestRate: 0, broadcastRate: 0, journalRate: 0, backlog: 0, _accIngest: 0, _accBroadcast: 0, _accJournal: 0, _windowStartMs: Date.now() }\n this.instances[key] = inst\n /* ๋ฏธ๋Ÿฌ์—๋„ ๋ถ€๋ฅธ๋‹ค โ€” ์„ ์–ธ์ด ์žˆ์œผ๋ฉด ใ€Œ๋ฏธ๋Ÿฌ์—๋Š” ์‹ฃ์ง€ ์•Š๋Š”๋‹คใ€๊ณ  ๋งํ•ด์•ผ ํ•œ๋‹ค(์กฐ์šฉํ•œ ๋ฌด์‹œ ๊ธˆ์ง€). */\n this.installStimulus(domainId, id, inst).catch(err => console.warn(`[twin-engine] \"${id}\": stimulus check failed โ€” ${err?.message ?? err}`))\n /*\n * **์›์ฒœ์ด ๋˜ํ’€์–ด ์ฃผ์ง€ ์•Š๋Š” ๊ฒƒ๋งŒ ์ž‡๋Š”๋‹ค** (2026-08-18 ์‹ค์ธก์œผ๋กœ ๋ถ™์ž„).\n *\n * ๋ฏธ๋Ÿฌ๋Š” ์˜ค๋žซ๋™์•ˆ ์•„๋ฌด๊ฒƒ๋„ ์ด์–ด๋ฐ›์ง€ ์•Š์•˜๋‹ค โ€” ์ง„์‹ค์ด ์›์ฒœ์— ์žˆ์œผ๋‹ˆ ์˜ณ์€ ํŒ๋‹จ์ด์—ˆ์ง€๋งŒ, ์›์ฒœ์ด **์• ์ดˆ์—\n * ๋‹ค์‹œ ๋งํ•ด ์ฃผ์ง€ ์•Š๋Š” ์ถ•**๊นŒ์ง€ ํ•จ๊ป˜ ๋ฒ„๋ ธ๋‹ค: ์—ด๋ฆฐ 15๋ถ„ ๊ตฌ๊ฐ„์˜ ๋ˆ„์ ยท์ ์‚ฐ ๊ธฐ์ค€์ ยท๊ด€์ธก ์ดํ›„ ์ตœ๋Œ€, ๊ทธ๋ฆฌ๊ณ \n * ํ™•์ธํ•ด ๋‘” ์‹ ํ˜ธ์™€ ์กฐ๊ฑด์ด ์–ธ์ œ๋ถ€ํ„ฐ์ธ์ง€. ๊ทธ๋ž˜์„œ ์žฌ๊ธฐ๋™ํ•˜๋ฉด ์˜ค๋ฅ˜ ์—†์ด ๊ฐ’์ด ์ž‘์•„์กŒ๋‹ค(๊ทธ ๊ตฌ๊ฐ„์˜ ์ „๋ ฅ๋Ÿ‰๊ณผ\n * ํ”ผํฌ๊ฐ€ ๋ถ€ํŒ… ์ดํ›„๋กœ๋งŒ ์žกํžˆ๊ณ , ์„ธ ์‹œ๊ฐ„์งธ ์ง€์†๋œ ๊ฒฝ๋ณด๊ฐ€ ใ€Œ0์ดˆ์งธใ€๊ฐ€ ๋๋‹ค โ€” ์š”๊ธˆ์ด ๊ฑธ๋ฆฐ ์ˆ˜๋‹ค).\n *\n * ๊ด€์ธก ์ถ•(์žฌ๊ณ ยท์œ„์น˜ยท์„ค๋น„)์€ **์—ฌ์ „ํžˆ ์‹ฌ์ง€ ์•Š๋Š”๋‹ค** โ€” ๋‹ค์Œ ๊ณ„์ธก์ด ์ •์ •ํ•˜๊ณ , ์‹ฌ์œผ๋ฉด ๋– ๋‚œ ๋ฌผ๊ฑด์ด\n * ๋˜์‚ด์•„๋‚œ๋‹ค. ๋ฌด์—‡์„ ๋„˜๊ธธ์ง€๋Š” `planLiveContinuity` ๊ฐ€ ๊ณ ๋ฅด๊ณ , ์–ด๋–ป๊ฒŒ ํก์ˆ˜ํ• ์ง€๋Š” ์ปค๋„์ด ์ •ํ•œ๋‹ค.\n */\n this.seedLiveContinuity(domainId, id, kernel)\n delete this.recovered[key]\n /* ๋ผ์ด๋ธŒ ๋ฐ”์ธ๋”ฉ(data ์ฑ„๋„) subdomain ํ•„ํ„ฐ์šฉ Domain 1ํšŒ ํ•ด์„(sim ๊ณผ ๋™์ผ). */\n getRepository(Domain).findOne({ where: { id: domainId } }).then(d => (inst.domain = d)).catch(() => {})\n /* ์ €๋„ revision ์นด์šดํ„ฐ ์‹œ๋“œ โ€” ๊ธฐ์กด ์ €๋„ ์ตœ๋Œ€์น˜์—์„œ ์ด์–ด๋ถ™์ž„(์žฌ๊ธฐ๋™ ์‹œ revision ์ถฉ๋Œ ๋ฐฉ์ง€). ์ดํ›„ ์ธ๋ฉ”๋ชจ๋ฆฌ ์ฆ๊ฐ€. */\n getRepository(TwinEvent)\n .findOne({ where: { domain: { id: domainId }, instanceId: id }, order: { revision: 'DESC' } })\n .then(top => (inst.revision = top?.revision ?? 0))\n .catch(() => (inst.revision = 0))\n this.register(domainId, id, kind, model, 'running', 'resync').catch(err => console.error('twin register fail', err))\n return inst\n }\n\n /**\n * live ์ด๋ฒคํŠธ ์ธ์ œ์ŠคํŠธ โ€” projector ๊ตฌ๋™ + data(tag) ๋ฐฉ์†ก(ํ๋ฃจํ”„์˜ ์ธ๋ฐ”์šด๋“œ ๋„์ฐฉ ์ง€์ , command-routing ยง8.2).\n * reference ์–ด๋Œ‘ํ„ฐ๊ฐ€ ๋‚ธ records โ†’ ์ปค๋„ face2-adapter.ingest โ†’ CanonicalEnvelope ๋ฅผ ์—ฌ๊ธฐ๋กœ ๋ฐ€์–ด๋„ฃ๋Š”๋‹ค.\n * (State ์ฑ„๋„ ๋ธํƒ€/์ €๋„ ๊ฒฐ์„ ์€ ํ›„์† โ€” ์Šค์ผˆ๋ ˆํ†ค์€ data(tag) ๋ฏธ๋Ÿฌ ์ค‘์‹ฌ.)\n */\n static ingestLive(domainId: string, id: string, envelopes: CanonicalEnvelope[]): void {\n const inst = this.instances[runtimeKey(domainId, id)]\n if (inst?.mode !== 'live' || !inst.projector) return\n const tIngest = performance.now()\n /* ์ธ์ž… ๋ด‰ํˆฌ๋ฅผ ํ‘œ์‹œํ•ด ๋‘๊ณ  ๋„ฃ๋Š”๋‹ค โ€” ์ปค๋„์ด ๊ทธ๊ฒƒ์„ ์žฌ๋ฐฉ์ถœํ•ด๋„ ์ €๋„์— ๋‘ ๋ฒˆ ์ ํžˆ์ง€ ์•Š๊ฒŒ(์œ„ ๊ตฌ๋… ์ฃผ์„). */\n for (const e of envelopes) {\n if (e && typeof e === 'object') inst.applying?.add(e as object)\n inst.projector.apply(e)\n inst.oee?.apply(e) // ๊ด€์ธก(projector) + ๊ณ„์‚ฐ(OEE ๋ˆ„์ )\n }\n recordPhase(inst.load ?? (inst.load = newLoadMeter()), 'ingest', performance.now() - tIngest)\n // ์ €๋„ ๊ฒฐ์„ (๋ผ์ด๋ธŒ๋„ sim ์ฒ˜๋Ÿผ ์ด๋ฒคํŠธ ์˜์†) โ€” ๋‹จ ์ด๋ฒคํŠธ๋งˆ๋‹ค DB write ํ•˜๋ฉด ๋ถ€ํ•˜ํญ๋ฐœ์ด๋ผ ๋ชจ์•„๋’€๋‹ค๊ฐ€\n // coalescer tick ์—์„œ ๋ฐฐ์น˜ ๊ธฐ๋ก(๋ฐฉ์†ก๊ณผ ๋™์ผ ์ฃผ๊ธฐ). ํžˆ์Šคํ† ๋ฆฌ ๋…ธ๋ธŒยทํƒ€์ž„๋ผ์ธยท๋น„์ฆˆ๋‹ˆ์Šค ์›์žฅ์ด ์ด ์ €๋„์„ ์ฝ๋Š”๋‹ค.\n ;(inst.pendingJournal ?? (inst.pendingJournal = [])).push(...envelopes)\n if (inst.metrics) { inst.metrics.ingestedTotal += envelopes.length; inst.metrics._accIngest += envelopes.length } // ๊ณ„์ธก(โ‘ฃ-1)\n // ๋ฐฉ์†ก ๋ณ‘ํ•ฉ(ingest-scale ยง1.1/ยง4.4) โ€” apply ๋Š” O(1)ยท์‹ธ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ฐฉ์†ก(snapshot O(state))์€ ๋น„์‹ธ(๋Œ€๊ทœ๋ชจ 5ms+)\n // ์ด๋ฒคํŠธ๋งˆ๋‹ค ๋ฐฉ์†กํ•˜๋ฉด ํญ๋ฐœ โ†’ dirty ๋งŒ ์ฐ๊ณ  coalescer tick ์ด ์ฃผ๊ธฐ ๋ฐฉ์†ก(๋ฐฉ์†ก๋ฅ  โ‰  ์ธ์ œ์ŠคํŠธ๋ฅ ).\n inst.dirty = true\n this.ensureBroadcastCoalescer()\n }\n\n /**\n * ๊ตฌ๊ฐ„ ์„ฑ๊ณผ ๋ฐฉ์†ก์€ **์—†์•ด๋‹ค**(2026-08-06). ์นด๋“œ๊ฐ€ `twinKpi` ๋ฅผ ์ง์ ‘ ๋ฌป๋Š”๋‹ค.\n *\n * ์™œ: ์นด๋“œ๋ฅผ ์—ฌ๋Ÿฌ ๋‹จ๊ณ„(๊ณต๊ฐ„ยทํŠธ์œˆยท๊ตฌ์—ญยท์ž๋ฆฌยท์„ค๋น„)์— ๋ถ™์ด๋ ค๋ฉด ๋ฐฉ์†ก์œผ๋กœ๋Š” ํƒœ๊ทธ๊ฐ€ ํŠธ์œˆ๋‹น 1,200๊ฐœ๊ฐ€ ๋˜๊ณ ,\n * **๋ชจ๋ธ์— ์นด๋“œ๋ฅผ ํ•˜๋‚˜๋„ ์•ˆ ๋†“์•„๋„** 30์ดˆ๋งˆ๋‹ค ํŠธ์œˆ๋งˆ๋‹ค ์ €๋„์„ ์ ‘์—ˆ๋‹ค. ์งˆ์˜๋กœ ๋ฐ”๊พธ๋‹ˆ ๋ณด๊ณ  ์žˆ๋Š” ์นด๋“œ\n * ์ˆ˜๋งŒํผ๋งŒ ๋“ค๊ณ , ๊ฐ™์€ (๋Œ€์ƒยท์ฐฝยท์ถ•) ์€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํ•˜๋‚˜๋กœ ํ•ฉ์นœ๋‹ค.\n *\n * ๋ค์œผ๋กœ ์งˆ์˜๋งŒ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด ๋‘˜ ์ƒ๊ฒผ๋‹ค โ€” **๊ณผ๊ฑฐ ์‹œ๊ฐ**(`toTime`)๊ณผ **๊ณต๊ฐ„ ๋‹จ์œ„ ํ•ฉ์‚ฐ**(์—ฌ๋Ÿฌ ํŠธ์œˆ์„\n * ํ•œ ๋ฒˆ์— ์ ‘๊ธฐ). ๋ฐฉ์†ก ๋ฃจํ”„๋Š” ํŠธ์œˆ๋ณ„์ด๋ผ ๋‘˜ ๋‹ค ๋ชป ํ–ˆ๋‹ค.\n *\n * ์ถ•์„ ๋‚˜๋ˆ ๋„ ํด๋“œ ๋น„์šฉ์ด ๊ฐ™๋‹ค๋Š” ์‹ค์ธก์ด ๊ทผ๊ฑฐ๋‹ค(`test/kpi-query-bench.test.ts`).\n */\n /** ๋ฐฉ์†ก ๋ณ‘ํ•ฉ ์ฃผ๊ธฐ(ms) โ€” ๋ฐฉ์†ก๋ฅ  ์ƒํ•œ. ์ธ์ œ์ŠคํŠธ๊ฐ€ ์•„๋ฌด๋ฆฌ ๋นจ๋ผ๋„ ์ด ์ฃผ๊ธฐ๋กœ๋งŒ ๋ฐฉ์†ก. */\n static BROADCAST_COALESCE_MS = 200\n private static broadcastTimer?: any\n\n /** live ๋ฐฉ์†ก coalescer โ€” dirty ์ธ live ์ธ์Šคํ„ด์Šค๋งŒ ์ฃผ๊ธฐ์ ์œผ๋กœ 1ํšŒ ๋ฐฉ์†ก(entitySigs ๋กœ ๋ณ€๊ฒฝ ์—”ํ‹ฐํ‹ฐ๋งŒ). */\n private static ensureBroadcastCoalescer(): void {\n if (this.broadcastTimer) return\n this.broadcastTimer = setInterval(() => this.flushLiveBroadcasts(), this.BROADCAST_COALESCE_MS)\n if (typeof this.broadcastTimer.unref === 'function') this.broadcastTimer.unref() // ์ข…๋ฃŒ ๋น„์ฐจ๋‹จ\n }\n\n /**\n * dirty ์ธ์Šคํ„ด์Šค ๋ฐฉ์†ก flush(์ฃผ๊ธฐ tick ๋˜๋Š” ๋ช…์‹œ ํ˜ธ์ถœ) โ€” **์‹œ๋ฎฌ๊ณผ ๋ผ์ด๋ธŒ ๋‘˜ ๋‹ค.**\n *\n * ์˜ˆ์ „์—๋Š” ๋ผ์ด๋ธŒ๋งŒ ๋ดค๋‹ค(`mode !== 'live'` ๋ฉด ๊ฑด๋„ˆ๋œ€). ์‹œ๋ฎฌ์€ delta ๋งˆ๋‹ค ๊ณง๋ฐ”๋กœ ๋ฐฉ์†กํ–ˆ๊ณ , ๊ทธ๊ฒƒ์ด\n * ํ•œ tick ์—์„œ ์ˆ˜๋ฐฑ ๋ฒˆ ๋ฐ˜๋ณต๋˜๋ฉฐ ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ๋ง‰์•˜๋‹ค(์œ„ `start()` ์ฃผ์„์˜ 35์ดˆ ํ‹ฑ). ๋ฐฉ์†ก์„ ๋ชจ์œผ๋Š”\n * ๊ทœ์œจ์€ ๋ชจ๋“œ์˜ ์„ฑ์งˆ์ด ์•„๋‹ˆ๋ผ **์ฑ„๋„์˜ ์„ฑ์งˆ**์ด๋‹ค โ€” ์ตœ์‹ -์ƒํƒœ ์ฑ„๋„์ด๋ฉด ์ค‘๊ฐ„ ์ƒํƒœ๋Š” ๋ณด๋‚ผ ๊ฐ’์ด ์—†๋‹ค.\n */\n static flushLiveBroadcasts(): void {\n const now = Date.now()\n for (const inst of Object.values(this.instances)) {\n const isLive = inst.mode === 'live'\n // ์ฒ˜๋ฆฌ๋Ÿ‰ ๊ณ„์ธก(โ‘ฃ-1) โ€” ์ฐฝ(โ‰ฅ1s)๋งˆ๋‹ค ์œ ์ž…/๋ฐฉ์†ก/์ €๋„๋ฅ  ๊ฐฑ์‹ . dirty ๋ฌด๊ด€(์œ ํœด๋ฉด 0์œผ๋กœ ์ˆ˜๋ ด). ๋ถ€ํ•˜๋ฅผ ์ฝ๋Š” ์‹ ํ˜ธ.\n const m = isLive ? inst.metrics : undefined\n if (m) {\n const dt = (now - m._windowStartMs) / 1000\n if (dt >= 1) {\n m.ingestRate = Math.round(m._accIngest / dt)\n m.broadcastRate = Math.round((m._accBroadcast / dt) * 10) / 10\n m.journalRate = Math.round(m._accJournal / dt)\n m._accIngest = 0; m._accBroadcast = 0; m._accJournal = 0; m._windowStartMs = now\n }\n }\n if (!inst.dirty) continue\n inst.dirty = false\n // โ‘  ์—”ํ‹ฐํ‹ฐ data(tag) ๋ฐฉ์†ก โ€” ๋ณด๋“œ ์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ ๋ Œ๋”.\n this.publishEntityData(inst)\n if (m) { m.broadcastTotal++; m._accBroadcast++ }\n /* ์‹œ๋ฎฌ์˜ ์ €๋„ยทstate ์ฑ„๋„์€ ์ž๊ธฐ ์ฝœ๋ฐฑ์ด delta ๋งˆ๋‹ค ์ฒ˜๋ฆฌํ•œ๋‹ค(์‚ฌ์‹ค์€ ํ•˜๋‚˜๋„ ๋น ๋œจ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค).\n ์—ฌ๊ธฐ์„œ ๋ชจ์œผ๋Š” ๊ฒƒ์€ **์—”ํ‹ฐํ‹ฐ ๋ฐฉ์†ก**๋ฟ์ด๋‹ค โ€” ํ™”๋ฉด์ด ์ฝ๋Š” ์ตœ์‹ -์ƒํƒœ ์ฑ„๋„. */\n if (!isLive) continue\n // โ‘ข ์ €๋„ ๋ฐฐ์น˜ ๊ธฐ๋ก โ€” ๋ชจ์•„๋‘” ์ด๋ฒคํŠธ์— revision ๋ถ€์—ฌํ•ด ๋ฒŒํฌ ์ €์žฅ(์ด๋ฒคํŠธ๋งˆ๋‹ค write ์•„๋‹˜).\n // revision ์นด์šดํ„ฐ๋Š” ์ธ๋ฉ”๋ชจ๋ฆฌ(startLive ์—์„œ ์ €๋„ high-water ๋กœ 1ํšŒ ์‹œ๋“œ) โ†’ tick ๋งˆ๋‹ค DB ์งˆ์˜ ์—†์Œ.\n const batch = inst.pendingJournal\n if (batch?.length && inst.revision != null) {\n inst.pendingJournal = []\n const start = inst.revision\n inst.revision = start + batch.length\n if (m) { m.journaledTotal += batch.length; m._accJournal += batch.length; m.backlog = batch.length }\n const tJournal = performance.now()\n this.persistBatch(inst.domainId, inst.id, batch, start)\n .then(() => recordPhase(inst.load ?? (inst.load = newLoadMeter()), 'journal', performance.now() - tJournal))\n .catch(err => console.error('twin live journal fail', err))\n }\n // โ‘ก State ์ฑ„๋„ ๋ฐฉ์†ก โ€” \"๋ฐ”๋€Œ์—ˆ๋‹ค\"๋Š” ๊ฐ€๋ฒผ์šด ์‹ ํ˜ธ๋งŒ(kind+revision). ๋งต ๊ตฌ๋…(subscribeTwinState)์€ ์ด ์‹ ํ˜ธ์—\n // scheduleRefresh(250ms ๋””๋ฐ”์šด์Šค)โ†’pollLive ๋กœ ๋˜๋ฌผ์–ด๋ด„. ์Šค๋ƒ…์ƒท(O(state))์€ ๋ณด๋Š” ์‚ฌ๋žŒ์ด ๋ฌผ์„ ๋•Œ๋งŒ 1ํšŒ ๊ณ„์‚ฐ.\n // (์—ฌ๊ธฐ์„œ payload ๋กœ ์Šค๋ƒ…์ƒท์„ ์‹ค์œผ๋ฉด ์•„๋ฌด๋„ ์•ˆ ์ฝ๋Š”๋ฐ tick ๋งˆ๋‹ค ํ†ต์งธ๋กœ ๋– ์„œ ์ˆœ์ˆ˜ ๋‚ญ๋น„ โ€” ์‹ ํ˜ธ๋งŒ ๋ณด๋‚ธ๋‹ค.)\n this.publishGuarded(\n 'twin-state',\n { twinState: { instanceId: inst.id, kind: 'delta', revision: inst.revision ?? 0 } },\n `twin-state:${inst.id}`\n )\n }\n /* ๋Œ๊ณ  ์žˆ๋Š” ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•˜๋‚˜๋„ ์—†์œผ๋ฉด tick ์„ ๋ฉˆ์ถ˜๋‹ค(์˜ˆ์ „์—” ใ€Œ๋ผ์ด๋ธŒ๊ฐ€ ์—†์œผ๋ฉดใ€์ด์—ˆ๋Š”๋ฐ, ์ด์ œ\n ์‹œ๋ฎฌ๋„ ์ด flush ์— ๊ธฐ๋Œ€๋ฏ€๋กœ ๊ทธ ์กฐ๊ฑด์ด๋ฉด ์‹œ๋ฎฌ ๋ฐฉ์†ก์ด ๋ฉˆ์ถ˜ ์ฑ„ ๋‚จ๋Š”๋‹ค). */\n if (!Object.keys(this.instances).length && this.broadcastTimer) {\n clearInterval(this.broadcastTimer)\n this.broadcastTimer = undefined\n }\n }\n\n /**\n * ์ €๋„ ํ–‰ ํ•œ ์ค„ โ€” **๊ธฐ๋ก ๊ฒฝ๋กœ๊ฐ€ ๋‘˜์ด๋ผ(๋ผ์ด๋ธŒ ๋ฒŒํฌยท์‹ฌ ๋‹จ๊ฑด) ํ–‰ ๋ชจ์–‘์€ ๋ฐ˜๋“œ์‹œ ํ•œ ๊ณณ์—์„œ ๋งŒ๋“ ๋‹ค.**\n * ๋‘ ๊ณณ์— ๊ฐ์ž ์ ์œผ๋ฉด ์Šน๊ฒฉ ๊ฒ€์ƒ‰ ํ‚ค๊ฐ€ ํ•œ์ชฝ์—๋งŒ ์ฑ„์›Œ์ง€๊ณ , ๋ฐ˜์ฏค ๋นˆ ์ƒ‰์ธ์€ \"์ €๋„์—๋Š” ์žˆ๋Š”๋ฐ\n * ๊ฒ€์ƒ‰์œผ๋กœ๋Š” ์•ˆ ๋‚˜์˜ค๋Š” ์ด๋ฒคํŠธ\" ๋ฅผ ๋งŒ๋“ ๋‹ค โ€” ์ €๋„์—์„œ ๊ฐ€์žฅ ๋‚˜์œ ์ข…๋ฅ˜์˜ ๊ฒฐํ•จ์ด๋‹ค.\n */\n /** ์ €๋„์˜ ์‹œ๊ฐ ์ถ•์€ ๋‚ ์งœ๋‹ค โ€” ๋ชป ์ฝ๋Š” ๊ฐ’์€ ๋น„์šด๋‹ค(0 ์ด๋‚˜ ์ง€๊ธˆ์œผ๋กœ ์œ„์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค). */\n private static toEventTimeValue(v: any): Date | undefined {\n if (v instanceof Date) return v\n const t = typeof v === 'string' ? Date.parse(v) : NaN\n return Number.isNaN(t) ? undefined : new Date(t)\n }\n\n private static journalRow(repo: any, domainId: string, instanceId: string, e: any, revision: number, structureRev?: number) {\n return repo.create({\n domain: { id: domainId } as any,\n instanceId,\n eventType: e?.eventType,\n /* ์ปค๋„์ด ์ปค๋งจ๋“œ์—์„œ ์ด์–ด ์ค€ ๊ฐ’ โ€” ์ด๊ฒƒ์ด ๊ฐ์‚ฌ ๊ธฐ๋ก๊ณผ ์ €๋„์„ ์ž‡๋Š” ๋‹ค๋ฆฌ๋‹ค. */\n correlationId: e?.correlationId,\n revision,\n /* **์ด ์‚ฌ์‹ค์ด ์ผ์–ด๋‚œ ๊ณต์žฅ**์„ ํ•จ๊ป˜ ์ฐ๋Š”๋‹ค โ€” ์ด๊ฒƒ์ด ์—†์œผ๋ฉด ๋‚˜์ค‘์— ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ์—ˆ์„ ๋•Œ ์ด ํ–‰์„\n ์ƒˆ ๊ณต์žฅ์— ๋Œ€๊ณ  ์ ‘๊ฒŒ ๋˜๊ณ , ๊ทธ๋•Œ ์—†๋˜ ์„ค๋น„์—์„œ ์ผ์ด ์žˆ์—ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค. */\n ...(structureRev === undefined ? {} : { structureRev }),\n /* ์ปค๋„์€ ISO ๋ฌธ์ž์—ด์„ ์ค€๋‹ค. ์ปฌ๋Ÿผ์€ ๋‚ ์งœ๋‹ค โ€” **์—ฌ๊ธฐ์„œ ์˜ฎ๊ธด๋‹ค.** ๋ฌธ์ž์—ด์„ ๊ทธ๋Œ€๋กœ ๋„ฃ์œผ๋ฉด\n ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ์ œ ํ˜•์‹์œผ๋กœ ์ •๊ทœํ™”ํ•˜์ง€ ์•Š์•„, ๋‚˜์ค‘์— ๋‚ ์งœ๋กœ ๊ฑฐ๋Š” ์งˆ์˜์— ์•ˆ ๊ฑธ๋ฆฐ๋‹ค. */\n eventTime: this.toEventTimeValue(e?.eventTime),\n ...twinEventKeys(e),\n payload: e\n })\n }\n\n /**\n * ์ด ํŠธ์œˆ์ด ์ง€๊ธˆ ์–ด๋А ๊ตฌ์กฐ๋กœ ๋„๋Š”๊ฐ€ โ€” ์ด๋ฒคํŠธ์— ์ฐ์„ ๋ฒˆํ˜ธ. ํ•œ ๋ฒˆ ์ฝ๊ณ  ์บ์‹œํ•œ๋‹ค(์“ฐ๊ธฐ๋งˆ๋‹ค ์กฐํšŒ ๊ธˆ์ง€).\n *\n * ์—†์œผ๋ฉด `undefined` ๋‹ค โ€” 0 ์ด ์•„๋‹ˆ๋‹ค. ๊ตฌ์กฐ ๋ฆฌ๋น„์ „์ด ์ƒ๊ธฐ๊ธฐ ์ „์— ๋งŒ๋“ค์–ด์ง„ ํŠธ์œˆ์€ ์•„์ง ๋ฆฌ๋น„์ „์ด\n * ์—†๊ณ , ๊ทธ ์‚ฌ์‹ค์„ 0 ์ด๋ผ๋Š” **์œ ํšจํ•ด ๋ณด์ด๋Š” ๋ฒˆํ˜ธ**๋กœ ์œ„์žฅํ•˜๋ฉด ์•ˆ ๋œ๋‹ค.\n */\n private static structureRevCache: Record<string, number> = {}\n static async structureRevOf(domainId: string, instanceId: string): Promise<number | undefined> {\n const key = runtimeKey(domainId, instanceId)\n const cached = this.structureRevCache[key]\n if (cached !== undefined) return cached\n const latest = await getRepository(TwinStructure).findOne({ where: { domain: { id: domainId }, instanceId }, order: { rev: 'DESC' } })\n if (latest) this.structureRevCache[key] = latest.rev\n return latest?.rev\n }\n\n /** live ์ €๋„ ๋ฐฐ์น˜ ๊ธฐ๋ก โ€” ๋ชจ์•„๋‘” CanonicalEnvelope ๋“ค์— startRevision+1.. ์„ ๋ถ€์—ฌํ•ด ๋ฒŒํฌ ์ €์žฅ(coalescer tick ๋‹น 1ํšŒ). */\n static async persistBatch(domainId: string, instanceId: string, envelopes: any[], startRevision: number): Promise<void> {\n const repo = getRepository(TwinEvent)\n const structureRev = await this.structureRevOf(domainId, instanceId)\n const rows = envelopes.map((e, i) => this.journalRow(repo, domainId, instanceId, e, startRevision + i + 1, structureRev))\n await repo.save(rows, { chunk: 500 })\n }\n\n /** ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ upsert(๋„๋ฉ”์ธ+instanceId ์œ ๋‹ˆํฌ). status ์ธ์ž๋กœ provision(stopped)/start(running) ๊ณต์šฉ. */\n static async register(\n domainId: string,\n instanceId: string,\n kind: string,\n model: TwinModelDef,\n status: 'running' | 'stopped' = 'running',\n restartPolicy?: RestartPolicy,\n origin?: any,\n /*\n * ์‚ฌ๋žŒ์ด ๋ถ€๋ฅด๋Š” ์ด๋ฆ„๊ณผ **๋ˆ„๊ฐ€ ํ–ˆ๋‚˜** โ€” ์—…๋ฌดํ‚ค๋ฅผ ๋‚˜๋ˆ  ๋‘” ๋Œ€๊ฐ€๋กœ ์ด๋ฆ„์„ ํ•จ๊ป˜ ์‹ค์–ด์•ผ ํ•œ๋‹ค.\n * ์‚ฌ๋žŒ ์—†๋Š” ๊ฒฝ๋กœ(๋ถ€ํŒ… ์ž๋™ ํ”„๋กœ๋น„์ €๋‹ยท๋ณต๊ตฌ)๋Š” `actor` ๋ฅผ ์ฃผ์ง€ ์•Š๋Š”๋‹ค โ€” ์•„๋ฌด ์‚ฌ์šฉ์ž๋ฅผ ์ ์œผ๋ฉด\n * ๊ฐ์‚ฌ ๊ธฐ๋ก์ด ๊ฑฐ์ง“์ด ๋œ๋‹ค.\n */\n meta?: { name?: string; description?: string; actor?: { id: string } }\n ): Promise<void> {\n const repo = getRepository(TwinInstance)\n const existing = await repo.findOne({ where: { domain: { id: domainId }, instanceId } })\n await repo.save(\n repo.create({\n ...(existing ?? {}),\n domain: { id: domainId } as any,\n instanceId,\n kind,\n model,\n // ์ธ์Šคํ„ด์Šคโ†”๊ณต๊ฐ„ 1๊ธ‰ ๋งํฌ(space #3) โ€” model.spaceId/areaId ๋ฅผ ์ปฌ๋Ÿผ์œผ๋กœ ์Šน๊ฒฉ(dual-write). model JSON ๋„ ์œ ์ง€(์ปค๋„ยท๋ณต๊ตฌ์šฉ).\n spaceId: (model as any)?.spaceId ?? existing?.spaceId,\n areaId: (model as any)?.areaId ?? existing?.areaId,\n /* ์žฌ๊ธฐ๋™ ์ •์ฑ…(ADR-0029 ยง2) โ€” ๋ช…์‹œ๊ฐ’ ์šฐ์„ , ์—†์œผ๋ฉด ๊ธฐ์กด๊ฐ’ ๋ณด์กด(์žฌํ”„๋กœ๋น„์ „์ด ์„ ์–ธ์„ ์ง€์šฐ์ง€ ์•Š๊ฒŒ).\n **๋‘˜ ๋‹ค ์—†์œผ๋ฉด ๋˜์ง„๋‹ค**: ์˜ˆ์ „์—๋Š” ์—ฌ๊ธฐ์„œ ๊ธฐ๋ณธ๊ฐ’์„ ๊ฐ์ธํ–ˆ๋Š”๋ฐ, ๊ทธ ๊ธฐ๋ณธ๊ฐ’์ด ใ€Œ์ €๋„ ์ดˆ๊ธฐํ™”ใ€๋ผ์„œ\n ์„ ์–ธ์„ ๋น ๋œจ๋ฆฐ ํ”„๋กœ๋น„์ €๋‹์ด ์กฐ์šฉํžˆ ์ด๋ ฅ์„ ์ง€์šฐ๋Š” ํŠธ์œˆ์„ ๋งŒ๋“ค์—ˆ๋‹ค. ์„ ์–ธ์€ ๋ถ€๋ฅด๋Š” ์ชฝ์˜ ๋ชซ์ด๋‹ค. */\n restartPolicy:\n restartPolicy ??\n readRestartPolicy(\n existing?.restartPolicy,\n `register(\"${instanceId}\") did not declare a restart policy and the stored row has none`\n ),\n /* ์šฉ๋„๋„ ๊ฐ์ธํ•œ๋‹ค. ๋ฒค์น˜๋กœ ๋’ค์ง‘๋Š” ๊ฒƒ์€ `setPurpose` ํ•˜๋‚˜๋ฟ์ด๋ฏ€๋กœ ๊ธฐ์กด๊ฐ’์„ ๋ฐ˜๋“œ์‹œ ๋ณด์กดํ•œ๋‹ค\n โ€” ์—ฌ๊ธฐ์„œ ๋ฎ์œผ๋ฉด ์žฌํ”„๋กœ๋น„์ „์ด ๋ฒค์น˜ ์‚ฌ๋ณธ์„ ์šด์˜ ํŠธ์œˆ์œผ๋กœ ๋˜๋Œ๋ฆฐ๋‹ค. */\n purpose: existing?.purpose ?? 'operational',\n /* **๋‹ค์‹œ ์ฝ๋Š” ๋ฐฉ๋ฒ•**์„ ๊ฐ์ธํ•œ๋‹ค. ๋ช…์‹œ๊ฐ’ ์šฐ์„ , ์—†์œผ๋ฉด ๊ธฐ์กด๊ฐ’ ๋ณด์กด โ€” ์›์ฒœ์„ ๋ชจ๋ฅด๋Š” ํ˜ธ์ถœ์ด\n ํ•œ ๋ฒˆ ์ง€๋‚˜๊ฐ€๋ฉด์„œ ์ด๋ฏธ ์•Œ๋˜ ๊ฒƒ์„ ์ง€์›Œ ๋ฒ„๋ฆฌ๋ฉด, ๊ทธ ํŠธ์œˆ์€ ๋‹ค์‹œ ์ฝ์„ ์ˆ˜ ์—†๋Š” ํŠธ์œˆ์ด ๋œ๋‹ค. */\n origin: origin ?? existing?.origin ?? null,\n /* ์ด๋ฆ„์€ **๋ฎ์ง€ ์•Š๊ณ  ์ฑ„์šด๋‹ค** โ€” ์‚ฌ์šฉ์ž๊ฐ€ ๊ณ ์นœ ์ด๋ฆ„์„ ์žฌํ”„๋กœ๋น„์ „์ด ๋˜๋Œ๋ฆฌ๋ฉด ์•ˆ ๋œ๋‹ค. */\n name: existing?.name ?? meta?.name ?? null,\n description: existing?.description ?? meta?.description ?? null,\n /* ๋งŒ๋“  ์‚ฌ๋žŒ์€ ์ฒ˜์Œ ํ•œ ๋ฒˆ๋งŒ. ๊ณ ์นœ ์‚ฌ๋žŒ์€ ์‚ฌ๋žŒ์ด ํ•œ ๊ฒฝ์šฐ์—๋งŒ ๊ฐฑ์‹ ํ•œ๋‹ค. */\n ...(existing ? {} : meta?.actor ? { creator: { id: meta.actor.id } as any } : {}),\n ...(meta?.actor ? { updater: { id: meta.actor.id } as any } : {}),\n status\n })\n )\n }\n\n /**\n * ๋ผ์ด๋ธŒ ๊ตฌ์กฐ ๋ณ€์ด(resource.add ๋“ฑ)๋ฅผ ์ €์žฅ๋œ model ์— ๋ฐ˜์˜ โ€” ๋Ÿฐํƒ€์ž„ ์ปค๋„์˜ ๋ฌด๋ฒ„๋ฅผ registry model.equipment ์— ๋™๊ธฐ.\n * ์ด๊ฒŒ ์—†์œผ๋ฉด ๋Ÿฐํƒ€์ž„์—” ์ถ”๊ฐ€๋ผ๋„(์ƒํƒœยท์ €๋„์—” ๋ฐ˜์˜) ์ €์žฅ model ๋Š” ์›๋ณธ์ด๋ผ ํ”„๋กœ๋น„์ €๋‹ ํŽธ์ง‘๊ธฐยท์žฌ๊ธฐ๋™(loadTwinModel)์ด\n * ์ถ”๊ฐ€๋ถ„์„ ์žƒ๋Š”๋‹ค. ๊ธฐ์กด model.equipment ํ•ญ๋ชฉ์€ ๋ณด์กด(homeLocation ์œ ์ง€)ํ•˜๊ณ  ์ƒˆ id ๋งŒ append(์ถ”๊ฐ€ ์‹œ์  location=homeLocation).\n * ์ขŒํ‘œ(layout)๋งŒ ๋‹ค๋ฃจ๋Š” register ์™€ ๋‹ฌ๋ฆฌ equipment ์ง‘ํ•ฉ์„ ๊ฐฑ์‹ ํ•˜๋‚˜, ์žฌํ”„๋กœ๋น„์ „(purge)์ด ์•„๋‹ˆ๋ผ in-place ๊ฐฑ์‹ ์ด๋ผ\n * ์ €๋„์€ ๋ณด์กด๋œ๋‹ค(์ถ”๊ฐ€๋Š” ์ด๋ฏธ equipment ๋ธํƒ€๋กœ ์ €๋„๋จ โ†’ replay ๋Š” id-keyed upsert ๋ผ ์ด์ค‘๊ณ„์‚ฐ ์—†์Œ).\n */\n static async syncBoardEquipment(domainId: string, instanceId: string): Promise<void> {\n const inst = this.instances[runtimeKey(domainId, instanceId)]\n const snap = inst?.kernel?.getSnapshot?.()\n if (!snap?.equipment) return\n const repo = getRepository(TwinInstance)\n const reg = await repo.findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!reg?.model) return\n const model = reg.model as TwinModelDef\n const known = new Set((model.equipment ?? []).map(m => m.id))\n const added = snap.equipment\n .filter((m: any) => !known.has(m.id))\n .map((m: any) => ({ id: m.id, kind: m.kind, homeLocation: m.location }))\n if (!added.length) return\n model.equipment = [...(model.equipment ?? []), ...added]\n reg.model = model\n await repo.save(reg)\n }\n\n /**\n * ํ”„๋กœ๋น„์ €๋‹ โ€” ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ๊ตฌ์กฐ(model)๋ฅผ ๋“ฑ๋ก๋งŒ ํ•˜๊ณ  ๊ธฐ๋™ํ•˜์ง€ ์•Š์Œ(status='stopped').\n * ์žฌํ”„๋กœ๋น„์ „ ์‹œ ๊ตฌ์กฐ ์‹œ๊ทธ๋‹ˆ์ฒ˜๊ฐ€ ๋ฐ”๋€Œ๋ฉด(๋…ธ๋“œยท๋ฌด๋ฒ„ ์ง‘ํ•ฉ/์†์„ฑ ๋ณ€๊ฒฝ) ๊ธฐ์กด ์ €๋„์„ purge ํ•œ๋‹ค(ADR-0015):\n * model ๋Š” replay ์˜ ๋งˆ์Šคํ„ฐ๋ผ ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๊ณผ๊ฑฐ ์ด๋ฒคํŠธ์˜ ์ „์ œ๊ฐ€ ๊นจ์ง„๋‹ค. ์ขŒํ‘œ(layout)๋งŒ ๋ฐ”๋€Œ๋ฉด ์ €๋„ ๋ณด์กด.\n */\n /**\n * ์‹คํ–‰ ์ค‘์ด๋ฉด ๊ตฌ์กฐ๋ฅผ ๊ต์ฒดํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” **ํŒ์ • ๋ฌธ์žฅ์„ ํ•œ ๊ณณ์— ๋‘”๋‹ค.**\n *\n * ์ธ์ œ์ŠคํŠธ๋Š” ์ „๋Ÿ‰ ๊ต์ฒด๋ผ, ์ด๋ฒคํŠธ๋ฅผ ์ ‘๊ณ  ์žˆ๋Š” ์ปค๋„ ๋ฐ‘์—์„œ ๋ฐ”๋‹ฅ์„ ๋ฐ”๊พธ๋Š” ์…ˆ์ด ๋œ๋‹ค. ์ง€๊ธˆ์€ ๊ฑฐ์ ˆ์ด\n * ์œ ์ผํ•œ ๋‹ต์ด์ง€๋งŒ ์ตœ์ข…ํ˜•์€ ์•„๋‹ˆ๋‹ค(`adoptStructure` ๋ฐฐ์„ ). ๋‘ ๊ณณ์—์„œ ๊ฐ™์€ ๋ฌธ์žฅ์œผ๋กœ ๊ฑฐ์ ˆํ•ด์•ผ\n * ๋‚˜์ค‘์— ์ด ๊ทœ์น™์„ ๊ฑท์–ด๋‚ผ ๋•Œ ๊ฑท์–ด๋‚ผ ๊ฒƒ์ด ํ•˜๋‚˜๋กœ ๋ณด์ธ๋‹ค.\n */\n private static assertNotRunning(domainId: string, instanceId: string): void {\n if (!this.instances[runtimeKey(domainId, instanceId)]) return\n /*\n * **๊ฑฐ์ ˆ๋„ ๋ฒˆ์—ญ๋ผ์•ผ ํ•œ๋‹ค.** ์ด ๋ฌธ์žฅ์€ ๋˜์ ธ์ ธ์„œ ๋ฆฌ์กธ๋ฒ„์˜ `catch` ๋ฅผ ์ง€๋‚˜ ํ™”๋ฉด ํ† ์ŠคํŠธ์— ๊ทธ๋Œ€๋กœ\n * ๋–ด๋‹ค โ€” ๋‹ค์„ฏ ์–ธ์–ด ์ œํ’ˆ์—์„œ ์˜์–ด ํ•œ ์ค„์ด ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์˜€๋‹ค(2026-08-14 ์‹ค์ธก).\n *\n * ๊ทธ๋ž˜์„œ ์ฝ”๋“œ์™€ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์˜ˆ์™ธ์— ์‹ค์–ด ๋ณด๋‚ธ๋‹ค(`ImportSpaceRefusal` ๊ณผ ๊ฐ™์€ ๊ทœ์•ฝ: ์˜์–ด ๋ฌธ์žฅ์€\n * canonical ์ด๊ณ  ๋กœ๊ทธยทํด๋ฐฑ์œผ๋กœ๋งŒ ์“ฐ์ธ๋‹ค). ์ด์œ ๊ฐ€ ์ฝ”๋“œ๋กœ ์˜ค๋ฉด ํ™”๋ฉด์ด ์˜ฎ๊ธธ ์ˆ˜ ์žˆ๋‹ค.\n */\n const err: any = new Error(`instance \"${instanceId}\" is running โ€” stop before re-provisioning`)\n err.code = 'twin-running'\n err.params = { instanceId }\n throw err\n }\n\n /**\n * ๋Œ๋ฉด์„œ ๊ณต์žฅ์„ ์ „ํ™˜ํ•œ๋‹ค โ€” **๋ฏธ๋Ÿฌ ์ „์šฉ.**\n *\n * ๋ฏธ๋Ÿฌ๊ฐ€ ๋น„์ถ”๋Š” ํ˜„์‹ค์€ ์•ˆ ๋ฉˆ์ถ˜๋‹ค. ์„ค๋น„ ํ•œ ๋Œ€๊ฐ€ ๋Š˜์—ˆ๋‹ค๊ณ  ํŠธ์œˆ์„ ๋ฉˆ์ท„๋‹ค ์„ธ์šฐ๋ฉด ๊ทธ ์‚ฌ์ด์˜ ์‚ฌ์‹ค์„\n * ์žƒ๊ณ , ๋ผ์ด๋ธŒ์—์„œ ์œ ์‹ค์€ ๊ณง ๊ฑฐ์ง“์ด๋‹ค. ๊ทธ๋ž˜์„œ ๋ฏธ๋Ÿฌ๋Š” **๋™์ž‘ ์ค‘์—** ์ƒˆ ๊ตฌ์กฐ๋ฅผ ๋ฐ›๋Š”๋‹ค.\n *\n * ์‹œ๋ฎฌ๋ ˆ์ด์…˜์€ ์—ฌ๊ธฐ ์˜ค์ง€ ์•Š๋Š”๋‹ค. ์กฐ๊ฑด์ด ๋ฐ”๋€ ์‹คํ—˜์€ ๋‹ค๋ฅธ ์‹คํ—˜์ด๋ฏ€๋กœ ๋ฉˆ์ถ”๊ณ  ๋‹ค์‹œ ์„ธ์šฐ๋Š” ๊ฒƒ์ด\n * ์˜ณ๋‹ค โ€” ์ปค๋„์ด ๊ทธ๋ ‡๊ฒŒ ๊ฑฐ์ ˆํ•œ๋‹ค(`FlowEngine.adoptStructure`).\n *\n * ์„ธ ๊ฐ€์ง€๊ฐ€ **ํ•จ๊ป˜** ์ผ์–ด๋‚˜์•ผ ํ•œ๋‹ค. ํ•˜๋‚˜๋ผ๋„ ๋น ์ง€๋ฉด ์ธต์ด ์–ด๊ธ‹๋‚œ๋‹ค:\n * โ‘  ๋ฆฌ๋น„์ „ โ€” ์ด ์‹œ์  ์ดํ›„์˜ ์ด๋ฒคํŠธ๊ฐ€ ์ƒˆ ๋ฒˆํ˜ธ๋ฅผ ๋‹ฌ๊ณ  ๋‹ค๋‹Œ๋‹ค(์žฌ์ƒ์ด ๋งˆ๋””๋ฅผ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๊ฒŒ)\n * โ‘ก ์ €์žฅ modelยท๊ตฌ์กฐ ํ–‰ โ€” ์กฐํšŒ๊ฐ€ ์ƒˆ ๊ตฌ์กฐ๋ฅผ ๋ณธ๋‹ค\n * โ‘ข ์ปค๋„ โ€” ์ง€๊ธˆ ์ ‘ํžˆ๋Š” ์ด๋ฒคํŠธ๊ฐ€ ์ƒˆ ๊ตฌ์กฐ ์œ„์—์„œ ์ ‘ํžŒ๋‹ค\n */\n static async adoptStructure(\n domainId: string,\n instanceId: string,\n model: TwinModelDef,\n comment?: string,\n origin?: any\n ): Promise<{ rev: number } & StructureShift> {\n const inst = this.instances[runtimeKey(domainId, instanceId)]\n if (!inst) throw new Error(`instance \"${instanceId}\" is not running โ€” provision it instead of adopting`)\n if (inst.mode !== 'live')\n throw new Error(`instance \"${instanceId}\" is a simulation โ€” stop it and re-provision (a changed experiment is a different experiment)`)\n\n const reg = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!reg) throw new Error(`instance \"${instanceId}\" is running but not registered โ€” refusing to adopt into an unknown twin`)\n\n const rev = await this.recordStructure(domainId, instanceId, model, comment)\n await this.register(domainId, instanceId, reg.kind, model, 'running', undefined, origin)\n /* ์ปค๋„์„ **๋งˆ์ง€๋ง‰์—** ์ „ํ™˜ํ•œ๋‹ค โ€” ์ €์žฅ์ด ์‹คํŒจํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ๋งŒ ์ƒˆ ๊ตฌ์กฐ๊ฐ€ ๋˜์–ด, ์žฌ๊ธฐ๋™ํ•˜๋ฉด ์กฐ์šฉํžˆ\n ์˜› ๊ตฌ์กฐ๋กœ ๋Œ์•„๊ฐ„๋‹ค(๊ณ ์น˜๊ธฐ ์–ด๋ ค์šด ์–ด๊ธ‹๋‚จ์ด๋‹ค). */\n const shift: StructureShift = inst.kernel.adoptStructure(model)\n /*\n * **๊ณต์ • ๋ช…์„ธยทํ˜„์žฅ์ด ์ •ํ•œ ์‹œ๊ฐ„๋„ ํ•จ๊ป˜ ์‹ฃ๋Š”๋‹ค** โ€” ์ปค๋„์˜ ๊ตฌ์กฐ ์ „ํ™˜์€ ์ž๋ฆฌยท์„ค๋น„๋ฅผ ๊ฐˆ์ง€๋งŒ, ๊ณต์ • ์‹œ๊ฐ„์€\n * ํ˜ธ์ŠคํŠธ๊ฐ€ ์‹ค์–ด ์ฃผ๋Š” ๊ฒƒ์ด๋ฏ€๋กœ(`model.localDurations`) ์—ฌ๊ธฐ์„œ ๋‹ค์‹œ ๋ถ€๋ฅด์ง€ ์•Š์œผ๋ฉด ๋Œ๊ณ  ์žˆ๋Š” ๋ฏธ๋Ÿฌ๋Š”\n * ์žฌ๊ธฐ๋™ํ•  ๋•Œ๊นŒ์ง€ ์˜› ์‹œ๊ฐ„์œผ๋กœ ๋ˆ๋‹ค(ํ™”๋ฉด์€ ใ€Œ๋„ฃ์—ˆ์Šต๋‹ˆ๋‹คใ€๋ผ๊ณ  ๋งํ•œ ๊ฐ’์ด๋‹ค).\n */\n this.applyOperations(inst.kernel, model, instanceId)\n\n /*\n * **ํˆฌ์˜ ํ–‰๋„ ์ƒˆ ๊ตฌ์กฐ๋ฅผ ๋”ฐ๋ฅธ๋‹ค** (2026-08-18 ์‹ค์ธก์œผ๋กœ ๋ถ™์ž„).\n *\n * ํ–‰(`twin_locations`ยท`twin_equipment`)์€ ๊ตฌ์กฐ์˜ ์บ์‹œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด ๊ฒฝ๋กœ๋Š” ์ปค๋„๋งŒ ๊ฐˆ๊ณ  ํ–‰์€ ๊ทธ๋Œ€๋กœ\n * ๋‘์—ˆ๋‹ค โ€” ๋Œ๊ณ  ์žˆ๋Š” ๋ฏธ๋Ÿฌ์— ๊ฐ’์„ ์„ ์–ธํ•˜๋ฉด ์ปค๋„์€ ์ƒˆ ๊ฐ’์œผ๋กœ ๊ณ„์‚ฐํ•˜๋Š”๋ฐ **ํ•ญ๋ชฉ ํŒจ๋„์€ ์˜› ํ–‰์„ ๋ณด์—ฌ\n * ์ค€๋‹ค**(๋„ฃ์€ ๊ฐ’์ด ํ™”๋ฉด์—์„œ ๋ณด์ด์ง€ ์•Š๋Š”๋‹ค). ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€ ์ˆœ๊ฐ„์ด ๊ณง ์บ์‹œ๋ฅผ ๋‹ค์‹œ ๊ทธ๋ฆด ์ˆœ๊ฐ„์ด๋‹ค.\n *\n * ์‹คํŒจ๋Š” ํก์ˆ˜ํ•œ๋‹ค: ํˆฌ์˜์ด ๋ง‰ํ˜€๋„(์˜ˆ: ๋ชจ๋ธ์— ์ค‘๋ณต id) ์ปค๋„์€ ์ด๋ฏธ ์ƒˆ ๊ตฌ์กฐ๋กœ ๋Œ๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๊ทธ ์‚ฌ์‹ค์„\n * ๋˜๋Œ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค โ€” ๋‹ค๋งŒ ์กฐ์šฉํžˆ ๋„˜๊ธฐ์ง€ ์•Š๊ณ  ๋งํ•œ๋‹ค.\n */\n await projectStructure(domainId, instanceId, model, instanceId).catch((err: any) =>\n console.warn(`[twin-engine] \"${instanceId}\" adopted a new structure but its projected rows were not refreshed โ€” ${err?.message ?? err}`)\n )\n\n /*\n * **๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€ ์ˆœ๊ฐ„์ด ์ƒํƒœ๊ฐ€ ๋ฐ”๋€ ์ˆœ๊ฐ„์ด๋‹ค** โ€” ๊ทธ๋Ÿฌ๋‹ˆ ๋ฐฉ์†กํ•œ๋‹ค.\n *\n * โ”€โ”€ ๋ฌด์—‡์ด ๋‚ฌ๋‚˜ (2026-08-18) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๊ตฌ์กฐ ์ „ํ™˜์€ ์ปค๋„๋งŒ ๊ฐˆ๊ณ  ์กฐ์šฉํžˆ ๋๋‚ฌ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ํ™”๋ฉด์ด ๋ณด๋Š” ๊ฒƒ ์ƒ๋‹น์ˆ˜๊ฐ€ ๊ตฌ์กฐ์—์„œ ํŒŒ์ƒ๋œ๋‹ค โ€”\n * ๊ณ„์•ฝ ๋Œ€๋น„ ํŒ์ •, ์ฃผ๋ชฉ ์‹ ํ˜ธ, ์ž๋ฆฌ ์ƒ‰. ํ˜„์žฅ์ด ๊ณ„์•ฝ์„ ๊ณ ์ณ ์„ ์–ธํ•œ ์ˆœ๊ฐ„ ์กฐ๊ฑด์ด ์„ฑ๋ฆฝํ•˜๋Š”๋ฐ๋„, ์ƒํƒœ\n * ๋ฐฉ์†ก์ด ์—†์–ด์„œ ์ง€๋„ ๋ ˆ์ผ์€ **๋‹ค์Œ ๊ณ„์ธก ํ‘œ๋ณธ์ด ์˜ฌ ๋•Œ๊นŒ์ง€** ์˜› ํ™”๋ฉด์„ ๋“ค๊ณ  ์žˆ์—ˆ๋‹ค(๊ทธ ์‚ฌ์ด ํ—ค๋”\n * ๋ฐฐ์ง€๋Š” 4์ดˆ ํด๋ง์œผ๋กœ ๋จผ์ € ์•Œ์•„, ใ€Œ๋ฐฐ์ง€์—” ์žˆ๊ณ  ๋ชฉ๋ก์—” ์—†๋Š”ใ€ ์–ด๊ธ‹๋‚œ ํ™”๋ฉด์ด ์‹ค์ œ๋กœ ๋ณด์˜€๋‹ค).\n *\n * ์ƒˆ ๋ฐฉ์†ก ๊ฒฝ๋กœ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค: dirty ๋ฅผ ์„ธ์›Œ **์ด๋ฏธ ์žˆ๋Š” ๋ณ‘ํ•ฉ ๊ทœ์œจ**(200ms)์— ์–น๋Š”๋‹ค. ๊ตฌ์กฐ ์ „ํ™˜์€\n * ๋“œ๋ฌผ์ง€๋งŒ, ์—ฌ๋Ÿฌ ํŠธ์œˆ์— ์ž‡๋‹ฌ์•„ ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ๊ณ (ํ˜„์žฅ ์ผ๊ด„ ์„ ์–ธ) ๊ทธ๋•Œ๋„ ๋ฐฉ์†ก๋ฅ  ์ƒํ•œ์€ ์ง€์ผœ์•ผ ํ•œ๋‹ค.\n */\n inst.dirty = true\n this.ensureBroadcastCoalescer()\n\n return { rev, ...shift }\n }\n\n static async provision(\n domainId: string,\n instanceId: string,\n kind: string,\n model: TwinModelDef,\n /**\n * **์žฌ๊ธฐ๋™ ์ •์ฑ…์€ ์ƒ์„ฑ ์‹œ์ ์˜ ์„ ์–ธ์ด๋‹ค**(ADR-0029 ยง2) โ€” ํŠธ์œˆ์€ ์ •์ฑ… ์—†์ด ์กด์žฌํ•  ์ˆ˜ ์—†๋‹ค.\n *\n * ์˜ˆ์ „์—๋Š” ์ด ์ž๋ฆฌ๊ฐ€ ์—†์—ˆ๊ณ  `register` ๊ฐ€ ๊ธฐ๋ณธ๊ฐ’(`sim-experiment` = ์ €๋„ ์ดˆ๊ธฐํ™”)์„ ๊ฐ์ธํ–ˆ๋‹ค. ๊ทธ๋ž˜์„œ\n * ์„ ์–ธ์„ ๋น ๋œจ๋ฆฐ ํ”„๋กœ๋น„์ €๋‹์ด **์žฌ๊ธฐ๋™๋งˆ๋‹ค ์ด๋ ฅ์„ ์ง€์šฐ๋Š” ํŠธ์œˆ**์„ ์กฐ์šฉํžˆ ๋งŒ๋“ค์—ˆ๋‹ค. ์ด์ œ ๋งŒ๋“œ๋Š” ์ชฝ์ด\n * ๋งํ•ด์•ผ ํ•œ๋‹ค: ์ด ํŠธ์œˆ์ด ์ž๊ธฐ ๊ณผ๊ฑฐ๋ฅผ ์–ด๋–ป๊ฒŒ ๋Œ€ํ•˜๋Š”์ง€๋Š” ๋งŒ๋“œ๋Š” ์‚ฌ๋žŒ์ด ์•„๋Š” ์‚ฌ์‹ค์ด๋‹ค.\n */\n restartPolicy: RestartPolicy,\n comment?: string,\n origin?: any,\n /** ์ด๋ฆ„ยท์ €์ž โ€” ์—…๋ฌดํ‚ค๋ฅผ ๋‚˜๋ˆ  ๋‘” ๋Œ€๊ฐ€๋กœ ์ด๋ฆ„์„ ํ•จ๊ป˜ ๋‚จ๊ธด๋‹ค(`register` ์˜ `meta` ๊ทธ๋Œ€๋กœ). */\n meta?: { name?: string; description?: string; actor?: { id: string } }\n ): Promise<void> {\n this.assertNotRunning(domainId, instanceId)\n /* ์ข…๋ฅ˜๋ฅผ **์ €์žฅํ•˜๊ธฐ ์ „์—** ๊ฒ€์ฆํ•œ๋‹ค. ๋‚˜์ค‘์— ๊ธฐ๋™ํ•  ๋•Œ ๊ฑธ๋ฆฌ๋ฉด ์›์ธ์ด ํ”„๋กœ๋น„์ €๋‹์—์„œ ๋ฉ€์–ด์ง€๊ณ ,\n ๊ทธ ์‚ฌ์ด ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์—๋Š” ๋Œ๋ฆด ์ˆ˜ ์—†๋Š” ํŠธ์œˆ์ด ์•‰์•„ ์žˆ๋‹ค. */\n kernelFor(kind)\n const repo = getRepository(TwinInstance)\n const existing = await repo.findOne({ where: { domain: { id: domainId }, instanceId } })\n\n /*\n * **๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ์–ด๋„ ์—ญ์‚ฌ๋ฅผ ์ง€์šฐ์ง€ ์•Š๋Š”๋‹ค.**\n *\n * ์˜ˆ์ „์—๋Š” ์„œ๋ช…์ด ๋‹ค๋ฅด๋ฉด ๊ทธ ํŠธ์œˆ์˜ ์ €๋„์„ ํ†ต์งธ๋กœ ์ง€์› ๋‹ค. ์•ˆ ์ง€์šฐ๋ฉด ์˜› ์ด๋ฒคํŠธ๋ฅผ ์ƒˆ ๊ณต์žฅ์— ๋Œ€๊ณ \n * ์ ‘๊ฒŒ ๋˜์–ด ์ด๋ ฅ์ด ๊ฑฐ์ง“๋ง์„ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค โ€” ๋ถ€์Šค๊ฐ€ ๋‘˜์ด๋˜ ์‹œ์ ˆ์˜ ์‚ฌ์‹ค์„ ์—ฌ์„ฏ ๊ฐœ์งœ๋ฆฌ ๊ณต์žฅ์—\n * ์ ‘์œผ๋ฉด ๊ทธ๋•Œ ์—†๋˜ ๋ถ€์Šค์—์„œ ์ผ์ด ์žˆ์—ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค. ์„ ํƒ์ง€๊ฐ€ **์—ญ์‚ฌ๋ฅผ ์žƒ๊ฑฐ๋‚˜ ๊ฑฐ์ง“๋ง์„\n * ํ•˜๊ฑฐ๋‚˜** ๋‘˜๋ฟ์ด์—ˆ๊ณ , ๊ทธ๋ž˜์„œ ๊ณต์žฅ์„ ๊ณ ์น  ๋•Œ๋งˆ๋‹ค ์ด๋ ฅ์„ ๋ฒ„๋ ค์•ผ ํ–ˆ๋‹ค.\n *\n * ์ด์ œ ์…‹์งธ ๊ธธ๋กœ ๊ฐ„๋‹ค: ๋ฐ”๋€ ๊ตฌ์กฐ๋ฅผ **์ƒˆ ๋ฆฌ๋น„์ „**์œผ๋กœ ๋‚จ๊ธฐ๊ณ , ์•ž์œผ๋กœ ์“ฐ์ด๋Š” ์ด๋ฒคํŠธ๊ฐ€ ๊ทธ ๋ฒˆํ˜ธ๋ฅผ\n * ๋‹ฌ๊ณ  ๋‹ค๋‹Œ๋‹ค. ์žฌ์ƒ์€ ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ๋Š” ์ง€์ ์—์„œ ์ „ํ™˜ํ•œ ๋’ค ์ด์–ด ์ ‘๋Š”๋‹ค(`replaySegments`).\n */\n await this.recordStructure(domainId, instanceId, model, comment)\n await this.register(domainId, instanceId, kind, model, existing?.status === 'running' ? 'stopped' : (existing?.status as any) ?? 'stopped', restartPolicy, origin, meta)\n }\n\n /**\n * ์ด ๊ตฌ์กฐ๋ฅผ ๋ฆฌ๋น„์ „์œผ๋กœ ๋‚จ๊ธฐ๊ณ  ๊ทธ ๋ฒˆํ˜ธ๋ฅผ ๋Œ๋ ค์ค€๋‹ค โ€” **๋ฐ”๋€Œ์—ˆ์„ ๋•Œ๋งŒ** ์ƒˆ ๋ฒˆํ˜ธ๊ฐ€ ์ƒ๊ธด๋‹ค.\n *\n * ํ”„๋กœ๋น„์ €๋‹์€ ๋ถ€ํŒ…๋งˆ๋‹ค ๋‹ค์‹œ ๋„๋Š”๋ฐ, ๊ทธ๋•Œ๋งˆ๋‹ค ๋ฆฌ๋น„์ „์ด ๋Š˜๋ฉด ์ด๋ ฅ์ด ๋œป ์—†๋Š” ๋งˆ๋””๋กœ ์ž˜๊ฒŒ ์ชผ๊ฐœ์ง„๋‹ค.\n * ๊ทธ๋ž˜์„œ **๊ตฌ์กฐ ์„œ๋ช…์ด ๊ฐ™์œผ๋ฉด ์žˆ๋˜ ๋ฆฌ๋น„์ „์„ ๊ทธ๋Œ€๋กœ ์“ด๋‹ค.**\n */\n static async recordStructure(domainId: string, instanceId: string, model: TwinModelDef, comment?: string): Promise<number> {\n const repo = getRepository(TwinStructure)\n const signature = this.structureFingerprint(model)\n const latest = await repo.findOne({ where: { domain: { id: domainId }, instanceId }, order: { rev: 'DESC' } })\n\n /*\n * **์ €์žฅ๋œ ์ง€๋ฌธ์ด ์•„๋‹ˆ๋ผ ์ €์žฅ๋œ ๊ณต์žฅ๊ณผ ๋น„๊ตํ•œ๋‹ค.**\n *\n * ์ง€๋ฌธ ๊ณ„์‚ฐ ๋ฐฉ์‹์„ ํ•œ ๋ฒˆ์ด๋ผ๋„ ๋ฐ”๊พธ๋ฉด(์›๋ฌธ โ†’ ํ•ด์‹œ๋กœ ๋ฐ”๊ฟจ๋‹ค) ์ €์žฅ๋œ ๋ฌธ์ž์—ด์€ ์ „๋ถ€ ์˜› ๋ฐฉ์‹์˜\n * ๊ฒƒ์ด๋ผ ๋ฌด์—‡๊ณผ๋„ ์•ˆ ๋งž๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋ฉด **์•„๋ฌด๊ฒƒ๋„ ์•ˆ ๋ฐ”๋€ ํŠธ์œˆ๋“ค์ด ์ „๋ถ€ \"๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ์—ˆ๋‹ค\"** ๋กœ\n * ๊ธฐ๋ก๋œ๋‹ค โ€” ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ๋๊ณ , ์žฌ๊ธฐ๋™ ํ•œ ๋ฒˆ์— ๋ฆฌ๋น„์ „์ด ํ†ต์งธ๋กœ ํ•˜๋‚˜์”ฉ ๋Š˜์—ˆ๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ ์•ˆ ๋งž์„ ๋•Œ ํ•œ ๋ฒˆ ๋” ๋ฌป๋Š”๋‹ค: ์ €์žฅ๋œ **๋ชจ๋ธ**๋กœ ์ง€๋ฌธ์„ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜๋ฉด ๊ฐ™์€๊ฐ€? ๊ฐ™๋‹ค๋ฉด\n * ๊ณต์žฅ์€ ๊ทธ๋Œ€๋กœ์ด๊ณ  ์ง€๋ฌธ ํ‘œ๊ธฐ๋งŒ ๋‚ก์€ ๊ฒƒ์ด๋‹ˆ, ๋ฆฌ๋น„์ „์„ ๋งŒ๋“ค์ง€ ์•Š๊ณ  ํ‘œ๊ธฐ๋งŒ ๊ณ ์นœ๋‹ค.\n */\n if (latest && latest.signature !== signature && this.structureFingerprint(latest.model as TwinModelDef) === signature) {\n latest.signature = signature\n await repo.save(latest)\n }\n\n if (latest?.signature === signature) {\n this.structureRevCache[runtimeKey(domainId, instanceId)] = latest.rev\n return latest.rev\n }\n\n const rev = (latest?.rev ?? 0) + 1\n await repo.save(repo.create({ domain: { id: domainId } as any, instanceId, rev, signature, model: model as any, ...(comment ? { comment } : {}) }))\n this.structureRevCache[runtimeKey(domainId, instanceId)] = rev\n /* ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์žฌ๊ตฌ์„ฑ ์บ์‹œ๋Š” ์˜› ๊ณต์žฅ์˜ ๊ฒƒ์ด๋‹ค โ€” ๋ฒ„๋ฆฐ๋‹ค(์ง€์šฐ๋Š” ๊ฑด ์บ์‹œ๋ฟ, ์‚ฌ์‹ค์€ ๋‚จ๋Š”๋‹ค). */\n delete this.recovered[runtimeKey(domainId, instanceId)]\n if (latest) console.info(`[twin-engine] \"${instanceId}\" structure changed โ†’ revision ${rev} (history kept; older events stay under revision ${latest.rev}).`)\n return rev\n }\n\n /**\n * ์ด ํŠธ์œˆ์ด ๊ฑฐ์ณ ์˜จ ๊ตฌ์กฐ๋“ค โ€” **๋ฌด์—‡์ด ์–ธ์ œ ๋‹ฌ๋ผ์กŒ๋‚˜.**\n *\n * ๋ฆฌ๋น„์ „์€ ๊ทธ ์‹œ์ ˆ ๊ณต์žฅ์„ ํ†ต์งธ๋กœ ๋‹ด์ง€๋งŒ(์žฌ์ƒ์— ํ•„์š”ํ•˜๋‹ค), ์‚ฌ๋žŒ์ด ๋ณด๊ณ  ์‹ถ์€ ๊ฒƒ์€ ํ†ต์งธ๊ฐ€ ์•„๋‹ˆ๋ผ\n * ์ฐจ์ด๋‹ค. ๋ชจ๋ธ์€ ๋นผ๊ณ  **์ฐจ์ด ์š”์•ฝ๋งŒ** ๋‚ด๋ณด๋‚ธ๋‹ค โ€” 62KB ์งœ๋ฆฌ ๋ณด๋“œ๋ฅผ ํ™”๋ฉด์— ์‹ค์–ด ๋ณด๋‚ผ ์ด์œ ๊ฐ€ ์—†๋‹ค.\n */\n static async structureHistory(\n domainId: string,\n instanceId: string\n ): Promise<{ rev: number; createdAt?: Date; comment?: string; events: number; diff: StructureDiff }[]> {\n const revs = await getRepository(TwinStructure).find({ where: { domain: { id: domainId }, instanceId }, order: { rev: 'ASC' } })\n if (!revs.length) return []\n\n /* ๋ฆฌ๋น„์ „๋งˆ๋‹ค ๊ทธ ์•„๋ž˜์—์„œ ๋ช‡ ๊ฑด์ด ์ผ์–ด๋‚ฌ๋‚˜ โ€” ์ด๋ ฅ์˜ ๋ฌด๊ฒŒ๋ฅผ ๋ณด์—ฌ์ค€๋‹ค(์งง๊ฒŒ ์Šค์ณ๊ฐ„ ๊ตฌ์กฐ์ธ์ง€). */\n const counts = new Map<number | null, number>()\n for (const row of await getRepository(TwinEvent)\n .createQueryBuilder('e')\n .select('e.structureRev', 'rev')\n .addSelect('COUNT(1)', 'n')\n .where('e.domain = :domainId', { domainId })\n .andWhere('e.instanceId = :instanceId', { instanceId })\n .groupBy('e.structureRev')\n .getRawMany())\n counts.set(row.rev === null || row.rev === undefined ? null : Number(row.rev), Number(row.n))\n\n /* ๋ฒˆํ˜ธ ์—†๋Š” ์˜› ํ–‰์€ **๊ฐ€์žฅ ์˜ค๋ž˜๋œ ๋ฆฌ๋น„์ „**์˜ ๋ชซ์ด๋‹ค โ€” ์žฌ์ƒ์ด ๊ทธ๋ ‡๊ฒŒ ์ ‘์œผ๋ฏ€๋กœ ์„ธ๋Š” ๊ฒƒ๋„ ๊ฐ™์•„์•ผ ํ•œ๋‹ค. */\n const oldest = revs[0].rev\n const legacy = counts.get(null) ?? 0\n\n return revs.map((r, i) => ({\n rev: r.rev,\n createdAt: r.createdAt,\n ...(r.comment ? { comment: r.comment } : {}),\n events: (counts.get(r.rev) ?? 0) + (r.rev === oldest ? legacy : 0),\n diff: diffStructures(i === 0 ? undefined : (revs[i - 1].model as any), r.model as any)\n }))\n }\n\n /** ์ง€๊ธˆ ์“ฐ์ด๋Š” ๊ตฌ์กฐ ๋ฆฌ๋น„์ „ โ€” ์ด๋ฒคํŠธ์— ์ฐ์„ ๋ฒˆํ˜ธ. ์•„์ง ์—†์œผ๋ฉด ๊ธฐ๋กํ•˜๋ฉฐ ๋งŒ๋“ ๋‹ค. */\n static async currentStructureRev(domainId: string, instanceId: string, model?: TwinModelDef): Promise<number | undefined> {\n const latest = await getRepository(TwinStructure).findOne({ where: { domain: { id: domainId }, instanceId }, order: { rev: 'DESC' } })\n if (latest) return latest.rev\n return model ? this.recordStructure(domainId, instanceId, model) : undefined\n }\n\n /** ๊ตฌ์กฐ ๋™์ผ์„ฑ ์ง€๋ฌธ โ€” ์ขŒํ‘œ(layout) ๋“ฑ ๋ทฐ ๊ด€์‹ฌ์‚ฌ๋Š” ์ œ์™ธํ•˜๊ณ  ์ปค๋„์ด ๋ณด๋Š” ์œ„์ƒยท์šฉ๋Ÿ‰ยท๋ฌด๋ฒ„๋งŒ. */\n /**\n * ์ง€๋ฌธ์„ **64์ž๋กœ ์ค„์ธ๋‹ค** โ€” ์ปฌ๋Ÿผ์ด varchar(64) ๋‹ค.\n *\n * ์›๋ฌธ ์ง€๋ฌธ์€ ์ž๋ฆฌยท์„ค๋น„๋ฅผ ์ „๋ถ€ ์ด์–ด ๋ถ™์ธ ๋ฌธ์ž์—ด์ด๋ผ ํฐ ๊ณต์žฅ์—์„œ๋Š” ์ˆ˜๋งŒ ์ž๊ฐ€ ๋œ๋‹ค. sqlite ๋Š”\n * ๊ธธ์ด๋ฅผ ๊ฐ•์ œํ•˜์ง€ ์•Š์•„ ๊ทธ๋ƒฅ ๋“ค์–ด๊ฐ€์ง€๋งŒ **Postgres ๋Š” ๊ฑฐ๊ธฐ์„œ ํ„ฐ์ง„๋‹ค** โ€” ๊ฐœ๋ฐœ์—์„œ๋Š” ๋ฉ€์ฉกํ•˜๊ณ \n * ์šด์˜์—์„œ๋งŒ ์ฃฝ๋Š” ์ข…๋ฅ˜์˜ ์‹คํŒจ๋‹ค. ๋น„๊ต์—๋งŒ ์“ฐ๋Š” ๊ฐ’์ด๋ฏ€๋กœ ํ•ด์‹œ๋กœ ์ถฉ๋ถ„ํ•˜๋‹ค.\n */\n private static structureFingerprint(model: TwinModelDef): string {\n return createHash('sha256').update(this.structureSignature(model)).digest('hex')\n }\n\n private static structureSignature(model: TwinModelDef): string {\n const locations = [...(model.locations ?? [])]\n .map(n => `${n.id}:${n.type}:${n.capacity}`)\n .sort()\n .join('|')\n const equipment = [...(model.equipment ?? [])]\n .map(m => `${m.id}:${m.kind}:${m.homeLocation}`)\n .sort()\n .join('|')\n return `N[${locations}]M[${equipment}]`\n }\n\n /** ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ model ๋กœ ๊ธฐ๋™(ํ”„๋กœ๋น„์ „๋œ ์ธ์Šคํ„ด์Šค start). model ์ธ์ž ์—†์ด ์ €์žฅ๋œ ๊ตฌ์กฐ๋กœ ์žฌ๊ธฐ๋™. */\n static async startFromRegistry(domainId: string, instanceId: string, restartPolicy?: RestartPolicy): Promise<InstanceRuntime> {\n const key = runtimeKey(domainId, instanceId)\n if (this.instances[key]) return this.instances[key]\n const reg = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!reg?.model) throw new Error(`instance \"${instanceId}\" not provisioned (no model)`)\n\n /*\n * ์›œ์Šคํƒ€ํŠธ ์žฌ๋ฃŒ๋ฅผ **์—ฌ๊ธฐ์„œ ํ™•์‹คํžˆ ํ™•๋ณดํ•œ๋‹ค.**\n * `start()` ๋Š” ๋™๊ธฐ๋ผ ์Šค์Šค๋กœ ์บ์‹œ๋ฅผ ์ฝ์„ ์ˆ˜ ์—†์–ด์„œ `recovered` ์— ๋ฏธ๋ฆฌ ๋‹ด๊ฒจ ์žˆ๊ธฐ๋ฅผ ๊ธฐ๋Œ€ํ•˜๋Š”๋ฐ,\n * ๊ทธ๊ฑด `bootstrap()` ์ด ๋จผ์ € ๋Œ์•˜์„ ๋•Œ๋งŒ ์ฐธ์ด๋‹ค. ๋ถ€ํŒ… ์ˆœ์„œ์— ๊ธฐ๋Œ€๋ฉด ์–ด๋–ค ๋‚ ์€ ์žฌ๊ณ ๊ฐ€ ์‚ด์•„๋‚˜๊ณ \n * ์–ด๋–ค ๋‚ ์€ ์กฐ์šฉํžˆ ๋นˆ ์ฑ„๋กœ ๋œฌ๋‹ค โ€” ์žฌํ˜„๋˜์ง€ ์•Š๋Š” ๊ฒฐํ•จ์ด ๊ฐ€์žฅ ๋‚˜์˜๋‹ค.\n * ์ฒดํฌํฌ์ธํŠธ ์บ์‹œ ์šฐ์„ (O(1) + ๋ผ์ด๋ธŒ ํŒŒ์ƒ์ƒํƒœ ๋ณด์กด), ์—†์œผ๋ฉด ์ €๋„ replay ํด๋ฐฑ(๋ถ€ํŒ…๊ณผ ๊ฐ™์€ ์ˆœ์„œ).\n */\n if (!this.recovered[key] && reg.purpose !== 'bench') {\n const cached = await this.loadSnapshot(domainId, instanceId).catch(() => null)\n if (cached?.state) {\n this.recovered[key] = { revision: cached.revision, state: cached.state }\n } else {\n const state = await this.recover(domainId, instanceId).catch(() => null)\n if (state) this.recovered[key] = { revision: state.revision, state }\n }\n }\n\n /*\n * ์ €๋„์— ๋‚จ์•„ ์žˆ๋Š” ๋งˆ์ง€๋ง‰ ๋ฒˆํ˜ธ โ€” **๋ชจ๋“œ์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ** ์ด๊ฒƒ์„ ์ด์–ด ์„ผ๋‹ค.\n *\n * ์ €๋„์„ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ๊ธฐ๋™ํ•˜๋Š” ์ •์ฑ…(`reset`)์ด๋ผ๋ฉด ์ด ๊ฐ’์ด 0์ด๋ผ ์•„๋ฌด ์˜ํ–ฅ์ด ์—†๋‹ค. ๊ทœ์น™์„\n * ๋ชจ๋“œ๋ณ„๋กœ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š๋Š” ์ด์œ : \"์ €๋„์ด ๋น„์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด ๊ทธ ๋’ค๋ถ€ํ„ฐ\" ํ•˜๋‚˜๋ฉด ์–ด๋А ๋ชจ๋“œ์—์„œ๋„\n * ๊ฒน์น  ์ˆ˜ ์—†๊ณ , ๋ชจ๋“œ๊ฐ€ ๋Š˜์–ด๋„ ์ด ์ž๋ฆฌ๋ฅผ ๋‹ค์‹œ ์†๋ณผ ์ผ์ด ์—†๋‹ค.\n */\n const last = await getRepository(TwinEvent)\n .createQueryBuilder('e')\n .select('MAX(e.revision)', 'max')\n .where('e.domain = :domainId', { domainId })\n .andWhere('e.instanceId = :instanceId', { instanceId })\n .getRawOne()\n\n return this.start(\n instanceId,\n domainId,\n /* ์ปค๋„ ์ข…๋ฅ˜ยทํ˜„์‹ค ์„ ์–ธ์€ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ๋ฐ˜๋“œ์‹œ ์žˆ๋‹ค(๋‘˜ ๋‹ค NOT NULL). ์˜ˆ์ „์—๋Š” `?? 'wms'` ๋กœ\n ๋ฉ”์› ๋Š”๋ฐ, ๊ทธ๊ฑด YMS/MES ํŠธ์œˆ์„ **์กฐ์šฉํžˆ WMS ๋กœ ๋ถ€ํŒ…**์‹œํ‚ค๋Š” ๊ธธ์ด์—ˆ๋‹ค โ€” ์˜ค๋ฅ˜ ์—†์ด ๋‹ค๋ฅธ ๊ณต์žฅ์ด ๋œฌ๋‹ค. */\n reg.kind,\n reg.model as TwinModelDef,\n /* ์ €์žฅ๋œ ๊ฐ’์€ **์—„๊ฒฉํžˆ** ์ฝ๋Š”๋‹ค โ€” ๋ชจ๋ฅด๋Š” ๊ฐ’์„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ๋ฉ”์šฐ๋ฉด ๊ทธ ํŠธ์œˆ์ด ์กฐ์šฉํžˆ ๋‹ค๋ฅด๊ฒŒ ์žฌ๊ธฐ๋™ํ•œ๋‹ค. */\n restartPolicy ?? readRestartPolicy(reg.restartPolicy, `twin \"${instanceId}\"`),\n reg.purpose,\n Number(last?.max ?? 0) || 0\n )\n }\n\n /**\n * ์„ ์–ธ ๊ธฐ๋ฐ˜ ๋ถ€ํŒ…(ยง0 ํ”„๋ ˆ์ž„ โ‘  โ†’ ๋ถ€ํŒ… ๊ฑฐ๋™ ๋งคํ•‘) โ€” ํŠธ์œˆ์ด ์„ ์–ธํ•œ restartPolicy ์— ๋”ฐ๋ผ ์žฌ๊ธฐ๋™ ๋ฐฉ์‹์„ ๊ตฌ๋ถ„ํ•œ๋‹ค.\n * ๋ถ€ํŒ… ๊ฒฝ๋กœ๋ฅผ ํ•œ ๊ณณ์— ๋ชจ์•„ \"๋Ÿฐํƒ€์ž„ โ‰  ํ˜„์‹ค\" ๋ฒ”์ฃผ์˜ค๋ฅ˜๋ฅผ ์ฝ”๋“œ๋กœ ๊ฐ•์ œํ•œ๋‹ค.\n * - 'resync' : ํ˜„์‹ค=์™ธ๋ถ€ ์‹ค๋ฌผ โ†’ startLive(์žฌ๋™๊ธฐ). ์ด๋ฒคํŠธ๋Š” ์–ด๋Œ‘ํ„ฐ ingest ๋กœ ์œ ์ž…, ์ปค๋„ tick ์—†์Œ.\n * - 'resume' : ์ƒ์„ฑ ํƒ€์ž„๋ผ์ธ ์ง€์† โ†’ ์ €๋„ ๋ณด์กด + resume(ํ˜„์‹ค ์ด์–ด๊ฐ).\n * โš  GATE(ยง8 โ‘กโ‘ข): ์ปค๋„ ์ƒํƒœ ์ง๋ ฌํ™”/์žฌ๊ฐœ๊ฐ€ ์•„์ง ์—†์–ด ์ง„์งœ resume ๋ถˆ๊ฐ€ โ†’ ์‹ค ํ•„์š”ยท์‹ค๋ถ€ํ•˜ ์‹œ ๊ตฌํ˜„.\n * ๊ทธ๋•Œ๊นŒ์ง€๋Š” ์ €๋„์„ ๋ณด์กดํ•˜๋˜ revision ์ถฉ๋Œ์„ ํ”ผํ•˜๋ ค fresh ๋กœ ๊ธฐ๋™ํ•˜๊ณ , ์„ ์–ธ๊ณผ ๊ตฌํ˜„์˜ ๊ฐ„๊ทน์„ ํฌ๊ฒŒ ๊ฒฝ๊ณ ํ•œ๋‹ค.\n * - 'reset' : seed ์žฌํ˜„ โ†’ resetJournal + fresh ๊ธฐ๋™(๋ฐฑ์ง€ ์‹œ์ž‘์ด ๋ฒ„๊ทธ๊ฐ€ ์•„๋‹ˆ๋ผ ์„ ์–ธ๋œ ๊ฑฐ๋™).\n * ๋ฐ˜ํ™˜: ๊ธฐ๋™๋œ InstanceRuntime.\n */\n static async bootDeclared(domainId: string, instanceId: string, mode: RestartPolicy): Promise<InstanceRuntime> {\n if (mode === 'resync') {\n const reg = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!reg?.model) throw new Error(`instance \"${instanceId}\" not provisioned (no model)`)\n return this.startLive(instanceId, domainId, reg.kind, reg.model as TwinModelDef)\n }\n if (mode === 'resume') {\n /*\n * **์ด์–ด์ง€๋Š” ํ˜„์‹ค** โ€” ์ €๋„์„ ์ง€์šฐ์ง€ ์•Š๋Š”๋‹ค.\n *\n * ์˜ˆ์ „์—๋Š” ์—ฌ๊ธฐ์„œ ์ €๋„์„ ์ง€์šฐ๊ณ  fresh ๋กœ ๋„์› ๋‹ค. resume ๊ธฐ๊ณ„์žฅ์น˜๊ฐ€ ์—†๋‹ค๊ณ  ๋ดค๊ธฐ ๋•Œ๋ฌธ์ธ๋ฐ,\n * ์‹ค์ œ๋กœ ์—†๋˜ ๊ฒƒ์€ **๋ฒˆํ˜ธ ์ด์–ด ์„ธ๊ธฐ ํ•˜๋‚˜**์˜€๋‹ค: ์ƒํƒœ ๋ณต์›์€ ์ด๋ฏธ `startFromRegistry` ๊ฐ€\n * ์ €๋„ ์žฌ์ƒ(๋˜๋Š” ์ฒดํฌํฌ์ธํŠธ)์œผ๋กœ ํ•˜๊ณ  ์žˆ์—ˆ๊ณ , ๋ง‰ํžŒ ๊ฒƒ์€ ์ปค๋„์ด ๋ฆฌ๋น„์ „์„ 0๋ถ€ํ„ฐ ๋‹ค์‹œ ์„ธ์–ด\n * ๊ธฐ์กด ํ–‰๊ณผ ๊ฒน์น˜๋Š” ๋ฌธ์ œ์˜€๋‹ค. ๊ทธ ํ•˜๋‚˜๋ฅผ `resumeRevision` ์œผ๋กœ ํ’€์—ˆ์œผ๋ฏ€๋กœ ์ด์ œ ์ด์–ด ๊ฐ„๋‹ค.\n *\n * ์•„์ง ์ด์–ด์ง€์ง€ ์•Š๋Š” ๊ฒƒ(์ •์งํ•˜๊ฒŒ): ์‹œ๋‚˜๋ฆฌ์˜ค ์ƒ์„ฑ๊ธฐ์˜ ๋‚œ์ˆ˜ ํ๋ฆ„์€ ์žฌ๊ธฐ๋™์— ์ด์–ด์ง€์ง€ ์•Š๋Š”๋‹ค โ€”\n * ๊ฐ™์€ ์”จ์•—์—์„œ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜๋ฏ€๋กœ ์ž๊ทน์˜ ํŒจํ„ด์ด ์žฌ๊ธฐ๋™ ์ง€์ ์—์„œ ํ•œ ๋ฒˆ ๋Š๊ธด๋‹ค. ์Œ“์ธ ์‚ฌ์‹ค๊ณผ\n * ์ƒํƒœ๋Š” ์ด์–ด์ง€๊ณ , ์•ž์œผ๋กœ ์ผ์–ด๋‚  ์ผ์˜ ๋ฌด์ž‘์œ„ ์ˆœ์„œ๋งŒ ์ƒˆ๋กœ ์‹œ์ž‘ํ•œ๋‹ค.\n */\n return this.startFromRegistry(domainId, instanceId, 'resume')\n }\n // `reset`: seed ์žฌํ˜„ โ€” ์ €๋„ ์ดˆ๊ธฐํ™” ํ›„ revision 0 ๋ถ€ํ„ฐ ์žฌ์‹คํ–‰.\n await this.resetJournal(domainId, instanceId)\n return this.startFromRegistry(domainId, instanceId, 'reset')\n }\n\n /**\n * ์ €๋„ ์ดˆ๊ธฐํ™” โ€” ์ธ์Šคํ„ด์Šค ์ด๋ฒคํŠธ ์ €๋„ purge(๋ ˆ์ง€์ŠคํŠธ๋ฆฌยท์ƒํƒœ๋Š” ์œ ์ง€).\n * ๋ฐ๋ชจ fresh-start ์šฉ: ๋งค ๋ถ€ํŒ… seed ๋ถ€ํ„ฐ ์ƒˆ๋กœ ์‹คํ–‰ํ•˜๋Š” ๋ฐ๋ชจ์—์„œ, ๋ณต๊ตฌ๋ณธ ํ๊ธฐ ํ›„ revision 0 ๋ถ€ํ„ฐ ์žฌ์‹คํ–‰ํ•˜๋ฉด\n * ์˜› ๋Ÿฐ๊ณผ revision ์ด ๊ฒน์ณ ์ €๋„์ด ์˜ค์—ผ๋œ๋‹ค โ†’ start ์ „์— ํ˜ธ์ถœํ•ด ํ˜„์žฌ ๋Ÿฐ๋งŒ ๋‚จ๊ธด๋‹ค.\n */\n static async resetJournal(domainId: string, instanceId: string): Promise<void> {\n await getRepository(TwinEvent).delete({ domain: { id: domainId } as any, instanceId })\n delete this.recovered[runtimeKey(domainId, instanceId)]\n }\n\n /** ์‚ญ์ œ โ€” ์ •์ง€ + ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์‚ญ์ œ + ์ €๋„ purge(domain ์Šค์ฝ”ํ”„). */\n static async remove(domainId: string, instanceId: string): Promise<void> {\n await this.stop(domainId, instanceId)\n this.forgetInstance(domainId, instanceId)\n await getRepository(TwinEvent).delete({ domain: { id: domainId } as any, instanceId })\n await getRepository(TwinInstance).delete({ domain: { id: domainId } as any, instanceId })\n }\n\n /**\n * ์ด ํŠธ์œˆ์— ๋Œ€ํ•ด **๋ฉ”๋ชจ๋ฆฌ์— ๋‚จ์€ ๊ฒƒ์„ ์ „๋ถ€ ์žŠ๋Š”๋‹ค** โ€” ์ง€์›€์˜ ํ•œ ์ž๋ฆฌ.\n *\n * ์บ์‹œ๊ฐ€ ๋ผ์ดํ”„์‚ฌ์ดํด๊ณผ ์–ด๊ธ‹๋‚˜ ์žˆ์—ˆ๋‹ค: ์ €๋„ยท๋“ฑ๋ก๋ถ€๋Š” ์ง€์šฐ๋ฉด์„œ ์ธ์Šคํ„ด์Šค๋ณ„ ์บ์‹œ๋Š” ๋‚จ๊ฒจ, ์‚ญ์ œ๋œ ํŠธ์œˆ์˜\n * ํ•ญ๋ชฉ์ด **์„œ๋ฒ„ ์žฌ๊ธฐ๋™๊นŒ์ง€ ์‚ด์•„ ์žˆ์—ˆ๋‹ค.** ํ•ญ๋ชฉ ํ•˜๋‚˜๊ฐ€ ํ•˜๋ฃจ์น˜ KPI ๊ทธ๋ฃน์„ ๋ฌผ๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์žŠ์ง€ ์•Š์œผ๋ฉด\n * ์ง€์šด ํŠธ์œˆ์ด ๊ณ„์† ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ฐจ์ง€ํ•œ๋‹ค. TTL ์€ ๊ฐ’์ด ๋‚ก๋Š” ๊ฒƒ์„ ๋ง‰์„ ๋ฟ **์—†์–ด์ง„ ์ฃผ์ธ์„ ์ง€์šฐ์ง€ ์•Š๋Š”๋‹ค.**\n *\n * ์žŠ์„ ๊ฒƒ์„ ์—ฌ๊ธฐ ๋ชจ์•„ ๋‘๋Š” ์ด์œ : ์บ์‹œ๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“œ๋Š” ์‚ฌ๋žŒ์ด ์ง€์šฐ๋Š” ์ž๋ฆฌ๋ฅผ ์ฐพ์•„ ํ—ค๋งค์ง€ ์•Š๊ฒŒ ํ•œ๋‹ค.\n * ์ƒˆ ์ธ์Šคํ„ด์Šค๋ณ„ ์บ์‹œ๋ฅผ ๋งŒ๋“ค๋ฉด **์ด ํ•จ์ˆ˜์— ํ•œ ์ค„์„ ๋”ํ•œ๋‹ค** โ€” ๊ทธ๋Ÿฌ์ง€ ์•Š์œผ๋ฉด ๊ฐ™์€ ๋ˆ„์ˆ˜๊ฐ€ ๋‹ค์‹œ ์ƒ๊ธด๋‹ค.\n */\n private static forgetInstance(domainId: string, instanceId: string): void {\n const key = runtimeKey(domainId, instanceId)\n delete this.recovered[key]\n this.measuredCache.delete(key)\n delete this.structureRevCache[key]\n }\n\n /** ๊ด€๋ฆฌ ๋ชฉ๋ก โ€” domain ์˜ ๋“ฑ๋ก ์ธ์Šคํ„ด์Šค ์ „์ฒด(๋ผ์ด๋ธŒ ์—ฌ๋ถ€ยท์ตœ์‹  ์ €๋„ revisionยท๋…ธ๋“œ/๋ฌด๋ฒ„ ์ˆ˜ ํฌํ•จ). */\n static async list(domainId: string): Promise<any[]> {\n const rows = await getRepository(TwinInstance).find({ where: { domain: { id: domainId } } })\n /*\n * **ํ˜„์žฅ ์ด๋ฆ„์„ ํ•จ๊ป˜ ๋‚ธ๋‹ค** โ€” ๋ชฉ๋ก์ด `spaceId` ๋งŒ ๋‚ด๋ณด๋‚ด์„œ ํ™”๋ฉด์ด ์ด๋ฆ„์„ ๋”ฐ๋กœ ์กฐํšŒํ•˜๊ณ  ์žˆ์—ˆ๋‹ค.\n * ๊ทธ ์กฐํšŒ(`twinSpaces`)๋Š” ๊ณต๊ฐ„๋งˆ๋‹ค ์นด์šดํŠธ ์ฟผ๋ฆฌ๋ฅผ ๋„๋Š” N+1 ์ด๋ผ ๋А๋ฆฌ๊ณ , ๊ทธ ์‚ฌ์ด ํ™”๋ฉด์€ **id ๋ฅผ\n * ์ด๋ฆ„์ฒ˜๋Ÿผ** ๋ณด์—ฌ ์ค€๋‹ค(2026-08-13 ๊ด€์ธก: ใ€Œํ˜„์žฅ crew-probe-siteใ€). ํ•œ ๋ฒˆ์— ์ฝ์–ด map ์œผ๋กœ ๋ถ™์ด๋ฉด\n * ์™•๋ณต๋„ ์ค„๊ณ  ๊ทธ ๊นœ๋นก์ž„๋„ ์‚ฌ๋ผ์ง„๋‹ค. ์ด๋ฆ„์ด ์—†์œผ๋ฉด **๋น„์šด๋‹ค** โ€” id ๋ฅผ ์ด๋ฆ„์œผ๋กœ ๋ฒ ๋ผ์ง€ ์•Š๋Š”๋‹ค.\n */\n const spaceNameOf = new Map(\n (await getRepository(TwinSpace).find({ where: { domain: { id: domainId } } })).map(s => [s.spaceId, s.name])\n )\n /*\n * **์ตœ์‹  ๋ฆฌ๋น„์ „์€ ํ•œ ๋ฒˆ์— ๋ฌป๋Š”๋‹ค.**\n *\n * ํŠธ์œˆ๋งˆ๋‹ค `findOne(order revision DESC)` ์„ ๋Œ๊ณ  ์žˆ์—ˆ๋‹ค โ€” 13๊ฐœ๋ฉด ์งˆ์˜ 13๋ฒˆ์ด๊ณ , ํŠธ์œˆ์ด ๋Š˜๋ฉด\n * ๊ทธ๋Œ€๋กœ ์ž๋ž€๋‹ค. ์ด ๋ชฉ๋ก์€ ํŠธ์œˆ ๊ด€๋ฆฌยทํ˜„์žฅ ๊ตฌ์„ฑยท์—”ํ‹ฐํ‹ฐ ํŒจ๋„์ด ๋ชจ๋‘ ์ฝ๋Š” ์ž๋ฆฌ๋‹ค.\n * ํ•œ ๋ฒˆ์˜ ๊ทธ๋ฃน ์งˆ์˜๋กœ ๋ฐ”๊พผ๋‹ค(๊ฐ™์€ ๋ชจ์–‘์˜ ์„ ๋ก€๊ฐ€ ์ด ํŒŒ์ผ์— ์ด๋ฏธ ์žˆ๋‹ค: structureRev ์ง‘๊ณ„).\n */\n const tipOfInstance = new Map<string, number>()\n try {\n const tips = await getRepository(TwinEvent)\n .createQueryBuilder('e')\n .select('e.instanceId', 'instanceId')\n .addSelect('MAX(e.revision)', 'revision')\n .where('e.domain = :domainId', { domainId })\n .groupBy('e.instanceId')\n .getRawMany()\n for (const t of tips) if (t?.instanceId != null) tipOfInstance.set(String(t.instanceId), Number(t.revision) || 0)\n } catch (err: any) {\n /* ์ง‘๊ณ„๊ฐ€ ์‹คํŒจํ•˜๋ฉด **0 ์œผ๋กœ ๋ฉ”์šฐ์ง€ ์•Š๋Š”๋‹ค** โ€” ๋ฆฌ๋น„์ „ 0 ์€ \"์•„์ง ์•„๋ฌด ์ผ๋„ ์—†์—ˆ๋‹ค\" ๋Š” ์‚ฌ์‹ค ์ฃผ์žฅ์ด๋‹ค.\n ๋น„์›Œ ๋‘๋ฉด ์•„๋ž˜์—์„œ `?? 0` ์ด ์•„๋‹ˆ๋ผ undefined ๋กœ ๋‚จ๊ณ , ํ™”๋ฉด์€ ๊ทธ๊ฒƒ์„ \"๋ชจ๋ฆ„\" ์œผ๋กœ ๊ทธ๋ฆฐ๋‹ค. */\n console.error('[twin-engine] latest revision aggregate failed', err?.message ?? err)\n }\n\n const out: any[] = []\n for (const r of rows) {\n const model = (r.model as TwinModelDef) ?? { locations: [], equipment: [] }\n out.push({\n instanceId: r.instanceId,\n /*\n * **์ด๋ฆ„์„ ํ•จ๊ป˜ ๋‚ธ๋‹ค.** ์—…๋ฌดํ‚ค(`instanceId`)๋งŒ ๋‚ด๋ณด๋‚ด๊ณ  ์žˆ์–ด์„œ ๋ชฉ๋ก์ด `crew-two` ๋งŒ ๋ณด์˜€๋‹ค โ€”\n * ์—…๋ฌดํ‚ค๋ฅผ ๋‚˜๋ˆ  ๋‘” ์„ค๊ณ„์—์„œ๋Š” ์ด๋ฆ„์„ ๊ฐ™์ด ์‹ค์–ด์•ผ ๊ทธ ๋‚˜๋ˆ”์ด ๊ฐ’์„ ํ•œ๋‹ค.\n * ์—†์œผ๋ฉด `undefined` ๋‹ค(id ๋ฅผ ๋ฒ ๋ผ์ง€ ์•Š๋Š”๋‹ค โ€” ํ™”๋ฉด์ด ์ด๋ฆ„ ์—†์Œ์„ ์•Œ์•„๋ณผ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค).\n */\n name: r.name ?? undefined,\n description: r.description ?? undefined,\n kind: r.kind,\n status: r.status,\n spaceId: r.spaceId, // co-location: ๊ฐ™์€ spaceId ์ธ์Šคํ„ด์Šค๋“ค์ด ํ•œ ํ˜„์žฅ ๊ณต์œ  โ€” ํ˜„์žฅ๋ทฐ ์ง‘์•ฝ ํ‚ค(G7)\n /* ์‚ฌ๋žŒ์ด ์ฝ๋Š” ํ˜„์žฅ ์ด๋ฆ„ โ€” ์—†์œผ๋ฉด `undefined`(ํ™”๋ฉด์ด \"์ด๋ฆ„ ์—†์Œ\" ์„ ์•Œ์•„๋ณผ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค). */\n spaceName: (r.spaceId ? spaceNameOf.get(r.spaceId) : undefined) || undefined,\n restartPolicy: r.restartPolicy, // ์žฌ๊ธฐ๋™ ์ •์ฑ…(ADR-0029 ยง2) โ€” resync/resume/reset. ์„ ์–ธ์ด๋ฏ€๋กœ ๋น„์–ด ์žˆ์„ ์ˆ˜ ์—†๋‹ค.\n purpose: r.purpose, // ์šด์˜ vs ๋ฒค์น˜ ์‚ฌ๋ณธ(1๊ธ‰ ๊ตฌ๋ณ„ โ€” ์ด๋ฆ„ ์ ‘๋‘์‚ฌ ์•„๋‹˜). ์ €์žฅ ์‹œ ๊ฐ์ธ๋˜๋ฏ€๋กœ ๋น„์ง€ ์•Š๋Š”๋‹ค.\n copyOf: r.copyOf ?? undefined,\n running: !!this.instances[runtimeKey(domainId, r.instanceId)],\n /*\n * **๊ณ„์ธก์ด ๋“ค์–ด์˜ค๊ณ  ์žˆ๋‚˜** โ€” ใ€Œ๋„๋Š” ์ค‘ใ€๊ณผ ๋‹ค๋ฅธ ์‚ฌ์‹ค์ด๋‹ค.\n *\n * ๋ฏธ๋Ÿฌ ํŠธ์œˆ์€ ํ”ผ๋“œ๊ฐ€ ๋–จ์–ด์ ธ๋„ ์ปค๋„์ด ๋Œ๊ธฐ๋งŒ ํ•˜๋ฉด ใ€Œ๋„๋Š” ์ค‘ใ€์ด์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์•„๋ฌด๊ฒƒ๋„ ๋ฐ›์ง€ ์•Š๋Š”\n * ํŠธ์œˆ๊ณผ ํ๋ฅด๋Š” ํŠธ์œˆ์ด ํ™”๋ฉด์—์„œ ๋˜‘๊ฐ™์ด ๋ณด์˜€๋‹ค(์žฌ๊ธฐ๋™ ๋’ค ์‹ค์ œ๋กœ ๊ทธ๋žฌ๋‹ค). ์‹œ๋ฎฌยท์ •์ง€ ํŠธ์œˆ์—๋Š”\n * ใ€Œํ•ด๋‹น ์—†์Œใ€์ด๋‹ค โ€” ์—†์–ด์•ผ ํ•˜๋Š” ๊ฒƒ์„ ๋Š๊ฒผ๋‹ค๊ณ  ๋ถ€๋ฅด์ง€ ์•Š๋Š”๋‹ค.\n */\n /* ์Šค์Šค๋กœ ๋ฉˆ์ถ˜ ์ด์œ  โ€” ์žˆ์œผ๋ฉด ๋‚ธ๋‹ค. ์žฌ๊ธฐ๋™ ๋’ค์—๋Š” ์—†๋‹ค(๊ทธ๋•Œ๋Š” ใ€Œ๋ชจ๋ฅธ๋‹คใ€๊ฐ€ ์‚ฌ์‹ค์ด๋‹ค). */\n stopNote: this.stopNotes.get(runtimeKey(domainId, r.instanceId)) || undefined,\n liveFeed: liveFeedStateOf({\n restartPolicy: r.restartPolicy,\n running: !!this.instances[runtimeKey(domainId, r.instanceId)],\n instanceId: r.instanceId\n }),\n revision: tipOfInstance.get(r.instanceId) ?? 0,\n /*\n * **๋ฆฌ๋”๋ฅผ ๊ฑฐ์ณ ์„ผ๋‹ค** โ€” ๋ณด๋“œ ํ‚ค๋ฅผ ์ง์ ‘ ์ฝ์œผ๋ฉด ์˜› ์„ธ๋Œ€ ๋ชจ๋ธ์ด 0 ์œผ๋กœ ๋ณด์ธ๋‹ค.\n *\n * ์ปค๋„์€ ์ž๋ฆฌยท์„ค๋น„ ๋ฐฐ์—ด์˜ **์˜› ์„ธ๋Œ€ ํ‚ค๊นŒ์ง€ ํก์ˆ˜ํ•ด** ์ฝ์–ด ์ฃผ๋Š”๋ฐ, ์ด ๋ชฉ๋ก์€ ์ƒˆ ์ด๋ฆ„๋งŒ ์ง์ ‘\n * ์„ธ๊ณ  ์žˆ์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์˜› ๋ชจ๋ธ 12๊ฐœ๊ฐ€ ํ™”๋ฉด์— **์ž๋ฆฌ 0 ยท ์„ค๋น„ 0**\n * ์œผ๋กœ ๋–ด๋‹ค โ€” ์˜ค๋ฅ˜ ์—†์ด, ๊ทธ๋ƒฅ ๋นˆ ๊ณต์žฅ์ฒ˜๋Ÿผ. ์„ธ๋Š” ๊ทœ์น™์ด ๋‘ ๋ฒŒ์ด๋ฉด ์ด๋Ÿฐ ์‹์œผ๋กœ ์–ด๊ธ‹๋‚œ๋‹ค.\n */\n locationCount: readBoardLocations(model).length,\n equipmentCount: readBoardEquipment(model).length\n })\n }\n return out\n }\n\n /** ์šด์˜ ๊ณต๊ฐ„ ๋ชฉ๋ก(๋ฒค์น˜ ์†Œ์Šค ์„ ํƒ๊ธฐ) โ€” ์ด๋ฆ„ยท๊ทœ๋ชจ ํฌํ•จ, ๋ฒค์น˜ ์‚ฌ๋ณธ ์ œ์™ธ. */\n static async listSpaces(domainId: string): Promise<{ spaceId: string; name: string; instances: number; locations: number; equipment: number }[]> {\n const nameOf = new Map((await getRepository(TwinSpace).find({ where: { domain: { id: domainId } } })).map(s => [s.spaceId, s.name]))\n const insts = await getRepository(TwinInstance).find({ where: { domain: { id: domainId } } })\n const agg = new Map<string, { spaceId: string; name: string; instances: number; locations: number; equipment: number }>()\n for (const r of insts) {\n /* ๋ฒค์น˜ ์ œ์™ธ๋Š” **์„ ์–ธ์œผ๋กœ๋งŒ** ํŒ๋‹จํ•œ๋‹ค. ์˜ˆ์ „์—๋Š” spaceId ์ด๋ฆ„(`bench-`ยท`loadtest*`)์œผ๋กœ๋„ ์ถ”์ธกํ–ˆ๋Š”๋ฐ,\n ๊ทธ๋Ÿฌ๋ฉด ๊ทธ๋ ‡๊ฒŒ ์ด๋ฆ„ ์ง€์€ ์ง„์งœ ์šด์˜ ๊ณต๊ฐ„์ด ๋ชฉ๋ก์—์„œ ์กฐ์šฉํžˆ ์‚ฌ๋ผ์ง„๋‹ค. purpose ๊ฐ€ ์ •๋ณธ์ด๋‹ค. */\n if (!r.spaceId || r.purpose === 'bench') continue\n const model: any = r.model ?? {}\n const a = agg.get(r.spaceId) ?? { spaceId: r.spaceId, name: nameOf.get(r.spaceId) ?? r.spaceId, instances: 0, locations: 0, equipment: 0 }\n a.instances++\n /* ๋ชฉ๋ก๊ณผ **๊ฐ™์€ ๊ทœ์น™**์œผ๋กœ ์„ผ๋‹ค โ€” ์—ฌ๊ธฐ๋งŒ ์ง์ ‘ ์„ธ๋ฉด ๊ณต๊ฐ„ ์š”์•ฝ๊ณผ ์ธ์Šคํ„ด์Šค ๋ชฉ๋ก์ด ๋‹ค๋ฅธ ์ˆ˜๋ฅผ ๋งํ•œ๋‹ค. */\n a.locations += readBoardLocations(model).length\n a.equipment += readBoardEquipment(model).length\n agg.set(r.spaceId, a)\n }\n return [...agg.values()]\n }\n\n /** ์ธ์Šคํ„ด์Šค ๋ชฉ์  ํ‘œ์‹(์šด์˜/๋ฒค์น˜) ์„ค์ • โ€” ๋ฒค์น˜ ์‚ฌ๋ณธ์„ 1๊ธ‰ ์†์„ฑ์œผ๋กœ ๊ตฌ๋ณ„(์ด๋ฆ„ ์ ‘๋‘์‚ฌ ์•„๋‹˜). */\n static async setPurpose(domainId: string, instanceId: string, purpose: 'operational' | 'bench', copyOf?: string): Promise<void> {\n await getRepository(TwinInstance).update({ domain: { id: domainId } as any, instanceId }, { purpose, copyOf: copyOf ?? null } as any)\n }\n\n /**\n * ๊ณต๊ฐ„ ๊ตฌ์กฐ ํŒ๋… โ€” ์™„์ „๋ณต์ œ(๋ฒค์น˜ ์‚ฌ๋ณธ)์˜ ์†Œ์Šค. ์ €์žฅ๋ฌผ์ด model(์œ„์ƒ)ยทTwinSpace.content(์น˜์ˆ˜ยทgeoยทํ‘œํ˜„)ยทTwinArea(์˜์—ญ)๋กœ\n * ๋ถ„์‚ฐ๋ผ ์žˆ์œผ๋ฏ€๋กœ ์…‹์„ ๋ชจ์•„ ๋Œ๋ ค์ค€๋‹ค. ํ˜ธ์ถœ์ธก์ด ReferenceMaster ๋กœ ์žฌ๊ตฌ์„ฑ โ†’ ์žฌ์‹๋ณ„ โ†’ ingestMaster.\n */\n static async spaceStructure(domainId: string, spaceId: string): Promise<{\n name?: string\n /** ์„ค๊ณ„ ์ขŒํ‘œ๊ณ„ ๋ฒ”์œ„(๋ฏธํ„ฐ)์™€ ์ง€์˜ค๋ ˆํผ๋Ÿฐ์Šค โ€” ์‚ฌ๋ณธ์ด ์›๋ณธ๊ณผ ๊ฐ™์€ ์ž๋ฆฌ์— ์„œ๋ ค๋ฉด ํ•จ๊ป˜ ๊ฐ€์•ผ ํ•œ๋‹ค. */\n frame: { extentX?: number; extentY?: number; geo?: any; primaryRepresentationId?: string }\n areas: any[]\n instances: { instanceId: string; kind?: string; model: any }[]\n } | null> {\n const sp = await getRepository(TwinSpace).findOne({ where: { domain: { id: domainId }, spaceId } })\n const areas = sp\n ? (await getRepository(TwinArea).find({ where: { domain: { id: domainId } as any, space: { id: sp.id } as any } })).map(a => ({ id: a.areaId, type: a.type, name: a.name, parentId: a.parentId, layout: a.layout }))\n : []\n const insts = await getRepository(TwinInstance).find({ where: { domain: { id: domainId }, spaceId } })\n if (!insts.length) return null\n return {\n name: sp?.name,\n frame: { extentX: sp?.extentX, extentY: sp?.extentY, geo: sp?.geo, primaryRepresentationId: sp?.primaryRepresentationId },\n areas,\n instances: insts.map(i => ({ instanceId: i.instanceId, kind: i.kind, model: i.model }))\n }\n }\n\n /** ๊ณต๊ฐ„(+ํ‘œํ˜„ยท์˜์—ญ) ์‚ญ์ œ โ€” ๋ฒค์น˜ ์ •๋ฆฌ ๋“ฑ. ํ˜ธ์ถœ์ธก์ด ๋ฐ”์ธ๋”ฉ ์ธ์Šคํ„ด์Šค๋ฅผ ๋จผ์ € ์ œ๊ฑฐํ•˜๋Š” ์ „์ œ(๊ฐ€๋“œ ์—†์Œ). deleteTwinSpace ๋ฆฌ์กธ๋ฒ„์™€ ๋™ํ˜•. */\n static async deleteSpace(domainId: string, spaceId: string): Promise<void> {\n const space = await getRepository(TwinSpace).findOne({ where: { domain: { id: domainId }, spaceId } })\n if (space) {\n const reps = await getRepository(TwinSpaceRepresentation).find({ where: { domain: { id: domainId }, space: { id: space.id } } })\n for (const rep of reps) await getRepository(TwinSpaceArea).delete({ domain: { id: domainId } as any, representation: { id: rep.id } as any })\n await getRepository(TwinSpaceRepresentation).delete({ domain: { id: domainId } as any, space: { id: space.id } as any })\n await getRepository(TwinArea).delete({ domain: { id: domainId } as any, space: { id: space.id } as any })\n }\n await getRepository(TwinSpace).delete({ domain: { id: domainId } as any, spaceId })\n }\n\n /**\n * Face2 ๋งˆ์Šคํ„ฐ ์ธ์ œ์ŠคํŠธ(ADR-0018) โ€” ๋ ˆํผ๋Ÿฐ์Šค ์‹œ์Šคํ…œ(์‹ค ๋˜๋Š” ๊ฐ€์ƒ)์˜ ๋งˆ์Šคํ„ฐ๋ฅผ ์ฝ์–ด ํŠธ์œˆ์„ ์ƒ์„ฑ.\n * ์—”ํ‹ฐํ‹ฐ๋ฅผ ์†๋ฐฐ์„ /๋ฐœ๋ช…ํ•˜์ง€ ์•Š๊ณ  ๋งˆ์Šคํ„ฐ์—์„œ ๋ฐ˜์˜: ๊ณต๊ฐ„(Space) upsert + ์ธ์Šคํ„ด์Šค provision(๋ฏธ๊ธฐ๋™).\n * ๋…ธ๋“œํƒ€์ž…์€ ์ปค๋„ ์นดํƒˆ๋กœ๊ทธ๋กœ ๊ฒ€์ฆ(warning). start ๋Š” ํ˜ธ์ถœ์ธก(bootstrap/mutation)์ด ๊ฒฐ์ •.\n *\n * `into.spaceId` โ€” **์ด ํ˜„์žฅ์— ๋”ํ•œ๋‹ค.** ํ•œ ํ˜„์‹ค์„ ์—ฌ๋Ÿฌ ๋ Œ์ฆˆ(WMSยทMESยทYMS)๊ฐ€ ๋น„์ถ”๋ฏ€๋กœ ์ƒˆ ํŠธ์œˆ์ด\n * ๊ธฐ์กด ๊ณต๊ฐ„์œผ๋กœ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋‹ค. ์•„๋ž˜ ๋ณ‘ํ•ฉ์€ ์›๋ž˜ ๊ทธ ๊ฒฝ์šฐ๋ฅผ ์œ„ํ•ด ์žˆ์—ˆ๋Š”๋ฐ(N:1) ๋งŒ๋“œ๋Š” ํ๋ฆ„์—์„œ\n * ๊ณต๊ฐ„์„ ๊ณ ๋ฅผ ๋ฐฉ๋ฒ•์ด ์—†์—ˆ๋‹ค โ€” ๋งˆ์Šคํ„ฐ๊ฐ€ ํŒŒ์ƒํ•œ id ๋งŒ ์“ฐ์˜€๋‹ค. ํŒ์ •์€ `resolveIngestSpace`(์ˆœ์ˆ˜).\n */\n static async ingestMaster(\n domainId: string,\n master: ReferenceMaster,\n /** ๋งŒ๋“ค์–ด์ง€๋Š” ํŠธ์œˆ์˜ ์žฌ๊ธฐ๋™ ์ •์ฑ… โ€” ์›๋ณธ์ด ์ •ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ **๋งŒ๋“œ๋Š” ์ชฝ์˜ ์„ ์–ธ**์ด๋‹ค(ADR-0029 ยง2). */\n restartPolicy: RestartPolicy,\n into?: { spaceId?: string },\n /** ๋ˆ„๊ฐ€ ์ธ์ œ์ŠคํŠธํ–ˆ๋‚˜ โ€” ์‚ฌ๋žŒ์ด ์—†๋Š” ๊ฒฝ๋กœ(๋ถ€ํŒ…)๋Š” ์ฃผ์ง€ ์•Š๋Š”๋‹ค(๊ฐ์‚ฌ ๊ธฐ๋ก์„ ์ง€์–ด๋‚ด์ง€ ์•Š๋Š”๋‹ค). */\n actor?: { id: string }\n ): Promise<{ instanceId: string; spaceId: string; warnings: IngestWarning[] }> {\n /*\n * **๊ฑฐ์ ˆํ•  ๊ฒƒ์ด๋ฉด ์•„๋ฌด๊ฒƒ๋„ ์“ฐ๊ธฐ ์ „์— ๊ฑฐ์ ˆํ•œ๋‹ค.**\n *\n * ๊ฐ€๋™ ์ค‘ ์žฌํ”„๋กœ๋น„์ €๋‹์€ `provision` ์ด ๋ง‰๋Š”๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ํ˜ธ์ถœ์€ ์ด ํ•จ์ˆ˜์˜ **๋งจ ๋**์ด๋ผ,\n * ๊ทธ๋•Œ๊นŒ์ง€ ๊ณต๊ฐ„ยทํ‘œํ˜„ยท๊ตฌ์—ญ(TwinArea)์€ ์ด๋ฏธ ์ €์žฅ๋œ ๋’ค์˜€๋‹ค. ์‚ฌ์šฉ์ž์—๊ฒŒ๋Š” \"์ธ์ œ์ŠคํŠธ ์‹คํŒจ\" ๋กœ\n * ๋ณด์ด๋Š”๋ฐ ์‹ค์ œ๋กœ๋Š” ์ ˆ๋ฐ˜์ด ์ ์šฉ๋œ ์ƒํƒœ โ€” ์‹คํŒจ๋ผ๊ณ  ๋งํ•˜๋ฉด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ”๊พธ๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ๋‚˜์˜๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ ํŒ์ •์„ ์•ž์œผ๋กœ ์˜ฎ๊ธด๋‹ค. ์•„๋ž˜ `provision` ์˜ ๊ฐ™์€ ํŒ์ •์€ ๊ทธ๋Œ€๋กœ ๋‘”๋‹ค โ€” ์ด๊ฑด ํŽธ์˜๋ฅผ ์œ„ํ•œ\n * ์•ž์„  ๊ฑฐ์ ˆ์ด๊ณ , ์ €๊ธฐ๊ฐ€ ์ง„์งœ ๋ฐฉ๋ฒฝ์ด๋‹ค(๋‹ค๋ฅธ ๊ฒฝ๋กœ๊ฐ€ ์ƒ๊ฒจ๋„ ์ง€์ผœ์ ธ์•ผ ํ•œ๋‹ค).\n *\n * **๋ฏธ๋Ÿฌ๋Š” ์—ฌ๊ธฐ์„œ ๊ฑฐ์ ˆํ•˜์ง€ ์•Š๋Š”๋‹ค.** ๋ฏธ๋Ÿฌ๊ฐ€ ๋น„์ถ”๋Š” ํ˜„์‹ค์€ ์•ˆ ๋ฉˆ์ถ”๋ฏ€๋กœ ๋™์ž‘ ์ค‘์— ์ „ํ™˜ํ•œ๋‹ค\n * (์•„๋ž˜ `adoptStructure`). ๊ฑฐ์ ˆ์€ ์‹œ๋ฎฌ๋ ˆ์ด์…˜์—๋งŒ ๋‚จ๋Š”๋‹ค โ€” ์กฐ๊ฑด์ด ๋ฐ”๋€ ์‹คํ—˜์€ ๋‹ค๋ฅธ ์‹คํ—˜์ด๋‹ค.\n */\n const running = this.instances[runtimeKey(domainId, master.source)]\n if (running && running.mode !== 'live') this.assertNotRunning(domainId, master.source)\n\n const { model, spaceContent, warnings } = masterToTwin(master, DOMAIN_CATALOG)\n /*\n * โ”€โ”€ ํ˜„์žฅ ์„ ์–ธ์„ ๋‹ค์‹œ ์–น๋Š”๋‹ค (2026-08-18) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n *\n * ์—ฌ๊ธฐ๊ฐ€ ใ€Œ์›์ฒœ์—์„œ ๋‹ค์‹œ ๊ทธ๋ฆฌ๋Š”ใ€ ์ž๋ฆฌ๋‹ค. ์š”๊ธˆ ๋‹จ๊ฐ€ยท๊ณ„์•ฝ ์ •๋ณด์ฒ˜๋Ÿผ **ํ˜„์žฅ์ด ์ •ํ•œ ์ˆ˜**๋Š” ์›์ฒœ์ด ๋ชจ๋ฅด๋ฏ€๋กœ\n * ๋‹ค์‹œ ๊ทธ๋ฆฌ๋ฉด ๊ทธ๋Œ€๋กœ ์‚ฌ๋ผ์ง„๋‹ค โ€” ๊ธˆ์•ก์ด ์‚ฌ๋ผ์ง€๊ณ , ์‚ฌ์šฉ์ž๋Š” ์ž๊ธฐ๊ฐ€ ๋„ฃ์€ ๊ฐ’์ด ์–ด๋””๋กœ ๊ฐ”๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค.\n * ๊ทธ๋ž˜์„œ ๊ฒน์œผ๋กœ ๋ณด๊ด€ํ•œ ์„ ์–ธ์„ ๋งค๋ฒˆ ๋‹ค์‹œ ์–น๋Š”๋‹ค(`engine/local-declarations`).\n *\n * ๋Œ€์ƒ์ด ์‚ฌ๋ผ์กŒ์œผ๋ฉด(๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ์—ˆ๋‹ค) ๊ทธ ์‚ฌ์‹ค์„ ๊ฒฝ๊ณ ๋กœ ๋‚ธ๋‹ค โ€” ๊ฐˆ ๊ณณ ์—†๋Š” ์„ ์–ธ์„ ์กฐ์šฉํžˆ ๋ฒ„๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.\n */\n const prior = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId: master.source } })\n /*\n * ๊ฒน์ด **๋‘˜**์ด๋‹ค โ€” ํ˜„์žฅ(๊ณต๊ฐ„)์˜ ๊ฒƒ๊ณผ ์ด ํŠธ์œˆ์˜ ๊ฒƒ. ์ˆœ์„œ๊ฐ€ ๊ทœ์œจ์ด๋‹ค: ํ˜„์žฅ ๋จผ์ €, ํŠธ์œˆ์ด ๋‚˜์ค‘.\n * ์š”๊ธˆ์ฒ˜๋Ÿผ ํ˜„์žฅ์ด ์ •ํ•œ ์ˆ˜๋Š” ๊ทธ ํ˜„์žฅ์˜ ํŠธ์œˆ ์ „๋ถ€๊ฐ€ ๊ฐ™์ด ์ฝ์–ด์•ผ ํ•˜๊ณ , ํ•œ ํŠธ์œˆ๋งŒ ๋‹ค๋ฅด๊ฒŒ ๋‘๋Š” ์‹คํ—˜์€\n * ์ข์€ ๊ฒน์ด ์ด๊ฒจ์•ผ ํ•œ๋‹ค(๋„“์€ ๊ฐ’์„ ๊ณ ์น˜๋ฉด ๋‚˜๋จธ์ง€ ํŠธ์œˆ์ด ํ•จ๊ป˜ ํ”๋“ค๋ฆฐ๋‹ค).\n */\n const priorSpaceId = prior?.spaceId ?? (model as any)?.spaceId\n const spaceRow = priorSpaceId\n ? await getRepository(TwinSpace).findOne({ where: { domain: { id: domainId }, spaceId: priorSpaceId } })\n : null\n if (prior?.localDeclarations || spaceRow?.localDeclarations) {\n const layered = applyDeclarationLayers(model as any, spaceRow?.localDeclarations as any, prior?.localDeclarations as any)\n Object.assign(model as any, layered.model)\n /*\n * ๊ฒน์„ **๋‹ค์‹œ ์ €์žฅํ•œ๋‹ค** โ€” ์—ฌ๊ธฐ์„œ ์–น์€ ๊ฒƒ์€ ์›์ฒœ์—์„œ ์ƒˆ๋กœ ๊ทธ๋ฆฐ ๋ชจ๋ธ์ด๋ฏ€๋กœ, ๊ทธ๋•Œ ์šฐ๋ฆฌ๊ฐ€ ๋ฎ์€ ๊ฐ’์ด\n * ๊ณง ์ง€๊ธˆ์˜ ์›์ฒœ ๊ฐ’์ด๋‹ค(`replaced`). ์ €์žฅํ•˜์ง€ ์•Š์œผ๋ฉด ๊ทธ ๊ธฐ์–ต์ด ๋‚ก์•„, ์ฒ ํšŒ๊ฐ€ ์˜› ์›์ฒœ ๊ฐ’์œผ๋กœ\n * ๋˜๋Œ๋ฆฐ๋‹ค โ€” ์›์ฒœ์ด ๊ทธ๋™์•ˆ ๊ฐ’์„ ๊ณ ์ณค์–ด๋„ ์•Œ ์ˆ˜ ์—†๋‹ค.\n */\n if (prior) {\n prior.localDeclarations = layered.instanceLayerApplied as any\n await getRepository(TwinInstance).save(prior)\n }\n if (spaceRow) {\n spaceRow.localDeclarations = layered.spaceLayerApplied as any\n await getRepository(TwinSpace).save(spaceRow)\n }\n /*\n * ๊ฐˆ ๊ณณ ์—†๋Š” ์„ ์–ธ์€ ๊ฒฝ๊ณ ๋กœ ๋‚ธ๋‹ค โ€” ๋‹ค๋งŒ **ํ˜„์žฅ ๊ฒน์˜ ๊ฒƒ์€ ๋บ€๋‹ค**: ํ•œ ํ˜„์žฅ์—๋Š” ์—ฌ๋Ÿฌ ์ข…๋ฅ˜์˜ ํŠธ์œˆ์ด\n * ์‚ด๊ณ (์ฐฝ๊ณ ยท์•ผ๋“œยท์—๋„ˆ์ง€), ์š”๊ธˆ ์ž๋ฆฌ๊ฐ€ ์—†๋Š” ํŠธ์œˆ์— ์š”๊ธˆ์ด ์–นํžˆ์ง€ ์•Š๋Š” ๊ฒƒ์€ ์ •์ƒ์ด๋‹ค.\n */\n for (const t of layered.missingTargets.filter(x => x.scope === 'instance')) {\n warnings.push(unresolvedReference('localDeclaration.target', `${t.target}:${t.id}`))\n }\n }\n const repo = getRepository(TwinSpace)\n /* ํ•ฉ์น  ๊ณต๊ฐ„์„ ๊ณจ๋ž์œผ๋ฉด **์žˆ๋Š”์ง€ ๋จผ์ € ํ™•์ธํ•œ๋‹ค** โ€” ์—†๋Š” ๊ณณ์— ์กฐ์šฉํžˆ ์ƒˆ ๊ณต๊ฐ„์„ ๋งŒ๋“ค๋ฉด ์‚ฌ์šฉ์ž๋Š”\n ํ•ฉ์ณค๋‹ค๊ณ  ๋ฏฟ๊ณ  ํ™”๋ฉด์€ ๋”ฐ๋กœ ๋…ผ๋‹ค. ํŒ์ • ํ•จ์ˆ˜๊ฐ€ ๊ทธ ๊ฒฝ์šฐ ๊ฑฐ์ ˆํ•œ๋‹ค. */\n const wanted = (into?.spaceId ?? '').trim()\n const wantedExists = wanted\n ? (await repo.count({ where: { domain: { id: domainId }, spaceId: wanted } })) > 0\n : false\n const choice = resolveIngestSpace(model.spaceId, wanted, wantedExists)\n const spaceId: string = choice.spaceId\n model.spaceId = spaceId // ๋ณด๋“œ(์ปค๋„ ์†Œ๋น„)๋„ ๊ฐ™์€ ๊ณต๊ฐ„์„ ๊ฐ€๋ฆฌ์ผœ์•ผ ํ•œ๋‹ค\n const existing = await repo.findOne({ where: { domain: { id: domainId }, spaceId } })\n if (choice.joined) {\n /* ๊ฐ™์€ id ์˜ ๊ตฌ์—ญยท๋žœ๋“œ๋งˆํฌ๋Š” ํ•ฉ์ง‘ํ•ฉ์œผ๋กœ ์ ‘ํžŒ๋‹ค โ€” ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์„ ๊ณ ๋ฅด์ง€ ์•Š๊ณ  ๋ฌด์—‡์ด\n ํ•ฉ์ณ์กŒ๋Š”์ง€ ๋งํ•œ๋‹ค(์ •๋‹นํ•œ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์œผ๋ฏ€๋กœ ๋ง‰์ง€ ์•Š๋Š”๋‹ค). */\n }\n /*\n * ๊ณต์œ  ๊ณต๊ฐ„(์—ฌ๋Ÿฌ ํŠธ์œˆ์ด ํ•œ spaceId, N:1) โ€” **๋จผ์ € ์“ด ๊ฐ’์ด ์ด๊ธด๋‹ค.**\n *\n * ๋งˆ์ง€๋ง‰ ์ธ์ œ์ŠคํŠธ๊ฐ€ ํ†ต์งธ๋กœ ๋ฎ์–ด์จ ํ‘œํ˜„ยท๊ตฌ์—ญ์ด ์œ ์‹ค๋˜๋˜ ๋ฌธ์ œ ๋ณด์ •. ์„ค๊ณ„ ์ขŒํ‘œ๊ณ„ ๋ฒ”์œ„์™€\n * ์ง€์˜ค๋ ˆํผ๋Ÿฐ์Šค๋Š” ๊ณต๊ฐ„์˜ ์„ฑ์งˆ์ด๋ผ ํŠธ์œˆ๋งˆ๋‹ค ๋‹ค๋ฅผ ์ˆ˜ ์—†๋‹ค โ€” ๋‘ ๋ฒˆ์งธ ํŠธ์œˆ์ด ๋“ค์–ด์˜ค๋ฉด์„œ ๋ฐ”๊พธ๋ฉด\n * ๋จผ์ € ๋†“์ธ ๊ตฌ์—ญ๋“ค์ด ํ†ต์งธ๋กœ ์–ด๊ธ‹๋‚œ๋‹ค. ๊ทธ๋ž˜์„œ ์ด๋ฏธ ์žˆ์œผ๋ฉด ๊ทธ๋Œ€๋กœ ๋‘”๋‹ค.\n */\n const cur: any = spaceContent\n const timezone = existing?.timezone || master.space.timezone\n const savedSpace = await repo.save(\n repo.create({\n ...(existing ?? {}),\n domain: { id: domainId } as any,\n spaceId,\n name: existing?.name || master.siteName,\n ...(timezone ? { timezone } : {}),\n extentX: existing?.extentX ?? cur.width,\n extentY: existing?.extentY ?? cur.depth,\n geo: existing?.geo ?? cur.geo,\n /*\n * ๋Œ€ํ‘œ ํ‘œํ˜„ ํฌ์ธํ„ฐ๋Š” **ํ‘œํ˜„์„ ์ €์žฅํ•œ ๋’ค** ์‹ค์ œ ํ–‰ id ๋กœ ์ฑ„์šด๋‹ค(์•„๋ž˜). ์—ฌ๊ธฐ์„œ ๋งˆ์Šคํ„ฐ์˜ ๋…ผ๋ฆฌ\n * id(`r-map` ๋”ฐ์œ„)๋ฅผ ๋„ฃ์œผ๋ฉด ํ‘œํ˜„ ํ–‰์€ ์ƒ์„ฑ uuid ๋ฅผ ๋ฐ›์œผ๋ฏ€๋กœ ํฌ์ธํ„ฐ๊ฐ€ **์ฒ˜์Œ๋ถ€ํ„ฐ ํ—ˆ๊ณต์„\n * ๊ฐ€๋ฆฌํ‚จ๋‹ค** โ€” ์‹ค์ œ๋กœ 13๊ฐœ ํ˜„์žฅ์ด ๊ทธ ์ƒํƒœ์˜€๊ณ  ์ •ํ•ฉ์„ฑ ์ ๊ฒ€์ด ์žก์•˜๋‹ค(2026-08-13). ํ™”๋ฉด์€\n * ํ–‰์˜ `isPrimary` ๋กœ โ˜…๋ฅผ ๊ทธ๋ ค์„œ ์ฆ์ƒ์ด ๋ณด์ด์ง€ ์•Š์•˜๋‹ค(์‚ฌ์‹ค์ด ๋‘ ๋ฒŒ์ด๋ฉด ์ด๋ ‡๊ฒŒ ์กฐ์šฉํ•˜๋‹ค).\n */\n primaryRepresentationId: existing?.primaryRepresentationId ?? null\n })\n )\n /*\n * ํ‘œํ˜„์„ twin_space_representations ํ…Œ์ด๋ธ”์— ์ €์žฅํ•œ๋‹ค โ€” ๋ทฐ(twin-map-page ๋“ฑ)๋Š” content ๊ฐ€ ์•„๋‹ˆ๋ผ ํ…Œ์ด๋ธ” ํ‘œํ˜„์„ ์†Œ์‹ฑํ•˜๋ฏ€๋กœ,\n * ์ €์žฅํ•˜์ง€ ์•Š์œผ๋ฉด ์ธ์ œ์ŠคํŠธ ์‚ฌ์ดํŠธ์— \"๋Œ€ํ‘œ ํ‘œํ˜„\" ์ด ์—†์–ด ์ง€๋„๋กœ ์‹œ์ž‘ํ•˜์ง€ ๋ชปํ•œ๋‹ค. rep.areas ๊ฐ€ ์žˆ์œผ๋ฉด TwinSpaceArea ๋„ ํ•จ๊ป˜ ์ €์žฅ.\n * ์ตœ์ดˆ ์ธ์ œ์ŠคํŠธ๋งŒ(๊ธฐ์กด ํ‘œํ˜„ ์žˆ์œผ๋ฉด ์‚ฌ์šฉ์ž ํŽธ์ง‘ ๋ณด์กด).\n */\n const repRepo = getRepository(TwinSpaceRepresentation)\n const areaRepo = getRepository(TwinSpaceArea)\n if ((await repRepo.count({ where: { space: { id: savedSpace.id } } })) === 0) {\n const reps: any[] = (spaceContent as any).representations ?? []\n for (let i = 0; i < reps.length; i++) {\n const rep = reps[i]\n const config =\n rep.type === 'map' ? { center: rep.center, zoom: rep.zoom }\n : rep.type === 'board' ? { boardId: rep.boardId }\n : rep.type === 'image' ? { imageUrl: rep.imageUrl, width: rep.width, height: rep.height }\n : {}\n const savedRep = await repRepo.save(repRepo.create({ domain: { id: domainId } as any, space: { id: savedSpace.id } as any, type: rep.type, name: rep.name, seq: i, isPrimary: !!rep.primary || rep.id === (spaceContent as any).primaryId, config }))\n for (const area of (rep.areas ?? []) as any[]) {\n await areaRepo.save(areaRepo.create({ domain: { id: domainId } as any, representation: { id: savedRep.id } as any, name: area.name, type: area.type, geometry: area.geometry, drillTo: area.drillTo ?? null, binding: area.binding ?? null, style: area.style ?? null }))\n }\n }\n /*\n * ๋Œ€ํ‘œ๋ฅผ **์ €์žฅ๋œ ํ–‰ id** ๋กœ ๊ฐ€๋ฆฌํ‚จ๋‹ค โ€” ๋งˆ์Šคํ„ฐ์˜ ๋…ผ๋ฆฌ id ๋Š” ์ €์žฅ ํ‚ค๊ฐ€ ์•„๋‹ˆ๋‹ค. ๊ณ ๋ฅธ ์ˆœ์„œ:\n * โ‘  ๋งˆ์Šคํ„ฐ๊ฐ€ primary ๋กœ ํ‘œ์‹œํ•œ ํ‘œํ˜„ โ‘ก ์—†์œผ๋ฉด ์ฒซ ํ‘œํ˜„ โ‘ข ํ‘œํ˜„์ด ์—†์œผ๋ฉด ๋น„์šด๋‹ค(์ง€์–ด๋‚ด์ง€ ์•Š๋Š”๋‹ค).\n */\n const saved = await repRepo.find({ where: { domain: { id: domainId } as any, space: { id: savedSpace.id } as any }, order: { seq: 'ASC' } })\n const primary = saved.find(r => r.isPrimary) ?? saved[0]\n if (primary && savedSpace.primaryRepresentationId !== primary.id) {\n await repo.save(repo.create({ ...savedSpace, primaryRepresentationId: primary.id }))\n /* ํ•˜๋‚˜๋งŒ ๋Œ€ํ‘œ๋‹ค โ€” ํ–‰ ํ”Œ๋ž˜๊ทธ๋„ ๊ทธ ํ•˜๋‚˜๋กœ ๋งž์ถ˜๋‹ค(๋‘˜์ด ์ผœ์ ธ ์žˆ์œผ๋ฉด ํ™”๋ฉด์ด โ˜…๋ฅผ ๋‘ ๋ฒˆ ๊ทธ๋ฆฐ๋‹ค). */\n for (const r of saved) if (!!r.isPrimary !== (r.id === primary.id)) await repRepo.save(repRepo.create({ ...r, isPrimary: r.id === primary.id }))\n }\n }\n /*\n * area ๋‹จ์ผํ™”(space #2, P1) โ€” ๋…ผ๋ฆฌ ๊ตฌ์—ญ์„ TwinArea(์ •๊ทœยทํ‘œํ˜„๋ฌด๊ด€ยท๊ณต์œ )์— dual-write(upsert by areaId).\n * P3: content.areas ์ €์žฅ ํ๊ธฐ โ†’ TwinArea ๊ฐ€ ์œ ์ผ ๊ถŒ์œ„. ์†Œ์Šค = masterToTwin ์‚ฐ์ถœ spaceContent.areas(cur).\n * (์›์ฒœ diff ์ œ๊ฑฐ[master ์—์„œ ๋น ์ง„ area ์‚ญ์ œ]๋Š” ์‚ฌ์šฉ์ž์ €์ž‘ area ๋ณดํ˜ธ ์œ„ํ•ด per-area provenance ํ•„์š” โ†’ ํ›„์†.)\n */\n const twinAreaRepo = getRepository(TwinArea)\n for (const a of ((spaceContent as any).areas ?? []) as any[]) {\n if (!a?.id) continue\n const existingArea = await twinAreaRepo.findOne({ where: { domain: { id: domainId }, space: { id: savedSpace.id }, areaId: a.id } })\n await twinAreaRepo.save(\n twinAreaRepo.create({\n ...(existingArea ?? {}),\n domain: { id: domainId } as any,\n space: { id: savedSpace.id } as any,\n areaId: a.id,\n name: a.name ?? a.id,\n type: a.type,\n parentId: a.parentId ?? null,\n layout: a.x != null || a.w != null ? { x: a.x, y: a.y, w: a.w, h: a.h } : null\n })\n )\n }\n\n if (running) {\n /* ์‹คํ–‰ ์ค‘์ธ ๋ฏธ๋Ÿฌ โ€” ๋ฉˆ์ถ”์ง€ ์•Š๊ณ  ์ „ํ™˜ํ•œ๋‹ค. ๋ฌด์—‡์ด ์‚ฌ๋ผ์กŒ๋Š”์ง€๋Š” **๊ฒฝ๊ณ ๋กœ ๋งํ•œ๋‹ค**\n (๋ฉˆ์ท„๋‹ค ์„ธ์šฐ๋Š” ๋งˆ๋””๊ฐ€ ์—†์œผ๋ฏ€๋กœ, ๋งํ•˜์ง€ ์•Š์œผ๋ฉด ์ž๋ฆฌ ํ•˜๋‚˜๊ฐ€ ์กฐ์šฉํžˆ ์—†์–ด์ง„๋‹ค). */\n const shift = await this.adoptStructure(domainId, master.source, model, undefined, master.origin)\n warnings.push(structureAdopted(shift.rev, shift))\n } else {\n /* ์‚ฌ์ดํŠธ ์ด๋ฆ„์ด ๊ณง ํŠธ์œˆ์˜ ์ด๋ฆ„์ด๋‹ค โ€” ๋งˆ์Šคํ„ฐ๊ฐ€ ์ด๋ฏธ ๋งํ–ˆ์œผ๋ฏ€๋กœ ์ง€์–ด๋‚ด์ง€ ์•Š๊ณ  ๊ทธ๋Œ€๋กœ ์‹ฃ๋Š”๋‹ค. */\n await this.provision(domainId, master.source, master.system, model, restartPolicy, undefined, master.origin, {\n name: master.siteName,\n description: (master as any).description,\n actor\n })\n }\n\n /*\n * ๊ตฌ์กฐ ํˆฌ์˜ โ€” model(์ปค๋„ ์ž…๋ ฅ ๋ฌธ์„œ)๋ฅผ **ํ‘œ์ค€ ์—”ํ‹ฐํ‹ฐ ํ–‰**์œผ๋กœ ํ‘ผ๋‹ค(ADR-0032).\n *\n * ์ธ์ œ์ŠคํŠธ๊ฐ€ ์œ ์ผํ•œ ์“ฐ๊ธฐ ๊ฒฝ๋กœ๋‹ค. ์—ฌ๊ธฐ์„œ ์‹คํŒจํ•ด๋„ ์ธ์ œ์ŠคํŠธ ์ž์ฒด๋Š” ์„ฑ๊ณต์œผ๋กœ ๋‘”๋‹ค โ€”\n * ํ–‰์€ **์›๋ณธ์—์„œ ์–ธ์ œ๋“  ๋‹ค์‹œ ๊ทธ๋ฆด ์ˆ˜ ์žˆ๋Š” ์บ์‹œ**์ด๊ณ , ํŠธ์œˆ ์ž์ฒด๋Š” model ๋กœ ์ด๋ฏธ ๋™์ž‘ํ•œ๋‹ค.\n * ๋‹ค๋งŒ **์กฐ์šฉํžˆ ๋„˜๊ธฐ์ง€ ์•Š๋Š”๋‹ค**: ๋ชป ์ด์€ ์ฐธ์กฐ๋Š” ์ธ์ œ์ŠคํŠธ ๊ฒฝ๊ณ ๋กœ ์˜ฌ๋ผ๊ฐ„๋‹ค.\n */\n try {\n const projected = await projectStructure(domainId, master.source, model, master.source)\n for (const ref of projected.unresolvedHome) warnings.push(unresolvedReference('equipment.homeLocation', ref))\n for (const ref of projected.unresolvedArea) warnings.push(unresolvedReference('location.area', ref))\n /*\n * ๋ฐœ์ „ ํ˜•์ƒ์€ **์‹œ๊ฐ**์„ ์ฝ๋Š”๋‹ค โ€” ์‹œ๊ฐ„๋Œ€๋ฅผ ๋ชจ๋ฅด๋ฉด UTC ๋กœ ์ฝํžˆ๊ณ , ํ˜„์žฅ ์ •์˜ค๊ฐ€ ์•„๋‹Œ ์‹œ๊ฐ์— ํ”ผํฌ๊ฐ€ ์„ ๋‹ค.\n * ์‹œ๊ฐ„๋Œ€๋ฅผ ์ง€์–ด๋‚ด์ง€ ์•Š๊ณ  ๊ทธ ์กฐํ•ฉ์„ ๋งํ•œ๋‹ค(๊ณต๊ฐ„์— ์„ ์–ธํ•˜๋ฉด ์‚ฌ๋ผ์ง„๋‹ค).\n */\n if ((model as any)?.utcOffsetMinutes === undefined) {\n for (const e of ((model as any)?.equipment ?? []) as any[]) {\n const hasProfile = ((e?.properties ?? []) as any[]).some(p => String(p?.id) === EMS_PROPERTY.genDailyProfile && String(p?.value ?? '').trim())\n if (hasProfile) warnings.push(generationWithoutTimeZone(String((model as any)?.spaceId ?? ''), String(e.id)))\n }\n }\n } catch (err: any) {\n console.error(`[twin-engine] structure projection failed for \"${master.source}\":`, err?.message)\n warnings.push(projectionFailed(err?.message ?? 'unknown'))\n }\n\n if (warnings.length) console.warn(`[twin-engine] ingest \"${master.source}\" warnings: ${describeWarnings(warnings)}`)\n return { instanceId: master.source, spaceId, warnings }\n }\n\n /** ๋‹จ๊ฑด ์ƒ์„ธ โ€” ํ”„๋กœ๋น„์ €๋‹ ์—๋””ํ„ฐ๊ฐ€ ํŽธ์ง‘ํ•  model(๊ตฌ์กฐ+layout) ํฌํ•จ. */\n static async detail(domainId: string, instanceId: string): Promise<any | null> {\n const r = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!r) return null\n return {\n instanceId: r.instanceId,\n kind: r.kind,\n status: r.status,\n running: !!this.instances[runtimeKey(domainId, r.instanceId)],\n restartPolicy: r.restartPolicy, // ํ˜„์‹ค ์„ ์–ธ โ€” what-if ์ ์šฉ ๊ฐ€๋“œ์šฉ(mirror=์˜ˆ์ธก ์ „์šฉ, ์ž๊ทน ์ฃผ์ž… ๋ถˆ๊ฐ€)\n model: r.model\n }\n }\n\n /**\n * ๋ผ์ด๋ธŒ ๋ฐ”์ธ๋”ฉ ๋ธŒ๋ฆฌ์ง€(P3, ADR-0018) โ€” ํŠธ์œˆ ์—”ํ‹ฐํ‹ฐ ์ƒํƒœ๋ฅผ `data(tag=์—”ํ‹ฐํ‹ฐid)` ์ฑ„๋„๋กœ publish.\n * ๋ณด๋“œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ tag ๋กœ ๊ตฌ๋…(board-ui provider)ํ•ด `component.data` ๋กœ ๋ผ์ด๋ธŒ ๊ฐฑ์‹ . delta ์‹œ์—๋งŒ(ํฌ์†Œ).\n * tag=์—”ํ‹ฐํ‹ฐ id(๋ฐ๋ชจ=๋‹จ์ผ ์ธ์Šคํ„ด์Šค). ๋ฉ€ํ‹ฐ ์ธ์Šคํ„ด์Šค/๋ณด๋“œ ์žฌ์‚ฌ์šฉ ์‹œ tag ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋Š” ํ›„์†.\n */\n /** ๋ฐฉ์†ก ์‹คํŒจ ๋กœ๊ทธ ์กฐ์ ˆ โ€” ์ฐฝ๋งˆ๋‹ค ํ•œ ์ค„(๋ง‰ํžŒ ๊ตฌ๋…์ž๋Š” ์ดˆ๋‹น ์ˆ˜์‹ญ ๋ฒˆ ์‹คํŒจํ•œ๋‹ค). */\n private static publishDrops = new Map<string, { count: number; lastLogMs: number }>()\n private static readonly PUBLISH_DROP_LOG_MS = 10_000\n\n /**\n * ํ•œ ๋ฒˆ์˜ ๋ฐฉ์†ก โ€” **๊ตฌ๋…์ž ํ•˜๋‚˜๊ฐ€ ํ˜ธ์ŠคํŠธ๋ฅผ ์ฃฝ์ด์ง€ ๋ชปํ•˜๊ฒŒ.**\n *\n * โ”€โ”€ ๋ฌด์—‡์ด ์ฃฝ์˜€๋‚˜ (2026-08-14) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๋ฐ€๋ฆฐ push ๊ฐ€ 1024๋ฅผ ๋„˜์œผ๋ฉด pubsub ์ด ๋˜์ง„๋‹ค(`RepeaterOverflowError`). ๊ทธ ๋ฐฉ์†ก์€ ํƒ€์ด๋จธ ์ฝœ๋ฐฑ\n * ์•ˆ์—์„œ ์ผ์–ด๋‚˜๋ฏ€๋กœ ์˜ˆ์™ธ๊ฐ€ ์žกํžˆ๋Š” ๊ณณ ์—†์ด ์˜ฌ๋ผ๊ฐ€ **ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋๋‚ฌ๋‹ค** โ€” ํŠธ์œˆ 14๊ฐœ๊ฐ€ ๋„๋Š” ํ˜ธ์ŠคํŠธ๊ฐ€\n * ์†Œ๋น„๋ฅผ ๋ฉˆ์ถ˜ ๊ตฌ๋…์ž ํ•˜๋‚˜ ๋•Œ๋ฌธ์— ํ†ต์งธ๋กœ.\n *\n * ๋ชป ๋ณด๋‚ธ ๊ฒƒ์€ **์‚ฌ์‹ค๋กœ ๋‚จ๊ธด๋‹ค**(ํšŸ์ˆ˜๋ฅผ ์„ธ๊ณ  ์ฐฝ๋งˆ๋‹ค ํ•œ ์ค„ ๋‚จ๊ธด๋‹ค). ์‚ผํ‚ค๋ฉด ใ€Œ๋ณด๋ƒˆ๋Š”๋ฐ ํ™”๋ฉด์ด ๋‚ก์•˜๋‹คใ€๊ฐ€\n * ๋˜๊ณ , ๊ทธ๊ฑด ๊ฐ€์žฅ ์ฐพ๊ธฐ ์–ด๋ ค์šด ๋ถ€๋ฅ˜๋‹ค.\n */\n private static publishGuarded(channel: 'data' | 'twin-state', payload: any, what: string): boolean {\n try {\n pubsub.publish(channel as any, payload)\n return true\n } catch (err: any) {\n const d = this.publishDrops.get(what) ?? { count: 0, lastLogMs: 0 }\n d.count++\n const now = Date.now()\n if (now - d.lastLogMs >= this.PUBLISH_DROP_LOG_MS) {\n d.lastLogMs = now\n console.warn(`[twin-engine] broadcast dropped on \"${what}\" (${d.count} so far) โ€” ${err?.message ?? err}`)\n }\n this.publishDrops.set(what, d)\n return false\n }\n }\n\n static publishEntityData(inst: InstanceRuntime): void {\n const domain = inst.domain\n if (!domain) return\n /* ์ƒํƒœ ์ถœ์ฒ˜ ์Šค์™‘ โ€” sim: ์ปค๋„ runtime, live: projector ๋ฏธ๋Ÿฌ(+OEE ๊ณ„์‚ฐ ์ธต ๋ณด๊ฐ•). ๊ณ„์•ฝยทpayload ๋™์ผ, ๋“œ๋ผ์ด๋ฒ„๋งŒ ๋‹ค๋ฆ„. */\n const load = inst.load ?? (inst.load = newLoadMeter())\n\n /* โ‘  ์ƒํƒœ ํˆฌ์˜ โ€” ์ƒํƒœ ํฌ๊ธฐ์— ๋น„๋ก€ํ•œ๋‹ค(๋Œ€๊ทœ๋ชจ์—์„œ ๊ฐ€์žฅ ๋ฌด๊ฑฐ์šด ์ถ•). */\n const tSnap = performance.now()\n const st: any =\n inst.mode === 'live'\n ? inst.oee\n ? withLiveOee(inst.projector?.snapshot?.(), inst.oee) // ๊ด€์ธก ์ปค๋„ + ๊ณ„์‚ฐ(OEE) โ†’ equipment payload ์— oee ํฌํ•จ(sim ๋™ํ˜•)\n : inst.projector?.snapshot?.()\n : inst.runtime?.resync?.()?.state\n recordPhase(load, 'snapshot', performance.now() - tSnap)\n if (!st) return\n /*\n * ๋ณ€ํ™”ํ•œ ์—”ํ‹ฐํ‹ฐ๋งŒ ๋ฐœํ–‰ โ€” ์ด์ „์—” delta ๋งˆ๋‹ค ์ „ ์—”ํ‹ฐํ‹ฐ(๋…ธ๋“œ+๋ฌด๋ฒ„+์˜ค๋”)๋ฅผ ๊ฐ’ ๋ณ€ํ™”์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ์ „๋Ÿ‰ ์žฌ๋ฐœํ–‰ํ•ด\n * ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋งค์ดˆ ๋ฐ˜๋ณต push ํ•˜๊ณ  ์žˆ์—ˆ๋‹ค(์˜ค์šฉ). ์ตœ์‹ -์ƒํƒœ ์ฑ„๋„์ด๋ฏ€๋กœ ๋ฌด๋ณ€ํ™” ์žฌ๋ฐฉ์†ก์€ ๋ฌด์˜๋ฏธํ•˜๋‹ค.\n * ์—”ํ‹ฐํ‹ฐ๋ณ„ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ๋น„๊ตํ•ด ๋ฐ”๋€ ๊ฒƒ๋งŒ push.\n */\n const sigs = inst.entitySigs ?? (inst.entitySigs = new Map())\n const seen = new Set<string>()\n /* payload ๋งคํ•‘์€ ์ˆœ์ˆ˜ ํ•จ์ˆ˜(buildEntityDeltas)๋กœ ๋ถ„๋ฆฌ โ€” ์—ฌ๊ธฐ์„  ์‹œ๊ทธ๋‹ˆ์ฒ˜ dedup + ๋ฐœํ–‰๋งŒ.\n * ๋ณ€ํ™”ํ•œ ์—”ํ‹ฐํ‹ฐ๋งŒ ๋ฐœํ–‰(์ตœ์‹ -์ƒํƒœ ์ฑ„๋„์ด๋ผ ๋ฌด๋ณ€ํ™” ์žฌ๋ฐฉ์†ก ๋ฌด์˜๋ฏธ). */\n /* โ‘ก payload ๋งŒ๋“ค๊ธฐ โ€” ์—”ํ‹ฐํ‹ฐ ์ˆ˜์— ๋น„๋ก€. โ‘ข ์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋น„๊ต + ๋ฐœํ–‰ โ€” ๋ฐ”๋€ ๊ฒƒ ์ˆ˜์— ๋น„๋ก€. */\n const tDelta = performance.now()\n const deltas = buildEntityDeltas(st, inst.id)\n recordPhase(load, 'deltas', performance.now() - tDelta)\n\n const tPub = performance.now()\n for (const { tag, data } of deltas) {\n seen.add(tag)\n const sig = JSON.stringify(data)\n if (sigs.get(tag) === sig) continue // ๋ฌด๋ณ€ํ™” โ†’ ๋ฐœํ–‰ ์ƒ๋žต\n sigs.set(tag, sig)\n /*\n * **๋ชป ๋ณด๋ƒˆ์œผ๋ฉด ๋ณด๋‚ธ ๊ฒƒ์œผ๋กœ ์ ์ง€ ์•Š๋Š”๋‹ค.** ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ๋‚จ๊ฒจ ๋‘๋ฉด ๋‹ค์Œ ์ฃผ๊ธฐ์— ใ€Œ๋ฌด๋ณ€ํ™”ใ€๋กœ ๊ฑด๋„ˆ๋›ฐ๊ณ ,\n * ๊ทธ ํƒœ๊ทธ๋Š” ์˜์›ํžˆ ๋‚ก์€ ๊ฐ’์„ ๋ณด์—ฌ ์ค€๋‹ค(์˜ค๋ฅ˜ ์—†์ด). ๋˜๋Œ๋ ค ๋‘๋ฉด ๋‹ค์Œ ์ฃผ๊ธฐ๊ฐ€ ๋‹ค์‹œ ์‹œ๋„ํ•œ๋‹ค.\n */\n if (!this.publishGuarded('data', { data: { domain, tag, data } }, `data:${inst.id}`)) sigs.delete(tag)\n }\n recordPhase(load, 'publish', performance.now() - tPub)\n /* ์‚ฌ๋ผ์ง„ ์—”ํ‹ฐํ‹ฐ์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜ ์ •๋ฆฌ(๋งต ๋ฌดํ•œ ์„ฑ์žฅ ๋ฐฉ์ง€). */\n if (sigs.size > seen.size) for (const tag of sigs.keys()) if (!seen.has(tag)) sigs.delete(tag)\n }\n\n static async persist(domainId: string, instanceId: string, msg: any): Promise<void> {\n const repo = getRepository(TwinEvent)\n await repo.save(this.journalRow(repo, domainId, instanceId, msg.event, msg.revision, await this.structureRevOf(domainId, instanceId)))\n }\n\n /**\n * ์žฌ๋ถ€ํŒ… ๋ณต๊ตฌ / ์‹œ๊ฐ„์—ฌํ–‰ โ€” DB ์ €๋„์„ replay ํ•ด ์ƒํƒœ ์žฌ๊ตฌ์„ฑ.\n * model ๋Š” ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ(TwinInstance)์—์„œ, ์ด๋ฒคํŠธ๋Š” TwinEvent(revision ASC)์—์„œ.\n * ์ปค์„œ ๋‘ ์ถ•(runtime-state-model ยง4): **์‹œ๊ฐ(untilTime, ์‚ฌ์šฉ์ž ๋ชจ๊ตญ์–ดยท๊ณต๊ฐ„ ๊ณตํ†ต์ถ•)** ์šฐ์„ , ์—†์œผ๋ฉด ๋ฆฌ๋น„์ „(untilRevision, ๋ Œ์ฆˆ ๋‚ด๋ถ€).\n * - untilTime ์ฃผ๋ฉด `eventTime โ‰ค T` ์ธ ์ด๋ฒคํŠธ๋งŒ(๊ทธ ์‹œ์  watermark) โ€” ๊ณต๋™๋ฐฐ์น˜ ์—ฌ๋Ÿฌ ํŠธ์œˆ์„ ํ•˜๋‚˜์˜ ์‹œ๊ฐ T๋กœ ํ†ต์ผ ํ•ด์†Œ.\n * - ๋‘˜ ๋‹ค ์—†์œผ๋ฉด ์ตœ์‹ (๋ผ์ด๋ธŒ ์ธ๋ฉ”๋ชจ๋ฆฌ ์ง„์‹ค).\n * ์ด๋ฒคํŠธ๋Š” ํ•ญ์ƒ revision ASC(์ธ๊ณผ ์ˆœ์„œ)๋กœ ์ ์šฉ โ€” ์‹œ๊ฐ ํ•„ํ„ฐ๋Š” ์ปท์˜คํ”„ ์ง‘ํ•ฉ๋งŒ ์ •ํ•œ๋‹ค.\n */\n static async recover(domainId: string, instanceId: string, untilRevision?: number, untilTime?: string): Promise<any> {\n // ๋ผ์ด๋ธŒ ์ตœ์‹ (์‹œ๊ฐ„์—ฌํ–‰ ์•„๋‹˜) + ์ธ๋ฉ”๋ชจ๋ฆฌ ์ธ์Šคํ„ด์Šค โ†’ ๋ผ์ด๋ธŒ ์ปค๋„ ์Šค๋ƒ…์ƒท์„ ์ง์ ‘ ์‚ฌ์šฉ.\n // replay(StateProjector)๋Š” attentionsยทack ๋“ฑ ๋ผ์ด๋ธŒ ์ „์šฉ ํŒŒ์ƒ ์ƒํƒœ๋ฅผ ๋‹ด์ง€ ๋ชปํ•˜๋ฏ€๋กœ, ์ตœ์‹ ์€ ์ปค๋„ ์ง„์‹ค์„ ์“ด๋‹ค.\n if (untilRevision == null && untilTime == null) {\n const live = this.instances[runtimeKey(domainId, instanceId)]\n if (live?.kernel?.getSnapshot) return live.kernel.getSnapshot()\n // live ๋ชจ๋“œ๋Š” kernel ์ด ์—†๊ณ  projector ๋ฏธ๋Ÿฌ โ†’ ์ธ๋ฉ”๋ชจ๋ฆฌ ์ตœ์‹  ์Šค๋ƒ…์ƒท(projector+OEE+attentions) ์ง์ ‘ ์‚ฌ์šฉ.\n // (์ €๋„์ด ์žˆ์–ด๋„ ์ตœ์‹ ์€ ์ธ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ง„์‹ค โ€” replay ๋Š” ์‹œ๊ฐ„์—ฌํ–‰/๋ณต๊ตฌ ์ „์šฉ.)\n if (live?.mode === 'live' && live.projector) return this.snapshot(domainId, instanceId)\n }\n /*\n * **๋์— ์žˆ๋Š” ์Šค๋ƒ…์ƒท์ด๋ฉด ์ ‘์ง€ ์•Š๋Š”๋‹ค.**\n *\n * ๋ฉˆ์ถ˜ ํŠธ์œˆ์„ ์กฐํšŒํ•  ๋•Œ๋งˆ๋‹ค ์ €๋„์„ ์ „๋Ÿ‰ ์ ‘๊ณ  ์žˆ์—ˆ๋‹ค โ€” ํŠธ์œˆ์„ ํ•˜๋‚˜๋„ ์•ˆ ๋Œ๋ ค๋„ ๋ชจ๋ธ ์กฐํšŒ๊ฐ€\n * 4.6~7.7์ดˆ์˜€๋˜ ์ด์œ ๋‹ค(crew-probe 23,731๊ฑด). ์Šค๋ƒ…์ƒท์€ ๊ฐ™์€ ํด๋“œ์˜ ๊ฒฐ๊ณผ์ด๋ฏ€๋กœ, ๊ทธ ๋’ค๋กœ ์ด๋ฒคํŠธ๋„\n * ๊ตฌ์กฐ ๋ณ€๊ฒฝ๋„ ์—†๋‹ค๋ฉด **๋‹ค์‹œ ์ ‘์–ด ๋ด์•ผ ๊ฐ™์€ ๊ฐ’**์ด๋‹ค.\n *\n * ์“ฐ์ง€ ์•Š๋Š” ์กฐ๊ฑด์„ ์ข๊ฒŒ ์žก๋Š”๋‹ค: ์ง€๊ธˆ์„ ๋ฌผ์—ˆ์„ ๋•Œ๋งŒ(์‹œ๊ฐ„์—ฌํ–‰์€ ๊ทธ ์‹œ์ ๊นŒ์ง€ ์ ‘์–ด์•ผ ํ•œ๋‹ค), ๋ฆฌ๋น„์ „์ด\n * ๋๊ณผ ๊ฐ™์„ ๋•Œ๋งŒ, ๊ตฌ์กฐ ๋ฆฌ๋น„์ „๊นŒ์ง€ ๊ฐ™์„ ๋•Œ๋งŒ. ํ•˜๋‚˜๋ผ๋„ ์–ด๊ธ‹๋‚˜๋ฉด ์ ‘๋Š”๋‹ค โ€” ์บ์‹œ๊ฐ€ ์‚ฌ์‹ค์„ ์ด๊ธฐ์ง€ ์•Š๋Š”๋‹ค.\n */\n const asOfNowRead = untilRevision == null && untilTime == null\n const tip = asOfNowRead ? await this.tipOf(domainId, instanceId).catch(() => null) : null\n /* ํ•œ ๋ฒˆ๋งŒ ์ฝ๋Š”๋‹ค โ€” ๋์— ์žˆ์œผ๋ฉด ๊ทธ๋Œ€๋กœ ์“ฐ๊ณ , ์•„๋‹ˆ๋ฉด ์•„๋ž˜์—์„œ **์ด์–ด ์ ‘๋Š” ์”จ์•—**์œผ๋กœ ์“ด๋‹ค. */\n const cachedForResume = asOfNowRead && tip ? await this.loadSnapshot(domainId, instanceId).catch(() => null) : null\n if (cachedForResume) {\n const state = unwrapState(cachedForResume.state)\n if (state && (cachedForResume.revision ?? 0) === tip!.revision && (cachedForResume.structureRev ?? null) === tip!.structureRev)\n return state\n }\n\n const reg = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!reg?.model) throw new Error(`twin instance \"${instanceId}\" not registered (no model to replay)`)\n\n /*\n * โ”€โ”€ ์žฌ๊ฐœ์ ์—์„œ **์ด์–ด ์ ‘๋Š”๋‹ค** (2026-08-18) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n *\n * ์šฐ๋ฆฌ๋Š” ์ด๋ฏธ ์ ‘์€ ๊ฒฐ๊ณผ๋ฅผ ๋‚จ๊ธฐ๊ณ  ์žˆ๋‹ค(`saveFoldedSnapshot`). ๊ทธ ์ง€์ ์˜ **์žฌ๊ฐœ์ **(๋ฆฌ๋“€์„œ ๋‚ด๋ถ€ ์ƒํƒœ\n * ์ „๋ถ€ + ๊ฐ€๋™ ๋ˆ„์ ๊ธฐ)์ด ํ•จ๊ป˜ ์žˆ์œผ๋ฉด, ๊ทธ ๋’ค์— ์ผ์–ด๋‚œ ๊ฒƒ๋งŒ ์ ‘์–ด๋„ ๊ฐ™์€ ๋‹ต์ด ๋‚˜์˜จ๋‹ค โ€” ๊ทธ ๋™์น˜๋Š”\n * ์ปค๋„ ์‹œํ—˜์ด ์ฆ๋ช…ํ•œ๋‹ค(0๋ถ€ํ„ฐ ์ ‘๊ธฐ == ์žฌ๊ฐœ์  + ๊ผฌ๋ฆฌ).\n *\n * ์“ฐ๋Š” ์กฐ๊ฑด์„ ์ข๊ฒŒ ์žก๋Š”๋‹ค: **์ง€๊ธˆ์„ ๋ฌผ์—ˆ์„ ๋•Œ๋งŒ**(์‹œ๊ฐ„์—ฌํ–‰์€ ๋ชฉํ‘œ ์ด์ „ ์žฌ๊ฐœ์ ์ด ํ•„์š”ํ•œ๋ฐ ์ง€๊ธˆ์€\n * ์ตœ์‹  ํ•˜๋‚˜๋งŒ ๋‚จ๊ธด๋‹ค โ€” ์‚ฌ์Šฌ์€ ๋‹ค์Œ ๋‹จ๊ณ„๋‹ค), ๊ตฌ์กฐ๊ฐ€ ๊ทธ๋Œ€๋กœ์ผ ๋•Œ๋งŒ(๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๊ทธ ๊ฒฝ๊ณ„์—์„œ ๊ฐˆ๋ผ\n * ์ ‘์–ด์•ผ ํ•œ๋‹ค), ์žฌ๊ฐœ์ ์ด ์ €๋„ ๋๋ณด๋‹ค ์•ž์„ค ๋•Œ๋งŒ. ํ•˜๋‚˜๋ผ๋„ ์–ด๊ธ‹๋‚˜๋ฉด 0๋ถ€ํ„ฐ ์ ‘๋Š”๋‹ค โ€” **์บ์‹œ๊ฐ€ ์‚ฌ์‹ค์„\n * ์ด๊ธฐ์ง€ ์•Š๋Š”๋‹ค.**\n */\n /*\n * ์”จ์•—์€ ๋‘˜ ์ค‘ ํ•˜๋‚˜๋‹ค: **์ง€๊ธˆ**์„ ๋ฌผ์œผ๋ฉด ์ตœ์‹  ์žฌ๊ฐœ์ , **๊ณผ๊ฑฐ**๋ฅผ ๋ฌผ์œผ๋ฉด ์‚ฌ์Šฌ์—์„œ ๋ชฉํ‘œ ์ง์ „ ์ง€์ .\n *\n * ๊ณผ๊ฑฐ ์”จ์•—์€ ๊ตฌ์กฐ๊ฐ€ ํ•œ ๋ฒˆ๋„ ๋ฐ”๋€Œ์ง€ ์•Š์€ ํŠธ์œˆ์—์„œ๋งŒ ์“ด๋‹ค โ€” ๊ตฌ์กฐ๊ฐ€ ๊ฐˆ๋ฆฐ ์ €๋„์€ ๋งˆ๋””๋งˆ๋‹ค ๊ฐˆ์•„ ์ ‘์–ด์•ผ\n * ํ•˜๊ณ , ๋งˆ๋””๋ฅผ ๊ฑด๋„ˆ๋›ด ์”จ์•—์€ ๊ทธ ๊ฒฝ๊ณ„์˜ ํŒ์ •์„ ์žƒ๋Š”๋‹ค(๊ทธ๋•Œ๋Š” 0๋ถ€ํ„ฐ ์ ‘๋Š” ๊ฒƒ์ด ์˜ณ๋‹ค).\n */\n const structureCount = asOfNowRead\n ? 0\n : await getRepository(TwinStructure).count({ where: { domain: { id: domainId }, instanceId } }).catch(() => 99)\n const pastSeed =\n !asOfNowRead && structureCount <= 1\n ? await this.chainSeedFor(domainId, instanceId, {\n ...(untilRevision != null ? { revision: untilRevision } : {}),\n ...(untilTime != null && !Number.isNaN(Date.parse(untilTime)) ? { timeMs: Date.parse(untilTime) } : {})\n }).catch(() => null)\n : null\n const resume =\n asOfNowRead && tip && cachedForResume && cachedForResume.fold && (cachedForResume.structureRev ?? null) === tip.structureRev\n ? cachedForResume\n : pastSeed\n\n /*\n * **์ž๋ฅผ ๊ฒƒ์„ ์•Œ๋ฉด์„œ ๋‹ค ์ฝ์–ด ์˜ค์ง€ ์•Š๋Š”๋‹ค** (2026-08-18 ์‹ค์ธก).\n *\n * ์ €๋„์„ ์ „๋Ÿ‰ ์ฝ์–ด ์˜จ ๋’ค JS ์—์„œ ๊ฑธ๋ €๋‹ค. 27๋งŒ ๊ฑด์งœ๋ฆฌ ํŠธ์œˆ(order-check)์—์„œ ํ•œ ์‹œ๊ฐ„ ์ „ ์ƒํƒœ๋ฅผ ๋ฌผ์œผ๋ฉด\n * **7.4์ดˆ**๊ฐ€ ๊ฑธ๋ ธ๊ณ , ๊ทธ ๋Œ€๋ถ€๋ถ„์ด ใ€Œํ•„์š” ์—†๋Š” ํ–‰์„ ์ฝ์–ด ์˜ค๋Š” ์‹œ๊ฐ„ใ€์ด์—ˆ๋‹ค. ์‹œ๊ฐยท๋ฆฌ๋น„์ „ ์ƒํ•œ์€ SQL ์ด\n * ์•„๋Š” ์กฐ๊ฑด์ด๋ฏ€๋กœ ๊ฑฐ๊ธฐ์„œ ์ž๋ฅธ๋‹ค(TypeORM ๊ด€์šฉ๊ตฌ๋งŒ โ€” ์›์‹œ SQL ์€ 5๊ฐœ ๋“œ๋ผ์ด๋ฒ„์—์„œ ๊ฐˆ๋ผ์ง„๋‹ค).\n *\n * ์‹œ๊ฐ ์ƒํ•œ์—๋Š” **๊ฒฝ๊ณ„๋ฅผ ๊ทธ๋Œ€๋กœ** ์“ด๋‹ค(`<=`): ๊ทธ ์‹œ๊ฐ์— ์ผ์–ด๋‚œ ์‚ฌ์‹ค์€ ๊ทธ ์‹œ๊ฐ์˜ ํ™”๋ฉด์— ์žˆ์–ด์•ผ ํ•œ๋‹ค.\n * ์‹œ๊ฐ์ด ์—†๋Š” ๋ ˆ๊ฑฐ์‹œ ํ–‰์€ ๋ณด์ˆ˜์ ์œผ๋กœ ํฌํ•จํ•ด ์™”๋Š”๋ฐ, SQL ๋กœ ์ž๋ฅด๋ฉด ๊ทธ ํ–‰๋“ค์ด ๋น ์ง„๋‹ค โ€” ๊ทธ๋ž˜์„œ ์‹œ๊ฐ\n * ์กฐ๊ฑด์ผ ๋•Œ๋Š” **์‹œ๊ฐ์ด ๋น„์–ด ์žˆ๋Š” ํ–‰๋„ ํ•จ๊ป˜** ๊ฐ€์ ธ์™€ ์˜ˆ์ „๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ๋‚ธ๋‹ค.\n */\n const cutoffMs = untilTime != null ? Date.parse(untilTime) : NaN\n const useTime = untilTime != null && !Number.isNaN(cutoffMs)\n const baseWhere = { domain: { id: domainId }, instanceId }\n /* ์ด์–ด ์ ‘์„ ๋•Œ๋Š” **๊ทธ ๋’ค๋งŒ** ์ฝ๋Š”๋‹ค โ€” ์žฌ๊ฐœ์ ๊นŒ์ง€์˜ ์‚ฌ์‹ค์€ ์ด๋ฏธ ์”จ์•— ์•ˆ์— ์žˆ๋‹ค. */\n const from = resume ? (resume.revision ?? 0) : undefined\n const rows = await getRepository(TwinEvent).find({\n where: useTime\n ? from\n ? /* ์”จ์•— ๋’ค ยท ๋ชฉํ‘œ ์ด๋‚ด โ€” ์‹œ๊ฐ์ด ๋นˆ ์˜› ํ–‰์€ ์”จ์•— ๋’ค์— ์žˆ๋Š” ๊ฒƒ๋งŒ ํฌํ•จํ•œ๋‹ค(๋ณด์ˆ˜์  ํฌํ•จ์„ ์œ ์ง€). */\n [\n { ...baseWhere, revision: MoreThan(from), eventTime: LessThanOrEqual(new Date(cutoffMs)) },\n { ...baseWhere, revision: MoreThan(from), eventTime: IsNull() }\n ]\n : [\n { ...baseWhere, eventTime: LessThanOrEqual(new Date(cutoffMs)) },\n { ...baseWhere, eventTime: IsNull() }\n ]\n : untilRevision != null\n ? from\n ? { ...baseWhere, revision: And(MoreThan(from), LessThanOrEqual(untilRevision)) }\n : { ...baseWhere, revision: LessThanOrEqual(untilRevision) }\n : from\n ? { ...baseWhere, revision: MoreThan(from) }\n : baseWhere,\n order: { revision: 'ASC' }\n })\n const wanted = rows\n\n /*\n * **๊ทธ๋•Œ์˜ ๊ณต์žฅ์œผ๋กœ ์ ‘๋Š”๋‹ค.**\n *\n * ์˜ˆ์ „์—๋Š” ๋ชจ๋“  ์ด๋ฒคํŠธ๋ฅผ ์ง€๊ธˆ ๋“ฑ๋ก๋œ ๋ณด๋“œ ํ•˜๋‚˜๋กœ ์ ‘์—ˆ๋‹ค. ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€ ์  ์—†์œผ๋ฉด ๋งž์ง€๋งŒ, ๋ฐ”๋€\n * ๋’ค์—๋Š” ์˜› ์‚ฌ์‹ค์„ ์ƒˆ ๊ณต์žฅ์— ๋Œ€๊ณ  ์ ‘๊ฒŒ ๋˜์–ด โ€” ๊ทธ๋•Œ ์—†๋˜ ์„ค๋น„์—์„œ ์ผ์ด ์žˆ์—ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค.\n * (๊ทธ๋ž˜์„œ ์˜ˆ์ „ ํ”„๋กœ๋น„์ €๋‹์€ ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์ €๋„์„ ์•„์˜ˆ ์ง€์› ๋‹ค. ์—ญ์‚ฌ๋ฅผ ์žƒ๊ฑฐ๋‚˜ ๊ฑฐ์ง“๋ง์„ ํ•˜๊ฑฐ๋‚˜.)\n *\n * ์ด์ œ ์ด๋ฒคํŠธ๊ฐ€ ์ž๊ธฐ ๊ตฌ์กฐ๋ฅผ ๋‹ฌ๊ณ  ์˜ค๋ฏ€๋กœ, ๋ฆฌ๋น„์ „์ด ๋ฐ”๋€Œ๋Š” ์ง€์ ์—์„œ ๊ตฌ์กฐ๋ฅผ ๊ฐˆ์•„ํƒ€๋ฉฐ ์ด์–ด ์ ‘๋Š”๋‹ค.\n * ๋ฆฌ๋น„์ „์ด ํ•˜๋‚˜๋ฟ์ด๊ฑฐ๋‚˜(๋Œ€๋‹ค์ˆ˜) ์•„์˜ˆ ์—†์œผ๋ฉด(๊ตฌ์กฐ ์ด๋ ฅ ์ด์ „) ์˜ˆ์ „๊ณผ ๋˜‘๊ฐ™์ด ํ•œ ๋ฒˆ์— ์ ‘๋Š”๋‹ค.\n */\n const structures = await getRepository(TwinStructure).find({\n where: { domain: { id: domainId }, instanceId },\n order: { rev: 'ASC' }\n })\n const boardOf = new Map<number, TwinModelDef>(structures.map(x => [x.rev, x.model as TwinModelDef]))\n /* ์ปฌ๋Ÿผ์ด ์ƒ๊ธฐ๊ธฐ ์ „ ํ–‰์€ ๋ฆฌ๋น„์ „์ด ๋น„์–ด ์žˆ๋‹ค โ€” **๊ฐ€์žฅ ์˜ค๋ž˜๋œ ๊ตฌ์กฐ**์— ์†ํ•œ๋‹ค(0 ์œผ๋กœ ์ฑ„์šฐ์ง€ ์•Š๋Š”๋‹ค). */\n const oldest = structures[0]?.rev\n const revOf = (r: { structureRev?: number }): number | undefined => r.structureRev ?? oldest\n\n const segments: { model: TwinModelDef; events: any[] }[] = []\n for (const r of wanted) {\n if (!r.payload) continue\n const rev = revOf(r)\n const model = (rev !== undefined && boardOf.get(rev)) || (reg.model as TwinModelDef)\n const last = segments[segments.length - 1]\n if (last && last.model === model) last.events.push(r.payload)\n else segments.push({ model, events: [r.payload] })\n }\n /*\n * **๊ฐ€์žฅ ์ƒˆ ๊ตฌ์กฐ๊ฐ€ ์ง€๊ธˆ์˜ ๊ณต์žฅ์ด๋‹ค** โ€” ๊ทธ ์•„๋ž˜์—์„œ ์•„์ง ์•„๋ฌด ์ผ๋„ ์—†์—ˆ๋”๋ผ๋„.\n *\n * ์žฌํ”„๋กœ๋น„์ €๋‹ ์งํ›„๊ฐ€ ์ •ํ™•ํžˆ ๊ทธ ์ƒํƒœ๋‹ค: ๋ถ€์Šค๋ฅผ ๋„ท ๋Š˜๋ ธ๋Š”๋ฐ ์ƒˆ ์ด๋ฒคํŠธ๋Š” ์•„์ง ํ•˜๋‚˜๋„ ์—†๋‹ค. ์ด๋•Œ\n * ๋งˆ์ง€๋ง‰ ์ด๋ฒคํŠธ์˜ ๊ตฌ์กฐ๋กœ๋งŒ ์ ‘์œผ๋ฉด ํ™”๋ฉด์€ **์˜› ๊ณต์žฅ**์„ ๋ณด์—ฌ์ค€๋‹ค โ€” ๋ฐฉ๊ธˆ ๋Š˜๋ฆฐ ๊ฒƒ์ด ์•ˆ ๋ณด์ธ๋‹ค.\n * ๊ทธ๋ž˜์„œ ๋งˆ๋””์˜ ๋์— ์ง€๊ธˆ ๊ตฌ์กฐ๋ฅผ ํ•œ ๋ฒˆ ๋” ์–น๋Š”๋‹ค(์ด๋ฒคํŠธ ์—†๋Š” ๋งˆ๋””).\n *\n * **๋‹ค๋งŒ \"์ง€๊ธˆ\" ์„ ๋ฌผ์—ˆ์„ ๋•Œ๋งŒ์ด๋‹ค.** ๊ณผ๊ฑฐ ์‹œ์ ์„ ๋ฌผ์—ˆ๋Š”๋ฐ ์ตœ์‹  ๊ตฌ์กฐ๋ฅผ ์–น์œผ๋ฉด, ๊ทธ ์‹œ์ ์— ์—†๋˜\n * ์„ค๋น„๊ฐ€ ํ™”๋ฉด์— ์„œ๊ณ  โ€” ์ด ์ž‘์—…์ด ๋ง‰์œผ๋ ค๋˜ ๋ฐ”๋กœ ๊ทธ ๊ฑฐ์ง“๋ง์ด ๋œ๋‹ค.\n */\n const asOfNow = untilRevision == null && untilTime == null\n const newest = structures[structures.length - 1]?.model as TwinModelDef | undefined\n if (asOfNow && newest && segments[segments.length - 1]?.model !== newest) segments.push({ model: newest, events: [] })\n\n /*\n * ์ ‘์€ ์ƒํƒœ์— **์ฃผ์˜ ์‹ ํ˜ธ์™€ ์‹œ๊ฐ์„ ์ฑ„์šด๋‹ค.**\n *\n * ๋ผ์ด๋ธŒยท์‹œ๋ฎฌ์€ ์ปค๋„์ด ์‹ ํ˜ธ๋ฅผ ์Šค์Šค๋กœ ๋‚ด์ง€๋งŒ, ์ €๋„์„ ์ ‘๋Š” ์ด ๊ฒฝ๋กœ๋Š” ํ”„๋กœ์ ํ„ฐ ์ƒํƒœ๋งŒ ๋‚ธ๋‹ค โ€” ์‹ ํ˜ธ๋„\n * `nowTime` ๋„ ์—†๋‹ค. ๊ทธ๋ž˜์„œ **๊ณผ๊ฑฐ๋ฅผ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜๋ฉด ์ฃผ์˜ ๋ ˆ์ผ์ด ํ…… ๋น„์—ˆ๊ณ **(์ง€๋„๋Š” `snap.attentions` ๋ฅผ\n * ์ฝ๋Š”๋‹ค), ๊ธฐ๋™๋ผ ์žˆ์ง€ ์•Š์€ ํŠธ์œˆ์„ ๋ณด๋Š” ํ™”๋ฉด๋„ ๊ฐ™์•˜๋‹ค. ์‹ ํ˜ธ๋Š” ์ƒํƒœ์—์„œ ๊ณ„์‚ฐ๋˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ\n * ์—ฌ๊ธฐ์„œ ๊ฐ™์€ ๊ณต์‹(`deriveAttentions`)์œผ๋กœ ์ฑ„์šฐ๋ฉด ๋œ๋‹ค โ€” ๋‘ ๋ฒŒ์„ ๋‘์ง€ ์•Š๋Š”๋‹ค.\n *\n * `nowTime` ์ด ๋จผ์ €๋‹ค: \"๋Šฆ์—ˆ๋‚˜\" ํŒ์ •์ด ๊ทธ ๊ฐ’์„ ๋ณธ๋‹ค. ๋‹ค์‹œ ๊ณ„์‚ฐํ•œ ์‹œ์ ์˜ ์ •์งํ•œ \"์ง€๊ธˆ\" ์€ ๋ฌผ์–ด๋ณธ ์‹œ๊ฐ\n * (`untilTime`)์ด๊ณ , ์—†์œผ๋ฉด ๋งˆ์ง€๋ง‰์œผ๋กœ ์ ์šฉํ•œ ์ด๋ฒคํŠธ์˜ ์‹œ๊ฐ์ด๋‹ค. ๋‘˜ ๋‹ค ์—†์œผ๋ฉด ์ฑ„์šฐ์ง€ ์•Š๋Š”๋‹ค โ€”\n * ๋ฒฝ์‹œ๊ณ„๋ฅผ ๋ผ์›Œ ๋„ฃ์œผ๋ฉด ๊ณผ๊ฑฐ ํ™”๋ฉด์ด \"์ง€๊ธˆ ๊ธฐ์ค€์œผ๋กœ ๋Šฆ์—ˆ๋‹ค\" ๊ณ  ๋งํ•˜๊ฒŒ ๋œ๋‹ค.\n */\n const lastEventTime = rows.length ? (rows[rows.length - 1]?.eventTime?.toISOString() ?? '') : ''\n\n /*\n * **๊ฐ€๋™ ์ด๋ ฅ๋„ ๋˜์‚ด๋ฆฐ๋‹ค** โ€” ๋‹ค์‹œ ๊ณ„์‚ฐํ•œ ํ™”๋ฉด์— ์„ค๋น„ ๊ณ„์ธก์ด ๋น„์–ด ์žˆ๋˜ ๊ฒƒ.\n *\n * OEE ๋Š” ์› ์‹œ์Šคํ…œ์ด ๋ˆ„์ ์„ ๋ณด๋‚ด ์ฃผ์ง€ ์•Š์•„ ํ˜ธ์ŠคํŠธ๊ฐ€ ์ƒํƒœ ์ „์ด๋ฅผ ์ ๋ถ„ํ•ด ๋งŒ๋“ ๋‹ค(๊ทธ๋ž˜์„œ ์ปค๋„์ด ์•„๋‹ˆ๋ผ\n * ์—ฌ๊ธฐ ์žˆ๋‹ค). ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ๋ˆ„์ ๊ธฐ๋Š” **๋ผ์ด๋ธŒ์—์„œ๋งŒ** ๋Œ์•˜๊ณ , ์ €๋„์„ ์ ‘๋Š” ๊ฒฝ๋กœ๋Š” ๊ทธ ๊ณ„์‚ฐ์„ ํ•˜์ง€ ์•Š์•˜๋‹ค โ€”\n * ๊ณผ๊ฑฐ๋ฅผ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜๋ฉด ๋ชจ๋“  ์„ค๋น„๊ฐ€ \"๊ฐ€๋™ ์ด๋ ฅ์ด ์ „ํ˜€ ์—†์Œ\" ์œผ๋กœ ๋ณด์˜€๋‹ค.\n *\n * ์—†๋Š” ๊ฒƒ์€ ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹ˆ๋ผ ๊ณ„์‚ฐ์ด๋‹ค: ์ž…๋ ฅ(`equipment.status` ์ „์ดยท`quality.output`)์€ ์ €๋„์— ๋‹ค\n * ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ **๊ฐ™์€ ๋ˆ„์ ๊ธฐ์— ๊ฐ™์€ ์ด๋ฒคํŠธ๋ฅผ ํƒœ์šด๋‹ค** โ€” ๊ทœ์น™์„ ๋‘ ๋ฒŒ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค.\n *\n * ์‹œ๊ฐ„์—ฌํ–‰์—์„œ๋„ ๋งž๋‹ค: ์—ฌ๊ธฐ ํƒœ์šฐ๋Š” ๊ฒƒ์€ ์ด๋ฏธ ์ž˜๋ผ ๋‚ธ(`wanted`) ์ด๋ฒคํŠธ๋ฟ์ด๋ฏ€๋กœ, ๊ทธ ์‹œ์ ๊นŒ์ง€์˜\n * ๊ฐ€๋™ ์ด๋ ฅ์ด ๋‚˜์˜จ๋‹ค(๊ทธ ๋’ค์— ์ผ์–ด๋‚œ ๊ณ ์žฅ์ด ๊ณผ๊ฑฐ ํ™”๋ฉด์— ์„ž์ด์ง€ ์•Š๋Š”๋‹ค).\n */\n const oee = new OeeAccumulator()\n /* ์žฌ๊ฐœ์ ์ด ์žˆ์œผ๋ฉด ๊ทธ ์œ„์— ๊ผฌ๋ฆฌ๋งŒ ์–น๋Š”๋‹ค โ€” ์—†์œผ๋ฉด ๊ผฌ๋ฆฌ๋ถ„๋งŒ ์„ธ์–ด ๊ฐ€์šฉ๋ฅ ์ด ์กฐ์šฉํžˆ ์ž‘์•„์ง„๋‹ค. */\n if (resume?.fold?.oee) oee.restore(resume.fold.oee)\n for (const r of wanted) {\n try {\n oee.apply(r.payload as any)\n } catch {\n /* ํ•œ ๊ฑด์ด ์ด์ƒํ•ด๋„ ๋‚˜๋จธ์ง€ ๊ณ„์ธก์„ ๋ฒ„๋ฆฌ์ง€ ์•Š๋Š”๋‹ค โ€” ๋ˆ„์ ๊ธฐ๋Š” ๋ชจ๋ฅด๋Š” ์ด๋ฒคํŠธ๋ฅผ ๋ฌด์‹œํ•˜๋Š” ๊ณ„์•ฝ์ด๋‹ค. */\n }\n }\n\n const withNow = (st: any): any => {\n if (!st || typeof st !== 'object') return st\n const nowTime = st.nowTime || untilTime || lastEventTime || undefined\n const based = nowTime ? { ...st, nowTime } : st\n /* ๊ณ„์ธก ์‹œ์ ์€ ๊ทธ ํ™”๋ฉด์˜ \"์ง€๊ธˆ\" ์ด๋‹ค โ€” ๋ฒฝ์‹œ๊ณ„๋กœ ์žฌ๋ฉด ๊ณผ๊ฑฐ ํ™”๋ฉด์˜ ๊ฐ€์šฉ๋ฅ ์ด ์‹œ๊ฐ„์ด ๊ฐˆ์ˆ˜๋ก ๋–จ์–ด์ง„๋‹ค. */\n const nowMs = nowTime ? Date.parse(String(nowTime)) : Number.NaN\n const withMetrics = withLiveOee(based, oee, Number.isFinite(nowMs) ? nowMs : undefined)\n return withLiveAttentions(withMetrics)\n }\n\n /* ์ ‘์€ ๊ฒฐ๊ณผ๋ฅผ ๋‚จ๊ธด๋‹ค โ€” **์ง€๊ธˆ์„ ๋ฌผ์—ˆ์„ ๋•Œ๋งŒ**(์‹œ๊ฐ„์—ฌํ–‰ ๊ฒฐ๊ณผ๋ฅผ \"์ง€๊ธˆ\" ์œผ๋กœ ์ €์žฅํ•˜๋ฉด ๊ฑฐ์ง“์ด ๋œ๋‹ค). */\n /*\n * ์ ‘์€ ์ง€์ ์˜ ๋ฆฌ๋น„์ „ โ€” ์‚ฌ์Šฌ์— ์ ์„ ์ด๋ฆ„์ด๋‹ค. ๊ผฌ๋ฆฌ๋ฅผ ์ ‘์—ˆ์œผ๋ฉด ๊ทธ ๊ผฌ๋ฆฌ์˜ ๋, ์•„๋ฌด๊ฒƒ๋„ ์•ˆ ์ฝ์—ˆ์œผ๋ฉด\n * ์”จ์•—์˜ ์ž๋ฆฌ ๊ทธ๋Œ€๋กœ๋‹ค(๋ชจ๋ฅด๋ฉด 0).\n */\n const foldedTo = rows.length ? (rows[rows.length - 1]?.revision ?? 0) : (from ?? 0)\n\n const keep = (st: any, fold?: { reducer: ReducerCheckpoint; oee: OeeCheckpoint }): any => {\n /* ์žฌ๊ฐœ์ ์„ ํ•จ๊ป˜ ๋‚จ๊ธด๋‹ค โ€” ์ƒํƒœ๋งŒ ๋‚จ๊ธฐ๋ฉด ๋‹ค์Œ ๋ฒˆ์— ๋˜ 0๋ถ€ํ„ฐ ์ ‘์–ด์•ผ ํ•œ๋‹ค(๊ทธ๊ฒƒ์ด ์ด ์ž‘์—…์˜ ์š”์ ์ด๋‹ค).\n **๊ตฌ์กฐ๊ฐ€ ๊ฐˆ๋ฆฐ ํด๋“œ์—๋Š” ์žฌ๊ฐœ์ ์„ ๋ถ™์ด์ง€ ์•Š๋Š”๋‹ค**: ๋งˆ๋””๋ฅผ ๊ฑด๋„ˆ๋›ด ์”จ์•—์€ ๊ทธ ๊ฒฝ๊ณ„์˜ ํŒ์ •์„ ์žƒ๋Š”๋‹ค. */\n if (asOfNowRead && tip && st) {\n void this.saveFoldedSnapshot(domainId, instanceId, { revision: tip.revision, state: st, structureRev: tip.structureRev, fold })\n }\n /*\n * ์‚ฌ์Šฌ์—๋Š” **๊ณผ๊ฑฐ๋ฅผ ์ ‘์—ˆ์„ ๋•Œ๋„** ํ•œ ์ง€์ ์„ ๋‚จ๊ธด๋‹ค (2026-08-18 ์‹ค์ธก์œผ๋กœ ๊ณ ์นจ).\n *\n * ์ฒ˜์Œ์—๋Š” ใ€Œ์ง€๊ธˆ ์ฝ๊ธฐใ€์—์„œ๋งŒ ๋‚จ๊ฒผ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋„๋Š” ํŠธ์œˆ์˜ ์ง€๊ธˆ ์ฝ๊ธฐ๋Š” ์ปค๋„ ์Šค๋ƒ…์ƒท์œผ๋กœ ์ฆ‰์‹œ ๋‹ตํ•˜๊ณ \n * ํด๋“œ์— ๋‹ฟ์ง€ ์•Š๋Š”๋‹ค โ€” ๊ทธ๋ž˜์„œ ์‚ฌ์Šฌ์ด **์˜์›ํžˆ ๋น„์–ด ์žˆ์—ˆ๋‹ค**(์‹ค์ธก: ์ง€์  0๊ฐœ, ์‹œ๊ฐ„์—ฌํ–‰ 3.7s ๊ทธ๋Œ€๋กœ).\n *\n * ์ง€์ ์€ ใ€Œ์ง€๊ธˆใ€์„ ์ฃผ์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค: ์ž๊ธฐ ๋ฆฌ๋น„์ „๊ณผ ์‹œ๊ฐ์„ ๋‹ฌ๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๊ณผ๊ฑฐ ํด๋“œ์˜ ๊ฒฐ๊ณผ๋ฅผ ๋‚จ๊ฒจ๋„\n * ๊ฑฐ์ง“์ด ์•„๋‹ˆ๋‹ค(๊ทธ๊ฒƒ์ด ์Šค๋ƒ…์ƒท๊ณผ ๋‹ค๋ฅธ ์ ์ด๋‹ค). ๊ทธ๋ž˜์„œ ์ฒซ ๊ณผ๊ฑฐ ์กฐํšŒ๊ฐ€ ๋‹ค์Œ ๊ณผ๊ฑฐ ์กฐํšŒ๋ฅผ ๋น ๋ฅด๊ฒŒ ํ•œ๋‹ค.\n */\n if (fold && st) {\n const at = asOfNowRead && tip ? tip.revision : foldedTo\n if (at > 0)\n void this.keepChainPoint(domainId, instanceId, {\n revision: at,\n ...(lastEventTime ? { eventTime: lastEventTime } : {}),\n structureRev: (asOfNowRead && tip ? tip.structureRev : null) ?? null,\n fold\n }).catch(() => {})\n }\n return st\n }\n\n /*\n * ์”จ์•—์ด ์žˆ์œผ๋ฉด **์ด์–ด ์ ‘๋Š”๋‹ค** โ€” ํ•œ ๊ตฌ์กฐ ์•ˆ์—์„œ๋งŒ(๊ตฌ์กฐ๊ฐ€ ๊ฐˆ๋ฆฌ๋ฉด ์•„๋ž˜ ๋งˆ๋”” ๊ฒฝ๋กœ๊ฐ€ ๋งก๋Š”๋‹ค).\n * ์ƒˆ ์žฌ๊ฐœ์ ๋„ ํ•จ๊ป˜ ๋‚จ๊ธด๋‹ค: ๋‹ค์Œ ๋ฒˆ์— ๋˜ ๊ผฌ๋ฆฌ๋งŒ ์ ‘์„ ์ˆ˜ ์žˆ์–ด์•ผ ์ด ์ง€๋ฆ„๊ธธ์ด ๊ณ„์† ์‚ฐ๋‹ค.\n */\n if (resume?.fold?.reducer && segments.length <= 1) {\n const model = (segments[0]?.model ?? (asOfNow && newest) ?? reg.model) as TwinModelDef\n const out = replayFrom(model, resume.fold.reducer, segments[0]?.events ?? [])\n return keep(withNow(out.state), { reducer: out.checkpoint, oee: oee.serialize() })\n }\n\n if (!segments.length) {\n const model = ((asOfNow && newest) || reg.model) as TwinModelDef\n const out = replayWithCheckpoint(model, [])\n return keep(withNow(out.state), { reducer: out.checkpoint, oee: oee.serialize() })\n }\n if (segments.length === 1) {\n const out = replayWithCheckpoint(segments[0].model, segments[0].events)\n return keep(withNow(out.state), { reducer: out.checkpoint, oee: oee.serialize() })\n }\n\n /* ์ปค๋„ ๊ณ„์•ฝ๋„ `model` ์ด๋‹ค(0.6.14) โ€” ๊ฒฝ๊ณ„์—์„œ ์–ดํœ˜๋ฅผ ๋˜๋Œ๋ ค ๋‹ด๋˜ ๋ธŒ๋ฆฟ์ง€๊ฐ€ ์‚ฌ๋ผ์กŒ๋‹ค. */\n const { state, shifts } = replaySegments(segments)\n /* ๊ฒฝ๊ณ„์—์„œ ์‚ฌ๋ผ์ง„ ๊ฒƒ์„ ์กฐ์šฉํžˆ ๋„˜๊ธฐ์ง€ ์•Š๋Š”๋‹ค โ€” ์ˆ˜๊ฐ€ ์ค„์–ด๋“  ์ด์œ ๋ฅผ ์–ด๋”˜๊ฐ€์—๋Š” ๋‚จ๊ฒจ์•ผ ํ•œ๋‹ค. */\n for (const sh of shifts)\n if (sh.equipmentDropped || sh.locationsDropped || sh.personsDropped || sh.assetsDropped)\n console.info(`[twin-engine] \"${instanceId}\" replay crossed a structure change โ€” dropped ${sh.equipmentDropped} equipment, ${sh.locationsDropped} locations, ${sh.personsDropped} persons, ${sh.assetsDropped} assets that no longer exist.`)\n return keep(withNow(state))\n }\n\n /**\n * ๊ณต๊ฐ„(๊ณต๋™๋ฐฐ์น˜) ์‹œ๊ฐ ๋ฒ”์œ„ โ€” ์Šคํฌ๋Ÿฌ๋ฒ„ ์•ต์ปค(runtime-state-model ยง4ยทยง6). ๊ทธ ๊ณต๊ฐ„ ์ „ ์ธ์Šคํ„ด์Šค ์ €๋„์˜ min/max eventTime.\n * ๋ฐ˜ํ™˜ {minTime, maxTime}(ISO) โ€” ์ด๋ฒคํŠธ/์‹œ๊ฐ ์—†์œผ๋ฉด null. ํด๋ผ ํžˆ์Šคํ† ๋ฆฌ ์Šคํฌ๋Ÿฌ๋ฒ„๊ฐ€ ์ด ๋ฒ”์œ„๋ฅผ ์‹œ๊ฐ์ถ•์œผ๋กœ ๊ทธ๋ฆฐ๋‹ค.\n */\n static async timeRange(domainId: string, spaceId: string): Promise<{ minTime: string | null; maxTime: string | null }> {\n const regs = await getRepository(TwinInstance).find({ where: { domain: { id: domainId }, spaceId } })\n const ids = regs.map(r => r.instanceId)\n if (!ids.length) return { minTime: null, maxTime: null }\n let min = Infinity\n let max = -Infinity\n for (const instanceId of ids) {\n const rows = await getRepository(TwinEvent).find({ where: { domain: { id: domainId }, instanceId } })\n for (const r of rows) {\n const t = r.eventTime != null ? Date.parse(String(r.eventTime)) : NaN\n if (Number.isNaN(t)) continue\n if (t < min) min = t\n if (t > max) max = t\n }\n }\n if (min === Infinity) return { minTime: null, maxTime: null }\n return { minTime: new Date(min).toISOString(), maxTime: new Date(max).toISOString() }\n }\n\n /** ์ •์ง€ ํ›… โ€” ์ธ์Šคํ„ด์Šค ์ •์ง€ ์‹œ ๋ถ€์ˆ˜์ž์› ์ •๋ฆฌ(์˜ˆ: reference-live ํ”ผ๋“œ unsubscribe). ์ˆœํ™˜ ์ž„ํฌํŠธ ์—†์ด ๊ฒฐ์„ . */\n static stopHooks: ((id: string) => void)[] = []\n static onStop(fn: (id: string) => void): void {\n this.stopHooks.push(fn)\n }\n\n static async stop(domainId: string, id: string): Promise<void> {\n const i = this.instances[runtimeKey(domainId, id)]\n if (i) {\n /*\n * **๋„๊ธฐ ์ „์— ๋‚จ๊ธด๋‹ค** โ€” ์ง€๊ธˆ์ด ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ง„์‹ค์ธ ๋งˆ์ง€๋ง‰ ์ˆœ๊ฐ„์ด๋‹ค.\n *\n * ๋‚จ๊ธฐ์ง€ ์•Š์œผ๋ฉด ๋‹ค์Œ ์กฐํšŒ๊ฐ€ ์ €๋„์„ ์ „๋Ÿ‰ ๋‹ค์‹œ ์ ‘๋Š”๋‹ค(๊ทธ ๊ฐ’์€ ์–ด์ฐจํ”ผ ๋ฐฉ๊ธˆ ๋ฉ”๋ชจ๋ฆฌ์— ์žˆ๋˜ ๊ฒƒ์ด๋‹ค).\n * ์ฒดํฌํฌ์ธํŠธ ๋ฃจํ”„๊ฐ€ 20์ดˆ๋งˆ๋‹ค ๋œจ์ง€๋งŒ ๊ทธ ์‚ฌ์ด์— ๋ฉˆ์ถ”๋ฉด ๊ทธ ๊ตฌ๊ฐ„์ด ํ†ต์งธ๋กœ ๋‹ค์‹œ ์ ‘ํžŒ๋‹ค.\n */\n await this.persistSnapshot(domainId, id).catch(err =>\n console.error(`[twin-engine] snapshot on stop fail \"${id}\"`, err?.message ?? err)\n )\n clearInterval(i.timer)\n i.unsub()\n delete this.instances[runtimeKey(domainId, id)]\n await getRepository(TwinInstance)\n .update({ domain: { id: i.domainId }, instanceId: id }, { status: 'stopped' })\n .catch(err => console.error('twin deregister fail', err))\n }\n for (const hook of this.stopHooks) { try { hook(id) } catch { /* ํ›… ๊ฒฉ๋ฆฌ */ } }\n }\n\n /*\n * tick ํ•œ ๋ฒˆ โ€” **ํ•œ ํŠธ์œˆ์˜ ์˜ˆ์™ธ๊ฐ€ ์„œ๋ฒ„๋ฅผ ๋‚ด๋ฆฌ์ง€ ๋ชปํ•˜๊ฒŒ** ๊ฐ์‹ผ๋‹ค.\n *\n * ์ž˜๋ชป๋œ ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์‹ค๋ ธ์„ ๋•Œ ๋‹ค์Œ tick ์—์„œ `rate.meanPerHour` ๋ฅผ ์ฝ๋‹ค ํ„ฐ์กŒ๊ณ , ํƒ€์ด๋จธ ์ฝœ๋ฐฑ์˜\n * ์˜ˆ์™ธ๋Š” ์•„๋ฌด๋„ ๋ฐ›์ง€ ์•Š์•„ **uncaught exception ์œผ๋กœ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋‚ด๋ ค๊ฐ”๋‹ค.** ํ•œ ํ…Œ๋„ŒํŠธ์˜ ์ž˜๋ชป๋œ\n * ์„ ์–ธ์ด ๋ชจ๋“  ํ…Œ๋„ŒํŠธ๋ฅผ ๋ฉˆ์ถ˜ ์…ˆ์ด๋‹ค. ๋ฌธ ์•ž์—์„œ ๋ง‰๋Š” ๊ฒƒ์ด 1์ฐจ ๋ฐฉ๋ฒฝ์ด๊ณ (`validateScenario`),\n * ์ด๊ฒƒ์ด 2์ฐจ ๋ฐฉ๋ฒฝ์ด๋‹ค.\n *\n * **์กฐ์šฉํžˆ ์‚ผํ‚ค์ง€ ์•Š๋Š”๋‹ค.** ์‹คํ–‰์„ ๋ฉˆ์ถ”๊ณ  ๊ทธ ์‚ฌ์‹ค์„ ๋‚จ๊ธด๋‹ค โ€” ์˜ˆ์™ธ๋ฅผ ๋ฌด์‹œํ•˜๊ณ  ๊ณ„์† tick ํ•˜๋ฉด\n * ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋งค ์ฃผ๊ธฐ ์Ÿ์•„์ง€๊ณ , ๊ทธ ํŠธ์œˆ์€ \"๋„๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋ฉด์„œ\" ์•„๋ฌด๊ฒƒ๋„ ์ง„ํ–‰ํ•˜์ง€ ์•Š๋Š”๋‹ค.\n */\n /**\n * ๊ฐ™์€ ํ˜„์žฅ ํŠธ์œˆ๋“ค์˜ **์„ค๋น„ ์ƒํƒœ**๋ฅผ ์ปค๋„์— ๋„˜๊ธด๋‹ค โ€” ์ปค๋„์ด ์š”์ฒญํ•  ๋•Œ๋งŒ.\n *\n * โ”€โ”€ ๊ฒฝ๊ณ„ (2026-08-14) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ํ˜ธ์ŠคํŠธ๊ฐ€ ์•„๋Š” ๊ฒƒ์€ **๋ˆ„๊ฐ€ ๊ฐ™์€ ํ˜„์žฅ์— ์žˆ๋Š”๊ฐ€** ํ•˜๋‚˜๋‹ค. ๋ฌด์—‡์„ ์ฝ๊ณ  ๊ทธ๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ๋ถ€ํ•˜๋กœ ๋ฐ”๊ฟ€์ง€๋Š”\n * ์ปค๋„์ด ์ •ํ•œ๋‹ค(๊ณ„์ˆ˜๋Š” ํŠธ์œˆ์˜ ๋ชจ๋ธ์ด ์„ ์–ธํ•œ๋‹ค). ํ˜ธ์ŠคํŠธ๊ฐ€ kW ๋ฅผ ๊ณ„์‚ฐํ•ด ์ฃผ๋ฉด ํŠธ์œˆ๋งˆ๋‹ค ๋‹ค๋ฅธ ๊ทœ์น™์ด\n * ์ƒ๊ธฐ๊ณ , ๊ทธ ๊ทœ์น™์€ ์–ด๋””์—๋„ ์ ํ˜€ ์žˆ์ง€ ์•Š๊ฒŒ ๋œ๋‹ค.\n *\n * ์ƒํƒœ๋งŒ ๋„˜๊ธด๋‹ค. ์Šค๋ƒ…์ƒท์„ ํ†ต์งธ๋กœ ๋„˜๊ธฐ๋ฉด ์ƒํƒœ ํฌ๊ธฐ์— ๋น„๋ก€ํ•œ ๋น„์šฉ์„ ๋งค tick ์น˜๋ฅด๊ฒŒ ๋œ๋‹ค โ€”\n * ์„ค๋น„ ๋ชฉ๋ก์€ ๊ทธ ํŠธ์œˆ์˜ ์ปค๋„์ด ์ด๋ฏธ ๋“ค๊ณ  ์žˆ๋Š” ๊ฒƒ์ด๋ผ ํ›‘๋Š” ๊ฐ’์ด ์‹ธ๋‹ค.\n */\n private static feedPeerEquipment(inst: InstanceRuntime): void {\n const kernel: any = inst.kernel\n if (typeof kernel?.observePeerEquipment !== 'function') return // ์ด์›ƒ์„ ์ฝ์ง€ ์•Š๋Š” ์ปค๋„\n if (!inst.spaceId) {\n kernel.observePeerEquipment([]) // ํ˜„์žฅ์ด ์—†์œผ๋ฉด ์ด์›ƒ๋„ ์—†๋‹ค(์˜› ์ƒํƒœ๊ฐ€ ๋‚จ์ง€ ์•Š๊ฒŒ ๋น„์šด๋‹ค)\n return\n }\n const peers: { id: string; status?: string }[] = []\n for (const other of Object.values(this.instances)) {\n if (other === inst || other.domainId !== inst.domainId || other.spaceId !== inst.spaceId) continue\n const eq: Map<string, any> | undefined = (other.kernel as any)?.equipment\n if (!eq || typeof eq.forEach !== 'function') continue\n eq.forEach(e => peers.push({ id: String(e?.id ?? ''), status: String(e?.status ?? '') }))\n }\n kernel.observePeerEquipment(peers)\n }\n\n private static tickGuarded(domainId: string, id: string, runtime: TwinRuntimeType): void {\n const inst = this.instances[runtimeKey(domainId, id)]\n const load = inst && (inst.load ?? (inst.load = newLoadMeter()))\n const t0 = performance.now()\n try {\n /* ์ด์›ƒ์˜ ์„ค๋น„ ์ƒํƒœ๋ฅผ ๋จผ์ € ์‹ฃ๋Š”๋‹ค โ€” ์ปค๋„์ด ์ด๋ฒˆ tick ์—์„œ ๋ถ€ํ•˜๋ฅผ ๋งŒ๋“ค ๋•Œ ์ฝ๋Š”๋‹ค. */\n if (inst) this.feedPeerEquipment(inst)\n runtime.tick(this.TICK_MS)\n\n /* ์žฌ๊ณ  ๋งํ•œ๋‹ค โ€” ์‹œ๋ฎฌ ํ‹ฑ์€ ๋ฉ”์ธ ์ด๋ฒคํŠธ ๋ฃจํ”„์—์„œ ์ˆ˜ํ–‰๋œ๋‹ค. ์˜ˆ์‚ฐ(๊ฐ„๊ฒฉ์˜ ์ ˆ๋ฐ˜)์„ ๋„˜๊ธฐ๋ฉด HTTPยท๊ตฌ๋…์ด\n ํ•จ๊ป˜ ๋А๋ ค์ง€๋Š”๋ฐ, ์˜ˆ์ „์—๋Š” ๊ทธ๊ฒƒ์„ ๋ณผ ๊ณ„๊ธฐํŒ์ด ์—†์–ด \"ํ„ฐ์ง€๋ฉด ์•Œ๊ณ  ๋А๋ ค์ง€๋ฉด ๋ชฐ๋ž๋‹ค\". */\n if (load) {\n const took = performance.now() - t0\n recordPhase(load, 'tick', took)\n const j = judgeCycle(load, took, this.TICK_MS, Date.now())\n if (j.warn) console.warn(slowTickMessage(id, took, j.budgetMs, load))\n this.guardStarvation(domainId, id, took)\n }\n } catch (err: any) {\n /*\n * ๋ฉˆ์ถ”๋Š” ๊ธธ์€ **ํ•˜๋‚˜**๋‹ค(`stop`) โ€” ์˜ˆ์ „์—๋Š” ํƒ€์ด๋จธ๋งŒ ๊ป๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋“ฑ๋ก๋ถ€๋Š” ๊ณ„์† `running` ์ด๋ผ\n * ๋งํ•˜๊ณ (์•„๋ฌด ํ‹ฑ๋„ ์—†๋Š” ์ฑ„๋กœ), ๋ถ€ํŒ… ์žฌ๊ฐœ๋Š” ๊ทธ ๊ฑฐ์ง“์„ ๊ทผ๊ฑฐ๋กœ ๋‹ค์‹œ ์„ธ์šด๋‹ค. ์Šค๋ƒ…์ƒท ๋ณด์กดยทํ”ผ๋“œ ์ •๋ฆฌยท\n * ๋“ฑ๋ก๋ถ€ ๊ฐฑ์‹ ์ด ๋ชจ๋‘ `stop` ์•ˆ์— ์žˆ๋‹ค.\n */\n this.stopWithNote(\n domainId,\n id,\n { code: 'tick-failed', params: { reason: String(err?.message ?? err) } },\n `[twin-engine] \"${id}\" tick failed โ€” this twin is stopped (other twins keep running). ` +\n `Fix the declaration and start it again. Reason: ${err?.message ?? err}`\n )\n }\n }\n\n /**\n * ํ˜ธ์ŠคํŠธ๋ฅผ ๊ตถ๊ธฐ๋Š” ํŠธ์œˆ์„ ๋ฉˆ์ถ˜๋‹ค โ€” **๋„๋Š” ์ฒ™ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋ฉˆ์ถ˜ ๊ฒƒ์ด ๋‚ซ๋‹ค.**\n *\n * ๊ตถ๊น€ ๋ฌธํ„ฑ์„ ๋„˜๋Š” ํ‹ฑ์ด ์—ฐ์† `STARVE_STREAK` ๋ฒˆ์ด๋ฉด ๊ทธ ํŠธ์œˆ์€ ๊ตฌ์กฐ์ ์œผ๋กœ ๋ฌด๊ฒ๋‹ค(์šฐ์—ฐ์ด ์•„๋‹ˆ๋‹ค).\n * ๋ฌธํ„ฑ ์•„๋ž˜๋กœ ํ•œ ๋ฒˆ๋งŒ ๋‚ด๋ ค์™€๋„ ์—ฐ์†์„ ๋Š๋Š”๋‹ค โ€” ๋ฌด๊ฑฐ์šด ์ˆœ๊ฐ„ ํ•˜๋‚˜๋กœ ํŠธ์œˆ์„ ๋‚ด๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.\n */\n private static guardStarvation(domainId: string, id: string, tookMs: number): void {\n const key = runtimeKey(domainId, id)\n const starveMs = this.TICK_MS * this.STARVE_FACTOR\n if (!(tookMs >= starveMs)) {\n this.starveStreak.delete(key)\n return\n }\n const streak = (this.starveStreak.get(key) ?? 0) + 1\n this.starveStreak.set(key, streak)\n if (streak < this.STARVE_STREAK) return\n\n this.starveStreak.delete(key)\n const secs = Math.round(tookMs) / 1000\n this.stopWithNote(\n domainId,\n id,\n { code: 'starved', params: { streak, thresholdSec: starveMs / 1000, lastSec: secs } },\n `[twin-engine] \"${id}\" stopped โ€” ${streak} consecutive ticks over ${starveMs / 1000}s (last ${secs}s). ` +\n `A simulation tick runs on the main loop, so this twin was stalling HTTP, subscriptions and every other twin. ` +\n `Its state is checkpointed; start it again after making it lighter (fewer orders/resources) or wait for off-loop ticking.`\n )\n }\n\n /** ๋ฉˆ์ถ”๊ณ  **์ด์œ ๋ฅผ ๋‚จ๊ธด๋‹ค** โ€” ์ด์œ  ์—†๋Š” ใ€Œ์ •์ง€ใ€๋Š” ์‚ฌ๋žŒ์ด ์ž๊ธฐ๊ฐ€ ๋ฉˆ์ถ˜ ๊ฒƒ์œผ๋กœ ์ฝ๋Š”๋‹ค. */\n private static stopWithNote(domainId: string, id: string, note: StopNote, log: string): void {\n console.error(log)\n this.stopNotes.set(runtimeKey(domainId, id), note)\n this.stop(domainId, id).catch(err => console.error(`[twin-engine] stop after guard failed \"${id}\"`, err?.message ?? err))\n }\n\n /** ์ด ํŠธ์œˆ์ด ์Šค์Šค๋กœ ๋ฉˆ์ถ˜ ์ด์œ (์žˆ์œผ๋ฉด) โ€” ํ™”๋ฉด์ด ์˜ฎ๊ฒจ ๋งํ•œ๋‹ค. */\n static stopNoteOf(domainId: string, id: string): StopNote | undefined {\n return this.stopNotes.get(runtimeKey(domainId, id))\n }\n\n /**\n * ์ด ํŠธ์œˆ์ด **์ง€๊ธˆ ์‹คํ–‰ ์ค‘์ธ๊ฐ€** โ€” ํŒ์ •์˜ ์ง‘ ํ•˜๋‚˜.\n *\n * \"์Šค๋ƒ…์ƒท์ด ์žˆ๋‚˜\" ๋กœ๋Š” ๋‹ต์ด ๋˜์ง€ ์•Š๋Š”๋‹ค: ์›œ์Šคํƒ€ํŠธ๊ฐ€ ๋˜์‚ด๋ฆฐ ์ƒํƒœ๊ฐ€ ์บ์‹œ์— ๋‚จ์•„ ์žˆ์œผ๋ฉด ๋ฉˆ์ถ˜ ํŠธ์œˆ๋„\n * ์Šค๋ƒ…์ƒท์„ ๋‚ธ๋‹ค. ๊ทธ๊ฒƒ์„ ๊ด€์ธก ์ค‘์œผ๋กœ ์ฝ์œผ๋ฉด ํ™”๋ฉด์ด **๋ฉˆ์ถ˜ ํŠธ์œˆ์˜ ์ž‘์—…์„ 0 ๊ฑด์ด๋ผ๊ณ  ๋‹จ์–ธ**ํ•œ๋‹ค\n * (์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ๋‚˜์™”๋‹ค โ€” ๊ด€์ธก์ด ์—†๋Š” ๊ฒƒ๊ณผ 0 ๊ฑด์€ ๋‹ค๋ฅด๋‹ค๋Š” ์ด ํ”„๋กœ์ ํŠธ์˜ ๊ทœ์œจ์„ ํ™”๋ฉด์ด ์–ด๊ฒผ๋‹ค).\n *\n * ๋ชฉ๋ก์ด ์“ฐ๋Š” ๊ฒƒ๊ณผ **๊ฐ™์€ ์ˆ ์–ด**๋‹ค(`list()` ์˜ `running`) โ€” ๋‘ ๋ฒŒ์ด๋ฉด ์–ด๊ธ‹๋‚œ๋‹ค.\n */\n static isRunning(domainId: string, id: string): boolean {\n return !!this.instances[runtimeKey(domainId, id)]\n }\n\n static runtime(domainId: string, id: string): TwinRuntimeType | undefined {\n return this.instances[runtimeKey(domainId, id)]?.runtime\n }\n\n /*\n * ์ปค๋งจ๋“œ ์‹คํ–‰ โ€” **ํŒ์ •์€ `routeCommand`(์ˆœ์ˆ˜)๊ฐ€ ํ•˜๊ณ  ์—ฌ๊ธฐ์„œ๋Š” ์‹คํ–‰๋งŒ** ํ•œ๋‹ค.\n * ํŒ์ •์„ ์ฝ”๋“œ ํ•œ๊ฐ€์šด๋ฐ ๋‘๋ฉด ์ด ๋ถ€๋ฅ˜๋ฅผ ํ…Œ์ŠคํŠธ๋กœ ๋ชป ์žก๋Š”๋‹ค(์—”์ง„์€ DB ๋ฅผ ๋ฌผ๊ณ  ์žˆ์–ด ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€\n * ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์—†๋‹ค). ์˜ˆ์ „์—๋Š” ๋ฆฌ์กธ๋ฒ„๊ฐ€ `inst.runtime.dispatch` ๋ฅผ ๊ณง๋ฐ”๋กœ ๋ถˆ๋Ÿฌ ๋ฏธ๋Ÿฌ์—์„œ ํ„ฐ์กŒ๋‹ค.\n */\n static async dispatchCommand(domainId: string, instanceId: string, command: any): Promise<{ accepted: boolean; error?: string; errorCode?: string; errorParams?: Record<string, string | number> }> {\n const inst = this.instances[runtimeKey(domainId, instanceId)]\n const type = String(command?.type ?? '')\n const route = routeCommand(\n inst && { mode: inst.mode, hasRuntime: !!inst.runtime, hasKernelDispatch: typeof (inst.kernel as any)?.dispatch === 'function' },\n !!inst && inst.domainId === domainId,\n type\n )\n if (route.target === 'reject') {\n return { accepted: false, errorCode: route.errorCode, errorParams: route.errorParams, error: route.errorCode }\n }\n\n const cmd = { ...command, tenantId: domainId } // tenantId ๋Š” ํ˜ธ์ถœ์ž ๋„๋ฉ”์ธ์œผ๋กœ ๊ฐ์ธ(๊ฐ์‚ฌยท๋ฌด๊ฒฐ์„ฑ)\n if (route.target === 'runtime') return inst!.runtime!.dispatch(cmd)\n\n /*\n * ๋ฏธ๋Ÿฌ โ€” ๊ด€์ธก ์ปค๋„๋กœ ๋ณด๋‚ด๊ณ , **์ปค๋งจ๋“œ๊ฐ€ ๋‚ธ ์‚ฌ์‹ค์„ ์ €๋„ ํ์— ์‹ค์–ด** ์ฝ”์–ผ๋ ˆ์„œ๊ฐ€ ๋ฒˆํ˜ธ๋ฅผ ๋ถ€์—ฌํ•˜๊ฒŒ ํ•œ๋‹ค.\n * ๋ฏธ๋Ÿฌ์—๋Š” State ๊ตฌ๋… ๋ฐฐ๊ด€์ด ์—†์–ด(์‹œ๋ฎฌ์€ ๊ทธ ๊ฒฝ๋กœ๋กœ ์ €๋„๋ง) ์ปค๋„ ๋ฐฉ์ถœ์ด ์•„๋ฌด ๋ฐ๋„ ๋‹ฟ์ง€ ์•Š๋Š”๋‹ค.\n * ์—ฌ๊ธฐ์„œ DB ๋ฅผ ๋”ฐ๋กœ ์ฝ์–ด ๋ฒˆํ˜ธ๋ฅผ ๋งค๊ธฐ๋ฉด ์ธ๋ฉ”๋ชจ๋ฆฌ ์นด์šดํ„ฐ์™€ ์–ด๊ธ‹๋‚˜ ๋ฆฌ๋น„์ „์ด ๊ฒน์นœ๋‹ค(๊ฒน์นจ์€ ์˜ค๋ฅ˜๋ฅผ\n * ๋‚ด์ง€ ์•Š๊ณ  ์žฌ์ƒ ์ˆœ์„œ๋งŒ ์กฐ์šฉํžˆ ๋’ค์„ž๋Š”๋‹ค).\n */\n const kernel: any = inst!.kernel\n const emitted: any[] = []\n const off = kernel.onEvent?.((e: any) => emitted.push(e))\n let ack: any\n try {\n ack = kernel.dispatch(cmd)\n } finally {\n off?.()\n }\n if (ack?.accepted && emitted.length) {\n inst!.pendingJournal = [...(inst!.pendingJournal ?? []), ...emitted]\n inst!.dirty = true // ์ฝ”์–ผ๋ ˆ์„œ๊ฐ€ ์ด๋ฒˆ ์ฃผ๊ธฐ์— ๋น„์šฐ๊ณ  ๋ฐฉ์†ก๊นŒ์ง€ ํ•˜๊ฒŒ ํ•œ๋‹ค\n }\n return ack ?? { accepted: false, errorCode: 'unknown-command', error: 'unknown-command' }\n }\n\n /**\n * ๋„๋ฉ”์ธ ์†Œ์œ  ๊ฒŒ์ดํŠธ โ€” ์ธ์Šคํ„ด์Šค๊ฐ€ ์ด ๋„๋ฉ”์ธ ์†Œ์œ ์ผ ๋•Œ๋งŒ true(ํ…Œ๋„ŒํŠธ ๊ฒฉ๋ฆฌ).\n * ์—†๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ๋„๋ฉ”์ธ์ด๋ฉด false. ๋…ธ์ถœ ๋ฆฌ์กธ๋ฒ„(per-id metrics/attentions/state/stop/forecast)๊ฐ€\n * this.instances[id] ๋ฅผ ๋งŒ์ง€๊ธฐ ์ „์— ๋ฐ˜๋“œ์‹œ ์ด๊ฑธ๋กœ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค. ์ธ์Šคํ„ด์Šค id ๋Š” ์ถ”์ธก ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ\n * ๊ฒ€์ฆ ์—†์ด ์ ‘๊ทผํ•˜๋ฉด ํฌ๋กœ์Šคํ…Œ๋„ŒํŠธ ์ฝ๊ธฐ/์ •์ง€๊ฐ€ ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.\n */\n /**\n * ์ด ๋Ÿฐํƒ€์ž„์˜ **๊ด€์ธก ๋ชจ๋“œ** โ€” `'live'`(์™ธ๋ถ€ ์‹ค๋ฌผ์„ ๋ฏธ๋Ÿฌ) ๋˜๋Š” `'sim'`(์ปค๋„์ด ์‹คํ–‰ํ•œ๋‹ค). ๊ธฐ๋™ ์ค‘์ด ์•„๋‹ˆ๋ฉด ์—†๋‹ค.\n *\n * ์†Œ๋น„์ฒ˜๊ฐ€ `instances[id].mode` ๋ฅผ ์ง์ ‘ ์ฝ๋˜ ์ž๋ฆฌ๋ฅผ ๋Œ€์‹ ํ•œ๋‹ค. ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋ฅผ ๋ฐ–์— ์—ด๋ฉด ๋„๋ฉ”์ธ ํ™•์ธ์ด\n * ์ž๋ฆฌ๋งˆ๋‹ค ์ œ๊ฐ๊ฐ์ด ๋˜๊ณ , ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ๋๋‹ค(ํ…Œ๋„ŒํŠธ ๊ฒฉ๋ฆฌ ์ „์ˆ˜ ํ™•์ธ, 2026-08-06).\n */\n static modeOf(domainId: string, id: string): 'live' | 'sim' | undefined {\n return this.instances[runtimeKey(domainId, id)]?.mode\n }\n\n static owns(domainId: string, id: string): boolean {\n return !!this.instances[runtimeKey(domainId, id)]\n }\n\n /**\n * ์ด ํŠธ์œˆ์ด ์ด ํ…Œ๋„ŒํŠธ ๊ฒƒ์ธ๊ฐ€ โ€” **๋–  ์žˆ๋“  ์•„๋‹ˆ๋“ .**\n *\n * `owns()` ๋Š” **๊ธฐ๋™ ์ค‘์ธ** ๋Ÿฐํƒ€์ž„๋งŒ ์•ˆ๋‹ค. ๊ทธ๊ฒƒ์„ ์ด๋ ฅ ์กฐํšŒ์˜ ๊ด€๋ฌธ์œผ๋กœ ์“ฐ๋ฉด, ๊บผ์ง„ ํŠธ์œˆ์˜ ์ €๋„์„\n * ์ฝ์œผ๋ ค ํ•  ๋•Œ \"์ด ํ…Œ๋„ŒํŠธ์— ์—†๋‹ค\" ๋Š” ๋‹ต์ด ๋Œ์•„์˜จ๋‹ค โ€” ๋‘ ๊ฐ€์ง€๊ฐ€ ํ‹€๋ ธ๋‹ค. ์ฒซ์งธ, ์ €๋„์€ ํŠธ์œˆ์ด ๊บผ์ ธ\n * ์žˆ์„ ๋•Œ **๊ฐ€์žฅ ํ•„์š”ํ•œ ๊ฒƒ**์ด๋‹ค(๊ทธ๊ฒŒ ์ด๋ ฅ์˜ ์กด์žฌ ์ด์œ ๋‹ค). ๋‘˜์งธ, ๊ทธ ๋ฌธ์žฅ์€ ๋‚จ์˜ ๊ฒƒ์ด๋ผ๋Š” ๋œป์ด๋ผ\n * ์‚ฌ์šฉ์ž๊ฐ€ ๊ถŒํ•œ ๋ฌธ์ œ๋กœ ์˜คํ•ดํ•œ๋‹ค. ์‹ค์ œ๋กœ๋Š” ๊ทธ๋ƒฅ ์‹คํ–‰ ์ค‘์ด ์•„๋‹ ๋ฟ์ด๋‹ค.\n *\n * ์†Œ์œ ๋Š” **๋“ฑ๋ก๋ถ€**๊ฐ€ ์•ˆ๋‹ค. ์ด๋ ฅยท์ง‘๊ณ„์ฒ˜๋Ÿผ ๋Ÿฐํƒ€์ž„๊ณผ ๋ฌด๊ด€ํ•œ ์งˆ๋ฌธ์€ ์ด์ชฝ์— ๋ฌป๋Š”๋‹ค.\n */\n static async ownsRegistered(domainId: string, instanceId: string): Promise<boolean> {\n if (this.owns(domainId, instanceId)) return true\n return !!(await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } }))\n }\n\n /**\n * **์ด ๊ณต๊ฐ„์˜ ์ธ์Šคํ„ด์Šค๋“ค** โ€” ํ•œ ํ˜„์‹ค์„ ์—ฌ๋Ÿฌ ๋ Œ์ฆˆ๊ฐ€ ๋น„์ถ”๋ฏ€๋กœ, ๊ณต๊ฐ„์„ ๋ฌผ์œผ๋ฉด ๊ทธ ๋ Œ์ฆˆ ์ „๋ถ€๋ฅผ ๋‹ตํ•œ๋‹ค.\n *\n * ํ™”๋ฉด์ด ์ด ๊ทœ์น™์„ ์†์œผ๋กœ ์งœ์ง€ ์•Š๊ฒŒ ์„œ๋ฒ„๊ฐ€ ๋‹ตํ•œ๋‹ค. ์˜ˆ์ธก ํ™”๋ฉด์€ ๊ฐ™์€ ํ™•์žฅ์„ **ํ•œ ํŒŒ์ผ์—์„œ ๋‘ ๋ฒˆ**\n * ๋ณต์ œํ•˜๊ณ  ์žˆ์—ˆ๋‹ค(์ „์ฒด ๋ชฉ๋ก์„ ๋ฐ›์•„ ํด๋ผ์ด์–ธํŠธ์—์„œ ๊ฑธ๋ €๋‹ค) โ€” ๊ทœ์น™์ด ํฉ์–ด์ง€๋ฉด ํ•œ์ชฝ๋งŒ ๊ณ ์ณ์ง„๋‹ค.\n *\n * ๋–  ์žˆ์ง€ ์•Š์€ ๊ฒƒ๋„ ํฌํ•จํ•œ๋‹ค: ๊ณต๊ฐ„์— ๋ฌด์—‡์ด ์žˆ๋Š”์ง€๋Š” ๊ธฐ๋™ ์—ฌ๋ถ€์™€ ๋‹ค๋ฅธ ์‚ฌ์‹ค์ด๋‹ค.\n */\n static async instanceIdsOfSpace(domainId: string, spaceId: string): Promise<string[]> {\n if (!spaceId) return []\n const rows = await getRepository(TwinInstance).find({ where: { domain: { id: domainId }, spaceId } })\n return rows.map(r => r.instanceId).filter((x): x is string => !!x)\n }\n\n /**\n * **์ด ๊ณต๊ฐ„์—์„œ ๋ด์•ผ ํ•  ๊ฒƒ** โ€” ๊ณต๊ฐ„์˜ ๋ชจ๋“  ๋ Œ์ฆˆ์—์„œ ์‹ ํ˜ธ๋ฅผ ๋ชจ์€๋‹ค.\n *\n * ํ•ฉ์ง‘ํ•ฉ์ด ๊ทธ๋Œ€๋กœ ๋œป์ด ์žˆ๋Š” ์œ ์ผํ•œ ๋ Œ์ฆˆ๋‹ค(์˜ˆ์ธก์€ ํ•ฉ์น  ์ˆ˜ ์—†๋‹ค โ€” P50 ๋‘ ๊ฐœ๋ฅผ ๋”ํ•  ์ˆ˜ ์—†๋‹ค).\n * ์ •๋ ฌยท์ž˜๋ผ๋‚ด๊ธฐ๋Š” ํ™”๋ฉด๊ณผ **๊ฐ™์€ ๊ทœ์น™**์„ ์“ด๋‹ค(`digestAttentions`) โ€” ์„œ๋ฒ„๊ฐ€ ๊ณ ๋ฅธ ์ƒ์œ„ N ์ด ํ™”๋ฉด์ด\n * ๊ณ ๋ฅผ N ๊ณผ ๋‹ฌ๋ผ์ง€๋ฉด ๊ทธ ์–ด๊ธ‹๋‚จ์€ ์•„๋ฌด ๋ฐ์„œ๋„ ์˜ค๋ฅ˜๋กœ ๋“œ๋Ÿฌ๋‚˜์ง€ ์•Š๋Š”๋‹ค.\n *\n * ์‹ ํ˜ธ๋งˆ๋‹ค ์–ด๋А ํŠธ์œˆ์—์„œ ์™”๋Š”์ง€(`instanceId`)๋ฅผ ๋ถ™์ธ๋‹ค. ๊ณต๊ฐ„์—์„œ ๋ณด๋ฉด ๊ฐ™์€ ์ž๋ฆฌ id ๊ฐ€ ๋ Œ์ฆˆ๋งˆ๋‹ค\n * ๋‹ค๋ฅธ ๊ฒƒ์„ ๊ฐ€๋ฆฌํ‚ฌ ์ˆ˜ ์žˆ๊ณ , ์กฐ์น˜๋Š” ๊ฒฐ๊ตญ ๊ทธ ํŠธ์œˆ์— ๋ณด๋‚ด์•ผ ํ•œ๋‹ค.\n */\n static async attentionsOfSpace(domainId: string, spaceId: string, limit?: number): Promise<{ attentions: any[]; attentionTotal: number; severityByLocation: Record<string, string> }> {\n const ids = await this.instanceIdsOfSpace(domainId, spaceId)\n const lenses = ids\n /* ๋–  ์žˆ์ง€ ์•Š์€ ํŠธ์œˆ์€ **์ง€๊ธˆ** ์‹ ํ˜ธ๊ฐ€ ์—†๋‹ค(๊ทธ ์‹œ์ ˆ ์‹ ํ˜ธ๋Š” ์‹œ๊ฐ„์—ฌํ–‰์ด ๋‹ตํ•œ๋‹ค). */\n .filter(id => this.owns(domainId, id))\n .map(id => {\n const kernel: any = this.kernel(domainId, id)\n const snap = kernel?.getSnapshot?.() ?? this.snapshot(domainId, id)\n return { instanceId: id, attentions: snap?.attentions ?? [] }\n })\n /* ๋ชจ์œผ๋Š” ๊ทœ์น™(ํƒœ๊น…ยท๊ธ‰ํ•œ ์ˆœ์„œยท์ž๋ฆฌ ์ƒ‰)์€ ์ˆœ์ˆ˜ ํ•จ์ˆ˜๊ฐ€ ๋“ค๊ณ  ์žˆ๋‹ค โ€” ์—ฌ๊ธฐ์„œ ์†์œผ๋กœ ์ ‘์ง€ ์•Š๋Š”๋‹ค. */\n return mergeLensAttentions(lenses, limit)\n }\n\n /** ๋ผ์ด๋ธŒ ์ปค๋„(ForecastTwin) โ€” forecast/divergence ์˜ˆ์ธก ์—ฐ์‚ฐ์šฉ. */\n static kernel(domainId: string, id: string): any {\n return this.instances[runtimeKey(domainId, id)]?.kernel\n }\n\n /** ๋ผ์ด๋ธŒ ์ฒ˜๋ฆฌ๋Ÿ‰ ๊ณ„์ธก ์Šค๋ƒ…์ƒท(๋ชจ๋‹ˆํ„ฐ, โ‘ฃ-1) โ€” ๋‚ด๋ถ€ ๋ˆ„์ (_acc*) ์ œ์™ธํ•œ ๊ณต๊ฐœ ์ง€ํ‘œ. live ์•„๋‹ˆ๋ฉด null. */\n static metrics(domainId: string, id: string): any {\n const m = this.instances[runtimeKey(domainId, id)]?.metrics\n if (!m) return null\n return {\n instanceId: id,\n ingestedTotal: m.ingestedTotal, broadcastTotal: m.broadcastTotal, journaledTotal: m.journaledTotal,\n ingestRate: m.ingestRate, broadcastRate: m.broadcastRate, journalRate: m.journalRate,\n backlog: m.backlog, broadcastCoalesceMs: this.BROADCAST_COALESCE_MS,\n /* ์ž‘์—…๋ณ„ ๋ถ€ํ•˜ โ€” ๋ฌด๊ฑฐ์šด ๊ฒƒ๋ถ€ํ„ฐ. ์žฐ ์ ์ด ์—†์œผ๋ฉด null(0 ์œผ๋กœ ์ฑ„์šฐ๋ฉด \"๋น ๋ฅด๋‹ค\" ๋กœ ์ฝํžŒ๋‹ค). */\n load: loadSummary(this.instances[runtimeKey(domainId, id)]?.load, this.TICK_MS)\n }\n }\n\n /**\n * ๋ถ€ํ•˜ ๊ณ„๊ธฐํŒ๋งŒ ๋”ฐ๋กœ โ€” **์‹œ๋ฎฌ ํŠธ์œˆ๋„ ํฌํ•จํ•œ๋‹ค.**\n *\n * `metrics()` ๋Š” ๋ผ์ด๋ธŒ ์ง€ํ‘œ(`inst.metrics`)๊ฐ€ ์žˆ์–ด์•ผ ๋ฌด์–ธ๊ฐ€๋ฅผ ๋Œ๋ ค์ค€๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ์ ์œ ํ•˜๋Š”\n * ๊ฒƒ์€ ์ฃผ๋กœ **์‹œ๋ฎฌ ํ‹ฑ**์ด๊ณ , ์‹œ๋ฎฌ ์ธ์Šคํ„ด์Šค์—๋Š” ๊ทธ ์ง€ํ‘œ๊ฐ€ ์—†์–ด ํ†ต์งธ๋กœ ์•ˆ ๋ณด์˜€๋‹ค.\n */\n static load(domainId: string, id: string): any {\n const inst = this.instances[runtimeKey(domainId, id)]\n if (!inst) return null\n\n return {\n instanceId: id,\n mode: inst.mode ?? 'sim',\n domainId: inst.domainId,\n domainLabel: inst.domain?.subdomain,\n restartPolicy: inst.restartPolicy,\n tickMs: this.TICK_MS,\n running: !!inst.timer || inst.mode === 'live',\n ...(loadSummary(inst.load, this.TICK_MS) ?? { recent: null, total: null, forksCreated: 0, overBudget: 0, budgetMs: this.TICK_MS * 0.5, loadRatio: null })\n }\n }\n\n /**\n * **ํ•œ ๊ณณ์—์„œ ๋ณด๋Š” ์ „์ฒด ๋ถ€ํ•˜** โ€” ๋ช‡ ๊ฐœ๊ฐ€ ์‹คํ–‰ ์ค‘์ด๊ณ , ๋ˆ„๊ฐ€ ๋ฃจํ”„๋ฅผ ์ ์œ ํ•˜๊ณ  ์žˆ๋‚˜.\n *\n * ์‹œ๋ฎฌ ํŠธ์œˆ๋„ ํฌํ•จํ•œ๋‹ค(`metrics()` ๋Š” ๋ผ์ด๋ธŒ ์ง€ํ‘œ๊ฐ€ ์žˆ์–ด์•ผ ๋‹ตํ•ด์„œ ์‹œ๋ฎฌ์ด ํ†ต์งธ๋กœ ์•ˆ ๋ณด์˜€๋‹ค).\n */\n static fleet(domainId?: string): any {\n const keys = Object.keys(this.instances).filter(key => !domainId || isOfDomain(key, domainId))\n const rows = keys.map(key => {\n const at = parseRuntimeKey(key)\n const inst = this.instances[key]\n /* ๋„๋ฉ”์ธ์„ ํ•จ๊ป˜ ๋„˜๊ธด๋‹ค โ€” ์šด์˜์ž๊ฐ€ ๋จผ์ € ๋ฌป๋Š” ๊ฒƒ์€ \"์–ด๋А ํ…Œ๋„ŒํŠธ๊ฐ€ ๋ฃจํ”„๋ฅผ ๋จน๋‚˜\" ๋‹ค.\n ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์ด๋ฆ„(subdomain)์€ ๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค์—๋งŒ ๋ถ™์–ด ์žˆ์œผ๋ฏ€๋กœ, ์—†์œผ๋ฉด ๋ฆฌ์กธ๋ฒ„๊ฐ€ ์ฑ„์šด๋‹ค. */\n return {\n instanceId: at.instanceId,\n mode: inst.mode ?? 'sim',\n domainId: at.domainId,\n domainLabel: inst.domain?.subdomain,\n meter: inst.load\n }\n })\n\n return {\n tickMs: this.TICK_MS,\n broadcastCoalesceMs: this.BROADCAST_COALESCE_MS,\n ...fleetLoad(rows, this.TICK_MS),\n /* ์ค„๋งˆ๋‹ค ์ƒ์„ธ โ€” ํ™”๋ฉด์ด ํŽผ์ณ ๋ณผ ์ˆ˜ ์žˆ๊ฒŒ. ์ตœ๊ทผ ๋ถ€ํ•˜ ์ˆœ์„œ๋Š” fleetLoad ๊ฐ€ ์ •ํ•œ๋‹ค. */\n details: keys.map(key => { const at = parseRuntimeKey(key); return this.load(at.domainId, at.instanceId) }).filter(Boolean)\n }\n }\n\n /** ์ด ํŠธ์œˆ์—์„œ fork ๊ฐ€ ๋งŒ๋“ค์–ด์กŒ๋‹ค โ€” ์˜ˆ์ธก ํ•œ ๋ฒˆ์ด ์ˆ˜์‹ญ ๊ฐœ๋ฅผ ๋งŒ๋“ ๋‹ค. */\n static countForks(domainId: string, id: string, count: number): void {\n const inst = this.instances[runtimeKey(domainId, id)]\n if (inst) recordFork(inst.load ?? (inst.load = newLoadMeter()), count)\n }\n\n /** ์—”์ง„ ๋ฐ–(์˜ˆ์ธก ์งˆ์˜ ๋“ฑ)์—์„œ ๋ฌด๊ฑฐ์šด ์ž‘์—…์„ ์žฐ๋‹ค โ€” ๊ฐ™์€ ๊ณ„๊ธฐํŒ์— ๋ชจ์ธ๋‹ค. */\n static recordLoad(domainId: string, id: string, phase: LoadPhase, tookMs: number): void {\n const inst = this.instances[runtimeKey(domainId, id)]\n if (inst) recordPhase(inst.load ?? (inst.load = newLoadMeter()), phase, tookMs)\n }\n\n /** ์ „์ฒด ๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค ๊ณ„์ธก(๋ชจ๋‹ˆํ„ฐ ๋Œ€์‹œ๋ณด๋“œ์šฉ). */\n static async allMetrics(domainId?: string): Promise<any[]> {\n /* ๋„๋ฉ”์ธ ์—†์ด ๋ถ€๋ฅด๋ฉด ์ „ ํ…Œ๋„ŒํŠธ๋ฅผ ํ›‘๋Š”๋‹ค(๋‚ด๋ถ€ ๋ชจ๋‹ˆํ„ฐ์šฉ) โ€” ํ‚ค์—์„œ ๋„๋ฉ”์ธ์„ ๋˜๋Œ๋ ค ๊ฐ์ž์—๊ฒŒ ๋ฌป๋Š”๋‹ค. */\n const rows = Object.keys(this.instances)\n .filter(key => !domainId || isOfDomain(key, domainId))\n .map(key => {\n const at = parseRuntimeKey(key)\n return this.metrics(at.domainId, at.instanceId)\n })\n .filter(Boolean)\n if (!rows.length || !domainId) return rows\n // ํ‘œ์‹œ ์ด๋ฆ„ ๋ถ€์—ฌ โ€” ์‹คํ–‰์ค‘ ์นด๋“œ๊ฐ€ id ๋งŒ ๋ณด์ด์ง€ ์•Š๋„๋ก ๊ณต๊ฐ„๋ช…์„ ์‹ค์–ด์ค€๋‹ค(๊ณต๊ฐ„ ์นด๋“œ์™€ ๋™์ผ). name=๊ณต๊ฐ„๋ช… ํด๋ฐฑ spaceId ํด๋ฐฑ instanceId.\n const insts = await getRepository(TwinInstance).find({ where: { domain: { id: domainId } } })\n const spaceOf = new Map(insts.map(i => [i.instanceId, i.spaceId]))\n /* ์šฉ๋„ ์„ ์–ธ๋„ ํ•จ๊ป˜ ์‹ค์–ด ๋ณด๋‚ธ๋‹ค โ€” ํ™”๋ฉด์ด ๊ณต๊ฐ„ ์ด๋ฆ„์œผ๋กœ ๋ฒค์น˜๋ฅผ **์ถ”์ธกํ•˜์ง€ ์•Š๊ฒŒ** ํ•œ๋‹ค.\n ์ถ”์ธกํ•˜๋ฉด `loadtest-` ๋กœ ์ด๋ฆ„ ์ง€์€ ์šด์˜ ํŠธ์œˆ์— ๋ฒค์น˜ ๋”ฑ์ง€๊ฐ€ ๋ถ™๋Š”๋‹ค. */\n const purposeOf = new Map(insts.map(i => [i.instanceId, i.purpose]))\n const nameOf = new Map((await getRepository(TwinSpace).find({ where: { domain: { id: domainId } } })).map(s => [s.spaceId, s.name]))\n for (const r of rows) {\n const sp = spaceOf.get(r.instanceId)\n r.spaceId = sp\n r.purpose = purposeOf.get(r.instanceId)\n r.name = (sp && nameOf.get(sp)) || sp || r.instanceId\n }\n return rows\n }\n\n /*\n * `buildForecastKernel` ์€ **์‚ฌ๋ผ์กŒ๋‹ค**(ํ†ตํ•ฉ P3, 2026-08-01).\n *\n * ๋ผ์ด๋ธŒ๊ฐ€ `StateProjector` ์˜€์„ ๋•Œ๋Š” ์ปค๋„์ด ์—†์–ด์„œ, ์˜ˆ์ธกํ•˜๋ ค๋ฉด ๊ด€์ธก ์Šค๋ƒ…์ƒท + ์ €๋„์˜ ์˜ค๋” ์›๊ฐ’์œผ๋กœ\n * **์ผํšŒ์šฉ ์ปค๋„์„ ์„ธ์›Œ์•ผ** ํ–ˆ๋‹ค. ์ด์ œ ๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ณง ์ปค๋„์ด๋ฏ€๋กœ(`startLive`) ๊ทธ ์ž๋ฆฌ์—์„œ\n * `fork` ํ•˜๋ฉด ๋œ๋‹ค โ€” `TwinEngine.kernel(id)` ๊ฐ€ simยทlive ๋‘˜ ๋‹ค ๋Œ๋ ค์ค€๋‹ค.\n *\n * (์˜ค๋” ์›๊ฐ’์„ ์ €๋„์—์„œ ๋˜์ฐพ๋˜ ์ด์œ ๋„ ์‚ฌ๋ผ์กŒ๋‹ค โ€” ์ƒํƒœ๊ฐ€ requestedยทfulfilledยทlines ๋ฅผ ์ง€ํ‚จ๋‹ค.)\n */\n\n /**\n * ์˜ˆ์ธก์šฉ ์ปค๋„์„ **์ž„์˜ ์‹œ๊ฐ T ๊ธฐ์ค€**์œผ๋กœ ์žฌ๊ตฌ์„ฑ โ€” ๊ณผ๊ฑฐ-vantage ์˜ˆ์ธก(๋ฐฑํ…Œ์ŠคํŠธ)ยท\"๊ทธ๋•Œ ์„œ์„œ ๋ณธ ๋ฏธ๋ž˜\".\n * recover(untilTime)๋กœ T ์‹œ์  ์ƒํƒœ๋ฅผ, T ์ดํ•˜ ์˜ค๋” ๊ด€์ธก์„ ๋ชจ์•„ hydrate โ†’ monteCarloForecast ๊ฐ€ T ์—์„œ ์•ž์œผ๋กœ ์‹คํ–‰ํ•œ๋‹ค.\n * sim/live ๋ฌด๊ด€(์ €๋„ ๊ธฐ๋ฐ˜ ์žฌ๊ตฌ์„ฑ). untilTime ์ƒ๋žต ์‹œ ์ตœ์‹ . ๋„๋ฉ”์ธ ์Šค์ฝ”ํ”„(regยทjournal ์กฐํšŒ๊ฐ€ domainId).\n */\n static async buildForecastKernelAt(domainId: string, instanceId: string, untilTime?: string): Promise<any | null> {\n const reg = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!reg?.model) return null\n const Kernel = kernelFor(reg.kind)\n const k = new Kernel(domainId, undefined, this.productionSpecOf(reg.model as TwinModelDef))\n k.loadTwinModel(reg.model as TwinModelDef)\n this.applyOperations(k, reg.model, instanceId) // ์˜ˆ์ธก๋„ ๊ฐ™์€ ๋ช…์„ธ๋กœ ๊ตด๋Ÿฌ์•ผ ํ•œ๋‹ค(ํ™”๋ฉด๊ณผ ๋‹ค๋ฅธ ์ˆซ์ž ๊ธˆ์ง€)\n await this.installEstimators(k, domainId, instanceId, reg.model) // ์˜ˆ์ธก์€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค โ€” ์‹ค์ธก์„ ๋†“์น˜๋ฉด ์˜ˆ์ธก์ด ์ƒ์ˆ˜๋กœ ๊ณ„์‚ฐ๋œ๋‹ค\n const state = await this.recover(domainId, instanceId, undefined, untilTime).catch(() => null)\n if (!state) return null\n const cutoff = untilTime != null ? Date.parse(untilTime) : Infinity\n const rows = await getRepository(TwinEvent).find({ where: { domain: { id: domainId }, instanceId, eventType: OP_EVENT.order }, order: { revision: 'ASC' } })\n const latest = new Map<string, any>()\n for (const r of rows) {\n if (Number.isFinite(cutoff) && (r.eventTime?.getTime() ?? NaN) > cutoff) continue\n const d = (r.payload as any)?.data\n if (d?.orderId) latest.set(d.orderId, d)\n }\n k.hydrateObserved(state, [...latest.values()])\n return k\n }\n\n /** ํ˜„์žฌ ์ „์ฒด ์Šค๋ƒ…์ƒท โ€” ๋ผ์ด๋ธŒ ์šฐ์„ , ์—†์œผ๋ฉด ์ €๋„ ๋ณต๊ตฌ ์บ์‹œ. */\n static snapshot(domainId: string, id: string): any {\n const inst = this.instances[runtimeKey(domainId, id)]\n if (inst?.mode === 'live' && inst.projector) {\n /* live: **์ปค๋„์ด ์ฃผ๋ชฉ ์‹ ํ˜ธ๋ฅผ ์Šค์Šค๋กœ ๋‚ธ๋‹ค**(๊ด€์ธก ๋ชจ๋“œ) โ€” ํ˜ธ์ŠคํŠธ๊ฐ€ ๋ง๋ถ™์ด๋˜ withLiveAttentions ๋Š”\n * ํ•„์š” ์—†๋‹ค. OEE ๋งŒ ํ˜ธ์ŠคํŠธ๊ฐ€ ์ฑ„์šด๋‹ค: ์› ์‹œ์Šคํ…œ์ด ์‹œ๊ฐ„ ๋ˆ„์ ์„ ๋ณด๋‚ด ์ฃผ์ง€ ์•Š์•„ ์ƒํƒœ ์ „์ด๋ฅผ ์ ๋ถ„ํ•ด\n * ๋งŒ๋“œ๋Š” ๊ฐ’์ด๋ผ ์ปค๋„์ด ๋Œ€์‹ ํ•  ์ˆ˜ ์—†๋‹ค(์ ํ•ฉ์„ฑ ํ•˜๋„ค์Šค์˜ ์œ ์ผํ•œ ์˜ˆ์™ธ). */\n const st = inst.projector.snapshot()\n return inst.oee ? withLiveOee(st, inst.oee) : st\n }\n return inst?.runtime?.resync() ?? this.recovered[runtimeKey(domainId, id)]\n }\n}\n"]}
1
+ {"version":3,"file":"twin-engine.js","sourceRoot":"","sources":["../../server/engine/twin-engine.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAEH,qCAAuD;AACvD,iDAAqE;AACrE,6DAA6D;AAC7D,qCAAgE;AAChE,iEAA4D;AAI5D,uEAA+D;AAC/D,iFAAwE;AACxE,mDAAgF;AAChF,mEAAgE;AAChE,qDAA0E;AAC1E,6DAAmD;AACnD,gFAAwE;AACxE,yCAAyC;AACzC,8EAAsE;AACtE,mFAA2E;AAC3E,uEAA+D;AAC/D,kFAAsE;AACtE,qGAA4F;AAC5F,iFAAwE;AACxE,qEAA6D;AAC7D,kFAA6F;AAC7F,0EAAyE;AACzE,kFAAmL;AACnL,qFAA6E;AAC7E,+DAA6E;AAC7E,mEAAgE;AAChE,2DAAyD;AACzD,iEAAmE;AACnE,2DAA2E;AAE3E,iDAA+C;AAC/C,6CAAwC;AAExC,+FAA6F;AAC7F,mDAA4J;AAC5J,+CAAuC;AACvC,iGAA4F;AAC5F,2DAAwE;AACxE,6DAAkE;AAClE,6DAAyD;AACzD,+DAA6E;AAE7E,mEAAyD;AACzD,yDAY2B;AAC3B,sDAAmD;AAGnD,uFAAuF;AACvF,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,EAAE,UAAU,EAAE,oBAAoB,EAAE,cAAc,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,cAAc,EAAE,QAAQ,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAA;AAEjQ,MAAM,OAAO,GAAwB,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,CAAA;AAEvG;;;;;GAKG;AACH,MAAM,iBAAiB,GAAG,EAAE,CAAA;AAE5B;;;;;;;;;;;;;;;;GAgBG;AACH,SAAS,SAAS,CAAC,CAAU;IAC3B,IAAI,CAAC,IAAI,IAAI;QAAE,OAAO,IAAI,CAAA;IAC1B,IAAI,CAAC,YAAY,IAAI;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;IAE/E,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAC1B,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA;IACnB,yDAAyD;IACzD,MAAM,KAAK,GAAG,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAC/C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAA;IAC3D,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AACtC,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,SAAS,CAAC,IAAY;IAC7B,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvB,IAAI,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,IAAI,uBAAuB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IAC5G,OAAO,CAAC,CAAA;AACV,CAAC;AAED,mEAAmE;AACnE,IAAI,wBAAwB,GAAG,KAAK,CAAA;AAEpC;;;;;;;;;;;;;GAaG;AACH,SAAS,eAAe,CAAC,MAAW,EAAE,IAAY;IAChD,IAAI,OAAO,MAAM,EAAE,OAAO,KAAK,UAAU,EAAE,CAAC;QAC1C,MAAM,CAAC,OAAO,EAAE,CAAA;QAChB,OAAM;IACR,CAAC;IACD,IAAI,wBAAwB;QAAE,OAAM;IACpC,wBAAwB,GAAG,IAAI,CAAA;IAC/B,IAAA,iBAAQ,EACN,iBAAiB,IAAI,8EAA8E;QACjG,2GAA2G,CAC9G,CAAA;AACH,CAAC;AAoGD,MAAa,UAAU;IACrB;;;;;;OAMG;aACI,cAAS,GAAoC,EAAE,CAAA;IACtD,+CAA+C;IAC/C,8DAA8D;aACvD,cAAS,GAAwB,EAAE,CAAA;aACnC,YAAO,GAAG,IAAI,CAAA;IAErB;;;;;;;;;;;;OAYG;IACH;;;;;;;;;OASG;IACH,8DAA8D;aACvD,kBAAa,GAAG,EAAE,CAAA;aACV,cAAS,GAAG,CAAC,CAAA;IAC5B;;;;OAIG;IACK,MAAM,CAAC,cAAc,CAAC,EAAc,EAAE,IAAsB;QAClE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC,CAAA;QACzD,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAA;QAC1E,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,MAAM,QAAQ,GAAG,WAAW,CAAC,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;YAC9C,IAAI,OAAO,QAAQ,EAAE,KAAK,KAAK,UAAU;gBAAE,QAAQ,CAAC,KAAK,EAAE,CAAA;YAC3D,IAAI,CAAC,QAAQ,CAAC,CAAA,CAAC,sBAAsB;YACrC,EAAE,EAAE,CAAA;QACN,CAAC,EAAE,MAAM,CAAC,CAAA;QACV,IAAI,OAAO,KAAK,EAAE,KAAK,KAAK,UAAU;YAAE,KAAK,CAAC,KAAK,EAAE,CAAA;QACrD,OAAO,KAAK,CAAA;IACd,CAAC;IAED,qDAAqD;aAC9C,kBAAa,GAAG,CAAC,CAAA;IACxB,mDAAmD;aAC5C,kBAAa,GAAG,CAAC,CAAA;aACT,iBAAY,GAAG,IAAI,GAAG,EAAkB,CAAA;IACvD;;;OAGG;aACY,cAAS,GAAG,IAAI,GAAG,EAAoB,CAAA;IAEtD;;0EAEsE;aAC/D,sBAAiB,GAAG,eAAe,CAAA;IAC1C;;;;;;;;;;OAUG;aACI,mBAAc,GAAG,iBAAiB,CAAA;aAClC,yBAAoB,GAAG,uBAAuB,CAAA;aAC9C,iBAAY,GAAG,IAAI,CAAA,GAAC,iCAAiC;aACrD,eAAU,GAAG,CAAC,CAAA,GAAC,kCAAkC;aACjD,mBAAc,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAA,GAAC,qCAAqC;aACpE,kBAAa,GAAG,KAAK,CAAA,GAAC,0CAA0C;IACvE;;;;;;;;;;;;;;;;;;;;;OAqBG;aACI,2BAAsB,GAAY,SAAS,CAAA;aAc3C,uBAAkB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA,GAAC,4BAA4B;IAIvE,8EAA8E;IAC9E,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,QAAgB,EAAE,UAAkB;QAC/D,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAA;QAC7D,IAAI,CAAC,IAAI;YAAE,OAAM;QACjB;;;;WAIG;QACH,MAAM,KAAK,GAAG,IAAA,2BAAW,EAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAA;QAC9D,IAAI,CAAC,KAAK;YAAE,OAAM;QAClB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAA;QACrD,wDAAwD;QACxD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,CAAQ,CAAC,CAAA;QAC5G,MAAM,4BAAY,CAAC,UAAU,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,IAAI,CAAC,cAAc,CAAC,CAAA;IACzI,CAAC;IAED;;;;;OAKG;aACqB,cAAS,GAAG,+DAA+D,CAAA;IAEnG,oFAAoF;IACpF,MAAM,CAAC,KAAK,CAAC,YAAY,CACvB,QAAgB,EAChB,UAAkB;QAElB,MAAM,KAAK,GAAG,MAAM,4BAAY,CAAC,YAAY,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAA;QAC/F,OAAQ,KAAa,EAAE,KAAK,IAAI,IAAI,CAAA;IACtC,CAAC;IAED;;;;;;;;;OASG;IACH,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAC7B,QAAgB,EAChB,UAAkB,EAClB,KAAgI;QAEhI,IAAI,CAAC,KAAK,EAAE,KAAK;YAAE,OAAM;QACzB,MAAM,4BAAY;aACf,UAAU,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,cAAc,CAAC;aACxF,KAAK,CAAC,CAAC,GAAQ,EAAE,EAAE,CAAC,IAAA,kBAAS,EAAC,qCAAqC,UAAU,GAAG,EAAE,GAAG,EAAE,OAAO,IAAI,GAAG,CAAC,CAAC,CAAA;IAC5G,CAAC;IAGD,8CAA8C;IACtC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,QAAgB,EAAE,UAAkB;QAClE,MAAM,KAAK,GAAG,MAAM,4BAAY,CAAC,YAAY,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;QACpH,MAAM,IAAI,GAAI,KAAa,EAAE,KAAK,EAAE,SAAS,CAAA;QAC7C,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAS,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IACrH,CAAC;IAED;;;;;;OAMG;IACK,MAAM,CAAC,KAAK,CAAC,YAAY,CAC/B,QAAgB,EAChB,UAAkB,EAClB,MAA8C;QAE9C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QACxD,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAA;QAC7B,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;YAC3C,IAAI,MAAM,CAAC,QAAQ,IAAI,IAAI,IAAI,QAAQ,GAAG,MAAM,CAAC,QAAQ;gBAAE,SAAQ;YACnE,MAAM,KAAK,GAAG,MAAM,4BAAY,CAAC,YAAY,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;YACxH,MAAM,KAAK,GAAI,KAAa,EAAE,KAAK,CAAA;YACnC,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO;gBAAE,SAAQ;YACnC,IAAI,MAAM,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;gBAC1B,MAAM,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;gBACrE,qDAAqD;gBACrD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM;oBAAE,SAAQ;YACxD,CAAC;YACD,OAAO,KAAK,CAAA;QACd,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,mDAAmD;IAC3C,MAAM,CAAC,KAAK,CAAC,cAAc,CACjC,QAAgB,EAChB,UAAkB;IAClB;;;;;OAKG;IACH,KAAuI;QAEvI,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QACxD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAA;QAC9D,IAAI,KAAK,CAAC,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAC,YAAY;YAAE,OAAM,CAAC,gBAAgB;QACxE,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAC9D,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;QACnD,MAAM,4BAAY,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,cAAc,CAAC,CAAA;QAClI,MAAM,4BAAY,CAAC,UAAU,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,cAAc,CAAC,CAAA;QAC5H;;;;;WAKG;QACH,IAAI,OAAO,CAAC,MAAM;YAAE,OAAO,CAAC,IAAI,CAAC,kBAAkB,UAAU,wBAAwB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAA;IAC/J,CAAC;IAED,0DAA0D;IAClD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,QAAgB,EAAE,UAAkB;QAC7D,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACtC,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,CAAC;YAClH,IAAA,qBAAa,EAAC,iCAAa,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC;SAClH,CAAC,CAAA;QACF,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAA;IAC5E,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,QAAgB;QACxC,sEAAsE;QACtE,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAChH,MAAM,IAAI,GAAG,SAAS,IAAI,IAAI,CAAC,sBAAsB,CAAA;QACrD,IAAI,CAAC,IAAI,IAAI,IAAI,IAAI,CAAC;YAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAA;QAExE,+DAA+D;QAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,GAAG,KAAK,CAAA;QAC3C,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;QAC7C,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;YAC3B,IAAA,iBAAQ,EACN,mCAAmC,IAAI,cAAc,OAAO,aAAa,aAAa,SAAS;gBAC7F,gDAAgD,CACnD,CAAA;QACH,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,aAAa,GAAG,KAAK,GAAG,IAAI,CAAC,CAAA;QAElE,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAA;QAC5F,IAAI,OAAO,GAAG,CAAC,CAAA;QACf,IAAI,SAAS,GAAG,CAAC,CAAA;QACjB,MAAM,OAAO,GAAa,EAAE,CAAA;QAE5B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;YAC9E,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,QAAQ,IAAI,CAAC,CAAC,CAAA;YACxC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,yCAAyC;gBACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAA;gBAC1B,SAAQ;YACV,CAAC;YACD,MAAM,GAAG,GAAG,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC;iBACvC,kBAAkB,EAAE;iBACpB,MAAM,EAAE;iBACR,IAAI,CAAC,yBAAS,CAAC;iBACf,KAAK,CAAC,uBAAuB,EAAE,EAAE,QAAQ,EAAE,CAAC;iBAC5C,QAAQ,CAAC,2BAA2B,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC;iBACnE,QAAQ,CAAC,mBAAmB,EAAE,EAAE,IAAI,EAAE,CAAC;iBACvC,QAAQ,CAAC,wBAAwB,CAAC;iBAClC,QAAQ,CAAC,sBAAsB,EAAE,EAAE,MAAM,EAAE,CAAC;iBAC5C,OAAO,EAAE,CAAA;YACZ,MAAM,CAAC,GAAG,GAAG,CAAC,QAAQ,IAAI,CAAC,CAAA;YAC3B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACV,OAAO,IAAI,CAAC,CAAA;gBACZ,SAAS,EAAE,CAAA;gBACX,oDAAoD;gBACpD,IAAA,gBAAO,EACL,iCAAiC,CAAC,CAAC,UAAU,OAAO,CAAC,iBAAiB,IAAI,MAAM,MAAM,CAAC,WAAW,EAAE,QAAQ;oBAC1G,mBAAmB,CACtB,CAAA;YACH,CAAC;QACH,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,IAAA,gBAAO,EACL,uCAAuC,OAAO,CAAC,MAAM,oCAAoC;gBACvF,4BAA4B,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAChG,CAAA;QACH,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAA;IACxC,CAAC;IAED,6CAA6C;IAC7C,MAAM,CAAC,kBAAkB,CAAC,QAAgB;QACxC,IAAI,IAAI,CAAC,cAAc;YAAE,OAAM;QAC/B;;;WAGG;QACH,IAAI,CAAC,IAAI,CAAC,sBAAsB,IAAI,CAAC,IAAI,CAAC,eAAe;YAAE,OAAM;QACjE,IAAI,CAAC,cAAc,GAAG,WAAW,CAAC,GAAG,EAAE;YACrC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAA,kBAAS,EAAC,oCAAoC,EAAE,GAAG,EAAE,OAAO,IAAI,GAAG,CAAC,CAAC,CAAA;QAChH,CAAC,EAAE,IAAI,CAAC,kBAAkB,CAAC,CAAA;QAC3B,IAAI,OAAO,IAAI,CAAC,cAAc,EAAE,KAAK,KAAK,UAAU;YAAE,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAA;QACjF,IAAA,gBAAO,EACL,wCAAwC,IAAI,CAAC,sBAAsB,IAAI,UAAU,MAAM;YACrF,GAAG,IAAI,CAAC,kBAAkB,GAAG,KAAK,KAAK,CAC1C,CAAA;IACH,CAAC;IAED,kDAAkD;IAClD,MAAM,CAAC,mBAAmB;QACxB,IAAI,IAAI,CAAC,eAAe;YAAE,OAAM;QAChC,IAAI,CAAC,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE;YACtC,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;gBACzD,MAAM,EAAE,UAAU,EAAE,GAAG,IAAA,gCAAe,EAAC,GAAG,CAAC,CAAA;gBAC3C,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAC1D,IAAA,kBAAS,EAAC,2CAA2C,UAAU,GAAG,EAAE,GAAG,EAAE,OAAO,IAAI,GAAG,CAAC,CACzF,CAAA;YACH,CAAC;QACH,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,CAAA;QACtB,IAAI,OAAO,IAAI,CAAC,eAAe,EAAE,KAAK,KAAK,UAAU;YAAE,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAA;IACrF,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,SAAS;QACpB,8DAA8D;QAC9D,qBAAO,CAAC,KAAK,EAAE,CAAA;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAA;YACxC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC,CAAA;YAC9D,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,IAAI,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,GAAG,CAAC,UAAU;oBAAE,SAAQ;gBAC9C,4DAA4D;gBAC5D,yEAAyE;gBACzE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;gBACtF,IAAI,MAAM,EAAE,KAAK,EAAE,CAAC;oBAClB,8DAA8D;oBAC9D,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAA,2BAAW,EAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAA;oBAC1H;;;;;;;uBAOG;oBACH,IAAA,gBAAO,EAAC,yCAAyC,GAAG,CAAC,UAAU,gBAAgB,MAAM,CAAC,QAAQ,qBAAqB,CAAC,CAAA;oBACpH,SAAQ;gBACV,CAAC;gBACD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;gBAChF,IAAI,KAAK,EAAE,CAAC;oBACV,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAA;oBAC9F,IAAA,gBAAO,EAAC,4BAA4B,GAAG,CAAC,UAAU,6BAA6B,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAA;gBACnG,CAAC;YACH,CAAC;YACD;;;;;;;eAOG;YACH,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;gBACzB,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,CAAA;YACvE,CAAC;YACD,IAAI,CAAC,mBAAmB,EAAE,CAAA,CAAC,kCAAkC;YAC7D;;;;eAIG;YACH,KAAK,MAAM,QAAQ,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAa,CAAC,EAAE,CAAC;gBACtF,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAA;YACnC,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAA,kBAAS,EAAC,oCAAoC,EAAE,GAAG,CAAC,CAAA;QACtD,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;OAgBG;IACK,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,GAAiB;QAC9C,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,GAAG,CAAA;QACpC,IAAI,CAAC,QAAQ,IAAI,CAAC,UAAU;YAAE,OAAM;QACpC,IAAI,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;YAAE,OAAM,CAAC,mBAAmB;QAEhF;;;;WAIG;QACH,IAAI,GAAG,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;YAC5B,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,kEAAkE,CAAC,CAAA;YAC/F,OAAM;QACR,CAAC;QAED,IAAI,CAAC;YACH;;;;;;eAMG;YACH,MAAM,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;YAClD,IAAI,GAAG,CAAC,aAAa,KAAK,QAAQ,EAAE,CAAC;gBACnC;kFACkE;gBAClE,IAAA,gBAAO,EAAC,iCAAiC,UAAU,iDAAiD,CAAC,CAAA;YACvG,CAAC;iBAAM,CAAC;gBACN,IAAA,gBAAO,EAAC,yBAAyB,GAAG,CAAC,aAAa,KAAK,UAAU,IAAI,CAAC,CAAA;YACxE,CAAC;QACH,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,IAAI,eAAe,CAAC,CAAA;QAC9D,CAAC;IACH,CAAC;IAED,oDAAoD;IAC5C,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,GAAiB,EAAE,GAAW;QAC7D,IAAA,iBAAQ,EAAC,kBAAkB,GAAG,CAAC,UAAU,kBAAkB,GAAG,gCAAgC,CAAC,CAAA;QAC/F,IAAI,CAAC;YACH,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAA;QACjF,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,IAAA,kBAAS,EAAC,iCAAiC,GAAG,CAAC,UAAU,yCAAyC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAA;QACjH,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACK,MAAM,CAAC,SAAS,CAAC,QAAgB,EAAE,EAAU,EAAE,MAAkB,EAAE,OAAgB;QACzF,MAAM,OAAO,GAAI,MAAc,CAAC,eAAe,CAAA;QAC/C,MAAM,IAAI,GAAG,IAAA,6BAAa,EAAC,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,OAAO,KAAK,UAAU,CAAC,CAAA;QAEnH,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC3B,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;gBAC5B,IAAA,gBAAO,EAAC,kBAAkB,EAAE,qFAAqF,CAAC,CAAA;YACpH,CAAC;iBAAM,IAAI,IAAI,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;gBACzC,IAAA,iBAAQ,EACN,6BAA6B,EAAE,iHAAiH,CACjJ,CAAA;YACH,CAAC;YACD,OAAM;QACR,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;QAC/B,MAAM,QAAQ,GAAG;YACf,GAAG,IAAI,CAAC,SAAS,UAAU;YAC3B,GAAG,IAAI,CAAC,cAAc,YAAY;YAClC,GAAG,IAAI,CAAC,UAAU,gBAAgB;YAClC,GAAG,IAAI,CAAC,SAAS,UAAU;YAC3B,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9D,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3D,4DAA4D;YAC5D,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,4BAA4B,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5E,gDAAgD;YAChD,GAAG,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,mBAAmB,0BAA0B,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SAC7F,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACZ,IAAA,gBAAO,EAAC,+BAA+B,EAAE,gBAAgB,QAAQ,GAAG,CAAC,CAAA;QACrE,0DAA0D;QAC1D,IAAI,IAAI,CAAC,mBAAmB,GAAG,CAAC,EAAE,CAAC;YACjC,IAAA,iBAAQ,EACN,kBAAkB,EAAE,MAAM,IAAI,CAAC,mBAAmB,8DAA8D;gBAC9G,gHAAgH,CACnH,CAAA;QACH,CAAC;IACH,CAAC;IAED,oFAAoF;IACpF;;;;;;;;OAQG;IACK,MAAM,CAAC,eAAe,CAAC,MAAW,EAAE,KAAU,EAAE,EAAU;QAChE;;;;;;WAMG;QACH,MAAM,QAAQ,GAAG,KAAK,EAAE,cAAoD,CAAA;QAC5E,IAAI,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC;YAC7C,IAAI,OAAO,MAAM,EAAE,gBAAgB,KAAK,UAAU,EAAE,CAAC;gBACnD,IAAA,iBAAQ,EACN,kBAAkB,EAAE,6BAA6B,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,4DAA4D;oBACvI,6JAA6J,CAChK,CAAA;YACH,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC;oBACH,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAA;gBACnC,CAAC;gBAAC,OAAO,GAAQ,EAAE,CAAC;oBAClB,oDAAoD;oBACpD,IAAA,iBAAQ,EAAC,kBAAkB,EAAE,2DAA2D,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC,CAAA;gBAChH,CAAC;YACH,CAAC;QACH,CAAC;QACD,4DAA4D;QAC5D,MAAM,MAAM,GAAG,KAAK,EAAE,WAAiE,CAAA;QACvF,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;YACzC,IAAI,OAAO,MAAM,EAAE,iBAAiB,KAAK,UAAU,EAAE,CAAC;gBACpD,IAAA,iBAAQ,EACN,kBAAkB,EAAE,sDAAsD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,mDAAmD;oBACrJ,4GAA4G,CAC/G,CAAA;YACH,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC;oBACH,MAAM,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAA;gBAClC,CAAC;gBAAC,OAAO,GAAQ,EAAE,CAAC;oBAClB,IAAA,iBAAQ,EAAC,kBAAkB,EAAE,4DAA4D,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC,CAAA;gBACjH,CAAC;YACH,CAAC;QACH,CAAC;QACD,MAAM,GAAG,GAAG,KAAK,EAAE,UAAU,CAAA;QAC7B,IAAI,CAAC,GAAG,EAAE,MAAM;YAAE,OAAM;QACxB,IAAI,OAAO,MAAM,EAAE,cAAc,KAAK,UAAU,EAAE,CAAC;YACjD,IAAA,iBAAQ,EAAC,kBAAkB,EAAE,qBAAqB,GAAG,CAAC,MAAM,2JAA2J,CAAC,CAAA;YACxN,OAAM;QACR,CAAC;QACD,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,CAAA;IAC5B,CAAC;IAED;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,MAAW,EAAE,QAAgB,EAAE,UAAkB,EAAE,KAAU;QAC1F,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;YAAE,OAAM;QACjD,MAAM,MAAM,GAAG,IAAA,0CAAoB,EAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QAC9G,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QACnE,MAAM,OAAO,GAAG,IAAA,qCAAe,EAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAA;QACxE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,uDAAuD;YACvD,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM;gBAAE,IAAA,iBAAQ,EAAC,kBAAkB,UAAU,wCAAwC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YACpI,OAAM;QACR,CAAC;QACD,MAAM,CAAC,iBAAiB,GAAG,OAAO,CAAA;QAClC;;;;;WAKG;QACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QAC7D,IAAI,MAAM,EAAE,SAAS,EAAE,CAAC;YACtB,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;gBACzC,IAAA,iBAAQ,EACN,kBAAkB,UAAU,wBAAwB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,sDAAsD;oBAC1I,kHAAkH,CACrH,CAAA;YACH,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,cAAc,GAAG,MAAM,CAAC,SAAS,CAAA;gBACxC,IAAA,gBAAO,EACL,kBAAkB,UAAU,iCAAiC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC;qBACxF,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;qBAC3G,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,oBAAoB,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAClI,CAAA;YACH,CAAC;QACH,CAAC;aAAM,IAAI,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;YAClC,+DAA+D;YAC/D,IAAA,gBAAO,EACL,kBAAkB,UAAU,4CAA4C,MAAM,CAAC,UAAU,KAAK,MAAM,CAAC,OAAO;iBACzG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;iBAClC,IAAI,CAAC,IAAI,CAAC,EAAE,CAChB,CAAA;QACH,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,IAAI,EAAE,CAAC,CAAA;QACpD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,IAAI,EAAE,CAAC,CAAA;QACnD,IAAA,gBAAO,EACL,kBAAkB,UAAU,qDAAqD,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE;YAC5H,2BAA2B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG;YACvE,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,mCAAmC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,yBAAyB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CACnK,CAAA;IACH,CAAC;IAED;;;;;;OAMG;aACY,kBAAa,GAAG,IAAI,GAAG,EAQnC,CAAA;aACqB,oBAAe,GAAG,MAAM,CAAA;IAChD;;;;;;;;;;;;OAYG;aACqB,iBAAY,GAAG,KAAK,CAAA;IAE5C,oEAAoE;IAC5D,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,QAAgB,EAAE,UAAkB;QACrE,MAAM,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QAClD,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,EAAE,MAAM,CAAA;IACzE,CAAC;IAEO,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,QAAgB,EAAE,UAAkB;QACzE,8DAA8D;QAC9D,MAAM,GAAG,GAAG,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACvC,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,eAAe;YAAE,OAAO,GAAG,CAAC,KAAK,CAAA;QACvE,IAAI,KAA4D,CAAA;QAChE,IAAI,MAA0D,CAAA;QAC9D,IAAI,CAAC;YACH,wDAAwD;YACxD,MAAM,GAAG,GAAQ,MAAM,IAAA,6BAAc,EAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAA;YAC5G,KAAK,GAAG,IAAA,8CAAsB,EAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAA;YACtD,6CAA6C;YAC7C,MAAM,GAAG,IAAA,uCAAmB,EAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAA;QACtD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAA,iBAAQ,EAAC,kBAAkB,UAAU,kFAAkF,EAAG,GAAW,EAAE,OAAO,CAAC,CAAA;QACjJ,CAAC;QACD,kEAAkE;QAClE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC9B,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;QAC9D,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;YAChD,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAA;YAC/C,IAAI,CAAC,MAAM,CAAC,IAAI;gBAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC3D,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IAED;;;;;;;;;;;;;OAaG;IACK,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,QAAgB,EAAE,UAAkB,EAAE,IAAqB;QAC9F,IAAI,MAAW,CAAA;QACf,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,IAAA,qBAAa,EAAC,iCAAa,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;YACnH,MAAM,GAAG,GAAG,EAAE,gBAAgB,CAAA;QAChC,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,IAAA,iBAAQ,EAAC,kBAAkB,UAAU,6CAA6C,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC,CAAA;YACxG,OAAM;QACR,CAAC;QACD,MAAM,IAAI,GAAG,IAAA,mCAAY,EAAC,MAAM,EAAE,EAAE,iBAAiB,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,gBAAuB,CAAC,CAAA;QAC5H,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC3B,+DAA+D;YAC/D,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC3B,IAAA,iBAAQ,EACN,kBAAkB,UAAU,+DAA+D,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI;oBAChJ,CAAC,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,yEAAyE,CAAC,CAAC,CAAC,EAAE,CAAC,CAChH,CAAA;YACH,CAAC;YACD,OAAM;QACR,CAAC;QACD,IAAI,CAAC;YACH,qDAAqD;YACrD,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;YAC/B,IAAI,CAAC,OAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAC1C,IAAI,CAAC,OAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAA;YAC9B,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAA;YACxC,IAAA,2BAAW,EAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAA,4BAAY,GAAE,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,CAAA;YAC1E,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YACvF,IAAA,gBAAO,EACL,kBAAkB,UAAU,0CAA0C,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,eAAe,GAAG,CACrJ,CAAA;QACH,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,IAAA,iBAAQ,EAAC,kBAAkB,UAAU,mDAAmD,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC,CAAA;QAChH,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,QAAgB,EAAE,UAAkB,EAAE,QAAa;QAC9E,MAAM,IAAI,GAAG,IAAA,qBAAa,EAAC,iCAAa,CAAC,CAAA;QACzC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;QAC3F,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,IAAA,iBAAQ,EAAC,kBAAkB,UAAU,iEAAiE,CAAC,CAAA;YACvG,OAAO,KAAK,CAAA;QACd,CAAC;QACD,GAAG,CAAC,gBAAgB,GAAG,IAAA,mCAAY,EAAC,GAAG,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAA;QACnE,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACpB,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;;;;;;;;;OAUG;IACH,MAAM,CAAC,KAAK,CAAC,sBAAsB,CAAC,QAAgB,EAAE,UAAkB;QACtE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QACnE,OAAO,MAAM,CAAC,IAAI,CAAE,QAAgB,EAAE,OAAO,IAAI,EAAE,CAAC,CAAA;IACtD,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,QAAgB,EAAE,UAAkB;QAC1D,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;YAC1G,MAAM,KAAK,GAAQ,GAAG,EAAE,KAAK,CAAA;YAC7B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;YACnE,MAAM,MAAM,GAAG,IAAA,0CAAoB,EAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;YAC9G,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,CAAA;QAClG,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAA;QAClB,CAAC;IACH,CAAC;IAED;;;;;;;;;OASG;IACH,MAAM,CAAC,KAAK,CAAC,QAAQ,CACnB,QAAgB,EAChB,MAAiD,EACjD,WAAmB,EACnB,iBAAyB;QAEzB;4CACoC;QACpC,MAAM,KAAK,GAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAA;QAC/C,IAAI,MAAM,CAAC,UAAU;YAAE,KAAK,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAA;;YACtD,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAA;QACnC,MAAM,UAAU,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;QAEpE,OAAO,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;YAC1B,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,CAAA;YAC/D,MAAM,MAAM,GAAQ,EAAE,EAAE,MAAM,CAAA,CAAC,+BAA+B;YAC9D,IAAI,OAAO,MAAM,EAAE,QAAQ,KAAK,UAAU;gBAAE,OAAO,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,aAAsB,EAAE,CAAA;YAEjI,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,iBAAiB,EAAE,CAAC,CAAA;YACpE;yDAC6C;YAC7C,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM;gBAAE,OAAO,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,eAAwB,EAAE,CAAA;YAC1H,OAAO,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAA;QACjE,CAAC,CAAC,CAAA;IACJ,CAAC;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAC/B,QAAgB,EAChB,MAAiD,EACjD,WAAmB,EACnB,iBAAyB,EACzB,MAA4C;QAE5C,MAAM,KAAK,GAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAA;QAC/C,IAAI,MAAM,CAAC,UAAU;YAAE,KAAK,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAA;;YACtD,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAA;QACnC,MAAM,UAAU,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;QAEpE,OAAO,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;YAC1B,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,CAAA;YAC/D,MAAM,MAAM,GAAQ,EAAE,EAAE,MAAM,CAAA;YAC9B,IAAI,OAAO,MAAM,EAAE,oBAAoB,KAAK,UAAU,EAAE,CAAC;gBACvD,OAAO,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,aAAsB,EAAE,CAAA;YACvF,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,CAAC,oBAAoB,CAAC,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,EAAE,CAAC,CAAA;YACtF,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM;gBAAE,OAAO,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,eAAwB,EAAE,CAAA;YAC1H,OAAO,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,CAAA;QAC/D,CAAC,CAAC,CAAA;IACJ,CAAC;IAED;;;;OAIG;IACK,MAAM,CAAC,kBAAkB,CAAC,QAAgB,EAAE,EAAU,EAAE,MAAW;QACzE,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,CAAA;QAC9D,IAAI,CAAC,MAAM;YAAE,OAAM;QACnB,MAAM,IAAI,GAAG,IAAA,kCAAkB,EAAC,MAAM,CAAC,CAAA;QACvC,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,mBAAmB,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAM;QACzE,IAAI,OAAO,MAAM,CAAC,iBAAiB,KAAK,UAAU,EAAE,CAAC;YACnD,IAAA,iBAAQ,EACN,6BAA6B,EAAE,6EAA6E;gBAC1G,mEAAmE,CACtE,CAAA;YACD,OAAM;QACR,CAAC;QACD,IAAI,CAAC;YACH,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACrC,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,8CAA8C;YAC9C,IAAA,iBAAQ,EAAC,6CAA6C,EAAE,4BAA4B,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC,CAAA;YAC1G,OAAM;QACR,CAAC;QACD,MAAM,OAAO,GAAG;YACd,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,8DAA8D,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACxF,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,4BAA4B,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5E,GAAG,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,mBAAmB,0BAA0B,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SAC7F,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACZ,IAAA,gBAAO,EAAC,yBAAyB,EAAE,kBAAkB,OAAO,2CAA2C,CAAC,CAAA;IAC1G,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,EAAU,EAAE,QAAgB,EAAE,IAAY,EAAE,KAAmB,EAAE,aAA6B,EAAE,OAAgB,EAAE,UAAmB;QAChJ,MAAM,GAAG,GAAG,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;QACpC,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;QAEnD,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;QAC9B,MAAM,MAAM,GAAe,IAAI,MAAM,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAA;QACxF,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA,CAAC,0BAA0B;QACtD,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAA,CAAC,6BAA6B;QACrE,8DAA8D;QAC9D,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAA,iBAAQ,EAAC,wCAAwC,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,CAAA;QAClI;;;;WAIG;QACH,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;QAC/B,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;QAC7C,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAA;QACxC,IAAI,MAAM,IAAI,IAAI;YAAE,IAAA,gBAAO,EAAC,kBAAkB,EAAE,sBAAsB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC9F;;;;;WAKG;QACH,IAAI,UAAU,IAAI,OAAQ,MAAc,CAAC,cAAc,KAAK,UAAU;YAAG,MAAc,CAAC,cAAc,CAAC,UAAU,CAAC,CAAA;QAClH;;;;;;;;WAQG;QACH,MAAM,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;QACnC,MAAM,OAAO,GAAoB,IAAI,WAAW,CAAC,MAAM,CAAC,CAAA;QAExD,8EAA8E;QAC9E;;;;;;;WAOG;QACH,MAAM,IAAI,GAAoB;YAC5B,EAAE;YACF,QAAQ;YACR,IAAI,EAAE,KAAK;YACX,OAAO;YACP,MAAM;YACN,4DAA4D;YAC5D,aAAa,EAAE,IAAA,qCAAiB,EAAC,aAAa,EAAE,UAAU,EAAE,IAAI,CAAC;YACjE,OAAO,EAAG,KAAa,EAAE,OAAO;YAChC;;;;;;;;;eASG;YACH,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE;YAC1B,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC;SAChB,CAAA;QACD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,CAAA;QAC1B,+DAA+D;QAC/D,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC1B,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA,CAAC,mCAAmC;QAC9D,4DAA4D;QAC5D,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAA,iBAAQ,EAAC,kBAAkB,EAAE,gCAAgC,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC,CAAA;QAE1I,oEAAoE;QACpE,IAAA,qBAAa,EAAC,cAAM,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QAEvG,+FAA+F;QAC/F,MAAM,GAAG,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,GAAwB,EAAE,EAAE;YACzD,IAAI,CAAC,cAAc,CACjB,YAAY,EACZ,EAAE,SAAS,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAG,GAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAChG,cAAc,EAAE,EAAE,CACnB,CAAA;YACD,kFAAkF;YAClF,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBACzB;;;;;;;;;;;;;;;mBAeG;gBACH,CAAC;gBAAA,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAG,GAAW,CAAC,QAAQ,EAAE,CAAC,CAAA;gBAChH;;;;;;;;;;;mBAWG;gBACH,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;gBACjB,4CAA4C;gBAC5C,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAA;gBACtC,IAAI,CAAC,wBAAwB,EAAE,CAAA;YACjC,CAAC;QACH,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,KAAK,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,CAAA;QAEpC,mDAAmD;QACnD,IAAA,2BAAW,EAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAA,4BAAY,GAAE,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,CAAA;QAE3E,qFAAqF;QACrF,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAA,kBAAS,EAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC,CAAA;QAE1H,2FAA2F;QAC3F,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,cAAc,CAC9B,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,EAAE,EAAE,OAAO,CAAC,EAC7C,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CACtB,CAAA;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;;;;;;;;;;OAWG;IACH;;;;;;;;;OASG;IACH;;;;;;;;;OASG;IACK,MAAM,CAAC,gBAAgB,CAAC,KAA+B;QAC7D,MAAM,MAAM,GAAI,KAAa,EAAE,OAAO,CAAA;QACtC,IAAI,MAAM,IAAI,CAAE,KAAa,EAAE,cAAc,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CACb,qFAAqF;gBACnF,gGAAgG,CACnG,CAAA;QACH,CAAC;QACD,OAAQ,KAAa,EAAE,cAAc,CAAA;IACvC,CAAC;IAED;;;;;;;;;;OAUG;IACH,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,KAAmB,EAAE,QAAgB,EAAE,OAAgB;QACpF,MAAM,GAAG,GAAG,OAAO,IAAK,KAAa,EAAE,OAAO,CAAA;QAC9C,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAA;QACtB,MAAM,KAAK,GAAG,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;QAC7H,MAAM,MAAM,GAAG,IAAA,iCAAW,EAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;QAC3C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,IAAI,KAAK,EAAE,QAAQ;gBAAE,IAAA,iBAAQ,EAAC,wBAAwB,GAAG,yBAAyB,KAAK,CAAC,QAAQ,gEAAgE,CAAC,CAAA;YACjK,OAAO,KAAK,CAAA;QACd,CAAC;QACD,OAAO,EAAE,GAAG,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC/C,CAAC;IAED,MAAM,CAAC,SAAS,CAAC,EAAU,EAAE,QAAgB,EAAE,IAAY,EAAE,KAAmB;QAC9E,MAAM,GAAG,GAAG,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;QACpC,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;QACnD,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;QAC9B,MAAM,MAAM,GAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAA;QACjF,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;QAC3B;8DACsD;QACtD,eAAe,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,CAAC,CAAA;QAC5C,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAA,CAAC,mCAAmC;QAC3E;2CACmC;QACnC,MAAM,SAAS,GAAG,EAAE,KAAK,EAAE,CAAC,CAAoB,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,CAAA;QAC5G,MAAM,IAAI,GAAoB,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,mCAAc,EAAE,EAAE,OAAO,EAAG,KAAa,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAA;QACtL;;;;;;;;;;;;;WAaG;QACH,MAAM,QAAQ,GAAG,IAAI,OAAO,EAAU,CAAA;QACtC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;QACxB,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAoB,EAAE,EAAE;YACrD,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAW,CAAC;gBAAE,OAAO,0BAA0B;iBAC7F;YAAA,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YAC5D,mDAAmD;YACnD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;YACjB,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;YAC9B,IAAI,CAAC,wBAAwB,EAAE,CAAA;QACjC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QAChB,yDAAyD;QACzD,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAA,iBAAQ,EAAC,wCAAwC,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,CAAA;QAClI,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAA;QAChC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,CAAA;QAC1B,0DAA0D;QAC1D,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAA,iBAAQ,EAAC,kBAAkB,EAAE,8BAA8B,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC,CAAA;QACxI;;;;;;;;;;WAUG;QACH,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,CAAC,CAAA;QAC7C,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;QAC1B,4DAA4D;QAC5D,IAAA,qBAAa,EAAC,cAAM,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QACvG;;;;;;;;;;;;;;;;;;;;WAoBG;QACH,IAAA,qBAAa,EAAC,yBAAS,CAAC;aACrB,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,CAAC;aAC7F,IAAI,CAAC,GAAG,CAAC,EAAE;YACV,MAAM,IAAI,GAAG,GAAG,EAAE,QAAQ,IAAI,CAAC,CAAA;YAC/B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;YACpB,IAAI,CAAC,IAAI,IAAI,OAAQ,MAAc,CAAC,cAAc,KAAK,UAAU;gBAAE,OAAM;YACzE,IAAI,CAAC;gBACH,CAAC;gBAAC,MAAc,CAAC,cAAc,CAAC,IAAI,CAAC,CAAA;YACvC,CAAC;YAAC,OAAO,GAAQ,EAAE,CAAC;gBAClB,qDAAqD;gBACrD,IAAA,iBAAQ,EAAC,kBAAkB,EAAE,mBAAmB,IAAI,2BAA2B,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC,CAAA;YACvG,CAAC;QACH,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAA;QACnC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAA,kBAAS,EAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC,CAAA;QAChH,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,UAAU,CAAC,QAAgB,EAAE,EAAU,EAAE,SAA8B;QAC5E,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAA;QACrD,IAAI,IAAI,EAAE,IAAI,KAAK,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO,CAAC,CAAA;QACtD,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;QACjC,gEAAgE;QAChE,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;YAC1B,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAW,CAAC,CAAA;YAC/D,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;YACvB,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA,CAAC,6BAA6B;QAClD,CAAC;QACD,IAAA,2BAAW,EAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAA,4BAAY,GAAE,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,CAG5F;QAAA,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAA;QACvE,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAAC,IAAI,CAAC,OAAO,CAAC,aAAa,IAAI,SAAS,CAAC,MAAM,CAAC;YAAC,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,SAAS,CAAC,MAAM,CAAA;QAAC,CAAC,CAAC,UAAU;QAC5H,mGAAmG;QACnG,8EAA8E;QAC9E,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;QACjB,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;QACpC,IAAI,CAAC,wBAAwB,EAAE,CAAA;QAC/B,OAAO,SAAS,CAAC,MAAM,CAAA;IACzB,CAAC;IAED;;;;;;;;;;;OAWG;IACH;;;;OAIG;aACI,yBAAoB,GAAG,EAAE,CAAA;IAChC,gDAAgD;aACzC,wBAAmB,GAAG,CAAC,CAAA;IAC9B;;;;;;OAMG;aACI,oBAAe,GAAG,CAAC,CAAA;IAE1B;;;;;;OAMG;IACH,MAAM,CAAC,cAAc,CAAC,IAAqB,EAAE,MAAc;QACzD,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS;YAAE,OAAM,CAAC,gBAAgB;QAC1D,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,CAAC,UAAU,GAAG,SAAS,CAAA;YAC3B,OAAM;QACR,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,MAAM,OAAO,GAAG,IAAA,kCAAe,EAAC,CAAC,CAAC,CAAA;YAClC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,IAAI,CAAC,UAAU,GAAG,SAAS,CAAA;gBAC3B,OAAM;YACR,CAAC;YACD,KAAK,MAAM,GAAG,IAAI,OAAO;gBAAE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACrD,CAAC;IACH,CAAC;IAED,kEAAkE;aAC3D,0BAAqB,GAAG,GAAG,CAAA;IAClC;;;;;;;;;;;;OAYG;aACI,8BAAyB,GAAG,IAAI,CAAA;IACvC,gEAAgE;aACzD,yBAAoB,GAAG,GAAG,CAAA;IACjC,4DAA4D;aACrD,sBAAiB,GAAG,GAAG,CAAA;IAC9B,+BAA+B;aACxB,sBAAiB,GAAG,CAAC,CAAA;IAG5B,wFAAwF;IAChF,MAAM,CAAC,wBAAwB;QACrC,IAAI,IAAI,CAAC,cAAc;YAAE,OAAM;QAC/B,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,qBAAqB,CAAA;QACnD,IAAI,CAAC,cAAc,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAA;QAC3F,IAAI,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,KAAK,UAAU;YAAE,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAA,CAAC,SAAS;IAC5F,CAAC;IAED;;;;;;OAMG;IACK,MAAM,CAAC,qBAAqB,CAAC,OAAe;QAClD,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,CAAA;QACrC,MAAM,IAAI,GAAG,MAAM,GAAG,IAAI,CAAC,oBAAoB,CAAA;QAC/C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,CAAA;QACpB,IAAI,IAAI,GAAG,MAAM,CAAA;QACjB,IAAI,OAAO,GAAG,IAAI,IAAI,MAAM,GAAG,IAAI,CAAC,yBAAyB,EAAE,CAAC;YAC9D,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,yBAAyB,EAAE,MAAM,GAAG,CAAC,CAAC,CAAA;YAC3D,IAAI,CAAC,iBAAiB,EAAE,CAAA;YACxB,IAAA,iBAAQ,EACN,kCAAkC,MAAM,QAAQ,IAAI,uBAAuB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,UAAU,CACxJ,CAAA;QACH,CAAC;aAAM,IAAI,OAAO,GAAG,GAAG,IAAI,MAAM,GAAG,IAAI,CAAC,qBAAqB,EAAE,CAAC;YAChE,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,qBAAqB,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAA;QACrE,CAAC;QACD,IAAI,IAAI,KAAK,MAAM;YAAE,OAAM;QAE3B,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAA;QAC7B,IAAI,IAAI,CAAC,cAAc;YAAE,aAAa,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;QAC3D,IAAI,CAAC,cAAc,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,IAAI,CAAC,CAAA;QACzE,IAAI,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,KAAK,UAAU;YAAE,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAA;IAClF,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,mBAAmB;QACxB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACtB,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;QACpC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YACjD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,KAAK,MAAM,CAAA;YACnC;;;;;;;eAOG;YACH,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAA;YACtB,IAAI,CAAC,EAAE,CAAC;gBACN,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,cAAc,CAAC,GAAG,IAAI,CAAA;gBAC1C,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;oBACZ,CAAC,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,GAAG,EAAE,CAAC,CAAA;oBAC5C,CAAC,CAAC,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAA;oBAC9D,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,GAAG,EAAE,CAAC,CAAA;oBAC9C,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC;oBAAC,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC;oBAAC,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC;oBAAC,CAAC,CAAC,cAAc,GAAG,GAAG,CAAA;gBAClF,CAAC;YACH,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,KAAK;gBAAE,SAAQ;YACzB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;YAClB,wDAAwD;YACxD,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,sBAAsB,IAAI,CAAC,CAAC,GAAG,CAAC,CAAA;YACnD,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC;gBACd,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAA;gBAC5B,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC,oBAAoB,CAAA;YACzD,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAA;YACpC,CAAC;YACD,2CAA2C;YAC3C,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAA;YAC5B,IAAI,CAAC,EAAE,CAAC;gBAAC,CAAC,CAAC,cAAc,EAAE,CAAC;gBAAC,CAAC,CAAC,aAAa,EAAE,CAAA;YAAC,CAAC;YAChD,yDAAyD;YACzD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;YACvB;uEAC2D;YAC3D,IAAI,CAAC,MAAM;gBAAE,SAAQ;YACrB,sFAAsF;YACtF,qFAAqF;YACrF,wEAAwE;YACxE,IAAI,CAAC,cAAc,CACjB,YAAY,EACZ,EAAE,SAAS,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,CAAC,EAAE,EAAE,EACnF,cAAc,IAAI,CAAC,EAAE,EAAE,CACxB,CAAA;QACH,CAAC;QACD;6DACqD;QACrD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YAC/D,aAAa,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;YAClC,IAAI,CAAC,cAAc,GAAG,SAAS,CAAA;YAC/B,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,qBAAqB,CAAA;YACnD,OAAM;QACR,CAAC;QACD,4DAA4D;QAC5D,IAAI,CAAC,qBAAqB,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,CAAA;IAC5D,CAAC;IAED;;;;OAIG;IACH,uDAAuD;IAC/C,MAAM,CAAC,gBAAgB,CAAC,CAAM;QACpC,IAAI,CAAC,YAAY,IAAI;YAAE,OAAO,CAAC,CAAA;QAC/B,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;QACrD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAA;IAClD,CAAC;IAEO,MAAM,CAAC,UAAU,CAAC,IAAS,EAAE,QAAgB,EAAE,UAAkB,EAAE,CAAM,EAAE,QAAgB,EAAE,YAAqB;QACxH,OAAO,IAAI,CAAC,MAAM,CAAC;YACjB,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS;YAC/B,UAAU;YACV,SAAS,EAAE,CAAC,EAAE,SAAS;YACvB,+CAA+C;YAC/C,aAAa,EAAE,CAAC,EAAE,aAAa;YAC/B,QAAQ;YACR;4DACgD;YAChD,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC;YACvD;8DACkD;YAClD,SAAS,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC,EAAE,SAAS,CAAC;YAC9C,GAAG,IAAA,kCAAa,EAAC,CAAC,CAAC;YACnB,OAAO,EAAE,CAAC;SACX,CAAC,CAAA;IACJ,CAAC;IAED;;;;;OAKG;IACH,kEAAkE;aACnD,sBAAiB,GAAkC,EAAE,CAAA;IACpE,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,QAAgB,EAAE,UAAkB;QAC9D,MAAM,GAAG,GAAG,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAA;QAC1C;;;WAGG;QACH,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAA;QACrE,MAAM,MAAM,GAAG,MAAM,IAAA,qBAAa,EAAC,iCAAa,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,CAAA;QACtI,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAA;QACxD,OAAO,MAAM,EAAE,GAAG,CAAA;IACpB,CAAC;IAED,2DAA2D;IACnD,MAAM,CAAC,UAAU;QACvB,OAAO,EAAE,aAAa,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAA;IAC7M,CAAC;IAED;;;;;;;;;;;OAWG;IACK,MAAM,CAAC,YAAY,CAAC,IAAqB;QAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAA;QACjC,IAAI,CAAC,KAAK,EAAE,MAAM;YAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;QAC5C,IAAI,CAAC,cAAc,GAAG,EAAE,CAAA;QACxB,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAA;QACtB;sDAC8C;QAC9C,IAAI,CAAC,EAAE,CAAC;YAAC,CAAC,CAAC,cAAc,IAAI,KAAK,CAAC,MAAM,CAAC;YAAC,CAAC,CAAC,WAAW,IAAI,KAAK,CAAC,MAAM,CAAC;YAAC,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,cAAc,EAAE,MAAM,IAAI,CAAC,CAAA;QAAC,CAAC;QAExH,kDAAkD;QAClD,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAA;QACtH,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAA;QAEvH,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;QAClC,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,IAAA,2BAAW,EAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAA,4BAAY,GAAE,CAAC,EAAE,SAAS,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,CAAA;QAClH,MAAM,IAAI,GAAoB,EAAE,CAAA;QAEhC,IAAI,OAAO,CAAC,MAAM;YAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAA;QACnF,IAAI,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,EAAE,CAAC;YAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAA;YAC3B,IAAI,CAAC,QAAQ,GAAG,KAAK,GAAG,KAAK,CAAC,MAAM,CAAA;YACpC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAA;QACpE,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;QAC1C;;;;WAIG;QACH,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAA;QAC7C,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;aACrB,IAAI,CAAC,GAAG,EAAE;YACT,IAAI,EAAE,CAAA;YACN;;;eAGG;YACH,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;QAC1D,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAA,kBAAS,EAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC,CAAA;IAC5D,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,QAAgB,EAAE,UAAkB,EAAE,KAAyC;QACzG,MAAM,IAAI,GAAG,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAA;QACrC,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QACpE,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAA;QAC9G,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IACnC,CAAC;IAED;;;;;;;;;OASG;IACK,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,IAAS,EAAE,IAAW;QACpD,MAAM,KAAK,GAAG,GAAG,CAAA;QACjB;;;;;;;;;;;;;;;;;;;WAmBG;QACH,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,KAAK;YAAE,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAA;IAC1F,CAAC;IAED,mGAAmG;IACnG,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,QAAgB,EAAE,UAAkB,EAAE,SAAgB,EAAE,aAAqB;QACrG,MAAM,IAAI,GAAG,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAA;QACrC,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QACpE,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,EAAE,aAAa,GAAG,CAAC,GAAG,CAAC,EAAE,YAAY,CAAC,CAAC,CAAA;QACzH,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IACnC,CAAC;IAED,yFAAyF;IACzF,MAAM,CAAC,KAAK,CAAC,QAAQ,CACnB,QAAgB,EAChB,UAAkB,EAClB,IAAY,EACZ,KAAmB,EACnB,SAAgC,SAAS,EACzC,aAA6B,EAC7B,MAAY;IACZ;;;;OAIG;IACH,IAAsE;QAEtE,MAAM,IAAI,GAAG,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAA;QACxC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;QACxF,MAAM,IAAI,CAAC,IAAI,CACb,IAAI,CAAC,MAAM,CAAC;YACV,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC;YACnB,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS;YAC/B,UAAU;YACV,IAAI;YACJ,KAAK;YACL,iGAAiG;YACjG,OAAO,EAAG,KAAa,EAAE,OAAO,IAAI,QAAQ,EAAE,OAAO;YACrD,MAAM,EAAG,KAAa,EAAE,MAAM,IAAI,QAAQ,EAAE,MAAM;YAClD;;sEAE0D;YAC1D,aAAa,EACX,aAAa;gBACb,IAAA,qCAAiB,EACf,QAAQ,EAAE,aAAa,EACvB,aAAa,UAAU,iEAAiE,CACzF;YACH;uDAC2C;YAC3C,OAAO,EAAE,QAAQ,EAAE,OAAO,IAAI,aAAa;YAC3C;qEACyD;YACzD,MAAM,EAAE,MAAM,IAAI,QAAQ,EAAE,MAAM,IAAI,IAAI;YAC1C,uDAAuD;YACvD,IAAI,EAAE,QAAQ,EAAE,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI,IAAI;YAC1C,WAAW,EAAE,QAAQ,EAAE,WAAW,IAAI,IAAI,EAAE,WAAW,IAAI,IAAI;YAC/D,6CAA6C;YAC7C,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,EAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjF,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,EAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjE,MAAM;SACP,CAAC,CACH,CAAA;IACH,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,QAAgB,EAAE,UAAkB;QAClE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAA;QAC7D,MAAM,IAAI,GAAG,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,CAAA;QAC1C,IAAI,CAAC,IAAI,EAAE,SAAS;YAAE,OAAM;QAC5B,MAAM,IAAI,GAAG,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAA;QACxC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;QACnF,IAAI,CAAC,GAAG,EAAE,KAAK;YAAE,OAAM;QACvB,MAAM,KAAK,GAAG,GAAG,CAAC,KAAqB,CAAA;QACvC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAC7D,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS;aACzB,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;aACpC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;QAC1E,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,OAAM;QACzB,KAAK,CAAC,SAAS,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC,EAAE,GAAG,KAAK,CAAC,CAAA;QACxD,GAAG,CAAC,KAAK,GAAG,KAAK,CAAA;QACjB,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACtB,CAAC;IAED;;;;OAIG;IACH;;;;;;OAMG;IACK,MAAM,CAAC,gBAAgB,CAAC,QAAgB,EAAE,UAAkB;QAClE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;YAAE,OAAM;QAC7D;;;;;;WAMG;QACH,MAAM,GAAG,GAAQ,IAAI,KAAK,CAAC,aAAa,UAAU,4CAA4C,CAAC,CAAA;QAC/F,GAAG,CAAC,IAAI,GAAG,cAAc,CAAA;QACzB,GAAG,CAAC,MAAM,GAAG,EAAE,UAAU,EAAE,CAAA;QAC3B,MAAM,GAAG,CAAA;IACX,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,KAAK,CAAC,cAAc,CACzB,QAAgB,EAChB,UAAkB,EAClB,KAAmB,EACnB,OAAgB,EAChB,MAAY;QAEZ,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAA;QAC7D,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,aAAa,UAAU,qDAAqD,CAAC,CAAA;QACxG,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;YACtB,MAAM,IAAI,KAAK,CAAC,aAAa,UAAU,+FAA+F,CAAC,CAAA;QAEzI,MAAM,GAAG,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;QAC1G,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,aAAa,UAAU,0EAA0E,CAAC,CAAA;QAE5H,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAA;QAC5E,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,CAAA;QACxF;wCACgC;QAChC,MAAM,KAAK,GAAmB,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAA;QAC/D;;;;WAIG;QACH,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC,CAAA;QAEpD;;;;;;;;;WASG;QACH,MAAM,IAAA,uCAAgB,EAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,GAAQ,EAAE,EAAE,CACjF,IAAA,iBAAQ,EAAC,kBAAkB,UAAU,yEAAyE,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC,CACrI,CAAA;QAED;;;;;;;;;;;WAWG;QACH,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;QACjB,kDAAkD;QAClD,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAA;QACzB,IAAI,CAAC,wBAAwB,EAAE,CAAA;QAE/B,OAAO,EAAE,GAAG,EAAE,GAAG,KAAK,EAAE,CAAA;IAC1B,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,SAAS,CACpB,QAAgB,EAChB,UAAkB,EAClB,IAAY,EACZ,KAAmB;IACnB;;;;;;OAMG;IACH,aAA4B,EAC5B,OAAgB,EAChB,MAAY;IACZ,iEAAiE;IACjE,IAAsE;QAEtE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QAC3C;6CACqC;QACrC,SAAS,CAAC,IAAI,CAAC,CAAA;QACf,MAAM,IAAI,GAAG,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAA;QACxC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;QAExF;;;;;;;;;;WAUG;QACH,MAAM,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAA;QAChE,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,QAAQ,EAAE,MAAc,IAAI,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,CAAC,CAAA;IAC1K,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,QAAgB,EAAE,UAAkB,EAAE,KAAmB,EAAE,OAAgB;QACtG,MAAM,IAAI,GAAG,IAAA,qBAAa,EAAC,iCAAa,CAAC,CAAA;QACzC,MAAM,SAAS,GAAG,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAA;QAClD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,CAAA;QAE9G;;;;;;;;;WASG;QACH,IAAI,MAAM,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,KAAqB,CAAC,KAAK,SAAS,EAAE,CAAC;YACtH,MAAM,CAAC,SAAS,GAAG,SAAS,CAAA;YAC5B,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACzB,CAAC;QAED,IAAI,MAAM,EAAE,SAAS,KAAK,SAAS,EAAE,CAAC;YACpC,IAAI,CAAC,iBAAiB,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,CAAA;YACrE,OAAO,MAAM,CAAC,GAAG,CAAA;QACnB,CAAC;QAED,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAA;QAClC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS,EAAE,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,KAAY,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;QACnJ,IAAI,CAAC,iBAAiB,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,GAAG,GAAG,CAAA;QAC9D,0DAA0D;QAC1D,OAAO,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAA;QACvD,IAAI,MAAM;YAAE,OAAO,CAAC,IAAI,CAAC,kBAAkB,UAAU,kCAAkC,GAAG,oDAAoD,MAAM,CAAC,GAAG,IAAI,CAAC,CAAA;QAC7J,OAAO,GAAG,CAAA;IACZ,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAC3B,QAAgB,EAChB,UAAkB;QAElB,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,iCAAa,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,CAAA;QAChI,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,CAAA;QAE3B,yDAAyD;QACzD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAyB,CAAA;QAC/C,KAAK,MAAM,GAAG,IAAI,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC;aAC7C,kBAAkB,CAAC,GAAG,CAAC;aACvB,MAAM,CAAC,gBAAgB,EAAE,KAAK,CAAC;aAC/B,SAAS,CAAC,UAAU,EAAE,GAAG,CAAC;aAC1B,KAAK,CAAC,sBAAsB,EAAE,EAAE,QAAQ,EAAE,CAAC;aAC3C,QAAQ,CAAC,4BAA4B,EAAE,EAAE,UAAU,EAAE,CAAC;aACtD,OAAO,CAAC,gBAAgB,CAAC;aACzB,UAAU,EAAE;YACb,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;QAE/F,iEAAiE;QACjE,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;QAC1B,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAEpC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;YACzB,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5C,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YAClE,IAAI,EAAE,IAAA,kCAAc,EAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAa,EAAE,CAAC,CAAC,KAAY,CAAC;SACvF,CAAC,CAAC,CAAA;IACL,CAAC;IAED,mDAAmD;IACnD,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,QAAgB,EAAE,UAAkB,EAAE,KAAoB;QACzF,MAAM,MAAM,GAAG,MAAM,IAAA,qBAAa,EAAC,iCAAa,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,CAAA;QACtI,IAAI,MAAM;YAAE,OAAO,MAAM,CAAC,GAAG,CAAA;QAC7B,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAC9E,CAAC;IAED,6DAA6D;IAC7D;;;;;;OAMG;IACK,MAAM,CAAC,oBAAoB,CAAC,KAAmB;QACrD,OAAO,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAClF,CAAC;IAEO,MAAM,CAAC,kBAAkB,CAAC,KAAmB;QACnD,MAAM,SAAS,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;aAC3C,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;aAC3C,IAAI,EAAE;aACN,IAAI,CAAC,GAAG,CAAC,CAAA;QACZ,MAAM,SAAS,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;aAC3C,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,YAAY,EAAE,CAAC;aAC/C,IAAI,EAAE;aACN,IAAI,CAAC,GAAG,CAAC,CAAA;QACZ,OAAO,KAAK,SAAS,MAAM,SAAS,GAAG,CAAA;IACzC,CAAC;IAED,mEAAmE;IACnE,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,QAAgB,EAAE,UAAkB,EAAE,aAA6B;QAChG,MAAM,GAAG,GAAG,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QAC5C,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;QACnD,MAAM,GAAG,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;QAC1G,IAAI,CAAC,GAAG,EAAE,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,aAAa,UAAU,8BAA8B,CAAC,CAAA;QAEvF;;;;;;;;;;;;;;;;;;;WAmBG;QACH,MAAM,MAAM,GAAG,aAAa,IAAI,IAAA,qCAAiB,EAAC,GAAG,CAAC,aAAa,EAAE,SAAS,UAAU,GAAG,CAAC,CAAA;QAC5F,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;YACxB;+CACmC;YACnC,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,QAAQ,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAqB,EAAE,QAAQ,CAAC,CAAC,CAAA;QAC1H,CAAC;QACD,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;YACvB;;;;;;eAMG;YACH,IAAI,GAAG,CAAC,OAAO,KAAK,OAAO;gBAAE,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QAC5E,CAAC;QAED;;;;;;WAMG;QACH,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;YACpD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;YAC9E,IAAI,MAAM,EAAE,KAAK,EAAE,CAAC;gBAClB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAA;YAC1E,CAAC;iBAAM,CAAC;gBACN,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;gBACxE,IAAI,KAAK;oBAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAA;YACtE,CAAC;QACH,CAAC;QAED;;;;;;WAMG;QACH,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC;aACxC,kBAAkB,CAAC,GAAG,CAAC;aACvB,MAAM,CAAC,iBAAiB,EAAE,KAAK,CAAC;aAChC,KAAK,CAAC,sBAAsB,EAAE,EAAE,QAAQ,EAAE,CAAC;aAC3C,QAAQ,CAAC,4BAA4B,EAAE,EAAE,UAAU,EAAE,CAAC;aACtD,SAAS,EAAE,CAAA;QAEd,OAAO,IAAI,CAAC,KAAK,CACf,UAAU,EACV,QAAQ;QACR;8EACsE;QACtE,GAAG,CAAC,IAAI,EACR,GAAG,CAAC,KAAqB;QACzB,oEAAoE;QACpE,MAAM,EACN,GAAG,CAAC,OAAO,EACX,MAAM,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,CAC5B,CAAA;IACH,CAAC;IAED;;;;;;;;;OASG;IACH,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,QAAgB,EAAE,UAAkB,EAAE,IAAmB;QACjF,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,MAAM,GAAG,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;YAC1G,IAAI,CAAC,GAAG,EAAE,KAAK;gBAAE,MAAM,IAAI,KAAK,CAAC,aAAa,UAAU,8BAA8B,CAAC,CAAA;YACvF,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,QAAQ,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,KAAqB,CAAC,CAAA;QAClF,CAAC;QACD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB;;;;;;;;;;;eAWG;YACH,OAAO,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAA;QAC/D,CAAC;QACD,iDAAiD;QACjD,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QAC7C,OAAO,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;IAC9D,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,QAAgB,EAAE,UAAkB;QAC5D,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS,EAAE,UAAU,EAAE,CAAC,CAAA;QACtF,OAAO,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAA;QACvD;;;;;;;;;;WAUG;QACH,MAAM,4BAAY;aACf,UAAU,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,cAAc,CAAC;aAC/G,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAA,iBAAQ,EAAC,kBAAkB,UAAU,kEAAkE,EAAE,GAAG,EAAE,OAAO,IAAI,GAAG,CAAC,CAAC,CAAA;QAC9I,MAAM,4BAAY;aACf,UAAU,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,cAAc,CAAC;aACvG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAA,iBAAQ,EAAC,kBAAkB,UAAU,yEAAyE,EAAE,GAAG,EAAE,OAAO,IAAI,GAAG,CAAC,CAAC,CAAA;IACvJ,CAAC;IAED,iDAAiD;IACjD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAgB,EAAE,UAAkB;QACtD,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QACrC,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QACzC,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS,EAAE,UAAU,EAAE,CAAC,CAAA;QACtF,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS,EAAE,UAAU,EAAE,CAAC,CAAA;IAC3F,CAAC;IAED;;;;;;;;;OASG;IACK,MAAM,CAAC,cAAc,CAAC,QAAgB,EAAE,UAAkB;QAChE,MAAM,GAAG,GAAG,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QAC5C,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;QAC1B,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC9B,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAA;IACpC,CAAC;IAED,qEAAqE;IACrE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAgB;QAChC,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAA;QAC5F;;;;;WAKG;QACH,MAAM,WAAW,GAAG,IAAI,GAAG,CACzB,CAAC,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAC7G,CAAA;QACD;;;;;;;;;;;;;;;;;;;;;;WAsBG;QACH,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAA;QAC/C,MAAM,OAAO,CAAC,GAAG,CACf,IAAI,CAAC,GAAG,CAAC,KAAK,EAAC,CAAC,EAAC,EAAE;YACjB,IAAI,CAAC;gBACH;;;;;;;;;;;mBAWG;gBACH,MAAM,GAAG,GAAG,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC;qBACvC,kBAAkB,CAAC,GAAG,CAAC;qBACvB,MAAM,CAAC,iBAAiB,EAAE,UAAU,CAAC;qBACrC,KAAK,CAAC,sBAAsB,EAAE,EAAE,QAAQ,EAAE,CAAC;qBAC3C,QAAQ,CAAC,4BAA4B,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC;qBACpE,SAAS,EAAyB,CAAA;gBACrC,2DAA2D;gBAC3D,IAAI,GAAG,EAAE,QAAQ,IAAI,IAAI;oBAAE,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAA;YAC/F,CAAC;YAAC,OAAO,GAAQ,EAAE,CAAC;gBAClB;;mEAEmD;gBACnD,IAAA,kBAAS,EAAC,gDAAgD,CAAC,CAAC,UAAU,GAAG,EAAE,GAAG,EAAE,OAAO,IAAI,GAAG,CAAC,CAAA;YACjG,CAAC;QACH,CAAC,CAAC,CACH,CAAA;QAED,MAAM,GAAG,GAAU,EAAE,CAAA;QACrB,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,KAAK,GAAI,CAAC,CAAC,KAAsB,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAA;YAC3E,GAAG,CAAC,IAAI,CAAC;gBACP,UAAU,EAAE,CAAC,CAAC,UAAU;gBACxB;;;;mBAIG;gBACH,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,SAAS;gBACzB,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,SAAS;gBACvC,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,wDAAwD;gBAC5E,iEAAiE;gBACjE,SAAS,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,SAAS;gBAC5E,aAAa,EAAE,CAAC,CAAC,aAAa,EAAE,+DAA+D;gBAC/F,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,qDAAqD;gBACzE,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,SAAS;gBAC7B,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC;gBAC7D;;;;;;mBAMG;gBACH,sDAAsD;gBACtD,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,SAAS;gBAC7E,QAAQ,EAAE,IAAA,uCAAe,EAAC;oBACxB,aAAa,EAAE,CAAC,CAAC,aAAa;oBAC9B,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC;oBAC7D,UAAU,EAAE,CAAC,CAAC,UAAU;iBACzB,CAAC;gBACF,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;gBAC9C;;;;;;mBAMG;gBACH,aAAa,EAAE,kBAAkB,CAAC,KAAK,CAAC,CAAC,MAAM;gBAC/C,cAAc,EAAE,kBAAkB,CAAC,KAAK,CAAC,CAAC,MAAM;aACjD,CAAC,CAAA;QACJ,CAAC;QACD,OAAO,GAAG,CAAA;IACZ,CAAC;IAED,gDAAgD;IAChD,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,QAAgB;QACtC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACpI,MAAM,KAAK,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAA;QAC7F,MAAM,GAAG,GAAG,IAAI,GAAG,EAAsG,CAAA;QACzH,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB;wEAC4D;YAC5D,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,KAAK,OAAO;gBAAE,SAAQ;YACjD,MAAM,KAAK,GAAQ,CAAC,CAAC,KAAK,IAAI,EAAE,CAAA;YAChC,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAA;YAC1I,CAAC,CAAC,SAAS,EAAE,CAAA;YACb,+DAA+D;YAC/D,CAAC,CAAC,SAAS,IAAI,kBAAkB,CAAC,KAAK,CAAC,CAAC,MAAM,CAAA;YAC/C,CAAC,CAAC,SAAS,IAAI,kBAAkB,CAAC,KAAK,CAAC,CAAC,MAAM,CAAA;YAC/C,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;QACvB,CAAC;QACD,OAAO,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,CAAA;IAC1B,CAAC;IAED,2DAA2D;IAC3D,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,QAAgB,EAAE,UAAkB,EAAE,OAAgC,EAAE,MAAe;QAC7G,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS,EAAE,UAAU,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,IAAI,EAAS,CAAC,CAAA;IACvI,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,QAAgB,EAAE,OAAe;QAO3D,MAAM,EAAE,GAAG,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,CAAA;QACnG,MAAM,KAAK,GAAG,EAAE;YACd,CAAC,CAAC,CAAC,MAAM,IAAA,qBAAa,EAAC,uBAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAS,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;YACpN,CAAC,CAAC,EAAE,CAAA;QACN,MAAM,KAAK,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,CAAA;QACtG,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,OAAO,IAAI,CAAA;QAC9B,OAAO;YACL,IAAI,EAAE,EAAE,EAAE,IAAI;YACd,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,uBAAuB,EAAE,EAAE,EAAE,uBAAuB,EAAE;YACzH,KAAK;YACL,SAAS,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;SACxF,CAAA;IACH,CAAC;IAED,0FAA0F;IAC1F,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,QAAgB,EAAE,OAAe;QACxD,MAAM,KAAK,GAAG,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,CAAA;QACtG,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,sDAAuB,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;YAChI,KAAK,MAAM,GAAG,IAAI,IAAI;gBAAE,MAAM,IAAA,qBAAa,EAAC,kCAAa,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS,EAAE,cAAc,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAS,EAAE,CAAC,CAAA;YAC7I,MAAM,IAAA,qBAAa,EAAC,sDAAuB,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAS,EAAE,CAAC,CAAA;YACxH,MAAM,IAAA,qBAAa,EAAC,uBAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAS,EAAE,CAAC,CAAA;QAC3G,CAAC;QACD,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS,EAAE,OAAO,EAAE,CAAC,CAAA;IACrF,CAAC;IAED;;;;;;;;OAQG;IACH,MAAM,CAAC,KAAK,CAAC,YAAY,CACvB,QAAgB,EAChB,MAAuB;IACvB,sEAAsE;IACtE,aAA4B,EAC5B,IAA2B;IAC3B,0DAA0D;IAC1D,KAAsB;QAEtB;;;;;;;;;;;;WAYG;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAA;QACnE,IAAI,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM;YAAE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;QAEtF,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,IAAA,kCAAY,EAAC,MAAM,EAAE,cAAc,CAAC,CAAA;QAC9E;;;;;;;;WAQG;QACH,MAAM,KAAK,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;QAC3H;;;;WAIG;QACH,MAAM,YAAY,GAAG,KAAK,EAAE,OAAO,IAAK,KAAa,EAAE,OAAO,CAAA;QAC9D,MAAM,QAAQ,GAAG,YAAY;YAC3B,CAAC,CAAC,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,CAAC;YACxG,CAAC,CAAC,IAAI,CAAA;QACR,IAAI,KAAK,EAAE,iBAAiB,IAAI,QAAQ,EAAE,iBAAiB,EAAE,CAAC;YAC5D,MAAM,OAAO,GAAG,IAAA,8CAAsB,EAAC,KAAY,EAAE,QAAQ,EAAE,iBAAwB,EAAE,KAAK,EAAE,iBAAwB,CAAC,CAAA;YACzH,MAAM,CAAC,MAAM,CAAC,KAAY,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;YAC1C;;;;eAIG;YACH,IAAI,KAAK,EAAE,CAAC;gBACV,KAAK,CAAC,iBAAiB,GAAG,OAAO,CAAC,oBAA2B,CAAA;gBAC7D,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YAC/C,CAAC;YACD,IAAI,QAAQ,EAAE,CAAC;gBACb,QAAQ,CAAC,iBAAiB,GAAG,OAAO,CAAC,iBAAwB,CAAA;gBAC7D,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAC/C,CAAC;YACD;;;eAGG;YACH,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,UAAU,CAAC,EAAE,CAAC;gBAC3E,QAAQ,CAAC,IAAI,CAAC,IAAA,yCAAmB,EAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;YACtF,CAAC;QACH,CAAC;QACD,MAAM,IAAI,GAAG,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAA;QACrC;kDAC0C;QAC1C,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;QAC3C,MAAM,YAAY,GAAG,MAAM;YACzB,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC;YAClF,CAAC,CAAC,KAAK,CAAA;QACT,MAAM,MAAM,GAAG,IAAA,oCAAkB,EAAC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,CAAA;QACtE,MAAM,OAAO,GAAW,MAAM,CAAC,OAAO,CAAA;QACtC,KAAK,CAAC,OAAO,GAAG,OAAO,CAAA,CAAC,4BAA4B;QACpD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,CAAA;QACrF,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClB;iDACqC;QACvC,CAAC;QACD;;;;;;WAMG;QACH,MAAM,GAAG,GAAQ,YAAY,CAAA;QAC7B,MAAM,QAAQ,GAAG,QAAQ,EAAE,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAA;QAC5D,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,IAAI,CAChC,IAAI,CAAC,MAAM,CAAC;YACV,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC;YACnB,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS;YAC/B,OAAO;YACP,IAAI,EAAE,QAAQ,EAAE,IAAI,IAAI,MAAM,CAAC,QAAQ;YACvC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjC,OAAO,EAAE,QAAQ,EAAE,OAAO,IAAI,GAAG,CAAC,KAAK;YACvC,OAAO,EAAE,QAAQ,EAAE,OAAO,IAAI,GAAG,CAAC,KAAK;YACvC,GAAG,EAAE,QAAQ,EAAE,GAAG,IAAI,GAAG,CAAC,GAAG;YAC7B;;;;;eAKG;YACH,uBAAuB,EAAE,QAAQ,EAAE,uBAAuB,IAAI,IAAI;SACnE,CAAC,CACH,CAAA;QACD;;;;WAIG;QACH,MAAM,OAAO,GAAG,IAAA,qBAAa,EAAC,sDAAuB,CAAC,CAAA;QACtD,MAAM,QAAQ,GAAG,IAAA,qBAAa,EAAC,kCAAa,CAAC,CAAA;QAC7C,IAAI,CAAC,MAAM,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,UAAU,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7E,MAAM,IAAI,GAAW,YAAoB,CAAC,eAAe,IAAI,EAAE,CAAA;YAC/D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;gBACnB,MAAM,MAAM,GACV,GAAG,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE;oBAC3D,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE;wBACjD,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE;4BACzF,CAAC,CAAC,EAAE,CAAA;gBACN,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,UAAU,CAAC,EAAE,EAAS,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,EAAE,KAAM,YAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;gBACrP,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAU,EAAE,CAAC;oBAC9C,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS,EAAE,cAAc,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAS,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC,CAAC,CAAA;gBAC3Q,CAAC;YACH,CAAC;YACD;;;eAGG;YACH,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,UAAU,CAAC,EAAE,EAAS,EAAE,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,CAAA;YAC5I,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAA;YACxD,IAAI,OAAO,IAAI,UAAU,CAAC,uBAAuB,KAAK,OAAO,CAAC,EAAE,EAAE,CAAC;gBACjE,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,UAAU,EAAE,uBAAuB,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;gBACpF,2DAA2D;gBAC3D,KAAK,MAAM,CAAC,IAAI,KAAK;oBAAE,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,EAAE,CAAC;wBAAE,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;YAClJ,CAAC;QACH,CAAC;QACD;;;;WAIG;QACH,MAAM,YAAY,GAAG,IAAA,qBAAa,EAAC,uBAAQ,CAAC,CAAA;QAC5C,KAAK,MAAM,CAAC,IAAI,CAAE,YAAoB,CAAC,KAAK,IAAI,EAAE,CAAU,EAAE,CAAC;YAC7D,IAAI,CAAC,CAAC,EAAE,EAAE;gBAAE,SAAQ;YACpB,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,UAAU,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;YACpI,MAAM,YAAY,CAAC,IAAI,CACrB,YAAY,CAAC,MAAM,CAAC;gBAClB,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC;gBACvB,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS;gBAC/B,KAAK,EAAE,EAAE,EAAE,EAAE,UAAU,CAAC,EAAE,EAAS;gBACnC,MAAM,EAAE,CAAC,CAAC,EAAE;gBACZ,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE;gBACpB,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,IAAI;gBAC5B,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;aAC/E,CAAC,CACH,CAAA;QACH,CAAC;QAED,IAAI,OAAO,EAAE,CAAC;YACZ;8DACkD;YAClD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;YACjG,QAAQ,CAAC,IAAI,CAAC,IAAA,sCAAgB,EAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAA;QACnD,CAAC;aAAM,CAAC;YACN,yDAAyD;YACzD,MAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE;gBAC3G,IAAI,EAAE,MAAM,CAAC,QAAQ;gBACrB,WAAW,EAAG,MAAc,CAAC,WAAW;gBACxC,KAAK;aACN,CAAC,CAAA;QACJ,CAAC;QAED;;;;;;WAMG;QACH,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,IAAA,uCAAgB,EAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;YACvF,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,cAAc;gBAAE,QAAQ,CAAC,IAAI,CAAC,IAAA,yCAAmB,EAAC,wBAAwB,EAAE,GAAG,CAAC,CAAC,CAAA;YAC7G,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,cAAc;gBAAE,QAAQ,CAAC,IAAI,CAAC,IAAA,yCAAmB,EAAC,eAAe,EAAE,GAAG,CAAC,CAAC,CAAA;YACpG;;;eAGG;YACH,IAAK,KAAa,EAAE,gBAAgB,KAAK,SAAS,EAAE,CAAC;gBACnD,KAAK,MAAM,CAAC,IAAI,CAAE,KAAa,EAAE,SAAS,IAAI,EAAE,CAAU,EAAE,CAAC;oBAC3D,MAAM,UAAU,GAAI,CAAC,CAAC,EAAE,UAAU,IAAI,EAAE,CAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,0BAAY,CAAC,eAAe,IAAI,MAAM,CAAC,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;oBAC9I,IAAI,UAAU;wBAAE,QAAQ,CAAC,IAAI,CAAC,IAAA,+CAAyB,EAAC,MAAM,CAAE,KAAa,EAAE,OAAO,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;gBAC/G,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,IAAA,kBAAS,EAAC,kDAAkD,MAAM,CAAC,MAAM,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,CAAA;YAC5F,QAAQ,CAAC,IAAI,CAAC,IAAA,sCAAgB,EAAC,GAAG,EAAE,OAAO,IAAI,SAAS,CAAC,CAAC,CAAA;QAC5D,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM;YAAE,IAAA,iBAAQ,EAAC,yBAAyB,MAAM,CAAC,MAAM,eAAe,IAAA,sCAAgB,EAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;QAChH,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAA;IACzD,CAAC;IAED,kDAAkD;IAClD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAgB,EAAE,UAAkB;QACtD,MAAM,CAAC,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;QACxG,IAAI,CAAC,CAAC;YAAE,OAAO,IAAI,CAAA;QACnB,OAAO;YACL,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC;YAC7D,aAAa,EAAE,CAAC,CAAC,aAAa,EAAE,iDAAiD;YACjF,KAAK,EAAE,CAAC,CAAC,KAAK;SACf,CAAA;IACH,CAAC;IAED;;;;OAIG;IACH,uDAAuD;aACxC,iBAAY,GAAG,IAAI,GAAG,EAAgD,CAAA;aAC7D,wBAAmB,GAAG,MAAM,CAAA;IAEpD;;;;;;;;;;OAUG;IACK,MAAM,CAAC,cAAc,CAAC,OAA8B,EAAE,OAAY,EAAE,IAAY;QACtF,IAAI,CAAC;YACH,cAAM,CAAC,OAAO,CAAC,OAAc,EAAE,OAAO,CAAC,CAAA;YACvC,OAAO,IAAI,CAAA;QACb,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,MAAM,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAA;YACnE,CAAC,CAAC,KAAK,EAAE,CAAA;YACT,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;YACtB,IAAI,GAAG,GAAG,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;gBAClD,CAAC,CAAC,SAAS,GAAG,GAAG,CAAA;gBACjB,IAAA,iBAAQ,EAAC,uCAAuC,IAAI,MAAM,CAAC,CAAC,KAAK,cAAc,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC,CAAA;YACvG,CAAC;YACD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;YAC9B,OAAO,KAAK,CAAA;QACd,CAAC;IACH,CAAC;IAED,MAAM,CAAC,iBAAiB,CAAC,IAAqB;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;QAC1B,IAAI,CAAC,MAAM;YAAE,OAAM;QACnB,4FAA4F;QAC5F,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAA,4BAAY,GAAE,CAAC,CAAA;QAEtD,4CAA4C;QAC5C,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;QAC/B,MAAM,EAAE,GACN,IAAI,CAAC,IAAI,KAAK,MAAM;YAClB,CAAC,CAAC,IAAI,CAAC,GAAG;gBACR,CAAC,CAAC,IAAA,gCAAW,EAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,uDAAuD;gBAC7G,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE;YAChC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,CAAA;QACrC,IAAA,2BAAW,EAAC,IAAI,EAAE,UAAU,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAA;QACxD,IAAI,CAAC,EAAE;YAAE,OAAM;QACf;;;;WAIG;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,IAAI,GAAG,EAAE,CAAC,CAAA;QAC7D,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;QAC9B;sDAC8C;QAC9C,6DAA6D;QAC7D,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;QAChC;;;;;;;;;;;WAWG;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAA;QAC/D,MAAM,MAAM,GAAG,IAAA,mCAAiB,EAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,UAAW,EAAE,CAAC,CAAA;QAC7F,IAAI,CAAC,eAAe,EAAE,CAAA;QACtB,IAAI,IAAI;YAAE,IAAI,CAAC,mBAAmB,EAAE,CAAA;QACpC,uCAAuC;QACvC,IAAI,CAAC,UAAU,GAAG,IAAI,GAAG,EAAE,CAAA;QAC3B,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAA;QAC7B,IAAA,2BAAW,EAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,CAAA;QAEvD,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;QAC9B,KAAK,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,MAAM,EAAE,CAAC;YACnC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YACb,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;YAChC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,GAAG;gBAAE,SAAQ,CAAC,cAAc;YAClD,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;YAClB;;;eAGG;YACH,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,IAAI,CAAC,EAAE,EAAE,CAAC;gBAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QACxG,CAAC;QACD,IAAA,2BAAW,EAAC,IAAI,EAAE,SAAS,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;QACtD;;;;;WAKG;QACH,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI;YAAE,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE;gBAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;oBAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IACxG,CAAC;IAED;;;;;OAKG;IAEH;;;;;;;OAOG;IACH,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,QAAgB,EAAE,UAAkB,EAAE,aAAsB,EAAE,SAAkB;QACnG,mDAAmD;QACnD,iFAAiF;QACjF,IAAI,aAAa,IAAI,IAAI,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;YAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAA;YAC7D,IAAI,IAAI,EAAE,MAAM,EAAE,WAAW;gBAAE,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAA;YAC/D,mFAAmF;YACnF,gDAAgD;YAChD,IAAI,IAAI,EAAE,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,SAAS;gBAAE,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QACzF,CAAC;QACD;;;;;;;;;WASG;QACH,MAAM,WAAW,GAAG,aAAa,IAAI,IAAI,IAAI,SAAS,IAAI,IAAI,CAAA;QAC9D,MAAM,GAAG,GAAG,WAAW,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QACzF,2DAA2D;QAC3D,MAAM,eAAe,GAAG,WAAW,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QACnH,IAAI,eAAe,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,IAAA,2BAAW,EAAC,eAAe,CAAC,KAAK,CAAC,CAAA;YAChD,IAAI,KAAK,IAAI,CAAC,eAAe,CAAC,QAAQ,IAAI,CAAC,CAAC,KAAK,GAAI,CAAC,QAAQ,IAAI,CAAC,eAAe,CAAC,YAAY,IAAI,IAAI,CAAC,KAAK,GAAI,CAAC,YAAY;gBAC5H,OAAO,KAAK,CAAA;QAChB,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;QAC1G,IAAI,CAAC,GAAG,EAAE,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,UAAU,uCAAuC,CAAC,CAAA;QAErG;;;;;;;;;;;WAWG;QACH;;;;;WAKG;QACH,MAAM,cAAc,GAAG,WAAW;YAChC,CAAC,CAAC,CAAC;YACH,CAAC,CAAC,MAAM,IAAA,qBAAa,EAAC,iCAAa,CAAC,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAA;QACjH,MAAM,QAAQ,GACZ,CAAC,WAAW,IAAI,cAAc,IAAI,CAAC;YACjC,CAAC,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,UAAU,EAAE;gBAC5C,GAAG,CAAC,aAAa,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC7D,GAAG,CAAC,SAAS,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACxG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;YACtB,CAAC,CAAC,IAAI,CAAA;QACV,MAAM,MAAM,GACV,WAAW,IAAI,GAAG,IAAI,eAAe,IAAI,eAAe,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC,YAAY,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,YAAY;YAC1H,CAAC,CAAC,eAAe;YACjB,CAAC,CAAC,QAAQ,CAAA;QAEd;;;;;;;;;;WAUG;QACH,MAAM,QAAQ,GAAG,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;QAChE,MAAM,OAAO,GAAG,SAAS,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;QAC5D,MAAM,SAAS,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,CAAA;QAC1D,qDAAqD;QACrD,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QACxD;;;WAGG;QACH,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAC,IAAI,CAAC;YAC/C,KAAK,EAAE,OAAO;gBACZ,CAAC,CAAC,IAAI;oBACJ,CAAC,CAAC,6DAA6D;wBAC7D;4BACE,EAAE,GAAG,SAAS,EAAE,QAAQ,EAAE,IAAA,kBAAQ,EAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAA,yBAAe,EAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE;4BAC1F,EAAE,GAAG,SAAS,EAAE,QAAQ,EAAE,IAAA,kBAAQ,EAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAA,gBAAM,GAAE,EAAE;yBAChE;oBACH,CAAC,CAAC;wBACE,EAAE,GAAG,SAAS,EAAE,SAAS,EAAE,IAAA,yBAAe,EAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE;wBAChE,EAAE,GAAG,SAAS,EAAE,SAAS,EAAE,IAAA,gBAAM,GAAE,EAAE;qBACtC;gBACL,CAAC,CAAC,aAAa,IAAI,IAAI;oBACrB,CAAC,CAAC,IAAI;wBACJ,CAAC,CAAC,EAAE,GAAG,SAAS,EAAE,QAAQ,EAAE,IAAA,aAAG,EAAC,IAAA,kBAAQ,EAAC,IAAI,CAAC,EAAE,IAAA,yBAAe,EAAC,aAAa,CAAC,CAAC,EAAE;wBACjF,CAAC,CAAC,EAAE,GAAG,SAAS,EAAE,QAAQ,EAAE,IAAA,yBAAe,EAAC,aAAa,CAAC,EAAE;oBAC9D,CAAC,CAAC,IAAI;wBACJ,CAAC,CAAC,EAAE,GAAG,SAAS,EAAE,QAAQ,EAAE,IAAA,kBAAQ,EAAC,IAAI,CAAC,EAAE;wBAC5C,CAAC,CAAC,SAAS;YACjB,KAAK,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE;SAC3B,CAAC,CAAA;QACF,MAAM,MAAM,GAAG,IAAI,CAAA;QAEnB;;;;;;;;;WASG;QACH,MAAM,UAAU,GAAG,MAAM,IAAA,qBAAa,EAAC,iCAAa,CAAC,CAAC,IAAI,CAAC;YACzD,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE;YAC/C,KAAK,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE;SACtB,CAAC,CAAA;QACF,MAAM,OAAO,GAAG,IAAI,GAAG,CAAuB,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,KAAqB,CAAC,CAAC,CAAC,CAAA;QACpG,iEAAiE;QACjE,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,CAAA;QACjC,MAAM,KAAK,GAAG,CAAC,CAA4B,EAAsB,EAAE,CAAC,CAAC,CAAC,YAAY,IAAI,MAAM,CAAA;QAE5F,MAAM,QAAQ,GAA6C,EAAE,CAAA;QAC7D,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,IAAI,CAAC,CAAC,CAAC,OAAO;gBAAE,SAAQ;YACxB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;YACpB,MAAM,KAAK,GAAG,CAAC,GAAG,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAK,GAAG,CAAC,KAAsB,CAAA;YACpF,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;YAC1C,IAAI,IAAI,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK;gBAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;;gBACxD,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QACpD,CAAC;QACD;;;;;;;;;WASG;QACH,MAAM,OAAO,GAAG,aAAa,IAAI,IAAI,IAAI,SAAS,IAAI,IAAI,CAAA;QAC1D,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,KAAiC,CAAA;QACnF,IAAI,OAAO,IAAI,MAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,KAAK,KAAK,MAAM;YAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAA;QAEtH;;;;;;;;;;;WAWG;QACH,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QAEhG;;;;;;;;;;;;WAYG;QACH,MAAM,GAAG,GAAG,IAAI,mCAAc,EAAE,CAAA;QAChC,wDAAwD;QACxD,IAAI,MAAM,EAAE,IAAI,EAAE,GAAG;YAAE,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACnD,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,IAAI,CAAC;gBACH,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,OAAc,CAAC,CAAA;YAC7B,CAAC;YAAC,MAAM,CAAC;gBACP,0DAA0D;YAC5D,CAAC;QACH,CAAC;QAED,MAAM,OAAO,GAAG,CAAC,EAAO,EAAO,EAAE;YAC/B,IAAI,CAAC,EAAE,IAAI,OAAO,EAAE,KAAK,QAAQ;gBAAE,OAAO,EAAE,CAAA;YAC5C,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,IAAI,SAAS,IAAI,aAAa,IAAI,SAAS,CAAA;YACrE,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;YAC/C,8DAA8D;YAC9D,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAA;YAChE,MAAM,WAAW,GAAG,IAAA,gCAAW,EAAC,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;YACvF,OAAO,IAAA,uCAAkB,EAAC,WAAW,CAAC,CAAA;QACxC,CAAC,CAAA;QAED,gEAAgE;QAChE;;;WAGG;QACH,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAA;QAEnF,MAAM,IAAI,GAAG,CAAC,EAAO,EAAE,IAAyD,EAAO,EAAE;YACvF;0EAC8D;YAC9D,IAAI,WAAW,IAAI,GAAG,IAAI,EAAE,EAAE,CAAC;gBAC7B,KAAK,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAA;YACjI,CAAC;YACD;;;;;;;;eAQG;YACH,IAAI,IAAI,IAAI,EAAE,EAAE,CAAC;gBACf,MAAM,EAAE,GAAG,WAAW,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAA;gBACvD,IAAI,EAAE,GAAG,CAAC;oBACR,KAAK,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,UAAU,EAAE;wBAC7C,QAAQ,EAAE,EAAE;wBACZ,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;wBACtD,YAAY,EAAE,CAAC,WAAW,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI;wBACpE,IAAI;qBACL,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YACtB,CAAC;YACD,OAAO,EAAE,CAAA;QACX,CAAC,CAAA;QAED;;;WAGG;QACH,IAAI,MAAM,EAAE,IAAI,EAAE,OAAO,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YAClD,MAAM,KAAK,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,CAAiB,CAAA;YACtF,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,EAAE,CAAC,CAAA;YAC7E,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,UAAU,EAAE,GAAG,EAAE,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;QACpF,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;YACrB,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,CAAiB,CAAA;YAChE,MAAM,GAAG,GAAG,oBAAoB,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;YAC3C,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,UAAU,EAAE,GAAG,EAAE,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;QACpF,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,GAAG,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;YACvE,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,UAAU,EAAE,GAAG,EAAE,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;QACpF,CAAC;QAED,4DAA4D;QAC5D,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAA;QAClD,wDAAwD;QACxD,KAAK,MAAM,EAAE,IAAI,MAAM;YACrB,IAAI,EAAE,CAAC,gBAAgB,IAAI,EAAE,CAAC,gBAAgB,IAAI,EAAE,CAAC,cAAc,IAAI,EAAE,CAAC,aAAa;gBACrF,OAAO,CAAC,IAAI,CAAC,kBAAkB,UAAU,iDAAiD,EAAE,CAAC,gBAAgB,eAAe,EAAE,CAAC,gBAAgB,eAAe,EAAE,CAAC,cAAc,aAAa,EAAE,CAAC,aAAa,+BAA+B,CAAC,CAAA;QAChP,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;IAC7B,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,QAAgB,EAAE,OAAe;QACtD,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,CAAA;QACrG,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAA;QACvC,IAAI,CAAC,GAAG,CAAC,MAAM;YAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;QAExD;;;;;;WAMG;QACH,MAAM,UAAU,GAAG,EAAE,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE,kBAAkB,EAAW,CAAA;QAChF,MAAM,IAAI,GAAG,KAAK,EAAE,UAAkB,EAAE,GAAkB,EAA0B,EAAE;YACpF,MAAM,GAAG,GAAG,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC;iBACvC,kBAAkB,CAAC,GAAG,CAAC;iBACvB,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;iBAC5B,KAAK,CAAC,sBAAsB,EAAE,EAAE,QAAQ,EAAE,CAAC;iBAC3C,QAAQ,CAAC,4BAA4B,EAAE,EAAE,UAAU,EAAE,CAAC;iBACtD,SAAS,EAAkB,CAAA;YAC9B,OAAO,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;QAC1B,CAAC,CAAA;QAED,IAAI,GAAG,GAAG,QAAQ,CAAA;QAClB,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAA;QAEnB;;;WAGG;QACH,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,iBAAiB,EAAE,CAAC;YACvD,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,iBAAiB,CAAC,CAAA;YACjD,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;YACxF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;gBACnB,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;gBACvB,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,GAAG,GAAG;oBAAE,GAAG,GAAG,EAAE,CAAA;gBACrC,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,GAAG,GAAG;oBAAE,GAAG,GAAG,EAAE,CAAA;YACvC,CAAC;QACH,CAAC;QAED,IAAI,GAAG,KAAK,QAAQ;YAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;QAC7D,OAAO,EAAE,OAAO,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAA;IACvF,CAAC;IAED,gFAAgF;aACzE,cAAS,GAA6B,EAAE,CAAA;IAC/C,MAAM,CAAC,MAAM,CAAC,EAAwB;QACpC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACzB,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAgB,EAAE,EAAU;QAC5C,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAA;QAClD,IAAI,CAAC,EAAE,CAAC;YACN;;;;;eAKG;YACH,MAAM,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CACnD,IAAA,kBAAS,EAAC,wCAAwC,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,IAAI,GAAG,CAAC,CAC9E,CAAA;YACD;;;;eAIG;YACH,MAAM,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;YAC1B,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;YACtB,CAAC,CAAC,KAAK,EAAE,CAAA;YACT,OAAO,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAA;YAC/C,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC;iBAC9B,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;iBAC7E,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAA,kBAAS,EAAC,sBAAsB,EAAE,GAAG,CAAC,CAAC,CAAA;QACzD,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAAC,IAAI,CAAC;gBAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;QAAC,CAAC;IAC9E,CAAC;IAED;;;;;;;;;;OAUG;IACH;;;;;;;;;;OAUG;IACK,MAAM,CAAC,iBAAiB,CAAC,IAAqB;QACpD,MAAM,MAAM,GAAQ,IAAI,CAAC,MAAM,CAAA;QAC/B,IAAI,OAAO,MAAM,EAAE,oBAAoB,KAAK,UAAU;YAAE,OAAM,CAAC,eAAe;QAC9E,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,MAAM,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAA,CAAC,kCAAkC;YAClE,OAAM;QACR,CAAC;QACD,MAAM,KAAK,GAAsC,EAAE,CAAA;QACnD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YAClD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO;gBAAE,SAAQ;YAClG,MAAM,EAAE,GAAkC,KAAK,CAAC,MAAc,EAAE,SAAS,CAAA;YACzE,IAAI,CAAC,EAAE,IAAI,OAAO,EAAE,CAAC,OAAO,KAAK,UAAU;gBAAE,SAAQ;YACrD,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;QAC3F,CAAC;QACD,MAAM,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAA;IACpC,CAAC;IAEO,MAAM,CAAC,WAAW,CAAC,QAAgB,EAAE,EAAU,EAAE,OAAwB;QAC/E,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAA;QACrD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAA,4BAAY,GAAE,CAAC,CAAC,CAAA;QAChE,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;QAC5B,IAAI,CAAC;YACH,sDAAsD;YACtD,IAAI,IAAI;gBAAE,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAA;YACtC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YAE1B;iEACqD;YACrD,IAAI,IAAI,EAAE,CAAC;gBACT,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,CAAA;gBACnC,IAAA,2BAAW,EAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,CAAA;gBAC/B,MAAM,CAAC,GAAG,IAAA,0BAAU,EAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;gBAC1D,IAAI,CAAC,CAAC,IAAI;oBAAE,IAAA,iBAAQ,EAAC,IAAA,+BAAe,EAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAA;gBACjE,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,EAAE,EAAE,IAAI,CAAC,CAAA;YAC1C,CAAC;QACH,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB;;;;eAIG;YACH,IAAI,CAAC,YAAY,CACf,QAAQ,EACR,EAAE,EACF,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,OAAO,IAAI,GAAG,CAAC,EAAE,EAAE,EACxE,kBAAkB,EAAE,mEAAmE;gBACrF,mDAAmD,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAC3E,CAAA;QACH,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACK,MAAM,CAAC,eAAe,CAAC,QAAgB,EAAE,EAAU,EAAE,MAAc;QACzE,MAAM,GAAG,GAAG,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;QACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,aAAa,CAAA;QAClD,IAAI,CAAC,CAAC,MAAM,IAAI,QAAQ,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YAC7B,OAAM;QACR,CAAC;QACD,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAA;QACpD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;QAClC,IAAI,MAAM,GAAG,IAAI,CAAC,aAAa;YAAE,OAAM;QAEvC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,CAAA;QACtC,IAAI,CAAC,YAAY,CACf,QAAQ,EACR,EAAE,EACF,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,GAAG,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EACrF,kBAAkB,EAAE,eAAe,MAAM,2BAA2B,QAAQ,GAAG,IAAI,WAAW,IAAI,MAAM;YACtG,+GAA+G;YAC/G,0HAA0H,CAC7H,CAAA;IACH,CAAC;IAED,wDAAwD;IAChD,MAAM,CAAC,YAAY,CAAC,QAAgB,EAAE,EAAU,EAAE,IAAc,EAAE,GAAW;QACnF,IAAA,kBAAS,EAAC,GAAG,CAAC,CAAA;QACd,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,CAAA;QAClD,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAA,kBAAS,EAAC,0CAA0C,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,IAAI,GAAG,CAAC,CAAC,CAAA;IACvH,CAAC;IAED,yCAAyC;IACzC,MAAM,CAAC,UAAU,CAAC,QAAgB,EAAE,EAAU;QAC5C,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAA;IACrD,CAAC;IAED;;;;;;;;OAQG;IACH,MAAM,CAAC,SAAS,CAAC,QAAgB,EAAE,EAAU;QAC3C,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAA;IACnD,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,QAAgB,EAAE,EAAU;QACzC,OAAO,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,CAAA;IAC1D,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,QAAgB,EAAE,UAAkB,EAAE,OAAY;QAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAA;QAC7D,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,CAAA;QACxC,MAAM,KAAK,GAAG,IAAA,iCAAY,EACxB,IAAI,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,iBAAiB,EAAE,OAAQ,IAAI,CAAC,MAAc,EAAE,QAAQ,KAAK,UAAU,EAAE,EAChI,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,KAAK,QAAQ,EACpC,IAAI,CACL,CAAA;QACD,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC9B,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,KAAK,EAAE,KAAK,CAAC,SAAS,EAAE,CAAA;QAChH,CAAC;QAED,MAAM,GAAG,GAAG,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAA,CAAC,kCAAkC;QACjF,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;YAAE,OAAO,IAAK,CAAC,OAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAA;QAEnE;;;;;WAKG;QACH,MAAM,MAAM,GAAQ,IAAK,CAAC,MAAM,CAAA;QAChC,MAAM,OAAO,GAAU,EAAE,CAAA;QACzB,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;QACzD,IAAI,GAAQ,CAAA;QACZ,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAA;QAC5B,CAAC;gBAAS,CAAC;YACT,GAAG,EAAE,EAAE,CAAA;QACT,CAAC;QACD,IAAI,GAAG,EAAE,QAAQ,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACpC,IAAK,CAAC,cAAc,GAAG,CAAC,GAAG,CAAC,IAAK,CAAC,cAAc,IAAI,EAAE,CAAC,EAAE,GAAG,OAAO,CAAC,CAAA;YACpE,IAAK,CAAC,KAAK,GAAG,IAAI,CAAA,CAAC,kCAAkC;QACvD,CAAC;QACD,OAAO,GAAG,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAA;IAC3F,CAAC;IAED;;;;;OAKG;IACH;;;;;OAKG;IACH,MAAM,CAAC,MAAM,CAAC,QAAgB,EAAE,EAAU;QACxC,OAAO,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,CAAA;IACvD,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,QAAgB,EAAE,EAAU;QACtC,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAA;IACnD,CAAC;IAED;;;;;;;;;OASG;IACH,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,QAAgB,EAAE,UAAkB;QAC9D,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC;YAAE,OAAO,IAAI,CAAA;QAChD,OAAO,CAAC,CAAC,CAAC,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC,CAAA;IAC3G,CAAC;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,QAAgB,EAAE,OAAe;QAC/D,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,CAAA;QACvB,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,CAAA;QACrG,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACpE,CAAC;IAED;;;;;;;;;OASG;IACH,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,QAAgB,EAAE,OAAe,EAAE,KAAc;QAC9E,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;QAC5D,MAAM,MAAM,GAAG,GAAG;YAChB,oDAAoD;aACnD,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;aACrC,GAAG,CAAC,EAAE,CAAC,EAAE;YACR,MAAM,MAAM,GAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;YAC7C,MAAM,IAAI,GAAG,MAAM,EAAE,WAAW,EAAE,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;YACnE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,IAAI,EAAE,EAAE,CAAA;QAC/D,CAAC,CAAC,CAAA;QACJ,2DAA2D;QAC3D,OAAO,IAAA,yCAAmB,EAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IAC3C,CAAC;IAED,yDAAyD;IACzD,MAAM,CAAC,MAAM,CAAC,QAAgB,EAAE,EAAU;QACxC,OAAO,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,CAAA;IACzD,CAAC;IAED,wEAAwE;IACxE,MAAM,CAAC,OAAO,CAAC,QAAgB,EAAE,EAAU;QACzC,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,CAAA;QAC3D,IAAI,CAAC,CAAC;YAAE,OAAO,IAAI,CAAA;QACnB,OAAO;YACL,UAAU,EAAE,EAAE;YACd,aAAa,EAAE,CAAC,CAAC,aAAa,EAAE,cAAc,EAAE,CAAC,CAAC,cAAc,EAAE,cAAc,EAAE,CAAC,CAAC,cAAc;YAClG,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,aAAa,EAAE,CAAC,CAAC,aAAa,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW;YACpF,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,mBAAmB,EAAE,IAAI,CAAC,iBAAiB;YAC/D,4DAA4D;YAC5D,IAAI,EAAE,IAAA,2BAAW,EAAC,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC;SAChF,CAAA;IACH,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,IAAI,CAAC,QAAgB,EAAE,EAAU;QACtC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAA;QACrD,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAA;QAEtB,OAAO;YACL,UAAU,EAAE,EAAE;YACd,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,KAAK;YACxB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,WAAW,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS;YACnC,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,MAAM,EAAE,IAAI,CAAC,OAAO;YACpB,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;YAC7C,GAAG,CAAC,IAAA,2BAAW,EAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,GAAG,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;SAC1J,CAAA;IACH,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,QAAiB;QAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,IAAI,IAAA,2BAAU,EAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAA;QAC9F,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;YAC1B,MAAM,EAAE,GAAG,IAAA,gCAAe,EAAC,GAAG,CAAC,CAAA;YAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;YAChC;0EAC8D;YAC9D,OAAO;gBACL,UAAU,EAAE,EAAE,CAAC,UAAU;gBACzB,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,KAAK;gBACxB,QAAQ,EAAE,EAAE,CAAC,QAAQ;gBACrB,WAAW,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS;gBACnC,KAAK,EAAE,IAAI,CAAC,IAAI;aACjB,CAAA;QACH,CAAC,CAAC,CAAA;QAEF,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,OAAO;YACpB,mBAAmB,EAAE,IAAI,CAAC,iBAAiB;YAC3C,oDAAoD;YACpD,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;YACzC,yDAAyD;YACzD,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;YAC7C,kBAAkB,EAAE,IAAI,CAAC,oBAAoB;YAC7C,kEAAkE;YAClE,OAAO,EAAE,qBAAO,CAAC,IAAI,EAAE;YACvB,GAAG,IAAA,yBAAS,EAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC;YAChC,wDAAwD;YACxD,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,MAAM,EAAE,GAAG,IAAA,gCAAe,EAAC,GAAG,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,UAAU,CAAC,CAAA,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;SAC5H,CAAA;IACH,CAAC;IAED,+CAA+C;IAC/C,MAAM,CAAC,UAAU,CAAC,QAAgB,EAAE,EAAU,EAAE,KAAa;QAC3D,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAA;QACrD,IAAI,IAAI;YAAE,IAAA,0BAAU,EAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAA,4BAAY,GAAE,CAAC,EAAE,KAAK,CAAC,CAAA;IACxE,CAAC;IAED,gDAAgD;IAChD,MAAM,CAAC,UAAU,CAAC,QAAgB,EAAE,EAAU,EAAE,KAAgB,EAAE,MAAc;QAC9E,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAA;QACrD,IAAI,IAAI;YAAE,IAAA,2BAAW,EAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAA,4BAAY,GAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;IACjF,CAAC;IAED;;;;;;;OAOG;aACY,kBAAa,GAAiC,EAAE,CAAA;IAK/D;;;;;OAKG;IACH,MAAM,CAAC,oBAAoB,CACzB,EAAgF;QAEhF,IAAI,CAAC,cAAc,GAAG,EAAE,CAAA;IAC1B,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,kBAAkB,CACvB,QAAgB,EAChB,UAAkB,EAClB,OAAe,EACf,QAA+D,EAC/D,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE;IAClB;;;;OAIG;IACH,WAAW,GAAG,CAAC;QAEf,MAAM,GAAG,GAAG,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,IAAA,kCAAe,GAAE,CAAC,CAAA;QACvF,IAAA,+BAAY,EACV,MAAM,EACN,OAAO,EACP,QAAQ,EACR,KAAK,EACL,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,MAAM,CAAC,EACjE,WAAW,CACZ,CAAA;IACH,CAAC;IAED;;;;;;;;;OASG;IACH,MAAM,CAAC,uBAAuB,CAAC,QAAgB,EAAE,UAAkB,EAAE,MAAc,EAAE,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,MAAe;QACtH,MAAM,GAAG,GAAG,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,IAAA,kCAAe,GAAE,CAAC,CAAA;QACvF,IAAA,oCAAiB,EAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;IAClD,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,sBAAsB,CAAC,QAAgB,EAAE,UAAkB;QAChE,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAA;QACnE,IAAI,MAAM;YAAE,IAAA,mCAAgB,EAAC,MAAM,CAAC,CAAA;IACtC,CAAC;IAED;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,kBAAkB,CAAC,QAAgB,EAAE,UAAkB,EAAE,IAAY,EAAE,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE;QAC9F,MAAM,GAAG,GAAG,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,IAAA,kCAAe,GAAE,CAAC,CAAA;QACvF,IAAA,qCAAiB,EAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,MAAM,CAAC,CAAC,CAAA;IAC3G,CAAC;IAED;;;;;;OAMG;IACH;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,iBAAiB,CACtB,QAAgB,EAChB,WAAqB;QAErB,OAAO,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE;YAClC,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;YACtD,OAAO;gBACL,UAAU;gBACV,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,yDAAyD;gBACzD,aAAa,EAAE,IAAI,CAAC,MAAM,EAAE,aAAa,IAAI,IAAI;gBACjD;;;mBAGG;gBACH,uDAAuD;gBACvD,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;gBACpH,MAAM,EAAE,IAAI,CAAC,MAAM;aACpB,CAAA;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAED;;;;;;;;;;OAUG;IACH,MAAM,CAAC,cAAc,CAAC,QAAgB,EAAE,UAAkB;QACxD,MAAM,GAAG,GAAG,IAAA,2BAAU,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACxB,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAA;QACtC,IAAI,MAAM,EAAE,CAAC;YACX,IAAA,mCAAgB,EAAC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,MAAM,CAAC,CAAC,CAAA;QAC/G,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;QAChC,MAAM,SAAS,GAAG,IAAA,uCAAe,EAAC;YAChC,aAAa,EAAE,IAAI,EAAE,aAAa;YAClC,OAAO,EAAE,CAAC,CAAC,IAAI;YACf,UAAU;SACX,CAAC,CAAA;QACF,OAAO,IAAA,+BAAY,EAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,CAAA;IAC1D,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,QAAiB;QACvC,6DAA6D;QAC7D,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;aACrC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,IAAI,IAAA,2BAAU,EAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;aACrD,GAAG,CAAC,GAAG,CAAC,EAAE;YACT,MAAM,EAAE,GAAG,IAAA,gCAAe,EAAC,GAAG,CAAC,CAAA;YAC/B,OAAO,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,UAAU,CAAC,CAAA;QACjD,CAAC,CAAC;aACD,MAAM,CAAC,OAAO,CAAC,CAAA;QAClB,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAA;QAC1C,2FAA2F;QAC3F,MAAM,KAAK,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAA;QAC7F,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;QAClE;yDACiD;QACjD,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;QACpE,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACpI,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAA;YACpC,CAAC,CAAC,OAAO,GAAG,EAAE,CAAA;YACd,CAAC,CAAC,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAA;YACvC,CAAC,CAAC,IAAI,GAAG,CAAC,EAAE,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,UAAU,CAAA;QACvD,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;;;;;;;OAQG;IAEH;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,qBAAqB,CAAC,QAAgB,EAAE,UAAkB,EAAE,SAAkB;QACzF,MAAM,GAAG,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;QAC1G,IAAI,CAAC,GAAG,EAAE,KAAK;YAAE,OAAO,IAAI,CAAA;QAC5B,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAClC,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAqB,CAAC,CAAC,CAAA;QAC3F,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,KAAqB,CAAC,CAAA;QAC1C,IAAI,CAAC,eAAe,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,EAAE,UAAU,CAAC,CAAA,CAAC,kCAAkC;QACjF,MAAM,IAAI,CAAC,iBAAiB,CAAC,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,CAAC,KAAK,CAAC,CAAA,CAAC,kCAAkC;QACnG,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;QAC9F,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAA;QACvB,MAAM,MAAM,GAAG,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAA;QACnE;;;;;;;WAOG;QACH,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC,CAAA;QAC5J,MAAM,MAAM,GAAG,IAAI,GAAG,EAAe,CAAA;QACrC,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,GAAG,CAAC,GAAG,MAAM;gBAAE,SAAQ;YACjF,MAAM,CAAC,GAAI,CAAC,CAAC,OAAe,EAAE,IAAI,CAAA;YAClC,IAAI,CAAC,EAAE,OAAO;gBAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;QAC1C,CAAC;QACD,CAAC,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QAC9C,OAAO,CAAC,CAAA;IACV,CAAC;IAED,wCAAwC;IACxC,MAAM,CAAC,QAAQ,CAAC,QAAgB,EAAE,EAAU;QAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAA;QACrD,IAAI,IAAI,EAAE,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAC5C;;wDAE4C;YAC5C,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAA;YACpC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAA,gCAAW,EAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QAClD,CAAC;QACD,OAAO,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,IAAI,CAAC,SAAS,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAA;IAC5E,CAAC;;AArkHH,gCAskHC","sourcesContent":["/*\n * TwinEngine โ€” operato-twin ์ปค๋„ ์ธ์Šคํ„ด์Šค๋ฅผ things-factory ์œ„์—์„œ ํ˜ธ์ŠคํŒ….\n * integration-base ์˜ ScenarioEngine ํŒจํ„ด ๋ฏธ๋Ÿฌ: ๋ฉ”๋ชจ๋ฆฌ ์ธ์Šคํ„ด์Šค ๋งต + ๋ฐฑ๊ทธ๋ผ์šด๋“œ tick + pubsub ์ƒํƒœ ๋ฐœํ–‰.\n *\n * ์ปค๋„(zero-dep, ESM+CJS ์ด์ค‘๋ฐฐํฌ)์€ CJS require ๋กœ ๋กœ๋“œ(Node 20 CommonJS ์†Œ๋น„ โ€” require(ESM) ํšŒํ”ผ). (vocabulary-guard: allow โ€” Node ๋Ÿฐํƒ€์ž„ ๋ฒ„์ „ ํ‘œ๊ธฐ)\n * ์ปค๋„์€ ๊ฒฐ์ •์  ๋…ผ๋ฆฌ ์—ฐ์‚ฐ ์ฝ”์–ด โ€” ์ด host ๊ฐ€ ์ „์†ก(pubsub)ยท์˜์†(TypeORM)ยท์Šค์ผ€์ค„(tick)ยท๋ณต๊ตฌ(replay)๋งŒ ์–‡๊ฒŒ ๋ž˜ํ•‘.\n * (์„ค๊ณ„ SoT: operato-twin/design/integration/things-factory-host.md)\n */\n\nimport { twinLog, twinWarn, twinError } from './log.js'\nimport { pubsub, getRepository, Domain } from '@things-factory/shell'\n/* ์ €๋„์„ ์ž๋ฅผ ์กฐ๊ฑด์€ SQL ์ด ์•ˆ๋‹ค โ€” ๊ด€์šฉ๊ตฌ๋งŒ ์“ด๋‹ค(์›์‹œ SQL ์€ 5๊ฐœ ๋“œ๋ผ์ด๋ฒ„์—์„œ ๊ฐˆ๋ผ์ง„๋‹ค). */\nimport { And, IsNull, LessThanOrEqual, MoreThan } from 'typeorm'\nimport { cacheService } from '@things-factory/cache-service'\n\nimport type { ReducerCheckpoint } from '@operato/twin-kernel'\nimport type { OeeCheckpoint } from './oee-accumulator.js'\nimport { TwinEvent } from '../service/twin-event/twin-event.js'\nimport { twinEventKeys } from '../service/twin-event/twin-event-keys.js'\nimport { planLiveContinuity, planWarmStart, unwrapState } from './warm-start.js'\nimport { applyDeclarationLayers } from './local-declarations.js'\nimport { isOfDomain, parseRuntimeKey, runtimeKey } from './runtime-key.js'\nimport { routeCommand } from './command-routing.js'\nimport { TwinInstance } from '../service/twin-instance/twin-instance.js'\n/* ์ž๊ทน์˜ ์ง‘์€ ์›๋ณธ์ด๋‹ค(ADR-0029) โ€” ๊ทธ ํ–‰์„ ์ฝ๊ณ  ์“ด๋‹ค. */\nimport { TwinReference } from '../service/reference/twin-reference.js'\nimport { TwinStructure } from '../service/twin-structure/twin-structure.js'\nimport { TwinSpace } from '../service/twin-space/twin-space.js'\nimport { utcOffsetOf } from '../service/reference/reference-master.js'\nimport { TwinSpaceRepresentation } from '../service/twin-space/twin-space-representation.js'\nimport { TwinSpaceArea } from '../service/twin-space/twin-space-area.js'\nimport { TwinArea } from '../service/twin-space/twin-area.js'\nimport { masterToTwin, type ReferenceMaster } from '../service/reference/reference-master.js'\nimport { resolveIngestSpace } from '../service/reference/ingest-space.js'\nimport { type IngestWarning, describeWarnings, unresolvedReference, projectionFailed, structureAdopted, generationWithoutTimeZone } from '../service/reference/reference-master.js'\nimport { projectStructure } from '../service/twin-model/project-structure.js'\nimport { buildTravelEstimator, chainEstimators } from './travel-estimator.js'\nimport { buildMeasuredEstimator } from './measured-estimator.js'\nimport { buildYieldEstimator } from './measured-yield.js'\nimport { planStimulus, withStimulus } from './declared-stimulus.js'\nimport { readRestartPolicy, type RestartPolicy } from './restart-policy.js'\nimport { describeModelBasis, type ModelBasis } from './model-basis.js'\nimport { computeTwinKpi } from './kpi-query.js'\nimport { createHash } from 'node:crypto'\n\nimport { buildEntityDeltas } from '@things-factory/headless-twin/dist-shared/entity-delta.js'\nimport { fleetLoad, judgeCycle, loadSummary, newLoadMeter, recordFork, recordPhase, slowTickMessage, type LoadMeter, type LoadPhase } from './load-meter.js'\nimport { loopLag } from './loop-lag.js'\nimport { touchedItemKeys } from '@things-factory/headless-twin/dist-shared/touched-items.js'\nimport { diffStructures, type StructureDiff } from './structure-diff.js'\nimport { OeeAccumulator, withLiveOee } from './oee-accumulator.js'\nimport { withLiveAttentions } from './live-attentions.js'\nimport { digestAttentions, mergeLensAttentions } from './attention-digest.js'\n\nimport { liveFeedStateOf } from './live-feed-registry.js'\nimport {\n ingestHealth,\n newIngestLedger,\n recordIngest,\n recordReadFailure,\n clearReadFailure,\n rollIngestWindow,\n /* ๋ณ„์นญ โ€” ๊ฐ™์€ ์ด๋ฆ„์˜ ์ •์  ๋ฉ”์„œ๋“œ์™€ ํ—ท๊ฐˆ๋ฆฌ์ง€ ์•Š๊ฒŒ(๊ทธ ๋ฉ”์„œ๋“œ๊ฐ€ ์ด๊ฒƒ์„ ๋ถ€๋ฅธ๋‹ค). */\n recordJournalWrite as recordLedgerWrite,\n type IngestHealthView,\n type IngestLedger,\n type IngestWindow\n} from './ingest-health.js'\nimport { EMS_PROPERTY } from '@operato/twin-kernel'\nimport type { TwinKernel, TwinModelDef, StructureShift, SubscriptionMessage, TwinRuntime as TwinRuntimeType, CanonicalEnvelope } from '@operato/twin-kernel'\n\n/* ์ปค๋„ ๋Ÿฐํƒ€์ž„ ๋กœ๋“œ โ€” CJS ๋ฒˆ๋“ค(dist-cjs). ํƒ€์ž…์€ ์œ„ import type ๋กœ. replay = ์ด๋ฒคํŠธ์—ดโ†’์ƒํƒœ ์žฌ๊ตฌ์„ฑ(๋ณต๊ตฌยท์‹œ๊ฐ„์—ฌํ–‰). */\nconst { WmsKernel, YmsKernel, MesKernel, EmsKernel, TwinRuntime, StateProjector, replay, replayFrom, replayWithCheckpoint, replaySegments, readBoardLocations, readBoardEquipment, DOMAIN_CATALOG, OP_EVENT, validateScenario } = require('@operato/twin-kernel')\n\nconst KERNELS: Record<string, any> = { wms: WmsKernel, yms: YmsKernel, mes: MesKernel, ems: EmsKernel }\n\n/**\n * ์‹œ๊ฐ์ถ•์„ ๊ตฌํ•  ๋•Œ ํ•œ ๋ฒˆ์— ๋„์šฐ๋Š” ํŠธ์œˆ ์ˆ˜.\n *\n * ํŠธ์œˆ๋งˆ๋‹ค ์™•๋ณต์ด ๋‘˜์ด๋ผ, ๊ณต๊ฐ„์— ํŠธ์œˆ์ด ์ˆ˜๋ฐฑ์ด๋ฉด ๋™์‹œ ์™•๋ณต๋„ ์ˆ˜๋ฐฑ์ด ๋œ๋‹ค โ€” ์ปค๋„ฅ์…˜ ํ’€์ด ๋งˆ๋ฅด๋ฉด ์ด\n * ํ•จ์ˆ˜ ํ•˜๋‚˜ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ์งˆ์˜๊ฐ€ ์ค„์„ ์„ ๋‹ค. 20์ด๋ฉด ์™•๋ณต 40๊ฐœ๋กœ ์ง€์—ฐ์€ ๊ฐ์ถ”๋ฉด์„œ ํ’€์€ ๋‚จ๋Š”๋‹ค.\n */\nconst TIME_RANGE_FANOUT = 20\n\n/**\n * DB ๊ฐ€ ์ค€ ์‹œ๊ฐ์„ epoch ms ๋กœ โ€” **๋ชจ์–‘์ด ๋“œ๋ผ์ด๋ฒ„๋งˆ๋‹ค ๋‹ค๋ฅด๋‹ค.**\n *\n * ์ง‘๊ณ„(MIN/MAX)์˜ ๋ฐ˜ํ™˜์€ ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ์ •ํ•œ๋‹ค: sqlite ๋Š” ๋ฌธ์ž์—ด, pgยทmysqlยทmssql ์€ `Date`. ์—”ํ‹ฐํ‹ฐ\n * ํ•˜์ด๋“œ๋ ˆ์ด์…˜์„ ๊ฑด๋„ˆ๋›ฐ๋ฉด TypeORM ์˜ ๋‚ ์งœ ๋ณ€ํ™˜๋„ ํ•จ๊ป˜ ๊ฑด๋„ˆ๋›ฐ๋ฏ€๋กœ ๋ฐ›๋Š” ์ชฝ์—์„œ ํ•œ ๋ฒˆ ์ •๊ทœํ™”ํ•œ๋‹ค.\n *\n * โ”€โ”€ ์‹œ๊ฐ„๋Œ€๋ฅผ ์žƒ์ง€ ์•Š๋Š”๋‹ค (์‹œํ—˜์ด ์žก์•˜๋‹ค) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ฒ˜์Œ์— `Date.parse(String(v))` ๋กœ ๋‘์—ˆ๋”๋‹ˆ **9์‹œ๊ฐ„์ด ๋ฐ€๋ ธ๋‹ค.** sqlite ๋Š” UTC ๋กœ ์ €์žฅํ•œ ๊ฐ’์„\n * `2026-01-15 09:00:00.000` ์ฒ˜๋Ÿผ **์‹œ๊ฐ„๋Œ€ ํ‘œ์‹œ ์—†์ด** ๋Œ๋ ค์ฃผ๋Š”๋ฐ, ๊ทธ ํ˜•ํƒœ๋ฅผ `Date.parse` ๋Š” **๋กœ์ปฌ\n * ์‹œ๊ฐ**์œผ๋กœ ์ฝ๋Š”๋‹ค(์—ฌ๊ธฐ๊ฐ€ KST ๋ผ UTC 00:00 ์ด ๋๋‹ค). ์›๋ž˜ ์ฝ”๋“œ๊ฐ€ ์ด ํ•จ์ •์„ ํ”ผํ•œ ๊ฒƒ์€ TypeORM ์ด\n * ํ•˜์ด๋“œ๋ ˆ์ด์…˜์—์„œ ๋จผ์ € `Date` ๋กœ ๋ฐ”๊ฟ” ์คฌ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค โ€” ๊ทธ ๋‹จ๊ณ„๋ฅผ ๊ฑด๋„ˆ๋›ด ๋Œ€๊ฐ€๋ฅผ ์—ฌ๊ธฐ์„œ ์น˜๋ฅธ๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ ์‹œ๊ฐ„๋Œ€ ํ‘œ์‹œ๊ฐ€ **์—†๋Š” ๋ฌธ์ž์—ด์€ UTC ๋กœ ์ฝ๋Š”๋‹ค**(TypeORM ์ด UTC ๋กœ ์ ์œผ๋ฏ€๋กœ). ํ‘œ์‹œ๊ฐ€ ์žˆ์œผ๋ฉด\n * ๊ทธ๋Œ€๋กœ ๋ฏฟ๊ณ , `Date` ๋Š” ์†๋Œ€์ง€ ์•Š๋Š”๋‹ค.\n *\n * ์ฝ์„ ์ˆ˜ ์—†๋Š” ๊ฐ’์€ **์—†์Œ(`null`)** ์ด๋‹ค โ€” 0 ์œผ๋กœ ๋–จ์–ด๋œจ๋ฆฌ๋ฉด 1970๋…„์ด ์‹œ๊ฐ์ถ•์˜ ์‹œ์ž‘์ด ๋œ๋‹ค.\n */\nfunction parseTime(v: unknown): number | null {\n if (v == null) return null\n if (v instanceof Date) return Number.isFinite(v.getTime()) ? v.getTime() : null\n\n const s = String(v).trim()\n if (!s) return null\n /* ๋์— `Z` ๋‚˜ `ยฑhh:mm` ์ด ๋ถ™์–ด ์žˆ์œผ๋ฉด ์‹œ๊ฐ„๋Œ€๋ฅผ ์•„๋Š” ๋ฌธ์ž์—ด์ด๋‹ค โ€” ๊ทธ๋Œ€๋กœ ๋ฏฟ๋Š”๋‹ค. */\n const zoned = /(?:Z|[+-]\\d{2}:?\\d{2})$/.test(s)\n const t = Date.parse(zoned ? s : `${s.replace(' ', 'T')}Z`)\n return Number.isFinite(t) ? t : null\n}\n\n/**\n * ์ข…๋ฅ˜ ๋ฌธ์ž์—ด โ†’ ์ปค๋„. **๋ชจ๋ฅด๋Š” ๊ฐ’์ด๋ฉด ์˜ค๋ฅ˜๋ฅผ ๋‚ธ๋‹ค.**\n *\n * ์˜ˆ์ „์—๋Š” ํ‘œ๋ฅผ ์ฐพ๊ณ  ์—†์œผ๋ฉด WmsKernel ๋กœ ๋–จ์–ด์กŒ๋‹ค. `kind` ๋Š” ๊ฒ€์ฆ ์—†๋Š” ์ž์œ  ๋ฌธ์ž์—ด(`@Arg('kind') kind: string`)\n * ์ด๋ผ ์˜คํƒ€ ํ•˜๋‚˜ยท๋Œ€์†Œ๋ฌธ์ž ํ•˜๋‚˜๋กœ ์•ผ๋“œ/์ƒ์‚ฐ ํŠธ์œˆ์ด **์กฐ์šฉํžˆ ์ฐฝ๊ณ  ์ปค๋„๋กœ ๋Œ์•˜๋‹ค.** ์˜ค๋ฅ˜๊ฐ€ ์—†์œผ๋‹ˆ ํ™”๋ฉด์—๋Š”\n * ํŠธ์œˆ์ด ์ •์ƒ์œผ๋กœ ๋ณด์ด๊ณ , ์•ˆ์—์„œ ๋„๋Š” ๊ทœ์น™๋งŒ ๋‹ค๋ฅธ ๋„๋ฉ”์ธ์˜ ๊ฒƒ์ด๋‹ค. ์˜ˆ์ธก ๊ฒฝ๋กœ๊ฐ€ ๊ฐ€์žฅ ๋‚˜์˜๋‹ค โ€”\n * ์•ผ๋“œ์˜ ๋ฏธ๋ž˜๋ฅผ ์ฐฝ๊ณ  ๊ทœ์น™์œผ๋กœ ์‹คํ–‰ํ•ด ๋†“๊ณ  ์ˆซ์ž๋งŒ ๋œฌ๋‹ค.\n *\n * ํ‹€๋ฆฐ ๊ณต์žฅ์„ ์กฐ์šฉํžˆ ๋„์šฐ๋Š” ๊ฒƒ๋ณด๋‹ค ๋œจ์ง€ ์•Š๋Š” ํŽธ์ด ๋‚ซ๋‹ค.\n */\nfunction kernelFor(kind: string): any {\n const K = KERNELS[kind]\n if (!K) throw new Error(`unknown twin kind \"${kind}\" โ€” expected one of ${Object.keys(KERNELS).join(' | ')}`)\n return K\n}\n\n/** `observe()` ๋ฅผ ๊ฐ–์ง€ ์•Š์€ ์ปค๋„์„ ๋งŒ๋‚œ ์ ์ด ์žˆ๋Š”๊ฐ€ โ€” ๊ฒฝ๊ณ ๋ฅผ ํ•œ ๋ฒˆ๋งŒ ๋‚ธ๋‹ค(ํ‹ฑ๋งˆ๋‹ค ์Ÿ์ง€ ์•Š๋Š”๋‹ค). */\nlet observeUnavailableWarned = false\n\n/**\n * **์ด ์ปค๋„์˜ ์ง„์‹ค์ด ์›๋ณธ์—์„œ ์˜จ๋‹ค๊ณ  ์„ ์–ธํ•œ๋‹ค** โ€” ๊ทธ๋ฆฌ๊ณ  ์„ ์–ธ์ด ๋‹ฟ์ง€ ์•Š์•˜์œผ๋ฉด ๋งํ•œ๋‹ค.\n *\n * โ”€โ”€ ๋ฌด์—‡์ด ํ‹€๋ ธ๋‚˜ (2026-08-21) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์˜ˆ์ „์—๋Š” `kernel.observe?.()` ์˜€๋‹ค. ์˜ต์…”๋„ ํ˜ธ์ถœ์ด๋ผ **๋ฉ”์„œ๋“œ๊ฐ€ ์—†์œผ๋ฉด ์กฐ์šฉํžˆ ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š๋Š”๋‹ค.**\n * ์„ค์น˜๋œ ์ปค๋„ 0.7.39 ์—๋Š” ๊ทธ ๋ฉ”์„œ๋“œ๊ฐ€ ์—†์œผ๋ฏ€๋กœ, ์ง€๊ธˆ ๋ฐฐํฌ๋ณธ์—์„œ๋Š” ๋ฏธ๋Ÿฌ๊ฐ€ ๊ด€์ธก ๊ตฌ๋™์œผ๋กœ ์„ ์–ธ๋˜์ง€\n * ์•Š๋Š”๋‹ค โ€” ๊ทธ๋Ÿฐ๋ฐ ์ฝ”๋“œ๋ฅผ ์ฝ์œผ๋ฉด ์„ ์–ธํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค.\n *\n * ๊ทธ ์ฐจ์ด๊ฐ€ ์‹ค์ œ ๊ฑฐ๋™์„ ๊ฐ€๋ฅธ๋‹ค: ๊ด€์ธก ๊ตฌ๋™์€ ์›๋ณธ์˜ ๋นˆํ‹ˆ์„ ๋ฐ›์•„๋“ค์ด๊ณ  ์„ธ์ง€๋งŒ, ์‹œ๋ฎฌ๋กœ ์˜ค์ธ๋œ ๋ฏธ๋Ÿฌ๋Š”\n * **๋ฉˆ์ถ˜๋‹ค.** ์ฆ‰ ใ€Œ๊ด€์šฉ์ด ์ผœ์ง„ ์ค„ ์•Œ์•˜๋Š”๋ฐ ์•ˆ ์ผœ์ ธ ์žˆ๋‹คใ€๊ฐ€ ์กฐ์šฉํžˆ ์ง€๋‚˜๊ฐ€๊ณ , ์žฅ์• ๊ฐ€ ๋‚ฌ์„ ๋•Œ ์›์ธ์ด\n * ์ปค๋„์— ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค โ€” ์›์ธ์€ ๋ฒ„์ „์ด๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ ์˜ต์…”๋„ ํ˜ธ์ถœ์„ ์—†์• ๊ณ , ์—†์œผ๋ฉด **ํ•œ ๋ฒˆ ๊ฒฝ๊ณ ํ•œ๋‹ค.** ์ปค๋„์ด ๋ฐฐํฌ๋˜๋ฉด ์ด ๊ฒฝ๊ณ ๋Š” ์‚ฌ๋ผ์ง„๋‹ค.\n */\nfunction declareObserved(kernel: any, what: string): void {\n if (typeof kernel?.observe === 'function') {\n kernel.observe()\n return\n }\n if (observeUnavailableWarned) return\n observeUnavailableWarned = true\n twinWarn(\n `[twin-engine] ${what}: kernel has no observe() โ€” this mirror is not declared observation-driven. ` +\n 'Source gaps will stop it instead of being tolerated and counted. Deploy a kernel that provides observe().'\n )\n}\n\n/* ๋ผ์ด๋ธŒ ์ฒ˜๋ฆฌ๋Ÿ‰ ๊ณ„์ธก(๋ชจ๋‹ˆํ„ฐ) โ€” ์œ ์ž…/๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…/์ €๋„๋ฅ ยท๋ฐฑ๋กœ๊ทธ. ์‹ค ๋™๊ธฐ ์ธํ„ฐํŽ˜์ด์Šค ๋ถ€ํ•˜๋ฅผ ์ฝ๋Š” ์ผ๊ธ‰ ์ง€ํ‘œ. */\ninterface TwinMetrics {\n ingestedTotal: number // ๋ˆ„์  ์œ ์ž… ์ด๋ฒคํŠธ\n broadcastTotal: number // ๋ˆ„์  ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ… ํšŸ์ˆ˜\n journaledTotal: number // ๋ˆ„์  ์ €๋„ ๊ธฐ๋ก ์ด๋ฒคํŠธ\n ingestRate: number // ์ตœ๊ทผ ์œ ์ž…๋ฅ (ev/s)\n broadcastRate: number // ์ตœ๊ทผ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…๋ฅ (ํšŒ/s)\n journalRate: number // ์ตœ๊ทผ ์ €๋„๋ฅ (ev/s)\n /**\n * **์ง€๊ธˆ ๋Œ€๊ธฐ ์ค‘์ธ** ์ €๋„ ๊ฑด์ˆ˜ โ€” ์•„์ง DB ๋กœ ๋‚˜๊ฐ€์ง€ ์•Š์€ ๊ฒƒ.\n *\n * โ”€โ”€ ๋ฌด์—‡์ด ํ‹€๋ ธ์—ˆ๋‚˜ (2026-08-21) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์˜ˆ์ „์—๋Š” ใ€Œ๋งˆ์ง€๋ง‰ flush ์—์„œ ์“ด ๊ฑด์ˆ˜ใ€๋ฅผ ์—ฌ๊ธฐ ๋„ฃ์—ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ 200ms ๋งˆ๋‹ค ๋ชจ์•„ ํ•œ ๋ฌธ์œผ๋กœ ๋„ฃ๋Š” ๊ฒƒ์€\n * **์ •์ƒ ๋™์ž‘**์ด๋‹ค(๊ทธ๋ ‡๊ฒŒ ๋งŒ๋“  ๊ฒƒ์ด ์–ด์ œ ๊ณ ์นœ ์„ฑ๋Šฅ ์ž‘์—…์ด๋‹ค). ๊ทธ๋ž˜์„œ ์ •์ƒ์ ์œผ๋กœ 10๊ฑด์„ ์“ด ์งํ›„\n * ํ™”๋ฉด์— ใ€Œ๋ฐ€๋ฆผ 10ใ€ ๊ฒฝ๊ณ ๊ฐ€ ๋–ด๊ณ , ๋‹ค์Œ flush ๊นŒ์ง€ ๊ทธ ๊ฐ’์ด ๋‚จ์•˜๋‹ค โ€” ํ๋Š” ์ด๋ฏธ 0 ์ธ๋ฐ๋„.\n *\n * ์šด์˜์ž์—๊ฒŒ ๊ทธ๊ฒƒ์€ ใ€Œ์ €์žฅ์ด 10๊ฑด ๋ฐ€๋ ค ์žˆ๋‹คใ€๋กœ ์ฝํžŒ๋‹ค. ๊ฑฐ์ง“ ๊ฒฝ๋ณด๋Š” ์ฐธ ๊ฒฝ๋ณด๋ฅผ ์ฃฝ์ธ๋‹ค.\n *\n * ์ด์ œ ์ด ๊ฐ’์€ **์ง€๊ธˆ ๋‚จ์•„ ์žˆ๋Š” ๊ฒƒ**์ด๋‹ค: ๋‹ค ๋‚˜๊ฐ”์œผ๋ฉด 0 ์ด๊ณ , ์ •๋ง๋กœ ์Œ“์ด๋Š” ์ค‘์ด๋ฉด ๊ทธ ์ˆ˜๊ฐ€ ์ž๋ž€๋‹ค.\n */\n backlog: number\n // ์ฐฝ(window) ์ง‘๊ณ„์šฉ ๋‚ด๋ถ€ ๋ˆ„์ \n _accIngest: number\n _accBroadcast: number\n _accJournal: number\n _windowStartMs: number\n}\n\n/*\n * ์žฌ๊ธฐ๋™ ์ •์ฑ…์€ **์„ ์–ธ์ด๊ณ  ๊ธฐ๋ณธ๊ฐ’์ด ์—†๋‹ค** โ€” ์ •์˜ยทํŒ์ •์€ `engine/restart-policy.ts` ๊ฐ€ ๋“ ๋‹ค(ADR-0029 ยง2).\n *\n * ์˜ˆ์ „์—๋Š” ์—ฌ๊ธฐ์— `DEFAULT_REALITY_MODE = 'sim-experiment'` ๊ฐ€ ์žˆ์—ˆ๊ณ , ๋ฏธ์„ ์–ธ์ด ์กฐ์šฉํžˆ **์ €๋„ ์ดˆ๊ธฐํ™”**๋กœ\n * ๋–จ์–ด์กŒ๋‹ค. ๊ทธ ๊ด€์šฉ์€ ๊ฐ’์ด ํ•˜๋‚˜ ์–ด๊ธ‹๋‚˜๋Š” ์ˆœ๊ฐ„ ์ด๋ ฅ์„ ์ง€์šฐ๋Š” ๊ธธ์ด ๋œ๋‹ค โ€” ๊ทธ๋ž˜์„œ ์—†์•ด๋‹ค.\n */\nexport type { RestartPolicy } from './restart-policy.js'\n\n/* ์ธ๋ฉ”๋ชจ๋ฆฌ ๋ผ์ด๋ธŒ ๋Ÿฐํƒ€์ž„ ํ™€๋”(์˜์† ์—”ํ‹ฐํ‹ฐ TwinInstance ์™€ ๊ตฌ๋ถ„). */\ninterface InstanceRuntime {\n /** ๋ถ€ํ•˜ ๊ณ„๊ธฐํŒ โ€” ์ž‘์—…๋ณ„ ์†Œ์š”. ์‹œ๋ฎฌยท๋ผ์ด๋ธŒ ๋ชจ๋‘ ๋ถ™๋Š”๋‹ค(๋ˆ„๊ฐ€ ๋ฃจํ”„๋ฅผ ์ ์œ ํ•˜๋Š”์ง€ ๋ณด๋ ค๋ฉด ๋‘˜ ๋‹ค ํ•„์š”ํ•˜๋‹ค). */\n load?: LoadMeter\n /** ํ˜„์‹ค ์ถœ์ฒ˜ ์„ ์–ธ(ยง0 ํ”„๋ ˆ์ž„ โ‘ ). ๋ถ€ํŒ… ๊ฑฐ๋™(reset/resume/resync)์˜ ๊ทผ๊ฑฐ. */\n restartPolicy?: RestartPolicy\n id: string\n domainId: string\n domain?: any // ๋ผ์ด๋ธŒ ๋ฐ”์ธ๋”ฉ(data ์ฑ„๋„)์šฉ Domain ๊ฐ์ฒด(subdomain ํ•„ํ„ฐ). start ์‹œ ๋น„๋™๊ธฐ ํ•ด์„.\n runtime?: TwinRuntimeType // sim: ์ปค๋„ ๋Ÿฐํƒ€์ž„(tick/subscribe/dispatch). live ๋Š” projector ์‚ฌ์šฉ.\n kernel?: any // sim: ForecastTwin(fork/getSnapshot/tick/scenario). live ๋ฏธ์‚ฌ์šฉ.\n mode?: 'sim' | 'live' // ์ƒํƒœ ๋“œ๋ผ์ด๋ฒ„ โ€” sim=์ปค๋„ tick / live=projector ๋ฏธ๋Ÿฌ(face2-inbound-live). ๋ฏธ์ง€์ •=sim.\n /** ์ด ํŠธ์œˆ์ด ์„  ํ˜„์žฅ โ€” ๊ฐ™์€ ํ˜„์žฅ์˜ ํŠธ์œˆ๋ผ๋ฆฌ ์„œ๋กœ์˜ ์„ค๋น„ ์ƒํƒœ๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ์—ด์‡ . */\n spaceId?: string\n /**\n * live ์˜ ์ƒํƒœ ์ ‘๊ทผ ์–ด๋Œ‘ํ„ฐ โ€” ์ด์ œ **๊ด€์ธก ๋ชจ๋“œ ์ปค๋„**์„ ๊ฐ€๋ฆฌํ‚จ๋‹ค(`kernel` ๊ณผ ๊ฐ™์€ ๊ฒƒ).\n * ์ด๋ฆ„์€ ์†Œ๋น„์ฒ˜ ํ˜ธํ™˜์œผ๋กœ ๋‚จ์•˜๊ณ , P3 ์—์„œ ์ปค๋„ ์–ดํœ˜๋กœ ์ •๋ฆฌํ•˜๋ฉด ์‚ฌ๋ผ์ง„๋‹ค.\n */\n projector?: any\n oee?: OeeAccumulator // live: OEE ๊ณ„์‚ฐ ์ธต(์ด๋ฒคํŠธ ๋ˆ„์  โ†’ equipment payload ๋ณด๊ฐ•). sim ์€ ์ปค๋„์ด ๊ณ„์‚ฐ.\n unsub: () => void\n /**\n * ๋ฐฉ๊ธˆ ์ธ์ž…ํ•œ ๋ด‰ํˆฌ๋“ค โ€” ์ปค๋„์ด ๊ทธ๊ฒƒ์„ ์žฌ๋ฐฉ์ถœํ•  ๋•Œ **์ €๋„์— ๋‘ ๋ฒˆ ์ ์ง€ ์•Š๊ธฐ** ์œ„ํ•œ ํ‘œ์‹œ.\n * ๋ผ์ด๋ธŒ๋งŒ ์“ด๋‹ค(sim ์€ ์ปค๋„์ด ์Šค์Šค๋กœ ๋‚ธ ๊ฒƒ๋งŒ ํ˜๋ฆฐ๋‹ค). ์•ฝํ•œ ์ฐธ์กฐ๋ผ ๋”ฐ๋กœ ๋น„์šธ ๊ฒƒ์ด ์—†๋‹ค.\n */\n applying?: WeakSet<object>\n timer?: any\n /** ์—”ํ‹ฐํ‹ฐ๋ณ„ ๋งˆ์ง€๋ง‰ ๋ฐœํ–‰ ์‹œ๊ทธ๋‹ˆ์ฒ˜ โ€” ๊ฐ’์ด ๋ฐ”๋€ ์—”ํ‹ฐํ‹ฐ๋งŒ ์žฌ๋ฐœํ–‰(๋ฌด๋ณ€ํ™” ๋ฐ˜๋ณต push ๋ฐฉ์ง€). */\n entitySigs?: Map<string, string>\n /** live ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ… ๋ณ‘ํ•ฉ(ingest-scale ยง4.4) โ€” ingest ๋งˆ๋‹ค ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…ํ•˜์ง€ ์•Š๊ณ  dirty ํ‘œ์‹œ โ†’ coalescer tick ์ด ์ฃผ๊ธฐ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…. */\n dirty?: boolean\n /**\n * ์ด ์ฐฝ์— **๊ฑด๋“œ๋ฆฐ ๋ฌผํ’ˆ ํƒœ๊ทธ** โ€” ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์ด ๊ทธ๊ฒƒ๋งŒ ๋งŒ๋“ ๋‹ค.\n *\n * `undefined` ๋Š” ใ€Œ๋งํ•  ์ˆ˜ ์—†๋‹คใ€๋‹ค(๋‚ฏ์„  ์‚ฌ๊ฑด์ด ํ•˜๋‚˜๋ผ๋„ ์™”๋‹ค) โ†’ ์ „๋ถ€ ๋งŒ๋“ ๋‹ค. ๋นˆ ์ง‘ํ•ฉ์€ ใ€Œ๋ฌผํ’ˆ์€\n * ํ•˜๋‚˜๋„ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š์•˜๋‹คใ€์ด๊ณ , ๊ทธ ๋‘˜์€ ๋‹ค๋ฅธ ์‚ฌ์‹ค์ด๋‹ค.\n */\n dirtyItems?: Set<string>\n /** ๋‹ค์Œ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์—์„œ ์ „๋ถ€ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋‚˜ โ€” ์ฃผ๊ธฐ๋งˆ๋‹ค ํ•œ ๋ฒˆ์€ ๊ทธ๋ฌผ๋กœ ์ „๋ถ€ ๋งŒ๋“ ๋‹ค. */\n fullBroadcastDue?: boolean\n /** ์ „๋ถ€ ๋งŒ๋“ค๊ธฐ๊นŒ์ง€ ๋‚จ์€ ์ฐฝ ์ˆ˜. */\n fullBroadcastCountdown?: number\n /** live ์ €๋„ ๊ฒฐ์„  โ€” ingest ์ด๋ฒคํŠธ๋ฅผ ๋ชจ์•˜๋‹ค๊ฐ€ coalescer tick ์—์„œ ๋ฐฐ์น˜ ๊ธฐ๋ก(์ด๋ฒคํŠธ๋งˆ๋‹ค DB write ๊ธˆ์ง€). */\n pendingJournal?: any[]\n /** live ์ €๋„ revision ์นด์šดํ„ฐ(sim ์˜ delta revision ๋Œ€์‘ โ€” ์‹œ๊ฐ„์—ฌํ–‰ยทํžˆ์Šคํ† ๋ฆฌ ๋…ธ๋ธŒ ์•ต์ปค). */\n revision?: number\n /** live ์ฒ˜๋ฆฌ๋Ÿ‰ ๊ณ„์ธก(๋ชจ๋‹ˆํ„ฐ, โ‘ฃ-1). */\n metrics?: TwinMetrics\n}\n\n/**\n * ํŠธ์œˆ์ด **์Šค์Šค๋กœ ๋ฉˆ์ถ˜ ์ด์œ ** โ€” ๋ฌธ์žฅ์ด ์•„๋‹ˆ๋ผ ์ฝ”๋“œ๋‹ค.\n *\n * ์„œ๋ฒ„๊ฐ€ ๋งŒ๋“  ์˜์–ด ๋ฌธ์žฅ์„ ๊ทธ๋Œ€๋กœ ์‹ค์œผ๋ฉด ํ•œ๊ตญ์–ดยท์ผ๋ณธ์–ด ํ™”๋ฉด์— ๊ทธ ์˜์–ด๊ฐ€ ๋œฌ๋‹ค. ์ด ์‹œ์Šคํ…œ์€ ๊ฑฐ์ ˆ ๋ฉ”์‹œ์ง€์—์„œ\n * ๊ฐ™์€ ๊ฒฐ๋ก ์— ์ด๋ฅด๋ €๋‹ค(์ฝ”๋“œ+ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋‚ด๊ณ  ํ™”๋ฉด์ด ์˜ฎ๊ธด๋‹ค). `reason` ๋งŒ์€ ์›๋ฌธ ๊ทธ๋Œ€๋กœ๋‹ค โ€” ์ปค๋„ยท๋Ÿฐํƒ€์ž„์ด\n * ๋‚ธ ์˜ค๋ฅ˜ ๋ฌธ๊ตฌ๋Š” ์˜ฎ๊ธธ ์ˆ˜ ์žˆ๋Š” ์–ดํœ˜๊ฐ€ ์•„๋‹ˆ๊ณ , ์˜ฎ๊ธฐ๋ ค ๋“ค๋ฉด ์›์ธ์„ ์žƒ๋Š”๋‹ค.\n */\nexport interface StopNote {\n code: 'starved' | 'tick-failed'\n params: Record<string, string | number>\n}\n\nexport class TwinEngine {\n /*\n * ๊ธฐ๋™ ์ค‘์ธ ๋Ÿฐํƒ€์ž„ โ€” **ํ‚ค๋Š” `runtimeKey(domainId, instanceId)`** ๋‹ค(`runtime-key.ts` ์— ์ด์œ ).\n *\n * ์˜ˆ์ „์—” `instanceId` ํ•˜๋‚˜๋กœ ํ‚ค๋ฅผ ์žก์•˜๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ •์ฒด์„ฑ์€ `(domain, instanceId)` ์ด๊ณ  DB ์œ ์ผ์„ฑ๋„\n * ๊ทธ์ชฝ์ด๋ผ, ๋‘ ํ…Œ๋„ŒํŠธ๊ฐ€ ๊ฐ™์€ id ๋ฅผ ์“ฐ๋ฉด(๋ ˆํผ๋Ÿฐ์Šค ๊ฒฝ๋กœ๊ฐ€ ์†Œ์Šค ์ด๋ฆ„์„ id ๋กœ ์“ด๋‹ค) ํ•œ ์ž๋ฆฌ๋ฅผ ๋‹คํ‰œ๋‹ค.\n * **์—”์ง„ ๋ฐ–์—์„œ ์ด ๋งต์„ ์ง์ ‘ ์ƒ‰์ธํ•˜์ง€ ์•Š๋Š”๋‹ค** โ€” `owns`ยท`runtime`ยท`kernel` ๊ฐ™์€ ์ ‘๊ทผ์ž๋ฅผ ์“ด๋‹ค.\n */\n static instances: Record<string, InstanceRuntime> = {}\n /** ๋ผ์ด๋ธŒ ๋Ÿฐํƒ€์ž„์ด ์—†์„ ๋•Œ(๋ณต๊ตฌ ํ›„ ๋ฏธ๊ธฐ๋™) ์ €๋„์—์„œ ์žฌ๊ตฌ์„ฑํ•œ ์ƒํƒœ ์บ์‹œ. */\n /** ์›œ์Šคํƒ€ํŠธ ์”จ์•— โ€” `instances` ์™€ **๊ฐ™์€ ํ‚ค**(๊ฒน์น˜๋ฉด ๋‚จ์˜ ์Šค๋ƒ…์ƒท์œผ๋กœ ์žฌ๊ณ ๊ฐ€ ์„ž์ธ๋‹ค). */\n static recovered: Record<string, any> = {}\n static TICK_MS = 1000\n\n /*\n * โ”€โ”€ ๊ตถ๊น€ ์•ˆ์ „๋ง (2026-08-14) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์‹œ๋ฎฌ ํ‹ฑ์€ **๋ฉ”์ธ ์ด๋ฒคํŠธ ๋ฃจํ”„**์—์„œ ๋ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํ•œ ํŠธ์œˆ์˜ ํ‹ฑ์ด ๊ธธ์–ด์ง€๋ฉด ๊ทธ ์‹œ๊ฐ„๋งŒํผ ํ˜ธ์ŠคํŠธ ์ „์ฒด๊ฐ€\n * ๋ฉˆ์ถ˜๋‹ค โ€” HTTPยท๊ตฌ๋…ยท๋‹ค๋ฅธ ํŠธ์œˆ์˜ ํ‹ฑ๊นŒ์ง€. ์‹ค์ธก์œผ๋กœ `order-check` ์˜ ํ‹ฑ ํ•˜๋‚˜๊ฐ€ 34.9์ดˆ์˜€๊ณ , ๊ทธ ์‚ฌ์ด\n * ๊ตฌ๋…์ž๊ฐ€ ์•„๋ฌด๊ฒƒ๋„ ๋นผ๋‚ด์ง€ ๋ชปํ•ด pubsub ์ด ๋„˜์ณ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ฃฝ์—ˆ๋‹ค.\n *\n * ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ… ๋ฐ˜๋ณต์€ ๊ฑท์–ด๋ƒˆ์ง€๋งŒ(`flushLiveBroadcasts` ๋กœ ๋ณ‘ํ•ฉ) **์ปค๋„ ํ‹ฑ ์ž์ฒด๋Š” ์—ฌ์ „ํžˆ ๋ฉ”์ธ ๋ฃจํ”„์— ์žˆ๋‹ค.**\n * ๊ทผ๋ณธ ํ•ด๊ฒฐ์€ ๋ถ„์‚ฐ์ด๊ณ  ๊ทธ๊ฒƒ์€ ์ด์—ฐ๋๋‹ค โ€” ๊ทธ๋•Œ๊นŒ์ง€์˜ ์•ˆ์ „๋ง์ด ์ด ์…‹์ด๋‹ค.\n *\n * ํŒ์ •์„ ์˜ˆ์‚ฐ(500ms)์ด ์•„๋‹ˆ๋ผ **๊ตถ๊น€ ๋ฌธํ„ฑ**์œผ๋กœ ๋”ฐ๋กœ ๋‘”๋‹ค: ์กฐ๊ธˆ ๋А๋ฆฐ ํŠธ์œˆ์€ ๊ณ„๊ธฐํŒ์ด ๋งํ•˜๊ฒŒ ๋‘๊ณ \n * (๊ฒฝ๊ณ ), ํ˜ธ์ŠคํŠธ๋ฅผ ๊ตถ๊ธฐ๋Š” ํŠธ์œˆ๋งŒ ๋ฉˆ์ถ˜๋‹ค. ํ•œ ๋ฒˆ์œผ๋กœ ๋ฉˆ์ถ”์ง€ ์•Š๋Š”๋‹ค โ€” ์›œ์Šคํƒ€ํŠธ ์งํ›„์˜ ์ฒซ ํ‹ฑ์€ ์›๋ž˜\n * ๋ฌด๊ฒ๋‹ค(๋ณต๊ตฌํ•œ ์ƒํƒœ๋ฅผ ์ฒ˜์Œ ์ ‘๋Š”๋‹ค). **์—ฐ์†**์œผ๋กœ ์ด์–ด์งˆ ๋•Œ๊ฐ€ ๊ตฌ์กฐ์ ์œผ๋กœ ๋А๋ฆฐ ๊ฒƒ์ด๋‹ค.\n */\n /*\n * โ”€โ”€ ํ‹ฑ์„ **ํ•œ ์ˆœ๊ฐ„์— ๋ชฐ์ง€ ์•Š๋Š”๋‹ค** (2026-08-21 ์‹ค์ธก) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ํŠธ์œˆ๋งˆ๋‹ค `setInterval(TICK_MS)` ๋ฅผ ๋ถ€ํŒ… ๋•Œ ๋‚˜๋ž€ํžˆ ์„ธ์šฐ๋ฉด, ์Šค๋ฌด ๊ฐœ๊ฐ€ **๊ฐ™์€ ๋ฐ€๋ฆฌ์ดˆ์—** ๊นจ์–ด๋‚œ๋‹ค.\n * ๊ฐ์ž์˜ ํ‹ฑ์ด ์งง์•„๋„(์‹ค์ธก: ๋ฌผํ’ˆ 2,400 ๊ฐœ์—์„œ 0.23ms) ๊ทธ ์ˆœ๊ฐ„์—๋Š” ์Šค๋ฌด ๊ฐœ๊ฐ€ ํ•œ ์ค„๋กœ ๋ถ™์–ด ์‹คํ–‰๋˜๊ณ ,\n * ๊ทธ ์‚ฌ์ด ๋„์ฐฉํ•œ HTTP ์š”์ฒญ์€ ์ „๋ถ€ ๋’ค์—์„œ ๊ธฐ๋‹ค๋ฆฐ๋‹ค. ์ดˆ๋‹น ํ•œ ๋ฒˆ์˜ ์ •์ฒด๊ฐ€ ใ€Œ๋ˆ„๋ฅผ ๋•Œ๋งˆ๋‹ค ๊ฑธ๋ฆฐ๋‹คใ€๋กœ\n * ๋‚˜ํƒ€๋‚˜๋Š” ์ž๋ฆฌ๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ ์ฒซ ๋ฐœํ™”๋งŒ ๊ฐ„๊ฒฉ ์•ˆ์—์„œ **๊ณ ๋ฅด๊ฒŒ ํฉ๋Š”๋‹ค** โ€” ์ด ์ž‘์—…๋Ÿ‰์€ ๊ฐ™๊ณ  ํ•œ ์ˆœ๊ฐ„์˜ ์ตœ๋Œ€์น˜๋งŒ ๋‚ฎ์•„์ง„๋‹ค.\n * ํŠธ์œˆ์ด ๊ฐ„๊ฒฉ๋ณด๋‹ค ๋งŽ์•„์ง€๋ฉด ๋‹ค์‹œ ๊ฒน์น˜๋ฏ€๋กœ, ๊ทธ๋•Œ๋Š” ์ด ํฉ๊ธฐ๊ฐ€ ์•„๋‹ˆ๋ผ ๋ถ„์‚ฐ์ด ๋‹ต์ด๋‹ค(์ด์—ฐ๋จ).\n */\n /** ๋ถ€ํŒ… ๋•Œ ํŠธ์œˆ ํ•˜๋‚˜๋ฅผ ๋˜์‚ด๋ฆฐ ๋’ค ๋ฃจํ”„๋ฅผ ๋น„์›Œ ์ฃผ๋Š” ์‹œ๊ฐ„(ms) โ€” ๊ทธ ์‚ฌ์ด ๋„์ฐฉํ•œ ์š”์ฒญ์ด ์ฒ˜๋ฆฌ๋œ๋‹ค. */\n static BOOT_YIELD_MS = 25\n private static tickPhase = 0\n /**\n * ํฉ์–ด์ง„ ์ฒซ ๋ฐœํ™” ๋’ค ์ฃผ๊ธฐ ํ‹ฑ. **ํ•ธ๋“ค์€ ํ•ญ์ƒ ์ง„์งœ ํƒ€์ด๋จธ**๋‹ค โ€” ์ •์ง€ํ•˜๋Š” ์ชฝ์ด `clearInterval(inst.timer)`\n * ํ•˜๋‚˜๋กœ ๋๋‚ด์•ผ ํ•˜๋ฏ€๋กœ, ์ฒซ ๋ฐœํ™” ์ „์—๋Š” ๊ทธ `setTimeout` ์„, ์ดํ›„์—๋Š” `setInterval` ์„ ๊ฐ™์€ ์ž๋ฆฌ์— ๋‘”๋‹ค\n * (๊ฐ์‹ผ ๊ฐ์ฒด๋ฅผ ์ฃผ๋ฉด `clearInterval` ์ด ์•„๋ฌด ์ผ๋„ ํ•˜์ง€ ์•Š๊ณ  ํŠธ์œˆ์ด ๋ฉˆ์ถ”์ง€ ์•Š๋Š”๋‹ค โ€” ์กฐ์šฉํ•œ ๊ฒฐํ•จ์ด ๋œ๋‹ค).\n */\n private static startTickTimer(fn: () => void, hold: (t: any) => void): any {\n const spread = Math.max(1, Math.round(this.TICK_MS / 20))\n const offset = (this.tickPhase = (this.tickPhase + spread) % this.TICK_MS)\n const first = setTimeout(() => {\n const interval = setInterval(fn, this.TICK_MS)\n if (typeof interval?.unref === 'function') interval.unref()\n hold(interval) // ์ •์ง€ ๊ฒฝ๋กœ๊ฐ€ ์ง€์šธ ๋Œ€์ƒ์„ ๋ฐ”๊ฟ” ์ค€๋‹ค\n fn()\n }, offset)\n if (typeof first?.unref === 'function') first.unref()\n return first\n }\n\n /** ๊ตถ๊น€ ๋ฌธํ„ฑ โ€” ํ‹ฑ ๊ฐ„๊ฒฉ์˜ ๋ฐฐ์ˆ˜(1์ดˆ ๊ฐ„๊ฒฉ์ด๋ฉด 5์ดˆ). ์ด ์‹œ๊ฐ„๋งŒํผ ํ˜ธ์ŠคํŠธ๊ฐ€ ๋ฉˆ์ถ˜๋‹ค. */\n static STARVE_FACTOR = 5\n /** ์—ฐ์† ๋ช‡ ๋ฒˆ์ด๋ฉด ๋ฉˆ์ถ”๋‚˜ โ€” 3๋ฒˆ์ด๋ฉด 15์ดˆ๋ฅผ ๊ตถ๊ธด ์…ˆ์ด๊ณ , ๊ทธ๊ฑด ์šฐ์—ฐ์ด ์•„๋‹ˆ๋‹ค. */\n static STARVE_STREAK = 3\n private static starveStreak = new Map<string, number>()\n /**\n * ์™œ ๋ฉˆ์ท„๋‚˜ โ€” **ํ™”๋ฉด์ด ๊ทธ๋Œ€๋กœ ๋งํ•  ์ˆ˜ ์žˆ๊ฒŒ.** ์Šค์Šค๋กœ ๋ฉˆ์ถ˜ ํŠธ์œˆ์ด ์ด์œ  ์—†์ด ใ€Œ์ •์ง€ใ€๋กœ๋งŒ ๋ณด์ด๋ฉด\n * ์‚ฌ๋žŒ์€ ์ž๊ธฐ๊ฐ€ ๋ฉˆ์ถ˜ ์ค„ ์•ˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ์—๋งŒ ๋‘”๋‹ค(์žฌ๊ธฐ๋™ํ•˜๋ฉด ์‚ฌ๋ผ์ง„๋‹ค โ€” ๊ทธ๋•Œ๋Š” ใ€Œ๋ชจ๋ฅธ๋‹คใ€๊ฐ€ ์‚ฌ์‹ค์ด๋‹ค).\n */\n private static stopNotes = new Map<string, StopNote>()\n\n /* ์ตœ์‹  ์Šค๋ƒ…์ƒท ์˜์†(warm-start) โ€” ์žฌ๊ธฐ๋™ ์‹œ ์ €๋„ fold-from-0 replay ๋Œ€์‹  ๋งˆ์ง€๋ง‰ ๋ผ์ด๋ธŒ ์Šค๋ƒ…์ƒท์œผ๋กœ ๋ณต์›.\n * ํ”„๋ ˆ์ž„์›Œํฌ ๊ณตํ†ต cache-service(@things-factory/cache-service) ์žฌ์‚ฌ์šฉ(์žฌ๋ฐœ๋ช… ๊ธˆ์ง€, framework-leverage ยง4).\n * ์ €๋„์€ ๊ทธ๋Œ€๋กœ ์ง„์‹ค(์‹œ๊ฐ„์—ฌํ–‰/history replay ๋ฌด๋ณ€๊ฒฝ) โ€” ์บ์‹œ๋Š” display-only ์›œ์Šคํƒ€ํŠธ ์ตœ์ ํ™”. */\n static SNAPSHOT_CACHE_ID = 'twin-snapshot'\n /*\n * โ”€โ”€ ์žฌ๊ฐœ์  **์‚ฌ์Šฌ** โ€” ๊ณผ๊ฑฐ๋ฅผ ๋ฌผ์—ˆ์„ ๋•Œ ๋ชฉํ‘œ ์ง์ „์—์„œ ์ ‘๊ธฐ ์œ„ํ•ด (2026-08-18) โ”€โ”€\n *\n * ์ตœ์‹  ์žฌ๊ฐœ์  ํ•˜๋‚˜๋กœ๋Š” ์‹œ๊ฐ„์—ฌํ–‰์„ ๋„์šธ ์ˆ˜ ์—†๋‹ค: ๊ทธ๊ฒƒ์€ ์–ธ์ œ๋‚˜ ๋ชฉํ‘œ๋ณด๋‹ค **๋’ค**์— ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ง€์ ์„\n * ์—ฌ๋Ÿฌ ๊ฐœ ๋‚จ๊ธด๋‹ค. ๋‹ค๋งŒ ๊ทธ๊ฒƒ๋“ค์€ ๊ฐ๊ฐ ์ƒํƒœ ์ „์ฒด๋ฅผ ๋“ค๊ณ  ์žˆ์–ด ๋ฌด๊ฒ๋‹ค โ€” ํ•œ ํ–‰์— ๋ชฐ์•„ ๋„ฃ์œผ๋ฉด ๊ฑฐ๋Œ€ํ•œ\n * JSON ์ด ๋˜๋ฏ€๋กœ **์ง€์ ๋งˆ๋‹ค ๋”ฐ๋กœ ๋‘๊ณ  ์ƒ‰์ธ์„ ๋‘”๋‹ค**(cache-service ๋Š” ํ•ด์‹œ ํ‚ค ์กฐํšŒ๋ผ ์—ด๊ฑฐ๊ฐ€ ์•ˆ ๋œ๋‹ค).\n *\n * ๊ฐ„๊ฒฉ์€ ๋ฆฌ๋น„์ „ ๋ˆˆ๊ธˆ์œผ๋กœ ์žก๋Š”๋‹ค(`CHAIN_STRIDE`): ๋ˆˆ๊ธˆ์„ ๋„˜์„ ๋•Œ๋งŒ ํ•œ ์ง€์ ์„ ๋‚จ๊ธฐ๋ฏ€๋กœ, ์ €๋„์ด ๋น ๋ฅด๊ฒŒ\n * ์ž๋ผ๋Š” ํŠธ์œˆ์—์„œ๋„ ์ง€์  ์ˆ˜๊ฐ€ ํญ๋ฐœํ•˜์ง€ ์•Š๋Š”๋‹ค. ์˜ค๋ž˜๋œ ๊ฒƒ๋ถ€ํ„ฐ ๋ฒ„๋ฆฌ๊ณ  ์ตœ๊ทผ `CHAIN_KEEP` ๊ฐœ๋งŒ ๋“ ๋‹ค โ€”\n * ๊ณผ๊ฑฐ๋กœ ๊นŠ์ด ๊ฐˆ์ˆ˜๋ก ์ง€์ ์ด ์—†์–ด 0๋ถ€ํ„ฐ ์ ‘๋Š” ๊ฒƒ์€ **์•Œ๋ ค์ง„ ํ•œ๊ณ„**๋‹ค(๋ฌดํ•œ ๋ณด๊ด€๋ณด๋‹ค ์ •์งํ•˜๋‹ค).\n */\n static CHAIN_CACHE_ID = 'twin-fold-chain'\n static CHAIN_INDEX_CACHE_ID = 'twin-fold-chain-index'\n static CHAIN_STRIDE = 5000 // ๋ฆฌ๋น„์ „ ๋ˆˆ๊ธˆ โ€” ์ด ๊ฐ„๊ฒฉ์„ ๋„˜์„ ๋•Œ๋งŒ ํ•œ ์ง€์ ์„ ๋‚จ๊ธด๋‹ค\n static CHAIN_KEEP = 5 // ์ตœ๊ทผ ๋ช‡ ์ง€์ ์„ ๋“ค๊ณ  ์žˆ๋‚˜(๊ทธ๋ณด๋‹ค ๊ณผ๊ฑฐ๋Š” 0๋ถ€ํ„ฐ ์ ‘๋Š”๋‹ค)\n static SNAPSHOT_TTL_S = 7 * 24 * 3600 // 7์ผ โ€” ์ •์ƒ ๋‹ค์šดํƒ€์ž„ ์ƒ์กด, ๋งŒ๋ฃŒ ์‹œ ์ €๋„ replay ํด๋ฐฑ\n static CHECKPOINT_MS = 20000 // ์ฒดํฌํฌ์ธํŠธ ์ฃผ๊ธฐ(ํ•ซ ๋ธŒ๋กœ๋“œ์บ์ŠคํŠธ ๊ฒฝ๋กœ์™€ ๋ถ„๋ฆฌ, O(state) ์Šค๋กœํ‹€)\n /**\n * **์ €๋„ ๋ณด์กด โ€” ์ง€์šฐ๋Š” ๊ฒƒ์€ ์„ ์–ธ์ด ์žˆ์„ ๋•Œ๋งŒ ํ•œ๋‹ค.**\n *\n * โ”€โ”€ ์™œ ํ•„์š”ํ•œ๊ฐ€ (2026-08-22 ์‹ค์ธก) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๊ฐœ๋ฐœ ์ €๋„์ด ์‹œ๊ฐ„๋‹น **581,794ํ–‰ ยท 0.85GB** ๋กœ ์ž๋ž๋‹ค(ํ•˜๋ฃจ 20GB). ๋ฐ๋ชจ MES ํŠธ์œˆ ์…‹์ด ์ „์ฒด์˜ **97%**\n * ๋ฅผ ๋งŒ๋“ค๊ณ  ์ง€์šฐ๋Š” ๊ฒƒ์ด ์—†์—ˆ๋‹ค. ์˜ค๋Š˜ ๊ณ ์นœ ๊ฒƒ๋“ค์€ ใ€Œ๊ทธ ํฌ๊ธฐ์—์„œ๋„ ์งˆ์˜๊ฐ€ ๋น ๋ฅด๊ฒŒใ€์ด๊ณ , **ํฌ๊ธฐ ์ž์ฒด๋ฅผ\n * ์ค„์ด๋Š” ๊ฒƒ์€ ์•„๋ฌด๊ฒƒ๋„ ์—†์—ˆ๋‹ค.** ๊ทธ๋Ÿฌ๋ฉด ๋ฉฐ์น ๋งˆ๋‹ค ๊ฐ™์€ ์ž๋ฆฌ๋กœ ๋Œ์•„์˜จ๋‹ค.\n *\n * โ”€โ”€ ๊ทธ๋Ÿฐ๋ฐ ์ €๋„์„ ์ง€์šฐ๋Š” ๊ฒƒ์€ ์‚ฌ์‹ค์„ ์žƒ๋Š” ์ผ์ด๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๊ทธ๋ž˜์„œ ์„ธ ๊ทœ์œจ์„ ์ง€ํ‚จ๋‹ค.\n *\n * โ‘  **์„ ์–ธ์ด ์—†์œผ๋ฉด ์•„๋ฌด๊ฒƒ๋„ ์ง€์šฐ์ง€ ์•Š๋Š”๋‹ค.** ๊ธฐ๋ณธ๊ฐ’์€ ์—†์Œ์ด๋‹ค โ€” ์กฐ์šฉํžˆ ์ง€์šฐ๋Š” ํŽธ์ด ์กฐ์šฉํžˆ ์Œ“๋Š”\n * ๊ฒƒ๋ณด๋‹ค ๋‚˜์˜๋‹ค. ์ง€์šฐ๋Š” ๊ฒƒ์€ ์‚ฌ๋žŒ์ด ์ •ํ•œ๋‹ค.\n * โ‘ก **์ฒดํฌํฌ์ธํŠธ๊ฐ€ ๋Œ€์‹ ํ•  ์ˆ˜ ์žˆ๋Š” ๋งŒํผ๋งŒ.** ์Šค๋ƒ…์ƒท์ด ์—†๊ฑฐ๋‚˜ ๊ทธ ๋ฆฌ๋น„์ „์„ ๋„˜๋Š” ์ž๋ฆฌ๋Š” ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.\n * ์ฃผ์„์ด ใ€Œ๋งŒ๋ฃŒ ์‹œ ์ €๋„ replay ํด๋ฐฑใ€์ด๋ผ๊ณ  ์ ์–ด ๋‘” ๊ทธ๋Œ€๋กœ โ€” ์Šค๋ƒ…์ƒท์ด ์‚ฌ๋ผ์ง€๋ฉด ์ €๋„์ด **์œ ์ผํ•œ**\n * ๋ณต๊ตฌ ์ˆ˜๋‹จ์ด๋ฏ€๋กœ, ๋‘˜์„ ํ•จ๊ป˜ ์žƒ์œผ๋ฉด ๊ทธ ํŠธ์œˆ์˜ ์ƒํƒœ๋Š” ๋˜๋Œ๋ฆด ์ˆ˜ ์—†๋‹ค.\n * โ‘ข **์ง€์šด ๊ฒƒ์„ ๋งํ•œ๋‹ค.** ๋ช‡ ๊ฑด์„ ์–ด๋А ์‹œ๊ฐ๊นŒ์ง€ ์ง€์› ๋Š”์ง€ ๋กœ๊ทธ์— ๋‚จ๊ธด๋‹ค. ์กฐ์šฉํžˆ ์ค„์–ด๋“  ์ €๋„์€\n * ใ€Œ์—†์—ˆ๋˜ ์ผใ€๊ณผ ๊ตฌ๋ณ„๋˜์ง€ ์•Š๋Š”๋‹ค.\n *\n * ๊ทธ๋ฆฌ๊ณ  ๋ณด์กด ๊ธฐ๊ฐ„์€ **์Šค๋ƒ…์ƒท TTL(7์ผ)๋ณด๋‹ค ์งง์„ ์ˆ˜ ์—†๋‹ค.** ๋” ์งง์œผ๋ฉด ์Šค๋ƒ…์ƒท์ด ์‚ด์•„ ์žˆ๋Š”๋ฐ ๊ทธ๊ฒƒ์ด\n * ๊ฐ€๋ฆฌํ‚ค๋Š” ์•ž์ชฝ ์ €๋„์ด ์—†๋Š” ๊ตฌ๊ฐ„์ด ์ƒ๊ธฐ๊ณ , ์‹œ๊ฐ„์—ฌํ–‰ยท๊ณ„๋ณด ์ถ”์ ์ด ๊ทธ ๊ตฌ๊ฐ„์—์„œ ์กฐ์šฉํžˆ ๋นˆ๋‹ค.\n */\n static JOURNAL_RETENTION_DAYS?: number = undefined\n /**\n * **๋„๋ฉ”์ธ๋งˆ๋‹ค ๋‹ค๋ฅธ ๋ณด์กด ๊ธฐ๊ฐ„์„ ์•ฑ์ด ๋‹ตํ•œ๋‹ค** โ€” ์—”์ง„์€ ๊ทธ ๊ฐ’์ด ์–ด๋””์„œ ์˜ค๋Š”์ง€ ๋ชจ๋ฅธ๋‹ค.\n *\n * ๋ณด์กด ๊ธฐ๊ฐ„์€ ํ…Œ๋„ŒํŠธ์˜ ์ •์ฑ…์ด๋‹ค: ํ•œ ๊ณ ๊ฐ์€ 30์ผ์ด ํ•„์š”ํ•˜๊ณ  ๋‹ค๋ฅธ ๊ณ ๊ฐ์€ 7์ผ์ด๋ฉด ๋œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์—”์ง„์ด\n * `Setting` ์„ ์ฝ๊ฒŒ ๋งŒ๋“ค๋ฉด **์—”์ง„์ด ํ™”๋ฉด ๊ด€์‹ฌ์‚ฌ๋ฅผ ์•Œ๊ฒŒ ๋œ๋‹ค** โ€” ๋ฐฉํ–ฅ์ด ๊ฑฐ๊พธ๋กœ๋‹ค(์—”์ง„์€ ์ปค๋„์˜ ํ˜ธ์ŠคํŠธ์ด๊ณ \n * ๊ทธ ์œ„์— ์–ด๋–ค ํ™”๋ฉด์ด ์žˆ๋Š”์ง€ ๋ชฐ๋ผ์•ผ ํ•œ๋‹ค).\n *\n * ๊ทธ๋ž˜์„œ ์‹œ์ž„์„ ๋‘”๋‹ค. ์•ฑ์ด ์ด ํ•จ์ˆ˜๋ฅผ ์‹ฌ๊ณ , ๊ทธ ์•ˆ์—์„œ `Setting` ์ด๋“  ๋‹ค๋ฅธ ๋ฌด์—‡์ด๋“  ์ฝ๋Š”๋‹ค. ์‹ฌ์ง€ ์•Š์œผ๋ฉด\n * `JOURNAL_RETENTION_DAYS`(์„ค์ • ํŒŒ์ผ์—์„œ ์˜จ ํ”„๋กœ์„ธ์Šค ๊ธฐ๋ณธ๊ฐ’)๊ฐ€ ๋‹ตํ•œ๋‹ค.\n *\n * `undefined` ๋ฅผ ๋Œ๋ ค์ฃผ๋ฉด **๊ทธ ๋„๋ฉ”์ธ์€ ์ง€์šฐ์ง€ ์•Š๋Š”๋‹ค** โ€” ใ€Œ๋ชจ๋ฅธ๋‹คใ€๋ฅผ ใ€Œ์ง€์›Œ๋„ ๋œ๋‹คใ€๋กœ ์ฝ์ง€ ์•Š๋Š”๋‹ค.\n */\n static retentionDaysOf?: (domainId: string) => Promise<number | undefined>\n static RETENTION_SWEEP_MS = 10 * 60 * 1000 // 10๋ถ„๋งˆ๋‹ค ํ•œ ๋ฒˆ โ€” ์ง€์šฐ๋Š” ์ผ์€ ๊ธ‰ํ•˜์ง€ ์•Š๋‹ค\n private static retentionTimer?: any\n private static checkpointTimer?: any\n\n /** ์ตœ์‹  ์Šค๋ƒ…์ƒท์„ cache-service ์— ์ฒดํฌํฌ์ธํŠธ(๋„๋ฉ”์ธ+instanceId ํ‚ค). display-onlyยท๋น„์ฐจ๋‹จยท์˜ค๋ฅ˜ํก์ˆ˜. */\n static async persistSnapshot(domainId: string, instanceId: string): Promise<void> {\n const inst = this.instances[runtimeKey(domainId, instanceId)]\n if (!inst) return\n /*\n * **๋ด‰ํˆฌ๊ฐ€ ์•„๋‹ˆ๋ผ ์ƒํƒœ๋ฅผ ์ €์žฅํ•œ๋‹ค.** `snapshot()` ์€ ์‹œ๋ฎฌ์—์„œ `runtime.resync()` ๋ด‰ํˆฌ๋ฅผ ์ฃผ๋Š”๋ฐ,\n * ๊ทธ๊ฒƒ์„ ๋‹ค์‹œ `{revision, state}` ๋กœ ๊ฐ์‹ธ ๋„ฃ์–ด ์™”๋‹ค โ†’ ๊บผ๋‚ธ ๊ฐ’์— ์ถ•์ด ํ•˜๋‚˜๋„ ์—†์–ด ์›œ์Šคํƒ€ํŠธ๊ฐ€\n * ์กฐ์šฉํžˆ ๋„˜์–ด๊ฐ”๋‹ค(์ €๋„์— ์ˆ˜์ฒœ ๊ฑด์ด ์žˆ์–ด๋„ ํŠธ์œˆ์ด ๋นˆ ์ฑ„๋กœ ๋–ด๋‹ค).\n */\n const state = unwrapState(this.snapshot(domainId, instanceId))\n if (!state) return\n const revision = inst.revision ?? state.revision ?? 0\n /* ๊ตฌ์กฐ ๋ฆฌ๋น„์ „๋„ ํ•จ๊ป˜ โ€” ์ฝ๋Š” ์ชฝ์ด \"์ด ์ƒํƒœ๊ฐ€ ์ง€๊ธˆ์˜ ๊ณต์žฅ์ธ๊ฐ€\" ๋ฅผ ๊ฐ€๋ฆด ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. */\n const { structureRev } = await this.tipOf(domainId, instanceId).catch(() => ({ structureRev: null }) as any)\n await cacheService.setInCache(this.SNAPSHOT_CACHE_ID, { domainId, instanceId }, { revision, state, structureRev }, this.SNAPSHOT_TTL_S)\n }\n\n /**\n * ์ ‘๊ธฐ์˜ **์žฌ๊ฐœ์ ** โ€” ๋ฆฌ๋“€์„œ ๋‚ด๋ถ€ ์ƒํƒœ ์ „๋ถ€ + ๊ฐ€๋™ ๋ˆ„์ ๊ธฐ.\n *\n * ์Šค๋ƒ…์ƒท(`state`)์€ ์†Œ๋น„์ฒ˜๊ฐ€ ๋ณด๋Š” ๊ฐ’์ด๋ผ ์ด์–ด ์ ‘๊ธฐ์˜ ์”จ์•—์ด ๋˜์ง€ ๋ชปํ•œ๋‹ค(๋ณด๋ฅ˜๋œ ๋‹ด๊น€ยท์ง‘ํ•ฉยท๋ฐ˜์˜ ๋ชป ํ•œ\n * ์‚ฌ๊ฑด ์ง‘๊ณ„๊ฐ€ ์—†๋‹ค โ€” ๊ทธ ์ƒํƒœ๋กœ ๋’ค๋ฅผ ์ ‘์œผ๋ฉด 0๋ถ€ํ„ฐ ์ ‘์€ ๊ฒฐ๊ณผ์™€ ์กฐ์šฉํžˆ ๋‹ฌ๋ผ์ง„๋‹ค). ๊ทธ๋ž˜์„œ ์”จ์•—์€ ๋”ฐ๋กœ ๋“ ๋‹ค.\n */\n private static readonly FOLD_NOTE = 'reducer + oee checkpoint โ€” the seed for folding only the tail'\n\n /** ์ฒดํฌํฌ์ธํŠธ๋œ ์ตœ์‹  ์Šค๋ƒ…์ƒท ๋กœ๋“œ(์—†์œผ๋ฉด null). getFromCache ๋Š” CacheStore ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ฐ˜ํ™˜ โ†’ ํŽ˜์ด๋กœ๋“œ๋Š” .value. */\n static async loadSnapshot(\n domainId: string,\n instanceId: string\n ): Promise<{ revision: number; state: any; structureRev?: number | null; fold?: { reducer: ReducerCheckpoint; oee: OeeCheckpoint } } | null> {\n const entry = await cacheService.getFromCache(this.SNAPSHOT_CACHE_ID, { domainId, instanceId })\n return (entry as any)?.value ?? null\n }\n\n /**\n * ์ ‘์€ ์ƒํƒœ๋ฅผ ์Šค๋ƒ…์ƒท์œผ๋กœ ๋‚จ๊ธด๋‹ค โ€” **๋ผ์ด๋ธŒ๊ฐ€ ์•„๋‹ˆ์–ด๋„.**\n *\n * `persistSnapshot` ์€ ๊ธฐ๋™ ์ค‘์ธ ์ธ์Šคํ„ด์Šค์—์„œ๋งŒ ๋œฌ๋‹ค(๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ง„์‹ค์ด๋ฏ€๋กœ ์˜ณ๋‹ค). ๊ทธ๋Ÿฐ๋ฐ **๋ฉˆ์ถ˜**\n * ํŠธ์œˆ์„ ์กฐํšŒํ•  ๋•Œ๋งˆ๋‹ค ์ €๋„์„ ์ „๋Ÿ‰ ๋‹ค์‹œ ์ ‘๊ณ  ์žˆ์—ˆ๋‹ค(23,731๊ฑด์งœ๋ฆฌ ํŠธ์œˆ์—์„œ 4.6์ดˆ). ๊ทธ ํด๋“œ์˜ ๊ฒฐ๊ณผ๋ฅผ\n * ๋‚จ๊ฒจ ๋‘๋ฉด **์ฒ˜์Œ ํ•œ ๋ฒˆ๋งŒ ๋А๋ฆฌ๋‹ค.**\n *\n * `structureRev` ๋ฅผ ํ•จ๊ป˜ ์ ๋Š”๋‹ค: ์ด๋ฒคํŠธ๊ฐ€ ํ•˜๋‚˜๋„ ์•ˆ ๋Š˜์–ด๋„ ๊ตฌ์กฐ๋ฅผ ๊ฐˆ์•„์น˜์šฐ๋ฉด(์žฌํ”„๋กœ๋น„์ €๋‹) ๊ทธ\n * ์ƒํƒœ๋Š” ๋‚ก์€ ๊ฒƒ์ด๋‹ค. ๋ฆฌ๋น„์ „๋งŒ ๋ณด๋ฉด ์ƒˆ ์„ค๋น„๊ฐ€ ์—†๋Š” ์˜› ์ƒํƒœ๋ฅผ \"์ง€๊ธˆ\" ์œผ๋กœ ๋‚ด๊ฒŒ ๋œ๋‹ค.\n */\n static async saveFoldedSnapshot(\n domainId: string,\n instanceId: string,\n value: { revision: number; state: any; structureRev?: number | null; fold?: { reducer: ReducerCheckpoint; oee: OeeCheckpoint } }\n ): Promise<void> {\n if (!value?.state) return\n await cacheService\n .setInCache(this.SNAPSHOT_CACHE_ID, { domainId, instanceId }, value, this.SNAPSHOT_TTL_S)\n .catch((err: any) => twinError(`[twin-engine] snapshot save fail \"${instanceId}\"`, err?.message ?? err))\n }\n\n\n /** ์‚ฌ์Šฌ ์ƒ‰์ธ โ€” ์–ด๋–ค ๋ฆฌ๋น„์ „ ์ง€์ ์„ ๋“ค๊ณ  ์žˆ๋‚˜(์ตœ์‹ ์ˆœ ์•„๋‹˜, ์˜ค๋ฆ„์ฐจ์ˆœ). */\n private static async chainIndex(domainId: string, instanceId: string): Promise<number[]> {\n const entry = await cacheService.getFromCache(this.CHAIN_INDEX_CACHE_ID, { domainId, instanceId }).catch(() => null)\n const revs = (entry as any)?.value?.revisions\n return Array.isArray(revs) ? revs.filter((r: any) => Number.isFinite(r)).sort((a: number, b: number) => a - b) : []\n }\n\n /**\n * ๋ชฉํ‘œ ์ด์ „์˜ **๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ์ง€์ **์„ ๊ณ ๋ฅธ๋‹ค โ€” ์—†์œผ๋ฉด `null`(0๋ถ€ํ„ฐ ์ ‘๋Š”๋‹ค).\n *\n * ์‹œ๊ฐ์œผ๋กœ ๋ฌผ์—ˆ์œผ๋ฉด ๊ทธ ์ง€์ ์˜ ๋งˆ์ง€๋ง‰ ์‚ฌ์‹ค ์‹œ๊ฐ์ด ๋ชฉํ‘œ ์ด๋‚ด์—ฌ์•ผ ํ•œ๋‹ค(๋ฆฌ๋น„์ „๋งŒ ๋ณด๋ฉด ๋ชฉํ‘œ๋ณด๋‹ค ๋’ค์˜\n * ์‚ฌ์‹ค์ด ์”จ์•—์— ์„ž์ธ๋‹ค). ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€ ํŠธ์œˆ์—์„œ๋Š” ์“ฐ์ง€ ์•Š๋Š”๋‹ค โ€” ๋งˆ๋””๋ฅผ ๊ฑด๋„ˆ๋›ด ์”จ์•—์€ ๊ทธ ๊ฒฝ๊ณ„์˜\n * ํŒ์ •์„ ์žƒ๋Š”๋‹ค(๊ทธ ๊ฒฝ์šฐ๋Š” 0๋ถ€ํ„ฐ ์ ‘๋Š” ๊ฒƒ์ด ์˜ณ๋‹ค).\n */\n private static async chainSeedFor(\n domainId: string,\n instanceId: string,\n target: { revision?: number; timeMs?: number }\n ): Promise<{ revision: number; eventTime?: string; structureRev?: number | null; fold?: { reducer: ReducerCheckpoint; oee: OeeCheckpoint } } | null> {\n const revs = await this.chainIndex(domainId, instanceId)\n if (!revs.length) return null\n for (const revision of [...revs].reverse()) {\n if (target.revision != null && revision > target.revision) continue\n const entry = await cacheService.getFromCache(this.CHAIN_CACHE_ID, { domainId, instanceId, revision }).catch(() => null)\n const value = (entry as any)?.value\n if (!value?.fold?.reducer) continue\n if (target.timeMs != null) {\n const t = value.eventTime ? Date.parse(String(value.eventTime)) : NaN\n /* ์‹œ๊ฐ์„ ๋ชจ๋ฅด๋Š” ์ง€์ ์€ ์“ฐ์ง€ ์•Š๋Š”๋‹ค โ€” ๋ชฉํ‘œ ์ด๋‚ด์ธ์ง€ ๊ฐ€๋ฆด ์ˆ˜ ์—†๋‹ค(์ง์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค). */\n if (!Number.isFinite(t) || t > target.timeMs) continue\n }\n return value\n }\n return null\n }\n\n /** ๋ˆˆ๊ธˆ์„ ๋„˜์—ˆ์œผ๋ฉด ํ•œ ์ง€์ ์„ ๋‚จ๊ธด๋‹ค โ€” ์˜ค๋ž˜๋œ ๊ฒƒ์€ ๋ฒ„๋ฆฐ๋‹ค(์ƒ‰์ธ๋„ ํ•จ๊ป˜ ์ค„์ธ๋‹ค). */\n private static async keepChainPoint(\n domainId: string,\n instanceId: string,\n /*\n * **๋ณด๊ธฐ(state)๋Š” ๋‹ด์ง€ ์•Š๋Š”๋‹ค** (2026-08-18 ์‹ค์ธก์œผ๋กœ ๊ณ ์นจ).\n *\n * ์ฒ˜์Œ์—๋Š” ์ƒํƒœ๊นŒ์ง€ ๋‹ด์•˜๋”๋‹ˆ ์ง€์  ํ•˜๋‚˜๊ฐ€ **11.4 MB** ์˜€๋‹ค(27๋งŒ ๊ฑด ํŠธ์œˆ). ์‚ฌ์Šฌ์ด ํ•„์š”ํ•œ ๊ฒƒ์€ ์”จ์•—\n * (์žฌ๊ฐœ์ )๋ฟ์ด๊ณ , ์†Œ๋น„์ฒ˜๊ฐ€ ๋ณด๋Š” ๊ฐ’์€ ๊ทธ ์”จ์•—์—์„œ ๋‹ค์‹œ ๋งŒ๋“ค์–ด์ง„๋‹ค โ€” ๊ฐ™์€ ์‚ฌ์‹ค์„ ๋‘ ๋ฒˆ ์ €์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค.\n */\n value: { revision: number; eventTime?: string; structureRev?: number | null; fold: { reducer: ReducerCheckpoint; oee: OeeCheckpoint } }\n ): Promise<void> {\n const revs = await this.chainIndex(domainId, instanceId)\n const newest = revs.length ? revs[revs.length - 1] : -Infinity\n if (value.revision - newest < this.CHAIN_STRIDE) return // ์•„์ง ๋ˆˆ๊ธˆ์„ ๋„˜์ง€ ์•Š์•˜๋‹ค\n const next = [...revs, value.revision].slice(-this.CHAIN_KEEP)\n const dropped = revs.filter(r => !next.includes(r))\n await cacheService.setInCache(this.CHAIN_CACHE_ID, { domainId, instanceId, revision: value.revision }, value, this.SNAPSHOT_TTL_S)\n await cacheService.setInCache(this.CHAIN_INDEX_CACHE_ID, { domainId, instanceId }, { revisions: next }, this.SNAPSHOT_TTL_S)\n /*\n * ๋ฒ„๋ฆฐ ์ง€์ ์€ **์ƒ‰์ธ์—์„œ๋งŒ** ๋น ์ง„๋‹ค โ€” ๊ณต์šฉ ์บ์‹œ์— ์‚ญ์ œ API ๊ฐ€ ์—†๋‹ค(`ICacheService` ๋Š” getยทsetยท\n * clearStaleCache ๋ฟ์ด๋‹ค). ๊ทธ๋ž˜์„œ ๊ฐ’์€ TTL(7์ผ)๊นŒ์ง€ ๋‚จ๋Š”๋‹ค: ์•„๋ฌด๋„ ๋‹ฟ์ง€ ๋ชปํ•˜์ง€๋งŒ ์ž๋ฆฌ๋Š” ์ฐจ์ง€ํ•œ๋‹ค.\n * ์ง€๊ธˆ ๊ทœ๋ชจ์—์„œ ๊ฐ๋‹นํ•  ์ˆ˜ ์žˆ๋Š” ๋‚ญ๋น„์ด๊ณ , ๊ณต์šฉ ๋ชจ๋“ˆ์— ์‚ญ์ œ๋ฅผ ์—ฌ๋Š” ๊ฒƒ์€ ๋‹ค๋ฅธ ์†Œ๋น„์ฒ˜๊นŒ์ง€ ํ•จ๊ป˜ ๋ณผ\n * ์ผ์ด๋ผ ์—ฌ๊ธฐ์„œ ๋ชฐ๋ž˜ ํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” **์•Œ๋ ค์ง„ ํ•œ๊ณ„๋กœ ์ ์–ด ๋‘”๋‹ค.**\n */\n if (dropped.length) console.info(`[twin-engine] \"${instanceId}\" fold chain dropped ${dropped.join(', ')} from the index (values expire with the cache TTL).`)\n }\n\n /** ์ด ํŠธ์œˆ ์ €๋„์˜ ๋ ๋ฆฌ๋น„์ „ ยท ์ตœ์‹  ๊ตฌ์กฐ ๋ฆฌ๋น„์ „ โ€” ์Šค๋ƒ…์ƒท์ด ์ง€๊ธˆ์˜ ์‚ฌ์‹ค์ธ์ง€ ๊ฐ€๋ฆฌ๋Š” ๋‘ ๊ฐ’. */\n private static async tipOf(domainId: string, instanceId: string): Promise<{ revision: number; structureRev: number | null }> {\n const [tip, newest] = await Promise.all([\n getRepository(TwinEvent).findOne({ where: { domain: { id: domainId }, instanceId }, order: { revision: 'DESC' } }),\n getRepository(TwinStructure).findOne({ where: { domain: { id: domainId }, instanceId }, order: { rev: 'DESC' } })\n ])\n return { revision: tip?.revision ?? 0, structureRev: newest?.rev ?? null }\n }\n\n /**\n * **์ €๋„์„ ๋ณด์กด ๊ธฐ๊ฐ„๊นŒ์ง€๋งŒ ๋‘”๋‹ค** โ€” ์ฒดํฌํฌ์ธํŠธ๊ฐ€ ๋Œ€์‹ ํ•  ์ˆ˜ ์žˆ๋Š” ๋งŒํผ๋งŒ ์ง€์šด๋‹ค.\n *\n * ํ•œ ์ธ์Šคํ„ด์Šค์—์„œ ์ง€์šฐ๋Š” ์กฐ๊ฑด์€ **๋‘˜ ๋‹ค** ๋งŒ์กฑํ•ด์•ผ ํ•œ๋‹ค.\n *\n * ยท `createdAt` ์ด ๋ณด์กด ๊ธฐ๊ฐ„๋ณด๋‹ค ์˜ค๋ž˜๋๋‹ค โ€” **ํ–‰์ด ์“ฐ์ธ ์‹ค์ œ ์‹œ๊ฐ**์ด ๊ธฐ์ค€์ด๋‹ค\n * ยท `revision` ์ด **์ฒดํฌํฌ์ธํŠธ ๋ฆฌ๋น„์ „ ์ดํ•˜**๋‹ค โ€” ๊ทธ ์•ž์€ ์Šค๋ƒ…์ƒท์ด ๋Œ€์‹ ํ•œ๋‹ค\n *\n * โ”€โ”€ ์™œ `eventTime` ์ด ์•„๋‹ˆ๋ผ `createdAt` ์ธ๊ฐ€ (2026-08-22 ์‹ค์ธก์œผ๋กœ ๊ณ ์นจ) โ”€โ”€โ”€โ”€\n * ์ฒ˜์Œ์— `eventTime` ์œผ๋กœ ์ ์—ˆ๋‹ค. ๊ทธ๊ฒƒ์€ **ํŠธ์œˆ์˜ ์‹œ๊ณ„**๋‹ค โ€” ์‹œ๋ฎฌ๋ ˆ์ด์…˜์€ ์ž๊ธฐ ์‹œ๊ณ„๋กœ ์‚ฌ๊ฑด์„ ์ฐ๊ณ ,\n * ๊ทธ ์‹œ๊ณ„๋Š” ์‹ค์ œ ์‹œ๊ฐ๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ์•ž์„œ๊ฑฐ๋‚˜ ๋’ค์„ ๋‹ค. ์‹ค์ธก:\n *\n * order-check ๊ฐ€์žฅ ๋Šฆ์€ eventTime = 2027-06-08 โ† ์‹ค์ œ ์‹œ๊ฐ๋ณด๋‹ค 10๊ฐœ์›” ์•ž\n * hatio-mx2 2026-01-01 ~ ์ง€๊ธˆ โ† 7๊ฐœ์›”์น˜๋ฅผ ํ•œ ๋ฒˆ์— ์ง€์šฐ๊ฒŒ ๋œ๋‹ค\n *\n * ์ฆ‰ ใ€Œ7์ผใ€์ด ํŠธ์œˆ๋งˆ๋‹ค ๋‹ค๋ฅธ ๋œป์ด ๋œ๋‹ค: ์‹œ๊ณ„๊ฐ€ ์•ž์„  ํŠธ์œˆ์€ ์˜์›ํžˆ ์ง€์›Œ์ง€์ง€ ์•Š๊ณ , ๊ณผ๊ฑฐ๋ถ€ํ„ฐ ์ฐ์€ ํŠธ์œˆ์€\n * ๊ฑฐ์˜ ์ „๋ถ€๊ฐ€ ํ•œ ๋ฒˆ์— ์ง€์›Œ์ง„๋‹ค. **๋ณด์กด์€ ์ €์žฅ ๋‚˜์ด์˜ ๋ฌธ์ œ**์ด๊ณ  ์ €์žฅ ๋‚˜์ด๋Š” ์‹ค์ œ ์‹œ๊ณ„๋‹ค.\n *\n * `createdAt` ์€ ๊ทธ ํ–‰์ด DB ์— ์“ฐ์ธ ์‹œ๊ฐ์ด๊ณ  1,599๋งŒ ํ–‰ ์ „๋ถ€ ์ฑ„์›Œ์ ธ ์žˆ๋‹ค(ํ™•์ธํ•จ). ๋„๋ฉ”์ธ ์‹œ๊ฐ์„\n * ์ •์ฑ…์— ์“ฐ์ง€ ์•Š๋Š”๋‹ค โ€” ๊ทธ ๋‘˜์„ ์„ž์œผ๋ฉด ์‹œ๋ฎฌ๊ณผ ๋ฏธ๋Ÿฌ์—์„œ ๊ฐ™์€ ์„ค์ •์ด ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•œ๋‹ค.\n *\n * ์Šค๋ƒ…์ƒท์ด ์—†์œผ๋ฉด **๊ทธ ์ธ์Šคํ„ด์Šค๋Š” ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.** ์ €๋„์ด ์œ ์ผํ•œ ๋ณต๊ตฌ ์ˆ˜๋‹จ์ธ ์ƒํƒœ์ด๋ฏ€๋กœ, ์ง€์šฐ๋ฉด\n * ๊ทธ ํŠธ์œˆ์˜ ์ƒํƒœ๋ฅผ ๋˜๋Œ๋ฆด ์ˆ˜ ์—†๋‹ค. ใ€Œ์ง€์šธ ์ˆ˜ ์—†์—ˆ๋‹คใ€๋Š” ์‚ฌ์‹ค๋„ ํ•จ๊ป˜ ์„ผ๋‹ค โ€” ์กฐ์šฉํžˆ ๋„˜๊ธฐ๋ฉด ใ€Œ๋ณด์กด์ด\n * ๋„๋Š”๋ฐ ์™œ ์•ˆ ์ค„์–ด๋“œ๋‚˜ใ€๊ฐ€ ๋œ๋‹ค.\n *\n * `createdAt` ์ด ๋นˆ ์˜› ํ–‰์€ **์ง€์šฐ์ง€ ์•Š๋Š”๋‹ค**(์‹œ๊ฐ์„ ๋ชจ๋ฅด๋Š” ๊ฒƒ์„ ใ€Œ์˜ค๋ž˜๋๋‹คใ€๋กœ ์ฝ์ง€ ์•Š๋Š”๋‹ค).\n *\n * ๋“œ๋ผ์ด๋ฒ„ ๋‹ค์„ฏ์„ ๋‹ค ์ง€๋‚˜์•ผ ํ•˜๋ฏ€๋กœ raw SQL ์„ ์“ฐ์ง€ ์•Š๋Š”๋‹ค โ€” ์กฐ๊ฑด ์‚ญ์ œ๋Š” ์ฟผ๋ฆฌ๋นŒ๋”๊ฐ€ ์ด์‹ํ•œ๋‹ค.\n */\n static async pruneJournal(domainId: string): Promise<{ deleted: number; instances: number; skipped: string[] }> {\n /* ๋„๋ฉ”์ธ์˜ ์ •์ฑ…์ด ๋จผ์ €๋‹ค(ยง`retentionDaysOf`). ์—†์œผ๋ฉด ํ”„๋กœ์„ธ์Šค ๊ธฐ๋ณธ๊ฐ’. ๋‘˜ ๋‹ค ์—†์œผ๋ฉด ์ง€์šฐ์ง€ ์•Š๋Š”๋‹ค. */\n const perDomain = this.retentionDaysOf ? await this.retentionDaysOf(domainId).catch(() => undefined) : undefined\n const days = perDomain ?? this.JOURNAL_RETENTION_DAYS\n if (!days || days <= 0) return { deleted: 0, instances: 0, skipped: [] }\n\n /* ๋ณด์กด ๊ธฐ๊ฐ„์€ ์Šค๋ƒ…์ƒท TTL ๋ณด๋‹ค ์งง์„ ์ˆ˜ ์—†๋‹ค โ€” ์งง์œผ๋ฉด ์Šค๋ƒ…์ƒท์ด ๊ฐ€๋ฆฌํ‚ค๋Š” ์•ž์ชฝ์ด ๋น„๋Š” ๊ตฌ๊ฐ„์ด ์ƒ๊ธด๋‹ค. */\n const minDays = this.SNAPSHOT_TTL_S / 86400\n const effectiveDays = Math.max(days, minDays)\n if (effectiveDays !== days) {\n twinWarn(\n `[twin-engine] journal retention ${days}์ผ์€ ์Šค๋ƒ…์ƒท TTL(${minDays}์ผ)๋ณด๋‹ค ์งง๋‹ค โ€” ${effectiveDays}์ผ๋กœ ์˜ฌ๋ฆฐ๋‹ค ` +\n '(๋” ์งง์œผ๋ฉด ์Šค๋ƒ…์ƒท์ด ์‚ด์•„ ์žˆ๋Š”๋ฐ ๊ทธ๊ฒƒ์ด ๊ฐ€๋ฆฌํ‚ค๋Š” ์•ž์ชฝ ์ €๋„์ด ์—†๋Š” ๊ตฌ๊ฐ„์ด ์ƒ๊ธด๋‹ค)'\n )\n }\n const cutoff = new Date(Date.now() - effectiveDays * 86400 * 1000)\n\n const rows = await getRepository(TwinInstance).find({ where: { domain: { id: domainId } } })\n let deleted = 0\n let instances = 0\n const skipped: string[] = []\n\n for (const r of rows) {\n const snap = await this.loadSnapshot(domainId, r.instanceId).catch(() => null)\n const upTo = Number(snap?.revision ?? 0)\n if (!upTo) {\n /* ์Šค๋ƒ…์ƒท์ด ์—†๋‹ค โ€” ์ €๋„์ด ์œ ์ผํ•œ ๋ณต๊ตฌ ์ˆ˜๋‹จ์ด๋ฏ€๋กœ ์†๋Œ€์ง€ ์•Š๋Š”๋‹ค. */\n skipped.push(r.instanceId)\n continue\n }\n const res = await getRepository(TwinEvent)\n .createQueryBuilder()\n .delete()\n .from(TwinEvent)\n .where('domain_id = :domainId', { domainId })\n .andWhere('instance_id = :instanceId', { instanceId: r.instanceId })\n .andWhere('revision <= :upTo', { upTo })\n .andWhere('created_at IS NOT NULL')\n .andWhere('created_at < :cutoff', { cutoff })\n .execute()\n const n = res.affected ?? 0\n if (n > 0) {\n deleted += n\n instances++\n /* **์ง€์šด ๊ฒƒ์„ ๋งํ•œ๋‹ค** โ€” ์กฐ์šฉํžˆ ์ค„์–ด๋“  ์ €๋„์€ ใ€Œ์—†์—ˆ๋˜ ์ผใ€๊ณผ ๊ตฌ๋ณ„๋˜์ง€ ์•Š๋Š”๋‹ค. */\n twinLog(\n `[twin-engine] journal pruned \"${r.instanceId}\" โ€” ${n}๊ฑด (revision โ‰ค ${upTo} ยท ${cutoff.toISOString()} ์ด์ „). ` +\n '๊ทธ ์•ž์€ ์ฒดํฌํฌ์ธํŠธ๊ฐ€ ๋Œ€์‹ ํ•œ๋‹ค.'\n )\n }\n }\n if (skipped.length) {\n twinLog(\n `[twin-engine] journal prune skipped ${skipped.length} instance(s) with no checkpoint โ€” ` +\n `์ €๋„์ด ์œ ์ผํ•œ ๋ณต๊ตฌ ์ˆ˜๋‹จ์ด๋ผ ์†๋Œ€์ง€ ์•Š์•˜๋‹ค: ${skipped.slice(0, 5).join(', ')}${skipped.length > 5 ? ' โ€ฆ' : ''}`\n )\n }\n return { deleted, instances, skipped }\n }\n\n /** ๋ณด์กด ์ •๋ฆฌ ์ฃผ๊ธฐ ๊ธฐ๋™(1ํšŒ) โ€” ์„ ์–ธ์ด ์—†์œผ๋ฉด ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š๋Š”๋‹ค. */\n static startRetentionLoop(domainId: string): void {\n if (this.retentionTimer) return\n /*\n * ๊ฑธ์ง€ ์•Š๋Š” ์กฐ๊ฑด: ํ”„๋กœ์„ธ์Šค ๊ธฐ๋ณธ๊ฐ’๋„ ์—†๊ณ  **๋„๋ฉ”์ธ์— ๋ฌผ์„ ๊ธธ๋„ ์—†์„** ๋•Œ๋‹ค. ์‹œ์ž„์ด ์‹ฌ๊ฒจ ์žˆ์œผ๋ฉด\n * ๊ธฐ๋ณธ๊ฐ’์ด ์—†์–ด๋„ ๊ฑธ์–ด์•ผ ํ•œ๋‹ค โ€” ๊ทธ ๋„๋ฉ”์ธ์ด ์ž๊ธฐ ๊ฐ’์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค.\n */\n if (!this.JOURNAL_RETENTION_DAYS && !this.retentionDaysOf) return\n this.retentionTimer = setInterval(() => {\n this.pruneJournal(domainId).catch(err => twinError('[twin-engine] journal prune failed', err?.message ?? err))\n }, this.RETENTION_SWEEP_MS)\n if (typeof this.retentionTimer?.unref === 'function') this.retentionTimer.unref()\n twinLog(\n `[twin-engine] journal retention on โ€” ${this.JOURNAL_RETENTION_DAYS ?? '(๋„๋ฉ”์ธ ์ •์ฑ…)'}์ผ ยท ` +\n `${this.RETENTION_SWEEP_MS / 60000}๋ถ„๋งˆ๋‹ค`\n )\n }\n\n /** ์ฒดํฌํฌ์ธํŠธ ๋ฃจํ”„ ๊ธฐ๋™(1ํšŒ) โ€” ๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค๋“ค์˜ ์ตœ์‹  ์Šค๋ƒ…์ƒท์„ ์ฃผ๊ธฐ ์˜์†. */\n static startCheckpointLoop(): void {\n if (this.checkpointTimer) return\n this.checkpointTimer = setInterval(() => {\n for (const [key, inst] of Object.entries(this.instances)) {\n const { instanceId } = parseRuntimeKey(key)\n this.persistSnapshot(inst.domainId, instanceId).catch(err =>\n twinError(`[twin-engine] snapshot checkpoint fail \"${instanceId}\"`, err?.message ?? err)\n )\n }\n }, this.CHECKPOINT_MS)\n if (typeof this.checkpointTimer?.unref === 'function') this.checkpointTimer.unref()\n }\n\n /**\n * ๋ถ€ํŒ… ํ›… โ€” DB ์— status='running' ์œผ๋กœ ๋‚จ์€ ์ธ์Šคํ„ด์Šค๋ฅผ ์ €๋„์—์„œ ์ƒํƒœ ์žฌ๊ตฌ์„ฑ(DBโ†’replay).\n * ๋ผ์ด๋ธŒ tick ์žฌ๊ฐœ(sim ๊ฒฐ์ •์  re-run / live ์ธ์ œ์ŠคํŠธ ์ง€์†)๋Š” ํ›„์†. ์—ฌ๊ธฐ์„  ์ƒํƒœ ๋ณต์› + ๋…ธ์ถœ.\n */\n static async bootstrap(): Promise<void> {\n /* ๋ถ€ํŒ…๋ถ€ํ„ฐ ์žฐ๋‹ค โ€” ์‚ฌ๋žŒ์ด ๊ฐ€์žฅ ๋‹ต๋‹ตํ•œ ๊ตฌ๊ฐ„์ด ์—ฌ๊ธฐ์ด๊ณ , ๊ทธ ๊ตฌ๊ฐ„์„ ์žฌ์ง€ ์•Š์œผ๋ฉด ๊ฐ’์œผ๋กœ ๋งํ•  ์ˆ˜ ์—†๋‹ค. */\n loopLag.start()\n try {\n const repo = getRepository(TwinInstance)\n const rows = await repo.find({ where: { status: 'running' } })\n for (const row of rows) {\n if (!row.domainId || !row.instanceId) continue\n // ์›œ์Šคํƒ€ํŠธ: ์บ์‹œ๋œ ์ตœ์‹  ์Šค๋ƒ…์ƒท ์šฐ์„ (O(1) + attentions/OEE ๋“ฑ ๋ผ์ด๋ธŒ ํŒŒ์ƒ์ƒํƒœ ๋ณด์กด).\n // ์—†์œผ๋ฉด ์ €๋„ fold-from-0 replay(์ง„์‹ค ํด๋ฐฑ โ€” replay ๋Š” ๋ผ์ด๋ธŒ ํŒŒ์ƒ์ƒํƒœ๋ฅผ ๋ชป ๋‹ด์œผ๋ฏ€๋กœ ์บ์‹œ๊ฐ€ ๋” ์ถฉ์‹ค).\n const cached = await this.loadSnapshot(row.domainId, row.instanceId).catch(() => null)\n if (cached?.state) {\n /* ์˜ˆ์ „์— ๊ฒนํฌ์žฅ์œผ๋กœ ์ €์žฅ๋œ ๊ฐ’์ด ๋‚จ์•„ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค โ€” ์ฝ๋Š” ์ชฝ์—์„œ๋„ ๋ฒ—๊ธด๋‹ค(ํ•œ ๋ฒˆ์€ ๋ฐ˜๋“œ์‹œ ๋งŒ๋‚œ๋‹ค). */\n this.recovered[runtimeKey(row.domainId, row.instanceId)] = { revision: cached.revision, state: unwrapState(cached.state) }\n /*\n * **ใ€Œ์›œ์Šคํƒ€ํŠธํ–ˆ๋‹คใ€๊ณ  ๋งํ•˜์ง€ ์•Š๋Š”๋‹ค** โ€” ์—ฌ๊ธฐ์„œ๋Š” ์ƒํƒœ๋ฅผ **์ฐพ์•„ ๋‘” ๊ฒƒ**๋ฟ์ด๋‹ค.\n *\n * ์‹ค์ œ ์ฃผ์ž…์€ ๊ธฐ๋™ ๋•Œ ์ผ์–ด๋‚˜๊ณ (`warmStart` ๊ฐ€ ๊ทธ๋•Œ ๋ฌด์—‡์„ ์‹ฌ์—ˆ๋Š”์ง€ ๋งํ•œ๋‹ค), ๋ฏธ๋Ÿฌ(live) ํŠธ์œˆ์€\n * ๊ทธ ์”จ์•—์„ ์•„์˜ˆ ์“ฐ์ง€ ์•Š๋Š”๋‹ค(`startLive` ๊ฐ€ ๋ฒ„๋ฆฐ๋‹ค). ๊ทธ๋Ÿฐ๋ฐ ์ด ์ค„์ด ใ€Œwarm-startedใ€๋ผ๊ณ  ๋งํ•ด\n * ๋กœ๊ทธ๋งŒ ์ฝ์œผ๋ฉด ์‹ฌ๊ธด ์ค„ ์•Œ๊ฒŒ ๋œ๋‹ค โ€” ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ์ฝ๊ณ  ์žฌ๊ธฐ๋™ ๋’ค ์ง€์†์‹œ๊ฐ„์ด ์‚ฌ๋ผ์ง„ ๊ฒƒ์„\n * ๋ฐ์ดํ„ฐ ๋ฌธ์ œ๋กœ ์˜ค์ง„ํ•  ๋ป”ํ–ˆ๋‹ค.\n */\n twinLog(`[twin-engine] found cached state for \"${row.instanceId}\" โ†’ revision ${cached.revision} (seeded at start).`)\n continue\n }\n const state = await this.recover(row.domainId, row.instanceId).catch(() => null)\n if (state) {\n this.recovered[runtimeKey(row.domainId, row.instanceId)] = { revision: state.revision, state }\n twinLog(`[twin-engine] recovered \"${row.instanceId}\" from journal โ†’ revision ${state.revision}.`)\n }\n }\n /*\n * ์ƒํƒœ๋งŒ ๋˜์ฐพ๋Š” ๊ฒƒ์œผ๋กœ๋Š” **๋„๋Š” ํŠธ์œˆ์ด ๋˜์ง€ ์•Š๋Š”๋‹ค** โ€” ๋Ÿฐํƒ€์ž„๊นŒ์ง€ ๋˜์‚ด๋ฆฐ๋‹ค(์•„๋ž˜).\n *\n * ๋˜์‚ด๋ฆฌ๊ธฐ ์‚ฌ์ด์— **๋ฃจํ”„๋ฅผ ํ•œ ๋ฒˆ ๋น„์›Œ ์ค€๋‹ค** (2026-08-21). ์›œ์Šคํƒ€ํŠธ ํ•˜๋‚˜๊ฐ€ ๋ฌผํ’ˆ ์ˆ˜์ฒœ ๊ฐœ๋ฅผ ์ ‘์œผ๋ฏ€๋กœ\n * ์Šค๋ฌด ๊ฐœ๋ฅผ ์—ฐ๋‹ฌ์•„ ํ•˜๋ฉด ๊ทธ ์‹œ๊ฐ„ ๋‚ด๋‚ด HTTP ๊ฐ€ ์„œ์ง€ ์•Š๋Š”๋‹ค โ€” ์„œ๋ฒ„๋Š” ์ด๋ฏธ `Server ready` ๋ฅผ ์ฐ์€\n * ๋’ค๋ผ์„œ, ์‚ฌ๋žŒ์—๊ฒŒ๋Š” ใ€Œ์—ด๋ ธ๋Š”๋ฐ ์•„๋ฌด ๋ฐ˜์‘์ด ์—†๋Š” ํ™”๋ฉดใ€์œผ๋กœ ๋ณด์ธ๋‹ค. ์ด ์‹œ๊ฐ„์€ ๊ฐ™๊ณ , ๊ทธ ์‚ฌ์ด์—\n * ๋„์ฐฉํ•œ ์š”์ฒญ์ด ์ฒ˜๋ฆฌ๋  ํ‹ˆ๋งŒ ์ƒ๊ธด๋‹ค.\n */\n for (const row of rows) {\n await this.resumeRow(row)\n await new Promise(resolve => setTimeout(resolve, this.BOOT_YIELD_MS))\n }\n this.startCheckpointLoop() // ์ดํ›„ ๊ธฐ๋™๋˜๋Š” ๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค์˜ ์ตœ์‹  ์Šค๋ƒ…์ƒท์„ ์ฃผ๊ธฐ ์˜์†\n /*\n * ๋ณด์กด ์ •๋ฆฌ โ€” **์„ ์–ธ์ด ์žˆ์„ ๋•Œ๋งŒ** ๋ˆ๋‹ค(ยง`JOURNAL_RETENTION_DAYS`). ๋„๋ฉ”์ธ๋งˆ๋‹ค ํ•œ ๋ฒˆ ๊ฑด๋‹ค.\n * ์ฒดํฌํฌ์ธํŠธ ๋ฃจํ”„ ๋’ค์— ๋‘๋Š” ์ด์œ : ์ง€์šธ ์ˆ˜ ์žˆ๋Š” ๊ฒฝ๊ณ„๊ฐ€ ์Šค๋ƒ…์ƒท์ด๋ฏ€๋กœ, ์Šค๋ƒ…์ƒท์„ ๋‚จ๊ธฐ๋Š” ์ชฝ์ด ๋จผ์ €\n * ๋Œ์•„์•ผ ์ฒซ ์ •๋ฆฌ๊ฐ€ ์‹ค์ œ๋กœ ์ง€์šธ ๊ฒƒ์„ ๊ฐ–๋Š”๋‹ค.\n */\n for (const domainId of new Set(rows.map(r => r.domainId).filter(Boolean) as string[])) {\n this.startRetentionLoop(domainId)\n }\n } catch (err) {\n twinError('[twin-engine] recovery scan failed', err)\n }\n }\n\n /**\n * ๋ถ€ํŒ… ๋•Œ **๋„๋Š” ํŠธ์œˆ์„ ์‹ค์ œ๋กœ ๋˜์‚ด๋ฆฐ๋‹ค** โ€” ใ€Œ๋„๋Š” ์ค‘ใ€์ด ์‚ฌ์‹ค์ด ๋˜๊ฒŒ.\n *\n * โ”€โ”€ ๋ฌด์—‡์ด ๊ฑฐ์ง“๋ง์ด์—ˆ๋‚˜ (2026-08-14) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * `bootstrap()` ์€ ์ƒํƒœ๋งŒ ๋˜์ฐพ์•„ `recovered` ์— ๋‹ด์•˜๊ณ , ์ปค๋„์„ ์„ธ์šฐ๋Š” ๊ฒƒ์€ **๋ช…์‹œ mutation ๋ฟ**์ด์—ˆ๋‹ค\n * (์ด ํŒŒ์ผ ์œ„์ชฝ ์ฃผ์„์ด ใ€Œํ–ฅํ›„ใ€๋ผ๊ณ  ์ ์–ด ๋‘” ๊ทธ ์ž๋ฆฌ๋‹ค). ๊ทธ๋ž˜์„œ ์„œ๋ฒ„๋ฅผ ํ•œ ๋ฒˆ ์žฌ๊ธฐ๋™ํ•˜๋ฉด ๋“ฑ๋ก๋ถ€๋Š”\n * `running` ์ด๋ผ ๋งํ•˜๋Š”๋ฐ **์•„๋ฌด ์ปค๋„๋„ ๋Œ์ง€ ์•Š์•˜๋‹ค** โ€” ํ™”๋ฉด์€ ๋„๋Š” ํŠธ์œˆ์„, ์‹ค์ œ๋กœ๋Š” ๋ฉˆ์ถ˜ ํŠธ์œˆ์„.\n * ๋ฏธ๋Ÿฌ ํŠธ์œˆ์—์„œ๋Š” ๋” ๋‚˜์˜๋‹ค: ๊ณ„์ธก์ด ์กฐ์šฉํžˆ ๋Š๊ธฐ๊ณ , ์‚ฌ๋žŒ์€ ใ€Œ๊ฐ’์ด ์•ˆ ๋ณ€ํ•˜๋„คใ€๋กœ ์•Œ๊ฒŒ ๋œ๋‹ค.\n *\n * โ”€โ”€ ๋ชจ๋“œ๋ฅผ ์ง€์–ด๋‚ด์ง€ ์•Š๋Š”๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๋ฏธ๋Ÿฌ์˜€๋˜ ํŠธ์œˆ์„ ์‹œ๋ฎฌ๋กœ ๋˜์‚ด๋ฆฌ๋ฉด **์—†๋˜ ์›€์ง์ž„์„ ๋งŒ๋“ค์–ด ๋‚ธ๋‹ค**(๊ด€์ธก ํŠธ์œˆ์ด ์Šค์Šค๋กœ ๋ฌผ๊ฑด์„ ์˜ฎ๊ธด๋‹ค).\n * ๊ทธ๋ž˜์„œ ์„ ์–ธ๋œ `restartPolicy` ๊ทธ๋Œ€๋กœ ๋˜์‚ด๋ฆฐ๋‹ค โ€” ๋ฏธ๋Ÿฌ๋Š” ๊ด€์ธก ๊ตฌ๋™์œผ๋กœ, ์‹œ๋ฎฌ์€ ์‹œ๋ฎฌ๋กœ.\n *\n * โ”€โ”€ ๋˜์‚ด๋ฆด ์ˆ˜ ์—†์œผ๋ฉด ๊ทธ๋ ‡๊ฒŒ ์ ๋Š”๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์‹คํŒจ๋ฅผ ์‚ผํ‚ค๋ฉด ๋“ฑ๋ก๋ถ€๊ฐ€ ๊ณ„์† `running` ์ด๋ผ ๋งํ•œ๋‹ค โ€” ์šฐ๋ฆฌ๊ฐ€ ๊ณ ์น˜๋ ค๋˜ ๊ทธ ๊ฑฐ์ง“๋ง์ด๋‹ค. ๊ทธ๋ž˜์„œ ์‹คํŒจํ•œ\n * ํ–‰์€ `stopped` ๋กœ ์ ๊ณ  ์ด์œ ๋ฅผ ๋‚จ๊ธด๋‹ค. ใ€Œ๋ฉˆ์ท„๋‹คใ€๋Š” ์‚ฌ์‹ค์ด๊ณ , ใ€Œ๋„๋Š” ์ค‘ใ€์€ ์‚ฌ์‹ค์ด ์•„๋‹ˆ์—ˆ๋‹ค.\n */\n private static async resumeRow(row: TwinInstance): Promise<void> {\n const { domainId, instanceId } = row\n if (!domainId || !instanceId) return\n if (this.instances[runtimeKey(domainId, instanceId)]) return // ์ด๋ฏธ ์„ธ์›Œ์กŒ๋‹ค(๋ฐ๋ชจ ์‹œ๋“œ ๋“ฑ)\n\n /*\n * ๋ฒค์น˜ ์‚ฌ๋ณธ์€ ๋˜์‚ด๋ฆฌ์ง€ ์•Š๋Š”๋‹ค โ€” ๊ทธ๊ฒƒ์€ **๋ˆ„๊ตฐ๊ฐ€ ์ง€์ผœ๋ณด๋˜ ์‹คํ—˜**์ด๊ณ , ๋ฌด์ธ์œผ๋กœ ๋˜์‚ด์•„๋‚˜๋ฉด ํ˜ธ์ŠคํŠธ๋ฅผ\n * ๊ทธ๋Œ€๋กœ ๋‘๋“ค๊ธด๋‹ค(๊ฒฉ๋ฆฌ ์‚ฌ๋ณธ์˜ ๋œป์€ ใ€Œ์šด์˜๊ณผ ์„ž์ด์ง€ ์•Š๋Š”๋‹คใ€์ด์ง€ ใ€Œ์˜์›ํžˆ ๋ˆ๋‹คใ€๊ฐ€ ์•„๋‹ˆ๋‹ค).\n * ์‹คํ—˜์€ ์žฌ๊ธฐ๋™์„ ๋„˜๊ธฐ์ง€ ๋ชปํ–ˆ์œผ๋ฏ€๋กœ ๋“ฑ๋ก๋ถ€๋„ ๊ทธ๋ ‡๊ฒŒ ์ ๋Š”๋‹ค.\n */\n if (row.purpose === 'bench') {\n await this.markStopped(row, 'bench copy โ€” an experiment does not survive a restart unattended')\n return\n }\n\n try {\n /*\n * **์„ ์–ธ๋œ ๋ชจ๋“œ๋กœ ๋˜์‚ด๋ฆฌ๋Š” ํŒ๋‹จ์€ ํ•œ ๊ณณ์— ์žˆ๋‹ค**(`startFromRegistry`) โ€” 2026-08-20.\n *\n * ์˜ˆ์ „์—๋Š” ์ด ์ž๋ฆฌ์—์„œ `resync` ๋ฅผ ๊ฐˆ๋ผ `startLive` ๋ฅผ ๋ถˆ๋ €๋‹ค. ๊ทธ๋ž˜์„œ ๋ถ€ํŒ…์œผ๋กœ ์‚ด์•„๋‚œ ๋ฏธ๋Ÿฌ๋Š”\n * ๊ด€์ธก ๊ตฌ๋™์ด์—ˆ์ง€๋งŒ **์‚ฌ๋žŒ์ด ํ™”๋ฉด์—์„œ ์‹œ์ž‘ํ•œ ๋ฏธ๋Ÿฌ๋Š” ์‹œ๋ฎฌ๋กœ ๋–ด๋‹ค**(๊ทธ ๋ฌธ์—๋Š” ๊ฐˆ๋ฆผ์ด ์—†์—ˆ๋‹ค).\n * ๊ฐ™์€ ์„ ์–ธ์ด ๋‘ ๊ฒฐ๊ณผ๋ฅผ ๋‚ด์ง€ ์•Š๋„๋ก ๊ฐˆ๋ฆผ์„ ๋ฌธ ์•ˆ์œผ๋กœ ์˜ฎ๊ฒผ๋‹ค.\n */\n await this.startFromRegistry(domainId, instanceId)\n if (row.restartPolicy === 'resync') {\n /* ๊ณ„์ธก์„ ๋‚˜๋ฅด๋Š” ํ”ผ๋“œ๋Š” ์ปค๋„ฅํ„ฐ์˜ ๊ฒƒ์ด๋‹ค โ€” ๋ ˆํผ๋Ÿฐ์Šค ๊ณ„์ธต์ด ๋ถ€ํŒ… ํ›…์—์„œ ๋‹ค์‹œ ๋ถ™์ธ๋‹ค\n (`resumeReferenceLiveFeeds`). ์—ฌ๊ธฐ์„œ ์–ด๋Œ‘ํ„ฐ๋ฅผ ์•„๋Š” ๊ฒƒ์€ ๊ณ„์ธต์„ ๊ฑฐ๊พธ๋กœ ์ž‡๋Š” ๊ฒƒ์ด๋‹ค. */\n twinLog(`[twin-engine] resumed mirror \"${instanceId}\" โ€” feed reattach is the reference layer's job.`)\n } else {\n twinLog(`[twin-engine] resumed ${row.restartPolicy} \"${instanceId}\".`)\n }\n } catch (err: any) {\n await this.markStopped(row, err?.message ?? 'resume failed')\n }\n }\n\n /** ๋˜์‚ด๋ฆฌ์ง€ ๋ชปํ•œ ํ–‰์„ ์ •์งํ•˜๊ฒŒ ์ ๋Š”๋‹ค โ€” ใ€Œ๋„๋Š” ์ค‘ใ€์ด๋ผ ๋งํ•˜๋Š” ์ฑ„๋กœ ๋‘์ง€ ์•Š๋Š”๋‹ค. */\n private static async markStopped(row: TwinInstance, why: string): Promise<void> {\n twinWarn(`[twin-engine] \"${row.instanceId}\" not resumed (${why}) โ€” registry says stopped now.`)\n try {\n await getRepository(TwinInstance).update({ id: row.id }, { status: 'stopped' })\n } catch (e: any) {\n twinError(`[twin-engine] could not mark \"${row.instanceId}\" stopped โ€” registry now lies about it.`, e?.message)\n }\n }\n\n /**\n * ์›œ์Šคํƒ€ํŠธ โ€” ๊ธฐ๋™ํ•˜๋Š” ์ปค๋„์— **์ง์ „ ๊ด€์ธก ์ƒํƒœ**๋ฅผ ์ฃผ์ž…ํ•œ๋‹ค.\n *\n * โ”€โ”€ ์™œ ํ•„์š”ํ•œ๊ฐ€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * `loadTwinModel` ๋Š” **๊ตฌ์กฐ๋งŒ** ์‹ฃ๋Š”๋‹ค(์ž๋ฆฌยท์„ค๋น„). ์ƒํƒœ(๋ฌด์—‡์ด ์–ด๋””์— ์–ผ๋งˆ๋‚˜)๋Š” ์—†๋‹ค. ๊ทธ๋ž˜์„œ ์žฌ๊ธฐ๋™ํ•œ\n * ํŠธ์œˆ์€ ์ €๋„์— ์ž…๊ณ  540๊ฑด์ด ๋‚จ์•„ ์žˆ์–ด๋„ ์žฌ๊ณ ๊ฐ€ 0 ์ด์—ˆ๊ณ , ํ™”๋ฉด์€ \"๋ณด์œ  ์ค‘์ธ ๊ฒƒ์ด ์—†์Šต๋‹ˆ๋‹ค\" ๋ผ๊ณ \n * ๋งํ–ˆ๋‹ค โ€” ์žˆ๋Š” ์žฌ๊ณ ๋ฅผ ์—†๋‹ค๊ณ  ํ•˜๋Š” ์…ˆ์ด๋‹ค(2026-07-31 hatiolab-wms ์‹ค์ธก์œผ๋กœ ํ™•์ธ).\n * `bootstrap()` ์ด ์ด๋ฏธ ์ฒดํฌํฌ์ธํŠธ ์บ์‹œ(์—†์œผ๋ฉด ์ €๋„ replay)๋กœ ์ƒํƒœ๋ฅผ ๋ณต๊ตฌํ•ด `recovered` ์— ๋‹ด์•„ ๋‘๋Š”๋ฐ,\n * ๊ธฐ๋™ ์ˆœ๊ฐ„ ๊ทธ๊ฑธ **๋ฒ„๋ฆฌ๊ณ ** ์žˆ์—ˆ๋‹ค. ๋ฐ˜๋งŒ ์—ฐ๊ฒฐ๋ผ ์žˆ๋˜ ์žฅ์น˜๋ฅผ ์ž‡๋Š”๋‹ค.\n *\n * โ”€โ”€ ๋ฐ˜์ชฝ์ด๋˜ ๋ณต๊ตฌ๋ฅผ ๋งˆ๋ฌด๋ฆฌํ•œ๋‹ค (2026-08-05) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์žฌ๊ณ ๋Š” ์‚ด์•„๋‚ฌ๋Š”๋ฐ **์ง„ํ–‰ ์ค‘ ์ฃผ๋ฌธ์ด ํ†ต์งธ๋กœ ์‚ฌ๋ผ์ง„** ํ™”๋ฉด์ด ๋‚จ์•„ ์žˆ์—ˆ๋‹ค. ์”จ์•—์ด ์ž๋ฆฌยท๋ฌผํ’ˆยท์„ค๋น„\n * ์…‹๋งŒ ๋„˜๊ฒผ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ ๊ทผ๊ฑฐ๋Š” \"์Šค๋ƒ…์ƒท ์˜ค๋”์— progress ๋ฐ–์— ์—†๋‹ค\" ์˜€๊ณ , ๊ทธ๋•Œ๋Š” ๋งž์•˜๋‹ค โ€”\n * ๊ทธ๋Ÿฌ๋‚˜ ์ปค๋„ `OrderState` ๊ฐ€ ์›๊ฐ’(`requested`ยท`fulfilled`ยท`lines`)์„ ๋˜์ฐพ์€ ๋’ค์—๋„ ์ด ์ž๋ฆฌ๋งŒ\n * ๊ทธ๋Œ€๋กœ ๋‚จ์•˜๋‹ค. ์˜ค๋ฅ˜๋ฅผ ๋‚ด์ง€ ์•Š๋Š” ์ข…๋ฅ˜๋ผ ์˜ค๋ž˜ ๋ฒ„ํ…ผ๋‹ค.\n *\n * ์ง€๊ธˆ์€ **๊ด€์ธก ์Šค๋ƒ…์ƒท ์ „์ฒด**๋ฅผ ๋„˜๊ธด๋‹ค(์˜ค๋”ยท์ž‘์—…ยท์‚ฌ๋žŒยท์ž์‚ฐ ํฌํ•จ). ์‹œ๋ฎฌ์€ ์ปค๋„ `snapshot()`,\n * ๋ผ์ด๋ธŒ๋Š” `StateProjector` ๊ฐ€ ๊ทธ ์ผ๊ณฑ ์ถ•์„ ๋ชจ๋‘ ๋‹ด๋Š”๋‹ค. ๋ฌด์—‡์„ ์‹ฌ์„ ์ˆ˜ ์žˆ๋Š”์ง€ ํŒ์ •ํ•˜๋Š” ๊ทœ์น™\n * (์ดํ–‰ ์™„๋ฃŒ ์˜ค๋” ์ œ์™ธยท๊ณ ์•„ ์ž‘์—… ์ œ์™ธ)์€ ์ปค๋„์— ์žˆ๊ณ , ํ˜ธ์ŠคํŠธ๊ฐ€ ๋ฏธ๋ฆฌ ๊ณจ๋ผ๋‚ด์ง€ ์•Š๋Š”๋‹ค.\n *\n * โ”€โ”€ ๋‚จ์€ ํ•œ๊ณ„๋Š” ์ˆจ๊ธฐ์ง€ ์•Š๊ณ  ์„ผ๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ยท ์›๊ฐ’์ด ์—†๋Š” ์˜ค๋”(progress ๋งŒ ์žˆ๋Š” ๊ฒƒ)๋Š” ๋‚จ์€ ์ˆ˜๋Ÿ‰์„ ์•Œ ์ˆ˜ ์—†์–ด ์ฃผ์ž…ํ•˜์ง€ ์•Š๋Š”๋‹ค. **์ง€์–ด๋‚ด์ง€ ์•Š๋Š”\n * ๋Œ€์‹  ๋ช‡ ๊ฑด์ธ์ง€ ๋งํ•œ๋‹ค** โ€” ์„ธ์ง€ ์•Š์œผ๋ฉด \"์ฃผ๋ฌธ์ด ์—†๋‹ค\" ์™€ \"์ฃผ๋ฌธ์„ ๋ชป ์‹ฌ์—ˆ๋‹ค\" ๊ฐ€ ํ™”๋ฉด์—์„œ ๊ฐ™์•„์ง„๋‹ค.\n * ยท ์ง„ํ–‰ ์ค‘ ๊ฐœ๋ณ„ ์ž‘์—…์˜ ๋‚ด๋ถ€ ์ƒํƒœ๋Š” ๊ด€์ธก๋งŒ์œผ๋กœ ์™„์ „ํžˆ ๋ณต์›๋˜์ง€ ์•Š๋Š”๋‹ค(์ปค๋„์ด ๋ช…์‹œํ•œ ํ•œ๊ณ„, ์žฌ๊ณ„ํš์— ๋งก๊น€).\n *\n * โ”€โ”€ ๋ฒค์น˜๋Š” ์‹œ๋“œํ•˜์ง€ ์•Š๋Š”๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๋ถ€ํ•˜ ๋ฒค์น˜๋Š” **์ƒˆ ์‹œ์ž‘์—์„œ ์šฉ๋Ÿ‰์„ ์žฌ๋Š” ๊ฒƒ**์ด ๋ชฉ์ ์ด๋ผ ํ˜„์žฌ ์ƒํƒœ๋ฅผ ์ฃผ์ž…ํ•˜๋ฉด ์ธก์ •์ด ์˜ค์—ผ๋œ๋‹ค.\n */\n private static warmStart(domainId: string, id: string, kernel: TwinKernel, purpose?: string): void {\n const hydrate = (kernel as any).hydrateObserved\n const plan = planWarmStart(this.recovered[runtimeKey(domainId, id)]?.state, purpose, typeof hydrate === 'function')\n\n if (plan.action === 'skip') {\n if (plan.reason === 'bench') {\n twinLog(`[twin-engine] \"${id}\" is a bench twin โ€” starting empty on purpose (seeding would skew the measurement).`)\n } else if (plan.reason === 'unsupported') {\n twinWarn(\n `[twin-engine] kernel for \"${id}\" cannot be warm-started (no hydrateObserved) โ€” it starts with structure only, so held stock will read as zero.`\n )\n }\n return\n }\n\n hydrate.call(kernel, plan.seed)\n const restored = [\n `${plan.itemCount} item(s)`,\n `${plan.equipmentCount} equipment`,\n `${plan.orderCount} open order(s)`,\n `${plan.taskCount} task(s)`,\n ...(plan.personCount ? [`${plan.personCount} person(s)`] : []),\n ...(plan.assetCount ? [`${plan.assetCount} asset(s)`] : []),\n /* ํ™•์ธํ•ด ๋‘” ์‹ ํ˜ธ๋ฅผ ์ด์–ด๋ฐ›์•˜๋‹ค๋Š” ์‚ฌ์‹ค๋„ ๋งํ•œ๋‹ค โ€” ์žƒ์œผ๋ฉด ํ™•์ธ ์ฒ˜๋ฆฌ๊ฐ€ ๋‹ค์‹œ ๋นจ๊ฐœ์ง€๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ธ๋‹ค. */\n ...(plan.ackedCount ? [`${plan.ackedCount} acknowledged attention(s)`] : []),\n /* ใ€Œ์–ธ์ œ๋ถ€ํ„ฐ์ธ๊ฐ€ใ€๋„ ๋งํ•œ๋‹ค โ€” ์žƒ์œผ๋ฉด ์ง€์†๋œ ์กฐ๊ฑด์ด ๋ชจ๋‘ ใ€Œ๋ฐฉ๊ธˆใ€์œผ๋กœ ๋ณด์ธ๋‹ค. */\n ...(plan.attentionSinceCount ? [`${plan.attentionSinceCount} attention start time(s)`] : [])\n ].join(', ')\n twinLog(`[twin-engine] warm-started \"${id}\" โ€” restored ${restored}.`)\n /* ๋บ€ ๊ฒƒ์€ ์กฐ์šฉํžˆ ๋„˜๊ธฐ์ง€ ์•Š๋Š”๋‹ค โ€” ์ง€์–ด๋‚ด์ง€ ์•Š์•˜๋‹ค๋Š” ์‚ฌ์‹ค ์ž์ฒด๋ฅผ ๋งํ•ด์•ผ ํ™”๋ฉด์˜ ๋นˆ์นธ์ด ์ฝํžŒ๋‹ค. */\n if (plan.ordersWithoutDemand > 0) {\n twinWarn(\n `[twin-engine] \"${id}\": ${plan.ordersWithoutDemand} order(s) could not be restored โ€” they carry progress only, ` +\n 'with no requested/fulfilled counts, so the remaining demand is unknown. They are left out rather than guessed.'\n )\n }\n }\n\n /** ํŠธ์œˆ ์ธ์Šคํ„ด์Šค ์‹œ์ž‘ โ€” ์ปค๋„ ์ƒ์„ฑ + ๋ชจ๋ธ ๋กœ๋“œ + ์ง์ „ ์ƒํƒœ ์›œ์Šคํƒ€ํŠธ + State ์ŠคํŠธ๋ฆผ ๋ธŒ๋ฆฌ์ง€ + ์›Œ์ปค tick + ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์˜์†. */\n /**\n * ๊ณต์ • ๋ช…์„ธ๋ฅผ ์ปค๋„์— ์‹ฃ๋Š”๋‹ค โ€” **์‹œ๋ฎฌ๋ ˆ์ด์…˜์˜ ์‹œ๊ฐ„์„ ๋ฐ์ดํ„ฐ๊ฐ€ ๋งํ•˜๊ฒŒ ํ•˜๋Š” ๋งˆ์ง€๋ง‰ ํ•œ ์นธ.**\n *\n * `model.operations`(๋งˆ์Šคํ„ฐ ์ธ์ œ์ŠคํŠธ๊ฐ€ ํ†ต๊ณผ์‹œํ‚จ ISA-95 OperationsSegment ๋ช…์„ธ)๋ฅผ ์ปค๋„์ด ์†Œ๋น„ํ•œ๋‹ค.\n * ์—†์œผ๋ฉด ์ปค๋„ ๊ธฐ๋ณธ ์ƒ์ˆ˜๋กœ ๊ตด๋Ÿฌ๊ฐ€๊ณ , ์ปค๋„ `specCoverage()` ๊ฐ€ ๋ฌด์—‡์„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ผ๋Š”์ง€ ๋ณด๊ณ ํ•œ๋‹ค.\n *\n * ์ปค๋„์ด ์•„์ง ์ด API ๋ฅผ ๊ฐ–์ง€ ์•Š์€ ๋ฒ„์ „์ด๋ฉด(๋ฐœํ–‰ ์ด์ „) **์กฐ์šฉํžˆ ๋„˜์–ด๊ฐ€์ง€ ์•Š๊ณ  ๊ฒฝ๊ณ ํ•œ๋‹ค** โ€” ๋ช…์„ธ๋ฅผ\n * ์„ ์–ธํ–ˆ๋Š”๋ฐ ๋ฐ˜์˜๋˜์ง€ ์•Š๋Š” ์ƒํƒœ๋ฅผ ๋ชจ๋ฅด๊ณ  ์ง€๋‚˜๊ฐ€๋ฉด, ์˜ˆ์ธก์ด ์ƒ์ˆ˜๋กœ ๋Œ์•„๊ฐ„ ๊ฒƒ์„ ์•„๋ฌด๋„ ์•Œ ์ˆ˜ ์—†๋‹ค.\n */\n private static applyOperations(kernel: any, model: any, id: string): void {\n /*\n * ํ˜„์žฅ์ด ์ •ํ•œ ๊ณต์ • ์‹œ๊ฐ„ โ€” ๋ช…์„ธ ํ–‰๊ณผ **๋”ฐ๋กœ** ์‹ฃ๋Š”๋‹ค(`declareDurations`).\n *\n * ํ–‰์ด ์—†๋Š” ์ข…๋ฅ˜์—๋„ ์‹œ๊ฐ„์„ ์ค„ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค: ์‹ค์ธก์œผ๋กœ ์ฐฝ๊ณ ยท์•ผ๋“œ ํŠธ์œˆ์—๋Š” ๊ณต์ • ๋ช…์„ธ ํ–‰์ด 0๊ฐœ์˜€๊ณ ,\n * ๊ทธ ํŠธ์œˆ๋“ค์˜ ์‹œ๊ฐ„์€ ์ „๋ถ€ ์ปค๋„ ์ƒ์ˆ˜์—์„œ ์™”๋‹ค. ํ–‰์„ ์ง€์–ด ๋งŒ๋“œ๋Š” ๊ธธ์€ ๋ง‰์•˜๋‹ค(`label`ยท`intent` ๋ฅผ\n * ์ง€์–ด๋‚ด๋ฉด ๋Šฅ๋ ฅ ๊ณ„์‚ฐ๊นŒ์ง€ ์˜ค์—ผ๋œ๋‹ค) โ€” ๊ทธ๋ž˜์„œ ์‹œ๊ฐ„๋งŒ ๋ฐ›๋Š” ์ฐฝ๊ตฌ๊ฐ€ ์ปค๋„์— ์žˆ๋‹ค.\n */\n const declared = model?.localDurations as Record<string, string> | undefined\n if (declared && Object.keys(declared).length) {\n if (typeof kernel?.declareDurations !== 'function') {\n twinWarn(\n `[twin-engine] \"${id}\": this facility declared ${Object.keys(declared).length} operation duration(s) but the kernel cannot consume them ` +\n '(declareDurations missing โ€” kernel needs publishing). The simulation keeps running on built-in constants, and specCoverage() will keep reporting \"default\".'\n )\n } else {\n try {\n kernel.declareDurations(declared)\n } catch (err: any) {\n /* ์ปค๋„์ด ๊ฑฐ์ ˆํ•œ ๊ฐ’์€ ์กฐ์šฉํžˆ ๋„˜๊ธฐ์ง€ ์•Š๋Š”๋‹ค โ€” ํ™”๋ฉด์€ ใ€Œ๋„ฃ์—ˆ์Šต๋‹ˆ๋‹คใ€๋ผ๊ณ  ๋งํ•œ ๊ฐ’์ด๋‹ค. */\n twinWarn(`[twin-engine] \"${id}\": declared operation duration rejected by the kernel โ€” ${err?.message ?? err}`)\n }\n }\n }\n /* ๊ณต์ • ๋ชจ์ˆ˜(์ˆ˜์œจยท์…‹์—…)๋„ ๊ฐ™์€ ๊ทœ์œจ๋กœ ์‹ฃ๋Š”๋‹ค โ€” ์ปค๋„์ด ๊ทธ ์ฐฝ๊ตฌ๋ฅผ ๊ฐ–์ง€ ์•Š์œผ๋ฉด ๊ทธ ์‚ฌ์‹ค์„ ๋งํ•œ๋‹ค. */\n const params = model?.localParams as Record<string, Record<string, string>> | undefined\n if (params && Object.keys(params).length) {\n if (typeof kernel?.declareParameters !== 'function') {\n twinWarn(\n `[twin-engine] \"${id}\": this facility declared operation parameters for ${Object.keys(params).length} operation(s) but the kernel cannot consume them ` +\n '(declareParameters missing โ€” kernel needs publishing). Yield and setup keep running on built-in constants.'\n )\n } else {\n try {\n kernel.declareParameters(params)\n } catch (err: any) {\n twinWarn(`[twin-engine] \"${id}\": declared operation parameter rejected by the kernel โ€” ${err?.message ?? err}`)\n }\n }\n }\n const ops = model?.operations\n if (!ops?.length) return\n if (typeof kernel?.loadOperations !== 'function') {\n twinWarn(`[twin-engine] \"${id}\": model declares ${ops.length} operation spec(s) but the kernel cannot consume them (loadOperations missing โ€” kernel needs publishing). Simulation will use built-in default durations.`)\n return\n }\n kernel.loadOperations(ops)\n }\n\n /**\n * ์†Œ์š”์‹œ๊ฐ„ ์ถ”์ •๊ธฐ ์ฃผ์ž… โ€” **์ƒ์ˆ˜๋ฅผ ๋ฐ์ดํ„ฐ๋กœ ๋ฐ”๊พธ๋Š” ๋‘ ๋ฒˆ์งธยท์„ธ ๋ฒˆ์งธ ์ธต.**\n *\n * ์ปค๋„ `durationOf` ์˜ ์šฐ์„ ์ˆœ์œ„๋Š” ์ถ”์ •๊ธฐ > ๋ช…์„ธ > ์ƒ์ˆ˜๋‹ค. ๊ทธ ์ถ”์ •๊ธฐ ์ž๋ฆฌ์— ๋‘ ๊ฐ€์ง€๋ฅผ ์‚ฌ์Šฌ๋กœ ๋„ฃ๋Š”๋‹ค:\n * โ‘  **์‹ค์ธก**(์ €๋„์˜ ์ž‘์—… ์ข…๋ฅ˜๋ณ„ ์ž‘์—…์‹œ๊ฐ„ p50) โ€” ๊ทธ ํ˜„์žฅ์—์„œ ์‹ค์ œ๋กœ ์–ผ๋งˆ ๊ฑธ๋ ธ๋‚˜. ๊ฐ€์žฅ ๊ฐ•ํ•œ ๊ทผ๊ฑฐ.\n * โ‘ก **๊ฑฐ๋ฆฌ ร— ์†๋„**(model.layout + ์„ค๋น„ ์†๋„ ์†์„ฑ) โ€” ์ด๋™์€ ๊ฑฐ๋ฆฌ์— ๋น„๋ก€ํ•œ๋‹ค. ์ปค๋„์€ ์ขŒํ‘œ๋ฅผ ๋ชจ๋ฅด๋ฏ€๋กœ\n * ํ˜ธ์ŠคํŠธ๊ฐ€ ๊ณ„์‚ฐํ•ด ๋„ฃ๋Š”๋‹ค.\n * ๋‘˜ ๋‹ค ๋ชป ๋งŒ๋“ค๋ฉด ์ฃผ์ž…ํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” ์ปค๋„์ด ๋ช…์„ธยท์ƒ์ˆ˜๋กœ ๊ตด๋Ÿฌ๊ฐ€๊ณ  `specCoverage()` ๊ฐ€ ๊ทธ ์‚ฌ์‹ค์„ ๋‚จ๊ธด๋‹ค.\n *\n * ์‹ค์ธก์€ DB ์กฐํšŒ๋ผ ๋น„๋™๊ธฐ๋‹ค. ๊ทธ๋ž˜์„œ ์ด ํ•จ์ˆ˜๋Š” **await ํ•˜์ง€ ์•Š๋Š” ์ชฝ์—์„œ๋„ ์•ˆ์ „**ํ•˜๋„๋ก ์‹คํŒจ๋ฅผ ์‚ผํ‚ค๋˜,\n * ๋ฌด์—‡์„ ์™œ ๋ชป ๋„ฃ์—ˆ๋Š”์ง€๋Š” ๋กœ๊ทธ๋กœ ๋‚จ๊ธด๋‹ค(์กฐ์šฉํ•œ ๋ฌดํšจํ™” ๊ธˆ์ง€).\n */\n static async installEstimators(kernel: any, domainId: string, instanceId: string, model: any): Promise<void> {\n if (!kernel || typeof kernel !== 'object') return\n const travel = buildTravelEstimator({ layout: model?.layout, equipment: model?.equipment, unit: model?.unit })\n const measured = await this.measuredEstimator(domainId, instanceId)\n const chained = chainEstimators([measured?.estimator, travel.estimator])\n if (!chained) {\n /* ์™œ ๋ชป ๋„ฃ์—ˆ๋Š”์ง€ ํ•œ ๋ฒˆ๋งŒ ์•Œ๋ฆฐ๋‹ค โ€” ์ด๋™์‹œ๊ฐ„์ด ์ƒ์ˆ˜๋กœ ๋‚จ์€ ์ด์œ ๋ฅผ ๋ชจ๋ฅด๊ณ  ์ง€๋‚˜๊ฐ€์ง€ ์•Š๊ฒŒ. */\n if (travel.reasons.length) twinWarn(`[twin-engine] \"${instanceId}\": no duration estimator installed โ€” ${travel.reasons.join('; ')}`)\n return\n }\n kernel.durationEstimator = chained\n /*\n * **์–‘ํ’ˆ๋ฅ ๋„ ์ด๋ ฅ์—์„œ ๋ฐฐ์šด๋‹ค** (2026-08-19) โ€” ์†Œ์š”์™€ ๊ฐ™์€ ์ž๋ฆฌ์—์„œ ๋ถ™์ธ๋‹ค.\n *\n * ์ปค๋„์ด ๊ทธ ์‹œ์ž„์„ ๊ฐ–์ง€ ์•Š์€ ๋ฒ„์ „์ด๋ฉด(๋ฐœํ–‰ ์ด์ „) ์กฐ์šฉํžˆ ๋„˜์–ด๊ฐ€์ง€ ์•Š๊ณ  ๋งํ•œ๋‹ค: ์ˆ˜์œจ์ด ์ƒ์ˆ˜๋กœ ๋‚จ์€\n * ์ด์œ ๋ฅผ ๋ชจ๋ฅด๊ณ  ์ง€๋‚˜๊ฐ€๋ฉด, ํ™”๋ฉด์˜ ๋ถˆ๋Ÿ‰ ํŒ์ •์ด ๊ทธ ํ˜„์žฅ์˜ ์‚ฌ์‹ค์ด ์•„๋‹ˆ๋ผ ์šฐ๋ฆฌ ์ƒ์ˆ˜์˜ ๊ฒฐ๊ณผ๋‹ค.\n */\n const yields = await this.measuredYield(domainId, instanceId)\n if (yields?.estimator) {\n if (typeof kernel.yieldOf !== 'function') {\n twinWarn(\n `[twin-engine] \"${instanceId}\": learned yield for ${Object.keys(yields.learned).length} operation kind(s) but the kernel cannot consume it ` +\n '(yieldOf missing โ€” kernel needs publishing). Yield keeps running on the declared value or the built-in constant.'\n )\n } else {\n kernel.yieldEstimator = yields.estimator\n twinLog(\n `[twin-engine] \"${instanceId}\": measured yield installed โ€” ${Object.entries(yields.learned)\n .map(([k, v]) => `${k}=${Math.round(v * 1000) / 10}%(${yields.samples[k].good + yields.samples[k].scrap}๊ฑด)`)\n .join(', ')}${yields.skipped.length ? ` ยท ํ‘œ๋ณธ ๋ถ€์กฑ์œผ๋กœ ๋บ€ ์ข…๋ฅ˜: ${yields.skipped.map(s => `${s.kind}(${s.judged})`).join(', ')}` : ''}`\n )\n }\n } else if (yields?.skipped.length) {\n /* ๋ฐฐ์šด ๊ฒƒ์ด ์—†๊ณ  ๋ฒ„๋ฆฐ ๊ฒƒ๋งŒ ์žˆ์œผ๋ฉด ๊ทธ ์‚ฌ์‹ค๋„ ๋งํ•œ๋‹ค โ€” ใ€Œ์ด๋ ฅ์ด ์—†๋‹คใ€์™€ ใ€Œํ‘œ๋ณธ์ด ๋ชจ์ž๋ผ๋‹คใ€๋Š” ๋‹ค๋ฅด๋‹ค. */\n twinLog(\n `[twin-engine] \"${instanceId}\": no measured yield yet โ€” samples below ${yields.minSamples}: ${yields.skipped\n .map(s => `${s.kind}(${s.judged})`)\n .join(', ')}`\n )\n }\n const learned = Object.keys(measured?.learned ?? {})\n const spread = Object.keys(measured?.spreads ?? {})\n twinLog(\n `[twin-engine] \"${instanceId}\": duration estimator installed โ€” measured kinds: ${learned.length ? learned.join(',') : 'none'}` +\n ` (with observed spread: ${spread.length ? spread.join(',') : 'none'})` +\n `${travel.estimator ? `, travel from distance (speeds: ${Object.keys(travel.speedsByKind).join(',')})` : `, travel not derived (${travel.reasons.join('; ')})`}`\n )\n }\n\n /**\n * ์‹ค์ธก ์ถ”์ •๊ธฐ โ€” **์˜ˆ์ธก ์š”์ฒญ๋งˆ๋‹ค ์ €๋„์„ ๋‹ค์‹œ ์ ‘์ง€ ์•Š๋Š”๋‹ค.**\n *\n * ์˜ˆ์ธก ์ปค๋„์€ ์š”์ฒญ๋งˆ๋‹ค ์ƒˆ๋กœ ์„ธ์›Œ์ง€๊ณ (๋ฏธ๋Ÿฌ ์˜ˆ์ธกยท๋ฐฑํ…Œ์ŠคํŠธ), ํ™”๋ฉด์€ ์‹œ๊ฐ์„ ๊ธ์œผ๋ฉด ๊ณ„์† ์žฌ์˜ˆ์ธกํ•œ๋‹ค.\n * ๊ฑฐ๊ธฐ์— KPI ์กฐํšŒ๋ฅผ ๊ทธ๋Œ€๋กœ ๋‹ฌ๋ฉด ์š”์ฒญ๋‹น ์ €๋„ ์Šค์บ”์ด ํ•˜๋‚˜์”ฉ ๋ถ™๋Š”๋‹ค โ€” ์‹ค์ธก์€ ๋ถ„ ๋‹จ์œ„๋กœ ๋ฐ”๋€Œ์ง€ ์•Š์œผ๋ฏ€๋กœ\n * ์งง์€ TTL ๋กœ ์žฌ์‚ฌ์šฉํ•œ๋‹ค. ์บ์‹œ๋Š” ์ธ์Šคํ„ด์Šค๋ณ„์ด๊ณ , ๋งŒ๋ฃŒ ์ „์—๋Š” ๊ฐ™์€ ๊ฐ’์„ ์“ด๋‹ค(์˜ˆ์ธก ๊ฐ„ ์ผ๊ด€์„ฑ๋„ ์–ป๋Š”๋‹ค).\n */\n private static measuredCache = new Map<\n string,\n {\n at: number\n value: ReturnType<typeof buildMeasuredEstimator> | undefined\n /** ๊ฐ™์€ ํด๋“œ์—์„œ ๋‚˜์˜จ ์–‘ํ’ˆ๋ฅ  โ€” **์ €๋„์„ ๋‘ ๋ฒˆ ์ ‘์ง€ ์•Š๋Š”๋‹ค**(์†Œ์š”์™€ ์ˆ˜์œจ์€ ๊ฐ™์€ ์ฐฝ์˜ ๊ฐ™์€ ์‚ฌ์‹ค์ด๋‹ค). */\n yields?: ReturnType<typeof buildYieldEstimator>\n }\n >()\n private static readonly MEASURED_TTL_MS = 60_000\n /**\n * ์บ์‹œ ํ•ญ๋ชฉ ์ƒํ•œ โ€” **๋ผ์ดํ”„์‚ฌ์ดํด์ด ๋†“์นœ ๊ฒƒ๊นŒ์ง€ ๋ง‰๋Š” ๋‘ ๋ฒˆ์งธ ๋ฐฉ์–ด.**\n *\n * ์ง€์›€์€ `forgetInstance` ๊ฐ€ ํ•œ๋‹ค(๊ทธ๊ฒƒ์ด ์ฒซ ๋ฒˆ์งธ ๋ฐฉ์–ด์ด๊ณ  ์ •ํ™•ํ•œ ์ชฝ์ด๋‹ค). ๊ทธ๋Ÿฐ๋ฐ ํŠธ์œˆ์ด ์šฐ๋ฆฌ API ๋ฅผ\n * ์ง€๋‚˜์ง€ ์•Š๊ณ  ์‚ฌ๋ผ์ง€๋Š” ๊ธธ์ด ์žˆ๋‹ค: ๋„๋ฉ”์ธ(ํ…Œ๋„ŒํŠธ)์งธ๋กœ ์ง€์›Œ์ง€๊ฑฐ๋‚˜ DB ๋ฅผ ์ง์ ‘ ์†๋Œ€๋Š” ๊ฒฝ์šฐ๋‹ค. ๊ทธ๋•Œ\n * ๋‚จ์€ ํ•ญ๋ชฉ์„ ์ง€์šธ ์ฃผ์ธ์ด ์—†์œผ๋ฏ€๋กœ ์ƒํ•œ์ด ํ•„์š”ํ•˜๋‹ค.\n *\n * ๋„˜์น˜๋ฉด **๊ฐ€์žฅ ์˜ค๋ž˜ ์†๋Œ€์ง€ ์•Š์€ ๊ฒƒ**๋ถ€ํ„ฐ ๋ฒ„๋ฆฐ๋‹ค(Map ์˜ ์‚ฝ์ž… ์ˆœ์„œ๊ฐ€ ๊ณง ๊ทธ ์ˆœ์„œ๋‹ค โ€” ๊ฐ’์„ ์“ธ ๋•Œ๋งˆ๋‹ค\n * ๋‹ค์‹œ ๋„ฃ์œผ๋ฏ€๋กœ). ๋ฒ„๋ฆฌ๋Š” ๊ฒƒ์ด ์†ํ•ด๊ฐ€ ์•„๋‹Œ ์ด์œ : ์ด ๊ฐ’์€ ์บ์‹œ์ด๊ณ , ์—†์œผ๋ฉด ๋‹ค์‹œ ๊ณ„์‚ฐํ•œ๋‹ค.\n *\n * ์ˆ˜๋ฅผ ํฌ๊ฒŒ ์žก๋Š”๋‹ค โ€” ํŠธ์œˆ ๊ทœ๋ชจ๋Š” ๋Š˜ ํฌ๊ณ , ํ•ญ๋ชฉ ํ•˜๋‚˜๋Š” ์ž‘์—… ์ข…๋ฅ˜๋ณ„ ์†Œ์š” ๋ช‡ ์ค„์ด๋‹ค. ์ƒํ•œ์ด ์ž‘์œผ๋ฉด\n * ์ •์ƒ ๊ทœ๋ชจ์—์„œ ์„œ๋กœ ๋ฐ€์–ด๋‚ด๋ฉฐ ์บ์‹œ๊ฐ€ ๋ฌด์˜๋ฏธํ•ด์ง„๋‹ค(๊ทธ๊ฒŒ ๋” ๋‚˜์˜๋‹ค: ์กฐ์šฉํžˆ ๋А๋ ค์ง„๋‹ค).\n */\n private static readonly MEASURED_MAX = 5_000\n\n /** ์ด ํŠธ์œˆ์ด ์ด๋ ฅ์—์„œ ๋ฐฐ์šด ์–‘ํ’ˆ๋ฅ  โ€” ์†Œ์š”์™€ **๊ฐ™์€ ํด๋“œยท๊ฐ™์€ ์บ์‹œ**์—์„œ ์˜จ๋‹ค(์ €๋„์„ ๋‘ ๋ฒˆ ์ ‘์ง€ ์•Š๋Š”๋‹ค). */\n private static async measuredYield(domainId: string, instanceId: string) {\n await this.measuredEstimator(domainId, instanceId)\n return this.measuredCache.get(runtimeKey(domainId, instanceId))?.yields\n }\n\n private static async measuredEstimator(domainId: string, instanceId: string) {\n /* ํ‚ค๋Š” `runtimeKey` ํ•˜๋‚˜๋กœ โ€” ์†์œผ๋กœ ์กฐ๋ฆฝํ•˜๋ฉด ์ง€์šฐ๋Š” ์ชฝ๊ณผ ์–ด๊ธ‹๋‚˜ ๋ชป ์ง€์šฐ๋Š” ํ•ญ๋ชฉ์ด ์ƒ๊ธด๋‹ค. */\n const key = runtimeKey(domainId, instanceId)\n const hit = this.measuredCache.get(key)\n if (hit && Date.now() - hit.at < this.MEASURED_TTL_MS) return hit.value\n let value: ReturnType<typeof buildMeasuredEstimator> | undefined\n let yields: ReturnType<typeof buildYieldEstimator> | undefined\n try {\n /* ์ž‘์—… ์ข…๋ฅ˜๋ณ„ ์‹ค์ธก โ€” ์ฐฝ์€ ๋„‰๋„‰ํžˆ(ํ•˜๋ฃจ) ๋‘๊ณ  ํ‘œ๋ณธ์ด ๋ชจ์ž๋ž€ ์ข…๋ฅ˜๋Š” ์ถ”์ •๊ธฐ๊ฐ€ ์Šค์Šค๋กœ ๋บ€๋‹ค. */\n const kpi: any = await computeTwinKpi({ domainId, instanceId, windowMinutes: 24 * 60, groupBy: 'taskKind' })\n value = buildMeasuredEstimator(kpi?.groups?.items, {})\n /* ๊ฐ™์€ ๊ทธ๋ฃน์—์„œ ์–‘ํ’ˆ๋ฅ ๋„ ๋ฐฐ์šด๋‹ค โ€” ํ•œ ๋ฒˆ ์ ‘์€ ์ €๋„์„ ๋‘˜์ด ๋‚˜๋ˆ  ์“ด๋‹ค. */\n yields = buildYieldEstimator(kpi?.groups?.items, {})\n } catch (err) {\n twinWarn(`[twin-engine] \"${instanceId}\": measured duration lookup failed โ€” falling back to declared/default durations.`, (err as any)?.message)\n }\n /* ๋‹ค์‹œ ๋„ฃ์–ด **์ตœ๊ทผ ์“ด ๊ฒƒ**์œผ๋กœ ๋งŒ๋“ ๋‹ค โ€” ์‚ฝ์ž… ์ˆœ์„œ๊ฐ€ ๊ณง ๋ฒ„๋ฆด ์ˆœ์„œ์ด๋ฏ€๋กœ ์ด ํ•œ ์ค„์ด LRU ๋ฅผ ๋งŒ๋“ ๋‹ค. */\n this.measuredCache.delete(key)\n this.measuredCache.set(key, { at: Date.now(), value, yields })\n if (this.measuredCache.size > this.MEASURED_MAX) {\n const oldest = this.measuredCache.keys().next()\n if (!oldest.done) this.measuredCache.delete(oldest.value)\n }\n return value\n }\n\n /**\n * **์›๋ณธ์ด ์„ ์–ธํ•œ ์ž๊ทน์„ ์‹ฃ๋Š”๋‹ค** โ€” ์žฌ๊ธฐ๋™ํ•ด๋„ ์‚ด์•„ ์žˆ๊ฒŒ (2026-08-19).\n *\n * โ”€โ”€ ๋ฌด์—‡์ด ๋‚ฌ๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๋ฐ๋ชจ์˜ ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ์‹œ๋“œ ์ฝ”๋“œ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์—๋งŒ ์‹ค์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํŠธ์œˆ์„ ์žฌ๊ธฐ๋™ํ•˜๋ฉด ์ž๊ทน์ด ์‚ฌ๋ผ์ง€๊ณ  ๊ตฌ์กฐ๋งŒ\n * ์„œ ์žˆ๋Š” ํŠธ์œˆ์ด ๋‚จ์•˜๋‹ค(์ž‘์—… 0ยท์˜ค๋” 0) โ€” ใ€Œ์‚ด์•„ ์žˆ๋Š” ๋ฐ๋ชจใ€๊ฐ€ **์ฒซ ์žฌ๊ธฐ๋™๊นŒ์ง€๋งŒ** ์‚ด์•˜๋‹ค.\n *\n * ์ž๊ทน์˜ ์ง‘์€ **์›๋ณธ**์ด๋‹ค(`TwinReference.connectionConfig.scenario`, ADR-0029 ยท\n * `plans/simulator-as-source.md` ยง4): ๋ฌด์—‡์ด ๋“ค์–ด์˜ค๊ณ  ๋ฌด์Šจ ์ฃผ๋ฌธ์ด ๋‚˜๋Š”์ง€๋Š” ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ๊ฐ€ ์ •ํ•˜๋Š” ์‚ฌ์‹ค์ด๊ณ \n * ํŠธ์œˆ์€ ๋ฐ˜์˜ํ•œ๋‹ค. ํŠธ์œˆ์— ์ƒˆ ์ถ•์„ ๋งŒ๋“ค๋ฉด ADR-0029 ๊ฐ€ ๊ฑท์–ด๋‚ด์•ผ ํ•  ํ‘œ๋ฉด์ด ํ•˜๋‚˜ ๋Š˜์–ด๋‚œ๋‹ค.\n *\n * ํŒ์ •์€ ์ˆœ์ˆ˜ ํ•จ์ˆ˜๊ฐ€ ํ•œ๋‹ค(`planStimulus`) โ€” ๋ฏธ๋Ÿฌ์— ์‹ฃ์ง€ ์•Š๊ณ , ๊ฒ€์‚ฌ๋ฅผ ํ†ต๊ณผํ•˜์ง€ ๋ชปํ•œ ์„ ์–ธ์€ ํƒœ์šฐ์ง€ ์•Š๊ณ \n * (๊ทธ ์ด๋ ฅ์ด ์žˆ๋‹ค: ์ž˜๋ชป๋œ ์„ ์–ธ ํ•˜๋‚˜๊ฐ€ ๋‹ค์Œ ํ‹ฑ์—์„œ ์„œ๋ฒ„๋ฅผ ๋‚ด๋ ธ๋‹ค), ๋ชป ์‹ค์€ ์ด์œ ๋Š” **๋งํ•œ๋‹ค.**\n */\n private static async installStimulus(domainId: string, instanceId: string, inst: InstanceRuntime): Promise<void> {\n let config: any\n try {\n const ref = await getRepository(TwinReference).findOne({ where: { domain: { id: domainId }, source: instanceId } })\n config = ref?.connectionConfig\n } catch (err: any) {\n twinWarn(`[twin-engine] \"${instanceId}\": could not read the declared stimulus โ€” ${err?.message ?? err}`)\n return\n }\n const plan = planStimulus(config, { hasScenarioEngine: !!inst.runtime?.scenario, mode: inst.mode }, validateScenario as any)\n if (plan.action === 'skip') {\n /* ์„ ์–ธ์ด ์—†๋Š” ๊ฒƒ์€ ์ •์ƒ์ด๋ฏ€๋กœ ์กฐ์šฉํžˆ ์ง€๋‚œ๋‹ค. ๋‚˜๋จธ์ง€ ์…‹์€ **๋งํ•œ๋‹ค** โ€” ์„ ์–ธํ–ˆ๋Š”๋ฐ ์•ˆ ์‹ค๋ฆฐ ์ƒํƒœ๋‹ค. */\n if (plan.reason !== 'none') {\n twinWarn(\n `[twin-engine] \"${instanceId}\": a stimulus is declared on its source but was not loaded (${plan.reason}${plan.detail ? `: ${plan.detail}` : ''}).` +\n (plan.reason === 'observed' ? ' This twin runs on observation โ€” we do not manufacture arrivals for it.' : '')\n )\n }\n return\n }\n try {\n /* ์ž๊ทน์„ ์‹ฃ๊ณ  ์‹œ์ž‘ํ•˜๋Š” ๋ฐ ๋“  ์‹œ๊ฐ„ โ€” ์‹ค์ธก์—์„œ ํฐ ํŠธ์œˆ์€ ์ด ๊ตฌ๊ฐ„์ด 29~72์ดˆ์˜€๋‹ค. */\n const tStim = performance.now()\n inst.runtime!.scenario.load(plan.scenario)\n inst.runtime!.scenario.start()\n const stimMs = performance.now() - tStim\n recordPhase(inst.load ?? (inst.load = newLoadMeter()), 'stimulus', stimMs)\n const kinds = (plan.scenario.generators ?? []).map((g: any) => g?.kind).filter(Boolean)\n twinLog(\n `[twin-engine] \"${instanceId}\": stimulus from its source started in ${Math.round(stimMs)}ms โ€” ${kinds.length ? kinds.join(', ') : 'no generators'}.`\n )\n } catch (err: any) {\n twinWarn(`[twin-engine] \"${instanceId}\": the declared stimulus was rejected at load โ€” ${err?.message ?? err}`)\n }\n }\n\n /**\n * ์ž๊ทน์„ **์›๋ณธ์— ์„ ์–ธํ•œ๋‹ค** โ€” ํ”„๋กœ๋น„์ €๋‹ยท๋ฐ๋ชจ ์‹œ๋“œ๊ฐ€ ๋ถ€๋ฅด๋Š” ๋ฌธ.\n *\n * ํŠธ์œˆ์ด ์•„๋‹ˆ๋ผ ์›๋ณธ์— ์ ๋Š” ์ด์œ ๋Š” ์œ„์™€ ๊ฐ™๋‹ค(ADR-0029). ์›๋ณธ ํ–‰์ด ์—†์œผ๋ฉด ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค โ€” ์–ด๋–ค ์›๋ณธ์—์„œ\n * ์˜จ ํŠธ์œˆ์ธ์ง€ ๋ชจ๋ฅด๋Š” ์ฑ„ ์ž๊ทน์„ ์ง€์–ด ๋ถ™์ด๋ฉด, ๊ทธ ์ž๊ทน์ด ์–ด๋””์„œ ์™”๋Š”์ง€ ์•„๋ฌด๋„ ๋˜์งš์„ ์ˆ˜ ์—†๋‹ค.\n */\n static async declareStimulus(domainId: string, instanceId: string, scenario: any): Promise<boolean> {\n const repo = getRepository(TwinReference)\n const ref = await repo.findOne({ where: { domain: { id: domainId }, source: instanceId } })\n if (!ref) {\n twinWarn(`[twin-engine] \"${instanceId}\": no source reference โ€” a stimulus has nowhere to be declared.`)\n return false\n }\n ref.connectionConfig = withStimulus(ref.connectionConfig, scenario)\n await repo.save(ref)\n return true\n }\n\n /**\n * ์ด ํŠธ์œˆ์ด **์ด๋ ฅ์—์„œ ์‹œ๊ฐ„์„ ๋ฐฐ์šด ์ž‘์—… ์ข…๋ฅ˜๋“ค** โ€” ์žฌ๊ธฐ๋™์—๋„ ๋‚จ๋Š” ๊ทผ๊ฑฐ.\n *\n * โ”€โ”€ ์™œ ํ•„์š”ํ•œ๊ฐ€ (2026-08-18 ์‹ค์ธก) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ปค๋„์˜ ์ž๊ธฐ๋ณด๊ณ (`specCoverage()`)๋Š” **์ž‘์—…์ด ์ƒˆ๋กœ ์ƒ๊ธธ ๋•Œ** ์ฑ„์›Œ์ง„๋‹ค. ๊ทธ๋ž˜์„œ ์žฌ๊ธฐ๋™ ์งํ›„์—๋Š” ์ด๋ ฅ์ด\n * ํ’๋ถ€ํ•œ ํŠธ์œˆ์—์„œ๋„ ๋ชฉ๋ก์ด ๋น„๊ณ , ใ€Œ์ด ํŠธ์œˆ์ด ๋ฌด์Šจ ๊ณต์ •์„ ๋Œ๋ฆฌ๋‚˜ใ€ ํ™”๋ฉด์ด ๋นˆ์นธ์ด ๋œ๋‹ค โ€” ๊ฐ’์„ ์ฑ„์šธ ๊ณณ์„\n * ๋ณด์—ฌ์•ผ ํ•˜๋Š” ํ™”๋ฉด์ด ์ •์ž‘ ๊ทธ๋•Œ ์•„๋ฌด ๋ง๋„ ๋ชป ํ•œ๋‹ค.\n *\n * ๊ทธ ๋นˆ์นธ์„ ์ด๋ ฅ๋กœ ๋ฉ”์šด๋‹ค: ์ €๋„์—์„œ ๋ฐฐ์šด ์ข…๋ฅ˜๋Š” **์ถ”์ •๊ธฐ๊ฐ€ ์ด๋ฏธ ๋‹ตํ•  ์ˆ˜ ์žˆ๋Š” ์ข…๋ฅ˜**์ด๋ฏ€๋กœ, ์ง€์–ด๋‚ด๋Š”\n * ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์žˆ๋Š” ์‚ฌ์‹ค์„ ๊บผ๋‚ด๋Š” ๊ฒƒ์ด๋‹ค. ๊ฐ™์€ ์บ์‹œ(60์ดˆ)๋ฅผ ์“ฐ๋ฏ€๋กœ ์กฐํšŒ๋งˆ๋‹ค ์ €๋„์„ ๋‹ค์‹œ ์ ‘์ง€ ์•Š๋Š”๋‹ค.\n */\n static async measuredOperationKinds(domainId: string, instanceId: string): Promise<string[]> {\n const measured = await this.measuredEstimator(domainId, instanceId)\n return Object.keys((measured as any)?.learned ?? {})\n }\n\n /**\n * ์ง€๊ธˆ ์ด ํŠธ์œˆ์ด ์–ด๋–ค ๋ชจ๋ธ๋กœ ๊ตด๋Ÿฌ๊ฐ€๋Š”๊ฐ€ โ€” ์˜ˆ์ธก ์ถœ๋ ฅ ๋ณด์ •์ด **์ž๊ธฐ๊ฐ€ ๋ฐฐ์šด ๋ชจ๋ธ**์—๋งŒ ์ ์šฉ๋˜๋„๋ก\n * ๋น„๊ตํ•˜๋Š” ์ง€๋ฌธ. ์žฌ๋ฃŒ๋Š” ํ˜ธ์ŠคํŠธ๊ฐ€ ์•„๋Š” ๊ฒƒ(์‹ค์ธกยท์†๋„ยท์„ ์–ธ ๋ช…์„ธ)์ด๋ผ ์ปค๋„ ๋ฐœํ–‰ ์ƒํƒœ์™€ ๋ฌด๊ด€ํ•˜๋‹ค.\n * ์‹คํŒจํ•˜๋ฉด undefined โ€” ๊ทธ๋•Œ๋Š” ๋น„๊ต๋ฅผ ํ•˜์ง€ ์•Š๋Š”๋‹ค(๋ชจ๋ฅด๋Š” ๊ฒƒ์„ ๊ทผ๊ฑฐ๋กœ ๋ณด์ •์„ ๋Š์ง€ ์•Š๋Š”๋‹ค).\n */\n static async modelBasis(domainId: string, instanceId: string): Promise<ModelBasis | undefined> {\n try {\n const reg = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n const model: any = reg?.model\n const measured = await this.measuredEstimator(domainId, instanceId)\n const travel = buildTravelEstimator({ layout: model?.layout, equipment: model?.equipment, unit: model?.unit })\n return { measured: measured?.learned, speeds: travel.speedsByKind, declared: model?.operations }\n } catch {\n return undefined\n }\n }\n\n /**\n * **์ด ํŠธ์œˆ์ด ํ•˜๋ฃจ ๋ช‡ ๋Œ€๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ๋Š”๊ฐ€** โ€” ์‹คํ–‰ํ•ด ๋ณด์ง€ ์•Š๊ณ  ๋‹ตํ•œ๋‹ค.\n *\n * ๊ณ„์‚ฐ์€ ์ปค๋„์ด ์ž๊ธฐ ์ƒํƒœ์—์„œ ํ•œ๋‹ค(`kernel.capacity`). ์—ฌ๊ธฐ์„œ ํ•˜๋Š” ์ผ์€ **๊ธฐ์ค€ ์ฃผ๋ฅผ ์ •ํ•ด ์ฃผ๋Š”\n * ๊ฒƒ**๋ฟ์ด๋‹ค: ๊ณตํœด์ผ์ด ์—†๋Š” ํ‰์ƒ์ฃผ์—ฌ์•ผ ํ•œ๋‹ค โ€” ๊ณตํœด์ผ์€ ์—ฐ๊ฐ„ ๊ฐ€์šฉ๋Ÿ‰์„ ๋”ฐ๋กœ ๊นŽ์ง€, ์ด ๊ณต์žฅ์˜ ํ‰์ƒ์‹œ\n * ์ƒํ•œ์„ ์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ปค๋„์ด ์ž„์˜๋กœ ๊ณ ๋ฅด๊ฒŒ ๋‘๋ฉด ๊ทธ ์ฃผ์— ๊ณตํœด์ผ์ด ๋ผ์—ˆ์„ ๋•Œ ์ƒํ•œ์ด ์กฐ์šฉํžˆ ๋‚ฎ์•„์ง„๋‹ค.\n *\n * ํŠธ์œˆ์ด ๊ธฐ๋™ ์ค‘์ด ์•„๋‹ˆ๋ฉด `undefined` ๋‹ค โ€” 0 ์ด ์•„๋‹ˆ๋‹ค. ๊ธฐ๋™ํ•˜์ง€ ์•Š์€ ํŠธ์œˆ์˜ ์ƒํ•œ์„ 0 ์ด๋ผ๊ณ  ๋‹ตํ•˜๋ฉด ํ™”๋ฉด์€\n * \"์ด ๊ณต์žฅ์€ ์•„๋ฌด๊ฒƒ๋„ ๋ชป ๋งŒ๋“ ๋‹ค\" ๊ณ  ๋งํ•œ๋‹ค.\n */\n static async capacity(\n domainId: string,\n target: { instanceId?: string; spaceId?: string },\n unitsPerDay: number,\n sampleWeekStartMs: number\n ): Promise<{ instanceId: string; kind?: string; analysis?: any; reason?: 'not-running' | 'no-operations' }[]> {\n /* ๋Œ€์ƒ์€ **๋“ฑ๋ก๋ถ€**๊ฐ€ ์ •ํ•œ๋‹ค โ€” ๊ธฐ๋™ ์ค‘์ธ ๋Ÿฐํƒ€์ž„๋งŒ ํ›‘์œผ๋ฉด \"์•ˆ ๋–  ์žˆ์–ด์„œ ์•ˆ ๋ณด์ด๋Š” ๊ฒƒ\" ๊ณผ \"์—†๋Š” ๊ฒƒ\" ์ด\n ๊ตฌ๋ณ„๋˜์ง€ ์•Š๋Š”๋‹ค. ํ™”๋ฉด์€ ๊ทธ ๋‘˜์„ ๋‹ค๋ฅด๊ฒŒ ๋งํ•ด์•ผ ํ•œ๋‹ค. */\n const where: any = { domain: { id: domainId } }\n if (target.instanceId) where.instanceId = target.instanceId\n else where.spaceId = target.spaceId\n const registered = await getRepository(TwinInstance).find({ where })\n\n return registered.map(reg => {\n const rt = this.instances[runtimeKey(domainId, reg.instanceId)]\n const kernel: any = rt?.kernel // ํ‚ค์— ๋„๋ฉ”์ธ์ด ์žˆ์œผ๋ฏ€๋กœ ๋‚จ์˜ ๋Ÿฐํƒ€์ž„์„ ์ง‘์„ ์ˆ˜ ์—†๋‹ค\n if (typeof kernel?.capacity !== 'function') return { instanceId: reg.instanceId, kind: reg.kind, reason: 'not-running' as const }\n\n const analysis = kernel.capacity({ unitsPerDay, sampleWeekStartMs })\n /* ๊ณต์ •์„ ์„ ์–ธํ•˜์ง€ ์•Š์€ ํŠธ์œˆ(๋Œ€๊ฐœ YMSยทWMS)์€ **ํŒ์ • ๋Œ€์ƒ์ด ์•„๋‹ˆ๋‹ค.** 0 ์œผ๋กœ ์ฑ„์›Œ ๋„ฃ์œผ๋ฉด\n \"์•ผ๋“œ๊ฐ€ ๋ณ‘๋ชฉ\" ์ด๋ผ๋Š” ์—†๋Š” ์‚ฌ์‹ค์ด ์ƒ๊ธด๋‹ค โ€” ์žด ๊ฒƒ์ด ์—†๋‹ค๊ณ  ๋งํ•œ๋‹ค. */\n if (!analysis?.operations?.length) return { instanceId: reg.instanceId, kind: reg.kind, reason: 'no-operations' as const }\n return { instanceId: reg.instanceId, kind: reg.kind, analysis }\n })\n }\n\n /**\n * **์ƒ์‚ฐ ๋Šฅ๋ ฅ ๋ณด๊ณ ์„œ** โ€” ISA-95 Part 4 `OperationsCapability`. ๊ตฌ๊ฐ„์˜ ์–‘์„ ์ข…๋ฅ˜๋กœ ๊ตฌ๋ถ„ํ•œ๋‹ค\n * (์•ฝ์ •ยท๊ฐ€์šฉยท๋‹ฌ์„ฑ๋ถˆ๊ฐ€). ์šฉ๋Ÿ‰(`capacity`)์€ ๋น„์œจ์„ ๋‚ด๊ณ  ์ด๊ฒƒ์€ **๊ตฌ๊ฐ„์˜ ์–‘**์„ ๋‚ธ๋‹ค.\n *\n * ๋Œ€์ƒ ์„ ์ •ยท๊ฑฐ์ ˆ ์‚ฌ์œ ๋Š” `capacity` ์™€ **๊ฐ™์€ ๊ทœ์œจ**์ด๋‹ค: ๋“ฑ๋ก๋ถ€๊ฐ€ ๋Œ€์ƒ์„ ์ •ํ•˜๊ณ (์•ˆ ๊ธฐ๋™ ์ค‘์ธ ๊ฒƒ๊ณผ\n * ์—†๋Š” ๊ฒƒ์„ ๊ตฌ๋ณ„ํ•œ๋‹ค), ๊ณต์ •์„ ์„ ์–ธํ•˜์ง€ ์•Š์€ ํŠธ์œˆ์€ ํŒ์ • ๋Œ€์ƒ์ด ์•„๋‹ˆ๋ผ๊ณ  ๋งํ•œ๋‹ค(0 ์œผ๋กœ ์ฑ„์šฐ๋ฉด\n * \"์•ผ๋“œ๊ฐ€ ๋ณ‘๋ชฉ\" ์ด๋ผ๋Š” ์—†๋Š” ์‚ฌ์‹ค์ด ์ƒ๊ธด๋‹ค).\n */\n static async operationsCapability(\n domainId: string,\n target: { instanceId?: string; spaceId?: string },\n unitsPerDay: number,\n sampleWeekStartMs: number,\n window: { fromTime: string; toTime: string }\n ): Promise<{ instanceId: string; kind?: string; report?: any; reason?: 'not-running' | 'no-operations' }[]> {\n const where: any = { domain: { id: domainId } }\n if (target.instanceId) where.instanceId = target.instanceId\n else where.spaceId = target.spaceId\n const registered = await getRepository(TwinInstance).find({ where })\n\n return registered.map(reg => {\n const rt = this.instances[runtimeKey(domainId, reg.instanceId)]\n const kernel: any = rt?.kernel\n if (typeof kernel?.operationsCapability !== 'function') {\n return { instanceId: reg.instanceId, kind: reg.kind, reason: 'not-running' as const }\n }\n const report = kernel.operationsCapability({ unitsPerDay, sampleWeekStartMs, window })\n if (!report?.perOperation?.length) return { instanceId: reg.instanceId, kind: reg.kind, reason: 'no-operations' as const }\n return { instanceId: reg.instanceId, kind: reg.kind, report }\n })\n }\n\n /**\n * ๋ฏธ๋Ÿฌ ๊ธฐ๋™์˜ ์—ฐ์†์„ฑ ์”จ์•— โ€” ์ด์–ด๋ฐ›์€ ๊ฒƒ์€ **๋งํ•œ๋‹ค**(์กฐ์šฉํžˆ ์ž‡์ง€ ์•Š๋Š”๋‹ค).\n *\n * ์ปค๋„์ด ๊ทธ ๋ฌธ์„ ์—ด์–ด ๋‘์ง€ ์•Š์•˜์œผ๋ฉด ๊ทธ ์‚ฌ์‹ค๋„ ๋งํ•œ๋‹ค: ๊ทธ ํŠธ์œˆ์€ ์žฌ๊ธฐ๋™๋งˆ๋‹ค ์—ด๋ฆฐ ๊ตฌ๊ฐ„์„ ์žƒ๋Š”๋‹ค.\n */\n private static seedLiveContinuity(domainId: string, id: string, kernel: any): void {\n const cached = this.recovered[runtimeKey(domainId, id)]?.state\n if (!cached) return\n const plan = planLiveContinuity(cached)\n if (!plan.ackedCount && !plan.attentionSinceCount && !plan.energy) return\n if (typeof kernel.hydrateContinuity !== 'function') {\n twinWarn(\n `[twin-engine] kernel for \"${id}\" cannot carry continuity (no hydrateContinuity) โ€” the open demand window, ` +\n 'its peak and the attention start times are lost on every restart.'\n )\n return\n }\n try {\n kernel.hydrateContinuity(plan.seed)\n } catch (err: any) {\n /* ์ด์–ด๋ฐ›๊ธฐ๊ฐ€ ์‹คํŒจํ•ด๋„ ๋ฏธ๋Ÿฌ๋Š” ๋Œ์•„์•ผ ํ•œ๋‹ค โ€” ๋‹ค๋งŒ ๋ฌด์—‡์„ ์žƒ์—ˆ๋Š”์ง€ ๋งํ•œ๋‹ค. */\n twinWarn(`[twin-engine] continuity seed failed for \"${id}\" โ€” starting without it: ${err?.message ?? err}`)\n return\n }\n const carried = [\n ...(plan.energy ? ['energy accumulation (open window, totalizer baselines, peak)'] : []),\n ...(plan.ackedCount ? [`${plan.ackedCount} acknowledged attention(s)`] : []),\n ...(plan.attentionSinceCount ? [`${plan.attentionSinceCount} attention start time(s)`] : [])\n ].join(', ')\n twinLog(`[twin-engine] mirror \"${id}\" carried over ${carried} โ€” observation axes come from the source.`)\n }\n\n static start(id: string, domainId: string, kind: string, model: TwinModelDef, restartPolicy?: RestartPolicy, purpose?: string, resumeFrom?: number): InstanceRuntime {\n const key = runtimeKey(domainId, id)\n if (this.instances[key]) return this.instances[key]\n\n const Kernel = kernelFor(kind)\n const kernel: TwinKernel = new Kernel(domainId, undefined, this.productionSpecOf(model))\n kernel.loadTwinModel(model) // ๊ตฌ์กฐ๋งŒ. ์ƒํƒœ๋Š” ์•„๋ž˜ ์›œ์Šคํƒ€ํŠธ๊ฐ€ ์ฃผ์ž…ํ•œ๋‹ค.\n this.applyOperations(kernel, model, id) // ์‹œ๊ฐ„ยท์ˆ˜์œจ ๋ช…์„ธ(์žˆ์œผ๋ฉด) โ€” ์—†์œผ๋ฉด ์ปค๋„ ๊ธฐ๋ณธ๊ฐ’\n /* ์ถ”์ •๊ธฐ๋Š” DB ์กฐํšŒ๋ฅผ ํฌํ•จํ•ด ๋น„๋™๊ธฐ โ€” ๊ธฐ๋™์„ ๋ง‰์ง€ ์•Š๊ณ  ๋ถ™๋Š”๋‹ค(๋ถ™๊ธฐ ์ „ ์ž‘์—…์€ ๋ช…์„ธยท์ƒ์ˆ˜๋กœ ์‚ฐ์ถœ). */\n this.installEstimators(kernel, domainId, id, model).catch(err => twinWarn('[twin-engine] estimator install failed', err?.message))\n /*\n * **์›œ์Šคํƒ€ํŠธ์— ๋“  ์‹œ๊ฐ„์„ ๊ฐ’์œผ๋กœ ๋‚จ๊ธด๋‹ค** (2026-08-22). ์‹ค์ธก์œผ๋กœ ๋ถ€ํŒ…์ด 620~717์ดˆ์˜€๊ณ  ํŠธ์œˆ ํ•˜๋‚˜์—\n * 15~93์ดˆ์˜€๋Š”๋ฐ, ์–ด๋А ์ž‘์—…์ด ๊ทธ ์‹œ๊ฐ„์„ ์“ฐ๋Š”์ง€ ๋‹ตํ•  ๊ณ„๊ธฐ๊ฐ€ ์—†์—ˆ๋‹ค. ๋กœ๊ทธ์—๋„ ๋ฐ€๋ฆฌ์ดˆ๊นŒ์ง€ ์ ์–ด\n * ๋ถ€ํŒ… ๋กœ๊ทธ๋งŒ์œผ๋กœ ๊ตฌ๊ฐ„์„ ์ฝ์„ ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.\n */\n const tWarm = performance.now()\n this.warmStart(domainId, id, kernel, purpose)\n const warmMs = performance.now() - tWarm\n if (warmMs >= 1000) twinLog(`[twin-engine] \"${id}\": warm start took ${Math.round(warmMs)}ms.`)\n /*\n * **๋ฒˆํ˜ธ๋ฅผ ์ด์–ด ์„ผ๋‹ค** โ€” ์ €๋„์— ์ด๋ฏธ ์žˆ๋Š” ๋ฒˆํ˜ธ์™€ ๊ฒน์น˜์ง€ ์•Š๊ฒŒ.\n *\n * ์ €๋„์ด ๋น„์–ด ์žˆ์œผ๋ฉด(0) ์•„๋ฌด ์ผ๋„ ์•ˆ ํ•œ๋‹ค. ๋น„์–ด ์žˆ์ง€ ์•Š์€๋ฐ 0๋ถ€ํ„ฐ ๋‹ค์‹œ ์„ธ๋ฉด ๊ฐ™์€ ํŠธ์œˆ์— ๊ฐ™์€\n * ๋ฆฌ๋น„์ „์ด ๋‘˜ ์ƒ๊ธฐ๊ณ , ์žฌ์ƒ ์ˆœ์„œ๊ฐ€ ๋’ค์„ž์ด๋ฉฐ, ์‹œ๊ฐ„์—ฌํ–‰์ด ์—‰๋šฑํ•œ ์‹œ์ ์„ ๋‹ตํ•œ๋‹ค โ€” ์˜ค๋ฅ˜๋Š” ์•ˆ ๋‚œ๋‹ค.\n */\n if (resumeFrom && typeof (kernel as any).resumeRevision === 'function') (kernel as any).resumeRevision(resumeFrom)\n /*\n * โ”€โ”€ ์ด ํŠธ์œˆ์˜ ์‹œ๊ณ„๋ฅผ **์ง€๊ธˆ**์— ๋งž์ถ˜๋‹ค (2026-08-15) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ปค๋„์˜ ๊ธฐ๋ณธ ๊ธฐ์ค€์ ์€ ์ƒ์ˆ˜(2026-01-01)๋‹ค. ๊ทธ๋Œ€๋กœ ๋‘๋ฉด ์‹œ๋ฎฌ ํŠธ์œˆ์˜ ์ €๋„ ์‹œ๊ฐ์ด **์žฌ๊ธฐ๋™๋งˆ๋‹ค\n * ๋˜๊ฐ๊ฒจ** ๋ฉฐ์น  ์น˜ ์‚ฌ๊ฑด์ด ์ „๋ถ€ ๊ฐ™์€ ๋ถ„์— ๋ชฐ๋ฆฐ๋‹ค โ€” ใ€Œ์–ธ์ œ ์žˆ์—ˆ๋˜ ์ผ์ธ๊ฐ€ใ€๋ฅผ ๋˜์งš์„ ์ˆ˜ ์—†๊ณ ,\n * ์‹ค ์‹œ๊ฐ์œผ๋กœ ์ฐฝ์„ ์ž๋ฅด๋Š” ์„ฑ๊ณผยท์ด๋ ฅ ์งˆ์˜์—๋Š” ๊ทธ ํŠธ์œˆ์ด ์•„์˜ˆ ๋ณด์ด์ง€ ์•Š๋Š”๋‹ค.\n *\n * ์žฌ๊ธฐ๋™ํ•˜๋ฉด ๊ทธ๋งŒํผ ์‹œ๊ณ„๊ฐ€ ์•ž์œผ๋กœ ๋›ฐ๋Š”๋ฐ, ๊ทธ๊ฒƒ์ด ์‚ฌ์‹ค์ด๋‹ค: ๊ทธ ์‚ฌ์ด ์ด ํŠธ์œˆ์€ ๋Œ์ง€ ์•Š์•˜๊ณ \n * ์ €๋„์˜ ๋นˆ ๊ตฌ๊ฐ„์ด ๊ทธ ์‚ฌ์‹ค์„ ๋งํ•œ๋‹ค.\n */\n kernel.setClockOrigin?.(Date.now())\n const runtime: TwinRuntimeType = new TwinRuntime(kernel)\n\n /* subscribe ๋Š” RuntimeSubscription({ unsubscribe() }) ๋ฐ˜ํ™˜ โ†’ () => void ๋กœ ๊ฐ์Œˆ. */\n /*\n * **๋ชจ๋“œ๋ฅผ ์ ์–ด ๋‘”๋‹ค** (2026-08-18 ์‹ค์ธก์œผ๋กœ ๊ณ ์นจ).\n *\n * ์‹œ๋ฎฌ ๊ฒฝ๋กœ๋Š” `mode` ๋ฅผ ๋น„์›Œ ๋‘์—ˆ๊ณ (ใ€Œ๋ฏธ์ง€์ •=simใ€์ด๋ผ๋Š” ๊ทœ์•ฝ์— ๊ธฐ๋Œ€), ๋ผ์ด๋ธŒ๋งŒ ์ ์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ\n * `modeOf()` ๊ฐ€ **๋„๋Š” ์‹œ๋ฎฌ๋ ˆ์ด์…˜์— undefined** ๋ฅผ ๋‹ตํ–ˆ๊ณ , ์„ ์–ธยท์ฒ ํšŒ์˜ ๋‹ต์ด ใ€Œ์ €์žฅํ–ˆ๋‹คใ€๋กœ ๋‚˜๊ฐ”๋‹ค โ€”\n * ์‹ค์ œ๋กœ๋Š” ๋„๋Š” ์ปค๋„์ด ์˜› ์ˆ˜๋ฅผ ๊ทธ๋Œ€๋กœ ์“ฐ๊ณ  ์žฌ๊ธฐ๋™ ๋•Œ ๋ฐ›๋Š”๋ฐ, ๊ทธ ์‚ฌ์‹ค์ด ๋‹ต์—์„œ ์‚ฌ๋ผ์ง„ ๊ฒƒ์ด๋‹ค.\n * ๊ทœ์•ฝ์— ๊ธฐ๋Œ€๋Š” ๋Œ€์‹  ์‚ฌ์‹ค์„ ์ ๋Š”๋‹ค: ใ€Œ๋Œ๊ณ  ์žˆ๋‚˜ใ€๋ฅผ ๋ฌป๋Š” ์ชฝ์ด ๊ทธ ๋‹ต์„ ๋ฐ›์•„์•ผ ํ•œ๋‹ค.\n */\n const inst: InstanceRuntime = {\n id,\n domainId,\n mode: 'sim',\n runtime,\n kernel,\n /* ์ •์ฑ…์€ ๋ถ€๋ฅด๋Š” ์ชฝ์ด ์„ ์–ธํ•œ๋‹ค โ€” ์—ฌ๊ธฐ์„œ ๊ณ ๋ฅด๋ฉด ๊ฐ™์€ ํŠธ์œˆ์ด ๋ถ€๋ฅด๋Š” ์ž๋ฆฌ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ์žฌ๊ธฐ๋™ํ•œ๋‹ค. */\n restartPolicy: readRestartPolicy(restartPolicy, `start(\"${id}\")`),\n spaceId: (model as any)?.spaceId,\n /*\n * **์‹œ๋ฎฌ๋„ ๊ณ„๊ธฐ๋ฅผ ๋“ ๋‹ค** (2026-08-20).\n *\n * ์˜ˆ์ „์—๋Š” `startLive` ์—์„œ๋งŒ ๋งŒ๋“ค์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋„๋Š” ํŠธ์œˆ 22๊ฐœ๊ฐ€ ์‹œ๋ฎฌ์ธ ์„œ๋ฒ„์—์„œ ใ€Œ์ดˆ๋‹น ๋ช‡ ํ–‰์„\n * ์“ฐ๋‚˜ใ€ยทใ€Œ๋ฐ€๋ฆฐ ๊ฒŒ ์žˆ๋‚˜ใ€๋ฅผ ๋ฌผ์„ ์ž๋ฆฌ๊ฐ€ **์•„์˜ˆ ์—†์—ˆ๋‹ค** โ€” ์ €๋„ ์“ฐ๊ธฐ๋ฅผ ๋ฐฐ์น˜๋กœ ๊ณ ์นœ ๋’ค์—๋„ ๊ทธ ํšจ๊ณผ์™€\n * ํšŒ๊ท€๋ฅผ ์ˆซ์ž๋กœ ๋ณผ ์ˆ˜ ์—†๋‹ค. ์„ธ์ง€ ์•Š๋Š” ๊ฐœ์„ ์€ ๋‹ค์Œ ์‚ฌ๋žŒ์ด ๋˜๋Œ๋ ค๋„ ์•„๋ฌด๋„ ๋ชจ๋ฅธ๋‹ค.\n *\n * ์œ ์ž…(`ingested`)์€ ์‹œ๋ฎฌ์— ๋œป์ด ์—†๋‹ค(์›๋ณธ์—์„œ ๋ฐ›๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ž๊ธฐ๊ฐ€ ๋‚ธ๋‹ค) โ€” ๊ทธ ์นธ์€ 0 ์œผ๋กœ\n * ๋‚จ๊ณ , ๊ทธ๊ฒƒ์ด ์‚ฌ์‹ค์ด๋‹ค(ใ€Œ๋ฐ›์€ ๊ฒƒ์ด ์—†๋‹คใ€).\n */\n metrics: this.newMetrics(),\n unsub: () => {}\n }\n this.instances[key] = inst\n /* ๋‹ค์‹œ ์„ธ์› ์œผ๋ฏ€๋กœ ์ง€๋‚œ ์ •์ง€ ์ด์œ ๋Š” ์‚ฌ์‹ค์ด ์•„๋‹ˆ๋‹ค โ€” ๋‚จ๊ฒจ ๋‘๋ฉด ๋„๋Š” ํŠธ์œˆ์ด ใ€Œ๊ตถ๊ฒจ์„œ ๋ฉˆ์ท„๋‹คใ€๊ณ  ๋งํ•œ๋‹ค. */\n this.stopNotes.delete(key)\n delete this.recovered[key] // ์›œ์Šคํƒ€ํŠธ๋กœ ์ปค๋„์— ์˜ฎ๊ฒจ ์‹ฌ์—ˆ๋‹ค โ€” ์ด์ œ ๋ผ์ด๋ธŒ๊ฐ€ ์ง„์‹ค์ด๋‹ค.\n /* ์›๋ณธ์ด ์„ ์–ธํ•œ ์ž๊ทน โ€” ๊ธฐ๋™์„ ๋ง‰์ง€ ์•Š๋Š”๋‹ค(์ถ”์ •๊ธฐ์™€ ๊ฐ™์€ ๊ทœ์œจ). ๋ชป ์‹ค์—ˆ์œผ๋ฉด ๊ทธ ์‚ฌ์‹ค์„ ๋งํ•œ๋‹ค. */\n this.installStimulus(domainId, id, inst).catch(err => twinWarn(`[twin-engine] \"${id}\": stimulus install failed โ€” ${err?.message ?? err}`))\n\n /* ๋ผ์ด๋ธŒ ๋ฐ”์ธ๋”ฉ(P3): data ์ฑ„๋„ ํ•„ํ„ฐ๊ฐ€ subdomain ์„ ๋ณด๋ฏ€๋กœ Domain ๊ฐ์ฒด๋ฅผ 1ํšŒ ํ•ด์„ํ•ด ๋‘”๋‹ค. */\n getRepository(Domain).findOne({ where: { id: domainId } }).then(d => (inst.domain = d)).catch(() => {})\n\n /* State ์ฑ„๋„: runtime.subscribe(snapshotโ†’deltaโ†’clock) โ†’ pubsub ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…(๊ตฌ๋… ๋ฆฌ์กธ๋ฒ„๊ฐ€ instanceId ํ•„ํ„ฐ). */\n const sub = runtime.subscribe((msg: SubscriptionMessage) => {\n this.publishGuarded(\n 'twin-state',\n { twinState: { instanceId: id, kind: msg.kind, revision: (msg as any).revision, payload: msg } },\n `twin-state:${id}`\n )\n /* ์˜์† + ๋ผ์ด๋ธŒ ๋ฐ”์ธ๋”ฉ ๋ธŒ๋ฆฌ์ง€: delta ๋ฅผ ์ €๋„ ๋ฒ„ํผ์— ๋‹ด๊ณ  + ์—”ํ‹ฐํ‹ฐ๋ณ„ data(tag:) publish โ†’ ๋ณด๋“œ ์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ. */\n if (msg.kind === 'delta') {\n /*\n * โ”€โ”€ ์“ฐ๊ธฐ๋„ **๋ชจ์•„์„œ** ํ•œ ๋ฒˆ (2026-08-20 ์‹ค์ธก์œผ๋กœ ์žก์Œ) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n *\n * ์—ฌ๊ธฐ์„œ ๋ธํƒ€๋งˆ๋‹ค `persist()` ๋ฅผ ๋ถˆ๋ €๋‹ค โ€” ํ–‰ ํ•˜๋‚˜๋‹น `save()` ํ•˜๋‚˜, ๊ทธ๋ฆฌ๊ณ  ๊ทธ ์•ˆ์—์„œ\n * `structureRevOf` ๋ฅผ await(๊ตฌ์กฐ ํ–‰์ด ์—†๋Š” ํŠธ์œˆ์€ ์บ์‹œ ๋ฏธ์Šค๊ฐ€ ๊ธฐ์–ต๋˜์ง€ ์•Š์•„ **๋ธํƒ€๋งˆ๋‹ค\n * SELECT** ์˜€๋‹ค). ๋ฐ๋ชจ ์ž๊ทน์„ ์ผ  ํŠธ์œˆ 23๊ฐœ์—์„œ ๊ทธ ๊ฒฐ๊ณผ๊ฐ€ ์ด๋žฌ๋‹ค: ํ”„๋กœ์„ธ์Šค CPU 81~112%,\n * ์•„๋ฌด ์ผ๋„ ํ•˜์ง€ ์•Š๋Š” ์งˆ์˜๊ฐ€ 8~14์ดˆ. ํ”„๋กœํŒŒ์ผ์€ `JSON.parse`ยท๋Œ€ํ˜• GCยท์Šค๋ ˆ๋“œํ’€์„ ๊ฐ€๋ฆฌํ‚ค๊ณ \n * ๊ณ„๊ธฐ๋Š” ํ‹ฑ์˜ ๋ชซ์ด 16% ๋ผ๊ณ  ๋งํ–ˆ๋‹ค โ€” **ํ‹ฑ์ด ์•„๋‹ˆ๋ผ ์“ฐ๊ธฐ์˜€๋‹ค.**\n *\n * ๋ฐ”๋กœ ์œ„ ์ฃผ์„์ด **๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…**์—์„œ ๊ฐ™์€ ํ•จ์ •์„ ์ ์–ด ๋‘์—ˆ๋‹ค(ํ‹ฑ ํ•˜๋‚˜๊ฐ€ 35์ดˆ). ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์€ ๋ชจ์œผ๋„๋ก\n * ๊ณ ์ณค๊ณ  ์“ฐ๊ธฐ๋Š” ๋‹จ๊ฑด์œผ๋กœ ๋‚จ์•„ ์žˆ์—ˆ๋‹ค. ๊ฐ™์€ ๊ทœ์œจ๋กœ ๋“ค์ธ๋‹ค โ€” ADR-0030 ์ด *\"๊ธฐ๋ก ๊ฒฝ๋กœ๊ฐ€ ๋‘˜์ธ\n * ๊ฒƒ์€ ์‹œ๋ฎฌ๋งŒ ์˜†๋ฌธ์œผ๋กœ ๋“ค์–ด์˜ค๊ธฐ ๋•Œ๋ฌธ\"* ์ด๋ผ ์˜ˆ๊ณ ํ•œ ๊ทธ ์ž๋ฆฌ๋‹ค.\n *\n * **๋ฆฌ๋น„์ „์€ ์ปค๋„์˜ ๊ฒƒ์„ ๊ทธ๋Œ€๋กœ ๋“ ๋‹ค**(๋ผ์ด๋ธŒ๋Š” flush ๋•Œ ํ˜ธ์ŠคํŠธ๊ฐ€ ๋ถ€์—ฌํ•œ๋‹ค). ์‹œ๋ฎฌ์˜ ์ €๋„์€\n * ์ปค๋„ ๋ฆฌ๋น„์ „์œผ๋กœ ์ ‘ํžˆ๋ฏ€๋กœ ์—ฌ๊ธฐ์„œ ๋‹ค์‹œ ๋ฒˆํ˜ธ๋ฅผ ๋งค๊ธฐ๋ฉด ์‹œ๊ฐ„์—ฌํ–‰์ด ์–ด๊ธ‹๋‚œ๋‹ค.\n */\n ;(inst.pendingJournal ?? (inst.pendingJournal = [])).push({ event: msg.event, revision: (msg as any).revision })\n /*\n * โ”€โ”€ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์€ **๋ชจ์•„์„œ** ํ•œ ๋ฒˆ (2026-08-14 ์‹ค์ธก์œผ๋กœ ์žก์Œ) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์—ฌ๊ธฐ์„œ ๊ณง๋ฐ”๋กœ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…ํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ปค๋„์€ ํ•œ ๋ฒˆ์˜ tick ์—์„œ ์‚ฌ์‹ค์„ **์—ฌ๋Ÿฌ ๊ฐœ** ๋‚ธ๋‹ค\n * (์˜ˆ์•ฝยท๋ฐฐ์น˜ยท์™„๋ฃŒโ€ฆ). ๊ทธ๋ž˜์„œ tick ํ•˜๋‚˜๊ฐ€ ์ „ ์ƒํƒœ ํˆฌ์˜์„ ์ˆ˜๋ฐฑ ๋ฒˆ ๋ฐ˜๋ณตํ–ˆ๋‹ค โ€” `order-check`\n * ํŠธ์œˆ์—์„œ **ํ‹ฑ ํ•˜๋‚˜๊ฐ€ 35์ดˆ**๋ฅผ ๋จน๊ณ (๋‹จ๊ณ„ ํ•ฉ์€ 32ms ์˜€๋‹ค: ์‹œ๊ฐ„์€ ๋ฐ˜๋ณต ํšŸ์ˆ˜์— ์žˆ์—ˆ๋‹ค) ๊ทธ\n * 35์ดˆ ๋™์•ˆ ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ๋ง‰ํ˜€ ๊ตฌ๋…์ž๊ฐ€ ์•„๋ฌด๊ฒƒ๋„ ๋นผ๋‚ด์ง€ ๋ชปํ–ˆ๋‹ค. ๋ฐ€๋ฆฐ push ๊ฐ€ 1024๋ฅผ ๋„˜๋Š”\n * ์ˆœ๊ฐ„ pubsub ์ด ์˜ค๋ฅ˜๋ฅผ ๋‚ด๊ณ , ๊ทธ ์˜ˆ์™ธ๊ฐ€ ํƒ€์ด๋จธ ์ฝœ๋ฐฑ์„ ํƒ€๊ณ  ์˜ฌ๋ผ์™€ **ํ˜ธ์ŠคํŠธ๊ฐ€ ์ฃฝ์—ˆ๋‹ค.**\n *\n * ๋ผ์ด๋ธŒ๋Š” ์ด๋ฏธ dirty ํ‘œ์‹œ + ์ฃผ๊ธฐ flush ๋กœ ์ด ๋ฌธ์ œ๋ฅผ ํ’€์–ด ๋‘์—ˆ๋‹ค(BROADCAST_COALESCE_MS).\n * ์‹œ๋ฎฌ๋งŒ ๊ทธ ๊ทœ์œจ ๋ฐ–์— ์žˆ์—ˆ๋‹ค โ€” ๊ฐ™์€ ๊ทœ์œจ๋กœ ๋“ค์ธ๋‹ค(์ตœ์‹ -์ƒํƒœ ์ฑ„๋„์ด๋ผ ์ค‘๊ฐ„ ์ƒํƒœ๋ฅผ ๋ชจ๋‘\n * ๋ณด๋‚ผ ์ด์œ ๊ฐ€ ์—†๋‹ค: 200ms ๋งˆ๋‹ค ๋งˆ์ง€๋ง‰ ๊ฒƒ ํ•˜๋‚˜๋ฉด ํ™”๋ฉด์€ ๊ฐ™๋‹ค).\n */\n inst.dirty = true\n /* ์ด ์‚ฌ์‹ค์ด ๊ฑด๋“œ๋ฆฐ ๋ฌผํ’ˆ๋งŒ ๋‹ค์Œ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์—์„œ ๋งŒ๋“ ๋‹ค(๋ชจ๋ฅด๋ฉด ์ „๋ถ€). */\n this.markItemsDirty(inst, [msg.event])\n this.ensureBroadcastCoalescer()\n }\n })\n inst.unsub = () => sub.unsubscribe()\n\n /* ์œ„์—์„œ ์žฐ ์›œ์Šคํƒ€ํŠธ ์‹œ๊ฐ„์„ ๊ณ„๊ธฐ์— ์ ๋Š”๋‹ค โ€” ๊ณ„๊ธฐ๋Š” ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ๊ธด ๋’ค์—์•ผ ์žˆ๋‹ค. */\n recordPhase(inst.load ?? (inst.load = newLoadMeter()), 'warmStart', warmMs)\n\n /* ๋ณต๊ตฌ ์•ต์ปค: ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— model/kind/status/restartPolicy ์˜์†(์žฌ๋ถ€ํŒ… ์‹œ ์ด๊ฒŒ ์žˆ์–ด์•ผ replayยท์„ ์–ธ ๊ฑฐ๋™ ๊ฐ€๋Šฅ). */\n this.register(domainId, id, kind, model, 'running', inst.restartPolicy).catch(err => twinError('twin register fail', err))\n\n /* ์›Œ์ปค tick โ€” ์Šค์ผˆ๋ ˆํ†ค์€ setInterval(๋ฉ”์ธ ๋ฃจํ”„). ๊ธด ์‹œ๋ฎฌ ์˜คํ”„-๋ฃจํ”„(worker thread)๋Š” ์Šค์ผ€์ผ ํ•˜๋“œ๋‹(ํ–ฅํ›„, ยงhost ๊ฒฝ๊ณ„). */\n inst.timer = this.startTickTimer(\n () => this.tickGuarded(domainId, id, runtime),\n t => (inst.timer = t)\n )\n return inst\n }\n\n /**\n * live-๋ชจ๋“œ ๊ธฐ๋™ โ€” **๊ด€์ธก ๋ชจ๋“œ ์ปค๋„**๋กœ ์‹ค ์ด๋ฒคํŠธ๋ฅผ ๋ฏธ๋Ÿฌํ•œ๋‹ค(ํ†ตํ•ฉ P2).\n *\n * ์˜ˆ์ „์—๋Š” `StateProjector` ๋ฅผ ์„ธ์› ๋‹ค. ๊ทธ๋ž˜์„œ ๋ผ์ด๋ธŒ์—๋Š” **์ปค๋„์ด ์—†์—ˆ๊ณ **, ๊ทธ ํ•˜๋‚˜ ๋•Œ๋ฌธ์— ์šฐํšŒ๊ฐ€\n * ์ค„์ค„์ด ์ƒ๊ฒผ๋‹ค: ์˜ˆ์ธกํ•˜๋ ค๋ฉด ์ž„์‹œ ์ปค๋„์„ ์„ธ์›Œ์•ผ ํ–ˆ๊ณ (`buildForecastKernel`), ์ฃผ๋ชฉ ์‹ ํ˜ธ๋ฅผ ํ˜ธ์ŠคํŠธ๊ฐ€\n * ๋ง๋ถ™์—ฌ์•ผ ํ–ˆ๊ณ (`withLiveAttentions`), AI ์˜ˆ์ธก ๋„๊ตฌ๋Š” ๋ฏธ๋Ÿฌ์—์„œ \"์ฐพ์„ ์ˆ˜ ์—†๋‹ค\" ๋กœ ๋๋‚ฌ๋‹ค.\n *\n * ์ด์ œ ๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค๋„ **์ปค๋„์ด๋‹ค.** ๊ฐ™์€ ๊ทœ์น™(`ObservedReducer`)์œผ๋กœ ์ด๋ฒคํŠธ๋ฅผ ์ ‘๊ณ , ์ฃผ๋ชฉ ์‹ ํ˜ธ๋ฅผ\n * ์Šค์Šค๋กœ ๋‚ด๊ณ , ๊ทธ ์ž๋ฆฌ์—์„œ `fork` ํ•ด ์˜ˆ์ธกํ•œ๋‹ค. ๊ตฌ๋™๋งŒ ๋‹ค๋ฅด๋‹ค โ€” sim ์€ `tick`, live ๋Š” `apply`.\n *\n * ์‹ค ์ด๋ฒคํŠธ์› = reference ์–ด๋Œ‘ํ„ฐ openLiveFeed โ†’ face2-adapter.ingest โ†’ CanonicalEnvelope โ†’ ingestLive().\n */\n /**\n * ๋ชจ๋ธ์ด ์‹ค์€ **์ƒ์‚ฐ ์ •์˜**(๋ ˆ์‹œํ”ผยท๋ผ์šฐํŠธยท๋ฐ”์ธ๋”ฉ)๋ฅผ ๊บผ๋‚ธ๋‹ค โ€” ์ปค๋„์˜ ์ •์˜-๊ตฌ๋™ ๋ชจ๋“œ ์ž…๊ตฌ.\n *\n * โ”€โ”€ ์—†์„ ๋•Œ ๋ฌด์—‡์ด ์ผ์–ด๋‚ฌ๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ปค๋„์—๋Š” ์ •์˜-๊ตฌ๋™ MES ๊ฒฝ๋กœ๊ฐ€ ์žˆ๋Š”๋ฐ **ํ˜ธ์ŠคํŠธ๊ฐ€ ๊ทธ๊ฒƒ์„ ํ•œ ๋ฒˆ๋„ ๋„˜๊ธฐ์ง€ ์•Š์•˜๋‹ค.** ๊ทธ๋ž˜์„œ ๋ชจ๋“  MES\n * ํŠธ์œˆ์ด **ํ•˜๋“œ์ฝ”๋”ฉ๋œ ๋ ˆ๊ฑฐ์‹œ ํ๋ฆ„**์œผ๋กœ ๋Œ์•˜๋‹ค โ€” ํ˜„์žฅ ๋ ˆ์‹œํ”ผ๋ฅผ ์•„๋ฌด๋ฆฌ ์ •์„ฑ๊ป ์ ์–ด๋„ ์ปค๋„์€ ๊ทธ๊ฒƒ์„\n * ๋ณด์ง€ ๋ชปํ•˜๊ณ  ํ† ์ด ๋ถ€ํ’ˆ์œผ๋กœ ํ† ์ด ์ œํ’ˆ์„ ๋งŒ๋“ค์—ˆ๋‹ค. ์„ ์–ธ๊ณผ ์‹คํ–‰์ด ๊ฐˆ๋ผ์ ธ ์žˆ๋˜ ์ž๋ฆฌ๋‹ค.\n *\n * ๋ชจ๋ธ์— ์—†์œผ๋ฉด `undefined` โ€” ๋ ˆ๊ฑฐ์‹œ ๊ฒฝ๋กœ ๊ทธ๋Œ€๋กœ๋‹ค(๊ธฐ์กด ํŠธ์œˆ์˜ ๊ฑฐ๋™์„ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค).\n */\n /**\n * ์ƒ์‚ฐ ์„ ์–ธ์„ ๊บผ๋‚ธ๋‹ค โ€” ์ปค๋„ ์ƒ์„ฑ์ž์— ๋„˜๊ธด๋‹ค.\n *\n * **์˜› ์ด๋ฆ„(`mesSpec`)์€ ์ฝ์ง€ ์•Š๋Š”๋‹ค.** ๊ทธ๊ฒƒ์€ ๊ณ„์•ฝ์— ์„ ์–ธ์กฐ์ฐจ ์—†๋˜ ํ•„๋“œ์˜€๊ณ (MES ์ปค๋„ ์ƒ์„ฑ์ž ์ธ์ž\n * ์ด๋ฆ„์ด ๊ทธ๋Œ€๋กœ ๊ตณ์€ ๊ฒƒ), ์ผ๋ฐ˜ ๊ธฐ์ œ์— ํ•œ ์‹œ์Šคํ…œ ์ด๋ฆ„์ด ๋ถ™์–ด ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฐฝ๊ณ  ํŠธ์œˆ์ด ์ด ์ž๋ฆฌ๋ฅผ\n * ์“ฐ์ง€ ๋ชปํ–ˆ๋‹ค. ๋ณ„๋ช…์œผ๋กœ ๋‚จ๊ฒจ ๋‘๋ฉด ๊ทธ ํ˜ผ๋™์ด ๊ณ„์†๋˜๋ฏ€๋กœ ํ•˜๋‚˜๋กœ ํ†ต์ผํ–ˆ๋‹ค.\n *\n * ์˜› ์ด๋ฆ„๋งŒ ๊ฐ€์ง„ ๋ชจ๋ธ์ด ์žˆ์œผ๋ฉด **์กฐ์šฉํžˆ ์ƒ์‚ฐ ์„ ์–ธ์„ ์žƒ๋Š” ๋Œ€์‹  ๋ถ„๋ช…ํžˆ ๋ฉˆ์ถ˜๋‹ค** โ€” ๊ทธ ํŠธ์œˆ์€ ๊ณต์ •์ด\n * ์—†๋Š” ์ฑ„๋กœ ๋Œ๊ฒŒ ๋˜๊ณ (๋ผ์ธ์ด ์„œ ์žˆ๋Š” ์ฐฝ๊ณ ), ์›์ธ์„ ์ฐพ๊ธฐ ์–ด๋ ต๋‹ค.\n */\n private static productionSpecOf(model: TwinModelDef | undefined): any {\n const legacy = (model as any)?.mesSpec\n if (legacy && !(model as any)?.productionSpec) {\n throw new Error(\n 'the twin model carries the retired `mesSpec` field โ€” rename it to `productionSpec` ' +\n '(same shape; the name was tied to one kernel while the declaration is ISA-95 operations + BOM)'\n )\n }\n return (model as any)?.productionSpec\n }\n\n /**\n * ํ˜„์žฅ(๊ณต๊ฐ„)์˜ **์‹œ๊ฐ ๊ธฐ์ค€**์„ ๋ชจ๋ธ์— ์–น๋Š”๋‹ค โ€” ์ปค๋„์ด ๊ต๋Œ€์˜ `HH:MM` ์„ ์ฝ์„ ๊ธฐ์ค€.\n *\n * **ํ…Œ๋„ŒํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ ๊ณต๊ฐ„์ด ๊ถŒ์œ„๋‹ค.** ํ•œ ํ…Œ๋„ŒํŠธ๊ฐ€ Rosarito(ํƒœํ‰์–‘)์™€ ํ•œ๊ตญ ๊ณต์žฅ์„ ํ•จ๊ป˜ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ณ ,\n * ํ…Œ๋„ŒํŠธ ๋‹จ์œ„(`Domain.timezone`)๋กœ ๋‘๋ฉด ๋‘˜ ์ค‘ ํ•˜๋‚˜๋Š” ๋ฐ˜๋“œ์‹œ ํ‹€๋ฆฐ๋‹ค. ๊ทธ๋ž˜์„œ ์ธ์Šคํ„ด์Šค๊ฐ€ ์—ฐ๊ฒฐ๋œ ๊ณต๊ฐ„์˜\n * `timezone` ์„ ์ฝ๋Š”๋‹ค. ๊ณต๊ฐ„์ด ๋งํ•˜์ง€ ์•Š์œผ๋ฉด **ํ…Œ๋„ŒํŠธ๋กœ ๋‚ด๋ ค๊ฐ€์ง€ ์•Š๋Š”๋‹ค** โ€” ์ž˜๋ชป๋œ ์ž…์ž๋กœ ๋‹ตํ•˜๋Š” ๊ฒƒ์ด\n * ๋ชจ๋ฅด๋Š” ๊ฒƒ๋ณด๋‹ค ๋‚˜์˜๋‹ค(๊ทธ๋•Œ๋Š” ์ปค๋„์ด UTC ๋กœ ์ฝ๊ณ , ๊ทธ ๊ธฐ๋ณธ๊ฐ’์€ ๊ณ„์•ฝ์— ๋ฐํ˜€์ ธ ์žˆ๋‹ค).\n *\n * ์ปค๋„์€ zero-dep ์ด๋ผ ์‹œ๊ฐ„๋Œ€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๊ฐ–์ง€ ์•Š์œผ๋ฏ€๋กœ **๋ถ„ ์˜คํ”„์…‹**์œผ๋กœ ํ’€์–ด ๋„˜๊ธด๋‹ค. ๊ทธ ๊ฐ’์€\n * ์ง€๊ธˆ ๊ณ„์ ˆ์˜ ๊ฒƒ์ด๋‹ค(์ผ๊ด‘์ ˆ์•ฝ์‹œ๊ฐ„) โ€” ๊ณ„์ ˆ์„ ๋„˜๋Š” ๊ธด ์˜ˆ์ธก์€ ํ•œ ์‹œ๊ฐ„ ์–ด๊ธ‹๋‚œ๋‹ค(๊ณ„์•ฝ์— ๋ช…์‹œ).\n */\n static async withSpaceTimeBase(model: TwinModelDef, domainId: string, spaceId?: string): Promise<TwinModelDef> {\n const sid = spaceId ?? (model as any)?.spaceId\n if (!sid) return model\n const space = await getRepository(TwinSpace).findOne({ where: { domain: { id: domainId }, spaceId: sid } }).catch(() => null)\n const offset = utcOffsetOf(space?.timezone)\n if (offset === undefined) {\n if (space?.timezone) twinWarn(`[twin-engine] space \"${sid}\" declares time zone \"${space.timezone}\" but it is not a known IANA zone โ€” times will be read as UTC.`)\n return model\n }\n return { ...model, utcOffsetMinutes: offset }\n }\n\n static startLive(id: string, domainId: string, kind: string, model: TwinModelDef): InstanceRuntime {\n const key = runtimeKey(domainId, id)\n if (this.instances[key]) return this.instances[key]\n const Kernel = kernelFor(kind)\n const kernel: any = new Kernel(domainId, undefined, this.productionSpecOf(model))\n kernel.loadTwinModel(model)\n /* **์„ธ์šฐ๋Š” ์ชฝ์ด ์•„๋Š” ์‚ฌ์‹ค์€ ์„ธ์šธ ๋•Œ ๋งํ•œ๋‹ค.** ์˜ˆ์ „์—๋Š” ์ฒซ ์ด๋ฒคํŠธ๊ฐ€ ๋„์ฐฉํ•ด์•ผ ์ปค๋„์ด ์Šค์Šค๋กœ๋ฅผ\n ๊ด€์ธก ๊ตฌ๋™์œผ๋กœ ์—ฌ๊ฒผ๊ณ , ๊ทธ๋ž˜์„œ ์•„์ง ์•„๋ฌด๊ฒƒ๋„ ๋ชป ๋ฐ›์€ ๋ฏธ๋Ÿฌ๋Š” ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ์ทจ๊ธ‰์„ ๋ฐ›์•˜๋‹ค. */\n declareObserved(kernel, `live twin '${id}'`)\n this.applyOperations(kernel, model, id) // ๋ช…์„ธ๋Š” ๋ผ์ด๋ธŒ์—๋„ ์‹ค๋ฆฐ๋‹ค(์˜ˆ์ธก ์ž๊ฒฉ์ด sim ๊ณผ ๊ฐ™์•„์ง„๋‹ค)\n /* `projector` ํ•„๋“œ๋Š” ์˜› ์ด๋ฆ„์œผ๋กœ ๋‚จ๊ธด๋‹ค โ€” ์†Œ๋น„์ฒ˜๊ฐ€ `snapshot()` ์„ ๋ถ€๋ฅด๋ฏ€๋กœ ์–‡์€ ์–ด๋Œ‘ํ„ฐ๋กœ ์ž‡๋Š”๋‹ค.\n * (P3 ์—์„œ ์†Œ๋น„์ฒ˜๋ฅผ ์ปค๋„ ์–ดํœ˜๋กœ ๋ฐ”๊พธ๋ฉด ์‚ฌ๋ผ์ง„๋‹ค.) */\n const projector = { apply: (e: CanonicalEnvelope) => kernel.apply(e), snapshot: () => kernel.getSnapshot() }\n const inst: InstanceRuntime = { id, domainId, mode: 'live', restartPolicy: 'resync', kernel, projector, oee: new OeeAccumulator(), spaceId: (model as any)?.spaceId, unsub: () => {} }\n /*\n * โ”€โ”€ ์ปค๋„์ด **ํŒ์ •์œผ๋กœ ๋‚ธ ์‚ฌ์‹ค**๋„ ์ €๋„์— ๋‚จ๋Š”๋‹ค (2026-08-14 ์‹ค์ธก์œผ๋กœ ์žก์Œ) โ”€โ”€โ”€โ”€\n *\n * ๋ผ์ด๋ธŒ๋Š” ์ธ์ž… ๋ด‰ํˆฌ๋งŒ ์ €๋„์— ์ ๊ณ  ์žˆ์—ˆ๋‹ค(`ingestLive`). ๊ทธ๋Ÿฐ๋ฐ ์ปค๋„์€ ๊ด€์ธก์„ ์ ‘๋‹ค๊ฐ€ **์ž๊ธฐ ์‚ฌ์‹ค**์„\n * ๋‚ธ๋‹ค โ€” ์—๋„ˆ์ง€์˜ ์ˆ˜์š” ๊ตฌ๊ฐ„ ๋งˆ๊ฐยทํ”ผํฌ ๊ฒฝ์‹ ยท๊ฐ์ถ• ์ œ์•ˆ์ด ๊ทธ๋ ‡๋‹ค(`emitOp`). ๊ทธ๊ฒƒ์„ ๊ตฌ๋…ํ•˜๋Š” ๊ณณ์ด\n * ์—†์–ด์„œ ๊ทธ ์‚ฌ์‹ค๋“ค์ด **์ปค๋„ ์•ˆ์—์„œ ์‚ฌ๋ผ์กŒ๋‹ค**: ํ‘œ๋ณธ 48๊ฑด์ด ์ €๋„์— ์Œ“์˜€๋Š”๋ฐ ๊ตฌ๊ฐ„ ๋งˆ๊ฐ์€ 0๊ฑด์ด์—ˆ๊ณ ,\n * ์ €๋„์„ ์ฝ๋Š” ์„ฑ๊ณผ ํ™”๋ฉด์˜ ์ „๋ ฅ ํƒ€์ผ์€ ์˜์›ํžˆ ๋‚˜์˜ค์ง€ ์•Š์•˜๋‹ค.\n *\n * sim ์€ `runtime.subscribe` ๋กœ ๊ฐ™์€ ์ผ์„ ํ•œ๋‹ค โ€” ๋ผ์ด๋ธŒ์—๋งŒ ๊ทธ ๋ฐฐ์„ ์ด ์—†์—ˆ๋‹ค.\n *\n * **์ธ์ž…์˜ ์žฌ๋ฐฉ์ถœ์€ ๊ฑธ๋Ÿฌ๋‚ธ๋‹ค**: `apply()` ๋Š” ๋ฐ›์€ ๋ด‰ํˆฌ๋ฅผ ๊ตฌ๋…์ž์—๊ฒŒ ๊ทธ๋Œ€๋กœ ํ˜๋ฆฐ๋‹ค(ํ˜ธ์ŠคํŠธ๊ฐ€ ๋‘ ๋ชจ๋“œ์—์„œ\n * ๊ฐ™์€ ๋ฐฐ์„ ์„ ์“ฐ๊ฒŒ ํ•˜๋ ค๊ณ ). ๊ทธ๊ฒƒ๊นŒ์ง€ ์ ์œผ๋ฉด ์ธ์ž…์ด ์ €๋„์— ๋‘ ๋ฒˆ ๋“ค์–ด๊ฐ„๋‹ค โ€” ๊ทธ๋ž˜์„œ ๋ฐฉ๊ธˆ ๋„ฃ์€ ๊ฒƒ๊ณผ\n * **๊ฐ™์€ ๊ฐ์ฒด**์ธ์ง€ ๋ณด๊ณ  ๊ฑด๋„ˆ๋›ด๋‹ค(id ๋น„๊ต๋Š” ์–ด๋Œ‘ํ„ฐ๊ฐ€ id ๋ฅผ ์–ด๋–ป๊ฒŒ ๋งŒ๋“œ๋Š”์ง€์— ๊ธฐ๋Œ€๊ฒŒ ๋˜์–ด ์•ฝํ•˜๋‹ค).\n */\n const applying = new WeakSet<object>()\n inst.applying = applying\n inst.unsub = kernel.onEvent?.((e: CanonicalEnvelope) => {\n if (e && typeof e === 'object' && applying.has(e as object)) return // ์ธ์ž…์˜ ์žฌ๋ฐฉ์ถœ โ€” ์ €๋„์€ ์ธ์ž…์—์„œ ํ•œ ๋ฒˆ๋งŒ\n ;(inst.pendingJournal ?? (inst.pendingJournal = [])).push(e)\n /* ์ปค๋„์ด ๋‚ธ ์‚ฌ์‹ค๋„ ์ƒํƒœ๋ฅผ ๋ฐ”๊พผ๋‹ค(ํ”ผํฌยท๋งˆ๊ฐ) โ€” ๋‹ค์Œ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ… ์ฃผ๊ธฐ์— ์‹ค๋ฆฐ๋‹ค. */\n inst.dirty = true\n this.markItemsDirty(inst, [e])\n this.ensureBroadcastCoalescer()\n }) ?? (() => {})\n /* ์ถ”์ •๊ธฐ(์‹ค์ธกยท๊ฑฐ๋ฆฌ)๋„ ๋ผ์ด๋ธŒ์— ๋ถ™์ธ๋‹ค โ€” ์˜ˆ์ธก์ด ์ƒ์ˆ˜๋กœ ๊ณ„์‚ฐ๋˜์ง€ ์•Š๊ฒŒ. ๊ธฐ๋™์„ ๋ง‰์ง€ ์•Š๋Š”๋‹ค. */\n this.installEstimators(kernel, domainId, id, model).catch(err => twinWarn('[twin-engine] estimator install failed', err?.message))\n inst.metrics = this.newMetrics()\n this.instances[key] = inst\n /* ๋ฏธ๋Ÿฌ์—๋„ ๋ถ€๋ฅธ๋‹ค โ€” ์„ ์–ธ์ด ์žˆ์œผ๋ฉด ใ€Œ๋ฏธ๋Ÿฌ์—๋Š” ์‹ฃ์ง€ ์•Š๋Š”๋‹คใ€๊ณ  ๋งํ•ด์•ผ ํ•œ๋‹ค(์กฐ์šฉํ•œ ๋ฌด์‹œ ๊ธˆ์ง€). */\n this.installStimulus(domainId, id, inst).catch(err => twinWarn(`[twin-engine] \"${id}\": stimulus check failed โ€” ${err?.message ?? err}`))\n /*\n * **์›์ฒœ์ด ๋˜ํ’€์–ด ์ฃผ์ง€ ์•Š๋Š” ๊ฒƒ๋งŒ ์ž‡๋Š”๋‹ค** (2026-08-18 ์‹ค์ธก์œผ๋กœ ๋ถ™์ž„).\n *\n * ๋ฏธ๋Ÿฌ๋Š” ์˜ค๋žซ๋™์•ˆ ์•„๋ฌด๊ฒƒ๋„ ์ด์–ด๋ฐ›์ง€ ์•Š์•˜๋‹ค โ€” ์ง„์‹ค์ด ์›์ฒœ์— ์žˆ์œผ๋‹ˆ ์˜ณ์€ ํŒ๋‹จ์ด์—ˆ์ง€๋งŒ, ์›์ฒœ์ด **์• ์ดˆ์—\n * ๋‹ค์‹œ ๋งํ•ด ์ฃผ์ง€ ์•Š๋Š” ์ถ•**๊นŒ์ง€ ํ•จ๊ป˜ ๋ฒ„๋ ธ๋‹ค: ์—ด๋ฆฐ 15๋ถ„ ๊ตฌ๊ฐ„์˜ ๋ˆ„์ ยท์ ์‚ฐ ๊ธฐ์ค€์ ยท๊ด€์ธก ์ดํ›„ ์ตœ๋Œ€, ๊ทธ๋ฆฌ๊ณ \n * ํ™•์ธํ•ด ๋‘” ์‹ ํ˜ธ์™€ ์กฐ๊ฑด์ด ์–ธ์ œ๋ถ€ํ„ฐ์ธ์ง€. ๊ทธ๋ž˜์„œ ์žฌ๊ธฐ๋™ํ•˜๋ฉด ์˜ค๋ฅ˜ ์—†์ด ๊ฐ’์ด ์ž‘์•„์กŒ๋‹ค(๊ทธ ๊ตฌ๊ฐ„์˜ ์ „๋ ฅ๋Ÿ‰๊ณผ\n * ํ”ผํฌ๊ฐ€ ๋ถ€ํŒ… ์ดํ›„๋กœ๋งŒ ์žกํžˆ๊ณ , ์„ธ ์‹œ๊ฐ„์งธ ์ง€์†๋œ ๊ฒฝ๋ณด๊ฐ€ ใ€Œ0์ดˆ์งธใ€๊ฐ€ ๋๋‹ค โ€” ์š”๊ธˆ์ด ๊ฑธ๋ฆฐ ์ˆ˜๋‹ค).\n *\n * ๊ด€์ธก ์ถ•(์žฌ๊ณ ยท์œ„์น˜ยท์„ค๋น„)์€ **์—ฌ์ „ํžˆ ์‹ฌ์ง€ ์•Š๋Š”๋‹ค** โ€” ๋‹ค์Œ ๊ณ„์ธก์ด ์ •์ •ํ•˜๊ณ , ์‹ฌ์œผ๋ฉด ๋– ๋‚œ ๋ฌผ๊ฑด์ด\n * ๋˜์‚ด์•„๋‚œ๋‹ค. ๋ฌด์—‡์„ ๋„˜๊ธธ์ง€๋Š” `planLiveContinuity` ๊ฐ€ ๊ณ ๋ฅด๊ณ , ์–ด๋–ป๊ฒŒ ํก์ˆ˜ํ• ์ง€๋Š” ์ปค๋„์ด ์ •ํ•œ๋‹ค.\n */\n this.seedLiveContinuity(domainId, id, kernel)\n delete this.recovered[key]\n /* ๋ผ์ด๋ธŒ ๋ฐ”์ธ๋”ฉ(data ์ฑ„๋„) subdomain ํ•„ํ„ฐ์šฉ Domain 1ํšŒ ํ•ด์„(sim ๊ณผ ๋™์ผ). */\n getRepository(Domain).findOne({ where: { id: domainId } }).then(d => (inst.domain = d)).catch(() => {})\n /*\n * ์ €๋„ revision ์นด์šดํ„ฐ ์‹œ๋“œ โ€” ๊ธฐ์กด ์ €๋„ ์ตœ๋Œ€์น˜์—์„œ ์ด์–ด๋ถ™์ž„(์žฌ๊ธฐ๋™ ์‹œ revision ์ถฉ๋Œ ๋ฐฉ์ง€).\n *\n * โ”€โ”€ **์ปค๋„์—๋„ ๊ฐ™์€ ๋ฒˆํ˜ธ๋ฅผ ์•Œ๋ ค ์ค€๋‹ค** (2026-08-23 ์‹ค์ธก) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์˜ˆ์ „์—๋Š” ์ด ์ž๋ฆฌ์—์„œ `inst.revision`(์ €๋„ ์ค„ ๋ฒˆํ˜ธ)๋งŒ ์ด์–ด๋ฐ›๊ณ  **์ปค๋„์€ 0 ๋ถ€ํ„ฐ ์„ธ๊ฒŒ ๋‘์—ˆ๋‹ค.**\n * ๊ทธ๋ž˜์„œ ์ฒดํฌํฌ์ธํŠธ๊ฐ€ ๋œป์ด ๋‹ค๋ฅธ ๋‘ ์ˆ˜๋ฅผ ๋‚˜๋ž€ํžˆ ์ ์—ˆ๋‹ค.\n *\n * ๋ฐ”๊นฅ revision 12,972 ์ €๋„์— ์ ํžŒ ์ค„ ๋ฒˆํ˜ธ (์ด ์ž๋ฆฌ์—์„œ ์ด์–ด๋ฐ›๋Š”๋‹ค)\n * state.revision 6,478 ์ปค๋„์ด ์ฒ˜๋ฆฌํ•œ ๋ด‰ํˆฌ ์ˆ˜ (0 ๋ถ€ํ„ฐ ์…Œ๋‹ค)\n *\n * ํฌ์ฒœ ๋ฏธ๋Ÿฌ์—์„œ ํ™•์ •ํ–ˆ๋‹ค: ์ฐจ์ด 6,494 ๋Š” ๊ทธ ํŠธ์œˆ์„ **๋‹ค์‹œ ์„ธ์šด ์‹œ๊ฐ**(09:11)์— ์ €๋„์ด ์ด๋ฏธ ๊ฐ–๊ณ \n * ์žˆ๋˜ ์ค„ ์ˆ˜์™€ ์ •ํ™•ํžˆ ๊ฐ™์•˜๋‹ค(์ค„ 6494 = 08:23:59, ์ค„ 6495 = 09:11:13). ์‚ฐ์ˆ˜๊ฐ€ ๋งž์•˜๋‹ค.\n *\n * ๊ฒฐํ•จ์€ ๋‘ ์ˆ˜๊ฐ€ ๋‹ค๋ฅด๋‹ค๋Š” ๊ฒƒ ์ž์ฒด๊ฐ€ ์•„๋‹ˆ๋ผ **๋น„๋Œ€์นญ**์ด๋‹ค: ์žฌ๊ธฐ๋™ ๊ฒฝ๋กœ(`start` โ†’ `resumeRevision`)๋Š”\n * ์ปค๋„์— ๋ฒˆํ˜ธ๋ฅผ ์•Œ๋ ค ์ฃผ๋Š”๋ฐ **์ด ๊ฒฝ๋กœ(๋ฏธ๋Ÿฌ)๋Š” ์•Œ๋ ค ์ฃผ์ง€ ์•Š์•˜๋‹ค.** ๊ทธ๋ž˜์„œ ๊ฐ™์€ ์ €์žฅ๋ฌผ์„ ์ฝ๋Š” ์†Œ๋น„์ฒ˜๊ฐ€\n * ๊ฐ™์€ ์ด๋ฆ„์˜ ๋‘ ์ˆ˜๋ฅผ ๊ฐ™์€ ์ถ•์œผ๋กœ ๊ฒฌ์ฃผ๊ฒŒ ๋˜๊ณ , ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ์ฝํ˜”๋‹ค.\n *\n * ์ €๋„์ด ๋น„์–ด ์žˆ์œผ๋ฉด(0) ์•„๋ฌด ์ผ๋„ ํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” ์ƒˆ ํŠธ์œˆ์€ 0 ๋ถ€ํ„ฐ ์„ธ๋Š” ๊ฒƒ์ด ๋งž๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ์กฐํšŒ๋Š”\n * ๋น„๋™๊ธฐ๋ผ ๊ทธ ์‚ฌ์ด์— ์ด๋ฒคํŠธ๊ฐ€ ๋ช‡ ๊ฑด ๋“ค์–ด์™€ ์žˆ์„ ์ˆ˜ ์žˆ๋Š”๋ฐ, ๊ทธ๋•Œ ๋’ค๋กœ ๋˜๋Œ๋ฆฌ๋Š” ๊ฒƒ์€ ์ปค๋„์ด ๊ฑฐ์ ˆํ•œ๋‹ค\n * (๊ฒน์น˜๋Š” ๋ฒˆํ˜ธ๋ฅผ ๋ง‰๋Š” ๊ทธ ํŒ์ •์ด๋‹ค). ๊ฑฐ์ ˆ์€ ์‚ผํ‚ค์ง€ ์•Š๊ณ  ๋‚จ๊ธด๋‹ค.\n */\n getRepository(TwinEvent)\n .findOne({ where: { domain: { id: domainId }, instanceId: id }, order: { revision: 'DESC' } })\n .then(top => {\n const head = top?.revision ?? 0\n inst.revision = head\n if (!head || typeof (kernel as any).resumeRevision !== 'function') return\n try {\n ;(kernel as any).resumeRevision(head)\n } catch (err: any) {\n /* ๋’ค๋กœ ๊ฐˆ ์ˆ˜ ์—†๋‹ค๋Š” ๊ฑฐ์ ˆ โ€” ์ด ์กฐํšŒ๊ฐ€ ๋„์ฐฉํ•˜๊ธฐ ์ „์— ์ด๋ฏธ ๊ทธ๋งŒํผ ์ฒ˜๋ฆฌํ–ˆ๋‹ค๋Š” ๋œป์ด๋‹ค. */\n twinWarn(`[twin-engine] \"${id}\": journal head ${head} is behind the kernel โ€” ${err?.message ?? err}`)\n }\n })\n .catch(() => (inst.revision = 0))\n this.register(domainId, id, kind, model, 'running', 'resync').catch(err => twinError('twin register fail', err))\n return inst\n }\n\n /**\n * live ์ด๋ฒคํŠธ ์ธ์ œ์ŠคํŠธ โ€” projector ๊ตฌ๋™ + data(tag) ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…(ํ๋ฃจํ”„์˜ ์ธ๋ฐ”์šด๋“œ ๋„์ฐฉ ์ง€์ , command-routing ยง8.2).\n * reference ์–ด๋Œ‘ํ„ฐ๊ฐ€ ๋‚ธ records โ†’ ์ปค๋„ face2-adapter.ingest โ†’ CanonicalEnvelope ๋ฅผ ์—ฌ๊ธฐ๋กœ ๋ฐ€์–ด๋„ฃ๋Š”๋‹ค.\n * (State ์ฑ„๋„ ๋ธํƒ€/์ €๋„ ๊ฒฐ์„ ์€ ํ›„์† โ€” ์Šค์ผˆ๋ ˆํ†ค์€ data(tag) ๋ฏธ๋Ÿฌ ์ค‘์‹ฌ.)\n *\n * โ”€โ”€ ๋„ฃ์€ ์ˆ˜๋ฅผ **๋‹ตํ•œ๋‹ค** (2026-08-20) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ํŠธ์œˆ์ด ๋ผ์ด๋ธŒ๋กœ ๋Œ์ง€ ์•Š์œผ๋ฉด ์—ฌ๊ธฐ์„œ ๋ด‰ํˆฌ๋ฅผ ๋ฒ„๋ฆฐ๋‹ค. ๊ทธ๊ฒƒ ์ž์ฒด๋Š” ๋งž๋‹ค(๋„ฃ์„ ์ปค๋„์ด ์—†๋‹ค). ๋ฌธ์ œ๋Š”\n * **์กฐ์šฉํžˆ** ๋ฒ„๋ฆฐ ๊ฒƒ์ด์—ˆ๋‹ค: ํŠธ์œˆ์ด ๋ฉˆ์ถ˜ ๋’ค์—๋„ ํ”ผ๋“œ๋Š” ๋‚จ์•„ ๋ ˆ์ฝ”๋“œ๋ฅผ ๋‚˜๋ฅด๊ณ , ์œ ์ž… ์žฅ๋ถ€๋Š” ๊ทธ๊ฒƒ์„\n * ใ€Œํ†ต๊ณผใ€๋กœ ์…Œ๋‹ค. ํ™”๋ฉด์€ ๋ฉˆ์ถ˜ ํŠธ์œˆ ์˜†์— ใ€Œ150 ํ†ต๊ณผ ยท 100%ใ€๋ผ๊ณ  ์ ์—ˆ๋‹ค โ€” ์‚ฌ์‹ค์ด ์‚ฌ๋ผ์ง€๋Š” ๋™์•ˆ\n * ํ™”๋ฉด์ด ์•ˆ์‹ฌ์‹œํ‚จ ๊ฒƒ์ด๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ **๋„ฃ์€ ์ˆ˜๋ฅผ ๋Œ๋ ค์ค€๋‹ค.** ๋ถ€๋ฅด๋Š” ์ชฝ์ด ์ œ์‹œ ์ˆ˜์™€ ๊ฒฌ์ฃผ์–ด ๋ฒ„๋ ค์ง„ ์ˆ˜๋ฅผ ์žฅ๋ถ€์— ์ ๋Š”๋‹ค. ๋ฐ˜ํ™˜์„\n * ๋ฌด์‹œํ•˜๋Š” ํ˜ธ์ถœ๋ถ€๋Š” ๊ทธ๋Œ€๋กœ ๋™์ž‘ํ•œ๋‹ค(์ „๊ณผ ๊ฐ™๋‹ค).\n */\n static ingestLive(domainId: string, id: string, envelopes: CanonicalEnvelope[]): number {\n const inst = this.instances[runtimeKey(domainId, id)]\n if (inst?.mode !== 'live' || !inst.projector) return 0\n const tIngest = performance.now()\n /* ์ธ์ž… ๋ด‰ํˆฌ๋ฅผ ํ‘œ์‹œํ•ด ๋‘๊ณ  ๋„ฃ๋Š”๋‹ค โ€” ์ปค๋„์ด ๊ทธ๊ฒƒ์„ ์žฌ๋ฐฉ์ถœํ•ด๋„ ์ €๋„์— ๋‘ ๋ฒˆ ์ ํžˆ์ง€ ์•Š๊ฒŒ(์œ„ ๊ตฌ๋… ์ฃผ์„). */\n for (const e of envelopes) {\n if (e && typeof e === 'object') inst.applying?.add(e as object)\n inst.projector.apply(e)\n inst.oee?.apply(e) // ๊ด€์ธก(projector) + ๊ณ„์‚ฐ(OEE ๋ˆ„์ )\n }\n recordPhase(inst.load ?? (inst.load = newLoadMeter()), 'ingest', performance.now() - tIngest)\n // ์ €๋„ ๊ฒฐ์„ (๋ผ์ด๋ธŒ๋„ sim ์ฒ˜๋Ÿผ ์ด๋ฒคํŠธ ์˜์†) โ€” ๋‹จ ์ด๋ฒคํŠธ๋งˆ๋‹ค DB write ํ•˜๋ฉด ๋ถ€ํ•˜ํญ๋ฐœ์ด๋ผ ๋ชจ์•„๋’€๋‹ค๊ฐ€\n // coalescer tick ์—์„œ ๋ฐฐ์น˜ ๊ธฐ๋ก(๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…๊ณผ ๋™์ผ ์ฃผ๊ธฐ). ํžˆ์Šคํ† ๋ฆฌ ๋…ธ๋ธŒยทํƒ€์ž„๋ผ์ธยท๋น„์ฆˆ๋‹ˆ์Šค ์›์žฅ์ด ์ด ์ €๋„์„ ์ฝ๋Š”๋‹ค.\n ;(inst.pendingJournal ?? (inst.pendingJournal = [])).push(...envelopes)\n if (inst.metrics) { inst.metrics.ingestedTotal += envelopes.length; inst.metrics._accIngest += envelopes.length } // ๊ณ„์ธก(โ‘ฃ-1)\n // ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ… ๋ณ‘ํ•ฉ(ingest-scale ยง1.1/ยง4.4) โ€” apply ๋Š” O(1)ยท์‹ธ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…(snapshot O(state))์€ ๋น„์‹ธ(๋Œ€๊ทœ๋ชจ 5ms+)\n // ์ด๋ฒคํŠธ๋งˆ๋‹ค ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…ํ•˜๋ฉด ํญ๋ฐœ โ†’ dirty ๋งŒ ์ฐ๊ณ  coalescer tick ์ด ์ฃผ๊ธฐ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…(๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…๋ฅ  โ‰  ์ธ์ œ์ŠคํŠธ๋ฅ ).\n inst.dirty = true\n this.markItemsDirty(inst, envelopes)\n this.ensureBroadcastCoalescer()\n return envelopes.length\n }\n\n /**\n * ๊ตฌ๊ฐ„ ์„ฑ๊ณผ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์€ **์—†์•ด๋‹ค**(2026-08-06). ์นด๋“œ๊ฐ€ `twinKpi` ๋ฅผ ์ง์ ‘ ๋ฌป๋Š”๋‹ค.\n *\n * ์™œ: ์นด๋“œ๋ฅผ ์—ฌ๋Ÿฌ ๋‹จ๊ณ„(๊ณต๊ฐ„ยทํŠธ์œˆยท๊ตฌ์—ญยท์ž๋ฆฌยท์„ค๋น„)์— ๋ถ™์ด๋ ค๋ฉด ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์œผ๋กœ๋Š” ํƒœ๊ทธ๊ฐ€ ํŠธ์œˆ๋‹น 1,200๊ฐœ๊ฐ€ ๋˜๊ณ ,\n * **๋ชจ๋ธ์— ์นด๋“œ๋ฅผ ํ•˜๋‚˜๋„ ์•ˆ ๋†“์•„๋„** 30์ดˆ๋งˆ๋‹ค ํŠธ์œˆ๋งˆ๋‹ค ์ €๋„์„ ์ ‘์—ˆ๋‹ค. ์งˆ์˜๋กœ ๋ฐ”๊พธ๋‹ˆ ๋ณด๊ณ  ์žˆ๋Š” ์นด๋“œ\n * ์ˆ˜๋งŒํผ๋งŒ ๋“ค๊ณ , ๊ฐ™์€ (๋Œ€์ƒยท์ฐฝยท์ถ•) ์€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํ•˜๋‚˜๋กœ ํ•ฉ์นœ๋‹ค.\n *\n * ๋ค์œผ๋กœ ์งˆ์˜๋งŒ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด ๋‘˜ ์ƒ๊ฒผ๋‹ค โ€” **๊ณผ๊ฑฐ ์‹œ๊ฐ**(`toTime`)๊ณผ **๊ณต๊ฐ„ ๋‹จ์œ„ ํ•ฉ์‚ฐ**(์—ฌ๋Ÿฌ ํŠธ์œˆ์„\n * ํ•œ ๋ฒˆ์— ์ ‘๊ธฐ). ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ… ๋ฃจํ”„๋Š” ํŠธ์œˆ๋ณ„์ด๋ผ ๋‘˜ ๋‹ค ๋ชป ํ–ˆ๋‹ค.\n *\n * ์ถ•์„ ๋‚˜๋ˆ ๋„ ํด๋“œ ๋น„์šฉ์ด ๊ฐ™๋‹ค๋Š” ์‹ค์ธก์ด ๊ทผ๊ฑฐ๋‹ค(`test/kpi-query-bench.test.ts`).\n */\n /**\n * ๋ช‡ ์ฐฝ๋งˆ๋‹ค ํ•œ ๋ฒˆ์€ **์ „๋ถ€** ๋งŒ๋“œ๋‚˜ โ€” ์‚ฌ๊ฑด ์—†์ด ๊ฐ’์ด ๋ฐ”๋€Œ๋Š” ์ž๋ฆฌ์— ๋Œ€ํ•œ ๊ทธ๋ฌผ.\n *\n * 25 ์ฐฝ์ด๋ฉด ๊ธฐ๋ณธ ์ฃผ๊ธฐ์—์„œ 5์ดˆ๋‹ค. ๋ณด์žฅ์ด ์•„๋‹ˆ๋ผ ๊ทธ๋ฌผ์ด๋‹ค(์œ„ `publishEntityData` ์ฃผ์„).\n */\n static FULL_BROADCAST_EVERY = 25\n /** ์ „๋ถ€ ๋งŒ๋“  ํšŸ์ˆ˜ โ€” ๋ฒ”์œ„๋ฅผ ์ขํžˆ์ง€ ๋ชปํ•œ ์ฐฝ์ด ์–ผ๋งˆ๋‚˜ ๋˜๋Š”์ง€ ๊ฐ’์œผ๋กœ ๋‚จ๋Š”๋‹ค. */\n static broadcastFullPasses = 0\n /**\n * ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์„ ๋งŒ๋“  ํšŸ์ˆ˜ ์ „๋ถ€ โ€” **์ „๋ถ€ ๋งŒ๋“  ํšŸ์ˆ˜์˜ ๋ถ„๋ชจ.**\n *\n * ๋ถ„์ž๋งŒ ๋‚ด๋ฉด ใ€Œ์ „๋ถ€ ๋งŒ๋“ค๊ธฐ 1,200ํšŒใ€๊ฐ€ ๋งŽ์€ ๊ฒƒ์ธ์ง€ ์ ์€ ๊ฒƒ์ธ์ง€ ์ฝ์„ ์ˆ˜ ์—†๋‹ค. ์ขํžˆ๊ธฐ๊ฐ€ ๋“ฃ๊ณ  ์žˆ์œผ๋ฉด\n * ์ด ๊ฐ’์˜ `1/FULL_BROADCAST_EVERY` ์ฏค์ด ์ „๋ถ€ ๋งŒ๋“  ํšŸ์ˆ˜์ด๊ณ , ๋‘ ๊ฐ’์ด ๋น„์Šทํ•˜๋ฉด ๋ฒ”์œ„๋ฅผ ๊ฑฐ์˜ ๋ชป ์ขํžŒ\n * ๊ฒƒ์ด๋‹ค(์›์ธ์€ ๋Œ€๊ฐœ ใ€Œ๋ชจ๋ฅธ๋‹คใ€๋กœ ๋–จ์–ด์ง€๋Š” ์‚ฌ๊ฑด์ด๋‹ค).\n */\n static broadcastPasses = 0\n\n /**\n * ์ด ์ฐฝ์— ๊ฑด๋“œ๋ฆฐ ๋ฌผํ’ˆ์„ ๋ชจ์€๋‹ค โ€” **๋งํ•  ์ˆ˜ ์—†์œผ๋ฉด ๋ฒ”์œ„๋ฅผ ๋ฒ„๋ฆฐ๋‹ค(์ „๋ถ€ ๋งŒ๋“ ๋‹ค).**\n *\n * `events` ๋ฅผ ์ฃผ์ง€ ์•Š์œผ๋ฉด ใ€Œ๋ฌด์—‡์ด ๋ฐ”๋€Œ์—ˆ๋Š”์ง€ ๋ชจ๋ฅธ๋‹คใ€๋‹ค(๊ตฌ์กฐ ์ „ํ™˜์ฒ˜๋Ÿผ ์ƒํƒœ ์ „๋ฐ˜์ด ๋‹ฌ๋ผ์ง€๋Š” ์ž๋ฆฌ).\n * ํ•œ ์ฐฝ์—์„œ ํ•œ ๋ฒˆ ใ€Œ๋ชจ๋ฅธ๋‹คใ€๊ฐ€ ๋˜๋ฉด ๊ทธ ์ฐฝ์€ ๋๊นŒ์ง€ ๋ชจ๋ฅด๋Š” ์ฑ„๋กœ ๋‘”๋‹ค โ€” ๋’ค์— ์˜จ ์‚ฌ๊ฑด์œผ๋กœ ๋ฒ”์œ„๋ฅผ\n * ๋˜์‚ด๋ฆฌ๋ฉด ์•ž ์‚ฌ๊ฑด์ด ๊ฑด๋“œ๋ฆฐ ๊ฒƒ์„ ๋น ๋œจ๋ฆฐ๋‹ค.\n */\n static markItemsDirty(inst: InstanceRuntime, events?: any[]): void {\n if (inst.dirtyItems === undefined) return // ์ด ์ฐฝ์€ ์ด๋ฏธ ใ€Œ๋ชจ๋ฅธ๋‹คใ€\n if (!events) {\n inst.dirtyItems = undefined\n return\n }\n for (const e of events) {\n const touched = touchedItemKeys(e)\n if (!touched) {\n inst.dirtyItems = undefined\n return\n }\n for (const epc of touched) inst.dirtyItems.add(epc)\n }\n }\n\n /** ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ… ๋ณ‘ํ•ฉ ์ฃผ๊ธฐ(ms) โ€” ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…๋ฅ  ์ƒํ•œ. ์ธ์ œ์ŠคํŠธ๊ฐ€ ์•„๋ฌด๋ฆฌ ๋นจ๋ผ๋„ ์ด ์ฃผ๊ธฐ๋กœ๋งŒ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…. */\n static BROADCAST_COALESCE_MS = 200\n /**\n * โ”€โ”€ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ… ์ฃผ๊ธฐ๋Š” **์žฌ ๋ณธ ๋น„์šฉ์— ๋งž์ถ˜๋‹ค** (2026-08-21 ์‹ค์ธก) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ํ•œ ๋ฒˆ์˜ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์€ ์ƒํƒœ ํฌ๊ธฐ์— ๋น„๋ก€ํ•œ๋‹ค(์‹ค์ธก: ๋ฌผํ’ˆ 2,400 ๊ฐœ์ธ ํŠธ์œˆ ํ•˜๋‚˜๊ฐ€ 4.5ms โ€” ์ƒํƒœ ํˆฌ์˜ 1.7ms,\n * payload ๋งŒ๋“ค๊ธฐ 1.8ms, ์‹œ๊ทธ๋‹ˆ์ฒ˜ 1.0ms). ํŠธ์œˆ์ด ์Šค๋ฌด ๊ฐœ๋ฉด 200ms ๋งˆ๋‹ค 90ms ๊ฐ€ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์— ๋“ค์–ด๊ฐ€๊ณ ,\n * ๊ทธ ์‹œ๊ฐ„์—๋Š” HTTP ๋„ ๊ตฌ๋…๋„ ์„œ์ง€ ๋ชปํ•œ๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ ํ•œ ์ฐฝ์—์„œ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์— ์“ด ์‹œ๊ฐ„์ด ์ฃผ๊ธฐ์˜ ์ผ์ • ๋ชซ์„ ๋„˜์œผ๋ฉด **์ฃผ๊ธฐ๋ฅผ ๋Š˜๋ฆฐ๋‹ค**. ํ™”๋ฉด์€ ์กฐ๊ธˆ ๋Šฆ๊ฒŒ\n * ๊ฐฑ์‹ ๋˜๊ณ (์ตœ์‹ -์ƒํƒœ ์ฑ„๋„์ด๋ผ ๊ฐ’์€ ๋งˆ์ง€๋ง‰ ๊ฒƒ ํ•˜๋‚˜๋ฟ์ด๋ฏ€๋กœ ๋‚ด์šฉ์€ ๊ฐ™๋‹ค), ๋Š˜๋ ธ๋‹ค๋Š” ๊ฒƒ์€ ๊ณ„๊ธฐํŒ์ด\n * ๋งํ•œ๋‹ค(`broadcastCoalesceMs`). ์—ฌ์œ ๊ฐ€ ์ƒ๊ธฐ๋ฉด ์›๋ž˜ ์ฃผ๊ธฐ๋กœ ๋˜๋Œ๋ฆฐ๋‹ค.\n *\n * ์ด๊ฒƒ์€ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ… ๋น„์šฉ์„ **์ค„์ด๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค** โ€” ๋น„์šฉ์„ ์ค„์ด๋Š” ๊ฒƒ์€ ๋ณ€๊ฒฝ๋ถ„๋งŒ ๋งŒ๋“œ๋Š” ์ผ์ด๊ณ  ๊ทธ๊ฒƒ์€ ๋ณ„\n * ์ž‘์—…์ด๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ๊ทธ๋•Œ๊นŒ์ง€ ํ˜ธ์ŠคํŠธ๊ฐ€ ๊ตถ์ง€ ์•Š๊ฒŒ ์ƒํ•œ์„ ๋‘”๋‹ค.\n */\n static BROADCAST_MAX_COALESCE_MS = 1000\n /** ์ฃผ๊ธฐ์˜ ๋ช‡ ๋ชซ๊นŒ์ง€ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์— ์จ๋„ ๋˜๋Š”๊ฐ€ โ€” ๋„˜์œผ๋ฉด ์ฃผ๊ธฐ๋ฅผ ๋Š˜๋ฆฐ๋‹ค(์ ˆ๋ฐ˜์ด๋ฉด ๋‚˜๋จธ์ง€ ์ ˆ๋ฐ˜์€ ๋‚จ๊ธด๋‹ค). */\n static BROADCAST_LOAD_RATIO = 0.3\n /** ์ง€๊ธˆ ์“ฐ๊ณ  ์žˆ๋Š” ์ฃผ๊ธฐ(ms) โ€” ๊ณ„๊ธฐํŒ์ด ์ด ๊ฐ’์„ ์ฝ๋Š”๋‹ค. ๋Š˜์–ด๋‚œ ์ฑ„๋กœ ์žˆ์œผ๋ฉด ๊ทธ๊ฒƒ์ด ์‚ฌ์‹ค์ด๋‹ค. */\n static broadcastPeriodMs = 200\n /** ์ฃผ๊ธฐ๋ฅผ ๋Š˜๋ฆฐ ํšŸ์ˆ˜ โ€” ์กฐ์šฉํžˆ ๋Šฆ์ถ”์ง€ ์•Š๋Š”๋‹ค. */\n static broadcastBackoffs = 0\n private static broadcastTimer?: any\n\n /** live ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ… coalescer โ€” dirty ์ธ live ์ธ์Šคํ„ด์Šค๋งŒ ์ฃผ๊ธฐ์ ์œผ๋กœ 1ํšŒ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…(entitySigs ๋กœ ๋ณ€๊ฒฝ ์—”ํ‹ฐํ‹ฐ๋งŒ). */\n private static ensureBroadcastCoalescer(): void {\n if (this.broadcastTimer) return\n this.broadcastPeriodMs = this.BROADCAST_COALESCE_MS\n this.broadcastTimer = setInterval(() => this.flushLiveBroadcasts(), this.broadcastPeriodMs)\n if (typeof this.broadcastTimer.unref === 'function') this.broadcastTimer.unref() // ์ข…๋ฃŒ ๋น„์ฐจ๋‹จ\n }\n\n /**\n * ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์— ์“ด ์‹œ๊ฐ„์„ ๋ณด๊ณ  ์ฃผ๊ธฐ๋ฅผ ์ •ํ•œ๋‹ค โ€” **๋Š˜๋ฆฌ๋Š” ๊ฒƒ๋„ ์ค„์ด๋Š” ๊ฒƒ๋„ ๊ฐ’์— ๊ทผ๊ฑฐํ•œ๋‹ค.**\n *\n * ํ•œ ๋ฒˆ์˜ flush ๊ฐ€ ์ฃผ๊ธฐ์˜ `BROADCAST_LOAD_RATIO` ๋ฅผ ๋„˜๊ฒŒ ์“ฐ๋ฉด ์ฃผ๊ธฐ๋ฅผ ๋‘ ๋ฐฐ๋กœ(์ƒํ•œ๊นŒ์ง€), ๊ทธ ๋ชซ์˜\n * ์ ˆ๋ฐ˜ ์•„๋ž˜๋กœ ๋‚ด๋ ค์˜ค๋ฉด ์ ˆ๋ฐ˜์œผ๋กœ(์›๋ž˜ ์ฃผ๊ธฐ๊นŒ์ง€) ๋˜๋Œ๋ฆฐ๋‹ค. ๋ฌธํ„ฑ์„ ๋‘ ๊ฐœ ๋‘๋Š” ์ด์œ ๋Š” ํ•˜๋‚˜๋ฉด ๊ฒฝ๊ณ„์—์„œ\n * ๋Š˜๋ฆฌ๊ณ  ์ค„์ด๊ธฐ๋ฅผ ๋ฐ˜๋ณตํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.\n */\n private static adjustBroadcastPeriod(flushMs: number): void {\n const period = this.broadcastPeriodMs\n const high = period * this.BROADCAST_LOAD_RATIO\n const low = high / 2\n let next = period\n if (flushMs > high && period < this.BROADCAST_MAX_COALESCE_MS) {\n next = Math.min(this.BROADCAST_MAX_COALESCE_MS, period * 2)\n this.broadcastBackoffs++\n twinWarn(\n `[twin-engine] broadcast period ${period}ms โ†’ ${next}ms โ€” one flush took ${Math.round(flushMs)}ms across ${Object.keys(this.instances).length} twin(s)`\n )\n } else if (flushMs < low && period > this.BROADCAST_COALESCE_MS) {\n next = Math.max(this.BROADCAST_COALESCE_MS, Math.round(period / 2))\n }\n if (next === period) return\n\n this.broadcastPeriodMs = next\n if (this.broadcastTimer) clearInterval(this.broadcastTimer)\n this.broadcastTimer = setInterval(() => this.flushLiveBroadcasts(), next)\n if (typeof this.broadcastTimer.unref === 'function') this.broadcastTimer.unref()\n }\n\n /**\n * dirty ์ธ์Šคํ„ด์Šค ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ… flush(์ฃผ๊ธฐ tick ๋˜๋Š” ๋ช…์‹œ ํ˜ธ์ถœ) โ€” **์‹œ๋ฎฌ๊ณผ ๋ผ์ด๋ธŒ ๋‘˜ ๋‹ค.**\n *\n * ์˜ˆ์ „์—๋Š” ๋ผ์ด๋ธŒ๋งŒ ๋ดค๋‹ค(`mode !== 'live'` ๋ฉด ๊ฑด๋„ˆ๋œ€). ์‹œ๋ฎฌ์€ delta ๋งˆ๋‹ค ๊ณง๋ฐ”๋กœ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…ํ–ˆ๊ณ , ๊ทธ๊ฒƒ์ด\n * ํ•œ tick ์—์„œ ์ˆ˜๋ฐฑ ๋ฒˆ ๋ฐ˜๋ณต๋˜๋ฉฐ ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ๋ง‰์•˜๋‹ค(์œ„ `start()` ์ฃผ์„์˜ 35์ดˆ ํ‹ฑ). ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์„ ๋ชจ์œผ๋Š”\n * ๊ทœ์œจ์€ ๋ชจ๋“œ์˜ ์„ฑ์งˆ์ด ์•„๋‹ˆ๋ผ **์ฑ„๋„์˜ ์„ฑ์งˆ**์ด๋‹ค โ€” ์ตœ์‹ -์ƒํƒœ ์ฑ„๋„์ด๋ฉด ์ค‘๊ฐ„ ์ƒํƒœ๋Š” ๋ณด๋‚ผ ๊ฐ’์ด ์—†๋‹ค.\n */\n static flushLiveBroadcasts(): void {\n const now = Date.now()\n const flushStart = performance.now()\n for (const inst of Object.values(this.instances)) {\n const isLive = inst.mode === 'live'\n /*\n * ์ฒ˜๋ฆฌ๋Ÿ‰ ๊ณ„์ธก(โ‘ฃ-1) โ€” ์ฐฝ(โ‰ฅ1s)๋งˆ๋‹ค ์œ ์ž…ยท๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…ยท์ €๋„๋ฅ  ๊ฐฑ์‹ . dirty ๋ฌด๊ด€(์œ ํœด๋ฉด 0์œผ๋กœ ์ˆ˜๋ ด).\n *\n * **๋‘ ๊ตฌ๋™์„ ํ•จ๊ป˜ ์„ผ๋‹ค** (2026-08-20). ์˜ˆ์ „์—๋Š” `isLive ? โ€ฆ : undefined` ๋กœ ์‹œ๋ฎฌ์„ ์ž˜๋ผ ๋ƒˆ๋‹ค.\n * ๊ทธ๋ž˜์„œ ๋„๋Š” ํŠธ์œˆ ๋Œ€๋ถ€๋ถ„์ด ์‹œ๋ฎฌ์ธ ์„œ๋ฒ„์—์„œ ใ€Œ์ดˆ๋‹น ๋ช‡ ํ–‰์„ ์“ฐ๋‚˜ใ€์— ๋‹ตํ•  ์ž๋ฆฌ๊ฐ€ ์—†์—ˆ๋‹ค โ€” ์ €๋„ ์“ฐ๊ธฐ๋ฅผ\n * ๋ฐฐ์น˜๋กœ ๊ณ ์นœ ๋’ค์—๋„ ๊ทธ ํšจ๊ณผ๋ฅผ ์ˆซ์ž๋กœ ๋ณผ ์ˆ˜ ์—†์—ˆ๋‹ค. ์œ ์ž…(`ingestRate`)์€ ์‹œ๋ฎฌ์—์„œ 0 ์œผ๋กœ ์ˆ˜๋ ดํ•˜๊ณ ,\n * ๊ทธ๊ฒƒ์ด ์‚ฌ์‹ค์ด๋‹ค(์›๋ณธ์—์„œ ๋ฐ›๋Š” ๊ฒƒ์ด ์—†๋‹ค).\n */\n const m = inst.metrics\n if (m) {\n const dt = (now - m._windowStartMs) / 1000\n if (dt >= 1) {\n m.ingestRate = Math.round(m._accIngest / dt)\n m.broadcastRate = Math.round((m._accBroadcast / dt) * 10) / 10\n m.journalRate = Math.round(m._accJournal / dt)\n m._accIngest = 0; m._accBroadcast = 0; m._accJournal = 0; m._windowStartMs = now\n }\n }\n if (!inst.dirty) continue\n inst.dirty = false\n /* ์ฃผ๊ธฐ๋งˆ๋‹ค ํ•œ ๋ฒˆ์€ ๋ฒ”์œ„๋ฅผ ๋ฒ„๋ฆฌ๊ณ  ์ „๋ถ€ ๋งŒ๋“ ๋‹ค โ€” ์‚ฌ๊ฑด ์—†์ด ๊ฐ’์ด ๋ฐ”๋€Œ๋Š” ์ž๋ฆฌ์— ๋Œ€ํ•œ ๊ทธ๋ฌผ. */\n const left = (inst.fullBroadcastCountdown ?? 0) - 1\n if (left <= 0) {\n inst.fullBroadcastDue = true\n inst.fullBroadcastCountdown = this.FULL_BROADCAST_EVERY\n } else {\n inst.fullBroadcastCountdown = left\n }\n // โ‘  ์—”ํ‹ฐํ‹ฐ data(tag) ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ… โ€” ๋ณด๋“œ ์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ ๋ Œ๋”.\n this.publishEntityData(inst)\n if (m) { m.broadcastTotal++; m._accBroadcast++ }\n /* โ‘ข ์ €๋„ ๋ฐฐ์น˜ ๊ธฐ๋ก โ€” **๋‘ ๊ตฌ๋™์ด ๊ฐ™์€ ๋ฌธ์„ ์“ด๋‹ค**(์‹œ๋ฎฌ๋„ ์—ฌ๊ธฐ์„œ ํ˜๋ฆฐ๋‹ค, ยง7.1). */\n this.flushJournal(inst)\n /* ์—ฌ๊ธฐ์„œ๋ถ€ํ„ฐ๋Š” **๋ผ์ด๋ธŒ๋งŒ**์ด๋‹ค: ์‹œ๋ฎฌ์˜ state ์ฑ„๋„์€ ์ž๊ธฐ ์ฝœ๋ฐฑ์ด ๋ธํƒ€๋งˆ๋‹ค ๋ณด๋‚ด๋ฏ€๋กœ(๋ฆฌ๋น„์ „์ด ์ปค๋„์˜\n ๊ฒƒ์ด๋‹ค) ์—ฌ๊ธฐ์„œ ๋˜ ๋ณด๋‚ด๋ฉด ๊ฐ™์€ ์‹ ํ˜ธ๊ฐ€ ๋‘ ๋ฒˆ ๊ฐ„๋‹ค. ์ €๋„์€ ์œ„์—์„œ ์ด๋ฏธ ๋‘ ๊ตฌ๋™ ๋ชซ์„ ํ˜๋ ธ๋‹ค. */\n if (!isLive) continue\n // โ‘ก State ์ฑ„๋„ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ… โ€” \"๋ฐ”๋€Œ์—ˆ๋‹ค\"๋Š” ๊ฐ€๋ฒผ์šด ์‹ ํ˜ธ๋งŒ(kind+revision). ๋งต ๊ตฌ๋…(subscribeTwinState)์€ ์ด ์‹ ํ˜ธ์—\n // scheduleRefresh(250ms ๋””๋ฐ”์šด์Šค)โ†’pollLive ๋กœ ๋˜๋ฌผ์–ด๋ด„. ์Šค๋ƒ…์ƒท(O(state))์€ ๋ณด๋Š” ์‚ฌ๋žŒ์ด ๋ฌผ์„ ๋•Œ๋งŒ 1ํšŒ ๊ณ„์‚ฐ.\n // (์—ฌ๊ธฐ์„œ payload ๋กœ ์Šค๋ƒ…์ƒท์„ ์‹ค์œผ๋ฉด ์•„๋ฌด๋„ ์•ˆ ์ฝ๋Š”๋ฐ tick ๋งˆ๋‹ค ํ†ต์งธ๋กœ ๋– ์„œ ์ˆœ์ˆ˜ ๋‚ญ๋น„ โ€” ์‹ ํ˜ธ๋งŒ ๋ณด๋‚ธ๋‹ค.)\n this.publishGuarded(\n 'twin-state',\n { twinState: { instanceId: inst.id, kind: 'delta', revision: inst.revision ?? 0 } },\n `twin-state:${inst.id}`\n )\n }\n /* ๊ฐ€๋™ ์ค‘์ธ ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•˜๋‚˜๋„ ์—†์œผ๋ฉด tick ์„ ๋ฉˆ์ถ˜๋‹ค(์˜ˆ์ „์—” ใ€Œ๋ผ์ด๋ธŒ๊ฐ€ ์—†์œผ๋ฉดใ€์ด์—ˆ๋Š”๋ฐ, ์ด์ œ\n ์‹œ๋ฎฌ๋„ ์ด flush ์— ๊ธฐ๋Œ€๋ฏ€๋กœ ๊ทธ ์กฐ๊ฑด์ด๋ฉด ์‹œ๋ฎฌ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์ด ๋ฉˆ์ถ˜ ์ฑ„ ๋‚จ๋Š”๋‹ค). */\n if (!Object.keys(this.instances).length && this.broadcastTimer) {\n clearInterval(this.broadcastTimer)\n this.broadcastTimer = undefined\n this.broadcastPeriodMs = this.BROADCAST_COALESCE_MS\n return\n }\n /* ์ด๋ฒˆ flush ๊ฐ€ ์–ผ๋งˆ๋ฅผ ์ผ๋Š”์ง€๋กœ ๋‹ค์Œ ์ฃผ๊ธฐ๋ฅผ ์ •ํ•œ๋‹ค โ€” ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์ด ๋ฃจํ”„๋ฅผ ๋‹ค ์“ฐ์ง€ ๋ชปํ•˜๊ฒŒ. */\n this.adjustBroadcastPeriod(performance.now() - flushStart)\n }\n\n /**\n * ์ €๋„ ํ–‰ ํ•œ ์ค„ โ€” **๊ธฐ๋ก ๊ฒฝ๋กœ๊ฐ€ ๋‘˜์ด๋ผ(๋ผ์ด๋ธŒ ๋ฒŒํฌยท์‹ฌ ๋‹จ๊ฑด) ํ–‰ ๋ชจ์–‘์€ ๋ฐ˜๋“œ์‹œ ํ•œ ๊ณณ์—์„œ ๋งŒ๋“ ๋‹ค.**\n * ๋‘ ๊ณณ์— ๊ฐ์ž ์ ์œผ๋ฉด ์Šน๊ฒฉ ๊ฒ€์ƒ‰ ํ‚ค๊ฐ€ ํ•œ์ชฝ์—๋งŒ ์ฑ„์›Œ์ง€๊ณ , ๋ฐ˜์ฏค ๋นˆ ์ƒ‰์ธ์€ \"์ €๋„์—๋Š” ์žˆ๋Š”๋ฐ\n * ๊ฒ€์ƒ‰์œผ๋กœ๋Š” ์•ˆ ๋‚˜์˜ค๋Š” ์ด๋ฒคํŠธ\" ๋ฅผ ๋งŒ๋“ ๋‹ค โ€” ์ €๋„์—์„œ ๊ฐ€์žฅ ๋‚˜์œ ์ข…๋ฅ˜์˜ ๊ฒฐํ•จ์ด๋‹ค.\n */\n /** ์ €๋„์˜ ์‹œ๊ฐ ์ถ•์€ ๋‚ ์งœ๋‹ค โ€” ๋ชป ์ฝ๋Š” ๊ฐ’์€ ๋น„์šด๋‹ค(0 ์ด๋‚˜ ์ง€๊ธˆ์œผ๋กœ ์œ„์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค). */\n private static toEventTimeValue(v: any): Date | undefined {\n if (v instanceof Date) return v\n const t = typeof v === 'string' ? Date.parse(v) : NaN\n return Number.isNaN(t) ? undefined : new Date(t)\n }\n\n private static journalRow(repo: any, domainId: string, instanceId: string, e: any, revision: number, structureRev?: number) {\n return repo.create({\n domain: { id: domainId } as any,\n instanceId,\n eventType: e?.eventType,\n /* ์ปค๋„์ด ์ปค๋งจ๋“œ์—์„œ ์ด์–ด ์ค€ ๊ฐ’ โ€” ์ด๊ฒƒ์ด ๊ฐ์‚ฌ ๊ธฐ๋ก๊ณผ ์ €๋„์„ ์ž‡๋Š” ๋‹ค๋ฆฌ๋‹ค. */\n correlationId: e?.correlationId,\n revision,\n /* **์ด ์‚ฌ์‹ค์ด ์ผ์–ด๋‚œ ๊ณต์žฅ**์„ ํ•จ๊ป˜ ์ฐ๋Š”๋‹ค โ€” ์ด๊ฒƒ์ด ์—†์œผ๋ฉด ๋‚˜์ค‘์— ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ์—ˆ์„ ๋•Œ ์ด ํ–‰์„\n ์ƒˆ ๊ณต์žฅ์— ๋Œ€๊ณ  ์ ‘๊ฒŒ ๋˜๊ณ , ๊ทธ๋•Œ ์—†๋˜ ์„ค๋น„์—์„œ ์ผ์ด ์žˆ์—ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค. */\n ...(structureRev === undefined ? {} : { structureRev }),\n /* ์ปค๋„์€ ISO ๋ฌธ์ž์—ด์„ ์ค€๋‹ค. ์ปฌ๋Ÿผ์€ ๋‚ ์งœ๋‹ค โ€” **์—ฌ๊ธฐ์„œ ์˜ฎ๊ธด๋‹ค.** ๋ฌธ์ž์—ด์„ ๊ทธ๋Œ€๋กœ ๋„ฃ์œผ๋ฉด\n ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ์ œ ํ˜•์‹์œผ๋กœ ์ •๊ทœํ™”ํ•˜์ง€ ์•Š์•„, ๋‚˜์ค‘์— ๋‚ ์งœ๋กœ ๊ฑฐ๋Š” ์งˆ์˜์— ์•ˆ ๊ฑธ๋ฆฐ๋‹ค. */\n eventTime: this.toEventTimeValue(e?.eventTime),\n ...twinEventKeys(e),\n payload: e\n })\n }\n\n /**\n * ์ด ํŠธ์œˆ์ด ์ง€๊ธˆ ์–ด๋А ๊ตฌ์กฐ๋กœ ๋„๋Š”๊ฐ€ โ€” ์ด๋ฒคํŠธ์— ์ฐ์„ ๋ฒˆํ˜ธ. ํ•œ ๋ฒˆ ์ฝ๊ณ  ์บ์‹œํ•œ๋‹ค(์“ฐ๊ธฐ๋งˆ๋‹ค ์กฐํšŒ ๊ธˆ์ง€).\n *\n * ์—†์œผ๋ฉด `undefined` ๋‹ค โ€” 0 ์ด ์•„๋‹ˆ๋‹ค. ๊ตฌ์กฐ ๋ฆฌ๋น„์ „์ด ์ƒ๊ธฐ๊ธฐ ์ „์— ๋งŒ๋“ค์–ด์ง„ ํŠธ์œˆ์€ ์•„์ง ๋ฆฌ๋น„์ „์ด\n * ์—†๊ณ , ๊ทธ ์‚ฌ์‹ค์„ 0 ์ด๋ผ๋Š” **์œ ํšจํ•ด ๋ณด์ด๋Š” ๋ฒˆํ˜ธ**๋กœ ์œ„์žฅํ•˜๋ฉด ์•ˆ ๋œ๋‹ค.\n */\n /** ๊ตฌ์กฐ ๋ฆฌ๋น„์ „ ์บ์‹œ โ€” `null` ์€ **์—†๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ๋‹ค**๋Š” ๋œป์ด๋‹ค(๋ชจ๋ฆ„๊ณผ ๊ตฌ๋ณ„ํ•œ๋‹ค, ยง7.1). */\n private static structureRevCache: Record<string, number | null> = {}\n static async structureRevOf(domainId: string, instanceId: string): Promise<number | undefined> {\n const key = runtimeKey(domainId, instanceId)\n const cached = this.structureRevCache[key]\n /*\n * **์—†๋‹ค๋Š” ๊ฒƒ๋„ ๋‹ต์ด๋‹ค** โ€” ์˜ˆ์ „์—๋Š” ์ฐพ์ง€ ๋ชปํ•˜๋ฉด ์บ์‹œํ•˜์ง€ ์•Š์•˜๋‹ค(`if (latest) โ€ฆ`). ๊ทธ๋ž˜์„œ ๊ตฌ์กฐ ํ–‰์ด\n * ์—†๋Š” ํŠธ์œˆ์€ **๋ถ€๋ฅผ ๋•Œ๋งˆ๋‹ค SELECT** ํ–ˆ๊ณ , ๊ทธ ๊ฒฝ๋กœ๊ฐ€ ๋ธํƒ€๋งˆ๋‹ค ๋ถˆ๋ฆฌ๊ณ  ์žˆ์—ˆ๋‹ค(ยง7.1). `null` ๋กœ ๊ธฐ์–ตํ•œ๋‹ค.\n */\n if (cached !== undefined) return cached === null ? undefined : cached\n const latest = await getRepository(TwinStructure).findOne({ where: { domain: { id: domainId }, instanceId }, order: { rev: 'DESC' } })\n this.structureRevCache[key] = latest ? latest.rev : null\n return latest?.rev\n }\n\n /** ๊ณ„๊ธฐ ํ•œ ๋ฒŒ โ€” **๋‘ ๊ตฌ๋™์ด ๊ฐ™์€ ๊ฒƒ์„ ๋“ ๋‹ค**(ํ•œ์ชฝ๋งŒ ๋“ค๋ฉด ๊ทธ ๊ตฌ๋™์€ ๋ฌผ์–ด๋„ ๋‹ต์ด ์—†๋‹ค). */\n private static newMetrics(): TwinMetrics {\n return { ingestedTotal: 0, broadcastTotal: 0, journaledTotal: 0, ingestRate: 0, broadcastRate: 0, journalRate: 0, backlog: 0, _accIngest: 0, _accBroadcast: 0, _accJournal: 0, _windowStartMs: Date.now() }\n }\n\n /**\n * ๋ชจ์•„ ๋‘” ์ €๋„์„ **ํ•œ ๋ฒˆ์—** ์“ด๋‹ค โ€” ๋‘ ๊ตฌ๋™์ด ๊ฐ™์€ ๋ฌธ์„ ์“ด๋‹ค (ยง7.1).\n *\n * โ”€โ”€ ์™œ ํ•œ ํ•จ์ˆ˜์ธ๊ฐ€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์“ฐ๋Š” ์ž๋ฆฌ๊ฐ€ ๋‘˜์ด๋ฉด(์ฃผ๊ธฐ flush ยท ์ •์ง€) ํ•œ์ชฝ๋งŒ ๊ณ ์ณ์ง€๊ณ , ๊ทธ ์–ด๊ธ‹๋‚จ์€ **์‚ฌ์‹ค์ด ์กฐ์šฉํžˆ ์‚ฌ๋ผ์ง€๋Š”**\n * ๋ชจ์–‘์œผ๋กœ ๋‚˜ํƒ€๋‚œ๋‹ค. ๊ทธ๋ž˜์„œ ํ˜๋ฆฌ๋Š” ๊ทœ์น™์„ ์—ฌ๊ธฐ ํ•œ ๊ณณ์— ๋‘”๋‹ค.\n *\n * โ”€โ”€ ๋ฆฌ๋น„์ „์„ ๋ˆ„๊ฐ€ ๋งค๊ธฐ๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ยท ๋ผ์ด๋ธŒ โ€” ์›์ฒœ์€ ๋ฆฌ๋น„์ „์„ ์ฃผ์ง€ ์•Š์œผ๋ฏ€๋กœ **ํ˜ธ์ŠคํŠธ๊ฐ€** ์ด์–ด ๋ถ™์ธ๋‹ค(์ €๋„ high-water ์—์„œ ์‹œ๋“œ).\n * ยท ์‹œ๋ฎฌ โ€” **์ปค๋„์˜ ๋ฆฌ๋น„์ „**์ด ์‹ค๋ ค ์˜จ๋‹ค(์ €๋„์ด ๊ทธ๊ฒƒ์œผ๋กœ ์ ‘ํžˆ๊ณ  ์‹œ๊ฐ„์—ฌํ–‰์ด ๊ทธ๊ฒƒ์„ ๋”›๋Š”๋‹ค).\n * ๊ทธ๋ž˜์„œ ๋ฒ„ํผ๋Š” ๋‘ ๋ชจ์–‘์„ ํ•จ๊ป˜ ๋“ ๋‹ค: ๋ด‰ํˆฌ๋งŒ ์žˆ์œผ๋ฉด ๋ผ์ด๋ธŒ, `{ event, revision }` ์ด๋ฉด ์‹œ๋ฎฌ์ด๋‹ค.\n */\n private static flushJournal(inst: InstanceRuntime): Promise<void> {\n const batch = inst.pendingJournal\n if (!batch?.length) return Promise.resolve()\n inst.pendingJournal = []\n const m = inst.metrics\n /* ์“ด ๊ฑด์ˆ˜๋Š” ๋ˆ„์ ์—, **์ง€๊ธˆ ๋‚จ์€ ๊ฒƒ**์€ backlog ์—. ์ด ์ž๋ฆฌ์—์„œ ๋ฐฐ์น˜ ํฌ๊ธฐ๋ฅผ backlog ๋กœ ์ ์œผ๋ฉด\n ์ •์ƒ์ ์ธ ๋ฐฐ์น˜ ์ €์žฅ์ด ํ™”๋ฉด์—์„œ ๊ฒฝ๊ณ ๋กœ ๋ณด์ธ๋‹ค(2026-08-21 ๊ต์ •). */\n if (m) { m.journaledTotal += batch.length; m._accJournal += batch.length; m.backlog = inst.pendingJournal?.length ?? 0 }\n\n /* ์‹œ๋ฎฌ์€ ์ž๊ธฐ ๋ฆฌ๋น„์ „์„ ๋“ค๊ณ  ์˜จ๋‹ค โ€” ๊ทธ๋Œ€๋กœ ์“ด๋‹ค. ๋ผ์ด๋ธŒ๋Š” ์—ฌ๊ธฐ์„œ ์ด์–ด ๋ถ™์ธ๋‹ค. */\n const carried = batch.filter((b: any) => b && typeof b === 'object' && 'event' in b && typeof b.revision === 'number')\n const plain = batch.filter((b: any) => !(b && typeof b === 'object' && 'event' in b && typeof b.revision === 'number'))\n\n const tJournal = performance.now()\n const done = () => recordPhase(inst.load ?? (inst.load = newLoadMeter()), 'journal', performance.now() - tJournal)\n const jobs: Promise<void>[] = []\n\n if (carried.length) jobs.push(this.persistCarried(inst.domainId, inst.id, carried))\n if (plain.length && inst.revision != null) {\n const start = inst.revision\n inst.revision = start + plain.length\n jobs.push(this.persistBatch(inst.domainId, inst.id, plain, start))\n }\n if (!jobs.length) return Promise.resolve()\n /*\n * **์•ฝ์†์„ ๋Œ๋ ค์ค€๋‹ค** โ€” ์ฃผ๊ธฐ flush ๋Š” ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š์ง€๋งŒ(ํ•ซ ๊ฒฝ๋กœ) **์ •์ง€๋Š” ๊ธฐ๋‹ค๋ ค์•ผ ํ•œ๋‹ค.** ๊ธฐ๋‹ค๋ฆฌ์ง€\n * ์•Š์œผ๋ฉด ๊ณง๋ฐ”๋กœ ์ด์–ด์ง€๋Š” ์ €๋„ ์žฌ์ƒ์ด ์•„์ง ์•ˆ ์“ฐ์ธ ๊ตฌ๊ฐ„์„ ๋ชป ๋ณด๊ณ , ์›œ์Šคํƒ€ํŠธ๊ฐ€ ใ€Œ์—†๋˜ ์ผใ€๋กœ ์‹œ์ž‘ํ•œ๋‹ค\n * (์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ๊นจ์กŒ๋‹ค: ํ™•๋ณด๋ถ„์„ ๋“  ์˜ค๋”๊ฐ€ ๋˜์‚ด์•„๋‚˜์ง€ ๋ชปํ–ˆ๋‹ค).\n */\n const written = carried.length + plain.length\n return Promise.all(jobs)\n .then(() => {\n done()\n /*\n * **์ ํžŒ ๋’ค์— ์ ๋Š”๋‹ค** โ€” ์‹คํŒจํ•œ ๋ฐฐ์น˜๋ฅผ ใ€Œ๋‚จ์•˜๋‹คใ€๊ณ  ์„ธ๋ฉด ์ถ”์ด๊ฐ€ ์—†๋Š” ์‚ฌ์‹ค์„ ์žˆ๋‹ค๊ณ  ๋งํ•œ๋‹ค.\n * ์ฐฝ(10๋ถ„)์— ์Œ“์ด๋ฏ€๋กœ ์žฌ๊ธฐ๋™ ๋’ค์—๋„ ใ€Œ์ง€๋‚œ ์—ฌ์„ฏ ์‹œ๊ฐ„ ์–ผ๋งˆ๋‚˜ ์ ์—ˆ๋‚˜ใ€๋ฅผ ๋‹ตํ•  ์ˆ˜ ์žˆ๋‹ค.\n */\n this.recordJournalWrite(inst.domainId, inst.id, written)\n })\n .catch(err => twinError('twin journal flush fail', err))\n }\n\n /**\n * ์ปค๋„์ด ๋งค๊ธด ๋ฆฌ๋น„์ „์„ ๊ทธ๋Œ€๋กœ ๋“ค๊ณ  ๋ฒŒํฌ ์ €์žฅ โ€” ์‹œ๋ฎฌ ๊ฒฝ๋กœ.\n *\n * ์˜ˆ์ „์—๋Š” ์ด ๊ฒฝ๋กœ๊ฐ€ **๋ธํƒ€๋งˆ๋‹ค ํ•œ ํ–‰์”ฉ** ์ €์žฅํ–ˆ๋‹ค(๊ทธ๋ฆฌ๊ณ  ํ–‰๋งˆ๋‹ค ๊ตฌ์กฐ ๋ฆฌ๋น„์ „์„ ๋ฌผ์—ˆ๋‹ค). ๊ทœ๋ชจ์—์„œ ๊ทธ๊ฒƒ์ด\n * ํ˜ธ์ŠคํŠธ๋ฅผ ๋จน์—ˆ๋‹ค(ยง7.1 ์‹ค์ธก). ์—ฌ๊ธฐ์„œ ๊ตฌ์กฐ ๋ฆฌ๋น„์ „์€ **ํ•œ ๋ฒˆ๋งŒ** ๋ฌป๋Š”๋‹ค.\n */\n static async persistCarried(domainId: string, instanceId: string, items: { event: any; revision: number }[]): Promise<void> {\n const repo = getRepository(TwinEvent)\n const structureRev = await this.structureRevOf(domainId, instanceId)\n const rows = items.map(it => this.journalRow(repo, domainId, instanceId, it.event, it.revision, structureRev))\n await this.insertRows(repo, rows)\n }\n\n /**\n * ์ €๋„ ํ–‰์„ ๋„ฃ๋Š”๋‹ค โ€” **๋„ฃ๊ธฐ๋งŒ ํ•œ๋‹ค**(2026-08-20).\n *\n * ์˜ˆ์ „์—๋Š” `save()` ์˜€๋‹ค. ๊ทธ๋Ÿฐ๋ฐ `save` ๋Š” ๋„ฃ์€ ๋’ค ์ƒ์„ฑ ์ปฌ๋Ÿผ์„ ์ฝ์œผ๋ ค๊ณ  **ํ–‰๋งˆ๋‹ค SELECT ๋ฅผ ํ•œ ๋ฒˆ ๋”**\n * ํ•œ๋‹ค(์‹œํ—˜ ๋กœ๊ทธ์—์„œ ๊ทธ ์งˆ์˜๊ฐ€ ๊ทธ๋Œ€๋กœ ๋ณด์˜€๋‹ค: `SELECT โ€ฆ FROM twin_events WHERE id = ?`). ์ €๋„์€\n * append-only ์ด๊ณ  ๋ถ€๋ฅด๋Š” ์ชฝ์€ ๋Œ๋ ค๋ฐ›์€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์“ฐ์ง€ ์•Š์œผ๋ฏ€๋กœ ๊ทธ ์™•๋ณต์ด ์ˆœ์ˆ˜ ๋‚ญ๋น„๋‹ค.\n *\n * ๋ฌถ์Œ์€ **๋‚˜๋ˆ ์„œ** ๋„ฃ๋Š”๋‹ค: ํ•œ ๋ฌธ์— ์—ด์ด ์—ด๋‹ค์„ฏ์ธ ํ–‰์„ ์ˆ˜์ฒœ ๊ฐœ ์‹ค์œผ๋ฉด ๋“œ๋ผ์ด๋ฒ„์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ํ•œ๊ณ„์—\n * ๊ฑธ๋ฆฐ๋‹ค(pg ๋Š” 65,535๊ฐœ). 500ํ–‰์ด๋ฉด ์–ด๋А ๋“œ๋ผ์ด๋ฒ„์—์„œ๋„ ์•ˆ์ „ํ•˜๋‹ค.\n */\n private static async insertRows(repo: any, rows: any[]): Promise<void> {\n const CHUNK = 500\n /*\n * โ”€โ”€ ํ•œ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ๊ฐ์‹ธ ๋ณด์•˜๊ณ , **๋˜๋Œ๋ ธ๋‹ค** (2026-08-22 ์‹ค์ธก) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ใ€Œ์ฒญํฌ๋งˆ๋‹ค ์ปค๋ฐ‹ํ•˜๋ฉด fsync ๊ฐ€ ๊ทธ๋งŒํผ ๋Š˜์–ด๋‚œ๋‹คใ€๋Š” ์ด์œ ๋กœ ์ „์ฒด๋ฅผ ํ•œ ํŠธ๋žœ์žญ์…˜์— ๊ฐ์ŒŒ๋‹ค. ์“ฐ๊ธฐ ์ž์ฒด๋Š”\n * ์‹ค์ œ๋กœ ๋นจ๋ผ์กŒ๋‹ค โ€” ๋А๋ฆฐ ์งˆ์˜ ๋ชฉ๋ก์—์„œ ์ด INSERT ๊ฐ€ ์‚ฌ๋ผ์กŒ๋‹ค. **๊ทธ๋Ÿฐ๋ฐ ์„œ๋ฒ„๊ฐ€ ๋” ๋А๋ ค์กŒ๋‹ค.**\n *\n * ๊ฐ์‹ธ๊ธฐ ์ „ ๋А๋ฆฐ ์งˆ์˜ ์ตœ๋Œ€ 32.3์ดˆ ยท ROLLBACK ์—†์Œ\n * ๊ฐ์‹ผ ๋’ค ๋А๋ฆฐ ์งˆ์˜ ์ตœ๋Œ€ 50.2์ดˆ ยท ROLLBACK 36.3์ดˆ ๋“ฑ์žฅ\n *\n * ๊ธฐ์ „์€ ๋“œ๋ผ์ด๋ฒ„๋‹ค. TypeORM ์˜ sqlite ๋“œ๋ผ์ด๋ฒ„๋Š” ์—ฐ๊ฒฐ์„ **ํ•˜๋‚˜**๋งŒ ๋“ ๋‹ค(ํ’€ ์—†์Œ). ํŠธ๋žœ์žญ์…˜์ด\n * ์—ด๋ ค ์žˆ๋Š” ๋™์•ˆ ๊ทธ ์œ ์ผํ•œ ์—ฐ๊ฒฐ์€ ์ด ๋ฌถ์Œ์˜ ๊ฒƒ์ด๋ฏ€๋กœ, **๋ฌถ์Œ์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ์•ฑ์˜ ๋ชจ๋“  ์งˆ์˜๊ฐ€\n * ๊ธฐ๋‹ค๋ฆฐ๋‹ค.** ์ฒญํฌ๋งˆ๋‹ค ์ปค๋ฐ‹ํ•˜๋ฉด ๊ทธ ์‚ฌ์ด์— ๋‹ค๋ฅธ ์งˆ์˜๊ฐ€ ๋ผ์–ด๋“ค ์ž๋ฆฌ๊ฐ€ ์ƒ๊ธด๋‹ค โ€” fsync ๋ฅผ ๋” ์น˜๋ฅด๋Š”\n * ๋Œ€์‹  **๋จธ๋ฆฌ ๋ง‰ํž˜์ด ์งง์•„์ง„๋‹ค.**\n *\n * ์ฆ‰ ์—ฌ๊ธฐ์„œ๋Š” ใ€Œ์ปค๋ฐ‹ ์ˆ˜๋ฅผ ์ค„์ด๋Š” ๊ฒƒใ€์ด ๋ชฉ์ ์ด ์•„๋‹ˆ๋‹ค. ๋ชฉ์ ์€ **ํ•œ ๋ฒˆ์— ์˜ค๋ž˜ ๋ถ™์žก์ง€ ์•Š๋Š” ๊ฒƒ**์ด๋‹ค.\n * ์ €๋„ ๋ฌถ์Œ์˜ ์›์ž์„ฑ์€ ๊ทธ ๋Œ€๊ฐ€๋ฅผ ์น˜๋ฅผ ๋งŒํผ์˜ ๊ฐ’์ด ์•„๋‹ˆ๋‹ค: ์ €๋„์€ append-only ์ด๊ณ  ๋ฆฌ๋น„์ „์ด\n * ์ด์–ด์ง€๋ฏ€๋กœ, ์ ˆ๋ฐ˜๋งŒ ๋“ค์–ด๊ฐ„ ๋ฌถ์Œ์€ ๋‹ค์Œ ๊ธฐ๋™์˜ replay ๊ฐ€ ๊ทธ ์ง€์ ๋ถ€ํ„ฐ ์ด์–ด๋ฐ›๋Š”๋‹ค.\n *\n * ์—ฐ๊ฒฐ ํ’€์ด ์žˆ๋Š” ๋“œ๋ผ์ด๋ฒ„(postgresยทmysql)์—์„œ๋Š” ํŒ๋‹จ์ด ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ๋‹ค โ€” ๊ทธ๋•Œ๋Š” ์ด ์ฃผ์„์„ ๊ทผ๊ฑฐ๋กœ\n * ๋‹ค์‹œ ์žฌ๊ณ  ์ •ํ•˜๋ผ. **๋“œ๋ผ์ด๋ฒ„๋งˆ๋‹ค ๋‹ค๋ฅธ ๊ฒฐ๋ก ์ด ๋‚˜๋Š” ์ž๋ฆฌ๋‹ค.**\n */\n for (let i = 0; i < rows.length; i += CHUNK) await repo.insert(rows.slice(i, i + CHUNK))\n }\n\n /** live ์ €๋„ ๋ฐฐ์น˜ ๊ธฐ๋ก โ€” ๋ชจ์•„๋‘” CanonicalEnvelope ๋“ค์— startRevision+1.. ์„ ๋ถ€์—ฌํ•ด ๋ฒŒํฌ ์ €์žฅ(coalescer tick ๋‹น 1ํšŒ). */\n static async persistBatch(domainId: string, instanceId: string, envelopes: any[], startRevision: number): Promise<void> {\n const repo = getRepository(TwinEvent)\n const structureRev = await this.structureRevOf(domainId, instanceId)\n const rows = envelopes.map((e, i) => this.journalRow(repo, domainId, instanceId, e, startRevision + i + 1, structureRev))\n await this.insertRows(repo, rows)\n }\n\n /** ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ upsert(๋„๋ฉ”์ธ+instanceId ์œ ๋‹ˆํฌ). status ์ธ์ž๋กœ provision(stopped)/start(running) ๊ณต์šฉ. */\n static async register(\n domainId: string,\n instanceId: string,\n kind: string,\n model: TwinModelDef,\n status: 'running' | 'stopped' = 'running',\n restartPolicy?: RestartPolicy,\n origin?: any,\n /*\n * ์‚ฌ๋žŒ์ด ๋ถ€๋ฅด๋Š” ์ด๋ฆ„๊ณผ **๋ˆ„๊ฐ€ ํ–ˆ๋‚˜** โ€” ์—…๋ฌดํ‚ค๋ฅผ ๋‚˜๋ˆ  ๋‘” ๋Œ€๊ฐ€๋กœ ์ด๋ฆ„์„ ํ•จ๊ป˜ ์‹ค์–ด์•ผ ํ•œ๋‹ค.\n * ์‚ฌ๋žŒ ์—†๋Š” ๊ฒฝ๋กœ(๋ถ€ํŒ… ์ž๋™ ํ”„๋กœ๋น„์ €๋‹ยท๋ณต๊ตฌ)๋Š” `actor` ๋ฅผ ์ฃผ์ง€ ์•Š๋Š”๋‹ค โ€” ์•„๋ฌด ์‚ฌ์šฉ์ž๋ฅผ ์ ์œผ๋ฉด\n * ๊ฐ์‚ฌ ๊ธฐ๋ก์ด ๊ฑฐ์ง“์ด ๋œ๋‹ค.\n */\n meta?: { name?: string; description?: string; actor?: { id: string } }\n ): Promise<void> {\n const repo = getRepository(TwinInstance)\n const existing = await repo.findOne({ where: { domain: { id: domainId }, instanceId } })\n await repo.save(\n repo.create({\n ...(existing ?? {}),\n domain: { id: domainId } as any,\n instanceId,\n kind,\n model,\n // ์ธ์Šคํ„ด์Šคโ†”๊ณต๊ฐ„ 1๊ธ‰ ๋งํฌ(space #3) โ€” model.spaceId/areaId ๋ฅผ ์ปฌ๋Ÿผ์œผ๋กœ ์Šน๊ฒฉ(dual-write). model JSON ๋„ ์œ ์ง€(์ปค๋„ยท๋ณต๊ตฌ์šฉ).\n spaceId: (model as any)?.spaceId ?? existing?.spaceId,\n areaId: (model as any)?.areaId ?? existing?.areaId,\n /* ์žฌ๊ธฐ๋™ ์ •์ฑ…(ADR-0029 ยง2) โ€” ๋ช…์‹œ๊ฐ’ ์šฐ์„ , ์—†์œผ๋ฉด ๊ธฐ์กด๊ฐ’ ๋ณด์กด(์žฌํ”„๋กœ๋น„์ „์ด ์„ ์–ธ์„ ์ง€์šฐ์ง€ ์•Š๊ฒŒ).\n **๋‘˜ ๋‹ค ์—†์œผ๋ฉด ์˜ค๋ฅ˜๋ฅผ ๋‚ธ๋‹ค**: ์˜ˆ์ „์—๋Š” ์—ฌ๊ธฐ์„œ ๊ธฐ๋ณธ๊ฐ’์„ ๊ฐ์ธํ–ˆ๋Š”๋ฐ, ๊ทธ ๊ธฐ๋ณธ๊ฐ’์ด ใ€Œ์ €๋„ ์ดˆ๊ธฐํ™”ใ€๋ผ์„œ\n ์„ ์–ธ์„ ๋น ๋œจ๋ฆฐ ํ”„๋กœ๋น„์ €๋‹์ด ์กฐ์šฉํžˆ ์ด๋ ฅ์„ ์ง€์šฐ๋Š” ํŠธ์œˆ์„ ๋งŒ๋“ค์—ˆ๋‹ค. ์„ ์–ธ์€ ๋ถ€๋ฅด๋Š” ์ชฝ์˜ ๋ชซ์ด๋‹ค. */\n restartPolicy:\n restartPolicy ??\n readRestartPolicy(\n existing?.restartPolicy,\n `register(\"${instanceId}\") did not declare a restart policy and the stored row has none`\n ),\n /* ์šฉ๋„๋„ ๊ฐ์ธํ•œ๋‹ค. ๋ฒค์น˜๋กœ ๋’ค์ง‘๋Š” ๊ฒƒ์€ `setPurpose` ํ•˜๋‚˜๋ฟ์ด๋ฏ€๋กœ ๊ธฐ์กด๊ฐ’์„ ๋ฐ˜๋“œ์‹œ ๋ณด์กดํ•œ๋‹ค\n โ€” ์—ฌ๊ธฐ์„œ ๋ฎ์œผ๋ฉด ์žฌํ”„๋กœ๋น„์ „์ด ๋ฒค์น˜ ์‚ฌ๋ณธ์„ ์šด์˜ ํŠธ์œˆ์œผ๋กœ ๋˜๋Œ๋ฆฐ๋‹ค. */\n purpose: existing?.purpose ?? 'operational',\n /* **๋‹ค์‹œ ์ฝ๋Š” ๋ฐฉ๋ฒ•**์„ ๊ฐ์ธํ•œ๋‹ค. ๋ช…์‹œ๊ฐ’ ์šฐ์„ , ์—†์œผ๋ฉด ๊ธฐ์กด๊ฐ’ ๋ณด์กด โ€” ์›์ฒœ์„ ๋ชจ๋ฅด๋Š” ํ˜ธ์ถœ์ด\n ํ•œ ๋ฒˆ ์ง€๋‚˜๊ฐ€๋ฉด์„œ ์ด๋ฏธ ์•Œ๋˜ ๊ฒƒ์„ ์ง€์›Œ ๋ฒ„๋ฆฌ๋ฉด, ๊ทธ ํŠธ์œˆ์€ ๋‹ค์‹œ ์ฝ์„ ์ˆ˜ ์—†๋Š” ํŠธ์œˆ์ด ๋œ๋‹ค. */\n origin: origin ?? existing?.origin ?? null,\n /* ์ด๋ฆ„์€ **๋ฎ์ง€ ์•Š๊ณ  ์ฑ„์šด๋‹ค** โ€” ์‚ฌ์šฉ์ž๊ฐ€ ๊ณ ์นœ ์ด๋ฆ„์„ ์žฌํ”„๋กœ๋น„์ „์ด ๋˜๋Œ๋ฆฌ๋ฉด ์•ˆ ๋œ๋‹ค. */\n name: existing?.name ?? meta?.name ?? null,\n description: existing?.description ?? meta?.description ?? null,\n /* ๋งŒ๋“  ์‚ฌ๋žŒ์€ ์ฒ˜์Œ ํ•œ ๋ฒˆ๋งŒ. ๊ณ ์นœ ์‚ฌ๋žŒ์€ ์‚ฌ๋žŒ์ด ํ•œ ๊ฒฝ์šฐ์—๋งŒ ๊ฐฑ์‹ ํ•œ๋‹ค. */\n ...(existing ? {} : meta?.actor ? { creator: { id: meta.actor.id } as any } : {}),\n ...(meta?.actor ? { updater: { id: meta.actor.id } as any } : {}),\n status\n })\n )\n }\n\n /**\n * ๋ผ์ด๋ธŒ ๊ตฌ์กฐ ๋ณ€์ด(resource.add ๋“ฑ)๋ฅผ ์ €์žฅ๋œ model ์— ๋ฐ˜์˜ โ€” ๋Ÿฐํƒ€์ž„ ์ปค๋„์˜ ๋ฌด๋ฒ„๋ฅผ registry model.equipment ์— ๋™๊ธฐ.\n * ์ด๊ฒŒ ์—†์œผ๋ฉด ๋Ÿฐํƒ€์ž„์—” ์ถ”๊ฐ€๋ผ๋„(์ƒํƒœยท์ €๋„์—” ๋ฐ˜์˜) ์ €์žฅ model ๋Š” ์›๋ณธ์ด๋ผ ํ”„๋กœ๋น„์ €๋‹ ํŽธ์ง‘๊ธฐยท์žฌ๊ธฐ๋™(loadTwinModel)์ด\n * ์ถ”๊ฐ€๋ถ„์„ ์žƒ๋Š”๋‹ค. ๊ธฐ์กด model.equipment ํ•ญ๋ชฉ์€ ๋ณด์กด(homeLocation ์œ ์ง€)ํ•˜๊ณ  ์ƒˆ id ๋งŒ append(์ถ”๊ฐ€ ์‹œ์  location=homeLocation).\n * ์ขŒํ‘œ(layout)๋งŒ ๋‹ค๋ฃจ๋Š” register ์™€ ๋‹ฌ๋ฆฌ equipment ์ง‘ํ•ฉ์„ ๊ฐฑ์‹ ํ•˜๋‚˜, ์žฌํ”„๋กœ๋น„์ „(purge)์ด ์•„๋‹ˆ๋ผ in-place ๊ฐฑ์‹ ์ด๋ผ\n * ์ €๋„์€ ๋ณด์กด๋œ๋‹ค(์ถ”๊ฐ€๋Š” ์ด๋ฏธ equipment ๋ธํƒ€๋กœ ์ €๋„๋จ โ†’ replay ๋Š” id-keyed upsert ๋ผ ์ด์ค‘๊ณ„์‚ฐ ์—†์Œ).\n */\n static async syncBoardEquipment(domainId: string, instanceId: string): Promise<void> {\n const inst = this.instances[runtimeKey(domainId, instanceId)]\n const snap = inst?.kernel?.getSnapshot?.()\n if (!snap?.equipment) return\n const repo = getRepository(TwinInstance)\n const reg = await repo.findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!reg?.model) return\n const model = reg.model as TwinModelDef\n const known = new Set((model.equipment ?? []).map(m => m.id))\n const added = snap.equipment\n .filter((m: any) => !known.has(m.id))\n .map((m: any) => ({ id: m.id, kind: m.kind, homeLocation: m.location }))\n if (!added.length) return\n model.equipment = [...(model.equipment ?? []), ...added]\n reg.model = model\n await repo.save(reg)\n }\n\n /**\n * ํ”„๋กœ๋น„์ €๋‹ โ€” ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ๊ตฌ์กฐ(model)๋ฅผ ๋“ฑ๋ก๋งŒ ํ•˜๊ณ  ๊ธฐ๋™ํ•˜์ง€ ์•Š์Œ(status='stopped').\n * ์žฌํ”„๋กœ๋น„์ „ ์‹œ ๊ตฌ์กฐ ์‹œ๊ทธ๋‹ˆ์ฒ˜๊ฐ€ ๋ฐ”๋€Œ๋ฉด(๋…ธ๋“œยท๋ฌด๋ฒ„ ์ง‘ํ•ฉ/์†์„ฑ ๋ณ€๊ฒฝ) ๊ธฐ์กด ์ €๋„์„ purge ํ•œ๋‹ค(ADR-0015):\n * model ๋Š” replay ์˜ ๋งˆ์Šคํ„ฐ๋ผ ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๊ณผ๊ฑฐ ์ด๋ฒคํŠธ์˜ ์ „์ œ๊ฐ€ ๊นจ์ง„๋‹ค. ์ขŒํ‘œ(layout)๋งŒ ๋ฐ”๋€Œ๋ฉด ์ €๋„ ๋ณด์กด.\n */\n /**\n * ์‹คํ–‰ ์ค‘์ด๋ฉด ๊ตฌ์กฐ๋ฅผ ๊ต์ฒดํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” **ํŒ์ • ๋ฌธ์žฅ์„ ํ•œ ๊ณณ์— ๋‘”๋‹ค.**\n *\n * ์ธ์ œ์ŠคํŠธ๋Š” ์ „๋Ÿ‰ ๊ต์ฒด๋ผ, ์ด๋ฒคํŠธ๋ฅผ ์ ‘๊ณ  ์žˆ๋Š” ์ปค๋„ ๋ฐ‘์—์„œ ๋ฐ”๋‹ฅ์„ ๋ฐ”๊พธ๋Š” ์…ˆ์ด ๋œ๋‹ค. ์ง€๊ธˆ์€ ๊ฑฐ์ ˆ์ด\n * ์œ ์ผํ•œ ๋‹ต์ด์ง€๋งŒ ์ตœ์ข…ํ˜•์€ ์•„๋‹ˆ๋‹ค(`adoptStructure` ๋ฐฐ์„ ). ๋‘ ๊ณณ์—์„œ ๊ฐ™์€ ๋ฌธ์žฅ์œผ๋กœ ๊ฑฐ์ ˆํ•ด์•ผ\n * ๋‚˜์ค‘์— ์ด ๊ทœ์น™์„ ๊ฑท์–ด๋‚ผ ๋•Œ ๊ฑท์–ด๋‚ผ ๊ฒƒ์ด ํ•˜๋‚˜๋กœ ๋ณด์ธ๋‹ค.\n */\n private static assertNotRunning(domainId: string, instanceId: string): void {\n if (!this.instances[runtimeKey(domainId, instanceId)]) return\n /*\n * **๊ฑฐ์ ˆ๋„ ๋ฒˆ์—ญ๋ผ์•ผ ํ•œ๋‹ค.** ์ด ๋ฌธ์žฅ์€ ์ „๋‹ฌ๋˜์–ด ๋ฆฌ์กธ๋ฒ„์˜ `catch` ๋ฅผ ์ง€๋‚˜ ํ™”๋ฉด ํ† ์ŠคํŠธ์— ๊ทธ๋Œ€๋กœ\n * ๋–ด๋‹ค โ€” ๋‹ค์„ฏ ์–ธ์–ด ์ œํ’ˆ์—์„œ ์˜์–ด ํ•œ ์ค„์ด ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์˜€๋‹ค(2026-08-14 ์‹ค์ธก).\n *\n * ๊ทธ๋ž˜์„œ ์ฝ”๋“œ์™€ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์˜ˆ์™ธ์— ์‹ค์–ด ๋ณด๋‚ธ๋‹ค(`ImportSpaceRefusal` ๊ณผ ๊ฐ™์€ ๊ทœ์•ฝ: ์˜์–ด ๋ฌธ์žฅ์€\n * canonical ์ด๊ณ  ๋กœ๊ทธยทํด๋ฐฑ์œผ๋กœ๋งŒ ์“ฐ์ธ๋‹ค). ์ด์œ ๊ฐ€ ์ฝ”๋“œ๋กœ ์˜ค๋ฉด ํ™”๋ฉด์ด ์˜ฎ๊ธธ ์ˆ˜ ์žˆ๋‹ค.\n */\n const err: any = new Error(`instance \"${instanceId}\" is running โ€” stop before re-provisioning`)\n err.code = 'twin-running'\n err.params = { instanceId }\n throw err\n }\n\n /**\n * ๋Œ๋ฉด์„œ ๊ณต์žฅ์„ ์ „ํ™˜ํ•œ๋‹ค โ€” **๋ฏธ๋Ÿฌ ์ „์šฉ.**\n *\n * ๋ฏธ๋Ÿฌ๊ฐ€ ๋น„์ถ”๋Š” ํ˜„์‹ค์€ ์•ˆ ๋ฉˆ์ถ˜๋‹ค. ์„ค๋น„ ํ•œ ๋Œ€๊ฐ€ ๋Š˜์—ˆ๋‹ค๊ณ  ํŠธ์œˆ์„ ๋ฉˆ์ท„๋‹ค ์„ธ์šฐ๋ฉด ๊ทธ ์‚ฌ์ด์˜ ์‚ฌ์‹ค์„\n * ์žƒ๊ณ , ๋ผ์ด๋ธŒ์—์„œ ์œ ์‹ค์€ ๊ณง ๊ฑฐ์ง“์ด๋‹ค. ๊ทธ๋ž˜์„œ ๋ฏธ๋Ÿฌ๋Š” **๋™์ž‘ ์ค‘์—** ์ƒˆ ๊ตฌ์กฐ๋ฅผ ๋ฐ›๋Š”๋‹ค.\n *\n * ์‹œ๋ฎฌ๋ ˆ์ด์…˜์€ ์—ฌ๊ธฐ ์˜ค์ง€ ์•Š๋Š”๋‹ค. ์กฐ๊ฑด์ด ๋ฐ”๋€ ์‹คํ—˜์€ ๋‹ค๋ฅธ ์‹คํ—˜์ด๋ฏ€๋กœ ๋ฉˆ์ถ”๊ณ  ๋‹ค์‹œ ์„ธ์šฐ๋Š” ๊ฒƒ์ด\n * ์˜ณ๋‹ค โ€” ์ปค๋„์ด ๊ทธ๋ ‡๊ฒŒ ๊ฑฐ์ ˆํ•œ๋‹ค(`FlowEngine.adoptStructure`).\n *\n * ์„ธ ๊ฐ€์ง€๊ฐ€ **ํ•จ๊ป˜** ์ผ์–ด๋‚˜์•ผ ํ•œ๋‹ค. ํ•˜๋‚˜๋ผ๋„ ๋น ์ง€๋ฉด ์ธต์ด ์–ด๊ธ‹๋‚œ๋‹ค:\n * โ‘  ๋ฆฌ๋น„์ „ โ€” ์ด ์‹œ์  ์ดํ›„์˜ ์ด๋ฒคํŠธ๊ฐ€ ์ƒˆ ๋ฒˆํ˜ธ๋ฅผ ๋‹ฌ๊ณ  ๋‹ค๋‹Œ๋‹ค(์žฌ์ƒ์ด ๋งˆ๋””๋ฅผ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๊ฒŒ)\n * โ‘ก ์ €์žฅ modelยท๊ตฌ์กฐ ํ–‰ โ€” ์กฐํšŒ๊ฐ€ ์ƒˆ ๊ตฌ์กฐ๋ฅผ ๋ณธ๋‹ค\n * โ‘ข ์ปค๋„ โ€” ์ง€๊ธˆ ์ ‘ํžˆ๋Š” ์ด๋ฒคํŠธ๊ฐ€ ์ƒˆ ๊ตฌ์กฐ ์œ„์—์„œ ์ ‘ํžŒ๋‹ค\n */\n static async adoptStructure(\n domainId: string,\n instanceId: string,\n model: TwinModelDef,\n comment?: string,\n origin?: any\n ): Promise<{ rev: number } & StructureShift> {\n const inst = this.instances[runtimeKey(domainId, instanceId)]\n if (!inst) throw new Error(`instance \"${instanceId}\" is not running โ€” provision it instead of adopting`)\n if (inst.mode !== 'live')\n throw new Error(`instance \"${instanceId}\" is a simulation โ€” stop it and re-provision (a changed experiment is a different experiment)`)\n\n const reg = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!reg) throw new Error(`instance \"${instanceId}\" is running but not registered โ€” refusing to adopt into an unknown twin`)\n\n const rev = await this.recordStructure(domainId, instanceId, model, comment)\n await this.register(domainId, instanceId, reg.kind, model, 'running', undefined, origin)\n /* ์ปค๋„์„ **๋งˆ์ง€๋ง‰์—** ์ „ํ™˜ํ•œ๋‹ค โ€” ์ €์žฅ์ด ์‹คํŒจํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ๋งŒ ์ƒˆ ๊ตฌ์กฐ๊ฐ€ ๋˜์–ด, ์žฌ๊ธฐ๋™ํ•˜๋ฉด ์กฐ์šฉํžˆ\n ์˜› ๊ตฌ์กฐ๋กœ ๋Œ์•„๊ฐ„๋‹ค(๊ณ ์น˜๊ธฐ ์–ด๋ ค์šด ์–ด๊ธ‹๋‚จ์ด๋‹ค). */\n const shift: StructureShift = inst.kernel.adoptStructure(model)\n /*\n * **๊ณต์ • ๋ช…์„ธยทํ˜„์žฅ์ด ์ •ํ•œ ์‹œ๊ฐ„๋„ ํ•จ๊ป˜ ์‹ฃ๋Š”๋‹ค** โ€” ์ปค๋„์˜ ๊ตฌ์กฐ ์ „ํ™˜์€ ์ž๋ฆฌยท์„ค๋น„๋ฅผ ๊ฐˆ์ง€๋งŒ, ๊ณต์ • ์‹œ๊ฐ„์€\n * ํ˜ธ์ŠคํŠธ๊ฐ€ ์‹ค์–ด ์ฃผ๋Š” ๊ฒƒ์ด๋ฏ€๋กœ(`model.localDurations`) ์—ฌ๊ธฐ์„œ ๋‹ค์‹œ ๋ถ€๋ฅด์ง€ ์•Š์œผ๋ฉด ๋Œ๊ณ  ์žˆ๋Š” ๋ฏธ๋Ÿฌ๋Š”\n * ์žฌ๊ธฐ๋™ํ•  ๋•Œ๊นŒ์ง€ ์˜› ์‹œ๊ฐ„์œผ๋กœ ๋ˆ๋‹ค(ํ™”๋ฉด์€ ใ€Œ๋„ฃ์—ˆ์Šต๋‹ˆ๋‹คใ€๋ผ๊ณ  ๋งํ•œ ๊ฐ’์ด๋‹ค).\n */\n this.applyOperations(inst.kernel, model, instanceId)\n\n /*\n * **ํˆฌ์˜ ํ–‰๋„ ์ƒˆ ๊ตฌ์กฐ๋ฅผ ๋”ฐ๋ฅธ๋‹ค** (2026-08-18 ์‹ค์ธก์œผ๋กœ ๋ถ™์ž„).\n *\n * ํ–‰(`twin_locations`ยท`twin_equipment`)์€ ๊ตฌ์กฐ์˜ ์บ์‹œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด ๊ฒฝ๋กœ๋Š” ์ปค๋„๋งŒ ๊ฐˆ๊ณ  ํ–‰์€ ๊ทธ๋Œ€๋กœ\n * ๋‘์—ˆ๋‹ค โ€” ๋Œ๊ณ  ์žˆ๋Š” ๋ฏธ๋Ÿฌ์— ๊ฐ’์„ ์„ ์–ธํ•˜๋ฉด ์ปค๋„์€ ์ƒˆ ๊ฐ’์œผ๋กœ ๊ณ„์‚ฐํ•˜๋Š”๋ฐ **ํ•ญ๋ชฉ ํŒจ๋„์€ ์˜› ํ–‰์„ ๋ณด์—ฌ\n * ์ค€๋‹ค**(๋„ฃ์€ ๊ฐ’์ด ํ™”๋ฉด์—์„œ ๋ณด์ด์ง€ ์•Š๋Š”๋‹ค). ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€ ์ˆœ๊ฐ„์ด ๊ณง ์บ์‹œ๋ฅผ ๋‹ค์‹œ ๊ทธ๋ฆด ์ˆœ๊ฐ„์ด๋‹ค.\n *\n * ์‹คํŒจ๋Š” ํก์ˆ˜ํ•œ๋‹ค: ํˆฌ์˜์ด ๋ง‰ํ˜€๋„(์˜ˆ: ๋ชจ๋ธ์— ์ค‘๋ณต id) ์ปค๋„์€ ์ด๋ฏธ ์ƒˆ ๊ตฌ์กฐ๋กœ ๋Œ๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๊ทธ ์‚ฌ์‹ค์„\n * ๋˜๋Œ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค โ€” ๋‹ค๋งŒ ์กฐ์šฉํžˆ ๋„˜๊ธฐ์ง€ ์•Š๊ณ  ๋งํ•œ๋‹ค.\n */\n await projectStructure(domainId, instanceId, model, instanceId).catch((err: any) =>\n twinWarn(`[twin-engine] \"${instanceId}\" adopted a new structure but its projected rows were not refreshed โ€” ${err?.message ?? err}`)\n )\n\n /*\n * **๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€ ์ˆœ๊ฐ„์ด ์ƒํƒœ๊ฐ€ ๋ฐ”๋€ ์ˆœ๊ฐ„์ด๋‹ค** โ€” ๊ทธ๋Ÿฌ๋‹ˆ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…ํ•œ๋‹ค.\n *\n * โ”€โ”€ ๋ฌด์—‡์ด ๋‚ฌ๋‚˜ (2026-08-18) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๊ตฌ์กฐ ์ „ํ™˜์€ ์ปค๋„๋งŒ ๊ฐˆ๊ณ  ์กฐ์šฉํžˆ ๋๋‚ฌ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ํ™”๋ฉด์ด ๋ณด๋Š” ๊ฒƒ ์ƒ๋‹น์ˆ˜๊ฐ€ ๊ตฌ์กฐ์—์„œ ํŒŒ์ƒ๋œ๋‹ค โ€”\n * ๊ณ„์•ฝ ๋Œ€๋น„ ํŒ์ •, ์ฃผ๋ชฉ ์‹ ํ˜ธ, ์ž๋ฆฌ ์ƒ‰. ํ˜„์žฅ์ด ๊ณ„์•ฝ์„ ๊ณ ์ณ ์„ ์–ธํ•œ ์ˆœ๊ฐ„ ์กฐ๊ฑด์ด ์„ฑ๋ฆฝํ•˜๋Š”๋ฐ๋„, ์ƒํƒœ\n * ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์ด ์—†์–ด์„œ ์ง€๋„ ๋ ˆ์ผ์€ **๋‹ค์Œ ๊ณ„์ธก ํ‘œ๋ณธ์ด ์˜ฌ ๋•Œ๊นŒ์ง€** ์˜› ํ™”๋ฉด์„ ๋“ค๊ณ  ์žˆ์—ˆ๋‹ค(๊ทธ ์‚ฌ์ด ํ—ค๋”\n * ๋ฐฐ์ง€๋Š” 4์ดˆ ํด๋ง์œผ๋กœ ๋จผ์ € ์•Œ์•„, ใ€Œ๋ฐฐ์ง€์—” ์žˆ๊ณ  ๋ชฉ๋ก์—” ์—†๋Š”ใ€ ์–ด๊ธ‹๋‚œ ํ™”๋ฉด์ด ์‹ค์ œ๋กœ ๋ณด์˜€๋‹ค).\n *\n * ์ƒˆ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ… ๊ฒฝ๋กœ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค: dirty ๋ฅผ ์„ธ์›Œ **์ด๋ฏธ ์žˆ๋Š” ๋ณ‘ํ•ฉ ๊ทœ์œจ**(200ms)์— ์–น๋Š”๋‹ค. ๊ตฌ์กฐ ์ „ํ™˜์€\n * ๋“œ๋ฌผ์ง€๋งŒ, ์—ฌ๋Ÿฌ ํŠธ์œˆ์— ์ž‡๋‹ฌ์•„ ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ๊ณ (ํ˜„์žฅ ์ผ๊ด„ ์„ ์–ธ) ๊ทธ๋•Œ๋„ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…๋ฅ  ์ƒํ•œ์€ ์ง€์ผœ์•ผ ํ•œ๋‹ค.\n */\n inst.dirty = true\n /* ๊ตฌ์กฐ๊ฐ€ ๊ฐˆ๋ ธ์œผ๋ฉด ๋ฌด์—‡์ด ๋‹ฌ๋ผ์กŒ๋Š”์ง€ ์‚ฌ๊ฑด์œผ๋กœ ๋งํ•  ์ˆ˜ ์—†๋‹ค โ€” ์ „๋ถ€ ๋‹ค์‹œ ๋งŒ๋“ ๋‹ค. */\n this.markItemsDirty(inst)\n this.ensureBroadcastCoalescer()\n\n return { rev, ...shift }\n }\n\n static async provision(\n domainId: string,\n instanceId: string,\n kind: string,\n model: TwinModelDef,\n /**\n * **์žฌ๊ธฐ๋™ ์ •์ฑ…์€ ์ƒ์„ฑ ์‹œ์ ์˜ ์„ ์–ธ์ด๋‹ค**(ADR-0029 ยง2) โ€” ํŠธ์œˆ์€ ์ •์ฑ… ์—†์ด ์กด์žฌํ•  ์ˆ˜ ์—†๋‹ค.\n *\n * ์˜ˆ์ „์—๋Š” ์ด ์ž๋ฆฌ๊ฐ€ ์—†์—ˆ๊ณ  `register` ๊ฐ€ ๊ธฐ๋ณธ๊ฐ’(`sim-experiment` = ์ €๋„ ์ดˆ๊ธฐํ™”)์„ ๊ฐ์ธํ–ˆ๋‹ค. ๊ทธ๋ž˜์„œ\n * ์„ ์–ธ์„ ๋น ๋œจ๋ฆฐ ํ”„๋กœ๋น„์ €๋‹์ด **์žฌ๊ธฐ๋™๋งˆ๋‹ค ์ด๋ ฅ์„ ์ง€์šฐ๋Š” ํŠธ์œˆ**์„ ์กฐ์šฉํžˆ ๋งŒ๋“ค์—ˆ๋‹ค. ์ด์ œ ๋งŒ๋“œ๋Š” ์ชฝ์ด\n * ๋งํ•ด์•ผ ํ•œ๋‹ค: ์ด ํŠธ์œˆ์ด ์ž๊ธฐ ๊ณผ๊ฑฐ๋ฅผ ์–ด๋–ป๊ฒŒ ๋Œ€ํ•˜๋Š”์ง€๋Š” ๋งŒ๋“œ๋Š” ์‚ฌ๋žŒ์ด ์•„๋Š” ์‚ฌ์‹ค์ด๋‹ค.\n */\n restartPolicy: RestartPolicy,\n comment?: string,\n origin?: any,\n /** ์ด๋ฆ„ยท์ €์ž โ€” ์—…๋ฌดํ‚ค๋ฅผ ๋‚˜๋ˆ  ๋‘” ๋Œ€๊ฐ€๋กœ ์ด๋ฆ„์„ ํ•จ๊ป˜ ๋‚จ๊ธด๋‹ค(`register` ์˜ `meta` ๊ทธ๋Œ€๋กœ). */\n meta?: { name?: string; description?: string; actor?: { id: string } }\n ): Promise<void> {\n this.assertNotRunning(domainId, instanceId)\n /* ์ข…๋ฅ˜๋ฅผ **์ €์žฅํ•˜๊ธฐ ์ „์—** ๊ฒ€์ฆํ•œ๋‹ค. ๋‚˜์ค‘์— ๊ธฐ๋™ํ•  ๋•Œ ๊ฑธ๋ฆฌ๋ฉด ์›์ธ์ด ํ”„๋กœ๋น„์ €๋‹์—์„œ ๋ฉ€์–ด์ง€๊ณ ,\n ๊ทธ ์‚ฌ์ด ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์—๋Š” ๋Œ๋ฆด ์ˆ˜ ์—†๋Š” ํŠธ์œˆ์ด ์•‰์•„ ์žˆ๋‹ค. */\n kernelFor(kind)\n const repo = getRepository(TwinInstance)\n const existing = await repo.findOne({ where: { domain: { id: domainId }, instanceId } })\n\n /*\n * **๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ์–ด๋„ ์—ญ์‚ฌ๋ฅผ ์ง€์šฐ์ง€ ์•Š๋Š”๋‹ค.**\n *\n * ์˜ˆ์ „์—๋Š” ์„œ๋ช…์ด ๋‹ค๋ฅด๋ฉด ๊ทธ ํŠธ์œˆ์˜ ์ €๋„์„ ํ†ต์งธ๋กœ ์ง€์› ๋‹ค. ์•ˆ ์ง€์šฐ๋ฉด ์˜› ์ด๋ฒคํŠธ๋ฅผ ์ƒˆ ๊ณต์žฅ์— ๋Œ€๊ณ \n * ์ ‘๊ฒŒ ๋˜์–ด ์ด๋ ฅ์ด ๊ฑฐ์ง“๋ง์„ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค โ€” ๋ถ€์Šค๊ฐ€ ๋‘˜์ด๋˜ ์‹œ์ ˆ์˜ ์‚ฌ์‹ค์„ ์—ฌ์„ฏ ๊ฐœ์งœ๋ฆฌ ๊ณต์žฅ์—\n * ์ ‘์œผ๋ฉด ๊ทธ๋•Œ ์—†๋˜ ๋ถ€์Šค์—์„œ ์ผ์ด ์žˆ์—ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค. ์„ ํƒ์ง€๊ฐ€ **์—ญ์‚ฌ๋ฅผ ์žƒ๊ฑฐ๋‚˜ ๊ฑฐ์ง“๋ง์„\n * ํ•˜๊ฑฐ๋‚˜** ๋‘˜๋ฟ์ด์—ˆ๊ณ , ๊ทธ๋ž˜์„œ ๊ณต์žฅ์„ ๊ณ ์น  ๋•Œ๋งˆ๋‹ค ์ด๋ ฅ์„ ๋ฒ„๋ ค์•ผ ํ–ˆ๋‹ค.\n *\n * ์ด์ œ ์…‹์งธ ๊ธธ๋กœ ๊ฐ„๋‹ค: ๋ฐ”๋€ ๊ตฌ์กฐ๋ฅผ **์ƒˆ ๋ฆฌ๋น„์ „**์œผ๋กœ ๋‚จ๊ธฐ๊ณ , ์•ž์œผ๋กœ ์“ฐ์ด๋Š” ์ด๋ฒคํŠธ๊ฐ€ ๊ทธ ๋ฒˆํ˜ธ๋ฅผ\n * ๋‹ฌ๊ณ  ๋‹ค๋‹Œ๋‹ค. ์žฌ์ƒ์€ ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ๋Š” ์ง€์ ์—์„œ ์ „ํ™˜ํ•œ ๋’ค ์ด์–ด ์ ‘๋Š”๋‹ค(`replaySegments`).\n */\n await this.recordStructure(domainId, instanceId, model, comment)\n await this.register(domainId, instanceId, kind, model, existing?.status === 'running' ? 'stopped' : (existing?.status as any) ?? 'stopped', restartPolicy, origin, meta)\n }\n\n /**\n * ์ด ๊ตฌ์กฐ๋ฅผ ๋ฆฌ๋น„์ „์œผ๋กœ ๋‚จ๊ธฐ๊ณ  ๊ทธ ๋ฒˆํ˜ธ๋ฅผ ๋Œ๋ ค์ค€๋‹ค โ€” **๋ฐ”๋€Œ์—ˆ์„ ๋•Œ๋งŒ** ์ƒˆ ๋ฒˆํ˜ธ๊ฐ€ ์ƒ๊ธด๋‹ค.\n *\n * ํ”„๋กœ๋น„์ €๋‹์€ ๋ถ€ํŒ…๋งˆ๋‹ค ๋‹ค์‹œ ๋„๋Š”๋ฐ, ๊ทธ๋•Œ๋งˆ๋‹ค ๋ฆฌ๋น„์ „์ด ๋Š˜๋ฉด ์ด๋ ฅ์ด ๋œป ์—†๋Š” ๋งˆ๋””๋กœ ์ž˜๊ฒŒ ์ชผ๊ฐœ์ง„๋‹ค.\n * ๊ทธ๋ž˜์„œ **๊ตฌ์กฐ ์„œ๋ช…์ด ๊ฐ™์œผ๋ฉด ์žˆ๋˜ ๋ฆฌ๋น„์ „์„ ๊ทธ๋Œ€๋กœ ์“ด๋‹ค.**\n */\n static async recordStructure(domainId: string, instanceId: string, model: TwinModelDef, comment?: string): Promise<number> {\n const repo = getRepository(TwinStructure)\n const signature = this.structureFingerprint(model)\n const latest = await repo.findOne({ where: { domain: { id: domainId }, instanceId }, order: { rev: 'DESC' } })\n\n /*\n * **์ €์žฅ๋œ ์ง€๋ฌธ์ด ์•„๋‹ˆ๋ผ ์ €์žฅ๋œ ๊ณต์žฅ๊ณผ ๋น„๊ตํ•œ๋‹ค.**\n *\n * ์ง€๋ฌธ ๊ณ„์‚ฐ ๋ฐฉ์‹์„ ํ•œ ๋ฒˆ์ด๋ผ๋„ ๋ฐ”๊พธ๋ฉด(์›๋ฌธ โ†’ ํ•ด์‹œ๋กœ ๋ฐ”๊ฟจ๋‹ค) ์ €์žฅ๋œ ๋ฌธ์ž์—ด์€ ์ „๋ถ€ ์˜› ๋ฐฉ์‹์˜\n * ๊ฒƒ์ด๋ผ ๋ฌด์—‡๊ณผ๋„ ์•ˆ ๋งž๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋ฉด **์•„๋ฌด๊ฒƒ๋„ ์•ˆ ๋ฐ”๋€ ํŠธ์œˆ๋“ค์ด ์ „๋ถ€ \"๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ์—ˆ๋‹ค\"** ๋กœ\n * ๊ธฐ๋ก๋œ๋‹ค โ€” ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ๋๊ณ , ์žฌ๊ธฐ๋™ ํ•œ ๋ฒˆ์— ๋ฆฌ๋น„์ „์ด ํ†ต์งธ๋กœ ํ•˜๋‚˜์”ฉ ๋Š˜์—ˆ๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ ์•ˆ ๋งž์„ ๋•Œ ํ•œ ๋ฒˆ ๋” ๋ฌป๋Š”๋‹ค: ์ €์žฅ๋œ **๋ชจ๋ธ**๋กœ ์ง€๋ฌธ์„ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜๋ฉด ๊ฐ™์€๊ฐ€? ๊ฐ™๋‹ค๋ฉด\n * ๊ณต์žฅ์€ ๊ทธ๋Œ€๋กœ์ด๊ณ  ์ง€๋ฌธ ํ‘œ๊ธฐ๋งŒ ๋‚ก์€ ๊ฒƒ์ด๋‹ˆ, ๋ฆฌ๋น„์ „์„ ๋งŒ๋“ค์ง€ ์•Š๊ณ  ํ‘œ๊ธฐ๋งŒ ๊ณ ์นœ๋‹ค.\n */\n if (latest && latest.signature !== signature && this.structureFingerprint(latest.model as TwinModelDef) === signature) {\n latest.signature = signature\n await repo.save(latest)\n }\n\n if (latest?.signature === signature) {\n this.structureRevCache[runtimeKey(domainId, instanceId)] = latest.rev\n return latest.rev\n }\n\n const rev = (latest?.rev ?? 0) + 1\n await repo.save(repo.create({ domain: { id: domainId } as any, instanceId, rev, signature, model: model as any, ...(comment ? { comment } : {}) }))\n this.structureRevCache[runtimeKey(domainId, instanceId)] = rev\n /* ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์žฌ๊ตฌ์„ฑ ์บ์‹œ๋Š” ์˜› ๊ณต์žฅ์˜ ๊ฒƒ์ด๋‹ค โ€” ๋ฒ„๋ฆฐ๋‹ค(์ง€์šฐ๋Š” ๊ฑด ์บ์‹œ๋ฟ, ์‚ฌ์‹ค์€ ๋‚จ๋Š”๋‹ค). */\n delete this.recovered[runtimeKey(domainId, instanceId)]\n if (latest) console.info(`[twin-engine] \"${instanceId}\" structure changed โ†’ revision ${rev} (history kept; older events stay under revision ${latest.rev}).`)\n return rev\n }\n\n /**\n * ์ด ํŠธ์œˆ์ด ๊ฑฐ์ณ ์˜จ ๊ตฌ์กฐ๋“ค โ€” **๋ฌด์—‡์ด ์–ธ์ œ ๋‹ฌ๋ผ์กŒ๋‚˜.**\n *\n * ๋ฆฌ๋น„์ „์€ ๊ทธ ์‹œ์ ˆ ๊ณต์žฅ์„ ํ†ต์งธ๋กœ ๋‹ด์ง€๋งŒ(์žฌ์ƒ์— ํ•„์š”ํ•˜๋‹ค), ์‚ฌ๋žŒ์ด ๋ณด๊ณ  ์‹ถ์€ ๊ฒƒ์€ ํ†ต์งธ๊ฐ€ ์•„๋‹ˆ๋ผ\n * ์ฐจ์ด๋‹ค. ๋ชจ๋ธ์€ ๋นผ๊ณ  **์ฐจ์ด ์š”์•ฝ๋งŒ** ๋‚ด๋ณด๋‚ธ๋‹ค โ€” 62KB ์งœ๋ฆฌ ๋ณด๋“œ๋ฅผ ํ™”๋ฉด์— ์‹ค์–ด ๋ณด๋‚ผ ์ด์œ ๊ฐ€ ์—†๋‹ค.\n */\n static async structureHistory(\n domainId: string,\n instanceId: string\n ): Promise<{ rev: number; createdAt?: Date; comment?: string; events: number; diff: StructureDiff }[]> {\n const revs = await getRepository(TwinStructure).find({ where: { domain: { id: domainId }, instanceId }, order: { rev: 'ASC' } })\n if (!revs.length) return []\n\n /* ๋ฆฌ๋น„์ „๋งˆ๋‹ค ๊ทธ ์•„๋ž˜์—์„œ ๋ช‡ ๊ฑด์ด ์ผ์–ด๋‚ฌ๋‚˜ โ€” ์ด๋ ฅ์˜ ๋ฌด๊ฒŒ๋ฅผ ๋ณด์—ฌ์ค€๋‹ค(์งง๊ฒŒ ์Šค์ณ๊ฐ„ ๊ตฌ์กฐ์ธ์ง€). */\n const counts = new Map<number | null, number>()\n for (const row of await getRepository(TwinEvent)\n .createQueryBuilder('e')\n .select('e.structureRev', 'rev')\n .addSelect('COUNT(1)', 'n')\n .where('e.domain = :domainId', { domainId })\n .andWhere('e.instanceId = :instanceId', { instanceId })\n .groupBy('e.structureRev')\n .getRawMany())\n counts.set(row.rev === null || row.rev === undefined ? null : Number(row.rev), Number(row.n))\n\n /* ๋ฒˆํ˜ธ ์—†๋Š” ์˜› ํ–‰์€ **๊ฐ€์žฅ ์˜ค๋ž˜๋œ ๋ฆฌ๋น„์ „**์˜ ๋ชซ์ด๋‹ค โ€” ์žฌ์ƒ์ด ๊ทธ๋ ‡๊ฒŒ ์ ‘์œผ๋ฏ€๋กœ ์„ธ๋Š” ๊ฒƒ๋„ ๊ฐ™์•„์•ผ ํ•œ๋‹ค. */\n const oldest = revs[0].rev\n const legacy = counts.get(null) ?? 0\n\n return revs.map((r, i) => ({\n rev: r.rev,\n createdAt: r.createdAt,\n ...(r.comment ? { comment: r.comment } : {}),\n events: (counts.get(r.rev) ?? 0) + (r.rev === oldest ? legacy : 0),\n diff: diffStructures(i === 0 ? undefined : (revs[i - 1].model as any), r.model as any)\n }))\n }\n\n /** ์ง€๊ธˆ ์“ฐ์ด๋Š” ๊ตฌ์กฐ ๋ฆฌ๋น„์ „ โ€” ์ด๋ฒคํŠธ์— ์ฐ์„ ๋ฒˆํ˜ธ. ์•„์ง ์—†์œผ๋ฉด ๊ธฐ๋กํ•˜๋ฉฐ ๋งŒ๋“ ๋‹ค. */\n static async currentStructureRev(domainId: string, instanceId: string, model?: TwinModelDef): Promise<number | undefined> {\n const latest = await getRepository(TwinStructure).findOne({ where: { domain: { id: domainId }, instanceId }, order: { rev: 'DESC' } })\n if (latest) return latest.rev\n return model ? this.recordStructure(domainId, instanceId, model) : undefined\n }\n\n /** ๊ตฌ์กฐ ๋™์ผ์„ฑ ์ง€๋ฌธ โ€” ์ขŒํ‘œ(layout) ๋“ฑ ๋ทฐ ๊ด€์‹ฌ์‚ฌ๋Š” ์ œ์™ธํ•˜๊ณ  ์ปค๋„์ด ๋ณด๋Š” ์œ„์ƒยท์šฉ๋Ÿ‰ยท๋ฌด๋ฒ„๋งŒ. */\n /**\n * ์ง€๋ฌธ์„ **64์ž๋กœ ์ค„์ธ๋‹ค** โ€” ์ปฌ๋Ÿผ์ด varchar(64) ๋‹ค.\n *\n * ์›๋ฌธ ์ง€๋ฌธ์€ ์ž๋ฆฌยท์„ค๋น„๋ฅผ ์ „๋ถ€ ์ด์–ด ๋ถ™์ธ ๋ฌธ์ž์—ด์ด๋ผ ํฐ ๊ณต์žฅ์—์„œ๋Š” ์ˆ˜๋งŒ ์ž๊ฐ€ ๋œ๋‹ค. sqlite ๋Š”\n * ๊ธธ์ด๋ฅผ ๊ฐ•์ œํ•˜์ง€ ์•Š์•„ ๊ทธ๋ƒฅ ๋“ค์–ด๊ฐ€์ง€๋งŒ **Postgres ๋Š” ๊ฑฐ๊ธฐ์„œ ํ„ฐ์ง„๋‹ค** โ€” ๊ฐœ๋ฐœ์—์„œ๋Š” ๋ฉ€์ฉกํ•˜๊ณ \n * ์šด์˜์—์„œ๋งŒ ์ฃฝ๋Š” ์ข…๋ฅ˜์˜ ์‹คํŒจ๋‹ค. ๋น„๊ต์—๋งŒ ์“ฐ๋Š” ๊ฐ’์ด๋ฏ€๋กœ ํ•ด์‹œ๋กœ ์ถฉ๋ถ„ํ•˜๋‹ค.\n */\n private static structureFingerprint(model: TwinModelDef): string {\n return createHash('sha256').update(this.structureSignature(model)).digest('hex')\n }\n\n private static structureSignature(model: TwinModelDef): string {\n const locations = [...(model.locations ?? [])]\n .map(n => `${n.id}:${n.type}:${n.capacity}`)\n .sort()\n .join('|')\n const equipment = [...(model.equipment ?? [])]\n .map(m => `${m.id}:${m.kind}:${m.homeLocation}`)\n .sort()\n .join('|')\n return `N[${locations}]M[${equipment}]`\n }\n\n /** ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ model ๋กœ ๊ธฐ๋™(ํ”„๋กœ๋น„์ „๋œ ์ธ์Šคํ„ด์Šค start). model ์ธ์ž ์—†์ด ์ €์žฅ๋œ ๊ตฌ์กฐ๋กœ ์žฌ๊ธฐ๋™. */\n static async startFromRegistry(domainId: string, instanceId: string, restartPolicy?: RestartPolicy): Promise<InstanceRuntime> {\n const key = runtimeKey(domainId, instanceId)\n if (this.instances[key]) return this.instances[key]\n const reg = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!reg?.model) throw new Error(`instance \"${instanceId}\" not provisioned (no model)`)\n\n /*\n * โ”€โ”€ ์„ ์–ธ๋œ `restartPolicy` ๊ฐ€ **๊ธฐ๋™ ๋ฐฉ์‹์„ ์ •ํ•œ๋‹ค** (2026-08-20) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n *\n * ์˜ˆ์ „์—๋Š” ์ด ํ•จ์ˆ˜๊ฐ€ ์ •์ฑ…์„ **์ฝ์–ด์„œ ๋„˜๊ธฐ๊ธฐ๋งŒ** ํ–ˆ๊ณ , ๊ธฐ๋™์€ ์–ธ์ œ๋‚˜ ์‹œ๋ฎฌ ๊ฒฝ๋กœ์˜€๋‹ค. ๊ทธ๋ž˜์„œ ๋ฏธ๋Ÿฌ๋กœ\n * ์„ ์–ธํ•œ ํŠธ์œˆ์„ ํ™”๋ฉด์—์„œ ์‹œ์ž‘ํ•˜๋ฉด **์‹œ๋ฎฌ๋กœ ๋–ด๋‹ค** โ€” ๊ทธ ํŠธ์œˆ์€ ์œ ์ž…์„ ๋ฐ›์ง€ ๋ชปํ•œ๋‹ค(`ingestLive` ๋Š”\n * ๋ผ์ด๋ธŒ๊ฐ€ ์•„๋‹ˆ๋ฉด 0 ์„ ๋Œ๋ ค์ค€๋‹ค). ์˜ค๋ฅ˜๋Š” ๋‚˜์ง€ ์•Š๊ณ , ํ™”๋ฉด์—๋Š” ใ€Œrunningใ€์ด๋ผ ์ ํžŒ๋‹ค.\n *\n * ๋ถ€ํŒ… ๊ฒฝ๋กœ(`resumeRow`)์—๋Š” ๊ทธ ๊ฐˆ๋ฆผ์ด ์žˆ์—ˆ๋Š”๋ฐ ์—ฌ๊ธฐ์—๋Š” ์—†์—ˆ๋‹ค. ์ฆ‰ **๋ถ€ํŒ…์œผ๋กœ ์‚ด์•„๋‚œ ๋ฏธ๋Ÿฌ๋Š”\n * ๋ฐ›๊ณ , ์‚ฌ๋žŒ์ด ์‹œ์ž‘ํ•œ ๋ฏธ๋Ÿฌ๋Š” ๋ฐ›์ง€ ๋ชปํ–ˆ๋‹ค.** ๊ฐ™์€ ์„ ์–ธ์ด ๋‘ ๊ฒฐ๊ณผ๋ฅผ ๋‚ด๋Š” ๊ฒƒ์€ ๊ฒฐํ•จ์ด๋‹ค.\n *\n * ๊ฐˆ๋ฆผ์„ ์—ฌ๊ธฐ ํ•œ ๊ณณ์— ๋‘”๋‹ค โ€” ๋ถ€ํŒ…๋„ ์ด ๋ฌธ์„ ์ง€๋‚œ๋‹ค.\n *\n * โ”€โ”€ `reset` ์€ ์„ ์–ธ๋Œ€๋กœ **์ €๋„์„ ๋น„์šด๋‹ค** (2026-08-20) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ใ€Œseed ์žฌํ˜„ใ€์€ ๋ฐฑ์ง€์—์„œ ๋‹ค์‹œ ์‹œ์ž‘ํ•œ๋‹ค๋Š” ๋œป์ด๋‹ค. ์˜ˆ์ „์—๋Š” ๊ทธ ์„ ์–ธ์ด ๊ตฌํ˜„๋˜์ง€ ์•Š์•„ `reset` ํŠธ์œˆ์ด\n * ์‚ฌ์‹ค์ƒ ์ด์–ด์กŒ๊ณ , ๊ทธ๋ž˜์„œ ใ€Œ์ด ํŠธ์œˆ์˜ ์ด๋ ฅ์€ ์™œ ์žฌ๊ธฐ๋™์„ ๋„˜๊ฒจ ๋‚จ์•„ ์žˆ๋‚˜ใ€๋ฅผ ์•„๋ฌด๋„ ์„ค๋ช…ํ•  ์ˆ˜ ์—†์—ˆ๋‹ค.\n *\n * ์ด๊ฒƒ์€ **์‚ฌ์‹ค์„ ์ง€์šฐ๋Š” ๋™์ž‘**์ด๋ผ ์ˆœ์„œ๋ฅผ ์ง€์ผœ ์ผฐ๋‹ค: ๋จผ์ € ์‚ฌ๋žŒ์ด ๊ฐ ํŠธ์œˆ์˜ ์ •์ฑ…์„ ๋‹ค์‹œ ์„ ์–ธํ•  ๋ฌธ์„\n * ๋งŒ๋“ค๊ณ (`setTwinRestartPolicy`), ์ด๋ ฅ์„ ๋‘๊ณ  ๋ณผ ํŠธ์œˆ์„ `resume` ์œผ๋กœ ์˜ฎ๊ธด ๋’ค์— ์ผ ๋‹ค. ๊ทธ ์ˆœ์„œ๋ฅผ\n * ๋’ค์ง‘์œผ๋ฉด ์„ ์–ธ์„ ์ง€ํ‚จ ๋Œ€๊ฐ€๋กœ ๋‚จ์˜ ์ด๋ ฅ์„ ์ง€์šด๋‹ค.\n */\n const policy = restartPolicy ?? readRestartPolicy(reg.restartPolicy, `twin \"${instanceId}\"`)\n if (policy === 'resync') {\n /* ๋ฏธ๋Ÿฌ๋Š” **๊ด€์ธก ๊ตฌ๋™**์œผ๋กœ ์„ธ์šด๋‹ค โ€” ์‹œ๋ฎฌ๋กœ ์„ธ์šฐ๋ฉด ์—†๋˜ ์›€์ง์ž„์„ ์Šค์Šค๋กœ ๋งŒ๋“ ๋‹ค.\n ์‹œ๊ฐ ๊ธฐ์ค€์€ ๊ณต๊ฐ„์ด ๊ฐ–๋Š”๋‹ค(๋ถ€ํŒ… ๊ฒฝ๋กœ์™€ ๊ฐ™์€ ๊ทœ์น™). */\n return this.startLive(instanceId, domainId, reg.kind, await this.withSpaceTimeBase(reg.model as TwinModelDef, domainId))\n }\n if (policy === 'reset') {\n /*\n * ์”จ์•— ์žฌํ˜„ โ€” ์ €๋„์„ ๋น„์šฐ๊ณ  ๋ฆฌ๋น„์ „ 0 ๋ถ€ํ„ฐ ๋‹ค์‹œ ์„ผ๋‹ค. ๋ณต๊ตฌ๋ณธ๋„ ํ•จ๊ป˜ ๋ฒ„๋ฆฐ๋‹ค(`resetJournal` ์ด ํ•œ๋‹ค):\n * ๋‚จ๊ฒจ ๋‘๋ฉด ๋ฐฑ์ง€๋กœ ์‹œ์ž‘ํ•œ ํŠธ์œˆ์— ์˜› ์ƒํƒœ๊ฐ€ ๋˜์‚ด์•„๋‚˜ ใ€Œ์”จ์•— ์žฌํ˜„ใ€์ด ์•„๋‹ˆ๊ฒŒ ๋œ๋‹ค.\n *\n * **๋ฒค์น˜ ์‚ฌ๋ณธ์€ ์˜ˆ์™ธ๋‹ค.** ๊ทธ๊ฒƒ์€ ๋ˆ„๊ตฐ๊ฐ€ ์ง€์ผœ๋ณด๋Š” ์‹คํ—˜์ด๊ณ , ๊ทธ ์‹คํ—˜์˜ ๊ธฐ๋ก์„ ๊ธฐ๋™์ด ์ง€์šฐ๋ฉด ์‹คํ—˜์ด\n * ์‚ฌ๋ผ์ง„๋‹ค(๋ถ€ํŒ…์€ ๋ฒค์น˜๋ฅผ ๋˜์‚ด๋ฆฌ์ง€๋„ ์•Š๋Š”๋‹ค โ€” `resumeRow`).\n */\n if (reg.purpose !== 'bench') await this.resetJournal(domainId, instanceId)\n }\n\n /*\n * ์›œ์Šคํƒ€ํŠธ ์žฌ๋ฃŒ๋ฅผ **์—ฌ๊ธฐ์„œ ํ™•์‹คํžˆ ํ™•๋ณดํ•œ๋‹ค.**\n * `start()` ๋Š” ๋™๊ธฐ๋ผ ์Šค์Šค๋กœ ์บ์‹œ๋ฅผ ์ฝ์„ ์ˆ˜ ์—†์–ด์„œ `recovered` ์— ๋ฏธ๋ฆฌ ๋‹ด๊ฒจ ์žˆ๊ธฐ๋ฅผ ๊ธฐ๋Œ€ํ•˜๋Š”๋ฐ,\n * ๊ทธ๊ฑด `bootstrap()` ์ด ๋จผ์ € ๋Œ์•˜์„ ๋•Œ๋งŒ ์ฐธ์ด๋‹ค. ๋ถ€ํŒ… ์ˆœ์„œ์— ๊ธฐ๋Œ€๋ฉด ์–ด๋–ค ๋‚ ์€ ์žฌ๊ณ ๊ฐ€ ์‚ด์•„๋‚˜๊ณ \n * ์–ด๋–ค ๋‚ ์€ ์กฐ์šฉํžˆ ๋นˆ ์ฑ„๋กœ ๋œฌ๋‹ค โ€” ์žฌํ˜„๋˜์ง€ ์•Š๋Š” ๊ฒฐํ•จ์ด ๊ฐ€์žฅ ๋‚˜์˜๋‹ค.\n * ์ฒดํฌํฌ์ธํŠธ ์บ์‹œ ์šฐ์„ (O(1) + ๋ผ์ด๋ธŒ ํŒŒ์ƒ์ƒํƒœ ๋ณด์กด), ์—†์œผ๋ฉด ์ €๋„ replay ํด๋ฐฑ(๋ถ€ํŒ…๊ณผ ๊ฐ™์€ ์ˆœ์„œ).\n */\n if (!this.recovered[key] && reg.purpose !== 'bench') {\n const cached = await this.loadSnapshot(domainId, instanceId).catch(() => null)\n if (cached?.state) {\n this.recovered[key] = { revision: cached.revision, state: cached.state }\n } else {\n const state = await this.recover(domainId, instanceId).catch(() => null)\n if (state) this.recovered[key] = { revision: state.revision, state }\n }\n }\n\n /*\n * ์ €๋„์— ๋‚จ์•„ ์žˆ๋Š” ๋งˆ์ง€๋ง‰ ๋ฒˆํ˜ธ โ€” **๋ชจ๋“œ์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ** ์ด๊ฒƒ์„ ์ด์–ด ์„ผ๋‹ค.\n *\n * ์ €๋„์„ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ๊ธฐ๋™ํ•˜๋Š” ์ •์ฑ…(`reset`)์ด๋ผ๋ฉด ์ด ๊ฐ’์ด 0์ด๋ผ ์•„๋ฌด ์˜ํ–ฅ์ด ์—†๋‹ค. ๊ทœ์น™์„\n * ๋ชจ๋“œ๋ณ„๋กœ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š๋Š” ์ด์œ : \"์ €๋„์ด ๋น„์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด ๊ทธ ๋’ค๋ถ€ํ„ฐ\" ํ•˜๋‚˜๋ฉด ์–ด๋А ๋ชจ๋“œ์—์„œ๋„\n * ๊ฒน์น  ์ˆ˜ ์—†๊ณ , ๋ชจ๋“œ๊ฐ€ ๋Š˜์–ด๋„ ์ด ์ž๋ฆฌ๋ฅผ ๋‹ค์‹œ ์†๋ณผ ์ผ์ด ์—†๋‹ค.\n */\n const last = await getRepository(TwinEvent)\n .createQueryBuilder('e')\n .select('MAX(e.revision)', 'max')\n .where('e.domain = :domainId', { domainId })\n .andWhere('e.instanceId = :instanceId', { instanceId })\n .getRawOne()\n\n return this.start(\n instanceId,\n domainId,\n /* ์ปค๋„ ์ข…๋ฅ˜ยทํ˜„์‹ค ์„ ์–ธ์€ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ๋ฐ˜๋“œ์‹œ ์žˆ๋‹ค(๋‘˜ ๋‹ค NOT NULL). ์˜ˆ์ „์—๋Š” `?? 'wms'` ๋กœ\n ๋ฉ”์› ๋Š”๋ฐ, ๊ทธ๊ฑด YMS/MES ํŠธ์œˆ์„ **์กฐ์šฉํžˆ WMS ๋กœ ๋ถ€ํŒ…**์‹œํ‚ค๋Š” ๊ธธ์ด์—ˆ๋‹ค โ€” ์˜ค๋ฅ˜ ์—†์ด ๋‹ค๋ฅธ ๊ณต์žฅ์ด ๋œฌ๋‹ค. */\n reg.kind,\n reg.model as TwinModelDef,\n /* ์ €์žฅ๋œ ๊ฐ’์€ ์œ„์—์„œ **์—„๊ฒฉํžˆ** ์ฝ์—ˆ๋‹ค โ€” ๋ชจ๋ฅด๋Š” ๊ฐ’์„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ๋ฉ”์šฐ๋ฉด ๊ทธ ํŠธ์œˆ์ด ์กฐ์šฉํžˆ ๋‹ค๋ฅด๊ฒŒ ์žฌ๊ธฐ๋™ํ•œ๋‹ค. */\n policy,\n reg.purpose,\n Number(last?.max ?? 0) || 0\n )\n }\n\n /**\n * ์„ ์–ธ ๊ธฐ๋ฐ˜ ๋ถ€ํŒ…(ยง0 ํ”„๋ ˆ์ž„ โ‘  โ†’ ๋ถ€ํŒ… ๊ฑฐ๋™ ๋งคํ•‘) โ€” ํŠธ์œˆ์ด ์„ ์–ธํ•œ restartPolicy ์— ๋”ฐ๋ผ ์žฌ๊ธฐ๋™ ๋ฐฉ์‹์„ ๊ตฌ๋ถ„ํ•œ๋‹ค.\n * ๋ถ€ํŒ… ๊ฒฝ๋กœ๋ฅผ ํ•œ ๊ณณ์— ๋ชจ์•„ \"๋Ÿฐํƒ€์ž„ โ‰  ํ˜„์‹ค\" ๋ฒ”์ฃผ์˜ค๋ฅ˜๋ฅผ ์ฝ”๋“œ๋กœ ๊ฐ•์ œํ•œ๋‹ค.\n * - 'resync' : ํ˜„์‹ค=์™ธ๋ถ€ ์‹ค๋ฌผ โ†’ startLive(์žฌ๋™๊ธฐ). ์ด๋ฒคํŠธ๋Š” ์–ด๋Œ‘ํ„ฐ ingest ๋กœ ์œ ์ž…, ์ปค๋„ tick ์—†์Œ.\n * - 'resume' : ์ƒ์„ฑ ํƒ€์ž„๋ผ์ธ ์ง€์† โ†’ ์ €๋„ ๋ณด์กด + resume(ํ˜„์‹ค ์ด์–ด๊ฐ).\n * โš  GATE(ยง8 โ‘กโ‘ข): ์ปค๋„ ์ƒํƒœ ์ง๋ ฌํ™”/์žฌ๊ฐœ๊ฐ€ ์•„์ง ์—†์–ด ์ง„์งœ resume ๋ถˆ๊ฐ€ โ†’ ์‹ค ํ•„์š”ยท์‹ค๋ถ€ํ•˜ ์‹œ ๊ตฌํ˜„.\n * ๊ทธ๋•Œ๊นŒ์ง€๋Š” ์ €๋„์„ ๋ณด์กดํ•˜๋˜ revision ์ถฉ๋Œ์„ ํ”ผํ•˜๋ ค fresh ๋กœ ๊ธฐ๋™ํ•˜๊ณ , ์„ ์–ธ๊ณผ ๊ตฌํ˜„์˜ ๊ฐ„๊ทน์„ ํฌ๊ฒŒ ๊ฒฝ๊ณ ํ•œ๋‹ค.\n * - 'reset' : seed ์žฌํ˜„ โ†’ resetJournal + fresh ๊ธฐ๋™(๋ฐฑ์ง€ ์‹œ์ž‘์ด ๋ฒ„๊ทธ๊ฐ€ ์•„๋‹ˆ๋ผ ์„ ์–ธ๋œ ๊ฑฐ๋™).\n * ๋ฐ˜ํ™˜: ๊ธฐ๋™๋œ InstanceRuntime.\n */\n static async bootDeclared(domainId: string, instanceId: string, mode: RestartPolicy): Promise<InstanceRuntime> {\n if (mode === 'resync') {\n const reg = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!reg?.model) throw new Error(`instance \"${instanceId}\" not provisioned (no model)`)\n return this.startLive(instanceId, domainId, reg.kind, reg.model as TwinModelDef)\n }\n if (mode === 'resume') {\n /*\n * **์ด์–ด์ง€๋Š” ํ˜„์‹ค** โ€” ์ €๋„์„ ์ง€์šฐ์ง€ ์•Š๋Š”๋‹ค.\n *\n * ์˜ˆ์ „์—๋Š” ์—ฌ๊ธฐ์„œ ์ €๋„์„ ์ง€์šฐ๊ณ  fresh ๋กœ ๋„์› ๋‹ค. resume ๊ธฐ๊ณ„์žฅ์น˜๊ฐ€ ์—†๋‹ค๊ณ  ๋ดค๊ธฐ ๋•Œ๋ฌธ์ธ๋ฐ,\n * ์‹ค์ œ๋กœ ์—†๋˜ ๊ฒƒ์€ **๋ฒˆํ˜ธ ์ด์–ด ์„ธ๊ธฐ ํ•˜๋‚˜**์˜€๋‹ค: ์ƒํƒœ ๋ณต์›์€ ์ด๋ฏธ `startFromRegistry` ๊ฐ€\n * ์ €๋„ ์žฌ์ƒ(๋˜๋Š” ์ฒดํฌํฌ์ธํŠธ)์œผ๋กœ ํ•˜๊ณ  ์žˆ์—ˆ๊ณ , ๋ง‰ํžŒ ๊ฒƒ์€ ์ปค๋„์ด ๋ฆฌ๋น„์ „์„ 0๋ถ€ํ„ฐ ๋‹ค์‹œ ์„ธ์–ด\n * ๊ธฐ์กด ํ–‰๊ณผ ๊ฒน์น˜๋Š” ๋ฌธ์ œ์˜€๋‹ค. ๊ทธ ํ•˜๋‚˜๋ฅผ `resumeRevision` ์œผ๋กœ ํ’€์—ˆ์œผ๋ฏ€๋กœ ์ด์ œ ์ด์–ด ๊ฐ„๋‹ค.\n *\n * ์•„์ง ์ด์–ด์ง€์ง€ ์•Š๋Š” ๊ฒƒ(์ •์งํ•˜๊ฒŒ): ์‹œ๋‚˜๋ฆฌ์˜ค ์ƒ์„ฑ๊ธฐ์˜ ๋‚œ์ˆ˜ ํ๋ฆ„์€ ์žฌ๊ธฐ๋™์— ์ด์–ด์ง€์ง€ ์•Š๋Š”๋‹ค โ€”\n * ๊ฐ™์€ ์”จ์•—์—์„œ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜๋ฏ€๋กœ ์ž๊ทน์˜ ํŒจํ„ด์ด ์žฌ๊ธฐ๋™ ์ง€์ ์—์„œ ํ•œ ๋ฒˆ ๋Š๊ธด๋‹ค. ์Œ“์ธ ์‚ฌ์‹ค๊ณผ\n * ์ƒํƒœ๋Š” ์ด์–ด์ง€๊ณ , ์•ž์œผ๋กœ ์ผ์–ด๋‚  ์ผ์˜ ๋ฌด์ž‘์œ„ ์ˆœ์„œ๋งŒ ์ƒˆ๋กœ ์‹œ์ž‘ํ•œ๋‹ค.\n */\n return this.startFromRegistry(domainId, instanceId, 'resume')\n }\n // `reset`: seed ์žฌํ˜„ โ€” ์ €๋„ ์ดˆ๊ธฐํ™” ํ›„ revision 0 ๋ถ€ํ„ฐ ์žฌ์‹คํ–‰.\n await this.resetJournal(domainId, instanceId)\n return this.startFromRegistry(domainId, instanceId, 'reset')\n }\n\n /**\n * ์ €๋„ ์ดˆ๊ธฐํ™” โ€” ์ธ์Šคํ„ด์Šค ์ด๋ฒคํŠธ ์ €๋„ purge(๋ ˆ์ง€์ŠคํŠธ๋ฆฌยท์ƒํƒœ๋Š” ์œ ์ง€).\n * ๋ฐ๋ชจ fresh-start ์šฉ: ๋งค ๋ถ€ํŒ… seed ๋ถ€ํ„ฐ ์ƒˆ๋กœ ์‹คํ–‰ํ•˜๋Š” ๋ฐ๋ชจ์—์„œ, ๋ณต๊ตฌ๋ณธ ํ๊ธฐ ํ›„ revision 0 ๋ถ€ํ„ฐ ์žฌ์‹คํ–‰ํ•˜๋ฉด\n * ์˜› ๋Ÿฐ๊ณผ revision ์ด ๊ฒน์ณ ์ €๋„์ด ์˜ค์—ผ๋œ๋‹ค โ†’ start ์ „์— ํ˜ธ์ถœํ•ด ํ˜„์žฌ ๋Ÿฐ๋งŒ ๋‚จ๊ธด๋‹ค.\n */\n static async resetJournal(domainId: string, instanceId: string): Promise<void> {\n await getRepository(TwinEvent).delete({ domain: { id: domainId } as any, instanceId })\n delete this.recovered[runtimeKey(domainId, instanceId)]\n /*\n * โ”€โ”€ **์ฒดํฌํฌ์ธํŠธ๋„ ํ•จ๊ป˜ ๋ฌดํšจ๋กœ ๋งŒ๋“ ๋‹ค** (2026-08-20) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n *\n * ์ €๋„๋งŒ ์ง€์šฐ๋ฉด ์”จ์•— ์žฌํ˜„์ด ๋˜์ง€ ์•Š๋Š”๋‹ค: ์›œ์Šคํƒ€ํŠธ๋Š” ์ฒดํฌํฌ์ธํŠธ๋ฅผ **๋จผ์ €** ๋ณด๊ณ , ๊ทธ๊ฒƒ์ด ๋‚จ์•„ ์žˆ์œผ๋ฉด\n * ๋ฐฑ์ง€๋กœ ์‹œ์ž‘ํ•œ ํŠธ์œˆ์— ์˜› ์ƒํƒœ๊ฐ€ ๋˜์‚ด์•„๋‚œ๋‹ค(์ €๋„์€ ๋น„์—ˆ๋Š”๋ฐ ์žฌ๊ณ ๊ฐ€ ์žˆ๋Š” ํŠธ์œˆ์ด ๋œ๋‹ค).\n * ์‹œ๊ฐ„์—ฌํ–‰์ด ๋”›๋Š” ์‚ฌ์Šฌ ์บ์‹œ๋„ ๊ฐ™์€ ์ด์œ ๋กœ ๋ฌดํšจ๋‹ค โ€” ์ง€์›Œ์ง„ ๋ฆฌ๋น„์ „์„ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ๋œ๋‹ค.\n *\n * ๊ณตํ†ต ์บ์‹œ ์„œ๋น„์Šค์—๋Š” ์‚ญ์ œ๊ฐ€ ์—†๋‹ค(get/set/clearStale ๋ฟ). ๊ทธ๋ž˜์„œ **ใ€Œ์—†์Œใ€์„ ์ ๋Š”๋‹ค** โ€” ๊ฐ’์„\n * ์ง€์–ด๋‚ด๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ใ€Œ์ฒดํฌํฌ์ธํŠธ๊ฐ€ ์—†๋‹คใ€๋Š” ์‚ฌ์‹ค์„ ์ ๋Š” ๊ฒƒ์ด๊ณ , ์ฝ๋Š” ์ชฝ์€ ์ด๋ฏธ `cached?.state` ๋กœ\n * ๊ทธ๊ฒƒ์„ ๊ฐ€๋ ค๋‚ธ๋‹ค. ๊ณตํ†ต ๋ชจ๋“ˆ์— ์‚ญ์ œ๋ฅผ ์ƒˆ๋กœ ๋šซ๋Š” ๊ฒƒ์€ ์ด ํ•œ ์ž๋ฆฌ๋ฅผ ์œ„ํ•ด ํ•˜๊ธฐ์—๋Š” ํฐ ๋ณ€๊ฒฝ์ด๋‹ค.\n */\n await cacheService\n .setInCache(this.SNAPSHOT_CACHE_ID, { domainId, instanceId }, { revision: 0, state: null }, this.SNAPSHOT_TTL_S)\n .catch(err => twinWarn(`[twin-engine] \"${instanceId}\" checkpoint not invalidated โ€” a seed run may inherit old state:`, err?.message ?? err))\n await cacheService\n .setInCache(this.CHAIN_INDEX_CACHE_ID, { domainId, instanceId }, { revisions: [] }, this.SNAPSHOT_TTL_S)\n .catch(err => twinWarn(`[twin-engine] \"${instanceId}\" chain index not cleared โ€” time travel may point at deleted revisions:`, err?.message ?? err))\n }\n\n /** ์‚ญ์ œ โ€” ์ •์ง€ + ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์‚ญ์ œ + ์ €๋„ purge(domain ์Šค์ฝ”ํ”„). */\n static async remove(domainId: string, instanceId: string): Promise<void> {\n await this.stop(domainId, instanceId)\n this.forgetInstance(domainId, instanceId)\n await getRepository(TwinEvent).delete({ domain: { id: domainId } as any, instanceId })\n await getRepository(TwinInstance).delete({ domain: { id: domainId } as any, instanceId })\n }\n\n /**\n * ์ด ํŠธ์œˆ์— ๋Œ€ํ•ด **๋ฉ”๋ชจ๋ฆฌ์— ๋‚จ์€ ๊ฒƒ์„ ์ „๋ถ€ ์žŠ๋Š”๋‹ค** โ€” ์ง€์›€์˜ ํ•œ ์ž๋ฆฌ.\n *\n * ์บ์‹œ๊ฐ€ ๋ผ์ดํ”„์‚ฌ์ดํด๊ณผ ์–ด๊ธ‹๋‚˜ ์žˆ์—ˆ๋‹ค: ์ €๋„ยท๋“ฑ๋ก๋ถ€๋Š” ์ง€์šฐ๋ฉด์„œ ์ธ์Šคํ„ด์Šค๋ณ„ ์บ์‹œ๋Š” ๋‚จ๊ฒจ, ์‚ญ์ œ๋œ ํŠธ์œˆ์˜\n * ํ•ญ๋ชฉ์ด **์„œ๋ฒ„ ์žฌ๊ธฐ๋™๊นŒ์ง€ ์‚ด์•„ ์žˆ์—ˆ๋‹ค.** ํ•ญ๋ชฉ ํ•˜๋‚˜๊ฐ€ ํ•˜๋ฃจ์น˜ KPI ๊ทธ๋ฃน์„ ๋ฌผ๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์žŠ์ง€ ์•Š์œผ๋ฉด\n * ์ง€์šด ํŠธ์œˆ์ด ๊ณ„์† ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ฐจ์ง€ํ•œ๋‹ค. TTL ์€ ๊ฐ’์ด ๋‚ก๋Š” ๊ฒƒ์„ ๋ง‰์„ ๋ฟ **์—†์–ด์ง„ ์ฃผ์ธ์„ ์ง€์šฐ์ง€ ์•Š๋Š”๋‹ค.**\n *\n * ์žŠ์„ ๊ฒƒ์„ ์—ฌ๊ธฐ ๋ชจ์•„ ๋‘๋Š” ์ด์œ : ์บ์‹œ๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“œ๋Š” ์‚ฌ๋žŒ์ด ์ง€์šฐ๋Š” ์ž๋ฆฌ๋ฅผ ์ฐพ์•„ ํ—ค๋งค์ง€ ์•Š๊ฒŒ ํ•œ๋‹ค.\n * ์ƒˆ ์ธ์Šคํ„ด์Šค๋ณ„ ์บ์‹œ๋ฅผ ๋งŒ๋“ค๋ฉด **์ด ํ•จ์ˆ˜์— ํ•œ ์ค„์„ ๋”ํ•œ๋‹ค** โ€” ๊ทธ๋Ÿฌ์ง€ ์•Š์œผ๋ฉด ๊ฐ™์€ ๋ˆ„์ˆ˜๊ฐ€ ๋‹ค์‹œ ์ƒ๊ธด๋‹ค.\n */\n private static forgetInstance(domainId: string, instanceId: string): void {\n const key = runtimeKey(domainId, instanceId)\n delete this.recovered[key]\n this.measuredCache.delete(key)\n delete this.structureRevCache[key]\n }\n\n /** ๊ด€๋ฆฌ ๋ชฉ๋ก โ€” domain ์˜ ๋“ฑ๋ก ์ธ์Šคํ„ด์Šค ์ „์ฒด(๋ผ์ด๋ธŒ ์—ฌ๋ถ€ยท์ตœ์‹  ์ €๋„ revisionยท๋…ธ๋“œ/๋ฌด๋ฒ„ ์ˆ˜ ํฌํ•จ). */\n static async list(domainId: string): Promise<any[]> {\n const rows = await getRepository(TwinInstance).find({ where: { domain: { id: domainId } } })\n /*\n * **ํ˜„์žฅ ์ด๋ฆ„์„ ํ•จ๊ป˜ ๋‚ธ๋‹ค** โ€” ๋ชฉ๋ก์ด `spaceId` ๋งŒ ๋‚ด๋ณด๋‚ด์„œ ํ™”๋ฉด์ด ์ด๋ฆ„์„ ๋”ฐ๋กœ ์กฐํšŒํ•˜๊ณ  ์žˆ์—ˆ๋‹ค.\n * ๊ทธ ์กฐํšŒ(`twinSpaces`)๋Š” ๊ณต๊ฐ„๋งˆ๋‹ค ์นด์šดํŠธ ์ฟผ๋ฆฌ๋ฅผ ๋„๋Š” N+1 ์ด๋ผ ๋А๋ฆฌ๊ณ , ๊ทธ ์‚ฌ์ด ํ™”๋ฉด์€ **id ๋ฅผ\n * ์ด๋ฆ„์ฒ˜๋Ÿผ** ๋ณด์—ฌ ์ค€๋‹ค(2026-08-13 ๊ด€์ธก: ใ€Œํ˜„์žฅ crew-probe-siteใ€). ํ•œ ๋ฒˆ์— ์ฝ์–ด map ์œผ๋กœ ๋ถ™์ด๋ฉด\n * ์™•๋ณต๋„ ์ค„๊ณ  ๊ทธ ๊นœ๋นก์ž„๋„ ์‚ฌ๋ผ์ง„๋‹ค. ์ด๋ฆ„์ด ์—†์œผ๋ฉด **๋น„์šด๋‹ค** โ€” id ๋ฅผ ์ด๋ฆ„์œผ๋กœ ๋ฒ ๋ผ์ง€ ์•Š๋Š”๋‹ค.\n */\n const spaceNameOf = new Map(\n (await getRepository(TwinSpace).find({ where: { domain: { id: domainId } } })).map(s => [s.spaceId, s.name])\n )\n /*\n * **์ตœ์‹  ๋ฆฌ๋น„์ „์€ ํŠธ์œˆ๋งˆ๋‹ค ์ธ๋ฑ์Šค ๋์—์„œ ํ•œ ํ–‰์”ฉ ์ฝ๋Š”๋‹ค.**\n *\n * โ”€โ”€ ๊ทธ๋ฃน ์งˆ์˜๋กœ ๋ฐ”๊พธ์—ˆ๋‹ค๊ฐ€ ๋˜๋Œ๋ ธ๋‹ค (2026-08-22 ์‹ค์ธก) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์˜ˆ์ „ ์ฃผ์„์€ ์ด๋žฌ๋‹ค: ใ€ŒํŠธ์œˆ๋งˆ๋‹ค `findOne(order revision DESC)` ์„ ๋Œ๊ณ  ์žˆ์—ˆ๋‹ค โ€” 13๊ฐœ๋ฉด ์งˆ์˜\n * 13๋ฒˆ์ด๊ณ , ํŠธ์œˆ์ด ๋Š˜๋ฉด ๊ทธ๋Œ€๋กœ ์ž๋ž€๋‹ค. ํ•œ ๋ฒˆ์˜ ๊ทธ๋ฃน ์งˆ์˜๋กœ ๋ฐ”๊พผ๋‹ค.ใ€\n *\n * **์งˆ์˜ ๊ฐœ์ˆ˜๋ฅผ ์ค„์˜€์ง€๋งŒ ์ผ์˜ ์–‘์„ ๋Š˜๋ ธ๋‹ค.**\n *\n * findOne ร— 13 `(domain, instance, revision)` ์ธ๋ฑ์Šค **๋์—์„œ ํ•œ ํ–‰** โ€” ๊ฐ๊ฐ O(1)\n * GROUP BY ํ•œ ๋ฒˆ ๊ทธ ๋„๋ฉ”์ธ์˜ ์ €๋„์„ **์ „์ˆ˜ ์ง‘๊ณ„** โ€” O(์ „์ฒด)\n *\n * ์ €๋„์ด ์ž‘์„ ๋•Œ๋Š” ์ด๋“์ด์—ˆ๊ณ , ์ปค์ง€๋ฉด์„œ ์†ํ•ด๊ฐ€ ๋๋‹ค. ์‹ค์ธก(์ €๋„ 1,134๋งŒ ํ–‰): ์ด ๊ทธ๋ฃน ์งˆ์˜๊ฐ€\n * **44.7์ดˆ**์˜€๋‹ค. ๊ทธ๋ฆฌ๊ณ  sqlite ๋“œ๋ผ์ด๋ฒ„๋Š” ์—ฐ๊ฒฐ์ด ํ•˜๋‚˜์ด๋ฏ€๋กœ ๊ทธ๋™์•ˆ ์•ฑ์˜ ๋ชจ๋“  ์งˆ์˜๊ฐ€ ๊ทธ ๋’ค์— ์„ฐ๋‹ค โ€”\n * ๊ฐ™์€ ์ˆœ๊ฐ„ 29ํ–‰์งœ๋ฆฌ `twin_instances` ์กฐํšŒ๋„ 44.7์ดˆ๋กœ ์ฐํ˜”๋‹ค. ์ด ๋ชฉ๋ก์€ ใ€ŒํŠธ์œˆ ๊ด€๋ฆฌยทํ˜„์žฅ ๊ตฌ์„ฑยท\n * ์—”ํ‹ฐํ‹ฐ ํŒจ๋„์ด ๋ชจ๋‘ ์ฝ๋Š” ์ž๋ฆฌใ€์—ฌ์„œ, ํ™”๋ฉด์„ ์—ด ๋•Œ๋งˆ๋‹ค ์„œ๋ฒ„ ์ „์ฒด๊ฐ€ ๊ทธ๋งŒํผ ๋ฉˆ์ท„๋‹ค.\n *\n * ํŠธ์œˆ ์ˆ˜๋Š” ์ˆ˜์‹ญ์ด๊ณ  ์ €๋„์€ ์ฒœ๋งŒ์ด๋‹ค. **์ž‘์€ ๊ฒƒ์„ ์—ฌ๋Ÿฌ ๋ฒˆ ์ฝ๋Š” ํŽธ์ด ํฐ ๊ฒƒ์„ ํ•œ ๋ฒˆ ํ›‘๋Š” ๊ฒƒ๋ณด๋‹ค ์‹ธ๋‹ค.**\n * ์งˆ์˜ ๊ฐœ์ˆ˜๊ฐ€ ํŠธ์œˆ ์ˆ˜์— ๋น„๋ก€ํ•ด ์ž๋ผ๋Š” ๊ฒƒ์€ ์‚ฌ์‹ค์ด์ง€๋งŒ, ๊ฐ ์งˆ์˜๊ฐ€ ์ธ๋ฑ์Šค ๋ ํ•œ ํ–‰์ด๋ฏ€๋กœ ๊ทธ ์„ฑ์žฅ์€\n * ๊ฐ๋‹น๋œ๋‹ค โ€” ๊ทธ๋ฆฌ๊ณ  ๋ณ‘๋ ฌ๋กœ ๋ฌป๋Š”๋‹ค.\n *\n * **๋‹ค์‹œ ๊ทธ๋ฃน ์งˆ์˜๋กœ ๋ฐ”๊พธ์ง€ ๋ง ๊ฒƒ.** ๋ฐ”๊พธ๋ ค๋ฉด ์ด ์ˆซ์ž๋ฅผ ๋จผ์ € ๋‹ค์‹œ ์žฌ๋ผ.\n */\n const tipOfInstance = new Map<string, number>()\n await Promise.all(\n rows.map(async r => {\n try {\n /*\n * **์ง‘๊ณ„ ํ•˜๋‚˜๋กœ ๋ฌป๋Š”๋‹ค โ€” ํ–‰์„ ์‹ค์–ด ์˜ค์ง€ ์•Š๋Š”๋‹ค.**\n *\n * `findOne(order revision DESC)` ๋กœ ๋‘์—ˆ๋”๋‹ˆ ๋‘ ๊ฐ€์ง€๊ฐ€ ํ‹€๋ ธ๋‹ค. โ‘  ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง„ ์—”ํ‹ฐํ‹ฐ์˜ ์ •๋ ฌ\n * ์กฐํšŒ๋Š” TypeORM ์ด `DISTINCT` ๋กœ ๊ฐ์‹ธ๋ฏ€๋กœ `select` ๋กœ ์ปฌ๋Ÿผ์„ ์ขํžˆ๋ฉด `distinctAlias.\n * TwinEvent_id` ๊ฐ€ ์—†๋‹ค๊ณ  ํ„ฐ์ง„๋‹ค(์‹ค์ธก: ๋ชจ๋“  ํŠธ์œˆ์—์„œ SQLITE_ERROR). โ‘ก `select` ๋ฅผ ๋–ผ๋ฉด\n * **`payload` ๊นŒ์ง€ ์‹ค์–ด ์˜จ๋‹ค** โ€” ์ด ๊ฐ’ ํ•˜๋‚˜๋ฅผ ์•Œ๋ ค๊ณ  ํฐ TEXT ๋ฅผ ์ฝ๋Š”๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ ๋‹จ์ผ ์ง‘๊ณ„๋ฅผ ์“ด๋‹ค. `(domain, instance, revision)` ์ธ๋ฑ์Šค์—์„œ instance ๊ฐ€ ์ •ํ•ด์ง€๋ฉด\n * `MAX` ๋Š” ๊ทธ ๊ตฌ๊ฐ„์˜ ๋์ด๋ฏ€๋กœ sqlite ๊ฐ€ ๋์„ ์ง‘๋Š”๋‹ค(์‹ค์ธก 0.007์ดˆ ยท ๋„๋ฉ”์ธ ์ „์ฒด GROUP BY ๋Š”\n * 14.5์ดˆ). ์ด ํŒŒ์ผ์˜ ๋‹ค๋ฅธ ์ž๋ฆฌ๋„ ๊ฐ™์€ ๊ทœ์œจ์ด๋‹ค(ยง`timeRange` ยท ๊ธฐ๋™ ์‹œ ์ตœ์ข… ๋ฆฌ๋น„์ „).\n */\n const row = await getRepository(TwinEvent)\n .createQueryBuilder('e')\n .select('MAX(e.revision)', 'revision')\n .where('e.domain = :domainId', { domainId })\n .andWhere('e.instanceId = :instanceId', { instanceId: r.instanceId })\n .getRawOne<{ revision: unknown }>()\n /* ํ–‰์ด ์—†์œผ๋ฉด `null` ์ด๋‹ค โ€” ๊ทธ๋•Œ๋Š” ๋น„์›Œ ๋‘”๋‹ค(0 ์€ \"์•„๋ฌด ์ผ๋„ ์—†์—ˆ๋‹ค\" ๋Š” ์ฃผ์žฅ์ด๋‹ค). */\n if (row?.revision != null) tipOfInstance.set(String(r.instanceId), Number(row.revision) || 0)\n } catch (err: any) {\n /* ํ•œ ํŠธ์œˆ์˜ ์กฐํšŒ๊ฐ€ ์‹คํŒจํ•ด๋„ **0 ์œผ๋กœ ๋ฉ”์šฐ์ง€ ์•Š๋Š”๋‹ค** โ€” ๋ฆฌ๋น„์ „ 0 ์€ \"์•„์ง ์•„๋ฌด ์ผ๋„ ์—†์—ˆ๋‹ค\" ๋Š”\n ์‚ฌ์‹ค ์ฃผ์žฅ์ด๋‹ค. ๋น„์›Œ ๋‘๋ฉด ์•„๋ž˜์—์„œ undefined ๋กœ ๋‚จ๊ณ , ํ™”๋ฉด์€ ๊ทธ๊ฒƒ์„ \"๋ชจ๋ฆ„\" ์œผ๋กœ ๊ทธ๋ฆฐ๋‹ค.\n ๊ทธ๋ฆฌ๊ณ  ๊ทธ ํŠธ์œˆ๋งŒ ๋ชจ๋ฆ„์ด ๋œ๋‹ค โ€” ์˜ˆ์ „์—๋Š” ์ง‘๊ณ„ ํ•˜๋‚˜๊ฐ€ ์‹คํŒจํ•˜๋ฉด ์ „๋ถ€ ๋ชจ๋ฆ„์ด์—ˆ๋‹ค. */\n twinError(`[twin-engine] latest revision lookup failed \"${r.instanceId}\"`, err?.message ?? err)\n }\n })\n )\n\n const out: any[] = []\n for (const r of rows) {\n const model = (r.model as TwinModelDef) ?? { locations: [], equipment: [] }\n out.push({\n instanceId: r.instanceId,\n /*\n * **์ด๋ฆ„์„ ํ•จ๊ป˜ ๋‚ธ๋‹ค.** ์—…๋ฌดํ‚ค(`instanceId`)๋งŒ ๋‚ด๋ณด๋‚ด๊ณ  ์žˆ์–ด์„œ ๋ชฉ๋ก์ด `crew-two` ๋งŒ ๋ณด์˜€๋‹ค โ€”\n * ์—…๋ฌดํ‚ค๋ฅผ ๋‚˜๋ˆ  ๋‘” ์„ค๊ณ„์—์„œ๋Š” ์ด๋ฆ„์„ ๊ฐ™์ด ์‹ค์–ด์•ผ ๊ทธ ๋‚˜๋ˆ”์ด ๊ฐ’์„ ํ•œ๋‹ค.\n * ์—†์œผ๋ฉด `undefined` ๋‹ค(id ๋ฅผ ๋ฒ ๋ผ์ง€ ์•Š๋Š”๋‹ค โ€” ํ™”๋ฉด์ด ์ด๋ฆ„ ์—†์Œ์„ ์•Œ์•„๋ณผ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค).\n */\n name: r.name ?? undefined,\n description: r.description ?? undefined,\n kind: r.kind,\n status: r.status,\n spaceId: r.spaceId, // co-location: ๊ฐ™์€ spaceId ์ธ์Šคํ„ด์Šค๋“ค์ด ํ•œ ํ˜„์žฅ ๊ณต์œ  โ€” ํ˜„์žฅ๋ทฐ ์ง‘์•ฝ ํ‚ค(G7)\n /* ์‚ฌ๋žŒ์ด ์ฝ๋Š” ํ˜„์žฅ ์ด๋ฆ„ โ€” ์—†์œผ๋ฉด `undefined`(ํ™”๋ฉด์ด \"์ด๋ฆ„ ์—†์Œ\" ์„ ์•Œ์•„๋ณผ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค). */\n spaceName: (r.spaceId ? spaceNameOf.get(r.spaceId) : undefined) || undefined,\n restartPolicy: r.restartPolicy, // ์žฌ๊ธฐ๋™ ์ •์ฑ…(ADR-0029 ยง2) โ€” resync/resume/reset. ์„ ์–ธ์ด๋ฏ€๋กœ ๋น„์–ด ์žˆ์„ ์ˆ˜ ์—†๋‹ค.\n purpose: r.purpose, // ์šด์˜ vs ๋ฒค์น˜ ์‚ฌ๋ณธ(1๊ธ‰ ๊ตฌ๋ณ„ โ€” ์ด๋ฆ„ ์ ‘๋‘์‚ฌ ์•„๋‹˜). ์ €์žฅ ์‹œ ๊ฐ์ธ๋˜๋ฏ€๋กœ ๋น„์ง€ ์•Š๋Š”๋‹ค.\n copyOf: r.copyOf ?? undefined,\n running: !!this.instances[runtimeKey(domainId, r.instanceId)],\n /*\n * **๊ณ„์ธก์ด ๋“ค์–ด์˜ค๊ณ  ์žˆ๋‚˜** โ€” ใ€Œ๋„๋Š” ์ค‘ใ€๊ณผ ๋‹ค๋ฅธ ์‚ฌ์‹ค์ด๋‹ค.\n *\n * ๋ฏธ๋Ÿฌ ํŠธ์œˆ์€ ํ”ผ๋“œ๊ฐ€ ๋–จ์–ด์ ธ๋„ ์ปค๋„์ด ๋Œ๊ธฐ๋งŒ ํ•˜๋ฉด ใ€Œ๋„๋Š” ์ค‘ใ€์ด์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์•„๋ฌด๊ฒƒ๋„ ๋ฐ›์ง€ ์•Š๋Š”\n * ํŠธ์œˆ๊ณผ ํ๋ฅด๋Š” ํŠธ์œˆ์ด ํ™”๋ฉด์—์„œ ๋˜‘๊ฐ™์ด ๋ณด์˜€๋‹ค(์žฌ๊ธฐ๋™ ๋’ค ์‹ค์ œ๋กœ ๊ทธ๋žฌ๋‹ค). ์‹œ๋ฎฌยท์ •์ง€ ํŠธ์œˆ์—๋Š”\n * ใ€Œํ•ด๋‹น ์—†์Œใ€์ด๋‹ค โ€” ์—†์–ด์•ผ ํ•˜๋Š” ๊ฒƒ์„ ๋Š๊ฒผ๋‹ค๊ณ  ๋ถ€๋ฅด์ง€ ์•Š๋Š”๋‹ค.\n */\n /* ์Šค์Šค๋กœ ๋ฉˆ์ถ˜ ์ด์œ  โ€” ์žˆ์œผ๋ฉด ๋‚ธ๋‹ค. ์žฌ๊ธฐ๋™ ๋’ค์—๋Š” ์—†๋‹ค(๊ทธ๋•Œ๋Š” ใ€Œ๋ชจ๋ฅธ๋‹คใ€๊ฐ€ ์‚ฌ์‹ค์ด๋‹ค). */\n stopNote: this.stopNotes.get(runtimeKey(domainId, r.instanceId)) || undefined,\n liveFeed: liveFeedStateOf({\n restartPolicy: r.restartPolicy,\n running: !!this.instances[runtimeKey(domainId, r.instanceId)],\n instanceId: r.instanceId\n }),\n revision: tipOfInstance.get(r.instanceId) ?? 0,\n /*\n * **๋ฆฌ๋”๋ฅผ ๊ฑฐ์ณ ์„ผ๋‹ค** โ€” ๋ณด๋“œ ํ‚ค๋ฅผ ์ง์ ‘ ์ฝ์œผ๋ฉด ์˜› ์„ธ๋Œ€ ๋ชจ๋ธ์ด 0 ์œผ๋กœ ๋ณด์ธ๋‹ค.\n *\n * ์ปค๋„์€ ์ž๋ฆฌยท์„ค๋น„ ๋ฐฐ์—ด์˜ **์˜› ์„ธ๋Œ€ ํ‚ค๊นŒ์ง€ ํก์ˆ˜ํ•ด** ์ฝ์–ด ์ฃผ๋Š”๋ฐ, ์ด ๋ชฉ๋ก์€ ์ƒˆ ์ด๋ฆ„๋งŒ ์ง์ ‘\n * ์„ธ๊ณ  ์žˆ์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์˜› ๋ชจ๋ธ 12๊ฐœ๊ฐ€ ํ™”๋ฉด์— **์ž๋ฆฌ 0 ยท ์„ค๋น„ 0**\n * ์œผ๋กœ ๋–ด๋‹ค โ€” ์˜ค๋ฅ˜ ์—†์ด, ๊ทธ๋ƒฅ ๋นˆ ๊ณต์žฅ์ฒ˜๋Ÿผ. ์„ธ๋Š” ๊ทœ์น™์ด ๋‘ ๋ฒŒ์ด๋ฉด ์ด๋Ÿฐ ์‹์œผ๋กœ ์–ด๊ธ‹๋‚œ๋‹ค.\n */\n locationCount: readBoardLocations(model).length,\n equipmentCount: readBoardEquipment(model).length\n })\n }\n return out\n }\n\n /** ์šด์˜ ๊ณต๊ฐ„ ๋ชฉ๋ก(๋ฒค์น˜ ์†Œ์Šค ์„ ํƒ๊ธฐ) โ€” ์ด๋ฆ„ยท๊ทœ๋ชจ ํฌํ•จ, ๋ฒค์น˜ ์‚ฌ๋ณธ ์ œ์™ธ. */\n static async listSpaces(domainId: string): Promise<{ spaceId: string; name: string; instances: number; locations: number; equipment: number }[]> {\n const nameOf = new Map((await getRepository(TwinSpace).find({ where: { domain: { id: domainId } } })).map(s => [s.spaceId, s.name]))\n const insts = await getRepository(TwinInstance).find({ where: { domain: { id: domainId } } })\n const agg = new Map<string, { spaceId: string; name: string; instances: number; locations: number; equipment: number }>()\n for (const r of insts) {\n /* ๋ฒค์น˜ ์ œ์™ธ๋Š” **์„ ์–ธ์œผ๋กœ๋งŒ** ํŒ๋‹จํ•œ๋‹ค. ์˜ˆ์ „์—๋Š” spaceId ์ด๋ฆ„(`bench-`ยท`loadtest*`)์œผ๋กœ๋„ ์ถ”์ธกํ–ˆ๋Š”๋ฐ,\n ๊ทธ๋Ÿฌ๋ฉด ๊ทธ๋ ‡๊ฒŒ ์ด๋ฆ„ ์ง€์€ ์ง„์งœ ์šด์˜ ๊ณต๊ฐ„์ด ๋ชฉ๋ก์—์„œ ์กฐ์šฉํžˆ ์‚ฌ๋ผ์ง„๋‹ค. purpose ๊ฐ€ ์ •๋ณธ์ด๋‹ค. */\n if (!r.spaceId || r.purpose === 'bench') continue\n const model: any = r.model ?? {}\n const a = agg.get(r.spaceId) ?? { spaceId: r.spaceId, name: nameOf.get(r.spaceId) ?? r.spaceId, instances: 0, locations: 0, equipment: 0 }\n a.instances++\n /* ๋ชฉ๋ก๊ณผ **๊ฐ™์€ ๊ทœ์น™**์œผ๋กœ ์„ผ๋‹ค โ€” ์—ฌ๊ธฐ๋งŒ ์ง์ ‘ ์„ธ๋ฉด ๊ณต๊ฐ„ ์š”์•ฝ๊ณผ ์ธ์Šคํ„ด์Šค ๋ชฉ๋ก์ด ๋‹ค๋ฅธ ์ˆ˜๋ฅผ ๋งํ•œ๋‹ค. */\n a.locations += readBoardLocations(model).length\n a.equipment += readBoardEquipment(model).length\n agg.set(r.spaceId, a)\n }\n return [...agg.values()]\n }\n\n /** ์ธ์Šคํ„ด์Šค ๋ชฉ์  ํ‘œ์‹(์šด์˜/๋ฒค์น˜) ์„ค์ • โ€” ๋ฒค์น˜ ์‚ฌ๋ณธ์„ 1๊ธ‰ ์†์„ฑ์œผ๋กœ ๊ตฌ๋ณ„(์ด๋ฆ„ ์ ‘๋‘์‚ฌ ์•„๋‹˜). */\n static async setPurpose(domainId: string, instanceId: string, purpose: 'operational' | 'bench', copyOf?: string): Promise<void> {\n await getRepository(TwinInstance).update({ domain: { id: domainId } as any, instanceId }, { purpose, copyOf: copyOf ?? null } as any)\n }\n\n /**\n * ๊ณต๊ฐ„ ๊ตฌ์กฐ ํŒ๋… โ€” ์™„์ „๋ณต์ œ(๋ฒค์น˜ ์‚ฌ๋ณธ)์˜ ์†Œ์Šค. ์ €์žฅ๋ฌผ์ด model(์œ„์ƒ)ยทTwinSpace.content(์น˜์ˆ˜ยทgeoยทํ‘œํ˜„)ยทTwinArea(์˜์—ญ)๋กœ\n * ๋ถ„์‚ฐ๋ผ ์žˆ์œผ๋ฏ€๋กœ ์…‹์„ ๋ชจ์•„ ๋Œ๋ ค์ค€๋‹ค. ํ˜ธ์ถœ์ธก์ด ReferenceMaster ๋กœ ์žฌ๊ตฌ์„ฑ โ†’ ์žฌ์‹๋ณ„ โ†’ ingestMaster.\n */\n static async spaceStructure(domainId: string, spaceId: string): Promise<{\n name?: string\n /** ์„ค๊ณ„ ์ขŒํ‘œ๊ณ„ ๋ฒ”์œ„(๋ฏธํ„ฐ)์™€ ์ง€์˜ค๋ ˆํผ๋Ÿฐ์Šค โ€” ์‚ฌ๋ณธ์ด ์›๋ณธ๊ณผ ๊ฐ™์€ ์ž๋ฆฌ์— ์„œ๋ ค๋ฉด ํ•จ๊ป˜ ๊ฐ€์•ผ ํ•œ๋‹ค. */\n frame: { extentX?: number; extentY?: number; geo?: any; primaryRepresentationId?: string }\n areas: any[]\n instances: { instanceId: string; kind?: string; model: any }[]\n } | null> {\n const sp = await getRepository(TwinSpace).findOne({ where: { domain: { id: domainId }, spaceId } })\n const areas = sp\n ? (await getRepository(TwinArea).find({ where: { domain: { id: domainId } as any, space: { id: sp.id } as any } })).map(a => ({ id: a.areaId, type: a.type, name: a.name, parentId: a.parentId, layout: a.layout }))\n : []\n const insts = await getRepository(TwinInstance).find({ where: { domain: { id: domainId }, spaceId } })\n if (!insts.length) return null\n return {\n name: sp?.name,\n frame: { extentX: sp?.extentX, extentY: sp?.extentY, geo: sp?.geo, primaryRepresentationId: sp?.primaryRepresentationId },\n areas,\n instances: insts.map(i => ({ instanceId: i.instanceId, kind: i.kind, model: i.model }))\n }\n }\n\n /** ๊ณต๊ฐ„(+ํ‘œํ˜„ยท์˜์—ญ) ์‚ญ์ œ โ€” ๋ฒค์น˜ ์ •๋ฆฌ ๋“ฑ. ํ˜ธ์ถœ์ธก์ด ๋ฐ”์ธ๋”ฉ ์ธ์Šคํ„ด์Šค๋ฅผ ๋จผ์ € ์ œ๊ฑฐํ•˜๋Š” ์ „์ œ(๊ฐ€๋“œ ์—†์Œ). deleteTwinSpace ๋ฆฌ์กธ๋ฒ„์™€ ๋™ํ˜•. */\n static async deleteSpace(domainId: string, spaceId: string): Promise<void> {\n const space = await getRepository(TwinSpace).findOne({ where: { domain: { id: domainId }, spaceId } })\n if (space) {\n const reps = await getRepository(TwinSpaceRepresentation).find({ where: { domain: { id: domainId }, space: { id: space.id } } })\n for (const rep of reps) await getRepository(TwinSpaceArea).delete({ domain: { id: domainId } as any, representation: { id: rep.id } as any })\n await getRepository(TwinSpaceRepresentation).delete({ domain: { id: domainId } as any, space: { id: space.id } as any })\n await getRepository(TwinArea).delete({ domain: { id: domainId } as any, space: { id: space.id } as any })\n }\n await getRepository(TwinSpace).delete({ domain: { id: domainId } as any, spaceId })\n }\n\n /**\n * Face2 ๋งˆ์Šคํ„ฐ ์ธ์ œ์ŠคํŠธ(ADR-0018) โ€” ๋ ˆํผ๋Ÿฐ์Šค ์‹œ์Šคํ…œ(์‹ค ๋˜๋Š” ๊ฐ€์ƒ)์˜ ๋งˆ์Šคํ„ฐ๋ฅผ ์ฝ์–ด ํŠธ์œˆ์„ ์ƒ์„ฑ.\n * ์—”ํ‹ฐํ‹ฐ๋ฅผ ์†๋ฐฐ์„ /๋ฐœ๋ช…ํ•˜์ง€ ์•Š๊ณ  ๋งˆ์Šคํ„ฐ์—์„œ ๋ฐ˜์˜: ๊ณต๊ฐ„(Space) upsert + ์ธ์Šคํ„ด์Šค provision(๋ฏธ๊ธฐ๋™).\n * ๋…ธ๋“œํƒ€์ž…์€ ์ปค๋„ ์นดํƒˆ๋กœ๊ทธ๋กœ ๊ฒ€์ฆ(warning). start ๋Š” ํ˜ธ์ถœ์ธก(bootstrap/mutation)์ด ๊ฒฐ์ •.\n *\n * `into.spaceId` โ€” **์ด ํ˜„์žฅ์— ๋”ํ•œ๋‹ค.** ํ•œ ํ˜„์‹ค์„ ์—ฌ๋Ÿฌ ๋ Œ์ฆˆ(WMSยทMESยทYMS)๊ฐ€ ๋น„์ถ”๋ฏ€๋กœ ์ƒˆ ํŠธ์œˆ์ด\n * ๊ธฐ์กด ๊ณต๊ฐ„์œผ๋กœ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋‹ค. ์•„๋ž˜ ๋ณ‘ํ•ฉ์€ ์›๋ž˜ ๊ทธ ๊ฒฝ์šฐ๋ฅผ ์œ„ํ•ด ์žˆ์—ˆ๋Š”๋ฐ(N:1) ๋งŒ๋“œ๋Š” ํ๋ฆ„์—์„œ\n * ๊ณต๊ฐ„์„ ๊ณ ๋ฅผ ๋ฐฉ๋ฒ•์ด ์—†์—ˆ๋‹ค โ€” ๋งˆ์Šคํ„ฐ๊ฐ€ ํŒŒ์ƒํ•œ id ๋งŒ ์“ฐ์˜€๋‹ค. ํŒ์ •์€ `resolveIngestSpace`(์ˆœ์ˆ˜).\n */\n static async ingestMaster(\n domainId: string,\n master: ReferenceMaster,\n /** ๋งŒ๋“ค์–ด์ง€๋Š” ํŠธ์œˆ์˜ ์žฌ๊ธฐ๋™ ์ •์ฑ… โ€” ์›๋ณธ์ด ์ •ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ **๋งŒ๋“œ๋Š” ์ชฝ์˜ ์„ ์–ธ**์ด๋‹ค(ADR-0029 ยง2). */\n restartPolicy: RestartPolicy,\n into?: { spaceId?: string },\n /** ๋ˆ„๊ฐ€ ์ธ์ œ์ŠคํŠธํ–ˆ๋‚˜ โ€” ์‚ฌ๋žŒ์ด ์—†๋Š” ๊ฒฝ๋กœ(๋ถ€ํŒ…)๋Š” ์ฃผ์ง€ ์•Š๋Š”๋‹ค(๊ฐ์‚ฌ ๊ธฐ๋ก์„ ์ง€์–ด๋‚ด์ง€ ์•Š๋Š”๋‹ค). */\n actor?: { id: string }\n ): Promise<{ instanceId: string; spaceId: string; warnings: IngestWarning[] }> {\n /*\n * **๊ฑฐ์ ˆํ•  ๊ฒƒ์ด๋ฉด ์•„๋ฌด๊ฒƒ๋„ ์“ฐ๊ธฐ ์ „์— ๊ฑฐ์ ˆํ•œ๋‹ค.**\n *\n * ๊ฐ€๋™ ์ค‘ ์žฌํ”„๋กœ๋น„์ €๋‹์€ `provision` ์ด ๋ง‰๋Š”๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ํ˜ธ์ถœ์€ ์ด ํ•จ์ˆ˜์˜ **๋งจ ๋**์ด๋ผ,\n * ๊ทธ๋•Œ๊นŒ์ง€ ๊ณต๊ฐ„ยทํ‘œํ˜„ยท๊ตฌ์—ญ(TwinArea)์€ ์ด๋ฏธ ์ €์žฅ๋œ ๋’ค์˜€๋‹ค. ์‚ฌ์šฉ์ž์—๊ฒŒ๋Š” \"์ธ์ œ์ŠคํŠธ ์‹คํŒจ\" ๋กœ\n * ๋ณด์ด๋Š”๋ฐ ์‹ค์ œ๋กœ๋Š” ์ ˆ๋ฐ˜์ด ์ ์šฉ๋œ ์ƒํƒœ โ€” ์‹คํŒจ๋ผ๊ณ  ๋งํ•˜๋ฉด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ”๊พธ๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ๋‚˜์˜๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ ํŒ์ •์„ ์•ž์œผ๋กœ ์˜ฎ๊ธด๋‹ค. ์•„๋ž˜ `provision` ์˜ ๊ฐ™์€ ํŒ์ •์€ ๊ทธ๋Œ€๋กœ ๋‘”๋‹ค โ€” ์ด๊ฑด ํŽธ์˜๋ฅผ ์œ„ํ•œ\n * ์•ž์„  ๊ฑฐ์ ˆ์ด๊ณ , ์ €๊ธฐ๊ฐ€ ์ง„์งœ ๋ฐฉ๋ฒฝ์ด๋‹ค(๋‹ค๋ฅธ ๊ฒฝ๋กœ๊ฐ€ ์ƒ๊ฒจ๋„ ์ง€์ผœ์ ธ์•ผ ํ•œ๋‹ค).\n *\n * **๋ฏธ๋Ÿฌ๋Š” ์—ฌ๊ธฐ์„œ ๊ฑฐ์ ˆํ•˜์ง€ ์•Š๋Š”๋‹ค.** ๋ฏธ๋Ÿฌ๊ฐ€ ๋น„์ถ”๋Š” ํ˜„์‹ค์€ ์•ˆ ๋ฉˆ์ถ”๋ฏ€๋กœ ๋™์ž‘ ์ค‘์— ์ „ํ™˜ํ•œ๋‹ค\n * (์•„๋ž˜ `adoptStructure`). ๊ฑฐ์ ˆ์€ ์‹œ๋ฎฌ๋ ˆ์ด์…˜์—๋งŒ ๋‚จ๋Š”๋‹ค โ€” ์กฐ๊ฑด์ด ๋ฐ”๋€ ์‹คํ—˜์€ ๋‹ค๋ฅธ ์‹คํ—˜์ด๋‹ค.\n */\n const running = this.instances[runtimeKey(domainId, master.source)]\n if (running && running.mode !== 'live') this.assertNotRunning(domainId, master.source)\n\n const { model, spaceContent, warnings } = masterToTwin(master, DOMAIN_CATALOG)\n /*\n * โ”€โ”€ ํ˜„์žฅ ์„ ์–ธ์„ ๋‹ค์‹œ ์–น๋Š”๋‹ค (2026-08-18) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n *\n * ์—ฌ๊ธฐ๊ฐ€ ใ€Œ์›์ฒœ์—์„œ ๋‹ค์‹œ ๊ทธ๋ฆฌ๋Š”ใ€ ์ž๋ฆฌ๋‹ค. ์š”๊ธˆ ๋‹จ๊ฐ€ยท๊ณ„์•ฝ ์ •๋ณด์ฒ˜๋Ÿผ **ํ˜„์žฅ์ด ์ •ํ•œ ์ˆ˜**๋Š” ์›์ฒœ์ด ๋ชจ๋ฅด๋ฏ€๋กœ\n * ๋‹ค์‹œ ๊ทธ๋ฆฌ๋ฉด ๊ทธ๋Œ€๋กœ ์‚ฌ๋ผ์ง„๋‹ค โ€” ๊ธˆ์•ก์ด ์‚ฌ๋ผ์ง€๊ณ , ์‚ฌ์šฉ์ž๋Š” ์ž๊ธฐ๊ฐ€ ๋„ฃ์€ ๊ฐ’์ด ์–ด๋””๋กœ ๊ฐ”๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค.\n * ๊ทธ๋ž˜์„œ ๊ฒน์œผ๋กœ ๋ณด๊ด€ํ•œ ์„ ์–ธ์„ ๋งค๋ฒˆ ๋‹ค์‹œ ์–น๋Š”๋‹ค(`engine/local-declarations`).\n *\n * ๋Œ€์ƒ์ด ์‚ฌ๋ผ์กŒ์œผ๋ฉด(๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ์—ˆ๋‹ค) ๊ทธ ์‚ฌ์‹ค์„ ๊ฒฝ๊ณ ๋กœ ๋‚ธ๋‹ค โ€” ๊ฐˆ ๊ณณ ์—†๋Š” ์„ ์–ธ์„ ์กฐ์šฉํžˆ ๋ฒ„๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.\n */\n const prior = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId: master.source } })\n /*\n * ๊ฒน์ด **๋‘˜**์ด๋‹ค โ€” ํ˜„์žฅ(๊ณต๊ฐ„)์˜ ๊ฒƒ๊ณผ ์ด ํŠธ์œˆ์˜ ๊ฒƒ. ์ˆœ์„œ๊ฐ€ ๊ทœ์œจ์ด๋‹ค: ํ˜„์žฅ ๋จผ์ €, ํŠธ์œˆ์ด ๋‚˜์ค‘.\n * ์š”๊ธˆ์ฒ˜๋Ÿผ ํ˜„์žฅ์ด ์ •ํ•œ ์ˆ˜๋Š” ๊ทธ ํ˜„์žฅ์˜ ํŠธ์œˆ ์ „๋ถ€๊ฐ€ ๊ฐ™์ด ์ฝ์–ด์•ผ ํ•˜๊ณ , ํ•œ ํŠธ์œˆ๋งŒ ๋‹ค๋ฅด๊ฒŒ ๋‘๋Š” ์‹คํ—˜์€\n * ์ข์€ ๊ฒน์ด ์ด๊ฒจ์•ผ ํ•œ๋‹ค(๋„“์€ ๊ฐ’์„ ๊ณ ์น˜๋ฉด ๋‚˜๋จธ์ง€ ํŠธ์œˆ์ด ํ•จ๊ป˜ ํ”๋“ค๋ฆฐ๋‹ค).\n */\n const priorSpaceId = prior?.spaceId ?? (model as any)?.spaceId\n const spaceRow = priorSpaceId\n ? await getRepository(TwinSpace).findOne({ where: { domain: { id: domainId }, spaceId: priorSpaceId } })\n : null\n if (prior?.localDeclarations || spaceRow?.localDeclarations) {\n const layered = applyDeclarationLayers(model as any, spaceRow?.localDeclarations as any, prior?.localDeclarations as any)\n Object.assign(model as any, layered.model)\n /*\n * ๊ฒน์„ **๋‹ค์‹œ ์ €์žฅํ•œ๋‹ค** โ€” ์—ฌ๊ธฐ์„œ ์–น์€ ๊ฒƒ์€ ์›์ฒœ์—์„œ ์ƒˆ๋กœ ๊ทธ๋ฆฐ ๋ชจ๋ธ์ด๋ฏ€๋กœ, ๊ทธ๋•Œ ์šฐ๋ฆฌ๊ฐ€ ๋ฎ์€ ๊ฐ’์ด\n * ๊ณง ์ง€๊ธˆ์˜ ์›์ฒœ ๊ฐ’์ด๋‹ค(`replaced`). ์ €์žฅํ•˜์ง€ ์•Š์œผ๋ฉด ๊ทธ ๊ธฐ์–ต์ด ๋‚ก์•„, ์ฒ ํšŒ๊ฐ€ ์˜› ์›์ฒœ ๊ฐ’์œผ๋กœ\n * ๋˜๋Œ๋ฆฐ๋‹ค โ€” ์›์ฒœ์ด ๊ทธ๋™์•ˆ ๊ฐ’์„ ๊ณ ์ณค์–ด๋„ ์•Œ ์ˆ˜ ์—†๋‹ค.\n */\n if (prior) {\n prior.localDeclarations = layered.instanceLayerApplied as any\n await getRepository(TwinInstance).save(prior)\n }\n if (spaceRow) {\n spaceRow.localDeclarations = layered.spaceLayerApplied as any\n await getRepository(TwinSpace).save(spaceRow)\n }\n /*\n * ๊ฐˆ ๊ณณ ์—†๋Š” ์„ ์–ธ์€ ๊ฒฝ๊ณ ๋กœ ๋‚ธ๋‹ค โ€” ๋‹ค๋งŒ **ํ˜„์žฅ ๊ฒน์˜ ๊ฒƒ์€ ๋บ€๋‹ค**: ํ•œ ํ˜„์žฅ์—๋Š” ์—ฌ๋Ÿฌ ์ข…๋ฅ˜์˜ ํŠธ์œˆ์ด\n * ์‚ด๊ณ (์ฐฝ๊ณ ยท์•ผ๋“œยท์—๋„ˆ์ง€), ์š”๊ธˆ ์ž๋ฆฌ๊ฐ€ ์—†๋Š” ํŠธ์œˆ์— ์š”๊ธˆ์ด ์–นํžˆ์ง€ ์•Š๋Š” ๊ฒƒ์€ ์ •์ƒ์ด๋‹ค.\n */\n for (const t of layered.missingTargets.filter(x => x.scope === 'instance')) {\n warnings.push(unresolvedReference('localDeclaration.target', `${t.target}:${t.id}`))\n }\n }\n const repo = getRepository(TwinSpace)\n /* ํ•ฉ์น  ๊ณต๊ฐ„์„ ๊ณจ๋ž์œผ๋ฉด **์žˆ๋Š”์ง€ ๋จผ์ € ํ™•์ธํ•œ๋‹ค** โ€” ์—†๋Š” ๊ณณ์— ์กฐ์šฉํžˆ ์ƒˆ ๊ณต๊ฐ„์„ ๋งŒ๋“ค๋ฉด ์‚ฌ์šฉ์ž๋Š”\n ํ•ฉ์ณค๋‹ค๊ณ  ๋ฏฟ๊ณ  ํ™”๋ฉด์€ ๋”ฐ๋กœ ๋…ผ๋‹ค. ํŒ์ • ํ•จ์ˆ˜๊ฐ€ ๊ทธ ๊ฒฝ์šฐ ๊ฑฐ์ ˆํ•œ๋‹ค. */\n const wanted = (into?.spaceId ?? '').trim()\n const wantedExists = wanted\n ? (await repo.count({ where: { domain: { id: domainId }, spaceId: wanted } })) > 0\n : false\n const choice = resolveIngestSpace(model.spaceId, wanted, wantedExists)\n const spaceId: string = choice.spaceId\n model.spaceId = spaceId // ๋ณด๋“œ(์ปค๋„ ์†Œ๋น„)๋„ ๊ฐ™์€ ๊ณต๊ฐ„์„ ๊ฐ€๋ฆฌ์ผœ์•ผ ํ•œ๋‹ค\n const existing = await repo.findOne({ where: { domain: { id: domainId }, spaceId } })\n if (choice.joined) {\n /* ๊ฐ™์€ id ์˜ ๊ตฌ์—ญยท๋žœ๋“œ๋งˆํฌ๋Š” ํ•ฉ์ง‘ํ•ฉ์œผ๋กœ ์ ‘ํžŒ๋‹ค โ€” ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์„ ๊ณ ๋ฅด์ง€ ์•Š๊ณ  ๋ฌด์—‡์ด\n ํ•ฉ์ณ์กŒ๋Š”์ง€ ๋งํ•œ๋‹ค(์ •๋‹นํ•œ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์œผ๋ฏ€๋กœ ๋ง‰์ง€ ์•Š๋Š”๋‹ค). */\n }\n /*\n * ๊ณต์œ  ๊ณต๊ฐ„(์—ฌ๋Ÿฌ ํŠธ์œˆ์ด ํ•œ spaceId, N:1) โ€” **๋จผ์ € ์“ด ๊ฐ’์ด ์ด๊ธด๋‹ค.**\n *\n * ๋งˆ์ง€๋ง‰ ์ธ์ œ์ŠคํŠธ๊ฐ€ ํ†ต์งธ๋กœ ๋ฎ์–ด์จ ํ‘œํ˜„ยท๊ตฌ์—ญ์ด ์œ ์‹ค๋˜๋˜ ๋ฌธ์ œ ๋ณด์ •. ์„ค๊ณ„ ์ขŒํ‘œ๊ณ„ ๋ฒ”์œ„์™€\n * ์ง€์˜ค๋ ˆํผ๋Ÿฐ์Šค๋Š” ๊ณต๊ฐ„์˜ ์„ฑ์งˆ์ด๋ผ ํŠธ์œˆ๋งˆ๋‹ค ๋‹ค๋ฅผ ์ˆ˜ ์—†๋‹ค โ€” ๋‘ ๋ฒˆ์งธ ํŠธ์œˆ์ด ๋“ค์–ด์˜ค๋ฉด์„œ ๋ฐ”๊พธ๋ฉด\n * ๋จผ์ € ๋†“์ธ ๊ตฌ์—ญ๋“ค์ด ํ†ต์งธ๋กœ ์–ด๊ธ‹๋‚œ๋‹ค. ๊ทธ๋ž˜์„œ ์ด๋ฏธ ์žˆ์œผ๋ฉด ๊ทธ๋Œ€๋กœ ๋‘”๋‹ค.\n */\n const cur: any = spaceContent\n const timezone = existing?.timezone || master.space.timezone\n const savedSpace = await repo.save(\n repo.create({\n ...(existing ?? {}),\n domain: { id: domainId } as any,\n spaceId,\n name: existing?.name || master.siteName,\n ...(timezone ? { timezone } : {}),\n extentX: existing?.extentX ?? cur.width,\n extentY: existing?.extentY ?? cur.depth,\n geo: existing?.geo ?? cur.geo,\n /*\n * ๋Œ€ํ‘œ ํ‘œํ˜„ ํฌ์ธํ„ฐ๋Š” **ํ‘œํ˜„์„ ์ €์žฅํ•œ ๋’ค** ์‹ค์ œ ํ–‰ id ๋กœ ์ฑ„์šด๋‹ค(์•„๋ž˜). ์—ฌ๊ธฐ์„œ ๋งˆ์Šคํ„ฐ์˜ ๋…ผ๋ฆฌ\n * id(`r-map` ๋”ฐ์œ„)๋ฅผ ๋„ฃ์œผ๋ฉด ํ‘œํ˜„ ํ–‰์€ ์ƒ์„ฑ uuid ๋ฅผ ๋ฐ›์œผ๋ฏ€๋กœ ํฌ์ธํ„ฐ๊ฐ€ **์ฒ˜์Œ๋ถ€ํ„ฐ ํ—ˆ๊ณต์„\n * ๊ฐ€๋ฆฌํ‚จ๋‹ค** โ€” ์‹ค์ œ๋กœ 13๊ฐœ ํ˜„์žฅ์ด ๊ทธ ์ƒํƒœ์˜€๊ณ  ์ •ํ•ฉ์„ฑ ์ ๊ฒ€์ด ์žก์•˜๋‹ค(2026-08-13). ํ™”๋ฉด์€\n * ํ–‰์˜ `isPrimary` ๋กœ โ˜…๋ฅผ ๊ทธ๋ ค์„œ ์ฆ์ƒ์ด ๋ณด์ด์ง€ ์•Š์•˜๋‹ค(์‚ฌ์‹ค์ด ๋‘ ๋ฒŒ์ด๋ฉด ์ด๋ ‡๊ฒŒ ์กฐ์šฉํ•˜๋‹ค).\n */\n primaryRepresentationId: existing?.primaryRepresentationId ?? null\n })\n )\n /*\n * ํ‘œํ˜„์„ twin_space_representations ํ…Œ์ด๋ธ”์— ์ €์žฅํ•œ๋‹ค โ€” ๋ทฐ(twin-map-page ๋“ฑ)๋Š” content ๊ฐ€ ์•„๋‹ˆ๋ผ ํ…Œ์ด๋ธ” ํ‘œํ˜„์„ ์†Œ์‹ฑํ•˜๋ฏ€๋กœ,\n * ์ €์žฅํ•˜์ง€ ์•Š์œผ๋ฉด ์ธ์ œ์ŠคํŠธ ์‚ฌ์ดํŠธ์— \"๋Œ€ํ‘œ ํ‘œํ˜„\" ์ด ์—†์–ด ์ง€๋„๋กœ ์‹œ์ž‘ํ•˜์ง€ ๋ชปํ•œ๋‹ค. rep.areas ๊ฐ€ ์žˆ์œผ๋ฉด TwinSpaceArea ๋„ ํ•จ๊ป˜ ์ €์žฅ.\n * ์ตœ์ดˆ ์ธ์ œ์ŠคํŠธ๋งŒ(๊ธฐ์กด ํ‘œํ˜„ ์žˆ์œผ๋ฉด ์‚ฌ์šฉ์ž ํŽธ์ง‘ ๋ณด์กด).\n */\n const repRepo = getRepository(TwinSpaceRepresentation)\n const areaRepo = getRepository(TwinSpaceArea)\n if ((await repRepo.count({ where: { space: { id: savedSpace.id } } })) === 0) {\n const reps: any[] = (spaceContent as any).representations ?? []\n for (let i = 0; i < reps.length; i++) {\n const rep = reps[i]\n const config =\n rep.type === 'map' ? { center: rep.center, zoom: rep.zoom }\n : rep.type === 'board' ? { boardId: rep.boardId }\n : rep.type === 'image' ? { imageUrl: rep.imageUrl, width: rep.width, height: rep.height }\n : {}\n const savedRep = await repRepo.save(repRepo.create({ domain: { id: domainId } as any, space: { id: savedSpace.id } as any, type: rep.type, name: rep.name, seq: i, isPrimary: !!rep.primary || rep.id === (spaceContent as any).primaryId, config }))\n for (const area of (rep.areas ?? []) as any[]) {\n await areaRepo.save(areaRepo.create({ domain: { id: domainId } as any, representation: { id: savedRep.id } as any, name: area.name, type: area.type, geometry: area.geometry, drillTo: area.drillTo ?? null, binding: area.binding ?? null, style: area.style ?? null }))\n }\n }\n /*\n * ๋Œ€ํ‘œ๋ฅผ **์ €์žฅ๋œ ํ–‰ id** ๋กœ ๊ฐ€๋ฆฌํ‚จ๋‹ค โ€” ๋งˆ์Šคํ„ฐ์˜ ๋…ผ๋ฆฌ id ๋Š” ์ €์žฅ ํ‚ค๊ฐ€ ์•„๋‹ˆ๋‹ค. ๊ณ ๋ฅธ ์ˆœ์„œ:\n * โ‘  ๋งˆ์Šคํ„ฐ๊ฐ€ primary ๋กœ ํ‘œ์‹œํ•œ ํ‘œํ˜„ โ‘ก ์—†์œผ๋ฉด ์ฒซ ํ‘œํ˜„ โ‘ข ํ‘œํ˜„์ด ์—†์œผ๋ฉด ๋น„์šด๋‹ค(์ง€์–ด๋‚ด์ง€ ์•Š๋Š”๋‹ค).\n */\n const saved = await repRepo.find({ where: { domain: { id: domainId } as any, space: { id: savedSpace.id } as any }, order: { seq: 'ASC' } })\n const primary = saved.find(r => r.isPrimary) ?? saved[0]\n if (primary && savedSpace.primaryRepresentationId !== primary.id) {\n await repo.save(repo.create({ ...savedSpace, primaryRepresentationId: primary.id }))\n /* ํ•˜๋‚˜๋งŒ ๋Œ€ํ‘œ๋‹ค โ€” ํ–‰ ํ”Œ๋ž˜๊ทธ๋„ ๊ทธ ํ•˜๋‚˜๋กœ ๋งž์ถ˜๋‹ค(๋‘˜์ด ์ผœ์ ธ ์žˆ์œผ๋ฉด ํ™”๋ฉด์ด โ˜…๋ฅผ ๋‘ ๋ฒˆ ๊ทธ๋ฆฐ๋‹ค). */\n for (const r of saved) if (!!r.isPrimary !== (r.id === primary.id)) await repRepo.save(repRepo.create({ ...r, isPrimary: r.id === primary.id }))\n }\n }\n /*\n * area ๋‹จ์ผํ™”(space #2, P1) โ€” ๋…ผ๋ฆฌ ๊ตฌ์—ญ์„ TwinArea(์ •๊ทœยทํ‘œํ˜„๋ฌด๊ด€ยท๊ณต์œ )์— dual-write(upsert by areaId).\n * P3: content.areas ์ €์žฅ ํ๊ธฐ โ†’ TwinArea ๊ฐ€ ์œ ์ผ ๊ถŒ์œ„. ์†Œ์Šค = masterToTwin ์‚ฐ์ถœ spaceContent.areas(cur).\n * (์›์ฒœ diff ์ œ๊ฑฐ[master ์—์„œ ๋น ์ง„ area ์‚ญ์ œ]๋Š” ์‚ฌ์šฉ์ž์ €์ž‘ area ๋ณดํ˜ธ ์œ„ํ•ด per-area provenance ํ•„์š” โ†’ ํ›„์†.)\n */\n const twinAreaRepo = getRepository(TwinArea)\n for (const a of ((spaceContent as any).areas ?? []) as any[]) {\n if (!a?.id) continue\n const existingArea = await twinAreaRepo.findOne({ where: { domain: { id: domainId }, space: { id: savedSpace.id }, areaId: a.id } })\n await twinAreaRepo.save(\n twinAreaRepo.create({\n ...(existingArea ?? {}),\n domain: { id: domainId } as any,\n space: { id: savedSpace.id } as any,\n areaId: a.id,\n name: a.name ?? a.id,\n type: a.type,\n parentId: a.parentId ?? null,\n layout: a.x != null || a.w != null ? { x: a.x, y: a.y, w: a.w, h: a.h } : null\n })\n )\n }\n\n if (running) {\n /* ์‹คํ–‰ ์ค‘์ธ ๋ฏธ๋Ÿฌ โ€” ๋ฉˆ์ถ”์ง€ ์•Š๊ณ  ์ „ํ™˜ํ•œ๋‹ค. ๋ฌด์—‡์ด ์‚ฌ๋ผ์กŒ๋Š”์ง€๋Š” **๊ฒฝ๊ณ ๋กœ ๋งํ•œ๋‹ค**\n (๋ฉˆ์ท„๋‹ค ์„ธ์šฐ๋Š” ๋งˆ๋””๊ฐ€ ์—†์œผ๋ฏ€๋กœ, ๋งํ•˜์ง€ ์•Š์œผ๋ฉด ์ž๋ฆฌ ํ•˜๋‚˜๊ฐ€ ์กฐ์šฉํžˆ ์—†์–ด์ง„๋‹ค). */\n const shift = await this.adoptStructure(domainId, master.source, model, undefined, master.origin)\n warnings.push(structureAdopted(shift.rev, shift))\n } else {\n /* ์‚ฌ์ดํŠธ ์ด๋ฆ„์ด ๊ณง ํŠธ์œˆ์˜ ์ด๋ฆ„์ด๋‹ค โ€” ๋งˆ์Šคํ„ฐ๊ฐ€ ์ด๋ฏธ ๋งํ–ˆ์œผ๋ฏ€๋กœ ์ง€์–ด๋‚ด์ง€ ์•Š๊ณ  ๊ทธ๋Œ€๋กœ ์‹ฃ๋Š”๋‹ค. */\n await this.provision(domainId, master.source, master.system, model, restartPolicy, undefined, master.origin, {\n name: master.siteName,\n description: (master as any).description,\n actor\n })\n }\n\n /*\n * ๊ตฌ์กฐ ํˆฌ์˜ โ€” model(์ปค๋„ ์ž…๋ ฅ ๋ฌธ์„œ)๋ฅผ **ํ‘œ์ค€ ์—”ํ‹ฐํ‹ฐ ํ–‰**์œผ๋กœ ํ‘ผ๋‹ค(ADR-0032).\n *\n * ์ธ์ œ์ŠคํŠธ๊ฐ€ ์œ ์ผํ•œ ์“ฐ๊ธฐ ๊ฒฝ๋กœ๋‹ค. ์—ฌ๊ธฐ์„œ ์‹คํŒจํ•ด๋„ ์ธ์ œ์ŠคํŠธ ์ž์ฒด๋Š” ์„ฑ๊ณต์œผ๋กœ ๋‘”๋‹ค โ€”\n * ํ–‰์€ **์›๋ณธ์—์„œ ์–ธ์ œ๋“  ๋‹ค์‹œ ๊ทธ๋ฆด ์ˆ˜ ์žˆ๋Š” ์บ์‹œ**์ด๊ณ , ํŠธ์œˆ ์ž์ฒด๋Š” model ๋กœ ์ด๋ฏธ ๋™์ž‘ํ•œ๋‹ค.\n * ๋‹ค๋งŒ **์กฐ์šฉํžˆ ๋„˜๊ธฐ์ง€ ์•Š๋Š”๋‹ค**: ๋ชป ์ด์€ ์ฐธ์กฐ๋Š” ์ธ์ œ์ŠคํŠธ ๊ฒฝ๊ณ ๋กœ ์˜ฌ๋ผ๊ฐ„๋‹ค.\n */\n try {\n const projected = await projectStructure(domainId, master.source, model, master.source)\n for (const ref of projected.unresolvedHome) warnings.push(unresolvedReference('equipment.homeLocation', ref))\n for (const ref of projected.unresolvedArea) warnings.push(unresolvedReference('location.area', ref))\n /*\n * ๋ฐœ์ „ ํ˜•์ƒ์€ **์‹œ๊ฐ**์„ ์ฝ๋Š”๋‹ค โ€” ์‹œ๊ฐ„๋Œ€๋ฅผ ๋ชจ๋ฅด๋ฉด UTC ๋กœ ์ฝํžˆ๊ณ , ํ˜„์žฅ ์ •์˜ค๊ฐ€ ์•„๋‹Œ ์‹œ๊ฐ์— ํ”ผํฌ๊ฐ€ ์„ ๋‹ค.\n * ์‹œ๊ฐ„๋Œ€๋ฅผ ์ง€์–ด๋‚ด์ง€ ์•Š๊ณ  ๊ทธ ์กฐํ•ฉ์„ ๋งํ•œ๋‹ค(๊ณต๊ฐ„์— ์„ ์–ธํ•˜๋ฉด ์‚ฌ๋ผ์ง„๋‹ค).\n */\n if ((model as any)?.utcOffsetMinutes === undefined) {\n for (const e of ((model as any)?.equipment ?? []) as any[]) {\n const hasProfile = ((e?.properties ?? []) as any[]).some(p => String(p?.id) === EMS_PROPERTY.genDailyProfile && String(p?.value ?? '').trim())\n if (hasProfile) warnings.push(generationWithoutTimeZone(String((model as any)?.spaceId ?? ''), String(e.id)))\n }\n }\n } catch (err: any) {\n twinError(`[twin-engine] structure projection failed for \"${master.source}\":`, err?.message)\n warnings.push(projectionFailed(err?.message ?? 'unknown'))\n }\n\n if (warnings.length) twinWarn(`[twin-engine] ingest \"${master.source}\" warnings: ${describeWarnings(warnings)}`)\n return { instanceId: master.source, spaceId, warnings }\n }\n\n /** ๋‹จ๊ฑด ์ƒ์„ธ โ€” ํ”„๋กœ๋น„์ €๋‹ ์—๋””ํ„ฐ๊ฐ€ ํŽธ์ง‘ํ•  model(๊ตฌ์กฐ+layout) ํฌํ•จ. */\n static async detail(domainId: string, instanceId: string): Promise<any | null> {\n const r = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!r) return null\n return {\n instanceId: r.instanceId,\n kind: r.kind,\n status: r.status,\n running: !!this.instances[runtimeKey(domainId, r.instanceId)],\n restartPolicy: r.restartPolicy, // ํ˜„์‹ค ์„ ์–ธ โ€” what-if ์ ์šฉ ๊ฐ€๋“œ์šฉ(mirror=์˜ˆ์ธก ์ „์šฉ, ์ž๊ทน ์ฃผ์ž… ๋ถˆ๊ฐ€)\n model: r.model\n }\n }\n\n /**\n * ๋ผ์ด๋ธŒ ๋ฐ”์ธ๋”ฉ ๋ธŒ๋ฆฌ์ง€(P3, ADR-0018) โ€” ํŠธ์œˆ ์—”ํ‹ฐํ‹ฐ ์ƒํƒœ๋ฅผ `data(tag=์—”ํ‹ฐํ‹ฐid)` ์ฑ„๋„๋กœ publish.\n * ๋ณด๋“œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ tag ๋กœ ๊ตฌ๋…(board-ui provider)ํ•ด `component.data` ๋กœ ๋ผ์ด๋ธŒ ๊ฐฑ์‹ . delta ์‹œ์—๋งŒ(ํฌ์†Œ).\n * tag=์—”ํ‹ฐํ‹ฐ id(๋ฐ๋ชจ=๋‹จ์ผ ์ธ์Šคํ„ด์Šค). ๋ฉ€ํ‹ฐ ์ธ์Šคํ„ด์Šค/๋ณด๋“œ ์žฌ์‚ฌ์šฉ ์‹œ tag ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋Š” ํ›„์†.\n */\n /** ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ… ์‹คํŒจ ๋กœ๊ทธ ์กฐ์ ˆ โ€” ์ฐฝ๋งˆ๋‹ค ํ•œ ์ค„(๋ง‰ํžŒ ๊ตฌ๋…์ž๋Š” ์ดˆ๋‹น ์ˆ˜์‹ญ ๋ฒˆ ์‹คํŒจํ•œ๋‹ค). */\n private static publishDrops = new Map<string, { count: number; lastLogMs: number }>()\n private static readonly PUBLISH_DROP_LOG_MS = 10_000\n\n /**\n * ํ•œ ๋ฒˆ์˜ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ… โ€” **๊ตฌ๋…์ž ํ•˜๋‚˜๊ฐ€ ํ˜ธ์ŠคํŠธ๋ฅผ ์ฃฝ์ด์ง€ ๋ชปํ•˜๊ฒŒ.**\n *\n * โ”€โ”€ ๋ฌด์—‡์ด ์ฃฝ์˜€๋‚˜ (2026-08-14) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๋ฐ€๋ฆฐ push ๊ฐ€ 1024๋ฅผ ๋„˜์œผ๋ฉด pubsub ์ด ์˜ค๋ฅ˜๋ฅผ ๋‚ธ๋‹ค(`RepeaterOverflowError`). ๊ทธ ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์€ ํƒ€์ด๋จธ ์ฝœ๋ฐฑ\n * ์•ˆ์—์„œ ์ผ์–ด๋‚˜๋ฏ€๋กœ ์˜ˆ์™ธ๊ฐ€ ์žกํžˆ๋Š” ๊ณณ ์—†์ด ์˜ฌ๋ผ๊ฐ€ **ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋๋‚ฌ๋‹ค** โ€” ํŠธ์œˆ 14๊ฐœ๊ฐ€ ๋„๋Š” ํ˜ธ์ŠคํŠธ๊ฐ€\n * ์†Œ๋น„๋ฅผ ๋ฉˆ์ถ˜ ๊ตฌ๋…์ž ํ•˜๋‚˜ ๋•Œ๋ฌธ์— ํ†ต์งธ๋กœ.\n *\n * ๋ชป ๋ณด๋‚ธ ๊ฒƒ์€ **์‚ฌ์‹ค๋กœ ๋‚จ๊ธด๋‹ค**(ํšŸ์ˆ˜๋ฅผ ์„ธ๊ณ  ์ฐฝ๋งˆ๋‹ค ํ•œ ์ค„ ๋‚จ๊ธด๋‹ค). ์‚ผํ‚ค๋ฉด ใ€Œ๋ณด๋ƒˆ๋Š”๋ฐ ํ™”๋ฉด์ด ๋‚ก์•˜๋‹คใ€๊ฐ€\n * ๋˜๊ณ , ๊ทธ๊ฑด ๊ฐ€์žฅ ์ฐพ๊ธฐ ์–ด๋ ค์šด ๋ถ€๋ฅ˜๋‹ค.\n */\n private static publishGuarded(channel: 'data' | 'twin-state', payload: any, what: string): boolean {\n try {\n pubsub.publish(channel as any, payload)\n return true\n } catch (err: any) {\n const d = this.publishDrops.get(what) ?? { count: 0, lastLogMs: 0 }\n d.count++\n const now = Date.now()\n if (now - d.lastLogMs >= this.PUBLISH_DROP_LOG_MS) {\n d.lastLogMs = now\n twinWarn(`[twin-engine] broadcast dropped on \"${what}\" (${d.count} so far) โ€” ${err?.message ?? err}`)\n }\n this.publishDrops.set(what, d)\n return false\n }\n }\n\n static publishEntityData(inst: InstanceRuntime): void {\n const domain = inst.domain\n if (!domain) return\n /* ์ƒํƒœ ์ถœ์ฒ˜ ์Šค์™‘ โ€” sim: ์ปค๋„ runtime, live: projector ๋ฏธ๋Ÿฌ(+OEE ๊ณ„์‚ฐ ์ธต ๋ณด๊ฐ•). ๊ณ„์•ฝยทpayload ๋™์ผ, ๋“œ๋ผ์ด๋ฒ„๋งŒ ๋‹ค๋ฆ„. */\n const load = inst.load ?? (inst.load = newLoadMeter())\n\n /* โ‘  ์ƒํƒœ ํˆฌ์˜ โ€” ์ƒํƒœ ํฌ๊ธฐ์— ๋น„๋ก€ํ•œ๋‹ค(๋Œ€๊ทœ๋ชจ์—์„œ ๊ฐ€์žฅ ๋ฌด๊ฑฐ์šด ์ถ•). */\n const tSnap = performance.now()\n const st: any =\n inst.mode === 'live'\n ? inst.oee\n ? withLiveOee(inst.projector?.snapshot?.(), inst.oee) // ๊ด€์ธก ์ปค๋„ + ๊ณ„์‚ฐ(OEE) โ†’ equipment payload ์— oee ํฌํ•จ(sim ๋™ํ˜•)\n : inst.projector?.snapshot?.()\n : inst.runtime?.resync?.()?.state\n recordPhase(load, 'snapshot', performance.now() - tSnap)\n if (!st) return\n /*\n * ๋ณ€ํ™”ํ•œ ์—”ํ‹ฐํ‹ฐ๋งŒ ๋ฐœํ–‰ โ€” ์ด์ „์—” delta ๋งˆ๋‹ค ์ „ ์—”ํ‹ฐํ‹ฐ(๋…ธ๋“œ+๋ฌด๋ฒ„+์˜ค๋”)๋ฅผ ๊ฐ’ ๋ณ€ํ™”์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ์ „๋Ÿ‰ ์žฌ๋ฐœํ–‰ํ•ด\n * ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋งค์ดˆ ๋ฐ˜๋ณต push ํ•˜๊ณ  ์žˆ์—ˆ๋‹ค(์˜ค์šฉ). ์ตœ์‹ -์ƒํƒœ ์ฑ„๋„์ด๋ฏ€๋กœ ๋ฌด๋ณ€ํ™” ์žฌ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์€ ๋ฌด์˜๋ฏธํ•˜๋‹ค.\n * ์—”ํ‹ฐํ‹ฐ๋ณ„ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ๋น„๊ตํ•ด ๋ฐ”๋€ ๊ฒƒ๋งŒ push.\n */\n const sigs = inst.entitySigs ?? (inst.entitySigs = new Map())\n const seen = new Set<string>()\n /* payload ๋งคํ•‘์€ ์ˆœ์ˆ˜ ํ•จ์ˆ˜(buildEntityDeltas)๋กœ ๋ถ„๋ฆฌ โ€” ์—ฌ๊ธฐ์„  ์‹œ๊ทธ๋‹ˆ์ฒ˜ dedup + ๋ฐœํ–‰๋งŒ.\n * ๋ณ€ํ™”ํ•œ ์—”ํ‹ฐํ‹ฐ๋งŒ ๋ฐœํ–‰(์ตœ์‹ -์ƒํƒœ ์ฑ„๋„์ด๋ผ ๋ฌด๋ณ€ํ™” ์žฌ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ… ๋ฌด์˜๋ฏธ). */\n /* โ‘ก payload ๋งŒ๋“ค๊ธฐ โ€” ์—”ํ‹ฐํ‹ฐ ์ˆ˜์— ๋น„๋ก€. โ‘ข ์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋น„๊ต + ๋ฐœํ–‰ โ€” ๋ฐ”๋€ ๊ฒƒ ์ˆ˜์— ๋น„๋ก€. */\n const tDelta = performance.now()\n /*\n * โ”€โ”€ ๋ฌผํ’ˆ์€ **๊ฑด๋“œ๋ฆฐ ๊ฒƒ๋งŒ** ๋งŒ๋“ ๋‹ค (2026-08-21 ์‹ค์ธก) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๋งŒ๋“œ๋Š” payload ์˜ ๋Œ€๋ถ€๋ถ„์ด ๋ฌผํ’ˆ์ด๋‹ค(์—”ํ‹ฐํ‹ฐ 3,611 ์ค‘ 2,400). ๋ฐ”๋€ ๊ฒƒ์ด ํ•˜๋‚˜์—ฌ๋„ ์ „๋ถ€ ๋งŒ๋“ค์–ด\n * ๋ฌธ์ž์—ด๋กœ ๋ฐ”๊พผ ๋’ค ใ€Œ๊ฐ™๋‹คใ€๋ฅผ ํ™•์ธํ•˜๊ณ  ๋ฒ„๋ ธ๋‹ค.\n *\n * ๋ฒ”์œ„๋Š” ์ด ์ฐฝ์— ๋“ค์–ด์˜จ ์‚ฌ๊ฑด์—์„œ ๋ชจ์•˜๋‹ค(`touchedItemKeys`). **๋งํ•  ์ˆ˜ ์—†๋Š” ์‚ฌ๊ฑด์ด ํ•˜๋‚˜๋ผ๋„ ์žˆ์œผ๋ฉด\n * ๋ฒ”์œ„๋Š” ์—†๊ณ  ์ „๋ถ€ ๋งŒ๋“ ๋‹ค** โ€” ๋‚ฏ์„  ์–ดํœ˜๊ฐ€ ์˜ค๋ฉด ์กฐ์šฉํžˆ ๋น ๋œจ๋ฆฌ๋Š” ๋Œ€์‹  ๋น„์‹ธ๊ฒŒ ์•ˆ์ „ํ•œ ์ชฝ์œผ๋กœ ๋–จ์–ด์ง„๋‹ค.\n *\n * ๊ทธ๋ฆฌ๊ณ  ์ฃผ๊ธฐ๋งˆ๋‹ค ํ•œ ๋ฒˆ์€ **๋ฌด์กฐ๊ฑด ์ „๋ถ€** ๋งŒ๋“ ๋‹ค(`FULL_BROADCAST_EVERY`). ์ปค๋„์ด ์‚ฌ๊ฑด ์—†์ด ๋ฌผํ’ˆ์„\n * ๋ฐ”๊พธ๋Š” ์ž๋ฆฌ๊ฐ€ ์ƒ๊ธฐ๋ฉด ๊ทธ ๊ฐ’์ด ํ™”๋ฉด์— ๋‚จ์„ ์ˆ˜ ์žˆ๋Š”๋ฐ, ๊ทธ ์ฐฝ์„ ๋ช‡ ์ดˆ๋กœ ๋ฌถ๋Š” ๊ทธ๋ฌผ์ด๋‹ค. **๋ณด์žฅ์ด ์•„๋‹ˆ๋ผ\n * ๊ทธ๋ฌผ์ด๋‹ค** โ€” ์‚ฌ๊ฑด ์—†์ด ๋ฐ”๋€Œ๋Š” ์ž๋ฆฌ๋ฅผ ์ฐพ์œผ๋ฉด ๊ทธ๊ฒƒ์„ ๊ณ ์น˜๋Š” ๊ฒƒ์ด ๋‹ต์ด๊ณ  ์ด ๊ทธ๋ฌผ์€ ์‹œ๊ฐ„์„ ๋ฒŒ ๋ฟ์ด๋‹ค.\n */\n const full = inst.fullBroadcastDue === true || !inst.dirtyItems\n const deltas = buildEntityDeltas(st, inst.id, full ? undefined : { items: inst.dirtyItems! })\n this.broadcastPasses++\n if (full) this.broadcastFullPasses++\n /* ์ด๋ฒˆ ์ฐฝ์˜ ๋ฒ”์œ„๋Š” ์—ฌ๊ธฐ์„œ ๋‹ซ๋Š”๋‹ค โ€” ๋‹ค์Œ ์ฐฝ์€ ๋‹ค์‹œ ๋ชจ์€๋‹ค. */\n inst.dirtyItems = new Set()\n inst.fullBroadcastDue = false\n recordPhase(load, 'deltas', performance.now() - tDelta)\n\n const tPub = performance.now()\n for (const { tag, data } of deltas) {\n seen.add(tag)\n const sig = JSON.stringify(data)\n if (sigs.get(tag) === sig) continue // ๋ฌด๋ณ€ํ™” โ†’ ๋ฐœํ–‰ ์ƒ๋žต\n sigs.set(tag, sig)\n /*\n * **๋ชป ๋ณด๋ƒˆ์œผ๋ฉด ๋ณด๋‚ธ ๊ฒƒ์œผ๋กœ ์ ์ง€ ์•Š๋Š”๋‹ค.** ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ๋‚จ๊ฒจ ๋‘๋ฉด ๋‹ค์Œ ์ฃผ๊ธฐ์— ใ€Œ๋ฌด๋ณ€ํ™”ใ€๋กœ ๊ฑด๋„ˆ๋›ฐ๊ณ ,\n * ๊ทธ ํƒœ๊ทธ๋Š” ์˜์›ํžˆ ๋‚ก์€ ๊ฐ’์„ ๋ณด์—ฌ ์ค€๋‹ค(์˜ค๋ฅ˜ ์—†์ด). ๋˜๋Œ๋ ค ๋‘๋ฉด ๋‹ค์Œ ์ฃผ๊ธฐ๊ฐ€ ๋‹ค์‹œ ์‹œ๋„ํ•œ๋‹ค.\n */\n if (!this.publishGuarded('data', { data: { domain, tag, data } }, `data:${inst.id}`)) sigs.delete(tag)\n }\n recordPhase(load, 'publish', performance.now() - tPub)\n /*\n * ์‚ฌ๋ผ์ง„ ์—”ํ‹ฐํ‹ฐ์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜ ์ •๋ฆฌ(๋งต ๋ฌดํ•œ ์„ฑ์žฅ ๋ฐฉ์ง€) โ€” **์ „๋ถ€ ๋งŒ๋“  ์ฐฝ์—์„œ๋งŒ.**\n * ๋ฒ”์œ„๋ฅผ ์ขํžŒ ์ฐฝ์˜ `seen` ์—๋Š” ๋งŒ๋“ค์ง€ ์•Š์€ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์—†์œผ๋ฏ€๋กœ, ๊ทธ๋•Œ ์ •๋ฆฌํ•˜๋ฉด ์‚ด์•„ ์žˆ๋Š” ํƒœ๊ทธ์˜\n * ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ์ง€์šด๋‹ค. ๋‚ก์€ ๊ฐ’์ด ๋‚˜๊ฐ€๋Š” ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ(๋‹ค์Œ ์ฐฝ์— ๋‹ค์‹œ ๋งŒ๋“ค์–ด ๋ณด๋‚ธ๋‹ค) ๊ฐ™์€ ๊ฐ’์„\n * ๋˜ํ’€์–ด ๋ณด๋‚ด๊ฒŒ ๋˜์–ด, ์ค„์ด๋ ค๋˜ ๊ฒƒ์„ ๋˜๋Œ๋ฆฐ๋‹ค.\n */\n if (full && sigs.size > seen.size) for (const tag of sigs.keys()) if (!seen.has(tag)) sigs.delete(tag)\n }\n\n /*\n * ๋‹จ๊ฑด ์ €์žฅ(`persist`)์€ **์—†์•ด๋‹ค** (2026-08-20, ยง7.1).\n *\n * ์‹œ๋ฎฌ์ด ๋ธํƒ€๋งˆ๋‹ค ์ด๊ฒƒ์„ ๋ถˆ๋Ÿฌ ํ–‰ ํ•˜๋‚˜์”ฉ ์ผ๊ณ , ๊ทธ๊ฒƒ์ด ๊ทœ๋ชจ์—์„œ ํ˜ธ์ŠคํŠธ๋ฅผ ๋จน์—ˆ๋‹ค. ๋‚จ๊ฒจ ๋‘๋ฉด ๋‹ค์Œ ์‚ฌ๋žŒ์ด\n * ๋‹ค์‹œ ๋ถ€๋ฅผ ์ž๋ฆฌ๊ฐ€ ๋˜๋ฏ€๋กœ ์ง€์šด๋‹ค โ€” ์“ฐ๋Š” ๋ฌธ์€ `flushJournal` ํ•˜๋‚˜๋‹ค(`persistBatch`ยท`persistCarried`).\n */\n\n /**\n * ์žฌ๋ถ€ํŒ… ๋ณต๊ตฌ / ์‹œ๊ฐ„์—ฌํ–‰ โ€” DB ์ €๋„์„ replay ํ•ด ์ƒํƒœ ์žฌ๊ตฌ์„ฑ.\n * model ๋Š” ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ(TwinInstance)์—์„œ, ์ด๋ฒคํŠธ๋Š” TwinEvent(revision ASC)์—์„œ.\n * ์ปค์„œ ๋‘ ์ถ•(runtime-state-model ยง4): **์‹œ๊ฐ(untilTime, ์‚ฌ์šฉ์ž ๋ชจ๊ตญ์–ดยท๊ณต๊ฐ„ ๊ณตํ†ต์ถ•)** ์šฐ์„ , ์—†์œผ๋ฉด ๋ฆฌ๋น„์ „(untilRevision, ๋ Œ์ฆˆ ๋‚ด๋ถ€).\n * - untilTime ์ฃผ๋ฉด `eventTime โ‰ค T` ์ธ ์ด๋ฒคํŠธ๋งŒ(๊ทธ ์‹œ์  watermark) โ€” ๊ณต๋™๋ฐฐ์น˜ ์—ฌ๋Ÿฌ ํŠธ์œˆ์„ ํ•˜๋‚˜์˜ ์‹œ๊ฐ T๋กœ ํ†ต์ผ ํ•ด์†Œ.\n * - ๋‘˜ ๋‹ค ์—†์œผ๋ฉด ์ตœ์‹ (๋ผ์ด๋ธŒ ์ธ๋ฉ”๋ชจ๋ฆฌ ์ง„์‹ค).\n * ์ด๋ฒคํŠธ๋Š” ํ•ญ์ƒ revision ASC(์ธ๊ณผ ์ˆœ์„œ)๋กœ ์ ์šฉ โ€” ์‹œ๊ฐ ํ•„ํ„ฐ๋Š” ์ปท์˜คํ”„ ์ง‘ํ•ฉ๋งŒ ์ •ํ•œ๋‹ค.\n */\n static async recover(domainId: string, instanceId: string, untilRevision?: number, untilTime?: string): Promise<any> {\n // ๋ผ์ด๋ธŒ ์ตœ์‹ (์‹œ๊ฐ„์—ฌํ–‰ ์•„๋‹˜) + ์ธ๋ฉ”๋ชจ๋ฆฌ ์ธ์Šคํ„ด์Šค โ†’ ๋ผ์ด๋ธŒ ์ปค๋„ ์Šค๋ƒ…์ƒท์„ ์ง์ ‘ ์‚ฌ์šฉ.\n // replay(StateProjector)๋Š” attentionsยทack ๋“ฑ ๋ผ์ด๋ธŒ ์ „์šฉ ํŒŒ์ƒ ์ƒํƒœ๋ฅผ ๋‹ด์ง€ ๋ชปํ•˜๋ฏ€๋กœ, ์ตœ์‹ ์€ ์ปค๋„ ์ง„์‹ค์„ ์“ด๋‹ค.\n if (untilRevision == null && untilTime == null) {\n const live = this.instances[runtimeKey(domainId, instanceId)]\n if (live?.kernel?.getSnapshot) return live.kernel.getSnapshot()\n // live ๋ชจ๋“œ๋Š” kernel ์ด ์—†๊ณ  projector ๋ฏธ๋Ÿฌ โ†’ ์ธ๋ฉ”๋ชจ๋ฆฌ ์ตœ์‹  ์Šค๋ƒ…์ƒท(projector+OEE+attentions) ์ง์ ‘ ์‚ฌ์šฉ.\n // (์ €๋„์ด ์žˆ์–ด๋„ ์ตœ์‹ ์€ ์ธ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ง„์‹ค โ€” replay ๋Š” ์‹œ๊ฐ„์—ฌํ–‰/๋ณต๊ตฌ ์ „์šฉ.)\n if (live?.mode === 'live' && live.projector) return this.snapshot(domainId, instanceId)\n }\n /*\n * **๋์— ์žˆ๋Š” ์Šค๋ƒ…์ƒท์ด๋ฉด ์ ‘์ง€ ์•Š๋Š”๋‹ค.**\n *\n * ๋ฉˆ์ถ˜ ํŠธ์œˆ์„ ์กฐํšŒํ•  ๋•Œ๋งˆ๋‹ค ์ €๋„์„ ์ „๋Ÿ‰ ์ ‘๊ณ  ์žˆ์—ˆ๋‹ค โ€” ํŠธ์œˆ์„ ํ•˜๋‚˜๋„ ์•ˆ ๋Œ๋ ค๋„ ๋ชจ๋ธ ์กฐํšŒ๊ฐ€\n * 4.6~7.7์ดˆ์˜€๋˜ ์ด์œ ๋‹ค(crew-probe 23,731๊ฑด). ์Šค๋ƒ…์ƒท์€ ๊ฐ™์€ ํด๋“œ์˜ ๊ฒฐ๊ณผ์ด๋ฏ€๋กœ, ๊ทธ ๋’ค๋กœ ์ด๋ฒคํŠธ๋„\n * ๊ตฌ์กฐ ๋ณ€๊ฒฝ๋„ ์—†๋‹ค๋ฉด **๋‹ค์‹œ ์ ‘์–ด ๋ด์•ผ ๊ฐ™์€ ๊ฐ’**์ด๋‹ค.\n *\n * ์“ฐ์ง€ ์•Š๋Š” ์กฐ๊ฑด์„ ์ข๊ฒŒ ์žก๋Š”๋‹ค: ์ง€๊ธˆ์„ ๋ฌผ์—ˆ์„ ๋•Œ๋งŒ(์‹œ๊ฐ„์—ฌํ–‰์€ ๊ทธ ์‹œ์ ๊นŒ์ง€ ์ ‘์–ด์•ผ ํ•œ๋‹ค), ๋ฆฌ๋น„์ „์ด\n * ๋๊ณผ ๊ฐ™์„ ๋•Œ๋งŒ, ๊ตฌ์กฐ ๋ฆฌ๋น„์ „๊นŒ์ง€ ๊ฐ™์„ ๋•Œ๋งŒ. ํ•˜๋‚˜๋ผ๋„ ์–ด๊ธ‹๋‚˜๋ฉด ์ ‘๋Š”๋‹ค โ€” ์บ์‹œ๊ฐ€ ์‚ฌ์‹ค์„ ์ด๊ธฐ์ง€ ์•Š๋Š”๋‹ค.\n */\n const asOfNowRead = untilRevision == null && untilTime == null\n const tip = asOfNowRead ? await this.tipOf(domainId, instanceId).catch(() => null) : null\n /* ํ•œ ๋ฒˆ๋งŒ ์ฝ๋Š”๋‹ค โ€” ๋์— ์žˆ์œผ๋ฉด ๊ทธ๋Œ€๋กœ ์“ฐ๊ณ , ์•„๋‹ˆ๋ฉด ์•„๋ž˜์—์„œ **์ด์–ด ์ ‘๋Š” ์”จ์•—**์œผ๋กœ ์“ด๋‹ค. */\n const cachedForResume = asOfNowRead && tip ? await this.loadSnapshot(domainId, instanceId).catch(() => null) : null\n if (cachedForResume) {\n const state = unwrapState(cachedForResume.state)\n if (state && (cachedForResume.revision ?? 0) === tip!.revision && (cachedForResume.structureRev ?? null) === tip!.structureRev)\n return state\n }\n\n const reg = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!reg?.model) throw new Error(`twin instance \"${instanceId}\" not registered (no model to replay)`)\n\n /*\n * โ”€โ”€ ์žฌ๊ฐœ์ ์—์„œ **์ด์–ด ์ ‘๋Š”๋‹ค** (2026-08-18) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n *\n * ์šฐ๋ฆฌ๋Š” ์ด๋ฏธ ์ ‘์€ ๊ฒฐ๊ณผ๋ฅผ ๋‚จ๊ธฐ๊ณ  ์žˆ๋‹ค(`saveFoldedSnapshot`). ๊ทธ ์ง€์ ์˜ **์žฌ๊ฐœ์ **(๋ฆฌ๋“€์„œ ๋‚ด๋ถ€ ์ƒํƒœ\n * ์ „๋ถ€ + ๊ฐ€๋™ ๋ˆ„์ ๊ธฐ)์ด ํ•จ๊ป˜ ์žˆ์œผ๋ฉด, ๊ทธ ๋’ค์— ์ผ์–ด๋‚œ ๊ฒƒ๋งŒ ์ ‘์–ด๋„ ๊ฐ™์€ ๋‹ต์ด ๋‚˜์˜จ๋‹ค โ€” ๊ทธ ๋™์น˜๋Š”\n * ์ปค๋„ ์‹œํ—˜์ด ์ฆ๋ช…ํ•œ๋‹ค(0๋ถ€ํ„ฐ ์ ‘๊ธฐ == ์žฌ๊ฐœ์  + ๊ผฌ๋ฆฌ).\n *\n * ์“ฐ๋Š” ์กฐ๊ฑด์„ ์ข๊ฒŒ ์žก๋Š”๋‹ค: **์ง€๊ธˆ์„ ๋ฌผ์—ˆ์„ ๋•Œ๋งŒ**(์‹œ๊ฐ„์—ฌํ–‰์€ ๋ชฉํ‘œ ์ด์ „ ์žฌ๊ฐœ์ ์ด ํ•„์š”ํ•œ๋ฐ ์ง€๊ธˆ์€\n * ์ตœ์‹  ํ•˜๋‚˜๋งŒ ๋‚จ๊ธด๋‹ค โ€” ์‚ฌ์Šฌ์€ ๋‹ค์Œ ๋‹จ๊ณ„๋‹ค), ๊ตฌ์กฐ๊ฐ€ ๊ทธ๋Œ€๋กœ์ผ ๋•Œ๋งŒ(๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๊ทธ ๊ฒฝ๊ณ„์—์„œ ๊ฐˆ๋ผ\n * ์ ‘์–ด์•ผ ํ•œ๋‹ค), ์žฌ๊ฐœ์ ์ด ์ €๋„ ๋๋ณด๋‹ค ์•ž์„ค ๋•Œ๋งŒ. ํ•˜๋‚˜๋ผ๋„ ์–ด๊ธ‹๋‚˜๋ฉด 0๋ถ€ํ„ฐ ์ ‘๋Š”๋‹ค โ€” **์บ์‹œ๊ฐ€ ์‚ฌ์‹ค์„\n * ์ด๊ธฐ์ง€ ์•Š๋Š”๋‹ค.**\n */\n /*\n * ์”จ์•—์€ ๋‘˜ ์ค‘ ํ•˜๋‚˜๋‹ค: **์ง€๊ธˆ**์„ ๋ฌผ์œผ๋ฉด ์ตœ์‹  ์žฌ๊ฐœ์ , **๊ณผ๊ฑฐ**๋ฅผ ๋ฌผ์œผ๋ฉด ์‚ฌ์Šฌ์—์„œ ๋ชฉํ‘œ ์ง์ „ ์ง€์ .\n *\n * ๊ณผ๊ฑฐ ์”จ์•—์€ ๊ตฌ์กฐ๊ฐ€ ํ•œ ๋ฒˆ๋„ ๋ฐ”๋€Œ์ง€ ์•Š์€ ํŠธ์œˆ์—์„œ๋งŒ ์“ด๋‹ค โ€” ๊ตฌ์กฐ๊ฐ€ ๊ฐˆ๋ฆฐ ์ €๋„์€ ๋งˆ๋””๋งˆ๋‹ค ๊ฐˆ์•„ ์ ‘์–ด์•ผ\n * ํ•˜๊ณ , ๋งˆ๋””๋ฅผ ๊ฑด๋„ˆ๋›ด ์”จ์•—์€ ๊ทธ ๊ฒฝ๊ณ„์˜ ํŒ์ •์„ ์žƒ๋Š”๋‹ค(๊ทธ๋•Œ๋Š” 0๋ถ€ํ„ฐ ์ ‘๋Š” ๊ฒƒ์ด ์˜ณ๋‹ค).\n */\n const structureCount = asOfNowRead\n ? 0\n : await getRepository(TwinStructure).count({ where: { domain: { id: domainId }, instanceId } }).catch(() => 99)\n const pastSeed =\n !asOfNowRead && structureCount <= 1\n ? await this.chainSeedFor(domainId, instanceId, {\n ...(untilRevision != null ? { revision: untilRevision } : {}),\n ...(untilTime != null && !Number.isNaN(Date.parse(untilTime)) ? { timeMs: Date.parse(untilTime) } : {})\n }).catch(() => null)\n : null\n const resume =\n asOfNowRead && tip && cachedForResume && cachedForResume.fold && (cachedForResume.structureRev ?? null) === tip.structureRev\n ? cachedForResume\n : pastSeed\n\n /*\n * **์ž๋ฅผ ๊ฒƒ์„ ์•Œ๋ฉด์„œ ๋‹ค ์ฝ์–ด ์˜ค์ง€ ์•Š๋Š”๋‹ค** (2026-08-18 ์‹ค์ธก).\n *\n * ์ €๋„์„ ์ „๋Ÿ‰ ์ฝ์–ด ์˜จ ๋’ค JS ์—์„œ ๊ฑธ๋ €๋‹ค. 27๋งŒ ๊ฑด์งœ๋ฆฌ ํŠธ์œˆ(order-check)์—์„œ ํ•œ ์‹œ๊ฐ„ ์ „ ์ƒํƒœ๋ฅผ ๋ฌผ์œผ๋ฉด\n * **7.4์ดˆ**๊ฐ€ ๊ฑธ๋ ธ๊ณ , ๊ทธ ๋Œ€๋ถ€๋ถ„์ด ใ€Œํ•„์š” ์—†๋Š” ํ–‰์„ ์ฝ์–ด ์˜ค๋Š” ์‹œ๊ฐ„ใ€์ด์—ˆ๋‹ค. ์‹œ๊ฐยท๋ฆฌ๋น„์ „ ์ƒํ•œ์€ SQL ์ด\n * ์•„๋Š” ์กฐ๊ฑด์ด๋ฏ€๋กœ ๊ฑฐ๊ธฐ์„œ ์ž๋ฅธ๋‹ค(TypeORM ๊ด€์šฉ๊ตฌ๋งŒ โ€” ์›์‹œ SQL ์€ 5๊ฐœ ๋“œ๋ผ์ด๋ฒ„์—์„œ ๊ฐˆ๋ผ์ง„๋‹ค).\n *\n * ์‹œ๊ฐ ์ƒํ•œ์—๋Š” **๊ฒฝ๊ณ„๋ฅผ ๊ทธ๋Œ€๋กœ** ์“ด๋‹ค(`<=`): ๊ทธ ์‹œ๊ฐ์— ์ผ์–ด๋‚œ ์‚ฌ์‹ค์€ ๊ทธ ์‹œ๊ฐ์˜ ํ™”๋ฉด์— ์žˆ์–ด์•ผ ํ•œ๋‹ค.\n * ์‹œ๊ฐ์ด ์—†๋Š” ๋ ˆ๊ฑฐ์‹œ ํ–‰์€ ๋ณด์ˆ˜์ ์œผ๋กœ ํฌํ•จํ•ด ์™”๋Š”๋ฐ, SQL ๋กœ ์ž๋ฅด๋ฉด ๊ทธ ํ–‰๋“ค์ด ๋น ์ง„๋‹ค โ€” ๊ทธ๋ž˜์„œ ์‹œ๊ฐ\n * ์กฐ๊ฑด์ผ ๋•Œ๋Š” **์‹œ๊ฐ์ด ๋น„์–ด ์žˆ๋Š” ํ–‰๋„ ํ•จ๊ป˜** ๊ฐ€์ ธ์™€ ์˜ˆ์ „๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ๋‚ธ๋‹ค.\n */\n const cutoffMs = untilTime != null ? Date.parse(untilTime) : NaN\n const useTime = untilTime != null && !Number.isNaN(cutoffMs)\n const baseWhere = { domain: { id: domainId }, instanceId }\n /* ์ด์–ด ์ ‘์„ ๋•Œ๋Š” **๊ทธ ๋’ค๋งŒ** ์ฝ๋Š”๋‹ค โ€” ์žฌ๊ฐœ์ ๊นŒ์ง€์˜ ์‚ฌ์‹ค์€ ์ด๋ฏธ ์”จ์•— ์•ˆ์— ์žˆ๋‹ค. */\n const from = resume ? (resume.revision ?? 0) : undefined\n /*\n * journal-fold: ์žฌ์ƒ์€ ์‚ฌ์‹ค์„ ํ•˜๋‚˜์”ฉ ์ ‘๋Š” ๊ฒƒ์ด๋ฏ€๋กœ ๊ทธ ๊ตฌ๊ฐ„์˜ ํ–‰์ด ํ•„์š”ํ•˜๋‹ค. ์ปค์„œ(`from`)์™€ ์‹œ๊ฐ\n * ์ƒํ•œ์ด ๊ตฌ๊ฐ„์„ ์ž๋ฅด๊ณ , ์ฒดํฌํฌ์ธํŠธ๊ฐ€ ์•ž์ชฝ์„ ์”จ์•—์œผ๋กœ ๋Œ€์‹ ํ•œ๋‹ค โ€” ํ‘œ ์ „์ฒด๋ฅผ ์ฝ์ง€ ์•Š๋Š”๋‹ค.\n */\n const rows = await getRepository(TwinEvent).find({\n where: useTime\n ? from\n ? /* ์”จ์•— ๋’ค ยท ๋ชฉํ‘œ ์ด๋‚ด โ€” ์‹œ๊ฐ์ด ๋นˆ ์˜› ํ–‰์€ ์”จ์•— ๋’ค์— ์žˆ๋Š” ๊ฒƒ๋งŒ ํฌํ•จํ•œ๋‹ค(๋ณด์ˆ˜์  ํฌํ•จ์„ ์œ ์ง€). */\n [\n { ...baseWhere, revision: MoreThan(from), eventTime: LessThanOrEqual(new Date(cutoffMs)) },\n { ...baseWhere, revision: MoreThan(from), eventTime: IsNull() }\n ]\n : [\n { ...baseWhere, eventTime: LessThanOrEqual(new Date(cutoffMs)) },\n { ...baseWhere, eventTime: IsNull() }\n ]\n : untilRevision != null\n ? from\n ? { ...baseWhere, revision: And(MoreThan(from), LessThanOrEqual(untilRevision)) }\n : { ...baseWhere, revision: LessThanOrEqual(untilRevision) }\n : from\n ? { ...baseWhere, revision: MoreThan(from) }\n : baseWhere,\n order: { revision: 'ASC' }\n })\n const wanted = rows\n\n /*\n * **๊ทธ๋•Œ์˜ ๊ณต์žฅ์œผ๋กœ ์ ‘๋Š”๋‹ค.**\n *\n * ์˜ˆ์ „์—๋Š” ๋ชจ๋“  ์ด๋ฒคํŠธ๋ฅผ ์ง€๊ธˆ ๋“ฑ๋ก๋œ ๋ณด๋“œ ํ•˜๋‚˜๋กœ ์ ‘์—ˆ๋‹ค. ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€ ์  ์—†์œผ๋ฉด ๋งž์ง€๋งŒ, ๋ฐ”๋€\n * ๋’ค์—๋Š” ์˜› ์‚ฌ์‹ค์„ ์ƒˆ ๊ณต์žฅ์— ๋Œ€๊ณ  ์ ‘๊ฒŒ ๋˜์–ด โ€” ๊ทธ๋•Œ ์—†๋˜ ์„ค๋น„์—์„œ ์ผ์ด ์žˆ์—ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค.\n * (๊ทธ๋ž˜์„œ ์˜ˆ์ „ ํ”„๋กœ๋น„์ €๋‹์€ ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์ €๋„์„ ์•„์˜ˆ ์ง€์› ๋‹ค. ์—ญ์‚ฌ๋ฅผ ์žƒ๊ฑฐ๋‚˜ ๊ฑฐ์ง“๋ง์„ ํ•˜๊ฑฐ๋‚˜.)\n *\n * ์ด์ œ ์ด๋ฒคํŠธ๊ฐ€ ์ž๊ธฐ ๊ตฌ์กฐ๋ฅผ ๋‹ฌ๊ณ  ์˜ค๋ฏ€๋กœ, ๋ฆฌ๋น„์ „์ด ๋ฐ”๋€Œ๋Š” ์ง€์ ์—์„œ ๊ตฌ์กฐ๋ฅผ ๊ฐˆ์•„ํƒ€๋ฉฐ ์ด์–ด ์ ‘๋Š”๋‹ค.\n * ๋ฆฌ๋น„์ „์ด ํ•˜๋‚˜๋ฟ์ด๊ฑฐ๋‚˜(๋Œ€๋‹ค์ˆ˜) ์•„์˜ˆ ์—†์œผ๋ฉด(๊ตฌ์กฐ ์ด๋ ฅ ์ด์ „) ์˜ˆ์ „๊ณผ ๋˜‘๊ฐ™์ด ํ•œ ๋ฒˆ์— ์ ‘๋Š”๋‹ค.\n */\n const structures = await getRepository(TwinStructure).find({\n where: { domain: { id: domainId }, instanceId },\n order: { rev: 'ASC' }\n })\n const boardOf = new Map<number, TwinModelDef>(structures.map(x => [x.rev, x.model as TwinModelDef]))\n /* ์ปฌ๋Ÿผ์ด ์ƒ๊ธฐ๊ธฐ ์ „ ํ–‰์€ ๋ฆฌ๋น„์ „์ด ๋น„์–ด ์žˆ๋‹ค โ€” **๊ฐ€์žฅ ์˜ค๋ž˜๋œ ๊ตฌ์กฐ**์— ์†ํ•œ๋‹ค(0 ์œผ๋กœ ์ฑ„์šฐ์ง€ ์•Š๋Š”๋‹ค). */\n const oldest = structures[0]?.rev\n const revOf = (r: { structureRev?: number }): number | undefined => r.structureRev ?? oldest\n\n const segments: { model: TwinModelDef; events: any[] }[] = []\n for (const r of wanted) {\n if (!r.payload) continue\n const rev = revOf(r)\n const model = (rev !== undefined && boardOf.get(rev)) || (reg.model as TwinModelDef)\n const last = segments[segments.length - 1]\n if (last && last.model === model) last.events.push(r.payload)\n else segments.push({ model, events: [r.payload] })\n }\n /*\n * **๊ฐ€์žฅ ์ƒˆ ๊ตฌ์กฐ๊ฐ€ ์ง€๊ธˆ์˜ ๊ณต์žฅ์ด๋‹ค** โ€” ๊ทธ ์•„๋ž˜์—์„œ ์•„์ง ์•„๋ฌด ์ผ๋„ ์—†์—ˆ๋”๋ผ๋„.\n *\n * ์žฌํ”„๋กœ๋น„์ €๋‹ ์งํ›„๊ฐ€ ์ •ํ™•ํžˆ ๊ทธ ์ƒํƒœ๋‹ค: ๋ถ€์Šค๋ฅผ ๋„ท ๋Š˜๋ ธ๋Š”๋ฐ ์ƒˆ ์ด๋ฒคํŠธ๋Š” ์•„์ง ํ•˜๋‚˜๋„ ์—†๋‹ค. ์ด๋•Œ\n * ๋งˆ์ง€๋ง‰ ์ด๋ฒคํŠธ์˜ ๊ตฌ์กฐ๋กœ๋งŒ ์ ‘์œผ๋ฉด ํ™”๋ฉด์€ **์˜› ๊ณต์žฅ**์„ ๋ณด์—ฌ์ค€๋‹ค โ€” ๋ฐฉ๊ธˆ ๋Š˜๋ฆฐ ๊ฒƒ์ด ์•ˆ ๋ณด์ธ๋‹ค.\n * ๊ทธ๋ž˜์„œ ๋งˆ๋””์˜ ๋์— ์ง€๊ธˆ ๊ตฌ์กฐ๋ฅผ ํ•œ ๋ฒˆ ๋” ์–น๋Š”๋‹ค(์ด๋ฒคํŠธ ์—†๋Š” ๋งˆ๋””).\n *\n * **๋‹ค๋งŒ \"์ง€๊ธˆ\" ์„ ๋ฌผ์—ˆ์„ ๋•Œ๋งŒ์ด๋‹ค.** ๊ณผ๊ฑฐ ์‹œ์ ์„ ๋ฌผ์—ˆ๋Š”๋ฐ ์ตœ์‹  ๊ตฌ์กฐ๋ฅผ ์–น์œผ๋ฉด, ๊ทธ ์‹œ์ ์— ์—†๋˜\n * ์„ค๋น„๊ฐ€ ํ™”๋ฉด์— ์„œ๊ณ  โ€” ์ด ์ž‘์—…์ด ๋ง‰์œผ๋ ค๋˜ ๋ฐ”๋กœ ๊ทธ ๊ฑฐ์ง“๋ง์ด ๋œ๋‹ค.\n */\n const asOfNow = untilRevision == null && untilTime == null\n const newest = structures[structures.length - 1]?.model as TwinModelDef | undefined\n if (asOfNow && newest && segments[segments.length - 1]?.model !== newest) segments.push({ model: newest, events: [] })\n\n /*\n * ์ ‘์€ ์ƒํƒœ์— **์ฃผ์˜ ์‹ ํ˜ธ์™€ ์‹œ๊ฐ์„ ์ฑ„์šด๋‹ค.**\n *\n * ๋ผ์ด๋ธŒยท์‹œ๋ฎฌ์€ ์ปค๋„์ด ์‹ ํ˜ธ๋ฅผ ์Šค์Šค๋กœ ๋‚ด์ง€๋งŒ, ์ €๋„์„ ์ ‘๋Š” ์ด ๊ฒฝ๋กœ๋Š” ํ”„๋กœ์ ํ„ฐ ์ƒํƒœ๋งŒ ๋‚ธ๋‹ค โ€” ์‹ ํ˜ธ๋„\n * `nowTime` ๋„ ์—†๋‹ค. ๊ทธ๋ž˜์„œ **๊ณผ๊ฑฐ๋ฅผ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜๋ฉด ์ฃผ์˜ ๋ ˆ์ผ์ด ํ…… ๋น„์—ˆ๊ณ **(์ง€๋„๋Š” `snap.attentions` ๋ฅผ\n * ์ฝ๋Š”๋‹ค), ๊ธฐ๋™๋ผ ์žˆ์ง€ ์•Š์€ ํŠธ์œˆ์„ ๋ณด๋Š” ํ™”๋ฉด๋„ ๊ฐ™์•˜๋‹ค. ์‹ ํ˜ธ๋Š” ์ƒํƒœ์—์„œ ๊ณ„์‚ฐ๋˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ\n * ์—ฌ๊ธฐ์„œ ๊ฐ™์€ ๊ณต์‹(`deriveAttentions`)์œผ๋กœ ์ฑ„์šฐ๋ฉด ๋œ๋‹ค โ€” ๋‘ ๋ฒŒ์„ ๋‘์ง€ ์•Š๋Š”๋‹ค.\n *\n * `nowTime` ์ด ๋จผ์ €๋‹ค: \"๋Šฆ์—ˆ๋‚˜\" ํŒ์ •์ด ๊ทธ ๊ฐ’์„ ๋ณธ๋‹ค. ๋‹ค์‹œ ๊ณ„์‚ฐํ•œ ์‹œ์ ์˜ ์ •์งํ•œ \"์ง€๊ธˆ\" ์€ ๋ฌผ์–ด๋ณธ ์‹œ๊ฐ\n * (`untilTime`)์ด๊ณ , ์—†์œผ๋ฉด ๋งˆ์ง€๋ง‰์œผ๋กœ ์ ์šฉํ•œ ์ด๋ฒคํŠธ์˜ ์‹œ๊ฐ์ด๋‹ค. ๋‘˜ ๋‹ค ์—†์œผ๋ฉด ์ฑ„์šฐ์ง€ ์•Š๋Š”๋‹ค โ€”\n * ๋ฒฝ์‹œ๊ณ„๋ฅผ ๋ผ์›Œ ๋„ฃ์œผ๋ฉด ๊ณผ๊ฑฐ ํ™”๋ฉด์ด \"์ง€๊ธˆ ๊ธฐ์ค€์œผ๋กœ ๋Šฆ์—ˆ๋‹ค\" ๊ณ  ๋งํ•˜๊ฒŒ ๋œ๋‹ค.\n */\n const lastEventTime = rows.length ? (rows[rows.length - 1]?.eventTime?.toISOString() ?? '') : ''\n\n /*\n * **๊ฐ€๋™ ์ด๋ ฅ๋„ ๋˜์‚ด๋ฆฐ๋‹ค** โ€” ๋‹ค์‹œ ๊ณ„์‚ฐํ•œ ํ™”๋ฉด์— ์„ค๋น„ ๊ณ„์ธก์ด ๋น„์–ด ์žˆ๋˜ ๊ฒƒ.\n *\n * OEE ๋Š” ์› ์‹œ์Šคํ…œ์ด ๋ˆ„์ ์„ ๋ณด๋‚ด ์ฃผ์ง€ ์•Š์•„ ํ˜ธ์ŠคํŠธ๊ฐ€ ์ƒํƒœ ์ „์ด๋ฅผ ์ ๋ถ„ํ•ด ๋งŒ๋“ ๋‹ค(๊ทธ๋ž˜์„œ ์ปค๋„์ด ์•„๋‹ˆ๋ผ\n * ์—ฌ๊ธฐ ์žˆ๋‹ค). ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ๋ˆ„์ ๊ธฐ๋Š” **๋ผ์ด๋ธŒ์—์„œ๋งŒ** ๋Œ์•˜๊ณ , ์ €๋„์„ ์ ‘๋Š” ๊ฒฝ๋กœ๋Š” ๊ทธ ๊ณ„์‚ฐ์„ ํ•˜์ง€ ์•Š์•˜๋‹ค โ€”\n * ๊ณผ๊ฑฐ๋ฅผ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜๋ฉด ๋ชจ๋“  ์„ค๋น„๊ฐ€ \"๊ฐ€๋™ ์ด๋ ฅ์ด ์ „ํ˜€ ์—†์Œ\" ์œผ๋กœ ๋ณด์˜€๋‹ค.\n *\n * ์—†๋Š” ๊ฒƒ์€ ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹ˆ๋ผ ๊ณ„์‚ฐ์ด๋‹ค: ์ž…๋ ฅ(`equipment.status` ์ „์ดยท`quality.output`)์€ ์ €๋„์— ๋‹ค\n * ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ **๊ฐ™์€ ๋ˆ„์ ๊ธฐ์— ๊ฐ™์€ ์ด๋ฒคํŠธ๋ฅผ ํƒœ์šด๋‹ค** โ€” ๊ทœ์น™์„ ๋‘ ๋ฒŒ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค.\n *\n * ์‹œ๊ฐ„์—ฌํ–‰์—์„œ๋„ ๋งž๋‹ค: ์—ฌ๊ธฐ ํƒœ์šฐ๋Š” ๊ฒƒ์€ ์ด๋ฏธ ์ž˜๋ผ ๋‚ธ(`wanted`) ์ด๋ฒคํŠธ๋ฟ์ด๋ฏ€๋กœ, ๊ทธ ์‹œ์ ๊นŒ์ง€์˜\n * ๊ฐ€๋™ ์ด๋ ฅ์ด ๋‚˜์˜จ๋‹ค(๊ทธ ๋’ค์— ์ผ์–ด๋‚œ ๊ณ ์žฅ์ด ๊ณผ๊ฑฐ ํ™”๋ฉด์— ์„ž์ด์ง€ ์•Š๋Š”๋‹ค).\n */\n const oee = new OeeAccumulator()\n /* ์žฌ๊ฐœ์ ์ด ์žˆ์œผ๋ฉด ๊ทธ ์œ„์— ๊ผฌ๋ฆฌ๋งŒ ์–น๋Š”๋‹ค โ€” ์—†์œผ๋ฉด ๊ผฌ๋ฆฌ๋ถ„๋งŒ ์„ธ์–ด ๊ฐ€์šฉ๋ฅ ์ด ์กฐ์šฉํžˆ ์ž‘์•„์ง„๋‹ค. */\n if (resume?.fold?.oee) oee.restore(resume.fold.oee)\n for (const r of wanted) {\n try {\n oee.apply(r.payload as any)\n } catch {\n /* ํ•œ ๊ฑด์ด ์ด์ƒํ•ด๋„ ๋‚˜๋จธ์ง€ ๊ณ„์ธก์„ ๋ฒ„๋ฆฌ์ง€ ์•Š๋Š”๋‹ค โ€” ๋ˆ„์ ๊ธฐ๋Š” ๋ชจ๋ฅด๋Š” ์ด๋ฒคํŠธ๋ฅผ ๋ฌด์‹œํ•˜๋Š” ๊ณ„์•ฝ์ด๋‹ค. */\n }\n }\n\n const withNow = (st: any): any => {\n if (!st || typeof st !== 'object') return st\n const nowTime = st.nowTime || untilTime || lastEventTime || undefined\n const based = nowTime ? { ...st, nowTime } : st\n /* ๊ณ„์ธก ์‹œ์ ์€ ๊ทธ ํ™”๋ฉด์˜ \"์ง€๊ธˆ\" ์ด๋‹ค โ€” ๋ฒฝ์‹œ๊ณ„๋กœ ์žฌ๋ฉด ๊ณผ๊ฑฐ ํ™”๋ฉด์˜ ๊ฐ€์šฉ๋ฅ ์ด ์‹œ๊ฐ„์ด ๊ฐˆ์ˆ˜๋ก ๋–จ์–ด์ง„๋‹ค. */\n const nowMs = nowTime ? Date.parse(String(nowTime)) : Number.NaN\n const withMetrics = withLiveOee(based, oee, Number.isFinite(nowMs) ? nowMs : undefined)\n return withLiveAttentions(withMetrics)\n }\n\n /* ์ ‘์€ ๊ฒฐ๊ณผ๋ฅผ ๋‚จ๊ธด๋‹ค โ€” **์ง€๊ธˆ์„ ๋ฌผ์—ˆ์„ ๋•Œ๋งŒ**(์‹œ๊ฐ„์—ฌํ–‰ ๊ฒฐ๊ณผ๋ฅผ \"์ง€๊ธˆ\" ์œผ๋กœ ์ €์žฅํ•˜๋ฉด ๊ฑฐ์ง“์ด ๋œ๋‹ค). */\n /*\n * ์ ‘์€ ์ง€์ ์˜ ๋ฆฌ๋น„์ „ โ€” ์‚ฌ์Šฌ์— ์ ์„ ์ด๋ฆ„์ด๋‹ค. ๊ผฌ๋ฆฌ๋ฅผ ์ ‘์—ˆ์œผ๋ฉด ๊ทธ ๊ผฌ๋ฆฌ์˜ ๋, ์•„๋ฌด๊ฒƒ๋„ ์•ˆ ์ฝ์—ˆ์œผ๋ฉด\n * ์”จ์•—์˜ ์ž๋ฆฌ ๊ทธ๋Œ€๋กœ๋‹ค(๋ชจ๋ฅด๋ฉด 0).\n */\n const foldedTo = rows.length ? (rows[rows.length - 1]?.revision ?? 0) : (from ?? 0)\n\n const keep = (st: any, fold?: { reducer: ReducerCheckpoint; oee: OeeCheckpoint }): any => {\n /* ์žฌ๊ฐœ์ ์„ ํ•จ๊ป˜ ๋‚จ๊ธด๋‹ค โ€” ์ƒํƒœ๋งŒ ๋‚จ๊ธฐ๋ฉด ๋‹ค์Œ ๋ฒˆ์— ๋˜ 0๋ถ€ํ„ฐ ์ ‘์–ด์•ผ ํ•œ๋‹ค(๊ทธ๊ฒƒ์ด ์ด ์ž‘์—…์˜ ์š”์ ์ด๋‹ค).\n **๊ตฌ์กฐ๊ฐ€ ๊ฐˆ๋ฆฐ ํด๋“œ์—๋Š” ์žฌ๊ฐœ์ ์„ ๋ถ™์ด์ง€ ์•Š๋Š”๋‹ค**: ๋งˆ๋””๋ฅผ ๊ฑด๋„ˆ๋›ด ์”จ์•—์€ ๊ทธ ๊ฒฝ๊ณ„์˜ ํŒ์ •์„ ์žƒ๋Š”๋‹ค. */\n if (asOfNowRead && tip && st) {\n void this.saveFoldedSnapshot(domainId, instanceId, { revision: tip.revision, state: st, structureRev: tip.structureRev, fold })\n }\n /*\n * ์‚ฌ์Šฌ์—๋Š” **๊ณผ๊ฑฐ๋ฅผ ์ ‘์—ˆ์„ ๋•Œ๋„** ํ•œ ์ง€์ ์„ ๋‚จ๊ธด๋‹ค (2026-08-18 ์‹ค์ธก์œผ๋กœ ๊ณ ์นจ).\n *\n * ์ฒ˜์Œ์—๋Š” ใ€Œ์ง€๊ธˆ ์ฝ๊ธฐใ€์—์„œ๋งŒ ๋‚จ๊ฒผ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋„๋Š” ํŠธ์œˆ์˜ ์ง€๊ธˆ ์ฝ๊ธฐ๋Š” ์ปค๋„ ์Šค๋ƒ…์ƒท์œผ๋กœ ์ฆ‰์‹œ ๋‹ตํ•˜๊ณ \n * ํด๋“œ์— ๋‹ฟ์ง€ ์•Š๋Š”๋‹ค โ€” ๊ทธ๋ž˜์„œ ์‚ฌ์Šฌ์ด **์˜์›ํžˆ ๋น„์–ด ์žˆ์—ˆ๋‹ค**(์‹ค์ธก: ์ง€์  0๊ฐœ, ์‹œ๊ฐ„์—ฌํ–‰ 3.7s ๊ทธ๋Œ€๋กœ).\n *\n * ์ง€์ ์€ ใ€Œ์ง€๊ธˆใ€์„ ์ฃผ์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค: ์ž๊ธฐ ๋ฆฌ๋น„์ „๊ณผ ์‹œ๊ฐ์„ ๋‹ฌ๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๊ณผ๊ฑฐ ํด๋“œ์˜ ๊ฒฐ๊ณผ๋ฅผ ๋‚จ๊ฒจ๋„\n * ๊ฑฐ์ง“์ด ์•„๋‹ˆ๋‹ค(๊ทธ๊ฒƒ์ด ์Šค๋ƒ…์ƒท๊ณผ ๋‹ค๋ฅธ ์ ์ด๋‹ค). ๊ทธ๋ž˜์„œ ์ฒซ ๊ณผ๊ฑฐ ์กฐํšŒ๊ฐ€ ๋‹ค์Œ ๊ณผ๊ฑฐ ์กฐํšŒ๋ฅผ ๋น ๋ฅด๊ฒŒ ํ•œ๋‹ค.\n */\n if (fold && st) {\n const at = asOfNowRead && tip ? tip.revision : foldedTo\n if (at > 0)\n void this.keepChainPoint(domainId, instanceId, {\n revision: at,\n ...(lastEventTime ? { eventTime: lastEventTime } : {}),\n structureRev: (asOfNowRead && tip ? tip.structureRev : null) ?? null,\n fold\n }).catch(() => {})\n }\n return st\n }\n\n /*\n * ์”จ์•—์ด ์žˆ์œผ๋ฉด **์ด์–ด ์ ‘๋Š”๋‹ค** โ€” ํ•œ ๊ตฌ์กฐ ์•ˆ์—์„œ๋งŒ(๊ตฌ์กฐ๊ฐ€ ๊ฐˆ๋ฆฌ๋ฉด ์•„๋ž˜ ๋งˆ๋”” ๊ฒฝ๋กœ๊ฐ€ ๋งก๋Š”๋‹ค).\n * ์ƒˆ ์žฌ๊ฐœ์ ๋„ ํ•จ๊ป˜ ๋‚จ๊ธด๋‹ค: ๋‹ค์Œ ๋ฒˆ์— ๋˜ ๊ผฌ๋ฆฌ๋งŒ ์ ‘์„ ์ˆ˜ ์žˆ์–ด์•ผ ์ด ์ง€๋ฆ„๊ธธ์ด ๊ณ„์† ์‚ฐ๋‹ค.\n */\n if (resume?.fold?.reducer && segments.length <= 1) {\n const model = (segments[0]?.model ?? (asOfNow && newest) ?? reg.model) as TwinModelDef\n const out = replayFrom(model, resume.fold.reducer, segments[0]?.events ?? [])\n return keep(withNow(out.state), { reducer: out.checkpoint, oee: oee.serialize() })\n }\n\n if (!segments.length) {\n const model = ((asOfNow && newest) || reg.model) as TwinModelDef\n const out = replayWithCheckpoint(model, [])\n return keep(withNow(out.state), { reducer: out.checkpoint, oee: oee.serialize() })\n }\n if (segments.length === 1) {\n const out = replayWithCheckpoint(segments[0].model, segments[0].events)\n return keep(withNow(out.state), { reducer: out.checkpoint, oee: oee.serialize() })\n }\n\n /* ์ปค๋„ ๊ณ„์•ฝ๋„ `model` ์ด๋‹ค(0.6.14) โ€” ๊ฒฝ๊ณ„์—์„œ ์–ดํœ˜๋ฅผ ๋˜๋Œ๋ ค ๋‹ด๋˜ ๋ธŒ๋ฆฟ์ง€๊ฐ€ ์‚ฌ๋ผ์กŒ๋‹ค. */\n const { state, shifts } = replaySegments(segments)\n /* ๊ฒฝ๊ณ„์—์„œ ์‚ฌ๋ผ์ง„ ๊ฒƒ์„ ์กฐ์šฉํžˆ ๋„˜๊ธฐ์ง€ ์•Š๋Š”๋‹ค โ€” ์ˆ˜๊ฐ€ ์ค„์–ด๋“  ์ด์œ ๋ฅผ ์–ด๋”˜๊ฐ€์—๋Š” ๋‚จ๊ฒจ์•ผ ํ•œ๋‹ค. */\n for (const sh of shifts)\n if (sh.equipmentDropped || sh.locationsDropped || sh.personsDropped || sh.assetsDropped)\n console.info(`[twin-engine] \"${instanceId}\" replay crossed a structure change โ€” dropped ${sh.equipmentDropped} equipment, ${sh.locationsDropped} locations, ${sh.personsDropped} persons, ${sh.assetsDropped} assets that no longer exist.`)\n return keep(withNow(state))\n }\n\n /**\n * ๊ณต๊ฐ„(๊ณต๋™๋ฐฐ์น˜) ์‹œ๊ฐ ๋ฒ”์œ„ โ€” ์Šคํฌ๋Ÿฌ๋ฒ„ ์•ต์ปค(runtime-state-model ยง4ยทยง6). ๊ทธ ๊ณต๊ฐ„ ์ „ ์ธ์Šคํ„ด์Šค ์ €๋„์˜ min/max eventTime.\n * ๋ฐ˜ํ™˜ {minTime, maxTime}(ISO) โ€” ์ด๋ฒคํŠธ/์‹œ๊ฐ ์—†์œผ๋ฉด null. ํด๋ผ ํžˆ์Šคํ† ๋ฆฌ ์Šคํฌ๋Ÿฌ๋ฒ„๊ฐ€ ์ด ๋ฒ”์œ„๋ฅผ ์‹œ๊ฐ์ถ•์œผ๋กœ ๊ทธ๋ฆฐ๋‹ค.\n *\n * โ”€โ”€ ๋‘ ์ˆ˜๋ฅผ ๊ตฌํ•˜๋ ค๊ณ  ์ €๋„์„ ๋‹ค ์ฝ์ง€ ์•Š๋Š”๋‹ค (2026-08-20 ์‹ค์ธก์œผ๋กœ ์žก์Œ) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์—ฌ๊ธฐ์„œ ์ธ์Šคํ„ด์Šค๋งˆ๋‹ค `find()` ๋กœ **ํ–‰์„ ์ „๋ถ€ ์—”ํ‹ฐํ‹ฐ๋กœ ํ•˜์ด๋“œ๋ ˆ์ด์…˜**ํ•œ ๋‹ค์Œ JS ์—์„œ min/max ๋ฅผ\n * ๊ณจ๋ž๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด ํ•จ์ˆ˜๋Š” ํ™”๋ฉด ์ƒ๋‹จ์˜ ์ปจํ…์ŠคํŠธ ๋ ๊ฐ€ **4์ดˆ๋งˆ๋‹ค** ๋ถ€๋ฅธ๋‹ค. ์‹ค์ธกํ•œ ๊ฐœ๋ฐœ ์„œ๋ฒ„์—์„œ\n * `order-check` ํ•œ ํŠธ์œˆ์ด 275,882ํ–‰ ยท `payload` 131MB ์˜€๋‹ค โ€” 4์ดˆ๋งˆ๋‹ค ๊ทธ JSON ์„ ์ „๋ถ€ ํŒŒ์‹ฑํ•œ ๊ฒƒ์ด๋‹ค.\n *\n * ๊ทธ ๊ฒฐ๊ณผ๊ฐ€ ์ด๋žฌ๋‹ค: ํ”„๋กœ์„ธ์Šค CPU 81~152%, ์•„๋ฌด ์ผ๋„ ํ•˜์ง€ ์•Š๋Š” ์งˆ์˜๊ฐ€ 8~14์ดˆ. JS ํ”„๋กœํŒŒ์ผ์˜ ์ƒ์œ„๊ฐ€\n * TypeORM ์˜ `RelationIdLoader`ยท`RawSqlResultsToEntityTransformer`ยท`stringToSimpleJson`(= `payload`\n * ํŒŒ์‹ฑ)์ด๊ณ  GC ๊ฐ€ 16.7% ์˜€๋‹ค. **ํŠธ์œˆ ํ‹ฑ๋„ ์ €๋„ ์“ฐ๊ธฐ๋„ ์•„๋‹ˆ๋ผ ์ด ์ฝ๊ธฐ์˜€๋‹ค.**\n *\n * ์ง‘๊ณ„๋Š” DB ๊ฐ€ ํ•œ๋‹ค. `(domain, instanceId, eventTime)` ์ธ๋ฑ์Šค๊ฐ€ ์ด๋ฏธ ์žˆ์–ด(`ix_twin_event_1`)\n * ์ธ๋ฑ์Šค์˜ **์–‘ ๋์„ ์ง‘๋Š”๋‹ค** โ€” ํ–‰์„ ํ•˜๋‚˜๋„ ์‹ค์–ด ์˜ค์ง€ ์•Š๋Š”๋‹ค.\n *\n * โ”€โ”€ ์™œ MIN ๊ณผ MAX ๋ฅผ ํ•œ ๋ฌธ์žฅ์— ๋„ฃ์ง€ ์•Š๋‚˜ (์‹ค์ธก) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ฒ˜์Œ์— `SELECT MIN(...), MAX(...) ... WHERE instanceId IN (...)` ํ•œ ๋ฐฉ์œผ๋กœ ๋‘์—ˆ๋”๋‹ˆ **21ms** ์˜€๋‹ค.\n * ์ง‘๊ณ„๊ฐ€ **๋‘˜์ด๋ฉด** ์˜ตํ‹ฐ๋งˆ์ด์ €์˜ ใ€Œ์ธ๋ฑ์Šค ๋์„ ์ง‘๋Š”ใ€ ์ตœ์ ํ™”๊ฐ€ ๊ฑธ๋ฆฌ์ง€ ์•Š์•„ ์ธ๋ฑ์Šค ๊ตฌ๊ฐ„์„ ํ›‘๋Š”๋‹ค โ€”\n * ์ฆ‰ ๋น„์šฉ์ด ์—ฌ์ „ํžˆ **ํ–‰ ์ˆ˜์— ๋น„๋ก€**ํ•œ๋‹ค. ํŠธ์œˆ๋งˆ๋‹ค ๋‹จ์ผ ์ง‘๊ณ„๋กœ ๋‚˜๋ˆ  ๋ฌผ์œผ๋ฉด **0.32ms**(ํŠธ์œˆ 3๊ฐœ ยท 6์™•๋ณต)\n * ์ด๊ณ , ๋น„์šฉ์ด **ํŠธ์œˆ ์ˆ˜์— ๋น„๋ก€**ํ•œ๋‹ค. ๊ทœ๋ชจ ๊ธฐ์ค€(์—”ํ‹ฐํ‹ฐ 10๋งŒ)์—์„œ๋Š” ์ด ์ฐจ์ด๊ฐ€ ๋ณธ์งˆ์ด๋‹ค.\n *\n * ์™•๋ณต์€ ํŠธ์œˆ๋‹น ๋‘˜์ด์ง€๋งŒ **ํ•จ๊ป˜ ๋„์šด๋‹ค** โ€” ์›๊ฒฉ DB ์—์„œ ์ง๋ ฌ๋กœ ๋Œ๋ฉด ์™•๋ณต ์ง€์—ฐ์ด ๊ทธ๋Œ€๋กœ ์Œ“์ธ๋‹ค.\n *\n * ๋“œ๋ผ์ด๋ฒ„ ๋‹ค์„ฏ์„ ๋‹ค ์ง€๋‚˜๊ฐ€์•ผ ํ•˜๋ฏ€๋กœ raw SQL ์„ ์“ฐ์ง€ ์•Š๋Š”๋‹ค(์ฟผ๋ฆฌ๋นŒ๋”์˜ MIN/MAX ๋Š” ์ด์‹๋œ๋‹ค).\n * ๋Œ๋ ค์ฃผ๋Š” ๊ฐ’์˜ **๋ชจ์–‘์€ ๋“œ๋ผ์ด๋ฒ„๋งˆ๋‹ค ๋‹ค๋ฅด๋‹ค**(๋ฌธ์ž์—ดยทDate) โ€” ๋ฐ›์€ ๋’ค์— ํ•œ ๋ฒˆ ์ •๊ทœํ™”ํ•œ๋‹ค(`parseTime`).\n */\n static async timeRange(domainId: string, spaceId: string): Promise<{ minTime: string | null; maxTime: string | null }> {\n const regs = await getRepository(TwinInstance).find({ where: { domain: { id: domainId }, spaceId } })\n const ids = regs.map(r => r.instanceId)\n if (!ids.length) return { minTime: null, maxTime: null }\n\n /**\n * ํ•œ ํŠธ์œˆ ์ €๋„์˜ ์‹œ๊ฐ ์–‘ ๋ ํ•˜๋‚˜ โ€” ๋‹จ์ผ ์ง‘๊ณ„๋ผ ์ธ๋ฑ์Šค ๋์„ ์ง‘๋Š”๋‹ค.\n *\n * ์ง‘๊ณ„์‹์„ **์กฐ๋ฆฝํ•˜์ง€ ์•Š๊ณ  ํ‘œ์— ๋ฆฌํ„ฐ๋Ÿด๋กœ ์ ๋Š”๋‹ค.** `` `${agg}(e.eventTime)` `` ๋กœ ๋งŒ๋“ค๋ฉด ์ด ์ž๋ฆฌ๊ฐ€\n * ์ง‘๊ณ„๋ฅผ ์“ฐ๋Š”์ง€ ํ›‘๋Š” ๊ฒ€์‚ฌ(`journal-read-discipline`)๊ฐ€ ์ฐพ์ง€ ๋ชปํ•œ๋‹ค โ€” ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ๋นจ๊ฐœ์กŒ๋‹ค.\n * ๋ฒˆ์—ญ ํ‚ค์—์„œ ๊ฒช์€ ๊ฒƒ๊ณผ ๊ฐ™์€ ๊ทœ์œจ์ด๋‹ค: ๊ฒ€์‚ฌ๊ฐ€ ์ผํ•˜๊ฒŒ ๋‘๋Š” ํŽธ์ด ๋‚ซ๋‹ค.\n */\n const AGG_SELECT = { MIN: 'MIN(e.eventTime)', MAX: 'MAX(e.eventTime)' } as const\n const edge = async (instanceId: string, agg: 'MIN' | 'MAX'): Promise<number | null> => {\n const row = await getRepository(TwinEvent)\n .createQueryBuilder('e')\n .select(AGG_SELECT[agg], 't')\n .where('e.domain = :domainId', { domainId })\n .andWhere('e.instanceId = :instanceId', { instanceId })\n .getRawOne<{ t: unknown }>()\n return parseTime(row?.t)\n }\n\n let min = Infinity\n let max = -Infinity\n\n /*\n * ํ•œ ๋ฒˆ์— ๋„์šฐ๋Š” ์ˆ˜๋ฅผ ๋ฌถ๋Š”๋‹ค โ€” ๊ณต๊ฐ„์— ํŠธ์œˆ์ด ์ˆ˜๋ฐฑ์ด๋ฉด ์™•๋ณต ์ˆ˜๋ฐฑ ๊ฐœ๋ฅผ ๋™์‹œ์— ๋ณด๋‚ด ์ปค๋„ฅ์…˜ ํ’€์„\n * ๋ง๋ ค ๋ฒ„๋ฆฐ๋‹ค(์ด ํ•จ์ˆ˜ ํ•˜๋‚˜ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ์งˆ์˜๊ฐ€ ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ๋œ๋‹ค).\n */\n for (let i = 0; i < ids.length; i += TIME_RANGE_FANOUT) {\n const batch = ids.slice(i, i + TIME_RANGE_FANOUT)\n const edges = await Promise.all(batch.flatMap(id => [edge(id, 'MIN'), edge(id, 'MAX')]))\n for (let k = 0; k < edges.length; k += 2) {\n const lo = edges[k]\n const hi = edges[k + 1]\n if (lo !== null && lo < min) min = lo\n if (hi !== null && hi > max) max = hi\n }\n }\n\n if (min === Infinity) return { minTime: null, maxTime: null }\n return { minTime: new Date(min).toISOString(), maxTime: new Date(max).toISOString() }\n }\n\n /** ์ •์ง€ ํ›… โ€” ์ธ์Šคํ„ด์Šค ์ •์ง€ ์‹œ ๋ถ€์ˆ˜์ž์› ์ •๋ฆฌ(์˜ˆ: reference-live ํ”ผ๋“œ unsubscribe). ์ˆœํ™˜ ์ž„ํฌํŠธ ์—†์ด ๊ฒฐ์„ . */\n static stopHooks: ((id: string) => void)[] = []\n static onStop(fn: (id: string) => void): void {\n this.stopHooks.push(fn)\n }\n\n static async stop(domainId: string, id: string): Promise<void> {\n const i = this.instances[runtimeKey(domainId, id)]\n if (i) {\n /*\n * **๋„๊ธฐ ์ „์— ๋‚จ๊ธด๋‹ค** โ€” ์ง€๊ธˆ์ด ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ง„์‹ค์ธ ๋งˆ์ง€๋ง‰ ์ˆœ๊ฐ„์ด๋‹ค.\n *\n * ๋‚จ๊ธฐ์ง€ ์•Š์œผ๋ฉด ๋‹ค์Œ ์กฐํšŒ๊ฐ€ ์ €๋„์„ ์ „๋Ÿ‰ ๋‹ค์‹œ ์ ‘๋Š”๋‹ค(๊ทธ ๊ฐ’์€ ์–ด์ฐจํ”ผ ๋ฐฉ๊ธˆ ๋ฉ”๋ชจ๋ฆฌ์— ์žˆ๋˜ ๊ฒƒ์ด๋‹ค).\n * ์ฒดํฌํฌ์ธํŠธ ๋ฃจํ”„๊ฐ€ 20์ดˆ๋งˆ๋‹ค ๋œจ์ง€๋งŒ ๊ทธ ์‚ฌ์ด์— ๋ฉˆ์ถ”๋ฉด ๊ทธ ๊ตฌ๊ฐ„์ด ํ†ต์งธ๋กœ ๋‹ค์‹œ ์ ‘ํžŒ๋‹ค.\n */\n await this.persistSnapshot(domainId, id).catch(err =>\n twinError(`[twin-engine] snapshot on stop fail \"${id}\"`, err?.message ?? err)\n )\n /*\n * **๋ชจ์•„ ๋‘” ์ €๋„๋„ ์ง€๊ธˆ ํ˜๋ฆฐ๋‹ค** โ€” ์ฃผ๊ธฐ flush ์‚ฌ์ด(์ตœ๋Œ€ `BROADCAST_COALESCE_MS`)์— ๋ฉˆ์ถ”๋ฉด ๊ทธ ๊ตฌ๊ฐ„์˜\n * ์‚ฌ์‹ค์ด ์‚ฌ๋ผ์ง„๋‹ค. ์Šค๋ƒ…์ƒท๋งŒ ๋‚จ๊ธฐ๋ฉด ์ƒํƒœ๋Š” ์‚ด์•„๋„ **์™œ ๊ทธ๋ ‡๊ฒŒ ๋๋Š”์ง€**๊ฐ€ ๋นˆ๋‹ค(์ €๋„์ด ๋‹ตํ•˜๋Š” ๊ฒƒ์ด๋‹ค).\n * ์“ฐ๊ธฐ๋Š” ์ด ํ•จ์ˆ˜๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š์ง€๋งŒ(๋น„์ฐจ๋‹จ) ๋ฒ„ํผ๋Š” ์—ฌ๊ธฐ์„œ ๋น„์›Œ์ง€๋ฏ€๋กœ ๋‹ค์Œ ๊ธฐ๋™์ด ๋‘ ๋ฒˆ ์ ์ง€ ์•Š๋Š”๋‹ค.\n */\n await this.flushJournal(i)\n clearInterval(i.timer)\n i.unsub()\n delete this.instances[runtimeKey(domainId, id)]\n await getRepository(TwinInstance)\n .update({ domain: { id: i.domainId }, instanceId: id }, { status: 'stopped' })\n .catch(err => twinError('twin deregister fail', err))\n }\n for (const hook of this.stopHooks) { try { hook(id) } catch { /* ํ›… ๊ฒฉ๋ฆฌ */ } }\n }\n\n /*\n * tick ํ•œ ๋ฒˆ โ€” **ํ•œ ํŠธ์œˆ์˜ ์˜ˆ์™ธ๊ฐ€ ์„œ๋ฒ„๋ฅผ ๋‚ด๋ฆฌ์ง€ ๋ชปํ•˜๊ฒŒ** ๊ฐ์‹ผ๋‹ค.\n *\n * ์ž˜๋ชป๋œ ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์‹ค๋ ธ์„ ๋•Œ ๋‹ค์Œ tick ์—์„œ `rate.meanPerHour` ๋ฅผ ์ฝ๋‹ค ํ„ฐ์กŒ๊ณ , ํƒ€์ด๋จธ ์ฝœ๋ฐฑ์˜\n * ์˜ˆ์™ธ๋Š” ์•„๋ฌด๋„ ๋ฐ›์ง€ ์•Š์•„ **uncaught exception ์œผ๋กœ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋‚ด๋ ค๊ฐ”๋‹ค.** ํ•œ ํ…Œ๋„ŒํŠธ์˜ ์ž˜๋ชป๋œ\n * ์„ ์–ธ์ด ๋ชจ๋“  ํ…Œ๋„ŒํŠธ๋ฅผ ๋ฉˆ์ถ˜ ์…ˆ์ด๋‹ค. ๋ฌธ ์•ž์—์„œ ๋ง‰๋Š” ๊ฒƒ์ด 1์ฐจ ๋ฐฉ๋ฒฝ์ด๊ณ (`validateScenario`),\n * ์ด๊ฒƒ์ด 2์ฐจ ๋ฐฉ๋ฒฝ์ด๋‹ค.\n *\n * **์กฐ์šฉํžˆ ์‚ผํ‚ค์ง€ ์•Š๋Š”๋‹ค.** ์‹คํ–‰์„ ๋ฉˆ์ถ”๊ณ  ๊ทธ ์‚ฌ์‹ค์„ ๋‚จ๊ธด๋‹ค โ€” ์˜ˆ์™ธ๋ฅผ ๋ฌด์‹œํ•˜๊ณ  ๊ณ„์† tick ํ•˜๋ฉด\n * ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋งค ์ฃผ๊ธฐ ์Ÿ์•„์ง€๊ณ , ๊ทธ ํŠธ์œˆ์€ \"๋„๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋ฉด์„œ\" ์•„๋ฌด๊ฒƒ๋„ ์ง„ํ–‰ํ•˜์ง€ ์•Š๋Š”๋‹ค.\n */\n /**\n * ๊ฐ™์€ ํ˜„์žฅ ํŠธ์œˆ๋“ค์˜ **์„ค๋น„ ์ƒํƒœ**๋ฅผ ์ปค๋„์— ๋„˜๊ธด๋‹ค โ€” ์ปค๋„์ด ์š”์ฒญํ•  ๋•Œ๋งŒ.\n *\n * โ”€โ”€ ๊ฒฝ๊ณ„ (2026-08-14) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ํ˜ธ์ŠคํŠธ๊ฐ€ ์•„๋Š” ๊ฒƒ์€ **๋ˆ„๊ฐ€ ๊ฐ™์€ ํ˜„์žฅ์— ์žˆ๋Š”๊ฐ€** ํ•˜๋‚˜๋‹ค. ๋ฌด์—‡์„ ์ฝ๊ณ  ๊ทธ๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ๋ถ€ํ•˜๋กœ ๋ฐ”๊ฟ€์ง€๋Š”\n * ์ปค๋„์ด ์ •ํ•œ๋‹ค(๊ณ„์ˆ˜๋Š” ํŠธ์œˆ์˜ ๋ชจ๋ธ์ด ์„ ์–ธํ•œ๋‹ค). ํ˜ธ์ŠคํŠธ๊ฐ€ kW ๋ฅผ ๊ณ„์‚ฐํ•ด ์ฃผ๋ฉด ํŠธ์œˆ๋งˆ๋‹ค ๋‹ค๋ฅธ ๊ทœ์น™์ด\n * ์ƒ๊ธฐ๊ณ , ๊ทธ ๊ทœ์น™์€ ์–ด๋””์—๋„ ์ ํ˜€ ์žˆ์ง€ ์•Š๊ฒŒ ๋œ๋‹ค.\n *\n * ์ƒํƒœ๋งŒ ๋„˜๊ธด๋‹ค. ์Šค๋ƒ…์ƒท์„ ํ†ต์งธ๋กœ ๋„˜๊ธฐ๋ฉด ์ƒํƒœ ํฌ๊ธฐ์— ๋น„๋ก€ํ•œ ๋น„์šฉ์„ ๋งค tick ์น˜๋ฅด๊ฒŒ ๋œ๋‹ค โ€”\n * ์„ค๋น„ ๋ชฉ๋ก์€ ๊ทธ ํŠธ์œˆ์˜ ์ปค๋„์ด ์ด๋ฏธ ๋“ค๊ณ  ์žˆ๋Š” ๊ฒƒ์ด๋ผ ํ›‘๋Š” ๊ฐ’์ด ์‹ธ๋‹ค.\n */\n private static feedPeerEquipment(inst: InstanceRuntime): void {\n const kernel: any = inst.kernel\n if (typeof kernel?.observePeerEquipment !== 'function') return // ์ด์›ƒ์„ ์ฝ์ง€ ์•Š๋Š” ์ปค๋„\n if (!inst.spaceId) {\n kernel.observePeerEquipment([]) // ํ˜„์žฅ์ด ์—†์œผ๋ฉด ์ด์›ƒ๋„ ์—†๋‹ค(์˜› ์ƒํƒœ๊ฐ€ ๋‚จ์ง€ ์•Š๊ฒŒ ๋น„์šด๋‹ค)\n return\n }\n const peers: { id: string; status?: string }[] = []\n for (const other of Object.values(this.instances)) {\n if (other === inst || other.domainId !== inst.domainId || other.spaceId !== inst.spaceId) continue\n const eq: Map<string, any> | undefined = (other.kernel as any)?.equipment\n if (!eq || typeof eq.forEach !== 'function') continue\n eq.forEach(e => peers.push({ id: String(e?.id ?? ''), status: String(e?.status ?? '') }))\n }\n kernel.observePeerEquipment(peers)\n }\n\n private static tickGuarded(domainId: string, id: string, runtime: TwinRuntimeType): void {\n const inst = this.instances[runtimeKey(domainId, id)]\n const load = inst && (inst.load ?? (inst.load = newLoadMeter()))\n const t0 = performance.now()\n try {\n /* ์ด์›ƒ์˜ ์„ค๋น„ ์ƒํƒœ๋ฅผ ๋จผ์ € ์‹ฃ๋Š”๋‹ค โ€” ์ปค๋„์ด ์ด๋ฒˆ tick ์—์„œ ๋ถ€ํ•˜๋ฅผ ๋งŒ๋“ค ๋•Œ ์ฝ๋Š”๋‹ค. */\n if (inst) this.feedPeerEquipment(inst)\n runtime.tick(this.TICK_MS)\n\n /* ์žฌ๊ณ  ๋งํ•œ๋‹ค โ€” ์‹œ๋ฎฌ ํ‹ฑ์€ ๋ฉ”์ธ ์ด๋ฒคํŠธ ๋ฃจํ”„์—์„œ ์ˆ˜ํ–‰๋œ๋‹ค. ์˜ˆ์‚ฐ(๊ฐ„๊ฒฉ์˜ ์ ˆ๋ฐ˜)์„ ๋„˜๊ธฐ๋ฉด HTTPยท๊ตฌ๋…์ด\n ํ•จ๊ป˜ ๋А๋ ค์ง€๋Š”๋ฐ, ์˜ˆ์ „์—๋Š” ๊ทธ๊ฒƒ์„ ๋ณผ ๊ณ„๊ธฐํŒ์ด ์—†์–ด \"ํ„ฐ์ง€๋ฉด ์•Œ๊ณ  ๋А๋ ค์ง€๋ฉด ๋ชฐ๋ž๋‹ค\". */\n if (load) {\n const took = performance.now() - t0\n recordPhase(load, 'tick', took)\n const j = judgeCycle(load, took, this.TICK_MS, Date.now())\n if (j.warn) twinWarn(slowTickMessage(id, took, j.budgetMs, load))\n this.guardStarvation(domainId, id, took)\n }\n } catch (err: any) {\n /*\n * ๋ฉˆ์ถ”๋Š” ๊ธธ์€ **ํ•˜๋‚˜**๋‹ค(`stop`) โ€” ์˜ˆ์ „์—๋Š” ํƒ€์ด๋จธ๋งŒ ๊ป๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋“ฑ๋ก๋ถ€๋Š” ๊ณ„์† `running` ์ด๋ผ\n * ๋งํ•˜๊ณ (์•„๋ฌด ํ‹ฑ๋„ ์—†๋Š” ์ฑ„๋กœ), ๋ถ€ํŒ… ์žฌ๊ฐœ๋Š” ๊ทธ ๊ฑฐ์ง“์„ ๊ทผ๊ฑฐ๋กœ ๋‹ค์‹œ ์„ธ์šด๋‹ค. ์Šค๋ƒ…์ƒท ๋ณด์กดยทํ”ผ๋“œ ์ •๋ฆฌยท\n * ๋“ฑ๋ก๋ถ€ ๊ฐฑ์‹ ์ด ๋ชจ๋‘ `stop` ์•ˆ์— ์žˆ๋‹ค.\n */\n this.stopWithNote(\n domainId,\n id,\n { code: 'tick-failed', params: { reason: String(err?.message ?? err) } },\n `[twin-engine] \"${id}\" tick failed โ€” this twin is stopped (other twins keep running). ` +\n `Fix the declaration and start it again. Reason: ${err?.message ?? err}`\n )\n }\n }\n\n /**\n * ํ˜ธ์ŠคํŠธ๋ฅผ ๊ตถ๊ธฐ๋Š” ํŠธ์œˆ์„ ๋ฉˆ์ถ˜๋‹ค โ€” **๋„๋Š” ์ฒ™ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋ฉˆ์ถ˜ ๊ฒƒ์ด ๋‚ซ๋‹ค.**\n *\n * ๊ตถ๊น€ ๋ฌธํ„ฑ์„ ๋„˜๋Š” ํ‹ฑ์ด ์—ฐ์† `STARVE_STREAK` ๋ฒˆ์ด๋ฉด ๊ทธ ํŠธ์œˆ์€ ๊ตฌ์กฐ์ ์œผ๋กœ ๋ฌด๊ฒ๋‹ค(์šฐ์—ฐ์ด ์•„๋‹ˆ๋‹ค).\n * ๋ฌธํ„ฑ ์•„๋ž˜๋กœ ํ•œ ๋ฒˆ๋งŒ ๋‚ด๋ ค์™€๋„ ์—ฐ์†์„ ๋Š๋Š”๋‹ค โ€” ๋ฌด๊ฑฐ์šด ์ˆœ๊ฐ„ ํ•˜๋‚˜๋กœ ํŠธ์œˆ์„ ๋‚ด๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.\n */\n private static guardStarvation(domainId: string, id: string, tookMs: number): void {\n const key = runtimeKey(domainId, id)\n const starveMs = this.TICK_MS * this.STARVE_FACTOR\n if (!(tookMs >= starveMs)) {\n this.starveStreak.delete(key)\n return\n }\n const streak = (this.starveStreak.get(key) ?? 0) + 1\n this.starveStreak.set(key, streak)\n if (streak < this.STARVE_STREAK) return\n\n this.starveStreak.delete(key)\n const secs = Math.round(tookMs) / 1000\n this.stopWithNote(\n domainId,\n id,\n { code: 'starved', params: { streak, thresholdSec: starveMs / 1000, lastSec: secs } },\n `[twin-engine] \"${id}\" stopped โ€” ${streak} consecutive ticks over ${starveMs / 1000}s (last ${secs}s). ` +\n `A simulation tick runs on the main loop, so this twin was stalling HTTP, subscriptions and every other twin. ` +\n `Its state is checkpointed; start it again after making it lighter (fewer orders/resources) or wait for off-loop ticking.`\n )\n }\n\n /** ๋ฉˆ์ถ”๊ณ  **์ด์œ ๋ฅผ ๋‚จ๊ธด๋‹ค** โ€” ์ด์œ  ์—†๋Š” ใ€Œ์ •์ง€ใ€๋Š” ์‚ฌ๋žŒ์ด ์ž๊ธฐ๊ฐ€ ๋ฉˆ์ถ˜ ๊ฒƒ์œผ๋กœ ์ฝ๋Š”๋‹ค. */\n private static stopWithNote(domainId: string, id: string, note: StopNote, log: string): void {\n twinError(log)\n this.stopNotes.set(runtimeKey(domainId, id), note)\n this.stop(domainId, id).catch(err => twinError(`[twin-engine] stop after guard failed \"${id}\"`, err?.message ?? err))\n }\n\n /** ์ด ํŠธ์œˆ์ด ์Šค์Šค๋กœ ๋ฉˆ์ถ˜ ์ด์œ (์žˆ์œผ๋ฉด) โ€” ํ™”๋ฉด์ด ์˜ฎ๊ฒจ ๋งํ•œ๋‹ค. */\n static stopNoteOf(domainId: string, id: string): StopNote | undefined {\n return this.stopNotes.get(runtimeKey(domainId, id))\n }\n\n /**\n * ์ด ํŠธ์œˆ์ด **์ง€๊ธˆ ์‹คํ–‰ ์ค‘์ธ๊ฐ€** โ€” ํŒ์ •์˜ ์ง‘ ํ•˜๋‚˜.\n *\n * \"์Šค๋ƒ…์ƒท์ด ์žˆ๋‚˜\" ๋กœ๋Š” ๋‹ต์ด ๋˜์ง€ ์•Š๋Š”๋‹ค: ์›œ์Šคํƒ€ํŠธ๊ฐ€ ๋˜์‚ด๋ฆฐ ์ƒํƒœ๊ฐ€ ์บ์‹œ์— ๋‚จ์•„ ์žˆ์œผ๋ฉด ๋ฉˆ์ถ˜ ํŠธ์œˆ๋„\n * ์Šค๋ƒ…์ƒท์„ ๋‚ธ๋‹ค. ๊ทธ๊ฒƒ์„ ๊ด€์ธก ์ค‘์œผ๋กœ ์ฝ์œผ๋ฉด ํ™”๋ฉด์ด **๋ฉˆ์ถ˜ ํŠธ์œˆ์˜ ์ž‘์—…์„ 0 ๊ฑด์ด๋ผ๊ณ  ๋‹จ์–ธ**ํ•œ๋‹ค\n * (์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ๋‚˜์™”๋‹ค โ€” ๊ด€์ธก์ด ์—†๋Š” ๊ฒƒ๊ณผ 0 ๊ฑด์€ ๋‹ค๋ฅด๋‹ค๋Š” ์ด ํ”„๋กœ์ ํŠธ์˜ ๊ทœ์œจ์„ ํ™”๋ฉด์ด ์–ด๊ฒผ๋‹ค).\n *\n * ๋ชฉ๋ก์ด ์“ฐ๋Š” ๊ฒƒ๊ณผ **๊ฐ™์€ ์ˆ ์–ด**๋‹ค(`list()` ์˜ `running`) โ€” ๋‘ ๋ฒŒ์ด๋ฉด ์–ด๊ธ‹๋‚œ๋‹ค.\n */\n static isRunning(domainId: string, id: string): boolean {\n return !!this.instances[runtimeKey(domainId, id)]\n }\n\n static runtime(domainId: string, id: string): TwinRuntimeType | undefined {\n return this.instances[runtimeKey(domainId, id)]?.runtime\n }\n\n /*\n * ์ปค๋งจ๋“œ ์‹คํ–‰ โ€” **ํŒ์ •์€ `routeCommand`(์ˆœ์ˆ˜)๊ฐ€ ํ•˜๊ณ  ์—ฌ๊ธฐ์„œ๋Š” ์‹คํ–‰๋งŒ** ํ•œ๋‹ค.\n * ํŒ์ •์„ ์ฝ”๋“œ ํ•œ๊ฐ€์šด๋ฐ ๋‘๋ฉด ์ด ๋ถ€๋ฅ˜๋ฅผ ํ…Œ์ŠคํŠธ๋กœ ๋ชป ์žก๋Š”๋‹ค(์—”์ง„์€ DB ๋ฅผ ๋ฌผ๊ณ  ์žˆ์–ด ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€\n * ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์—†๋‹ค). ์˜ˆ์ „์—๋Š” ๋ฆฌ์กธ๋ฒ„๊ฐ€ `inst.runtime.dispatch` ๋ฅผ ๊ณง๋ฐ”๋กœ ๋ถˆ๋Ÿฌ ๋ฏธ๋Ÿฌ์—์„œ ํ„ฐ์กŒ๋‹ค.\n */\n static async dispatchCommand(domainId: string, instanceId: string, command: any): Promise<{ accepted: boolean; error?: string; errorCode?: string; errorParams?: Record<string, string | number> }> {\n const inst = this.instances[runtimeKey(domainId, instanceId)]\n const type = String(command?.type ?? '')\n const route = routeCommand(\n inst && { mode: inst.mode, hasRuntime: !!inst.runtime, hasKernelDispatch: typeof (inst.kernel as any)?.dispatch === 'function' },\n !!inst && inst.domainId === domainId,\n type\n )\n if (route.target === 'reject') {\n return { accepted: false, errorCode: route.errorCode, errorParams: route.errorParams, error: route.errorCode }\n }\n\n const cmd = { ...command, tenantId: domainId } // tenantId ๋Š” ํ˜ธ์ถœ์ž ๋„๋ฉ”์ธ์œผ๋กœ ๊ฐ์ธ(๊ฐ์‚ฌยท๋ฌด๊ฒฐ์„ฑ)\n if (route.target === 'runtime') return inst!.runtime!.dispatch(cmd)\n\n /*\n * ๋ฏธ๋Ÿฌ โ€” ๊ด€์ธก ์ปค๋„๋กœ ๋ณด๋‚ด๊ณ , **์ปค๋งจ๋“œ๊ฐ€ ๋‚ธ ์‚ฌ์‹ค์„ ์ €๋„ ํ์— ์‹ค์–ด** ์ฝ”์–ผ๋ ˆ์„œ๊ฐ€ ๋ฒˆํ˜ธ๋ฅผ ๋ถ€์—ฌํ•˜๊ฒŒ ํ•œ๋‹ค.\n * ๋ฏธ๋Ÿฌ์—๋Š” State ๊ตฌ๋… ๋ฐฐ๊ด€์ด ์—†์–ด(์‹œ๋ฎฌ์€ ๊ทธ ๊ฒฝ๋กœ๋กœ ์ €๋„๋ง) ์ปค๋„ ๋ฐฉ์ถœ์ด ์•„๋ฌด ๋ฐ๋„ ๋‹ฟ์ง€ ์•Š๋Š”๋‹ค.\n * ์—ฌ๊ธฐ์„œ DB ๋ฅผ ๋”ฐ๋กœ ์ฝ์–ด ๋ฒˆํ˜ธ๋ฅผ ๋งค๊ธฐ๋ฉด ์ธ๋ฉ”๋ชจ๋ฆฌ ์นด์šดํ„ฐ์™€ ์–ด๊ธ‹๋‚˜ ๋ฆฌ๋น„์ „์ด ๊ฒน์นœ๋‹ค(๊ฒน์นจ์€ ์˜ค๋ฅ˜๋ฅผ\n * ๋‚ด์ง€ ์•Š๊ณ  ์žฌ์ƒ ์ˆœ์„œ๋งŒ ์กฐ์šฉํžˆ ๋’ค์„ž๋Š”๋‹ค).\n */\n const kernel: any = inst!.kernel\n const emitted: any[] = []\n const off = kernel.onEvent?.((e: any) => emitted.push(e))\n let ack: any\n try {\n ack = kernel.dispatch(cmd)\n } finally {\n off?.()\n }\n if (ack?.accepted && emitted.length) {\n inst!.pendingJournal = [...(inst!.pendingJournal ?? []), ...emitted]\n inst!.dirty = true // ์ฝ”์–ผ๋ ˆ์„œ๊ฐ€ ์ด๋ฒˆ ์ฃผ๊ธฐ์— ๋น„์šฐ๊ณ  ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…๊นŒ์ง€ ํ•˜๊ฒŒ ํ•œ๋‹ค\n }\n return ack ?? { accepted: false, errorCode: 'unknown-command', error: 'unknown-command' }\n }\n\n /**\n * ๋„๋ฉ”์ธ ์†Œ์œ  ๊ฒŒ์ดํŠธ โ€” ์ธ์Šคํ„ด์Šค๊ฐ€ ์ด ๋„๋ฉ”์ธ ์†Œ์œ ์ผ ๋•Œ๋งŒ true(ํ…Œ๋„ŒํŠธ ๊ฒฉ๋ฆฌ).\n * ์—†๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ๋„๋ฉ”์ธ์ด๋ฉด false. ๋…ธ์ถœ ๋ฆฌ์กธ๋ฒ„(per-id metrics/attentions/state/stop/forecast)๊ฐ€\n * this.instances[id] ๋ฅผ ๋งŒ์ง€๊ธฐ ์ „์— ๋ฐ˜๋“œ์‹œ ์ด๊ฑธ๋กœ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค. ์ธ์Šคํ„ด์Šค id ๋Š” ์ถ”์ธก ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ\n * ๊ฒ€์ฆ ์—†์ด ์ ‘๊ทผํ•˜๋ฉด ํฌ๋กœ์Šคํ…Œ๋„ŒํŠธ ์ฝ๊ธฐ/์ •์ง€๊ฐ€ ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.\n */\n /**\n * ์ด ๋Ÿฐํƒ€์ž„์˜ **๊ด€์ธก ๋ชจ๋“œ** โ€” `'live'`(์™ธ๋ถ€ ์‹ค๋ฌผ์„ ๋ฏธ๋Ÿฌ) ๋˜๋Š” `'sim'`(์ปค๋„์ด ์‹คํ–‰ํ•œ๋‹ค). ๊ธฐ๋™ ์ค‘์ด ์•„๋‹ˆ๋ฉด ์—†๋‹ค.\n *\n * ์†Œ๋น„์ฒ˜๊ฐ€ `instances[id].mode` ๋ฅผ ์ง์ ‘ ์ฝ๋˜ ์ž๋ฆฌ๋ฅผ ๋Œ€์‹ ํ•œ๋‹ค. ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋ฅผ ๋ฐ–์— ์—ด๋ฉด ๋„๋ฉ”์ธ ํ™•์ธ์ด\n * ์ž๋ฆฌ๋งˆ๋‹ค ์ œ๊ฐ๊ฐ์ด ๋˜๊ณ , ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ๋๋‹ค(ํ…Œ๋„ŒํŠธ ๊ฒฉ๋ฆฌ ์ „์ˆ˜ ํ™•์ธ, 2026-08-06).\n */\n static modeOf(domainId: string, id: string): 'live' | 'sim' | undefined {\n return this.instances[runtimeKey(domainId, id)]?.mode\n }\n\n static owns(domainId: string, id: string): boolean {\n return !!this.instances[runtimeKey(domainId, id)]\n }\n\n /**\n * ์ด ํŠธ์œˆ์ด ์ด ํ…Œ๋„ŒํŠธ ๊ฒƒ์ธ๊ฐ€ โ€” **๋–  ์žˆ๋“  ์•„๋‹ˆ๋“ .**\n *\n * `owns()` ๋Š” **๊ธฐ๋™ ์ค‘์ธ** ๋Ÿฐํƒ€์ž„๋งŒ ์•ˆ๋‹ค. ๊ทธ๊ฒƒ์„ ์ด๋ ฅ ์กฐํšŒ์˜ ๊ด€๋ฌธ์œผ๋กœ ์“ฐ๋ฉด, ๊บผ์ง„ ํŠธ์œˆ์˜ ์ €๋„์„\n * ์ฝ์œผ๋ ค ํ•  ๋•Œ \"์ด ํ…Œ๋„ŒํŠธ์— ์—†๋‹ค\" ๋Š” ๋‹ต์ด ๋Œ์•„์˜จ๋‹ค โ€” ๋‘ ๊ฐ€์ง€๊ฐ€ ํ‹€๋ ธ๋‹ค. ์ฒซ์งธ, ์ €๋„์€ ํŠธ์œˆ์ด ๊บผ์ ธ\n * ์žˆ์„ ๋•Œ **๊ฐ€์žฅ ํ•„์š”ํ•œ ๊ฒƒ**์ด๋‹ค(๊ทธ๊ฒŒ ์ด๋ ฅ์˜ ์กด์žฌ ์ด์œ ๋‹ค). ๋‘˜์งธ, ๊ทธ ๋ฌธ์žฅ์€ ๋‚จ์˜ ๊ฒƒ์ด๋ผ๋Š” ๋œป์ด๋ผ\n * ์‚ฌ์šฉ์ž๊ฐ€ ๊ถŒํ•œ ๋ฌธ์ œ๋กœ ์˜คํ•ดํ•œ๋‹ค. ์‹ค์ œ๋กœ๋Š” ๊ทธ๋ƒฅ ์‹คํ–‰ ์ค‘์ด ์•„๋‹ ๋ฟ์ด๋‹ค.\n *\n * ์†Œ์œ ๋Š” **๋“ฑ๋ก๋ถ€**๊ฐ€ ์•ˆ๋‹ค. ์ด๋ ฅยท์ง‘๊ณ„์ฒ˜๋Ÿผ ๋Ÿฐํƒ€์ž„๊ณผ ๋ฌด๊ด€ํ•œ ์งˆ๋ฌธ์€ ์ด์ชฝ์— ๋ฌป๋Š”๋‹ค.\n */\n static async ownsRegistered(domainId: string, instanceId: string): Promise<boolean> {\n if (this.owns(domainId, instanceId)) return true\n return !!(await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } }))\n }\n\n /**\n * **์ด ๊ณต๊ฐ„์˜ ์ธ์Šคํ„ด์Šค๋“ค** โ€” ํ•œ ํ˜„์‹ค์„ ์—ฌ๋Ÿฌ ๋ Œ์ฆˆ๊ฐ€ ๋น„์ถ”๋ฏ€๋กœ, ๊ณต๊ฐ„์„ ๋ฌผ์œผ๋ฉด ๊ทธ ๋ Œ์ฆˆ ์ „๋ถ€๋ฅผ ๋‹ตํ•œ๋‹ค.\n *\n * ํ™”๋ฉด์ด ์ด ๊ทœ์น™์„ ์†์œผ๋กœ ์งœ์ง€ ์•Š๊ฒŒ ์„œ๋ฒ„๊ฐ€ ๋‹ตํ•œ๋‹ค. ์˜ˆ์ธก ํ™”๋ฉด์€ ๊ฐ™์€ ํ™•์žฅ์„ **ํ•œ ํŒŒ์ผ์—์„œ ๋‘ ๋ฒˆ**\n * ๋ณต์ œํ•˜๊ณ  ์žˆ์—ˆ๋‹ค(์ „์ฒด ๋ชฉ๋ก์„ ๋ฐ›์•„ ํด๋ผ์ด์–ธํŠธ์—์„œ ๊ฑธ๋ €๋‹ค) โ€” ๊ทœ์น™์ด ํฉ์–ด์ง€๋ฉด ํ•œ์ชฝ๋งŒ ๊ณ ์ณ์ง„๋‹ค.\n *\n * ๋–  ์žˆ์ง€ ์•Š์€ ๊ฒƒ๋„ ํฌํ•จํ•œ๋‹ค: ๊ณต๊ฐ„์— ๋ฌด์—‡์ด ์žˆ๋Š”์ง€๋Š” ๊ธฐ๋™ ์—ฌ๋ถ€์™€ ๋‹ค๋ฅธ ์‚ฌ์‹ค์ด๋‹ค.\n */\n static async instanceIdsOfSpace(domainId: string, spaceId: string): Promise<string[]> {\n if (!spaceId) return []\n const rows = await getRepository(TwinInstance).find({ where: { domain: { id: domainId }, spaceId } })\n return rows.map(r => r.instanceId).filter((x): x is string => !!x)\n }\n\n /**\n * **์ด ๊ณต๊ฐ„์—์„œ ๋ด์•ผ ํ•  ๊ฒƒ** โ€” ๊ณต๊ฐ„์˜ ๋ชจ๋“  ๋ Œ์ฆˆ์—์„œ ์‹ ํ˜ธ๋ฅผ ๋ชจ์€๋‹ค.\n *\n * ํ•ฉ์ง‘ํ•ฉ์ด ๊ทธ๋Œ€๋กœ ๋œป์ด ์žˆ๋Š” ์œ ์ผํ•œ ๋ Œ์ฆˆ๋‹ค(์˜ˆ์ธก์€ ํ•ฉ์น  ์ˆ˜ ์—†๋‹ค โ€” P50 ๋‘ ๊ฐœ๋ฅผ ๋”ํ•  ์ˆ˜ ์—†๋‹ค).\n * ์ •๋ ฌยท์ž˜๋ผ๋‚ด๊ธฐ๋Š” ํ™”๋ฉด๊ณผ **๊ฐ™์€ ๊ทœ์น™**์„ ์“ด๋‹ค(`digestAttentions`) โ€” ์„œ๋ฒ„๊ฐ€ ๊ณ ๋ฅธ ์ƒ์œ„ N ์ด ํ™”๋ฉด์ด\n * ๊ณ ๋ฅผ N ๊ณผ ๋‹ฌ๋ผ์ง€๋ฉด ๊ทธ ์–ด๊ธ‹๋‚จ์€ ์•„๋ฌด ๋ฐ์„œ๋„ ์˜ค๋ฅ˜๋กœ ๋“œ๋Ÿฌ๋‚˜์ง€ ์•Š๋Š”๋‹ค.\n *\n * ์‹ ํ˜ธ๋งˆ๋‹ค ์–ด๋А ํŠธ์œˆ์—์„œ ์™”๋Š”์ง€(`instanceId`)๋ฅผ ๋ถ™์ธ๋‹ค. ๊ณต๊ฐ„์—์„œ ๋ณด๋ฉด ๊ฐ™์€ ์ž๋ฆฌ id ๊ฐ€ ๋ Œ์ฆˆ๋งˆ๋‹ค\n * ๋‹ค๋ฅธ ๊ฒƒ์„ ๊ฐ€๋ฆฌํ‚ฌ ์ˆ˜ ์žˆ๊ณ , ์กฐ์น˜๋Š” ๊ฒฐ๊ตญ ๊ทธ ํŠธ์œˆ์— ๋ณด๋‚ด์•ผ ํ•œ๋‹ค.\n */\n static async attentionsOfSpace(domainId: string, spaceId: string, limit?: number): Promise<{ attentions: any[]; attentionTotal: number; severityByLocation: Record<string, string> }> {\n const ids = await this.instanceIdsOfSpace(domainId, spaceId)\n const lenses = ids\n /* ๋–  ์žˆ์ง€ ์•Š์€ ํŠธ์œˆ์€ **์ง€๊ธˆ** ์‹ ํ˜ธ๊ฐ€ ์—†๋‹ค(๊ทธ ์‹œ์ ˆ ์‹ ํ˜ธ๋Š” ์‹œ๊ฐ„์—ฌํ–‰์ด ๋‹ตํ•œ๋‹ค). */\n .filter(id => this.owns(domainId, id))\n .map(id => {\n const kernel: any = this.kernel(domainId, id)\n const snap = kernel?.getSnapshot?.() ?? this.snapshot(domainId, id)\n return { instanceId: id, attentions: snap?.attentions ?? [] }\n })\n /* ๋ชจ์œผ๋Š” ๊ทœ์น™(ํƒœ๊น…ยท๊ธ‰ํ•œ ์ˆœ์„œยท์ž๋ฆฌ ์ƒ‰)์€ ์ˆœ์ˆ˜ ํ•จ์ˆ˜๊ฐ€ ๋“ค๊ณ  ์žˆ๋‹ค โ€” ์—ฌ๊ธฐ์„œ ์†์œผ๋กœ ์ ‘์ง€ ์•Š๋Š”๋‹ค. */\n return mergeLensAttentions(lenses, limit)\n }\n\n /** ๋ผ์ด๋ธŒ ์ปค๋„(ForecastTwin) โ€” forecast/divergence ์˜ˆ์ธก ์—ฐ์‚ฐ์šฉ. */\n static kernel(domainId: string, id: string): any {\n return this.instances[runtimeKey(domainId, id)]?.kernel\n }\n\n /** ๋ผ์ด๋ธŒ ์ฒ˜๋ฆฌ๋Ÿ‰ ๊ณ„์ธก ์Šค๋ƒ…์ƒท(๋ชจ๋‹ˆํ„ฐ, โ‘ฃ-1) โ€” ๋‚ด๋ถ€ ๋ˆ„์ (_acc*) ์ œ์™ธํ•œ ๊ณต๊ฐœ ์ง€ํ‘œ. live ์•„๋‹ˆ๋ฉด null. */\n static metrics(domainId: string, id: string): any {\n const m = this.instances[runtimeKey(domainId, id)]?.metrics\n if (!m) return null\n return {\n instanceId: id,\n ingestedTotal: m.ingestedTotal, broadcastTotal: m.broadcastTotal, journaledTotal: m.journaledTotal,\n ingestRate: m.ingestRate, broadcastRate: m.broadcastRate, journalRate: m.journalRate,\n backlog: m.backlog, broadcastCoalesceMs: this.broadcastPeriodMs,\n /* ์ž‘์—…๋ณ„ ๋ถ€ํ•˜ โ€” ๋ฌด๊ฑฐ์šด ๊ฒƒ๋ถ€ํ„ฐ. ์žฐ ์ ์ด ์—†์œผ๋ฉด null(0 ์œผ๋กœ ์ฑ„์šฐ๋ฉด \"๋น ๋ฅด๋‹ค\" ๋กœ ์ฝํžŒ๋‹ค). */\n load: loadSummary(this.instances[runtimeKey(domainId, id)]?.load, this.TICK_MS)\n }\n }\n\n /**\n * ๋ถ€ํ•˜ ๊ณ„๊ธฐํŒ๋งŒ ๋”ฐ๋กœ โ€” **์‹œ๋ฎฌ ํŠธ์œˆ๋„ ํฌํ•จํ•œ๋‹ค.**\n *\n * `metrics()` ๋Š” ๋ผ์ด๋ธŒ ์ง€ํ‘œ(`inst.metrics`)๊ฐ€ ์žˆ์–ด์•ผ ๋ฌด์–ธ๊ฐ€๋ฅผ ๋Œ๋ ค์ค€๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ์ ์œ ํ•˜๋Š”\n * ๊ฒƒ์€ ์ฃผ๋กœ **์‹œ๋ฎฌ ํ‹ฑ**์ด๊ณ , ์‹œ๋ฎฌ ์ธ์Šคํ„ด์Šค์—๋Š” ๊ทธ ์ง€ํ‘œ๊ฐ€ ์—†์–ด ํ†ต์งธ๋กœ ์•ˆ ๋ณด์˜€๋‹ค.\n */\n static load(domainId: string, id: string): any {\n const inst = this.instances[runtimeKey(domainId, id)]\n if (!inst) return null\n\n return {\n instanceId: id,\n mode: inst.mode ?? 'sim',\n domainId: inst.domainId,\n domainLabel: inst.domain?.subdomain,\n restartPolicy: inst.restartPolicy,\n tickMs: this.TICK_MS,\n running: !!inst.timer || inst.mode === 'live',\n ...(loadSummary(inst.load, this.TICK_MS) ?? { recent: null, total: null, forksCreated: 0, overBudget: 0, budgetMs: this.TICK_MS * 0.5, loadRatio: null })\n }\n }\n\n /**\n * **ํ•œ ๊ณณ์—์„œ ๋ณด๋Š” ์ „์ฒด ๋ถ€ํ•˜** โ€” ๋ช‡ ๊ฐœ๊ฐ€ ์‹คํ–‰ ์ค‘์ด๊ณ , ๋ˆ„๊ฐ€ ๋ฃจํ”„๋ฅผ ์ ์œ ํ•˜๊ณ  ์žˆ๋‚˜.\n *\n * ์‹œ๋ฎฌ ํŠธ์œˆ๋„ ํฌํ•จํ•œ๋‹ค(`metrics()` ๋Š” ๋ผ์ด๋ธŒ ์ง€ํ‘œ๊ฐ€ ์žˆ์–ด์•ผ ๋‹ตํ•ด์„œ ์‹œ๋ฎฌ์ด ํ†ต์งธ๋กœ ์•ˆ ๋ณด์˜€๋‹ค).\n */\n static fleet(domainId?: string): any {\n const keys = Object.keys(this.instances).filter(key => !domainId || isOfDomain(key, domainId))\n const rows = keys.map(key => {\n const at = parseRuntimeKey(key)\n const inst = this.instances[key]\n /* ๋„๋ฉ”์ธ์„ ํ•จ๊ป˜ ๋„˜๊ธด๋‹ค โ€” ์šด์˜์ž๊ฐ€ ๋จผ์ € ๋ฌป๋Š” ๊ฒƒ์€ \"์–ด๋А ํ…Œ๋„ŒํŠธ๊ฐ€ ๋ฃจํ”„๋ฅผ ๋จน๋‚˜\" ๋‹ค.\n ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์ด๋ฆ„(subdomain)์€ ๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค์—๋งŒ ๋ถ™์–ด ์žˆ์œผ๋ฏ€๋กœ, ์—†์œผ๋ฉด ๋ฆฌ์กธ๋ฒ„๊ฐ€ ์ฑ„์šด๋‹ค. */\n return {\n instanceId: at.instanceId,\n mode: inst.mode ?? 'sim',\n domainId: at.domainId,\n domainLabel: inst.domain?.subdomain,\n meter: inst.load\n }\n })\n\n return {\n tickMs: this.TICK_MS,\n broadcastCoalesceMs: this.broadcastPeriodMs,\n /* ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ… ์ฃผ๊ธฐ๋ฅผ ๋Š˜๋ฆฐ ํšŸ์ˆ˜ โ€” ๋Š˜์–ด๋‚œ ์ฃผ๊ธฐ๋งŒ ๋ณด๋ฉด ใ€Œ์›๋ž˜ ๊ทธ๋Ÿฐ ๊ฐ’ใ€์œผ๋กœ ์ฝํžŒ๋‹ค. */\n broadcastBackoffs: this.broadcastBackoffs,\n /* ๋ฌผํ’ˆ ๋ฒ”์œ„๋ฅผ ์ขํžˆ์ง€ ๋ชปํ•ด ์ „๋ถ€ ๋งŒ๋“  ํšŸ์ˆ˜ โ€” ์ขํžˆ๊ธฐ๊ฐ€ ์‹ค์ œ๋กœ ๋“ฃ๊ณ  ์žˆ๋Š”์ง€๋ฅผ ์ด ๊ฐ’์œผ๋กœ ๋ณธ๋‹ค. */\n broadcastPasses: this.broadcastPasses,\n broadcastFullPasses: this.broadcastFullPasses,\n broadcastFullEvery: this.FULL_BROADCAST_EVERY,\n /* **๋ฃจํ”„๊ฐ€ ์‹ค์ œ๋กœ ์–ผ๋งˆ๋‚˜ ๋ง‰ํ˜”๋‚˜** โ€” ํŠธ์œˆ ๋ถ€ํ•˜์™€ ๋‚˜๋ž€ํžˆ ๋†“๊ณ  ์›์ธ์„ ๊ฐ€๋ฆฐ๋‹ค(loop-lag.ts ์ฃผ์„). */\n loopLag: loopLag.view(),\n ...fleetLoad(rows, this.TICK_MS),\n /* ์ค„๋งˆ๋‹ค ์ƒ์„ธ โ€” ํ™”๋ฉด์ด ํŽผ์ณ ๋ณผ ์ˆ˜ ์žˆ๊ฒŒ. ์ตœ๊ทผ ๋ถ€ํ•˜ ์ˆœ์„œ๋Š” fleetLoad ๊ฐ€ ์ •ํ•œ๋‹ค. */\n details: keys.map(key => { const at = parseRuntimeKey(key); return this.load(at.domainId, at.instanceId) }).filter(Boolean)\n }\n }\n\n /** ์ด ํŠธ์œˆ์—์„œ fork ๊ฐ€ ๋งŒ๋“ค์–ด์กŒ๋‹ค โ€” ์˜ˆ์ธก ํ•œ ๋ฒˆ์ด ์ˆ˜์‹ญ ๊ฐœ๋ฅผ ๋งŒ๋“ ๋‹ค. */\n static countForks(domainId: string, id: string, count: number): void {\n const inst = this.instances[runtimeKey(domainId, id)]\n if (inst) recordFork(inst.load ?? (inst.load = newLoadMeter()), count)\n }\n\n /** ์—”์ง„ ๋ฐ–(์˜ˆ์ธก ์งˆ์˜ ๋“ฑ)์—์„œ ๋ฌด๊ฑฐ์šด ์ž‘์—…์„ ์žฐ๋‹ค โ€” ๊ฐ™์€ ๊ณ„๊ธฐํŒ์— ๋ชจ์ธ๋‹ค. */\n static recordLoad(domainId: string, id: string, phase: LoadPhase, tookMs: number): void {\n const inst = this.instances[runtimeKey(domainId, id)]\n if (inst) recordPhase(inst.load ?? (inst.load = newLoadMeter()), phase, tookMs)\n }\n\n /*\n * โ”€โ”€ ๋™๊ธฐํ™” ๊ฑด๊ฐ• ์žฅ๋ถ€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n *\n * **๋Ÿฐํƒ€์ž„์ด ์•„๋‹ˆ๋ผ ์—”์ง„์ด ๋“ ๋‹ค.** ์ธ์Šคํ„ด์Šค์— ๋ถ™์ด๋ฉด ํŠธ์œˆ์„ ์žฌ๊ธฐ๋™ํ•  ๋•Œ ์‚ฌ๋ผ์ง€๋Š”๋ฐ, ์‚ฌ๋žŒ์ด ์•Œ๊ณ  ์‹ถ์€\n * ๊ฒƒ์€ ๋ฐ”๋กœ ๊ทธ ์ˆœ๊ฐ„์ด๋‹ค โ€” ใ€Œ๊ณ ์ณ์„œ ๋‹ค์‹œ ๋„์› ๋Š”๋ฐ ์ด์ œ ํ†ต๊ณผํ•˜๋‚˜ใ€. ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‚ฌ๋Š” ๋™์•ˆ ์ด์–ด์ง„๋‹ค.\n *\n * ์ง€๊ธˆ์€ ๋ฉ”๋ชจ๋ฆฌ๋งŒ์ด๋‹ค. ์ฐฝ์ด ๋‹ซํž ๋•Œ ํ•œ ํ–‰์”ฉ ์˜์†ํ•˜๋Š” ๊ฒƒ์€ `onWindowClosed` ํ•œ ์ž๋ฆฌ์— ๋ถ™๋Š”๋‹ค.\n */\n private static ingestLedgers: Record<string, IngestLedger> = {}\n\n /** ์ฐฝ์ด ๋‹ซํž ๋•Œ ๋ถ€๋ฅผ ๊ณณ โ€” ์˜์† ๊ณ„์ธต์ด ๋ถ€ํŒ…์—์„œ ํ•œ ๋ฒˆ ๋“ฑ๋กํ•œ๋‹ค(์ปค๋„ ์ธต์€ ๊ทธ ๊ณ„์ธต์„ ๋ชจ๋ฅธ๋‹ค). */\n private static onWindowClosed?: (at: { domainId: string; instanceId: string }, closed: IngestWindow) => void\n\n /**\n * ๋‹ซํžŒ ์ฐฝ์„ ๋ฐ›์„ ๊ณณ์„ ๋“ฑ๋กํ•œ๋‹ค โ€” **์˜์†(B)์ด ๋ถ™๋Š” ์œ ์ผํ•œ ๋ฌธ.**\n *\n * ์ด ํŒจํ‚ค์ง€๋Š” ์ €์žฅ ๊ณ„์ธต์„ ๋ชจ๋ฅธ๋‹ค. ๋“ฑ๋กํ•˜๋Š” ์ชฝ์ด ์ž๊ธฐ ๋ฐฉ์‹์œผ๋กœ ์“ด๋‹ค. ํ›…์ด ์˜ค๋ฅ˜๋ฅผ ๋‚ด๋„ ์žฅ๋ถ€๋Š” ๊ณ„์† ๊ตด๋Ÿฌ๊ฐ„๋‹ค\n * (`rollIngestWindow` ๊ฐ€ ๊ฐ์‹ผ๋‹ค) โ€” ์˜์†์„ ์ง€ํ‚ค๋ ค๊ณ  ๊ด€์ธก์„ ๋ฉˆ์ถ”์ง€ ์•Š๋Š”๋‹ค.\n */\n static onIngestWindowClosed(\n fn: (at: { domainId: string; instanceId: string }, closed: IngestWindow) => void\n ): void {\n this.onWindowClosed = fn\n }\n\n /**\n * ํ•œ ๋ฒˆ์˜ ์ธ์ œ์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ ์žฅ๋ถ€์— ์ ๋Š”๋‹ค.\n *\n * `offered` ๋Š” **์ œ์‹œ๋œ ๋ ˆ์ฝ”๋“œ ์ˆ˜**๋‹ค(๊ฑฐ๋ถ€ ์—ฌ๋ถ€ ๋ฌด๊ด€). ํ†ต๊ณผ์œจ์„ ์„œ๋กœ ๋‹ค๋ฅธ ๋‘ ๊ณ„์ˆ˜๊ธฐ์—์„œ ๋‚˜๋ˆ  ๊ณ„์‚ฐํ•˜๋ฉด\n * ๋ถ„๋ชจ์™€ ๋ถ„์ž๊ฐ€ ๋‹ค๋ฅธ ๊ฒƒ์„ ์„ธ๊ฒŒ ๋˜๋ฏ€๋กœ, ํ•œ์ž๋ฆฌ์—์„œ ๋ณธ ์ˆ˜๋ฅผ ๊ทธ๋Œ€๋กœ ๋„˜๊ธด๋‹ค.\n */\n static recordIngestResult(\n domainId: string,\n instanceId: string,\n offered: number,\n rejected: { record?: unknown; errors?: string[] }[] | undefined,\n nowMs = Date.now(),\n /**\n * ๋งคํ•‘์€ ํ†ต๊ณผํ–ˆ๋Š”๋ฐ **์ปค๋„์ด ๋ฐ›์ง€ ์•Š์€** ์ˆ˜(`ingestLive` ์˜ ๋ฐ˜ํ™˜๊ณผ ๊ฒฌ์ฃผ์–ด ์–ป๋Š”๋‹ค).\n *\n * ใ€Œํ†ต๊ณผใ€๋กœ ์„ธ์ง€ ์•Š๋Š”๋‹ค โ€” ํŠธ์œˆ์ด ๋ฉˆ์ถ˜ ์‚ฌ์ด ์‚ฌ์‹ค์ด ์‚ฌ๋ผ์ง€๋Š”๋ฐ ํ™”๋ฉด์ด 100% ๋ผ๊ณ  ๋งํ•˜๊ฒŒ ๋œ๋‹ค.\n */\n undelivered = 0\n ): void {\n const key = runtimeKey(domainId, instanceId)\n const ledger = this.ingestLedgers[key] ?? (this.ingestLedgers[key] = newIngestLedger())\n recordIngest(\n ledger,\n offered,\n rejected,\n nowMs,\n closed => this.onWindowClosed?.({ domainId, instanceId }, closed),\n undelivered\n )\n }\n\n /**\n * **์›๋ณธ์— ๋‹ฟ์ง€ ๋ชปํ–ˆ๋‹ค**๋ฅผ ์ ๋Š”๋‹ค โ€” ใ€Œ๋ฐ›์€ ๊ฒƒ์ด ์—†๋‹คใ€์™€ ๊ฐ€๋ฅธ๋‹ค(ยง`recordReadFailure`).\n *\n * ์ด ๋ฌธ์ด ์—†๋˜ ๋™์•ˆ ์‹ค ์›๋ณธ์ด ๋Š๊ฒจ๋„ ํŠธ์œˆ์˜ ์กฐํšŒ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ์— ๊ทธ ์‚ฌ์‹ค์ด ์—†์—ˆ๋‹ค. ํ™”๋ฉด์ด ๋ณผ ์ˆ˜ ์žˆ๋Š”\n * ๊ฒƒ์€ ใ€Œ์ƒˆ ์‚ฌ์‹ค์ด ์—†๋‹คใ€๋ฟ์ด์—ˆ๊ณ  ๊ทธ๊ฒƒ์€ ใ€Œ์›๋ณธ์ด ์กฐ์šฉํ•˜๋‹คใ€์™€ ๊ตฌ๋ณ„๋˜์ง€ ์•Š๋Š”๋‹ค โ€” ์‹ค์ฆ ์ค‘์— ์›๋ณธ์ด\n * ๋Š๊ธฐ๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์›์ธ์„ ์ฐพ์„ ์ˆ˜ ์—†๋‹ค.\n *\n * ๋กœ๊ทธ๋กœ๋Š” ๋งํ•˜๊ณ  ์žˆ์—ˆ๋‹ค(์–ด๋Œ‘ํ„ฐ๊ฐ€ ์žฌ์‹œ๋„๋ฅผ ๊ฒฝ๊ณ ํ•œ๋‹ค). ๊ทธ๋Ÿฌ๋‚˜ **๋กœ๊ทธ๋Š” ์‚ฌ๋žŒ์ด ๋ณผ ๋•Œ๋งŒ ๊ฐ’์ด ์žˆ๋‹ค** โ€”\n * ํ™”๋ฉด์ด ๋งํ•˜๋ ค๋ฉด ์ƒํƒœ์— ์žˆ์–ด์•ผ ํ•œ๋‹ค.\n */\n static recordIngestReadFailure(domainId: string, instanceId: string, reason: string, nowMs = Date.now(), stream?: string): void {\n const key = runtimeKey(domainId, instanceId)\n const ledger = this.ingestLedgers[key] ?? (this.ingestLedgers[key] = newIngestLedger())\n recordReadFailure(ledger, reason, nowMs, stream)\n }\n\n /**\n * ์ฝ๊ธฐ๊ฐ€ ์„ฑ๊ณตํ–ˆ๋‹ค โ€” ๋‹จ์ ˆ ๊ธฐ๋ก์„ ์ง€์šด๋‹ค.\n *\n * **๋นˆ ์ฝ๊ธฐ๋„ ์„ฑ๊ณต์ด๋‹ค.** ์›๋ณธ์ด ใ€Œ์ƒˆ ๊ฒƒ์ด ์—†๋‹คใ€๊ณ  ๋‹ตํ•œ ๊ฒƒ์€ ๋‹ฟ์•˜๋‹ค๋Š” ๋œป์ด๋ฏ€๋กœ, ๊ทธ๋•Œ๋„ ๋ถ€๋ฅธ๋‹ค.\n * ๊ทธ ๋‘˜์„ ๊ฐ™๊ฒŒ ๋‘๋ฉด ์กฐ์šฉํ•œ ์›๋ณธ์ด ๋Š๊ธด ์›๋ณธ์œผ๋กœ ๋ณด์ธ๋‹ค.\n */\n static clearIngestReadFailure(domainId: string, instanceId: string): void {\n const ledger = this.ingestLedgers[runtimeKey(domainId, instanceId)]\n if (ledger) clearReadFailure(ledger)\n }\n\n /**\n * ์ €๋„์— **์ ์€ ๊ฒƒ**์„ ๊ฐ™์€ ์žฅ๋ถ€์— ๋‚จ๊ธด๋‹ค โ€” ์œ ์ž…๊ณผ ๊ฐ™์€ 10๋ถ„ ์ฐฝ์—.\n *\n * โ”€โ”€ ์™œ ์œ ์ž… ์žฅ๋ถ€์— ๋„ฃ๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ƒˆ ์žฅ๋ถ€๋ฅผ ๋งŒ๋“ค๋ฉด ใ€Œ๋‹ซํžŒ ์ฐฝ๋งŒ ์ตœ๊ทผใ€ยทใ€Œ0 ๊ณผ ์—†์Œ์„ ๊ฐ€๋ฅธ๋‹คใ€ยท์˜์†์„ ๋‘ ๋ฒŒ ์ง€์ผœ์•ผ ํ•˜๊ณ , ๊ทธ์ค‘ ํ•œ ๋ฒŒ๋งŒ\n * ๊ณ ์ณ์ง€๋Š” ๊ฒƒ์ด ๋ณดํ†ต์ด๋‹ค. ์œ ์ž… ์ฐฝ์€ ๊ทธ ๊ทœ์œจ์ด ์ด๋ฏธ ๋“ค์–ด ์žˆ๊ณ  ๋‹ซํž ๋•Œ ํ–‰์œผ๋กœ ๋‚จ๋Š”๋‹ค.\n *\n * โ”€โ”€ ์ด ๊ฐ’์ด ์—†์œผ๋ฉด ๋ฌด์—‡์„ ๋ชป ๋ณด๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๊ณ„๊ธฐ(`journalRate`)๋Š” **์ง€๊ธˆ**๋งŒ ๋‹ตํ•œ๋‹ค. ํ”„๋กœ์„ธ์Šค๋ฅผ ๋‹ค์‹œ ๋„์šฐ๋ฉด 0 ์—์„œ ์‹œ์ž‘ํ•˜๋ฏ€๋กœ ใ€Œ์–ด์ œ ์ด ์‹œ๊ฐ์—๋„\n * ์ด๋žฌ๋‚˜ใ€ยทใ€Œ๊ณ ์นœ ๋’ค๋กœ ์ค„์—ˆ๋‚˜ใ€๋ฅผ ๋ฌผ์„ ์ž๋ฆฌ๊ฐ€ ์—†๋‹ค. 2026-08-20 ์— ๊ณ ์นœ ๊ฒƒ์ด ๋ฐ”๋กœ ์“ฐ๊ธฐ ๊ฒฝ๋กœ์ด๋ฏ€๋กœ,\n * ๋˜๋Œ์•„๊ฐ€๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.\n */\n static recordJournalWrite(domainId: string, instanceId: string, rows: number, nowMs = Date.now()): void {\n const key = runtimeKey(domainId, instanceId)\n const ledger = this.ingestLedgers[key] ?? (this.ingestLedgers[key] = newIngestLedger())\n recordLedgerWrite(ledger, rows, nowMs, closed => this.onWindowClosed?.({ domainId, instanceId }, closed))\n }\n\n /**\n * ใ€Œ์ด ํŠธ์œˆ์ด ํ˜„์žฅ๊ณผ ๋งž์ถฐ์ง€๊ณ  ์žˆ๋‚˜ใ€ โ€” ํ•œ๋ˆˆ ํŒ์ • + ์ถ”์ด + ์‚ฌ์œ  + ํ‘œ๋ณธ.\n *\n * ์กฐํšŒํ•  ๋•Œ ์ฐฝ์„ ํ•œ ๋ฒˆ ๊ตด๋ฆฐ๋‹ค: ์œ ์ž…์ด ๋ฉˆ์ถ”๋ฉด ๋‹ค์Œ ์ธ์ œ์ŠคํŠธ๊ฐ€ ์—†์–ด ์ฐฝ์ด ์˜์›ํžˆ ๋‹ซํžˆ์ง€ ์•Š๋Š”๋ฐ, ๊ทธ๋Ÿฌ๋ฉด\n * ใ€Œ์ตœ๊ทผใ€์ด ์˜›๊ฒƒ์œผ๋กœ ๋‚จ๋Š”๋‹ค. ํƒ€์ด๋จธ๋ฅผ ๋‘์ง€ ์•Š๋Š” ์ด์œ ๋Š” ํŠธ์œˆ๋งˆ๋‹ค ํƒ€์ด๋จธ๋ฅผ ๊ฑธ๋ฉด ๊ทธ ํƒ€์ด๋จธ๋“ค์ด ๋‹ค์‹œ\n * ๋ฉ”์ธ ๋ฃจํ”„์— ์–นํžˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค(์˜ค๋Š˜ ํ™•์ธํ•œ ๊ทธ ๋ถ€ํ•˜๋ฅผ ์ด ๊ธฐ๋Šฅ์ด ๋‹ค์‹œ ๋งŒ๋“ค ์ด์œ ๊ฐ€ ์—†๋‹ค).\n */\n /**\n * ๋„๋ฉ”์ธ์˜ ํŠธ์œˆ๋งˆ๋‹ค **ํ•œ ์ค„ ์š”์•ฝ** โ€” ๋ชฉ๋ก ํ™”๋ฉด๊ณผ ๋ฏธ๋‹ˆ ์ถ”์ด์šฉ.\n *\n * โ”€โ”€ ์™œ ์ƒ์„ธ์™€ ๋”ฐ๋กœ์ธ๊ฐ€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * `ingestHealthOf` ๋Š” ์‚ฌ์œ  ๋ฌธ๊ตฌ์™€ **๋ ˆ์ฝ”๋“œ ์›๋ฌธ ํ‘œ๋ณธ**๊นŒ์ง€ ๋‚ธ๋‹ค. ๋ชฉ๋ก์— ํŠธ์œˆ์ด ์Šค๋ฌด ๊ฐœ๋ฉด ๊ทธ ์›๋ฌธ์ด\n * ์Šค๋ฌด ๋ฒŒ ์‹ค๋ ค ์กฐํšŒ๊ฐ€ ๋ฌด๊ฑฐ์›Œ์ง€๊ณ , ํ™”๋ฉด์€ ์–ด์ฐจํ”ผ ๊ทธ๊ฒƒ์„ ๊ทธ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ž˜์„œ ์—ฌ๊ธฐ์„œ๋Š” **์ˆซ์ž๋งŒ** ๋‚ธ๋‹ค.\n *\n * ์ถ”์ด๋Š” ์ฐฝ๋‹น ์ˆซ์ž ๋„ท์ด๋ผ ์ŠคํŒŒํฌ๋ผ์ธ ํ•˜๋‚˜์— ์ถฉ๋ถ„ํ•˜๊ณ  ๊ฐ€๋ณ๋‹ค.\n *\n * โ”€โ”€ ๋“ฑ๋ก๋œ ํŠธ์œˆ์„ ๊ธฐ์ค€์œผ๋กœ ํ›‘๋Š”๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๋„๋Š” ํŠธ์œˆ๋งŒ ํ›‘์œผ๋ฉด ใ€Œ๊ณ ์น˜๋ ค๊ณ  ๋ฉˆ์ถฐ ๋‘” ํŠธ์œˆใ€์ด ๋ชฉ๋ก์—์„œ ์‚ฌ๋ผ์ง„๋‹ค โ€” ์‚ฌ๋žŒ์ด ๋ฐฉ๊ธˆ ๋ฉˆ์ถ˜ ๊ทธ๊ฒƒ์„ ๋ณด๋ ค๊ณ \n * ๋ชฉ๋ก์„ ์—ฌ๋Š”๋ฐ ์—†์œผ๋ฉด ๊ฒฐํ•จ์œผ๋กœ ์ฝ๋Š”๋‹ค. ๊ทธ๋ž˜์„œ ํ˜ธ์ถœ๋ถ€(๋ชฉ๋ก ํ™”๋ฉด)๊ฐ€ ์•„๋Š” instanceId ๋“ค์„ ๋ฐ›๋Š”๋‹ค.\n */\n static ingestHealthBrief(\n domainId: string,\n instanceIds: string[]\n ): { instanceId: string; verdict: string; acceptedRatio: number | null; trend: { offered: number; rejected: number; undelivered: number; rows: number }[]; lastAt: string | null }[] {\n return instanceIds.map(instanceId => {\n const full = this.ingestHealthOf(domainId, instanceId)\n return {\n instanceId,\n verdict: full.verdict,\n /* ์ตœ๊ทผ **๋‹ซํžŒ** ์ฐฝ์˜ ํ†ต๊ณผ์œจ. ์ฐฝ์ด ์•ˆ ๋‹ซํ˜”์œผ๋ฉด ๋น„์šด๋‹ค โ€” 0 ์ด๋‚˜ 1 ๋กœ ์ฑ„์šฐ์ง€ ์•Š๋Š”๋‹ค. */\n acceptedRatio: full.recent?.acceptedRatio ?? null,\n /*\n * ์ŠคํŒŒํฌ๋ผ์ธ์šฉ โ€” ์ฐฝ๋งˆ๋‹ค ์…‹. **๋ฏธ์ „๋‹ฌ์„ ๋นผ๋†“์œผ๋ฉด ์ŠคํŒŒํฌ๋ผ์ธ์ด ๊ฑฐ์ง“์„ ๊ทธ๋ฆฐ๋‹ค**: ๋ฒ„๋ ค์ง„ ๊ฒƒ์„\n * ํ†ต๊ณผ๋กœ ์„ธ๋ฉด ํŠธ์œˆ์ด ๋ฉˆ์ถ˜ ๊ตฌ๊ฐ„์—์„œ๋„ ์„ ์ด 100% ์— ๋ถ™๋Š”๋‹ค.\n */\n /* ์ ํžŒ ํ–‰๋„ ํ•จ๊ป˜ โ€” ์‹œ๋ฎฌ ํŠธ์œˆ์€ ์œ ์ž…์ด 0 ์ด๋ผ ์ด ๊ฐ’ ์—†์ด๋Š” ์ถ”์ด๊ฐ€ ๋นˆ ์„ ์œผ๋กœ ๋ณด์ธ๋‹ค. */\n trend: full.trend.map(w => ({ offered: w.offered, rejected: w.rejected, undelivered: w.undelivered, rows: w.rows })),\n lastAt: full.lastAt\n }\n })\n }\n\n /**\n * ํ•œ ํŠธ์œˆ์˜ ๋™๊ธฐํ™” ๊ฑด๊ฐ•.\n *\n * โ”€โ”€ ์กฐํšŒ๊ฐ€ ์žฅ๋ถ€๋ฅผ ์ „์ง„์‹œํ‚จ๋‹ค(์˜๋„) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ฐฝ์€ **๋‹ค์Œ ์œ ์ž…์ด ์žˆ์„ ๋•Œ** ๋‹ซํžŒ๋‹ค. ๊ทธ๋ž˜์„œ ํ”ผ๋“œ๊ฐ€ ์ฃฝ์œผ๋ฉด ๋งˆ์ง€๋ง‰ ์ฐฝ์ด ์—ด๋ฆฐ ์ฑ„๋กœ ๋‚จ์•„ ์˜์›ํžˆ ์˜์†๋˜์ง€\n * ์•Š๊ณ , ์ถ”์ด์—๋„ ๋“ค์–ด๊ฐ€์ง€ ์•Š๋Š”๋‹ค. ์กฐํšŒ ์‹œ์ ์— ํ•œ ๋ฒˆ ๊ตด๋ ค ์ฃผ๋ฉด ๊ทธ ๋งˆ์ง€๋ง‰ ์ฐฝ์ด ๋‹ซํžˆ๋ฉด์„œ ์˜์† ํ›…๋„ ๋ถˆ๋ฆฐ๋‹ค\n * โ€” ์ฆ‰ **์ฃฝ์€ ํ”ผ๋“œ์˜ ๋งˆ์ง€๋ง‰ ๊ตฌ๊ฐ„์„ ์žƒ์ง€ ์•Š๊ธฐ ์œ„ํ•ด** ์ฝ๊ธฐ๊ฐ€ ๊ตด๋ฆฐ๋‹ค. ๋ถ€์ˆ˜ํšจ๊ณผ์ง€๋งŒ ํ•„์š”ํ•œ ๋ถ€์ˆ˜ํšจ๊ณผ๋‹ค.\n *\n * ์‹œ๊ฐ์€ **ํ•œ ๋ฒˆ๋งŒ ์ฝ์–ด** ๊ตด๋ฆฌ๊ธฐ์™€ ํŒ์ •์— ๊ฐ™์€ ๊ฐ’์„ ์“ด๋‹ค. ๋‘ ๋ฒˆ ์ฝ์œผ๋ฉด ๊ทธ ์‚ฌ์ด์— ์ฐฝ์ด ๋‹ซํ˜€ ํŒ์ •์ด\n * ๊ตด๋ฆฌ๊ธฐ ์ „ ์ƒํƒœ๋ฅผ ๋ณด๋Š” ์ผ์ด ์ƒ๊ธด๋‹ค.\n */\n static ingestHealthOf(domainId: string, instanceId: string): IngestHealthView {\n const key = runtimeKey(domainId, instanceId)\n const nowMs = Date.now()\n const ledger = this.ingestLedgers[key]\n if (ledger) {\n rollIngestWindow(ledger, nowMs, undefined, closed => this.onWindowClosed?.({ domainId, instanceId }, closed))\n }\n\n const inst = this.instances[key]\n const feedState = liveFeedStateOf({\n restartPolicy: inst?.restartPolicy,\n running: !!inst,\n instanceId\n })\n return ingestHealth(ledger, feedState, undefined, nowMs)\n }\n\n /**\n * ๋„๋Š” ์ธ์Šคํ„ด์Šค ์ „์ฒด์˜ ๊ณ„์ธก(๋ชจ๋‹ˆํ„ฐ ๋Œ€์‹œ๋ณด๋“œ์šฉ) โ€” **์‹œ๋ฎฌ๊ณผ ๋ฏธ๋Ÿฌ๋ฅผ ํ•จ๊ป˜**.\n *\n * ์˜ˆ์ „์—๋Š” ์‹œ๋ฎฌ์— ๊ณ„๊ธฐ๊ฐ€ ์—†์–ด ์ด ๋ชฉ๋ก์—์„œ ์กฐ์šฉํžˆ ๋น ์กŒ๋‹ค(๊ณ„๊ธฐ๊ฐ€ `null` ์ด๋ผ ๊ฑธ๋Ÿฌ์กŒ๋‹ค). ๋„๋Š” ํŠธ์œˆ\n * ๋Œ€๋ถ€๋ถ„์ด ์‹œ๋ฎฌ์ธ ์„œ๋ฒ„์—์„œ ๊ทธ ๋ชฉ๋ก์€ ใ€Œ๋ถ€ํ•˜๊ฐ€ ๊ฑฐ์˜ ์—†๋‹คใ€๋กœ ๋ณด์˜€๋‹ค.\n */\n static async allMetrics(domainId?: string): Promise<any[]> {\n /* ๋„๋ฉ”์ธ ์—†์ด ๋ถ€๋ฅด๋ฉด ์ „ ํ…Œ๋„ŒํŠธ๋ฅผ ํ›‘๋Š”๋‹ค(๋‚ด๋ถ€ ๋ชจ๋‹ˆํ„ฐ์šฉ) โ€” ํ‚ค์—์„œ ๋„๋ฉ”์ธ์„ ๋˜๋Œ๋ ค ๊ฐ์ž์—๊ฒŒ ๋ฌป๋Š”๋‹ค. */\n const rows = Object.keys(this.instances)\n .filter(key => !domainId || isOfDomain(key, domainId))\n .map(key => {\n const at = parseRuntimeKey(key)\n return this.metrics(at.domainId, at.instanceId)\n })\n .filter(Boolean)\n if (!rows.length || !domainId) return rows\n // ํ‘œ์‹œ ์ด๋ฆ„ ๋ถ€์—ฌ โ€” ์‹คํ–‰์ค‘ ์นด๋“œ๊ฐ€ id ๋งŒ ๋ณด์ด์ง€ ์•Š๋„๋ก ๊ณต๊ฐ„๋ช…์„ ์‹ค์–ด์ค€๋‹ค(๊ณต๊ฐ„ ์นด๋“œ์™€ ๋™์ผ). name=๊ณต๊ฐ„๋ช… ํด๋ฐฑ spaceId ํด๋ฐฑ instanceId.\n const insts = await getRepository(TwinInstance).find({ where: { domain: { id: domainId } } })\n const spaceOf = new Map(insts.map(i => [i.instanceId, i.spaceId]))\n /* ์šฉ๋„ ์„ ์–ธ๋„ ํ•จ๊ป˜ ์‹ค์–ด ๋ณด๋‚ธ๋‹ค โ€” ํ™”๋ฉด์ด ๊ณต๊ฐ„ ์ด๋ฆ„์œผ๋กœ ๋ฒค์น˜๋ฅผ **์ถ”์ธกํ•˜์ง€ ์•Š๊ฒŒ** ํ•œ๋‹ค.\n ์ถ”์ธกํ•˜๋ฉด `loadtest-` ๋กœ ์ด๋ฆ„ ์ง€์€ ์šด์˜ ํŠธ์œˆ์— ๋ฒค์น˜ ๋”ฑ์ง€๊ฐ€ ๋ถ™๋Š”๋‹ค. */\n const purposeOf = new Map(insts.map(i => [i.instanceId, i.purpose]))\n const nameOf = new Map((await getRepository(TwinSpace).find({ where: { domain: { id: domainId } } })).map(s => [s.spaceId, s.name]))\n for (const r of rows) {\n const sp = spaceOf.get(r.instanceId)\n r.spaceId = sp\n r.purpose = purposeOf.get(r.instanceId)\n r.name = (sp && nameOf.get(sp)) || sp || r.instanceId\n }\n return rows\n }\n\n /*\n * `buildForecastKernel` ์€ **์‚ฌ๋ผ์กŒ๋‹ค**(ํ†ตํ•ฉ P3, 2026-08-01).\n *\n * ๋ผ์ด๋ธŒ๊ฐ€ `StateProjector` ์˜€์„ ๋•Œ๋Š” ์ปค๋„์ด ์—†์–ด์„œ, ์˜ˆ์ธกํ•˜๋ ค๋ฉด ๊ด€์ธก ์Šค๋ƒ…์ƒท + ์ €๋„์˜ ์˜ค๋” ์›๊ฐ’์œผ๋กœ\n * **์ผํšŒ์šฉ ์ปค๋„์„ ์„ธ์›Œ์•ผ** ํ–ˆ๋‹ค. ์ด์ œ ๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ณง ์ปค๋„์ด๋ฏ€๋กœ(`startLive`) ๊ทธ ์ž๋ฆฌ์—์„œ\n * `fork` ํ•˜๋ฉด ๋œ๋‹ค โ€” `TwinEngine.kernel(id)` ๊ฐ€ simยทlive ๋‘˜ ๋‹ค ๋Œ๋ ค์ค€๋‹ค.\n *\n * (์˜ค๋” ์›๊ฐ’์„ ์ €๋„์—์„œ ๋˜์ฐพ๋˜ ์ด์œ ๋„ ์‚ฌ๋ผ์กŒ๋‹ค โ€” ์ƒํƒœ๊ฐ€ requestedยทfulfilledยทlines ๋ฅผ ์ง€ํ‚จ๋‹ค.)\n */\n\n /**\n * ์˜ˆ์ธก์šฉ ์ปค๋„์„ **์ž„์˜ ์‹œ๊ฐ T ๊ธฐ์ค€**์œผ๋กœ ์žฌ๊ตฌ์„ฑ โ€” ๊ณผ๊ฑฐ-vantage ์˜ˆ์ธก(๋ฐฑํ…Œ์ŠคํŠธ)ยท\"๊ทธ๋•Œ ์„œ์„œ ๋ณธ ๋ฏธ๋ž˜\".\n * recover(untilTime)๋กœ T ์‹œ์  ์ƒํƒœ๋ฅผ, T ์ดํ•˜ ์˜ค๋” ๊ด€์ธก์„ ๋ชจ์•„ hydrate โ†’ monteCarloForecast ๊ฐ€ T ์—์„œ ์•ž์œผ๋กœ ์‹คํ–‰ํ•œ๋‹ค.\n * sim/live ๋ฌด๊ด€(์ €๋„ ๊ธฐ๋ฐ˜ ์žฌ๊ตฌ์„ฑ). untilTime ์ƒ๋žต ์‹œ ์ตœ์‹ . ๋„๋ฉ”์ธ ์Šค์ฝ”ํ”„(regยทjournal ์กฐํšŒ๊ฐ€ domainId).\n */\n static async buildForecastKernelAt(domainId: string, instanceId: string, untilTime?: string): Promise<any | null> {\n const reg = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!reg?.model) return null\n const Kernel = kernelFor(reg.kind)\n const k = new Kernel(domainId, undefined, this.productionSpecOf(reg.model as TwinModelDef))\n k.loadTwinModel(reg.model as TwinModelDef)\n this.applyOperations(k, reg.model, instanceId) // ์˜ˆ์ธก๋„ ๊ฐ™์€ ๋ช…์„ธ๋กœ ๊ตด๋Ÿฌ์•ผ ํ•œ๋‹ค(ํ™”๋ฉด๊ณผ ๋‹ค๋ฅธ ์ˆซ์ž ๊ธˆ์ง€)\n await this.installEstimators(k, domainId, instanceId, reg.model) // ์˜ˆ์ธก์€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค โ€” ์‹ค์ธก์„ ๋†“์น˜๋ฉด ์˜ˆ์ธก์ด ์ƒ์ˆ˜๋กœ ๊ณ„์‚ฐ๋œ๋‹ค\n const state = await this.recover(domainId, instanceId, undefined, untilTime).catch(() => null)\n if (!state) return null\n const cutoff = untilTime != null ? Date.parse(untilTime) : Infinity\n /*\n * journal-fold: ์˜ค๋”์˜ ๋งˆ์ง€๋ง‰ ์ƒํƒœ๋Š” ๊ทธ ์˜ค๋”์— ์ผ์–ด๋‚œ ์‚ฌ์‹ค๋“ค์„ ์ ‘์–ด์•ผ ๋‚˜์˜จ๋‹ค.\n *\n * **์—†์–ด์งˆ ์กฐ๊ฑด** โ€” ์ง€๊ธˆ ์ด ์ฝ๊ธฐ์—๋Š” ์ƒํ•œ์ด ์—†๊ณ  `eventType` ์— ์ธ๋ฑ์Šค๋„ ์—†๋‹ค. ๊ทธ๋ž˜์„œ ์ €๋„์ด ํฐ\n * ํŠธ์œˆ์—์„œ๋Š” ์ด ํ•œ ๋ฒˆ์ด ๊ทธ ํŠธ์œˆ์˜ ์ €๋„ ์ „์ฒด ์ฃผ์‚ฌ๋‹ค. ์˜ค๋” ์ƒํƒœ๋ฅผ ๋”ฐ๋กœ ์ ‘์–ด ๋‘” ํ‘œ(ํˆฌ์˜)๋ฅผ ๋‘๊ฑฐ๋‚˜,\n * `(domain, instanceId, eventType, revision)` ์ธ๋ฑ์Šค๋ฅผ ๋ถ™์ด๊ณ  ์ปค์„œ๋ฅผ ๋„ฃ์œผ๋ฉด ์ด ์˜ˆ์™ธ๋Š” ์‚ฌ๋ผ์ง„๋‹ค.\n * ์‹œ๊ฐ ์ƒํ•œ(`cutoff`)์„ SQL ๋กœ ๋‚ด๋ ค๋„ ์ ˆ๋ฐ˜์€ ์ค€๋‹ค.\n */\n const rows = await getRepository(TwinEvent).find({ where: { domain: { id: domainId }, instanceId, eventType: OP_EVENT.order }, order: { revision: 'ASC' } })\n const latest = new Map<string, any>()\n for (const r of rows) {\n if (Number.isFinite(cutoff) && (r.eventTime?.getTime() ?? NaN) > cutoff) continue\n const d = (r.payload as any)?.data\n if (d?.orderId) latest.set(d.orderId, d)\n }\n k.hydrateObserved(state, [...latest.values()])\n return k\n }\n\n /** ํ˜„์žฌ ์ „์ฒด ์Šค๋ƒ…์ƒท โ€” ๋ผ์ด๋ธŒ ์šฐ์„ , ์—†์œผ๋ฉด ์ €๋„ ๋ณต๊ตฌ ์บ์‹œ. */\n static snapshot(domainId: string, id: string): any {\n const inst = this.instances[runtimeKey(domainId, id)]\n if (inst?.mode === 'live' && inst.projector) {\n /* live: **์ปค๋„์ด ์ฃผ๋ชฉ ์‹ ํ˜ธ๋ฅผ ์Šค์Šค๋กœ ๋‚ธ๋‹ค**(๊ด€์ธก ๋ชจ๋“œ) โ€” ํ˜ธ์ŠคํŠธ๊ฐ€ ๋ง๋ถ™์ด๋˜ withLiveAttentions ๋Š”\n * ํ•„์š” ์—†๋‹ค. OEE ๋งŒ ํ˜ธ์ŠคํŠธ๊ฐ€ ์ฑ„์šด๋‹ค: ์› ์‹œ์Šคํ…œ์ด ์‹œ๊ฐ„ ๋ˆ„์ ์„ ๋ณด๋‚ด ์ฃผ์ง€ ์•Š์•„ ์ƒํƒœ ์ „์ด๋ฅผ ์ ๋ถ„ํ•ด\n * ๋งŒ๋“œ๋Š” ๊ฐ’์ด๋ผ ์ปค๋„์ด ๋Œ€์‹ ํ•  ์ˆ˜ ์—†๋‹ค(์ ํ•ฉ์„ฑ ํ•˜๋„ค์Šค์˜ ์œ ์ผํ•œ ์˜ˆ์™ธ). */\n const st = inst.projector.snapshot()\n return inst.oee ? withLiveOee(st, inst.oee) : st\n }\n return inst?.runtime?.resync() ?? this.recovered[runtimeKey(domainId, id)]\n }\n}\n"]}