@things-factory/headless-twin 10.1.278 โ†’ 10.1.280

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 (614) hide show
  1. package/package.json +21 -7
  2. package/dist-server/engine/attention-digest.js.map +0 -1
  3. package/dist-server/engine/canonical-ingest.js.map +0 -1
  4. package/dist-server/engine/checkpoint-fold.js.map +0 -1
  5. package/dist-server/engine/command-routing.js.map +0 -1
  6. package/dist-server/engine/declared-stimulus.js.map +0 -1
  7. package/dist-server/engine/energy-topology.js.map +0 -1
  8. package/dist-server/engine/event-time.js.map +0 -1
  9. package/dist-server/engine/index.js.map +0 -1
  10. package/dist-server/engine/ingest-dedupe.js.map +0 -1
  11. package/dist-server/engine/ingest-health.js.map +0 -1
  12. package/dist-server/engine/integration-coverage.js.map +0 -1
  13. package/dist-server/engine/integration-probes.js.map +0 -1
  14. package/dist-server/engine/integration-runner.js.map +0 -1
  15. package/dist-server/engine/integration-target-profile.js.map +0 -1
  16. package/dist-server/engine/kpi-baseline.js.map +0 -1
  17. package/dist-server/engine/kpi-fold.js.map +0 -1
  18. package/dist-server/engine/kpi-query.js.map +0 -1
  19. package/dist-server/engine/kpi-target.js.map +0 -1
  20. package/dist-server/engine/live-attentions.js.map +0 -1
  21. package/dist-server/engine/live-feed-registry.js.map +0 -1
  22. package/dist-server/engine/load-meter.js.map +0 -1
  23. package/dist-server/engine/local-declarations.js.map +0 -1
  24. package/dist-server/engine/log.js.map +0 -1
  25. package/dist-server/engine/loop-lag.js.map +0 -1
  26. package/dist-server/engine/measured-estimator.js.map +0 -1
  27. package/dist-server/engine/measured-yield.js.map +0 -1
  28. package/dist-server/engine/model-basis.js.map +0 -1
  29. package/dist-server/engine/model-gap.js.map +0 -1
  30. package/dist-server/engine/model-refusal.js.map +0 -1
  31. package/dist-server/engine/model-vocabulary.js.map +0 -1
  32. package/dist-server/engine/oee-accumulator.js.map +0 -1
  33. package/dist-server/engine/operation-basis.js.map +0 -1
  34. package/dist-server/engine/producer-guard.js.map +0 -1
  35. package/dist-server/engine/property-effects.js.map +0 -1
  36. package/dist-server/engine/read-time.js.map +0 -1
  37. package/dist-server/engine/restart-policy.js.map +0 -1
  38. package/dist-server/engine/runtime-key.js.map +0 -1
  39. package/dist-server/engine/spec-coverage.js.map +0 -1
  40. package/dist-server/engine/stage-path.js.map +0 -1
  41. package/dist-server/engine/state-axes.js.map +0 -1
  42. package/dist-server/engine/structure-diff.js.map +0 -1
  43. package/dist-server/engine/travel-estimator.js.map +0 -1
  44. package/dist-server/engine/twin-engine.js.map +0 -1
  45. package/dist-server/engine/twin-state-channel.js.map +0 -1
  46. package/dist-server/engine/warm-start.js.map +0 -1
  47. package/dist-server/index.js.map +0 -1
  48. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js.map +0 -1
  49. package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js.map +0 -1
  50. package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js.map +0 -1
  51. package/dist-server/migrations/1786300000000-IndexEventTypeByTime.js.map +0 -1
  52. package/dist-server/migrations/1786400000000-IndexEventCreatedAt.js.map +0 -1
  53. package/dist-server/migrations/1786500000000-CreateTwinSubjectEvents.js.map +0 -1
  54. package/dist-server/migrations/1786600000000-RenameOperatoMesAdapterType.js.map +0 -1
  55. package/dist-server/migrations/1786700000000-AddDispatchRetryColumns.js.map +0 -1
  56. package/dist-server/migrations/1786800000000-CreateTwinReferenceReconciliations.js.map +0 -1
  57. package/dist-server/migrations/index.js.map +0 -1
  58. package/dist-server/routes.js.map +0 -1
  59. package/dist-server/service/actuation/actuation-advisor.js.map +0 -1
  60. package/dist-server/service/actuation/actuation-outcome.js.map +0 -1
  61. package/dist-server/service/actuation/actuation-rule-resolver.js.map +0 -1
  62. package/dist-server/service/actuation/actuation-rule.js.map +0 -1
  63. package/dist-server/service/actuation/approval-gateway.js.map +0 -1
  64. package/dist-server/service/actuation/catch-up-effects.js.map +0 -1
  65. package/dist-server/service/actuation/command-dispatcher.js.map +0 -1
  66. package/dist-server/service/actuation/command-store.js.map +0 -1
  67. package/dist-server/service/actuation/dispatch-after-approval.js.map +0 -1
  68. package/dist-server/service/actuation/effect-match.js.map +0 -1
  69. package/dist-server/service/actuation/index.js.map +0 -1
  70. package/dist-server/service/actuation/retry-plan.js.map +0 -1
  71. package/dist-server/service/actuation/rule-evaluate.js.map +0 -1
  72. package/dist-server/service/actuation/rule-loop.js.map +0 -1
  73. package/dist-server/service/actuation/rule-runner.js.map +0 -1
  74. package/dist-server/service/actuation/rule-wiring.js.map +0 -1
  75. package/dist-server/service/actuation/settle-effects.js.map +0 -1
  76. package/dist-server/service/actuation/sweep-dispatch.js.map +0 -1
  77. package/dist-server/service/actuation/twin-command-resolver.js.map +0 -1
  78. package/dist-server/service/actuation/twin-command.js.map +0 -1
  79. package/dist-server/service/actuation/twin-now.js.map +0 -1
  80. package/dist-server/service/index.js.map +0 -1
  81. package/dist-server/service/reference/actuation-routing.js.map +0 -1
  82. package/dist-server/service/reference/actuation-target.js.map +0 -1
  83. package/dist-server/service/reference/actuation-verification.js.map +0 -1
  84. package/dist-server/service/reference/attention-lane.js.map +0 -1
  85. package/dist-server/service/reference/connection-portability-resolver.js.map +0 -1
  86. package/dist-server/service/reference/connection-portability.js.map +0 -1
  87. package/dist-server/service/reference/control-routing.js.map +0 -1
  88. package/dist-server/service/reference/discovery-result.js.map +0 -1
  89. package/dist-server/service/reference/fill-cadence.js.map +0 -1
  90. package/dist-server/service/reference/fill-dedupe.js.map +0 -1
  91. package/dist-server/service/reference/fill-loop.js.map +0 -1
  92. package/dist-server/service/reference/fill-span.js.map +0 -1
  93. package/dist-server/service/reference/hook-contract.js.map +0 -1
  94. package/dist-server/service/reference/hook-rejected.js.map +0 -1
  95. package/dist-server/service/reference/hook-store.js.map +0 -1
  96. package/dist-server/service/reference/index.js.map +0 -1
  97. package/dist-server/service/reference/ingest-space.js.map +0 -1
  98. package/dist-server/service/reference/knob-defaults.js.map +0 -1
  99. package/dist-server/service/reference/live-cadence.js.map +0 -1
  100. package/dist-server/service/reference/live-feed-lease.js.map +0 -1
  101. package/dist-server/service/reference/live-ingest.js.map +0 -1
  102. package/dist-server/service/reference/reference-adapter.js.map +0 -1
  103. package/dist-server/service/reference/reference-assessment.js.map +0 -1
  104. package/dist-server/service/reference/reference-fill-run.js.map +0 -1
  105. package/dist-server/service/reference/reference-fill.js.map +0 -1
  106. package/dist-server/service/reference/reference-hook.js.map +0 -1
  107. package/dist-server/service/reference/reference-link-groups.js.map +0 -1
  108. package/dist-server/service/reference/reference-links.js.map +0 -1
  109. package/dist-server/service/reference/reference-live.js.map +0 -1
  110. package/dist-server/service/reference/reference-master.js.map +0 -1
  111. package/dist-server/service/reference/reference-probe.js.map +0 -1
  112. package/dist-server/service/reference/reference-progress-channel.js.map +0 -1
  113. package/dist-server/service/reference/reference-progress-subscription.js.map +0 -1
  114. package/dist-server/service/reference/reference-progress.js.map +0 -1
  115. package/dist-server/service/reference/reference-reconciliation-query.js.map +0 -1
  116. package/dist-server/service/reference/reference-reconciliation-writer.js.map +0 -1
  117. package/dist-server/service/reference/reference-reconciliation.js.map +0 -1
  118. package/dist-server/service/reference/reference-registry.js.map +0 -1
  119. package/dist-server/service/reference/reference-resolver.js.map +0 -1
  120. package/dist-server/service/reference/template-registry.js.map +0 -1
  121. package/dist-server/service/reference/twin-reference-reconciliation.js.map +0 -1
  122. package/dist-server/service/reference/twin-reference.js.map +0 -1
  123. package/dist-server/service/twin-attention/index.js.map +0 -1
  124. package/dist-server/service/twin-attention/twin-attention-query.js.map +0 -1
  125. package/dist-server/service/twin-audit/command-audit.js.map +0 -1
  126. package/dist-server/service/twin-audit/index.js.map +0 -1
  127. package/dist-server/service/twin-audit/twin-audit-event.js.map +0 -1
  128. package/dist-server/service/twin-audit/twin-audit-query.js.map +0 -1
  129. package/dist-server/service/twin-backfill/backfill-period-facts.js.map +0 -1
  130. package/dist-server/service/twin-backfill/backfill-shape.js.map +0 -1
  131. package/dist-server/service/twin-backfill/index.js.map +0 -1
  132. package/dist-server/service/twin-backfill/twin-backfill-resolver.js.map +0 -1
  133. package/dist-server/service/twin-control/index.js.map +0 -1
  134. package/dist-server/service/twin-control/twin-control-mutation.js.map +0 -1
  135. package/dist-server/service/twin-event/index.js.map +0 -1
  136. package/dist-server/service/twin-event/journal-count.js.map +0 -1
  137. package/dist-server/service/twin-event/twin-event-keys.js.map +0 -1
  138. package/dist-server/service/twin-event/twin-event-type.js.map +0 -1
  139. package/dist-server/service/twin-event/twin-event.js.map +0 -1
  140. package/dist-server/service/twin-forecast/forecast-metrics.js.map +0 -1
  141. package/dist-server/service/twin-forecast/forecast-tuning.js.map +0 -1
  142. package/dist-server/service/twin-forecast/gap-analytics.js.map +0 -1
  143. package/dist-server/service/twin-forecast/index.js.map +0 -1
  144. package/dist-server/service/twin-forecast/twin-forecast-query.js.map +0 -1
  145. package/dist-server/service/twin-ingest-window/index.js.map +0 -1
  146. package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js.map +0 -1
  147. package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js.map +0 -1
  148. package/dist-server/service/twin-ingest-window/twin-ingest-window.js.map +0 -1
  149. package/dist-server/service/twin-instance/index.js.map +0 -1
  150. package/dist-server/service/twin-instance/twin-instance.js.map +0 -1
  151. package/dist-server/service/twin-journal/event-type-split-shape.js.map +0 -1
  152. package/dist-server/service/twin-journal/event-type-split.js.map +0 -1
  153. package/dist-server/service/twin-journal/index.js.map +0 -1
  154. package/dist-server/service/twin-journal/journal-order.js.map +0 -1
  155. package/dist-server/service/twin-journal/twin-journal-query.js.map +0 -1
  156. package/dist-server/service/twin-lifecycle/domain-catalog.js.map +0 -1
  157. package/dist-server/service/twin-lifecycle/index.js.map +0 -1
  158. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +0 -1
  159. package/dist-server/service/twin-metrics/index.js.map +0 -1
  160. package/dist-server/service/twin-metrics/twin-metrics-query.js.map +0 -1
  161. package/dist-server/service/twin-model/axis-journal-evidence.js.map +0 -1
  162. package/dist-server/service/twin-model/choose-recipe.js.map +0 -1
  163. package/dist-server/service/twin-model/epcis-coverage.js.map +0 -1
  164. package/dist-server/service/twin-model/external-resolver.js.map +0 -1
  165. package/dist-server/service/twin-model/iec61850-coverage.js.map +0 -1
  166. package/dist-server/service/twin-model/index.js.map +0 -1
  167. package/dist-server/service/twin-model/isa95-coverage.js.map +0 -1
  168. package/dist-server/service/twin-model/item-ref.js.map +0 -1
  169. package/dist-server/service/twin-model/name-index.js.map +0 -1
  170. package/dist-server/service/twin-model/project-structure.js.map +0 -1
  171. package/dist-server/service/twin-model/standard-coverage.js.map +0 -1
  172. package/dist-server/service/twin-model/status-tally.js.map +0 -1
  173. package/dist-server/service/twin-model/twin-equipment.js.map +0 -1
  174. package/dist-server/service/twin-model/twin-lineage-query.js.map +0 -1
  175. package/dist-server/service/twin-model/twin-location.js.map +0 -1
  176. package/dist-server/service/twin-model/twin-model-item-query.js.map +0 -1
  177. package/dist-server/service/twin-model/twin-model-mutation.js.map +0 -1
  178. package/dist-server/service/twin-model/twin-model-query.js.map +0 -1
  179. package/dist-server/service/twin-model/twin-model-tree-query.js.map +0 -1
  180. package/dist-server/service/twin-model/twin-operation.js.map +0 -1
  181. package/dist-server/service/twin-readiness/index.js.map +0 -1
  182. package/dist-server/service/twin-readiness/twin-readiness-query.js.map +0 -1
  183. package/dist-server/service/twin-space/area-resolver.js.map +0 -1
  184. package/dist-server/service/twin-space/index.js.map +0 -1
  185. package/dist-server/service/twin-space/move-space.js.map +0 -1
  186. package/dist-server/service/twin-space/representation-role.js.map +0 -1
  187. package/dist-server/service/twin-space/space-integrity.js.map +0 -1
  188. package/dist-server/service/twin-space/twin-area.js.map +0 -1
  189. package/dist-server/service/twin-space/twin-space-area.js.map +0 -1
  190. package/dist-server/service/twin-space/twin-space-representation.js.map +0 -1
  191. package/dist-server/service/twin-space/twin-space-resolver.js.map +0 -1
  192. package/dist-server/service/twin-space/twin-space.js.map +0 -1
  193. package/dist-server/service/twin-state/index.js.map +0 -1
  194. package/dist-server/service/twin-state/twin-state-subscription.js.map +0 -1
  195. package/dist-server/service/twin-structure/index.js.map +0 -1
  196. package/dist-server/service/twin-structure/twin-structure.js.map +0 -1
  197. package/dist-server/service/twin-subject/event-subjects.js.map +0 -1
  198. package/dist-server/service/twin-subject/index.js.map +0 -1
  199. package/dist-server/service/twin-subject/item-resolver.js.map +0 -1
  200. package/dist-server/service/twin-subject/subject-query-shape.js.map +0 -1
  201. package/dist-server/service/twin-subject/twin-subject-backfill.js.map +0 -1
  202. package/dist-server/service/twin-subject/twin-subject-event.js.map +0 -1
  203. package/dist-server/service/twin-subject/twin-subject-fast-path.js.map +0 -1
  204. package/dist-server/service/twin-subject/twin-subject-query.js.map +0 -1
  205. package/dist-server/service/twin-subject/twin-subject-writer.js.map +0 -1
  206. package/dist-server/service/twin-target/index.js.map +0 -1
  207. package/dist-server/service/twin-target/twin-target-resolver.js.map +0 -1
  208. package/dist-server/service/twin-target/twin-target.js.map +0 -1
  209. package/dist-shared/axis-read.js.map +0 -1
  210. package/dist-shared/entity-delta.js.map +0 -1
  211. package/dist-shared/kpi-broadcast.js.map +0 -1
  212. package/dist-shared/touched-items.js.map +0 -1
  213. package/dist-shared/twin-level.js.map +0 -1
  214. package/server/engine/attention-digest.ts +0 -102
  215. package/server/engine/canonical-ingest.ts +0 -511
  216. package/server/engine/checkpoint-fold.ts +0 -12
  217. package/server/engine/command-routing.ts +0 -67
  218. package/server/engine/declared-stimulus.ts +0 -66
  219. package/server/engine/energy-topology.ts +0 -189
  220. package/server/engine/event-time.ts +0 -96
  221. package/server/engine/index.ts +0 -51
  222. package/server/engine/ingest-dedupe.ts +0 -24
  223. package/server/engine/ingest-health.ts +0 -24
  224. package/server/engine/integration-coverage.ts +0 -147
  225. package/server/engine/integration-probes.ts +0 -144
  226. package/server/engine/integration-runner.ts +0 -95
  227. package/server/engine/integration-target-profile.ts +0 -103
  228. package/server/engine/kpi-baseline.ts +0 -202
  229. package/server/engine/kpi-fold.ts +0 -1516
  230. package/server/engine/kpi-query.ts +0 -1210
  231. package/server/engine/kpi-target.ts +0 -248
  232. package/server/engine/live-attentions.ts +0 -30
  233. package/server/engine/live-feed-registry.ts +0 -59
  234. package/server/engine/load-meter.ts +0 -393
  235. package/server/engine/local-declarations.ts +0 -779
  236. package/server/engine/log.ts +0 -72
  237. package/server/engine/loop-lag.ts +0 -120
  238. package/server/engine/measured-estimator.ts +0 -91
  239. package/server/engine/measured-yield.ts +0 -89
  240. package/server/engine/model-basis.ts +0 -162
  241. package/server/engine/model-gap.ts +0 -168
  242. package/server/engine/model-refusal.ts +0 -31
  243. package/server/engine/model-vocabulary.ts +0 -82
  244. package/server/engine/oee-accumulator.ts +0 -195
  245. package/server/engine/operation-basis.ts +0 -131
  246. package/server/engine/producer-guard.ts +0 -64
  247. package/server/engine/property-effects.ts +0 -216
  248. package/server/engine/read-time.ts +0 -77
  249. package/server/engine/restart-policy.ts +0 -55
  250. package/server/engine/runtime-key.ts +0 -58
  251. package/server/engine/spec-coverage.ts +0 -105
  252. package/server/engine/stage-path.ts +0 -172
  253. package/server/engine/state-axes.ts +0 -60
  254. package/server/engine/structure-diff.ts +0 -88
  255. package/server/engine/travel-estimator.ts +0 -138
  256. package/server/engine/twin-engine.ts +0 -4979
  257. package/server/engine/twin-state-channel.ts +0 -39
  258. package/server/engine/warm-start.ts +0 -265
  259. package/server/index.ts +0 -90
  260. package/server/migrations/1786000000000-RenameTwinInstanceBoardToModel.ts +0 -43
  261. package/server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.ts +0 -54
  262. package/server/migrations/1786200000000-CarryLiveFeedCursor.ts +0 -53
  263. package/server/migrations/1786300000000-IndexEventTypeByTime.ts +0 -48
  264. package/server/migrations/1786400000000-IndexEventCreatedAt.ts +0 -38
  265. package/server/migrations/1786500000000-CreateTwinSubjectEvents.ts +0 -93
  266. package/server/migrations/1786600000000-RenameOperatoMesAdapterType.ts +0 -66
  267. package/server/migrations/1786700000000-AddDispatchRetryColumns.ts +0 -82
  268. package/server/migrations/1786800000000-CreateTwinReferenceReconciliations.ts +0 -39
  269. package/server/migrations/index.ts +0 -25
  270. package/server/routes.ts +0 -75
  271. package/server/service/actuation/actuation-advisor.ts +0 -131
  272. package/server/service/actuation/actuation-outcome.ts +0 -97
  273. package/server/service/actuation/actuation-rule-resolver.ts +0 -147
  274. package/server/service/actuation/actuation-rule.ts +0 -139
  275. package/server/service/actuation/approval-gateway.ts +0 -44
  276. package/server/service/actuation/catch-up-effects.ts +0 -152
  277. package/server/service/actuation/command-dispatcher.ts +0 -474
  278. package/server/service/actuation/command-store.ts +0 -236
  279. package/server/service/actuation/dispatch-after-approval.ts +0 -71
  280. package/server/service/actuation/effect-match.ts +0 -124
  281. package/server/service/actuation/index.ts +0 -27
  282. package/server/service/actuation/retry-plan.ts +0 -145
  283. package/server/service/actuation/rule-evaluate.ts +0 -352
  284. package/server/service/actuation/rule-loop.ts +0 -160
  285. package/server/service/actuation/rule-runner.ts +0 -216
  286. package/server/service/actuation/rule-wiring.ts +0 -84
  287. package/server/service/actuation/settle-effects.ts +0 -115
  288. package/server/service/actuation/sweep-dispatch.ts +0 -179
  289. package/server/service/actuation/twin-command-resolver.ts +0 -387
  290. package/server/service/actuation/twin-command.ts +0 -232
  291. package/server/service/actuation/twin-now.ts +0 -97
  292. package/server/service/index.ts +0 -100
  293. package/server/service/reference/actuation-routing.ts +0 -192
  294. package/server/service/reference/actuation-target.ts +0 -163
  295. package/server/service/reference/actuation-verification.ts +0 -85
  296. package/server/service/reference/attention-lane.ts +0 -21
  297. package/server/service/reference/connection-portability-resolver.ts +0 -171
  298. package/server/service/reference/connection-portability.ts +0 -329
  299. package/server/service/reference/control-routing.ts +0 -62
  300. package/server/service/reference/discovery-result.ts +0 -95
  301. package/server/service/reference/fill-cadence.ts +0 -29
  302. package/server/service/reference/fill-dedupe.ts +0 -66
  303. package/server/service/reference/fill-loop.ts +0 -153
  304. package/server/service/reference/fill-span.ts +0 -31
  305. package/server/service/reference/hook-contract.ts +0 -364
  306. package/server/service/reference/hook-rejected.ts +0 -53
  307. package/server/service/reference/hook-store.ts +0 -28
  308. package/server/service/reference/index.ts +0 -18
  309. package/server/service/reference/ingest-space.ts +0 -104
  310. package/server/service/reference/knob-defaults.ts +0 -59
  311. package/server/service/reference/live-cadence.ts +0 -129
  312. package/server/service/reference/live-feed-lease.ts +0 -56
  313. package/server/service/reference/live-ingest.ts +0 -94
  314. package/server/service/reference/reference-adapter.ts +0 -985
  315. package/server/service/reference/reference-assessment.ts +0 -250
  316. package/server/service/reference/reference-fill-run.ts +0 -179
  317. package/server/service/reference/reference-fill.ts +0 -223
  318. package/server/service/reference/reference-hook.ts +0 -479
  319. package/server/service/reference/reference-link-groups.ts +0 -21
  320. package/server/service/reference/reference-links.ts +0 -77
  321. package/server/service/reference/reference-live.ts +0 -420
  322. package/server/service/reference/reference-master.ts +0 -999
  323. package/server/service/reference/reference-probe.ts +0 -264
  324. package/server/service/reference/reference-progress-channel.ts +0 -26
  325. package/server/service/reference/reference-progress-subscription.ts +0 -78
  326. package/server/service/reference/reference-progress.ts +0 -95
  327. package/server/service/reference/reference-reconciliation-query.ts +0 -28
  328. package/server/service/reference/reference-reconciliation-writer.ts +0 -38
  329. package/server/service/reference/reference-reconciliation.ts +0 -55
  330. package/server/service/reference/reference-registry.ts +0 -17
  331. package/server/service/reference/reference-resolver.ts +0 -969
  332. package/server/service/reference/template-registry.ts +0 -85
  333. package/server/service/reference/twin-reference-reconciliation.ts +0 -27
  334. package/server/service/reference/twin-reference.ts +0 -190
  335. package/server/service/twin-attention/index.ts +0 -3
  336. package/server/service/twin-attention/twin-attention-query.ts +0 -70
  337. package/server/service/twin-audit/command-audit.ts +0 -114
  338. package/server/service/twin-audit/index.ts +0 -5
  339. package/server/service/twin-audit/twin-audit-event.ts +0 -158
  340. package/server/service/twin-audit/twin-audit-query.ts +0 -72
  341. package/server/service/twin-backfill/backfill-period-facts.ts +0 -168
  342. package/server/service/twin-backfill/backfill-shape.ts +0 -86
  343. package/server/service/twin-backfill/index.ts +0 -3
  344. package/server/service/twin-backfill/twin-backfill-resolver.ts +0 -35
  345. package/server/service/twin-control/index.ts +0 -3
  346. package/server/service/twin-control/twin-control-mutation.ts +0 -150
  347. package/server/service/twin-event/index.ts +0 -3
  348. package/server/service/twin-event/journal-count.ts +0 -53
  349. package/server/service/twin-event/twin-event-keys.ts +0 -215
  350. package/server/service/twin-event/twin-event-type.ts +0 -68
  351. package/server/service/twin-event/twin-event.ts +0 -250
  352. package/server/service/twin-forecast/forecast-metrics.ts +0 -106
  353. package/server/service/twin-forecast/forecast-tuning.ts +0 -40
  354. package/server/service/twin-forecast/gap-analytics.ts +0 -139
  355. package/server/service/twin-forecast/index.ts +0 -3
  356. package/server/service/twin-forecast/twin-forecast-query.ts +0 -486
  357. package/server/service/twin-ingest-window/index.ts +0 -7
  358. package/server/service/twin-ingest-window/twin-ingest-window-query.ts +0 -125
  359. package/server/service/twin-ingest-window/twin-ingest-window-writer.ts +0 -57
  360. package/server/service/twin-ingest-window/twin-ingest-window.ts +0 -113
  361. package/server/service/twin-instance/index.ts +0 -3
  362. package/server/service/twin-instance/twin-instance.ts +0 -199
  363. package/server/service/twin-journal/event-type-split-shape.ts +0 -112
  364. package/server/service/twin-journal/event-type-split.ts +0 -144
  365. package/server/service/twin-journal/index.ts +0 -3
  366. package/server/service/twin-journal/journal-order.ts +0 -20
  367. package/server/service/twin-journal/twin-journal-query.ts +0 -615
  368. package/server/service/twin-lifecycle/domain-catalog.ts +0 -51
  369. package/server/service/twin-lifecycle/index.ts +0 -3
  370. package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +0 -285
  371. package/server/service/twin-metrics/index.ts +0 -3
  372. package/server/service/twin-metrics/twin-metrics-query.ts +0 -172
  373. package/server/service/twin-model/axis-journal-evidence.ts +0 -57
  374. package/server/service/twin-model/choose-recipe.ts +0 -31
  375. package/server/service/twin-model/epcis-coverage.ts +0 -251
  376. package/server/service/twin-model/external-resolver.ts +0 -173
  377. package/server/service/twin-model/iec61850-coverage.ts +0 -111
  378. package/server/service/twin-model/index.ts +0 -25
  379. package/server/service/twin-model/isa95-coverage.ts +0 -320
  380. package/server/service/twin-model/item-ref.ts +0 -80
  381. package/server/service/twin-model/name-index.ts +0 -94
  382. package/server/service/twin-model/project-structure.ts +0 -213
  383. package/server/service/twin-model/standard-coverage.ts +0 -35
  384. package/server/service/twin-model/status-tally.ts +0 -37
  385. package/server/service/twin-model/twin-equipment.ts +0 -191
  386. package/server/service/twin-model/twin-lineage-query.ts +0 -327
  387. package/server/service/twin-model/twin-location.ts +0 -147
  388. package/server/service/twin-model/twin-model-item-query.ts +0 -1029
  389. package/server/service/twin-model/twin-model-mutation.ts +0 -503
  390. package/server/service/twin-model/twin-model-query.ts +0 -792
  391. package/server/service/twin-model/twin-model-tree-query.ts +0 -211
  392. package/server/service/twin-model/twin-operation.ts +0 -157
  393. package/server/service/twin-readiness/index.ts +0 -3
  394. package/server/service/twin-readiness/twin-readiness-query.ts +0 -96
  395. package/server/service/twin-space/area-resolver.ts +0 -75
  396. package/server/service/twin-space/index.ts +0 -8
  397. package/server/service/twin-space/move-space.ts +0 -262
  398. package/server/service/twin-space/representation-role.ts +0 -15
  399. package/server/service/twin-space/space-integrity.ts +0 -293
  400. package/server/service/twin-space/twin-area.ts +0 -63
  401. package/server/service/twin-space/twin-space-area.ts +0 -66
  402. package/server/service/twin-space/twin-space-representation.ts +0 -99
  403. package/server/service/twin-space/twin-space-resolver.ts +0 -582
  404. package/server/service/twin-space/twin-space.ts +0 -148
  405. package/server/service/twin-state/index.ts +0 -3
  406. package/server/service/twin-state/twin-state-subscription.ts +0 -62
  407. package/server/service/twin-structure/index.ts +0 -3
  408. package/server/service/twin-structure/twin-structure.ts +0 -96
  409. package/server/service/twin-subject/event-subjects.ts +0 -162
  410. package/server/service/twin-subject/index.ts +0 -10
  411. package/server/service/twin-subject/item-resolver.ts +0 -92
  412. package/server/service/twin-subject/subject-query-shape.ts +0 -84
  413. package/server/service/twin-subject/twin-subject-backfill.ts +0 -196
  414. package/server/service/twin-subject/twin-subject-event.ts +0 -101
  415. package/server/service/twin-subject/twin-subject-fast-path.ts +0 -346
  416. package/server/service/twin-subject/twin-subject-query.ts +0 -210
  417. package/server/service/twin-subject/twin-subject-writer.ts +0 -189
  418. package/server/service/twin-target/index.ts +0 -5
  419. package/server/service/twin-target/twin-target-resolver.ts +0 -142
  420. package/server/service/twin-target/twin-target.ts +0 -97
  421. package/server/types/global.d.ts +0 -22
  422. package/shared/axis-read.ts +0 -28
  423. package/shared/entity-delta.ts +0 -335
  424. package/shared/kpi-broadcast.ts +0 -13
  425. package/shared/touched-items.ts +0 -73
  426. package/shared/twin-level.ts +0 -48
  427. package/test/ack-shape-alignment.test.ts +0 -97
  428. package/test/actuation-advisor.test.ts +0 -55
  429. package/test/actuation-approval-door.test.ts +0 -411
  430. package/test/actuation-dispatch.test.ts +0 -209
  431. package/test/actuation-effect.test.ts +0 -162
  432. package/test/actuation-outcome.test.ts +0 -152
  433. package/test/actuation-rule-runner.test.ts +0 -281
  434. package/test/actuation-rule.test.ts +0 -266
  435. package/test/actuation-seam.test.ts +0 -255
  436. package/test/actuation-settle.test.ts +0 -164
  437. package/test/actuation-target.test.ts +0 -145
  438. package/test/actuation-verification-state.test.ts +0 -139
  439. package/test/adopt-structure-live.test.ts +0 -133
  440. package/test/aggregate-not-findone.test.ts +0 -112
  441. package/test/area-resolver-db.test.ts +0 -110
  442. package/test/attention-digest.test.ts +0 -161
  443. package/test/axis-declaration-passthrough-db.test.ts +0 -152
  444. package/test/axis-journal-evidence.test.ts +0 -71
  445. package/test/axis-read.test.ts +0 -188
  446. package/test/backfill-shape.test.ts +0 -89
  447. package/test/boot-resume.test.ts +0 -287
  448. package/test/broadcast-cost-baseline.test.ts +0 -201
  449. package/test/broadcast-period.test.ts +0 -58
  450. package/test/broadcast-queue-overflow.test.ts +0 -244
  451. package/test/canonical-ingest-vocabularies.test.ts +0 -451
  452. package/test/canonical-quantity-door.test.ts +0 -61
  453. package/test/capability-mapping.test.ts +0 -89
  454. package/test/checkpoint-refuses-empty.test.ts +0 -103
  455. package/test/choose-recipe.test.ts +0 -117
  456. package/test/column-type-portability.test.ts +0 -122
  457. package/test/command-routing.test.ts +0 -61
  458. package/test/command-store-writes-columns.test.ts +0 -126
  459. package/test/connection-portability-doors.test.ts +0 -87
  460. package/test/connector-capability-declaration.test.ts +0 -195
  461. package/test/contract-layer-guard.test.ts +0 -48
  462. package/test/control-capability.test.ts +0 -98
  463. package/test/cursor-stall-not-read-failure.test.ts +0 -126
  464. package/test/declaration-reaches-model.test.ts +0 -226
  465. package/test/declared-location-types.test.ts +0 -89
  466. package/test/declared-stimulus.test.ts +0 -88
  467. package/test/dedupe-transformation.test.ts +0 -112
  468. package/test/discovery-result.test.ts +0 -75
  469. package/test/dispatch-after-approval-source.test.ts +0 -81
  470. package/test/duration-estimators.test.ts +0 -144
  471. package/test/energy-topology.test.ts +0 -113
  472. package/test/entity-delta.test.ts +0 -352
  473. package/test/equipment-identity-reaches.test.ts +0 -57
  474. package/test/event-subjects.test.ts +0 -148
  475. package/test/event-time-column.test.ts +0 -67
  476. package/test/event-type-split.test.ts +0 -178
  477. package/test/external-resolver.test.ts +0 -177
  478. package/test/fact-scope-wiring.test.ts +0 -96
  479. package/test/fill-dedupe.test.ts +0 -59
  480. package/test/fill-loop.test.ts +0 -35
  481. package/test/first-envelope.test.ts +0 -153
  482. package/test/fold-gap-speaks.test.ts +0 -53
  483. package/test/fold-shift-dst.test.ts +0 -110
  484. package/test/forecast-metrics.test.ts +0 -157
  485. package/test/forecast-tuning.test.ts +0 -42
  486. package/test/gap-analytics.test.ts +0 -113
  487. package/test/generated-not-counted.test.ts +0 -99
  488. package/test/guard-roots.ts +0 -76
  489. package/test/home-in-area.test.ts +0 -90
  490. package/test/hook-address.test.ts +0 -28
  491. package/test/hook-rejected-shape.test.ts +0 -86
  492. package/test/hook-response-sum.test.ts +0 -193
  493. package/test/hook-sequence.test.ts +0 -333
  494. package/test/ingest-bench.test.ts +0 -70
  495. package/test/ingest-dedupe.test.ts +0 -56
  496. package/test/ingest-expected-quiet.test.ts +0 -111
  497. package/test/ingest-health-engine.test.ts +0 -248
  498. package/test/ingest-health-wiring.test.ts +0 -120
  499. package/test/ingest-health.test.ts +0 -306
  500. package/test/ingest-history.test.ts +0 -247
  501. package/test/ingest-idempotent.test.ts +0 -211
  502. package/test/ingest-reconcile-four-ways.test.ts +0 -97
  503. package/test/ingest-rules-header.test.ts +0 -100
  504. package/test/ingest-running-guard.test.ts +0 -136
  505. package/test/ingest-space.test.ts +0 -78
  506. package/test/ingest-window-rolls-unobserved.test.ts +0 -72
  507. package/test/ingest-wiring-guard.test.ts +0 -197
  508. package/test/instance-cache-lifecycle.test.ts +0 -110
  509. package/test/intake-mapping-parity.test.ts +0 -175
  510. package/test/integration-probes.test.ts +0 -103
  511. package/test/integration-runner.test.ts +0 -95
  512. package/test/item-ref.test.ts +0 -78
  513. package/test/journal-order-axis.test.ts +0 -80
  514. package/test/journal-read-discipline.test.ts +0 -186
  515. package/test/journal-retention.test.ts +0 -275
  516. package/test/journal-sort-axis.test.ts +0 -142
  517. package/test/journal-write-door.test.ts +0 -110
  518. package/test/journal-write-trend.test.ts +0 -115
  519. package/test/kernel-kind-guard.test.ts +0 -98
  520. package/test/knob-defaults.test.ts +0 -72
  521. package/test/kpi-baseline-db.test.ts +0 -216
  522. package/test/kpi-baseline.test.ts +0 -196
  523. package/test/kpi-fold.test.ts +0 -1456
  524. package/test/kpi-query-bench.test.ts +0 -130
  525. package/test/lens-own-places.test.ts +0 -50
  526. package/test/lineage-survives-restart.test.ts +0 -234
  527. package/test/live-cadence.test.ts +0 -170
  528. package/test/live-cursor-wiring.test.ts +0 -87
  529. package/test/live-feed-lease.test.ts +0 -63
  530. package/test/live-feed-registry.test.ts +0 -75
  531. package/test/live-kernel-facts.test.ts +0 -161
  532. package/test/live-mirror-parity.test.ts +0 -286
  533. package/test/load-meter.test.ts +0 -328
  534. package/test/local-declarations.test.ts +0 -662
  535. package/test/log-stamp.test.ts +0 -59
  536. package/test/loop-lag.test.ts +0 -82
  537. package/test/master-to-twin.test.ts +0 -279
  538. package/test/measured-yield.test.ts +0 -90
  539. package/test/merge-streams.test.ts +0 -70
  540. package/test/mirror-resumes-from-checkpoint.test.ts +0 -192
  541. package/test/model-basis.test.ts +0 -141
  542. package/test/model-gap.test.ts +0 -153
  543. package/test/model-refusal.test.ts +0 -75
  544. package/test/model-vocabulary.test.ts +0 -114
  545. package/test/move-space.test.ts +0 -149
  546. package/test/mutation-gate.test.ts +0 -122
  547. package/test/oee-accumulator.test.ts +0 -204
  548. package/test/oee-site-calendar.test.ts +0 -146
  549. package/test/open-doors.test.ts +0 -197
  550. package/test/operation-basis.test.ts +0 -127
  551. package/test/operational-vocabulary.test.ts +0 -108
  552. package/test/operations-capability-db.test.ts +0 -165
  553. package/test/order-and-transaction-split.test.ts +0 -107
  554. package/test/order-fold-host.test.ts +0 -112
  555. package/test/producer-guard.test.ts +0 -66
  556. package/test/project-structure-db.test.ts +0 -226
  557. package/test/projection-reaches-screen.test.ts +0 -277
  558. package/test/projection-reads-declared.test.ts +0 -109
  559. package/test/property-effects.test.ts +0 -128
  560. package/test/provenance-promotion.test.ts +0 -99
  561. package/test/read-failure-ledger.test.ts +0 -106
  562. package/test/read-failure-visible.test.ts +0 -145
  563. package/test/read-time.test.ts +0 -118
  564. package/test/reference-fill.test.ts +0 -235
  565. package/test/reference-grounding.test.ts +0 -70
  566. package/test/reference-hook.test.ts +0 -177
  567. package/test/reference-links.test.ts +0 -56
  568. package/test/reference-reconciliation.test.ts +0 -39
  569. package/test/registry-key-guard.test.ts +0 -80
  570. package/test/rejection-carries-event-id.test.ts +0 -101
  571. package/test/rename-twin.test.ts +0 -89
  572. package/test/resolve-ts-siblings.mjs +0 -52
  573. package/test/restart-policy.test.ts +0 -111
  574. package/test/resync-origin-site.test.ts +0 -83
  575. package/test/retry-plan.test.ts +0 -139
  576. package/test/revision-axis.test.ts +0 -110
  577. package/test/runtime-key.test.ts +0 -66
  578. package/test/save-intake-collision.test.ts +0 -91
  579. package/test/scale-twin-bench.test.ts +0 -103
  580. package/test/secrets-at-rest.test.ts +0 -135
  581. package/test/snapshot-freshness.test.ts +0 -60
  582. package/test/source-outcome-audit.test.ts +0 -104
  583. package/test/space-integrity.test.ts +0 -223
  584. package/test/space-representation.test.ts +0 -66
  585. package/test/space-scope-includes-stopped.test.ts +0 -55
  586. package/test/spec-coverage.test.ts +0 -113
  587. package/test/stage-path.test.ts +0 -95
  588. package/test/standard-coverage.test.ts +0 -148
  589. package/test/state-axes.test.ts +0 -74
  590. package/test/status-tally.test.ts +0 -55
  591. package/test/streamline-e2e.test.ts +0 -76
  592. package/test/structure-revision-db.test.ts +0 -315
  593. package/test/subject-fast-path.test.ts +0 -148
  594. package/test/subject-read-model.test.ts +0 -175
  595. package/test/sweep-dispatch.test.ts +0 -191
  596. package/test/tenant-registry-db.test.ts +0 -149
  597. package/test/time-range.test.ts +0 -152
  598. package/test/touched-items.test.ts +0 -61
  599. package/test/twin-audit.test.ts +0 -83
  600. package/test/twin-event-keys.test.ts +0 -193
  601. package/test/twin-model-item-db.test.ts +0 -319
  602. package/test/twin-model-parent-relation-db.test.ts +0 -125
  603. package/test/twin-model-tree-db.test.ts +0 -209
  604. package/test/twin-origin-resync.test.ts +0 -133
  605. package/test/twin-state-channel.test.ts +0 -111
  606. package/test/vocabulary-guard.test.ts +0 -43
  607. package/test/warm-start-seam.test.ts +0 -162
  608. package/test/warm-start.test.ts +0 -297
  609. package/test/withheld-door.test.ts +0 -95
  610. package/test/yield-loop.test.ts +0 -199
  611. package/tsconfig.json +0 -15
  612. package/tsconfig.shared.json +0 -23
  613. package/tsconfig.shared.tsbuildinfo +0 -1
  614. package/tsconfig.tsbuildinfo +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"twin-event.js","sourceRoot":"","sources":["../../../server/service/twin-event/twin-event.ts"],"names":[],"mappings":"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","sourcesContent":["import { CreateDateColumn, Entity, Index, Column, RelationId, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'\nimport { ObjectType, Field, ID, Int } from 'type-graphql'\n\nimport { Domain, ScalarObject } from '@things-factory/shell'\n\n/*\n * TwinEvent โ€” append-only ํŠธ์œˆ ์ด๋ฒคํŠธ ์ €๋„(EPCIS ์ด๋ฒคํŠธ + ์šด์˜ ๋ธํƒ€).\n * ์ปค๋„ EventJournal ์˜ ์˜์† ๋Œ€์‘ โ€” ์ƒํƒœ=์ด๋ฒคํŠธ์—ด์˜ ํ•จ์ˆ˜(์žฌ๋ถ€ํŒ… ์‹œ DBโ†’replay ์žฌ๊ตฌ์„ฑ).\n * append-only ์ด๋ฏ€๋กœ updater/deletedAt ์—†์Œ(์ด๋ ฅ CRUD ๊ฐ€ ์•„๋‹ˆ๋ผ ๋ถˆ๋ณ€ ์ด๋ฒคํŠธ ์ŠคํŠธ๋ฆผ).\n * payload ๋Š” simple-json(๋ฉ€ํ‹ฐDB ์ด์‹ โ€” postgres/mysql/sqlite/mssql/oracle ๊ณตํ†ต, DB-specific JSON ํƒ€์ž… ๊ธˆ์ง€).\n * (CLAUDE.md: ๋ชจ๋“  @ObjectType/@Field ๋Š” ์˜๋ฌธ description ํ•„์ˆ˜.)\n */\n/*\n * โ”€โ”€ ์ธ๋ฑ์Šค ์„ค๊ณ„ (2026-07-31) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ด ํ‘œ๋Š” **์ธ์ œ์ŠคํŠธ ๊ฒฝ๋กœ์˜ ๋œจ๊ฑฐ์šด append-only ํ…Œ์ด๋ธ”**์ด๋‹ค. ์ธ๋ฑ์Šค ํ•˜๋‚˜ํ•˜๋‚˜๊ฐ€ ์“ฐ๊ธฐ ์ฆํญ์ด๋ฏ€๋กœ\n * \"์žˆ์œผ๋ฉด ์ข‹์„\" ์ธ๋ฑ์Šค๋ฅผ ๋ถ™์ด์ง€ ์•Š๋Š”๋‹ค. ์‹ค์ œ ์งˆ์˜ ํŒจํ„ด์— ๋Œ€์‘ํ•˜๋Š” ๊ฒƒ๋งŒ ๋‘”๋‹ค.\n *\n * ix_0 (domain, instanceId, revision) ์›์žฅ ๊ธฐ๋ณธ ์ •๋ ฌยท์ปค์„œ ํŽ˜์ด์ง•ยทreplay(ASC ์ฃผ์‚ฌ)\n * ix_1 (domain, instanceId, eventTime) ์‹œ๊ฐ ์ปค์„œ(untilTime)ยท์‹œ๊ฐ„์ฐฝ KPI โ€” ๊ฑฐ์˜ ๋ชจ๋“  ์กฐํšŒ๊ฐ€ ํƒ„๋‹ค\n * ix_2 (domain, instanceId, eventType, revision) ํƒ€์ž… ํ•„ํ„ฐ + ์ •๋ ฌ ๋™์‹œ ์ถฉ์กฑ(์Šค์ผ€์ค„ ํ™”๋ฉด task/equipment)\n * ix_3 (domain, instanceId, epc) \"์ด ๋ฌผ๊ฑด์˜ ์ด๋ ฅ\" โ€” Entity360 ์˜ ๋ณธ์งˆ ์งˆ๋ฌธ\n * ix_4 (domain, instanceId, orderId) \"์ด ์˜ค๋”๊ฐ€ ์–ด๋””๊นŒ์ง€ ๊ฐ”๋‚˜\"\n * ix_9 (domain, instanceId, bizTransaction) \"์ด ๊ฑฐ๋ž˜์— ๋ฌด์Šจ ์ผ์ด ์žˆ์—ˆ๋‚˜\" โ€” EPCISโ†”์˜ค๋”์˜ ๋‹ค๋ฆฌ\n *\n * bizStepยทlocationIdยทmoverId ๋Š” ์ปฌ๋Ÿผ๋งŒ ๋‘๊ณ  ์ธ๋ฑ์Šค๋Š” ๋‘์ง€ ์•Š๋Š”๋‹ค โ€” ํ•œ ํŠธ์œˆ ์•ˆ์—์„œ ์นด๋””๋„๋ฆฌํ‹ฐ๊ฐ€\n * ๋‚ฎ์•„(์—…๋ฌด๋‹จ๊ณ„ ๋ช‡ ๊ฐœ, ์œ„์น˜ ์ˆ˜๋ฐฑ, ์„ค๋น„ ์ˆ˜์‹ญ) (domain,instanceId) ๋กœ ์ด๋ฏธ ์ขํ˜€์ง„ ๋’ค์˜ ์ž”์—ฌ ํ•„ํ„ฐ๋กœ\n * ์ถฉ๋ถ„ํ•˜๊ณ , ๋œจ๊ฑฐ์šด ํ‘œ์— ์ธ๋ฑ์Šค๋ฅผ ๋” ์–น์„ ๊ฐ€์น˜๊ฐ€ ์—†๋‹ค. ์ €๋„ ํ•˜๋‚˜๊ฐ€ ์•„์ฃผ ์ปค์ ธ์„œ ์ด ์ถ•๋“ค์˜ ์กฐํšŒ๊ฐ€\n * ๋А๋ ค์ง€๋ฉด ๊ทธ๋•Œ ์ธก์ •์„ ๊ทผ๊ฑฐ๋กœ ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•  ์ผ์ด์ง€, ์ง€๋ ˆ ์–น์–ด ์“ฐ๊ธฐ๋ฅผ ๋ฌด๊ฒ๊ฒŒ ํ•  ์ผ์€ ์•„๋‹ˆ๋‹ค.\n */\n@Entity()\n@Index('ix_twin_event_0', (e: TwinEvent) => [e.domain, e.instanceId, e.revision], { unique: false })\n@Index('ix_twin_event_1', (e: TwinEvent) => [e.domain, e.instanceId, e.eventTime], { unique: false })\n@Index('ix_twin_event_2', (e: TwinEvent) => [e.domain, e.instanceId, e.eventType, e.revision], { unique: false })\n@Index('ix_twin_event_3', (e: TwinEvent) => [e.domain, e.instanceId, e.epc], { unique: false })\n@Index('ix_twin_event_4', (e: TwinEvent) => [e.domain, e.instanceId, e.orderId], { unique: false })\n/* ix_5 โ€” \"์ด ์ง€์‹œ๊ฐ€ ๋ฌด์—‡์„ ์ผ์œผ์ผฐ๋‚˜\". ๊ฐ์‚ฌ ๊ธฐ๋ก์˜ commandId ๋กœ ์ €๋„์„ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜๋Š” ์ถ•. */\n@Index('ix_twin_event_5', (e: TwinEvent) => [e.domain, e.correlationId], { unique: false })\n/* ix_6 โ€” \"๋ฐ˜์ถœ์„ ํ•œ ๋ฒˆ์ด๋ผ๋„ ๊ณ„์‚ฐํ–ˆ๋‚˜\". ์—†์œผ๋ฉด ๊ทธ ์งˆ๋ฌธ์ด ์ธ์Šคํ„ด์Šค ์ €๋„ ์ „๋Ÿ‰ ์ฃผ์‚ฌ๊ฐ€ ๋œ๋‹ค. */\n@Index('ix_twin_event_6', (e: TwinEvent) => [e.domain, e.instanceId, e.action], { unique: false })\n/*\n * ix_7 โ€” **\"์ด ์ข…๋ฅ˜์˜ ์‚ฌ์‹ค์„ ์‹œ๊ฐ์ˆœ์œผ๋กœ\"** (2026-08-25 ์‹ค์ธก์œผ๋กœ ์ถ”๊ฐ€)\n *\n * ์ด ์ถ•์ด ์—†์–ด์„œ ๊ณต์ • ํƒ€์ž„๋ผ์ธ์ด 22์ดˆ์˜€๋‹ค. ์ข…๋ฅ˜๋กœ ๊ฑฐ๋ฅด๊ณ  ์‹œ๊ฐ์œผ๋กœ ์ •๋ ฌํ•˜๋Š” ์กฐํšŒ๊ฐ€ ๊ฐˆ ๊ณณ์ด ์—†์—ˆ๋‹ค:\n *\n * ix_2 (โ€ฆ, eventType, revision) ์ข…๋ฅ˜๋Š” ๊ฑธ๋Ÿฌ์ง€๊ณ  ์ •๋ ฌ์ด **์ ํžŒ ์ˆœ์„œ**๋‹ค โ†’ 4์›” ์‚ฌ์‹ค์„ ์ตœ๊ทผ์œผ๋กœ ๊ทธ๋ ธ๋‹ค\n * ix_1 (โ€ฆ, eventTime) ์ •๋ ฌ์€ ๋งž๊ณ  **์ข…๋ฅ˜๋ฅผ ๋ชป ๊ฑฐ๋ฅธ๋‹ค** โ†’ ํ–‰๋งˆ๋‹ค ํ…Œ์ด๋ธ”์„ ์—ด์–ด ํ™•์ธํ•œ๋‹ค\n *\n * ๋’ค์ชฝ์œผ๋กœ ๊ฑธ์œผ๋ฉด ๊ทธ ํŠธ์œˆ์—์„œ ์ฐพ๋Š” ์ข…๋ฅ˜๊ฐ€ ๋ฉˆ์ถ˜ ์‹œ์ ๊นŒ์ง€์˜ ๋ชจ๋“  ํ–‰์„ ์ฝ๊ณ  ๋ฒ„๋ฆฐ๋‹ค. ์Šนํ™”ํ‘ธ๋“œ์—์„œ ์ž‘์—…\n * ์‚ฌ์‹ค์€ 8์›” 22์ผ์— ๋ฉˆ์ถฐ ์žˆ๊ณ  ๊ทธ ๋’ค๋กœ ๋ฆฌ๋น„์ „์ด 110๋งŒ ๋Š˜์—ˆ์œผ๋ฏ€๋กœ, 200๊ฑด์— ๋‹ฟ๊ธฐ๊นŒ์ง€ 110๋งŒ ํ–‰์„ ์—ด์—ˆ๋‹ค.\n *\n * ์œ„ ์ฃผ์„์ด ใ€Œ์ธก์ •์„ ๊ทผ๊ฑฐ๋กœ ์ถ”๊ฐ€ํ•  ์ผ์ด์ง€ ์ง€๋ ˆ ์–น์„ ์ผ์€ ์•„๋‹ˆ๋‹คใ€๋ผ๊ณ  ์ ์–ด ๋‘์—ˆ๋‹ค. ๊ทธ ์ธก์ •์ด ๋‚˜์™”๋‹ค.\n */\n@Index('ix_twin_event_7', (e: TwinEvent) => [e.domain, e.instanceId, e.eventType, e.eventTime], { unique: false })\n/*\n * ix_8 โ€” **\"์ด ํŠธ์œˆ์˜ ์˜ค๋ž˜๋œ ๊ธฐ๋ก\"** (2026-08-27 ์‹ค์ธก์œผ๋กœ ์ถ”๊ฐ€)\n *\n * ๋ณด๊ด€ ๊ธฐ๊ฐ„ ์ •๋ฆฌ๊ฐ€ `created_at` ์œผ๋กœ ์ž๋ฅด๋Š”๋ฐ(๋ณด๊ด€์€ ์ €์žฅ ๋‚˜์ด์˜ ๋ฌธ์ œ๋‹ค) ๊ทธ ์ถ•์— ์ธ๋ฑ์Šค๊ฐ€ ์—†์—ˆ๋‹ค.\n * ๊ทธ๋ž˜์„œ ์ •๋ฆฌ๊ฐ€ ๋งค ๋ฐฐ์น˜๋งˆ๋‹ค ๊ทธ ํŠธ์œˆ์˜ ์ €๋„์„ ์ „๋Ÿ‰ ์ฃผ์‚ฌํ–ˆ๋‹ค.\n *\n * hatio-mx2 ์˜ 7์ผ ๋ฐ– ํ–‰์„ ์„ธ๊ธฐ 208์ดˆ โ† 1,029๋งŒ ํ–‰์„ ์ „๋ถ€ ์ฝ๋Š”๋‹ค(7์ผ ๋ฐ–์€ 2,446๊ฑด๋ฟ์ด๋‹ค)\n * revision ์œผ๋กœ ํ•œ ํ–‰ ์งš๊ธฐ 0.004์ดˆ\n *\n * ์ •๋ฆฌ๋Š” ํ•œ ์ฐฝ์— 2์ดˆ๋งŒ ์“ฐ๋„๋ก ์˜ˆ์‚ฐ์ด ๊ฑธ๋ ค ์žˆ์–ด์„œ, ๊ทธ 2์ดˆ๋ฅผ ์ฃผ์‚ฌ์— ๋‹ค ์“ฐ๊ณ  44๊ฑด๋งŒ ์ง€์šฐ๊ณ  ๋ฉˆ์ท„๋‹ค.\n */\n@Index('ix_twin_event_8', (e: TwinEvent) => [e.domain, e.instanceId, e.createdAt], { unique: false })\n/* ix_9 โ€” \"์ด ๊ฑฐ๋ž˜์— ๋ฌด์Šจ ์ผ์ด ์žˆ์—ˆ๋‚˜\". EPCIS ์‚ฌ๊ฑด์—์„œ ์˜ค๋”๋กœ ๊ฑด๋„ˆ๊ฐ€๋Š” ๋‹ค๋ฆฌ(ยง`bizTransaction`). */\n@Index('ix_twin_event_9', (e: TwinEvent) => [e.domain, e.instanceId, e.bizTransaction], { unique: false })\n@ObjectType({ description: 'Append-only twin event journal record (EPCIS event or operational delta).' })\nexport class TwinEvent {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID, { description: 'Unique identifier of the event record.' })\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain, { nullable: true, description: 'Owning tenant domain.' })\n domain?: Domain\n\n @RelationId((e: TwinEvent) => e.domain)\n domainId?: string\n\n /*\n * ์ด ์‚ฌ์‹ค์„ ๋‚ธ ํŠธ์œˆ. **๋นŒ ์ˆ˜ ์—†๋‹ค** โ€” ์ €๋„ ํ–‰์„ ๋งŒ๋“œ๋Š” ๊ณณ์€ `journalRow` ํ•˜๋‚˜๋ฟ์ด๊ณ  ๊ฑฐ๊ธฐ์„œ\n * ํ•„์ˆ˜ ์ธ์ž๋กœ ๋ฐ›๋Š”๋‹ค. nullable ๋กœ ๋‘๋ฉด ์ฝ๋Š” ์ชฝ์ด ๋งค๋ฒˆ `?? ''` ๋ฅผ ๋‹ฌ๊ฒŒ ๋˜๊ณ , ๊ทธ ๋ฐฉ์–ด๊ฐ€ ์‹ค์ œ๋กœ๋Š”\n * ์ผ์–ด๋‚˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•˜๋А๋ผ \"๋นˆ ์ธ์Šคํ„ด์Šค์˜ ์ด๋ฒคํŠธ\" ๋ผ๋Š” ์—†๋Š” ๊ฐœ๋…์„ ์ฝ”๋“œ์— ๋‚จ๊ธด๋‹ค.\n */\n @Column()\n @Field({ description: 'Twin runtime instance id that emitted the event.' })\n instanceId: string\n\n /* ์ปค๋„ ๋ด‰ํˆฌ์˜ ํ•„์ˆ˜ ํ•„๋“œ(`CanonicalEnvelope.eventType`)๋ผ ๋นŒ ์ˆ˜ ์—†๋‹ค โ€” ๊ณ„์•ฝ์„ ๊ทธ๋Œ€๋กœ ์˜ฎ๊ธด๋‹ค. */\n @Column()\n @Field({ description: 'Event type: epcis.* | task.status | equipment.status | order.status.' })\n eventType: string\n\n @Column({ type: 'int', nullable: true })\n @Field(type => Int, { nullable: true, description: 'Monotonic state revision at which the event was emitted.' })\n revision?: number\n\n /**\n * ์ด ์‚ฌ์‹ค์ด **์–ด๋А ๊ณต์žฅ์—์„œ** ์ผ์–ด๋‚ฌ๋‚˜ โ€” `TwinStructure.rev`.\n *\n * ์ด๊ฒƒ์ด ์—†๋˜ ์‹œ์ ˆ์—๋Š” ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์ €๋„์„ ํ†ต์งธ๋กœ ์ง€์šฐ๋Š” ๊ฒƒ์ด ์œ ์ผํ•œ ๊ธธ์ด์—ˆ๋‹ค(์•ˆ ์ง€์šฐ๋ฉด ์˜›\n * ์ด๋ฒคํŠธ๋ฅผ ์ƒˆ ๊ณต์žฅ์— ๋Œ€๊ณ  ๊ณ„์‚ฐํ•ด ์ด๋ ฅ์ด ๊ฑฐ์ง“๋ง์„ ํ•œ๋‹ค). ์ด ํ•œ ์นธ์ด ์…‹์งธ ๊ธธ์„ ์—ฐ๋‹ค โ€” ์žฌ์ƒ์ด\n * ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ๋Š” ์ง€์ ์—์„œ ์ „ํ™˜ํ•œ ๋’ค ์ด์–ด์„œ ๊ณ„์‚ฐํ•œ๋‹ค.\n *\n * **๋น„์–ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค**: ์ปฌ๋Ÿผ์ด ์ƒ๊ธฐ๊ธฐ ์ „์— ์“ฐ์ธ ํ–‰์ด๋‹ค. ๊ทธ ํ–‰๋“ค์€ **๊ฐ€์žฅ ์˜ค๋ž˜๋œ ๋ฆฌ๋น„์ „**์—\n * ์†ํ•œ๋‹ค(0 ์„ ์ฑ„์›Œ ๋„ฃ์ง€ ์•Š๋Š”๋‹ค โ€” 0 ์€ \"๋ชจ๋ฆ„\" ์ด ์•„๋‹ˆ๋ผ ์œ ํšจํ•œ ๋ฒˆํ˜ธ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค).\n */\n @Column({ type: 'int', nullable: true })\n @Field(type => Int, { nullable: true, description: 'Structure revision (TwinStructure.rev) in force when this event happened. Absent on rows written before structure revisions existed; those belong to the oldest revision.' })\n structureRev?: number\n\n /*\n * ์ด ์‚ฌ์‹ค์ด ์ผ์–ด๋‚œ ์‹œ๊ฐ(ํŠธ์œˆ์˜ ์‹œ๊ณ„). **๋‚ ์งœ ํƒ€์ž…์ด๋‹ค.**\n *\n * ์˜ˆ์ „์—๋Š” ๋ฌธ์ž์—ด์ด์—ˆ๋‹ค. ์ฝ์„ ๋•Œ๋งˆ๋‹ค `Date.parse` ํ–ˆ๊ณ , ์ •๋ ฌ์€ UTC ISO ๋งŒ ๋“ค์–ด์˜จ๋‹ค๋Š” ์ „์ œ ์œ„์—์„œ\n * ์‚ฌ์ „์‹ ๋น„๊ต๊ฐ€ ์šฐ์—ฐํžˆ ๋งž์•˜๋‹ค โ€” `+09:00` ์˜คํ”„์…‹ ํ‘œ๊ธฐ๊ฐ€ ํ•˜๋‚˜ ์„ž์ด๋ฉด ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ์ˆœ์„œ๊ฐ€ ํ‹€๋ฆฐ๋‹ค.\n * ๊ทธ ์ „์ œ๋Š” ์ปฌ๋Ÿผ ์–ด๋””์—๋„ ์ ํ˜€ ์žˆ์ง€ ์•Š์•˜๋‹ค.\n *\n * **ํƒ€์ž… ์ด๋ฆ„์„ ์ ์ง€ ์•Š๋Š”๋‹ค** (2026-08-19 Postgres ๋ถ€ํŒ… ์‹คํŒจ๋กœ ๊ณ ์นจ).\n *\n * `datetime` ์„ ์ ์—ˆ๋”๋‹ˆ Postgres ๊ฐ€ ๋ถ€ํŒ… ์ค‘์— ๊ฑฐ์ ˆํ–ˆ๋‹ค(`DataTypeNotSupportedError`) โ€” ๊ทธ ์ด๋ฆ„์€\n * sqliteยทMySQL ์˜ ๊ฒƒ์ด๊ณ  Postgres ๋Š” `timestamp` ๋งŒ ์•ˆ๋‹ค. ๊ฑฐ๊พธ๋กœ `timestamp` ๋Š” sqlite ๊ฐ€ ๋ชจ๋ฅธ๋‹ค:\n * **๋‹ค์„ฏ ๋“œ๋ผ์ด๋ฒ„์— ๋‹ค ํ†ตํ•˜๋Š” ์ด๋ฆ„์ด ์•„์˜ˆ ์—†๋‹ค.**\n *\n * ๊ทธ๋ž˜์„œ ์ด๋ฆ„์„ ๊ณ ๋ฅด๋Š” ์ผ์„ TypeORM ์— ๋งก๊ธด๋‹ค. `emitDecoratorMetadata` ๊ฐ€ ์ผœ์ ธ ์žˆ์œผ๋ฏ€๋กœ ์ด ์†์„ฑ์˜\n * TS ํƒ€์ž…(`Date`)์—์„œ ๋“œ๋ผ์ด๋ฒ„๋ณ„ ํƒ€์ž…์„ ์Šค์Šค๋กœ ๊ณ ๋ฅธ๋‹ค(Postgres `timestamp` ยท sqliteยทMySQL `datetime`).\n * ์ด ๋ ˆํฌ์˜ ๋‹ค์ค‘ DB ๊ทœ์•ฝ์ด ์š”๊ตฌํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ ๊ทธ๊ฒƒ์ด๋‹ค โ€” ๋“œ๋ผ์ด๋ฒ„ ๋ฐฉ์–ธ์„ ์ฝ”๋“œ์— ์ ์ง€ ์•Š๋Š”๋‹ค.\n */\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Time at which the fact happened on the twin clock.' })\n eventTime?: Date\n\n /*\n * โ”€โ”€ ์Šน๊ฒฉ๋œ ๊ฒ€์ƒ‰ ์ถ• โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * payload ์•ˆ์— ์žˆ๋˜ ๊ฐ’์„ ์ธ์ œ์ŠคํŠธ ์‹œ์ ์— ๊บผ๋‚ด ์‹ค์ปฌ๋Ÿผ์œผ๋กœ ๋‘”๋‹ค(`twin-event-keys.ts` ๊ฐ€ ๋‹จ๋… ์†Œ์œ ).\n * payload ๊ฐ€ ์—ฌ์ „ํžˆ ์ •๋ณธ์ด๊ณ  ์ด๊ฒƒ๋“ค์€ **ํŒŒ์ƒ ์ƒ‰์ธ**์ด๋‹ค โ€” ์ƒˆ๋กœ์šด ์ง„์‹ค์ด ์•„๋‹ˆ๋ผ ์ฐพ์„ ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ์žฅ์น˜.\n * simple-json(TEXT) ์•ˆ์˜ ๊ฐ’์€ 5๊ฐœ DB ๋“œ๋ผ์ด๋ฒ„ ๊ณตํ†ต์œผ๋กœ ๊ฑฐ๋ฅผ ๋ฐฉ๋ฒ•์ด ์—†์–ด์„œ(๋ฉ€ํ‹ฐDB ํ˜ธํ™˜ ๊ทœ์น™์ƒ\n * DB๋ณ„ JSON ์—ฐ์‚ฐ์ž ๊ธˆ์ง€) ์Šน๊ฒฉ ์™ธ์˜ ์„ ํƒ์ง€๊ฐ€ ์—†๋‹ค.\n * ๊ธธ์ด ์ƒํ•œ 255 ๋Š” GS1 ์‹๋ณ„์ž ๊ทœ๊ฒฉ ๋Œ€๋น„ ์ถฉ๋ถ„ํ•˜๋ฉฐ, ๋„˜์น˜๋Š” ๊ฐ’์€ ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ์ž˜๋ฆฌ์ง€ ์•Š๊ณ  ๊ฒฝ๊ณ ๋ฅผ ๋‚จ๊ธด๋‹ค.\n *\n * โ”€โ”€ ์ถ•์„ ์ƒˆ๋กœ ์ถ”๊ฐ€ํ•  ๋•Œ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ƒˆ ์Šน๊ฒฉ ์ปฌ๋Ÿผ์„ ๋งŒ๋“ค๋ฉด **์ด๋ฏธ ์Œ“์ธ ํ–‰์€ ๋น„์–ด ์žˆ๋‹ค.** ๊ทธ ํ–‰๋“ค์€ ์ƒˆ ์ถ•์œผ๋กœ ๊ฒ€์ƒ‰๋˜์ง€ ์•Š๊ณ ,\n * ์‚ฌ์šฉ์ž์—๊ฒŒ๋Š” \"๊ณผ๊ฑฐ๊ฐ€ ์—†๋Š” ๊ฒƒ\" ์œผ๋กœ ๋ณด์ธ๋‹ค(์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ๋น ์ง„ ๋ฐ์ดํ„ฐ).\n *\n * ์˜ˆ์ „์—๋Š” ๊ธฐ๋™ ํ›…์ด ๋งค๋ฒˆ ํ…Œ์ด๋ธ”์„ ์‚ดํŽด ์ฑ„์› ๋‹ค. ๊ทธ๊ฑด ๋‘ ๊ฐ€์ง€๋กœ ํ‹€๋ ธ๋‹ค โ€” ์ €๋„์ด ์ปค์งˆ์ˆ˜๋ก ๋ถ€ํŒ…์ด\n * ๋А๋ ค์ง€๊ณ , \"bizStep ์ด ๋น„์—ˆ์œผ๋ฉด ์˜› ํ–‰\" ์ด๋ผ๋Š” ์ „์ œ๋ฅผ ์ฝ”๋“œ์— ๊ณ ์ •ํ•ด ๊ทธ ์ „์ œ๊ฐ€ ๊นจ์ง€๋Š” ์ˆœ๊ฐ„\n * (๊ฐ์‚ฌ ํ–‰์ฒ˜๋Ÿผ ์—…๋ฌด ๋‹จ๊ณ„๊ฐ€ ์—†๋Š” ํ–‰) ๋งค ๋ถ€ํŒ…๋งˆ๋‹ค ํ—›๋Œ์•˜๋‹ค. ๊ทธ๋ž˜์„œ ๊ฑท์–ด๋ƒˆ๋‹ค(git: backfill-keys.ts).\n *\n * ์ฑ„์šฐ๋Š” ์ผ์€ **๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ•œ ๋ฒˆ**์ด ๋งž๋‹ค(`yarn migration`). ๊ทธ ์ปฌ๋Ÿผ์— ๋งž๋Š” ๊ฒƒ์„ ๊ทธ๋•Œ ์“ด๋‹ค โ€”\n * ๋ฒ”์šฉ ์Šค์บ๋„ˆ๋ฅผ ๋˜์‚ด๋ฆฌ์ง€ ๋ง ๊ฒƒ. ๊ฐœ๋ฐœ ๋ฐ์ดํƒ€๋ผ๋ฉด ๊ทธ๋ƒฅ ๋ฒ„๋ฆฌ๋Š” ๊ฒƒ๋„ ๋‹ต์ด๋‹ค.\n */\n /**\n * ์ด ์‚ฌ์‹ค์„ ์ผ์œผํ‚จ **์ง€์‹œ** โ€” ์ปค๋„์ด ์ปค๋งจ๋“œ์—์„œ ์ด์–ด ์ค€ ์ƒ๊ด€๊ฐ’(๊ธฐ๋ณธ์€ commandId).\n *\n * ์ด๊ฒƒ์ด ๊ฐ์‚ฌ ๊ธฐ๋ก(TwinAuditEvent.commandId)๊ณผ ์ €๋„์„ ์ž‡๋Š” ์œ ์ผํ•œ ๋‹ค๋ฆฌ๋‹ค. ์—†์œผ๋ฉด ์Šน์ธ ๊ธฐ๋ก์€\n * \"์‚ฌ๋žŒ์ด ํ—ˆ๋ฝํ–ˆ๋‹ค\" ๊นŒ์ง€์ด๊ณ , ๊ทธ ๋’ค ๊ณต์žฅ์ด ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ์›€์ง์˜€๋Š”์ง€์™€ ์ด์–ด์ง€์ง€ ์•Š๋Š”๋‹ค.\n *\n * **๋Œ€๋ถ€๋ถ„์˜ ํ–‰์€ ๋น„์–ด ์žˆ๋‹ค** โ€” ์ปค๋งจ๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ ์‹œ๋ฎฌ ์‹œ๊ฐ„์ด ๋‚ณ์€ ์‚ฌ์‹ค์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๊ฒƒ์ด ์ •์ƒ์ด๊ณ ,\n * ๋น„์–ด ์žˆ๋‹ค๊ณ  \"๋œ ์ฑ„์›Œ์ง„ ์˜› ํ–‰\" ์œผ๋กœ ๋ณด๋ฉด ์•ˆ ๋œ๋‹ค(๊ฐ™์€ ์˜คํ•ด๋ฅผ bizStep ์—์„œ ์ด๋ฏธ ํ•œ ๋ฒˆ ํ–ˆ๋‹ค).\n */\n @Column({ length: 255, nullable: true })\n @Field({ nullable: true, description: 'Id of the command that caused this fact (kernel correlation id; defaults to the commandId). Empty for facts that simulation time produced rather than a command.' })\n correlationId?: string\n\n /* ์˜› ํ–‰์€ ๋น„์–ด ์žˆ๋‹ค โ€” ์Šน๊ฒฉ ์ „์— ๊ธฐ๋ก๋œ ๊ฒƒ์ด๋ผ **๋ชจ๋ฅธ๋‹ค**(0 ์ด๋‚˜ OBSERVE ๋กœ ์œ„์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค). */\n @Column({ length: 16, nullable: true })\n @Field({ nullable: true, description: 'EPCIS action (ADD / OBSERVE / DELETE), promoted from the payload. Empty for operational deltas, and for rows journaled before this column existed.' })\n action?: string\n\n @Column({ length: 255, nullable: true })\n @Field({ nullable: true, description: 'Business step (CBV bizStep tail), promoted from the payload for indexed filtering.' })\n bizStep?: string\n\n @Column({ length: 255, nullable: true })\n @Field({ nullable: true, description: 'Item identifier (EPC / EPC class / parent id), promoted from the payload for indexed lookup of one item history.' })\n epc?: string\n\n @Column({ length: 255, nullable: true })\n @Field({ nullable: true, description: 'Internal order identifier, promoted from the payload for indexed lookup of one order history.' })\n orderId?: string\n\n /*\n * **๊ฑฐ๋ž˜ ์‹๋ณ„์ž๋Š” ์˜ค๋” ์‹๋ณ„์ž์™€ ๋‹ค๋ฅธ ๊ฒƒ์ด๋‹ค.**\n *\n * ์ „์—๋Š” ๋‘˜์ด ํ•œ ์นธ(`orderId`)์— ๋“ค์–ด๊ฐ”๋‹ค. ๊ทธ๋ž˜์„œ ํ•œ ์˜ค๋”์˜ ์ด๋ ฅ์ด ์ƒ‰์ธ ์•ˆ์—์„œ ๋‘ ์ชฝ์œผ๋กœ\n * ๊ฐˆ๋ผ์กŒ๋‹ค โ€” ์šด์˜ ๋ธํƒ€๋Š” `order-1`, EPCIS ์‚ฌ๊ฑด์€ `urn:epc:id:gdti:โ€ฆ` ๋กœ ์ ํ˜€ ์–ด๋А ์ด๋ฆ„์œผ๋กœ\n * ๋ฌผ์–ด๋„ ์ ˆ๋ฐ˜๋งŒ ๋‚˜์™”๋‹ค(์‹ค์ธก 2026-09-05: ์–ดํœ˜๊ฐ€ ์„ž์ธ ํ–‰ 10,004๊ฐœ, ์˜ค๋ฅ˜๋Š” ๋‚˜์ง€ ์•Š์Œ).\n *\n * ์˜ค๋” ์‚ฌ๊ฑด์€ ๋‘ ๊ฐ’์„ ๋‹ค ๋“ค๊ณ  ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ด ์นธ์ด **EPCIS ์‚ฌ๊ฑด์—์„œ ์˜ค๋”๋กœ ๊ฑด๋„ˆ๊ฐ€๋Š” ๋‹ค๋ฆฌ**๊ฐ€\n * ๋œ๋‹ค โ€” ใ€Œ์ด ๊ฐœ์ฒด๋ฅผ ์–ด๋А ๋ ˆ์‹œํ”ผ๋กœ ๋งŒ๋“ค์—ˆ๋‚˜ใ€๊ฐ€ ๊ทธ ๋‹ค๋ฆฌ๋กœ ๋‹ตํ•ด์ง„๋‹ค.\n */\n @Column({ length: 255, nullable: true })\n @Field({ nullable: true, description: 'Business transaction identifier (PO / SO / production order), promoted from the payload for indexed lookup of one transaction.' })\n bizTransaction?: string\n\n @Column({ length: 255, nullable: true })\n @Field({ nullable: true, description: 'Location identifier (read point, business location, or the plain location an operational delta carries), promoted from the payload for indexed filtering.' })\n locationId?: string\n\n @Column({ length: 255, nullable: true })\n @Field({ nullable: true, description: 'Equipment identifier carried by operational deltas, promoted from the payload so one machine history can be asked for on the server. The column keeps the legacy name `moverId`: the journal is append-only history and mixing two names for the same fact across time is worse than an outdated name. Renaming belongs with event-schema versioning.' })\n moverId?: string\n\n /**\n * **Whether the sender declared this fact as having actually happened** โ€” the envelope's\n * `provenance`, promoted here.\n *\n * โ”€โ”€ Why a column (measured 2026-09-09) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * This table held 1,134 rows, all of them generator output, and **there was nowhere to ask\n * about it**:\n *\n * ```\n * select count(*) from twin_events 1134\n * select count(*) where payload like '%SIM-%' 1134\n * select count(*) where order_id like 'WO-SIM-%' 558 <- half of them\n * ```\n *\n * The only signal was the sender's naming convention (`SIM-`), and the column that convention\n * reaches was empty on half the rows. While it sits inside `payload`, none of the five drivers\n * can answer \"count these without the invented ones\" โ€” the same reason `action` was promoted.\n *\n * โ”€โ”€ Three states, kept apart โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ```\n * 'simulated' the sender said it was invented\n * 'actual' the sender said it happened\n * null **not declared** โ€” which is not `actual`\n * ```\n *\n * Folding the last two together means a generator that omits the declaration has its output\n * counted as production, and nothing says so. Hence no default: an absent declaration is not\n * disguised as a valid-looking value (the discipline of `structureRev` and `lastWarningCount`).\n *\n * โ”€โ”€ No index โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * Three possible values is low cardinality within one twin โ€” the judgement already made for\n * `bizStep` and `locationId`. Performance folds arrive already narrowed by domain, instance and\n * time, so filtering after that is cheap.\n */\n @Column({ length: 16, nullable: true })\n @Field({ nullable: true, description: 'Whether the sending side declared this fact as actually having happened. Either \"actual\" or \"simulated\"; null means it was not declared, which is not the same as actual โ€” a generator that omits it must not be counted as production.' })\n provenance?: string\n\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'Raw canonical envelope (EPCIS event or operational delta) as JSON.' })\n payload?: any\n\n @CreateDateColumn()\n @Field({ nullable: true, description: 'Wall-clock timestamp when the record was persisted.' })\n createdAt?: Date\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"forecast-metrics.js","sourceRoot":"","sources":["../../../server/service/twin-forecast/forecast-metrics.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * ์˜ˆ์ธก ์ง€ํ‘œ โ€” **์Šค๋ƒ…์ƒท์—์„œ ์ˆ˜ ํ•˜๋‚˜๋ฅผ ๋ฝ‘๋Š” ๊ทœ์น™.**\n *\n * โ”€โ”€ ์™œ ์ˆœ์ˆ˜ ๋ชจ๋“ˆ์ธ๊ฐ€ (2026-08-15) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ด ํ‘œ๊ฐ€ ๋ฆฌ์กธ๋ฒ„ ์•ˆ์— ์žˆ์–ด์„œ ์‹œํ—˜์ด ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์—†์—ˆ๋‹ค(type-graphqlยทshell ์„ ๋ฌผ๊ณ  ์žˆ๋‹ค). ๊ทธ๋Ÿฐ๋ฐ ์—ฌ๊ธฐ์„œ\n * ํ‹€๋ฆฌ๋ฉด ์˜ˆ์ธก ๊ทธ๋ž˜ํ”„ ์ „์ฒด๊ฐ€ ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ๋‹ค๋ฅธ ๊ฒƒ์„ ๊ทธ๋ฆฐ๋‹ค โ€” ์˜ค๋ฅ˜ ์—†์ด. ๊ทœ์น™์€ ์‹œํ—˜์ด ๋‹ฟ๋Š” ์ž๋ฆฌ์— ๋‘”๋‹ค.\n *\n * โ”€โ”€ ์—๋„ˆ์ง€ ์ง€ํ‘œ๋ฅผ ๋”ํ•œ ์ด์œ  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์˜ˆ์ธก ํ™”๋ฉด์˜ ์ง€ํ‘œ๊ฐ€ ๋ฌผ๋ฅ˜ ์—ฌ์„ฏ(์žฌ๊ณ ยท์ ์œ ยท์ž‘์—…ยท์˜ค๋”ยท์ถœ๊ณ ยท๋ฐฑ๋กœ๊ทธ)์œผ๋กœ ๊ณ ์ •๋ผ ์žˆ์–ด์„œ, ์—๋„ˆ์ง€ ํŠธ์œˆ์„\n * ๊ณ ๋ฅด๋ฉด **๋‚จ์˜ ์งˆ๋ฌธ์— ๋‹ตํ•˜๋Š” ๊ทธ๋ž˜ํ”„**๊ฐ€ ๋–ด๋‹ค. ์—๋„ˆ์ง€ ํŠธ์œˆ์—๋Š” ์žฌ๊ณ ๋„ ์˜ค๋”๋„ ์—†์œผ๋ฏ€๋กœ ๊ทธ ๊ฐ’๋“ค์€\n * ์ „๋ถ€ 0 ์ด๊ณ , 0 ์€ ใ€Œ์—†๋‹คใ€๊ฐ€ ์•„๋‹ˆ๋ผ ใ€Œ์ด ํŠธ์œˆ์˜ ์งˆ๋ฌธ์ด ์•„๋‹ˆ๋‹คใ€์ด๋‹ค.\n *\n * ์—ฌ๊ธฐ ๋”ํ•œ ์…‹์€ **์ปค๋„์ด ์ด๋ฏธ ์ƒํƒœ๋กœ ๋“ค๊ณ  ์žˆ๋Š” ๊ฒƒ**์ด๋‹ค โ€” ์ƒˆ ๊ณ„์‚ฐ์„ ๋งŒ๋“ค์ง€ ์•Š์•˜๋‹ค. ํŠนํžˆ ๋ถ€ํ•˜ ํ•ฉ์€\n * ์ปค๋„์ด ๋ฟŒ๋ฆฌ ๊ณ„๋Ÿ‰๊ธฐ๋กœ๋งŒ ์„ธ๋Š”๋ฐ(๊ณ„์ธต ๊ณ„๋Ÿ‰์˜ ์ด์ค‘ ๊ณ„์ƒ ๋ฐฉ์ง€), ๊ทธ ๊ทœ์น™์„ ์—ฌ๊ธฐ์„œ ๋‹ค์‹œ ์“ฐ๋ฉด ๋‘ ๋ฒŒ์ด ๋œ๋‹ค.\n * ๊ทธ๋ž˜์„œ ์ง€์ ์„ ์ง์ ‘ ๋”ํ•˜์ง€ ์•Š๊ณ  **๊ตฌ๊ฐ„ ๊ฐ’**์„ ์ฝ๋Š”๋‹ค.\n */\n\nimport { isFlowOrder, isOrderTerminal } from '@operato/ops-contract'\n\n/*\n * โ”€โ”€ Folded orders are counted too (ADR-0092 decision 3, ruling 2026-09-24) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n *\n * A twin folds finished orders out of its hot list at checkpoint time and keeps only their counts\n * (`foldedOrders.counts`, kind ร— terminal status, never trimmed). Counting the hot list alone would drop\n * `orders` and `shipped` the moment a fold happens โ€” and \"the increase since the fork\" alone would still\n * break `twinForecastGapTrend`, whose actual at T+h is read from recovered state: a fold between T and\n * T+h makes the actual increase negative. So both metrics are cumulative including the folded side, and\n * an increase is the difference of the same number. Which folded kinds are flow orders is asked of the\n * contract's `isFlowOrder`, the same as the hot list; `shipped` uses the same word on both sides.\n */\nfunction foldedFlowOrders(s: any, status?: string): number {\n let n = 0\n for (const [kind, byStatus] of Object.entries((s?.foldedOrders?.counts ?? {}) as Record<string, Record<string, number>>)) {\n if (!isFlowOrder({ kind })) continue\n if (status) n += Number(byStatus?.[status]) || 0\n else for (const c of Object.values(byStatus ?? {})) n += Number(c) || 0\n }\n return n\n}\n\n/** ์Šค๋ƒ…์ƒท โ†’ ์ˆ˜ ํ•˜๋‚˜. ๊ฐ’์ด ์—†์œผ๋ฉด 0 ์ด ์•„๋‹ˆ๋ผ **๊ทธ ์ง€ํ‘œ๋ฅผ ๊ทธ๋ฆด ์ˆ˜ ์—†๋‹ค**๋Š” ๋œป์ด์ง€๋งŒ, ๊ทธ๋ž˜ํ”„ ๊ณ„์•ฝ์ด\n * ์ˆ˜๋ฅผ ์š”๊ตฌํ•˜๋ฏ€๋กœ 0 ์„ ๋‚ธ๋‹ค โ€” ๊ทธ๋ž˜์„œ ์—๋„ˆ์ง€ ์ง€ํ‘œ๋Š” ใ€Œ์—†์Œใ€์ด 0 ๊ณผ ํ—ท๊ฐˆ๋ฆฌ์ง€ ์•Š๋Š” ๊ฒƒ๋งŒ ๊ณจ๋ž๋‹ค. */\nexport type MetricFn = (s: any) => number\n\nexport const FORECAST_METRICS: Record<string, MetricFn> = {\n items: s => (s?.items || []).length,\n occupancy: s => (s?.locations || []).reduce((a: number, n: any) => a + (n.occupancy || 0), 0),\n tasks: s => (s?.tasks || []).length,\n /*\n * โ”€โ”€ ์„ธ๋Š” ๊ฒƒ์€ **ํ๋ฆ„ ์˜ค๋”**๋‹ค (2026-09-19, ADR-0076 ๋ณดํƒฌ โ‘ฅ) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n *\n * ๋ฐ›๋Š” ์˜ค๋”(์ž…๊ณ  ยท ๋ฐ˜ํ’ˆ ์ž…๊ณ )๋Š” ๋„์ฐฉ์ด ์„ธ์šฐ๊ณ  ๋„์ฐฉ์ด ์ดํ–‰ํ•œ๋‹ค. ๊ทธ๋Œ€๋กœ ์„ธ๋ฉด ใ€Œ๋‚˜๊ฐ„ ๊ฒƒใ€์ด ๋ฐ›์„ ๋•Œ๋งˆ๋‹ค\n * ํ•œ ๊ฑด์”ฉ ๋Š˜๊ณ  ๋ฐฑ๋กœ๊ทธ๋Š” ์˜์˜ ์•ˆ ์ค„์–ด๋“ ๋‹ค โ€” ์˜ˆ์ธก ๊ทธ๋ž˜ํ”„๊ฐ€ ์žˆ์ง€๋„ ์•Š์€ ์ผ์„ ๊ทธ๋ฆฐ๋‹ค. ๋ฌด์—‡์ด ํ๋ฆ„\n * ์˜ค๋”์ธ์ง€๋Š” ๊ณ„์•ฝ์˜ `isFlowOrder` ํ•œ ๊ณณ์ด ์ •ํ•œ๋‹ค(์—ฌ๊ธฐ์„œ `kind` ๋ฅผ ๋‹ค์‹œ ์ ์ง€ ์•Š๋Š”๋‹ค).\n */\n orders: s => (s?.orders || []).filter(isFlowOrder).length + foldedFlowOrders(s),\n // ์ดํ–‰ ์ง€ํ‘œ โ€” ๋ผ์ด๋ธŒ ์˜ˆ์ธก์˜ ํ•ต์‹ฌ ์งˆ๋ฌธ(\"์–ธ์ œ ๋‹ค ๋‚˜๊ฐ€๋‚˜ยท๋ฐฑ๋กœ๊ทธ ์–ธ์ œ ํ’€๋ฆฌ๋‚˜\").\n shipped: s => (s?.orders || []).filter(isFlowOrder).filter((o: any) => o.status === 'shipped').length + foldedFlowOrders(s, 'shipped'),\n /*\n * โ”€โ”€ ๋ฐฑ๋กœ๊ทธ๋Š” **ใ€Œ์ข…๊ฒฐ์ธ๊ฐ€ใ€**๋กœ ๋ฌป๋Š”๋‹ค (2026-09-19) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n *\n * ๋‚ฑ๋ง ๋‘˜(`shipped`ยท`cancelled`)๋กœ ๋ฌผ์œผ๋ฉด **์›๋ณธ์ด ๋‹ค๋ฅธ ๋‚ฑ๋ง์„ ์“ฐ๋Š” ๋ฏธ๋Ÿฌ์—์„œ ๋๋‚œ ์˜ค๋”๊ฐ€ ์˜์˜\n * ๋ฐฑ๋กœ๊ทธ์— ๋‚จ๋Š”๋‹ค.** `status` ๋Š” ์—ด๋ฆฐ ์ถ•์ด๊ณ (ํ‘œ์ค€๋„ `RequestState` ๋ฅผ ์—ด๊ฑฐํ•˜์ง€ ์•Š๋Š”๋‹ค) ์‹ค ์‹œ์Šคํ…œ์€\n * `completed`ยท`FINISHED` ๋ฅผ ์“ด๋‹ค โ€” ๊ทธ ํŠธ์œˆ์˜ ๋ฐฑ๋กœ๊ทธ ๊ณก์„ ์€ ๋‚ด๋ ค๊ฐ€์ง€ ์•Š๋Š”๋‹ค. ์ข…๊ฒฐ ํŒ์ •์€ ์ปค๋„์ด\n * ํ•œ ๊ณณ์—์„œ ํ•œ๋‹ค(`isOrderTerminal` โ€” ๋‚ฑ๋ง์ด ์•„๋‹ˆ๋ผ **์–‘**์„ 1์ฐจ ๊ทผ๊ฑฐ๋กœ ๋ณธ๋‹ค).\n *\n * `shipped` ํ•œ ๋‚ฑ๋ง์€ ๋‚จ๋Š”๋‹ค. ๊ทธ๊ฒƒ์€ ์ด ์ปค๋„์ด **์ž๊ธฐ๊ฐ€ ์“ฐ๋Š” ๋ง**์ด๊ณ (WMS ์˜ ์ถœํ•˜ ์™„๋ฃŒ), ๊ณ„์•ฝ์˜\n * ์ข…๊ฒฐ ๋ชฉ๋ก(`completed` ยท `cancelled`)์—๋Š” ์—†๋‹ค. ์–‘์„ ๋งํ•˜์ง€ ์•Š๋Š” ์Šค๋ƒ…์ƒท์—์„œ ๊ทธ ์˜ค๋”๊ฐ€ ๋ฐฑ๋กœ๊ทธ๋กœ\n * ๋˜๋Œ์•„์˜ค์ง€ ์•Š๊ฒŒ ๋‘˜์„ ํ•จ๊ป˜ ๋ณธ๋‹ค โ€” ๋นผ๋Š” ์ชฝ์ด๋ผ ์ด ์…ˆ์ด ์ „๋ณด๋‹ค ์ปค์ง€๋Š” ์ผ์€ ์—†๋‹ค. ์ปค๋„์˜ ๋‚ฑ๋ง์ด\n * ๊ณ„์•ฝ์˜ ์ข…๊ฒฐ ๋ชฉ๋ก์— ๋“ค์–ด์˜ค๋Š” ๋‚  ์ด ์ค„์ด ์ง€์›Œ์ง„๋‹ค(์•„ํ‚คํ…ํŠธ์—๊ฒŒ ์˜ฌ๋ฆผ).\n */\n backlog: s =>\n (s?.orders || [])\n .filter(isFlowOrder)\n .filter((o: any) => !isOrderTerminal(o) && o.status !== 'shipped').length,\n\n /*\n * โ”€โ”€ ์—๋„ˆ์ง€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * `peakKW` ๋Š” **๋งˆ๊ฐ๋œ ๊ตฌ๊ฐ„์˜ ์ตœ๋Œ€**๋‹ค โ€” ๋‹จ์กฐ ์ฆ๊ฐ€๋ผ ์ง€ํ‰์„  ์œ„์—์„œ ใ€Œ์ตœ๋Œ€์ˆ˜์š”๊ฐ€ ์–ด๋””๊นŒ์ง€ ์˜ค๋ฅด๋‚˜ใ€๋กœ\n * ์ฝํžŒ๋‹ค. ์—ด๋ฆฐ ๊ตฌ๊ฐ„์€ ๋„ฃ์ง€ ์•Š๋Š”๋‹ค(์•„์ง ํ™•์ •์ด ์•„๋‹ˆ๋‹ค โ€” ์ปค๋„์ด ์ง€ํ‚ค๋Š” ๊ทœ์œจ์„ ์—ฌ๊ธฐ์„œ๋„ ์ง€ํ‚จ๋‹ค).\n */\n peakKW: s => Number(s?.energy?.peakSince?.kW) || 0,\n /*\n * ์ด๋ฒˆ ๊ตฌ๊ฐ„์ด ์ด๋Œ€๋กœ ๊ฐ€๋ฉด ์–ผ๋งˆ๋กœ ๋งˆ๊ฐ๋˜๋‚˜ โ€” ์ปค๋„์ด ๋‚ธ ํˆฌ์˜(`mean-so-far`)์„ ๊ทธ๋Œ€๋กœ ์ฝ๋Š”๋‹ค.\n * ์šฐ๋ฆฌ๊ฐ€ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜์ง€ ์•Š๋Š”๋‹ค: ํˆฌ์˜ ๊ทœ์น™์ด ๋‘ ๋ฒŒ์ด ๋˜๋ฉด ํ™”๋ฉด๊ณผ ํŒ์ •์ด ๋‹ค๋ฅธ ๋ง์„ ํ•œ๋‹ค.\n */\n projectedKW: s => Number(s?.energy?.open?.projectedKW ?? s?.energy?.open?.meanKW) || 0,\n /*\n * ๊ณ„์•ฝ์„ ๋„˜๊ธด ๊ตฌ๊ฐ„ ์ˆ˜ โ€” ใ€Œ๋ช‡ ๋ฒˆ ๋„˜๋‚˜ใ€๋Š” ์š”๊ธˆ์ด ๊ฑธ๋ฆฐ ์งˆ๋ฌธ์ด๋ผ ์ตœ๋Œ€์น˜์™€ ๋”ฐ๋กœ ๋ณธ๋‹ค.\n * ๊ณ„์•ฝ์„ ๋ชจ๋ฅด๋Š” ํŠธ์œˆ์—์„œ๋Š” ๋Š˜ 0 ์ด๋‹ค(๋„˜๊น€์„ ํŒ์ •ํ•  ๊ทผ๊ฑฐ๊ฐ€ ์—†๋‹ค โ€” ์ง€์–ด๋‚ด์ง€ ์•Š๋Š”๋‹ค).\n */\n overWindows: s => (s?.energy?.closed || []).filter((w: any) => w?.overContract === true).length\n}\n\n/** ์ด ์ง€ํ‘œ๊ฐ€ ๊ทธ ์ข…๋ฅ˜์˜ ํŠธ์œˆ์—์„œ ๋œป์ด ์žˆ๋‚˜ โ€” ํ™”๋ฉด์ด ๋ชฉ๋ก์„ ๊ณ ๋ฅผ ๋•Œ ์“ด๋‹ค. */\nexport const ENERGY_METRICS = ['projectedKW', 'peakKW', 'overWindows'] as const\nexport const FLOW_METRICS = ['items', 'occupancy', 'tasks', 'orders', 'shipped', 'backlog'] as const\n\n/**\n * ํŠธ์œˆ ์ข…๋ฅ˜์— ๋งž๋Š” ์ง€ํ‘œ ๋ชฉ๋ก โ€” **ํ•œ ๊ณณ์—์„œ ์ •ํ•œ๋‹ค.**\n *\n * ํ™”๋ฉด์ด ๊ฐ์ž ๋ชฉ๋ก์„ ๋“ค๊ณ  ์žˆ์œผ๋ฉด ์ข…๋ฅ˜๊ฐ€ ๋Š˜ ๋•Œ ์–ด๋А ํ™”๋ฉด์ด ๋’ค์ฒ˜์กŒ๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค.\n */\nexport function metricsForKind(kind?: string): string[] {\n return kind === 'ems' ? [...ENERGY_METRICS] : [...FLOW_METRICS]\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"forecast-tuning.js","sourceRoot":"","sources":["../../../server/service/twin-forecast/forecast-tuning.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;AAcH,wCAKC;AAjBD,uDAAuD;AAC1C,QAAA,oBAAoB,GAAG,EAAE,CAAA;AACtC,uDAAuD;AAC1C,QAAA,WAAW,GAAG,MAAM,CAAA;AACjC,oCAAoC;AACvB,QAAA,WAAW,GAAG,KAAK,CAAA;AAEhC;;;;GAIG;AACH,SAAgB,cAAc,CAAC,SAAiB;IAC9C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC;QAAE,OAAO,mBAAW,CAAA;IACrE,MAAM,GAAG,GAAG,SAAS,GAAG,4BAAoB,CAAA;IAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,mBAAW,CAAC,GAAG,mBAAW,CAAA;IAC3D,OAAO,IAAI,CAAC,GAAG,CAAC,mBAAW,EAAE,IAAI,CAAC,GAAG,CAAC,mBAAW,EAAE,OAAO,CAAC,CAAC,CAAA;AAC9D,CAAC","sourcesContent":["/*\n * ์˜ˆ์ธก์„ ์–ผ๋งˆ๋‚˜ ์ž˜๊ฒŒ ๊ตด๋ฆด ๊ฒƒ์ธ๊ฐ€ โ€” **ํ•œ ํšŒ์ฐจ์˜ ํ‹ฑ ์ˆ˜๋ฅผ ๋ฌถ๋Š”๋‹ค.**\n *\n * โ”€โ”€ ์™œ ํ•„์š”ํ•œ๊ฐ€ (2026-08-17 ์‹ค์ธก) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์˜ˆ์ธก ๋น„์šฉ์˜ ๊ฑฐ์˜ ์ „๋ถ€๊ฐ€ ํ‹ฑ์ด๋‹ค. ํŠธ์œˆ ํ•˜๋‚˜์˜ ์˜ˆ์ธก ํ•œ ๋ฒˆ์ด 30ํšŒ์ฐจ ร— 300ํ‹ฑ = 9,000ํ‹ฑ, ํ•œ ํ‹ฑ 3.2ms โ†’\n * 28.5์ดˆ์˜€๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋ชฌํ…Œ์นด๋ฅผ๋กœ๋Š” ์ง€ํ‰์„  **๋์—์„œ** ์ง€ํ‘œ๋ฅผ ํ•œ ๋ฒˆ ์ฝ๋Š”๋‹ค โ€” ์ค‘๊ฐ„์„ 1์ดˆ ๋‹จ์œ„๋กœ ๋ณผ ์ด์œ ๊ฐ€\n * ์—†๋‹ค๋ฉด ์„ฑ๊ธ€๊ฒŒ ๊ตด๋ ค๋„ ๋‹ต์ด ๊ฐ™๋‹ค.\n *\n * ์ •๋ง ๊ฐ™์€์ง€๋Š” ์žฌ์„œ ํ™•์ธํ–ˆ๋‹ค(`operato-twin/test/fork-cost.test.ts`, 10ํšŒ์ฐจยท์ง€ํ‰์„  5๋ถ„):\n *\n * step 1s โ†’ 3,048ms ยท ์žฌ๊ณ  p50 325 ยท ์™„๋ฃŒ์ž‘์—… 8 ยท ์™„๋ฃŒ์˜ค๋” 0\n * step 5s โ†’ 628ms ยท ์žฌ๊ณ  p50 325 ยท ์™„๋ฃŒ์ž‘์—… 8 ยท ์™„๋ฃŒ์˜ค๋” 0 โ† ๋‹ต์ด ๊ฐ™๊ณ  5๋ฐฐ ์‹ธ๋‹ค\n * step 10s โ†’ 286ms ยท ์žฌ๊ณ  p50 326 ยท โ€ฆ โ† ์—ฌ๊ธฐ์„œ๋ถ€ํ„ฐ ํ”๋“ค๋ฆฐ๋‹ค\n *\n * โ”€โ”€ ์™œ ๊ณ ์ • step ์ด ์•„๋‹ˆ๋ผ ํ‹ฑ ์ˆ˜ ์ƒํ•œ์ธ๊ฐ€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * step ์„ 5์ดˆ๋กœ ๋ชป ๋ฐ•์œผ๋ฉด 1๋ถ„์งœ๋ฆฌ ์ง€ํ‰์„ ์€ 12ํ‹ฑ์ด ๋˜์–ด ๋„ˆ๋ฌด ์„ฑ๊ธ€๊ณ , 2์‹œ๊ฐ„์งœ๋ฆฌ๋Š” 1,440ํ‹ฑ์ด๋ผ ์—ฌ์ „ํžˆ\n * ๋น„์‹ธ๋‹ค. ๋ฌถ์–ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ step ์ด ์•„๋‹ˆ๋ผ **ํ•œ ํšŒ์ฐจ๊ฐ€ ๋„๋Š” ํšŸ์ˆ˜**๋‹ค.\n *\n * ์ƒํ•œ(10์ดˆ)์„ ๋”ฐ๋กœ ๋‘๋Š” ์ด์œ : ์ง€ํ‰์„ ์ด ๊ธธ๋‹ค๊ณ  ๋ฌดํ•œ์ • ์„ฑ๊ธ€๊ฒŒ ๊ตด๋ฆฌ๋ฉด ์งง์€ ์ž‘์—…(์ดˆ ๋‹จ์œ„ ํ”ผํ‚น)์ด ํ†ต์งธ๋กœ\n * ํ•œ ํ‹ฑ์— ์‚ผ์ผœ์ง„๋‹ค. ๊ทธ ์ง€์ ์„ ๋„˜์ง€ ์•Š๋Š”๋‹ค.\n */\n\n/** ํ•œ ํšŒ์ฐจ๊ฐ€ ๋„๋Š” ํ‹ฑ ์ˆ˜์˜ ๋ชฉํ‘œ โ€” ์ด๋ณด๋‹ค ์ž˜๊ฒŒ ๊ตด๋ ค์•ผ ํ•  ์ด์œ ๊ฐ€ ์ƒ๊ธฐ๋ฉด ์—ฌ๊ธฐ๋ฅผ ๊ณ ์นœ๋‹ค. */\nexport const TARGET_TICKS_PER_RUN = 60\n/** ์•„๋ฌด๋ฆฌ ์ง€ํ‰์„ ์ด ๊ธธ์–ด๋„ ์ด๋ณด๋‹ค ์„ฑ๊ธ€๊ฒŒ ๊ตด๋ฆฌ์ง€ ์•Š๋Š”๋‹ค โ€” ์งง์€ ์ž‘์—…์ด ํ•œ ํ‹ฑ์— ์‚ผ์ผœ์ง„๋‹ค. */\nexport const MAX_STEP_MS = 10_000\n/** ์ปค๋„์˜ ์‹œ๊ฐ ๋‹จ์œ„ โ€” ์ด๋ณด๋‹ค ์ž˜๊ฒŒ ๊ตด๋ฆด ์ด์œ ๋Š” ์—†๋‹ค. */\nexport const MIN_STEP_MS = 1_000\n\n/**\n * ์ด ์ง€ํ‰์„ ์„ ๊ตด๋ฆด ํ‹ฑ ํฌ๊ธฐ.\n *\n * ์ดˆ ๋‹จ์œ„๋กœ ๋–จ์–ด๋œจ๋ฆฐ๋‹ค โ€” 3,333ms ๊ฐ™์€ ๊ฐ’์€ ์‚ฌ๋žŒ์ด ์ฝ์„ ์ˆ˜๋„, ํ™”๋ฉด์ด ์„ค๋ช…ํ•  ์ˆ˜๋„ ์—†๋‹ค.\n */\nexport function forecastStepMs(horizonMs: number): number {\n if (!Number.isFinite(horizonMs) || horizonMs <= 0) return MIN_STEP_MS\n const raw = horizonMs / TARGET_TICKS_PER_RUN\n const rounded = Math.round(raw / MIN_STEP_MS) * MIN_STEP_MS\n return Math.min(MAX_STEP_MS, Math.max(MIN_STEP_MS, rounded))\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"gap-analytics.js","sourceRoot":"","sources":["../../../server/service/twin-forecast/gap-analytics.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * ์˜ˆ์ธก ์ •ํ™•๋„ ์ง„๋‹จ โ€” SPCยท์ •ํ™•๋„ยทํŽธํ–ฅยท๋ณด์ • ๊ณ„์‚ฐ์˜ canonical ๊ตฌํ˜„(์„œ๋ฒ„ ์†Œ์œ ).\n * ํ”„๋ ˆ์  ํ…Œ์ด์…˜(ํด๋ผ)์ด ์•„๋‹ˆ๋ผ ์—ฌ๊ธฐ์—์„œ ํ•œ ๋ฒˆ ๊ณ„์‚ฐํ•ด twinForecastGapTrend ๊ฐ€ ๋Œ๋ ค์ค€๋‹ค โ†’ APIยทtwin-aiยท๊ฒฝ๋ณดยท๋‹ค๋ฅธ UI ์žฌ์‚ฌ์šฉ, ์„œ๋ฒ„ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ.\n *\n * ๋‘ ์ถ•(๋…๋ฆฝ):\n * ์•ˆ์ •์„ฑ(stability) โ€” ์˜ค์ฐจ ํญ์ด ์ผ์ •ํ•œ๊ฐ€(SPC I-chart: ๊ด€๋ฆฌํ•œ๊ณ„ ์ดํƒˆ=shift, ๋‹จ์กฐ ์ถ”์„ธ=drift).\n * ํŽธํ–ฅ(bias) โ€” ํ‰๊ท  ์˜ค์ฐจ(CL)๊ฐ€ ๋ชฉํ‘œ 0 ์—์„œ ๋ฒ—์–ด๋‚ฌ๋‚˜(CL ์ด ๊ด€๋ฆฌํญ ์ ˆ๋ฐ˜ ์ด์ƒ ์ดํƒˆ ๋˜๋Š” ์ถ”์ ์‹ ํ˜ธ ํผ).\n * ๊ด€๋ฆฌ๋„๋Š” ์ž๊ธฐ ํ‰๊ท (CL)์„ ์ค‘์‹ฌ์œผ๋กœ ์žก์œผ๋ฏ€๋กœ \"์•ˆ์ •์ \"์ด \"๋ฌดํŽธํ–ฅ\"์„ ๋œปํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” ๊ทธ๋ž˜์„œ ๋ณ„๋„ ์ถ•.\n */\n\n/** SPC I-chart ํ‘œ๋ณธ ์ˆ˜ โ€” ์‹ ๋ขฐํ•  ๋งŒํ•œ ๊ด€๋ฆฌํ•œ๊ณ„์˜ ํ†ต์„ค ์ตœ์†Œ(20~25) ํ•˜ํ•œ. ์„œ๋ฒ„๊ฐ€ ๊ด€์žฅ(ํ‘œํ˜„ ๊ณ„์ธต ์•„๋‹˜). */\nexport const GAP_SAMPLES = 24\n\nexport interface GapPoint {\n t: number\n p50: number\n min: number\n max: number\n actual: number\n error: number // ์‹ค์ œ โˆ’ ์˜ˆ์ธก(p50). ์–‘์ˆ˜ = ๊ณผ์†Œ์˜ˆ์ธก(์˜ˆ์ธก์ด ๋‚ฎ์Œ).\n inBand: boolean\n naiveAbsError: number\n modelAbsError: number\n}\n\n/** ํ•ฉ์‚ฐ ๊ฒฐ๊ณผ + **๋ฌด์—‡์„ ๋ชป ๋„ฃ์—ˆ๋Š”์ง€.** ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ์ค„์ด์ง€ ์•Š๋Š”๋‹ค. */\nexport interface AggregateResult {\n points: GapPoint[]\n /** ํ•œ ํŠธ์œˆ์ด๋ผ๋„ ์žฌ์ง€ ๋ชปํ•ด ํ†ต์งธ๋กœ ๋บ€ vantage ์ˆ˜. */\n droppedVantages: number\n}\n\n/**\n * ๊ณต๋™๋ฐฐ์น˜(co-located) ํŠธ์œˆ๋“ค์˜ ์  ๋ฐฐ์—ด์„ ๊ณต์žฅ ๋‹จ์œ„ ํ•œ ์‹œ๊ณ„์—ด๋กœ ํ•ฉ์‚ฐ.\n *\n * โ”€โ”€ ์˜ˆ์ „์— ๋ฌด์—‡์ด ์–ด๊ธ‹๋‚˜ ์žˆ์—ˆ๋‚˜ (2026-08-08) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * \"๋™์ผ ๋ถ€ํŒ… โ†’ vantage ์ •๋ ฌ\" ์„ **๊ฐ€์ •**ํ•˜๊ณ  ๋ฐฐ์—ด ์ธ๋ฑ์Šค๋ผ๋ฆฌ ๋”ํ–ˆ๋‹ค. ๊ทธ ๊ฐ€์ •์€ ์„ธ ๊ณณ์—์„œ ๊นจ์กŒ๋‹ค:\n *\n * โ‘  ๊ฒฉ์ž๋ฅผ ํŠธ์œˆ๋งˆ๋‹ค ์ž๊ธฐ ์ €๋„์˜ ์ฒซยท๋งˆ์ง€๋ง‰ ์ด๋ฒคํŠธ๋กœ ๋งŒ๋“ค์—ˆ๋‹ค. ์ €๋„ ๊ตฌ๊ฐ„์ด ๋‹ค๋ฅด๋ฉด ๊ฐ™์€ ์ธ๋ฑ์Šค๊ฐ€\n * ์„œ๋กœ ๋‹ค๋ฅธ ์‹œ๊ฐ์ด๋‹ค. **๋ถ€ํŒ…์ด ๊ฐ™์•„๋„** ์–ด๊ธ‹๋‚œ๋‹ค.\n * โ‘ก ํ•œ vantage ๋ฅผ ๋ชป ์žฌ๋ฉด `continue` ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ณ  ๋ฐ€์–ด ๋‹ด์•˜๋‹ค. ๊ทธ ์ˆœ๊ฐ„๋ถ€ํ„ฐ ์ธ๋ฑ์Šค๊ฐ€ ํ•œ ์นธ์”ฉ ๋ฐ€๋ฆฐ๋‹ค.\n * โ‘ข ๊ธธ์ด๋ฅผ `max` ๋กœ ์žก์•„, ๋’ค์ชฝ ์ธ๋ฑ์Šค๋Š” ๋‚จ์€ ํŠธ์œˆ๋งŒ ๋”ํ•ด์กŒ๋‹ค โ€” ๊ณต์žฅ ํ•ฉ๊ณ„ ๊ณก์„ ์ด ๊ผฌ๋ฆฌ์—์„œ\n * ์•„๋ž˜๋กœ ๊บพ์ธ๋‹ค. ๊ณต์žฅ๊ณผ ์•„๋ฌด ์ƒ๊ด€ ์—†๋Š” ์ด์œ ๋กœ.\n *\n * ์…‹ ๋‹ค ์˜ค๋ฅ˜๋ฅผ ๋‚ด์ง€ ์•Š์•˜๋‹ค. ๊ทธ๋Ÿด๋“ฏํ•œ ๊ณก์„ ์ด ๋‚˜์˜ค๊ณ , ๊ทธ ๊ณก์„ ์œผ๋กœ ์˜ˆ์ธก ์ •ํ™•๋„๋ฅผ ํŒ์ •ํ–ˆ๋‹ค.\n *\n * โ”€โ”€ ์ง€๊ธˆ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๊ฒฉ์ž๋Š” ๋ฐ–์—์„œ ํ•˜๋‚˜๋ฅผ ๋งŒ๋“ค์–ด ๋ชจ๋‘์—๊ฒŒ ๊ฐ™์€ ๊ฒƒ์„ ์ฃผ๊ณ (`sharedGrid`), ๋ชป ์žฐ ์ž๋ฆฌ๋Š” `null` ๋กœ\n * ๋‚จ๊ธด๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” **๋ชจ๋“  ํŠธ์œˆ์ด ๊ฐ’์„ ๊ฐ€์ง„ vantage ๋งŒ** ๋”ํ•œ๋‹ค. ํ•˜๋‚˜๋ผ๋„ ๋น„๋ฉด ๊ทธ ์‹œ๊ฐ์˜\n * ๊ณต์žฅ ์ด๋Ÿ‰์€ ์•Œ ์ˆ˜ ์—†๋Š” ๊ฒƒ์ด์ง€, ๊ทธ ํŠธ์œˆ์ด 0 ์„ ๋‚ธ ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.\n *\n * ๋บ€ ๊ฐœ์ˆ˜๋Š” ๋Œ๋ ค์ค€๋‹ค โ€” ํ™”๋ฉด์ด \"24์  ์ค‘ 18์ \" ์ด๋ผ๊ณ  ๋งํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.\n */\nexport function aggregatePoints(per: (GapPoint | null)[][]): AggregateResult {\n if (!per.length) return { points: [], droppedVantages: 0 }\n const n = Math.max(0, ...per.map(pts => pts.length))\n const out: GapPoint[] = []\n let droppedVantages = 0\n for (let i = 0; i < n; i++) {\n const slot = per.map(pts => pts[i])\n if (slot.some(pt => !pt)) { droppedVantages++; continue }\n const pts = slot as GapPoint[]\n const sum = (f: (p: GapPoint) => number) => pts.reduce((a, p) => a + f(p), 0)\n const p50 = sum(p => p.p50)\n const min = sum(p => p.min)\n const max = sum(p => p.max)\n const actual = sum(p => p.actual)\n out.push({\n t: pts[0].t, // ๊ฒฉ์ž๊ฐ€ ํ•˜๋‚˜์ด๋ฏ€๋กœ ์–ด๋А ํŠธ์œˆ์—์„œ ์ฝ์–ด๋„ ๊ฐ™๋‹ค.\n p50, min, max, actual,\n error: actual - p50,\n inBand: actual >= min && actual <= max,\n naiveAbsError: sum(p => p.naiveAbsError),\n modelAbsError: sum(p => p.modelAbsError)\n })\n }\n return { points: out, droppedVantages }\n}\n\n/** ์•ˆ์ •์„ฑ ์ถ• + ํŽธํ–ฅ ์ถ• ํŒ์ •(๊ด€๋ฆฌ๋„). errors = ์‹ค์ œโˆ’์˜ˆ์ธก ์‹œ๊ณ„์—ด. */\nexport function computeSpc(errors: number[]): any {\n const n = errors.length\n if (n < 4) return { insufficient: true }\n const cl = errors.reduce((a, b) => a + b, 0) / n\n const mr: number[] = []\n for (let i = 1; i < n; i++) mr.push(Math.abs(errors[i] - errors[i - 1]))\n const mrBar = mr.reduce((a, b) => a + b, 0) / mr.length\n const sigma = mrBar / 1.128 || Math.max(1e-6, Math.abs(cl) * 0.01) // d2(n=2)=1.128\n const ucl = cl + 3 * sigma, lcl = cl - 3 * sigma\n // ์ถ•1 ์•ˆ์ •์„ฑ โ€” ๊ด€๋ฆฌํ•œ๊ณ„ ์ดํƒˆ(shift) ๋˜๋Š” ๋‹จ์กฐ ์ถ”์„ธ(drift).\n const ooc = errors.map((e, i) => (e > ucl || e < lcl ? i : -1)).filter(i => i >= 0)\n let up = 1, down = 1, trend = false\n for (let i = 1; i < n; i++) { up = errors[i] > errors[i - 1] ? up + 1 : 1; down = errors[i] < errors[i - 1] ? down + 1 : 1; if (up >= 6 || down >= 6) trend = true }\n const instability = ooc.length ? 'shift' : trend ? 'drift' : null\n // ์ถ•2 ํŽธํ–ฅ โ€” ํ‰๊ท  ์˜ค์ฐจ๊ฐ€ 0 ์—์„œ ์ดํƒˆ. |CL| > 0.5ฯƒ ๋˜๋Š” ์ถ”์ ์‹ ํ˜ธ(๋ˆ„์ ์˜ค์ฐจ/ํ‰๊ท ์ ˆ๋Œ€์˜ค์ฐจ) > 4.\n const mad = errors.reduce((s, e) => s + Math.abs(e), 0) / n || 1\n const trackingSignal = errors.reduce((a, b) => a + b, 0) / mad\n const biased = Math.abs(cl) > 0.5 * sigma || Math.abs(trackingSignal) > 4\n return { cl, ucl, lcl, sigma, n, ooc, instability, stable: !instability, biased, biasSign: cl >= 0 ? 'under' : 'over', trackingSignal }\n}\n\n/**\n * ์ง‘๊ณ„ ์ง€ํ‘œ โ€” ์ •ํ™•๋„(1โˆ’WMAPE)ยทํŽธํ–ฅ(MPE)ยท์˜ˆ์ธก๊ตฌ๊ฐ„ ์ ์ค‘ยทFVA(์˜ˆ์ธก ๊ฐ€์น˜).\n *\n * A percentage whose denominator is zero is **not measured**, and says so with `null` (2026-09-24).\n * When every actual in the window is 0 โ€” the line stood still, or the metric was not observed โ€” WMAPE\n * is undefined. It used to become 0, so the card read \"100% accurate\" beside \"0 of 6 in band, mean\n * error โˆ’20\". Likewise `fvaPct` when the naive error is 0: 0 read as \"the forecast adds nothing\".\n * The absolute measures (mean error, in-band count, fva) are real in that window and stay. The two\n * neighbours below already refuse on thin evidence (`computeSpc` ยท `learnedCalibration`).\n */\nexport function gapMetrics(pts: GapPoint[]): any {\n const sumAbsErr = pts.reduce((s, x) => s + Math.abs(x.error), 0)\n const sumActual = pts.reduce((s, x) => s + Math.abs(x.actual), 0)\n const accuracy = sumActual > 0 ? Math.max(0, Math.round((1 - sumAbsErr / sumActual) * 100)) : null\n const mpe = pts.length ? pts.reduce((s, x) => s + x.error, 0) / pts.length : 0\n const coverage = pts.length ? pts.filter(x => x.inBand).length / pts.length : 0\n // ์˜ˆ์ธก ๊ฐ€์น˜(FVA) โ€” \"ํ˜„์žฌ๊ฐ’ ๊ทธ๋Œ€๋กœ\"(naive) ๋Œ€๋น„ ์˜ค์ฐจ ๊ฐ์†Œ. fva=๊ฐ์†Œ ์ด๋Ÿ‰, fvaPct=naive ์˜ค์ฐจ๋ฅผ ๋ช‡ % ์ค„์˜€๋‚˜(๊ฐ€์น˜์˜ ํฌ๊ธฐ).\n const sumNaive = pts.reduce((s, x) => s + x.naiveAbsError, 0)\n const sumModel = pts.reduce((s, x) => s + x.modelAbsError, 0)\n const fva = sumNaive - sumModel\n const fvaPct = sumNaive > 0 ? Math.round((1 - sumModel / sumNaive) * 100) : null\n return { accuracy, mpe, coverage, inBandCount: pts.filter(x => x.inBand).length, total: pts.length, fva, fvaPct }\n}\n\n/** ํ•™์Šต(์ž๊ธฐ๋ณด์ •) ์˜ˆ์ƒ โ€” ํ‰๊ท  ์˜ค์ฐจ(ํŽธํ–ฅ)๋ฅผ ๊ฑท์–ด๋ƒˆ์„ ๋•Œ ๊ธฐ๋Œ€๋˜๋Š” ์ •ํ™•๋„ยท์ปค๋ฒ„๋ฆฌ์ง€. accBefore/covBefore ๋Š” ์›๋ณธ ์ง€ํ‘œ์—์„œ. */\nexport function learnedCalibration(pts: GapPoint[], metrics: any): any {\n if (pts.length < 3) return null\n const errs = pts.map(p => p.error)\n const biasShift = errs.reduce((a, b) => a + b, 0) / errs.length // ํ•™์Šต๋œ ํŽธํ–ฅ(์ด๋งŒํผ ์˜ˆ์ธก์„ ์˜ฌ๋ฆผ/๋‚ด๋ฆผ)\n const corrected = errs.map(e => e - biasShift) // ํŽธํ–ฅ ์ œ๊ฑฐ ํ›„ ์ž”์ฐจ\n const absC = corrected.map(Math.abs).sort((a, b) => a - b)\n const halfWidth = absC[Math.floor(absC.length * 0.8)] ?? (absC[absC.length - 1] || 1) // 80% ์ปค๋ฒ„๋ฆฌ์ง€ ๋ฐด๋“œ\n /* The bias is learnable with every actual at 0; the accuracy before and after is not (see gapMetrics). */\n const sumActual = pts.reduce((s, p) => s + Math.abs(p.actual), 0)\n const accAfter = sumActual > 0 ? Math.max(0, Math.round((1 - corrected.reduce((s, e) => s + Math.abs(e), 0) / sumActual) * 100)) : null\n const covAfter = corrected.filter(e => Math.abs(e) <= halfWidth).length\n return { biasShift: Math.round(biasShift), halfWidth: Math.round(halfWidth), accBefore: metrics.accuracy, accAfter, covBefore: metrics.inBandCount, covAfter, n: pts.length }\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/twin-forecast/index.ts"],"names":[],"mappings":";;;AAAA,qEAA4D;AAE/C,QAAA,SAAS,GAAG,CAAC,0CAAiB,CAAC,CAAA","sourcesContent":["import { TwinForecastQuery } from './twin-forecast-query.js'\n\nexport const resolvers = [TwinForecastQuery]\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"twin-forecast-query.js","sourceRoot":"","sources":["../../../server/service/twin-forecast/twin-forecast-query.ts"],"names":[],"mappings":";;;;AAAA,gDAA6C;AAC7C,4DAAwD;AACxD,+CAAiG;AAEjG,iDAAkF;AAElF,oDAAkD;AAClD,oEAAgE;AAChE,gEAAoG;AACpG,+DAAuD;AACvD,yDAA4H;AAC5H,+DAAuE;AACvE,6DAAqD;AAErD,kDAAkD;AAClD,MAAM,EAAE,uBAAuB,EAAE,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAA;AAEnE;;;;;;;;;;GAUG;AACH,SAAS,QAAQ;IACf,IAAI,SAAS,GAAG,CAAC,CAAA;IACjB,OAAO;QACL,EAAE,EAAE,GAAG,EAAE,CACP,IAAI,OAAO,CAAO,OAAO,CAAC,EAAE;YAC1B,MAAM,CAAC,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;YAC3B,YAAY,CAAC,GAAG,EAAE;gBAChB,SAAS,IAAI,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;gBAClC,OAAO,EAAE,CAAA;YACX,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC;QACJ,IAAI,EAAE;YACJ,OAAO,SAAS,CAAA;QAClB,CAAC;KACF,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,IAAI,GAAG,sCAAsC,CAAA;AACnD,MAAM,gBAAgB,GAAG;IACvB,IAAI,EAAE,CAAC;IACP,UAAU,EAAE;QACV,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE;KACnK;CACF,CAAA;AACD;;;;;;GAMG;AACH,SAAS,QAAQ,CAAC,MAAe;IAC/B,IAAI,CAAC,MAAM;QAAE,OAAO,sCAAgB,CAAC,KAAK,CAAA;IAC1C,OAAO,sCAAgB,CAAC,MAAM,CAAC,IAAI,IAAI,CAAA;AACzC,CAAC;AAED;;qEAEqE;AACrE,MAAM,WAAW,GAAG,IAAI,GAAG,EAGxB,CAAA;AACH,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,CAAS,EAAE,CAAS,EAAE,CAAS,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAA;AAEpF;;;GAGG;AACH,KAAK,UAAU,SAAS,CAAC,QAAgB,EAAE,UAAkB,EAAE,CAAS;IACtE;;;;;;;;;OASG;IACH,MAAM,IAAI,GAAG,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAA;IACrC,MAAM,IAAI,GAAG,CAAC,GAAkB,EAAE,EAAE,CAClC,IAAI;SACD,kBAAkB,CAAC,GAAG,CAAC;SACvB,MAAM,CAAC,GAAG,GAAG,eAAe,EAAE,IAAI,CAAC;SACnC,KAAK,CAAC,sBAAsB,EAAE,EAAE,QAAQ,EAAE,CAAC;SAC3C,QAAQ,CAAC,4BAA4B,EAAE,EAAE,UAAU,EAAE,CAAC;SACtD,SAAS,EAAmB,CAAA;IACjC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACzE,+DAA+D;IAC/D,MAAM,KAAK,GAAG,IAAA,2BAAY,EAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAA;IAC3D,MAAM,IAAI,GAAG,IAAA,2BAAY,EAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC,CAAA;IACzD,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAA;IAChC,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,CAAA;IAC1B,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;IACtC,OAAO,WAAW,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;AACtD,CAAC;AAED;;;;;;;;;GASG;AACH,KAAK,UAAU,SAAS,CAAC,QAAgB,EAAE,UAAkB,EAAE,CAAqB,EAAE,CAAS,EAAE,IAAc,EAAE,IAAS;IACxH,MAAM,MAAM,GAAmB,EAAE,CAAA;IACjC,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,MAAM,qBAAU,CAAC,qBAAqB,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;QACnH,IAAI,CAAC,CAAC,EAAE,CAAC;YAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAAC,SAAQ;QAAC,CAAC;QACvC,MAAM,IAAI,GAAG,MAAM,uBAAuB,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAA,mCAAc,EAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC,CAAA;QACvJ,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAA;QAChC,MAAM,EAAE,GAAG,MAAM,qBAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;QACrH,IAAI,CAAC,EAAE,EAAE,CAAC;YAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAAC,SAAQ;QAAC,CAAC;QACxC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAA;QACf,MAAM,GAAG,GAAG,IAAI,EAAE,GAAG,IAAI,KAAK,CAAA;QAC9B,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,IAAI,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,IAAI,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,GAAG,EAAE,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,QAAQ,CAAC,EAAE,aAAa,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,EAAE,aAAa,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,CAAA;IAClP,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;;;GAMG;AACH,SAAS,UAAU,CAAC,OAA8C,EAAE,CAAS;IAC3E,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA;IACzC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC9C,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAA;IAChE,IAAI,CAAC,CAAC,WAAW,GAAG,EAAE,CAAC;QAAE,OAAO,IAAI,CAAA;IACpC,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,WAAW,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;AACrF,CAAC;AAIM,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAKtB,AAAN,KAAK,CAAC,YAAY,CACG,UAAkB,EACF,MAAc,EACH,IAAY,EACP,SAAiB,EACT,QAAa,EACzC,EAAU,EAClC,OAAwB;QAE/B;;oEAE4D;QAC5D,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAA;QACxC,MAAM,CAAC,GAAG,EAAE;YACV,CAAC,CAAC,MAAM,qBAAU,CAAC,qBAAqB,CAAC,QAAQ,EAAE,UAAU,EAAE,EAAE,CAAC;YAClE,CAAC,CAAC,qBAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC;gBACrC,CAAC,CAAC,qBAAU,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC;gBACzC,CAAC,CAAC,SAAS,CAAA;QACf,IAAI,CAAC,CAAC;YAAE,OAAO,IAAI,CAAA;QAEnB,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAA;QAC1B,mDAAmD;QACnD,IAAI,CAAC,CAAC;YAAE,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,CAAA;QACtF,MAAM,CAAC,GAAG,SAAS,IAAI,MAAM,CAAA;QAC7B,MAAM,CAAC,GAAG,IAAI,IAAI,EAAE,CAAA;QACpB;;;WAGG;QACH,MAAM,IAAI,GAAG,IAAA,mCAAc,EAAC,CAAC,CAAC,CAAA;QAC9B,MAAM,IAAI,GAAG,QAAQ,IAAI,gBAAgB,CAAA;QAEzC;;;;;WAKG;QACH,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;QAC7B,MAAM,QAAQ,GAAG,QAAQ,EAAE,CAAA;QAC3B,MAAM,YAAY,GAAG,MAAM,uBAAuB,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAA;QAC/I,qBAAU,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;QAC9F,qBAAU,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC,CAAA;QAE9C;8EACsE;QACtE,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,CAAA;QAClF;;;;;;WAMG;QACH,MAAM,KAAK,GAAG,MAAM,qBAAU,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QAC/D,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,IAAI,IAAA,kCAAiB,EAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;QAChE,IAAI,KAAK,EAAE,CAAC;YACV,IAAA,gBAAO,EACL,oBAAoB,UAAU,kEAAkE;gBAC9F,gBAAgB,IAAA,mCAAkB,EAAC,MAAO,CAAC,KAAK,CAAC,WAAW,IAAA,mCAAkB,EAAC,KAAK,CAAC,EAAE,CAC1F,CAAA;QACH,CAAC;QACD;;;;;;;WAOG;QACH,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,OAAO,GAAa,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAA;YACzF,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACnB,MAAM,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;gBACjD,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;gBAC7F,YAAY,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,CAAA;gBAC5B,YAAY,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,CAAA;YAC9B,CAAC;YACD,YAAY,CAAC,WAAW,GAAG,OAAO,CAAC,MAAM,CAAA;QAC3C,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAA;QACjD,IAAI,GAAG,IAAI,YAAY,EAAE,CAAC;YACxB;;;;eAIG;YACH,IAAI,OAAO,YAAY,CAAC,GAAG,KAAK,QAAQ;gBAAE,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAA;YACtH,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,GAAG,GAAG,CAAC,SAAS,CAAA;YAC7C,YAAY,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;YACnC,YAAY,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,GAAG,CAAC,SAAS,CAAC,CAAA;YACnD,YAAY,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,GAAG,CAAC,SAAS,CAAC,CAAA;YACnD;;;;;eAKG;YACH,IAAI,YAAY,CAAC,GAAG,KAAK,SAAS;gBAAE,YAAY,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC,CAAA;YACnG,IAAI,YAAY,CAAC,GAAG,KAAK,SAAS;gBAAE,YAAY,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC,CAAA;YACnG,IAAI,YAAY,CAAC,GAAG,KAAK,SAAS;gBAAE,YAAY,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC,CAAA;YACnG,YAAY,CAAC,UAAU,GAAG,IAAI,CAAA;QAChC,CAAC;QAED;;;;;WAKG;QACH,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;QAC/B,MAAM,UAAU,GAAG,QAAQ,EAAE,CAAA;QAC7B,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;QACnB,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAA;QACtC,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAA;QACnB,MAAM,UAAU,GAAmC,EAAE,CAAA;QACrD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;YACjC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACb,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,CAAA;YAC5D,uDAAuD;YACvD,IAAI,UAAU,CAAC,MAAM,GAAG,EAAE,KAAK,CAAC;gBAAE,MAAM,UAAU,CAAC,EAAE,EAAE,CAAA;QACzD,CAAC;QAED,qBAAU,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,UAAU,CAAC,EAAE,CAAC,CAAA;QAClG,qBAAU,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC,CAAA;QAE9C,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAA,CAAC,2CAA2C;QAE9E;0FACkF;QAClF,MAAM,MAAM,GAAmC,EAAE,CAAA;QACjD,IAAI,MAAM,GAAQ,IAAI,CAAA;QACtB,IAAI,EAAE,EAAE,CAAC;YACP,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;YACxB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;YACzC,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC,CAAA;YACtB,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;gBACnC,MAAM,OAAO,GAAG,CAAC,CAAA;gBACjB,MAAM,EAAE,GAAG,IAAI,GAAG,OAAO,CAAA;gBACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;oBAClC,MAAM,EAAE,GAAG,MAAM,qBAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;oBAC1H,IAAI,EAAE;wBAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;gBAClD,CAAC;gBACD,8FAA8F;gBAC9F,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;oBACzC,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,CAAA;oBACzC,MAAM,GAAG,GAAG,YAAY,EAAE,GAAG,IAAI,OAAO,CAAA;oBACxC,MAAM,GAAG;wBACP,MAAM,EAAE,CAAC;wBACT,GAAG;wBACH,KAAK,EAAE,CAAC,GAAG,GAAG,EAAE,yBAAyB;wBACzC,MAAM,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,IAAI,QAAQ,CAAC;wBACrF,aAAa,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;wBAChC,aAAa,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,6CAA6C;qBACnF,CAAA;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED;;;;WAIG;QACH;sEAC8D;QAC9D,MAAM,YAAY,GAAG,IAAA,mCAAgB,EAAC,EAAE,CAAC,IAAI,IAAA,mCAAgB,EAAC,CAAC,CAAC,CAAA;QAChE,OAAO;YACL,MAAM,EAAE,MAAM,IAAI,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM;YACnG,mEAAmE;YACnE,MAAM,EAAE,IAAI;YACZ;;;;;;eAMG;YACH,GAAG,CAAC,OAAQ,EAAU,CAAC,oBAAoB,KAAK,UAAU;gBACxD,CAAC,CAAC,CAAC,GAAG,EAAE;oBACJ,MAAM,QAAQ,GAAI,EAAU,CAAC,oBAAoB,EAAE,CAAA;oBACnD,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;gBAC3D,CAAC,CAAC,EAAE;gBACN,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,OAAQ,EAAU,CAAC,oBAAoB,KAAK,UAAU;gBACxD,CAAC,CAAC,CAAC,GAAG,EAAE;oBACJ,MAAM,SAAS,GAAI,EAAU,CAAC,oBAAoB,EAAE,CAAA;oBACpD,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;gBAC9C,CAAC,CAAC,EAAE;gBACN,CAAC,CAAC,EAAE,CAAC;YACP,UAAU,EAAE,CAAC,CAAC,GAAG;YACjB,qDAAqD;YACrD,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5C,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzC;;;;;;;;;;;;;;;;;eAiBG;YACH,GAAG,CAAC,GAAG,EAAE;gBACP,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAClB,YAAoB,EAAE,oBAAoB,IAAI,CAAC,EAC/C,EAAU,EAAE,WAAW,EAAE,EAAE,EAAE,oBAAoB,IAAI,CAAC,CACxD,CAAA;gBACD,sDAAsD;gBACtD,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,oBAAoB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;YACvD,CAAC,CAAC,EAAE;SACL,CAAA;IACH,CAAC;IAED;;;;OAIG;IAMG,AAAN,KAAK,CAAC,oBAAoB,CACL,UAAkB,EACF,MAAc,EACE,SAAiB,EACnB,OAAe,EACL,QAAa,EACjE,OAAwB,EAC2B,WAAsB;QAEhF,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAA;QACxC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAA;QAC1B,MAAM,CAAC,GAAG,SAAS,IAAI,MAAM,CAAA;QAC7B,IAAI,CAAC,CAAC;YAAE,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,IAAA,6BAAU,EAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;QACzI,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,IAAI,8BAAW,CAAC,CAAC,CAAA,CAAC,6BAA6B;QACzF,MAAM,IAAI,GAAG,QAAQ,IAAI,gBAAgB,CAAA;QACzC,6DAA6D;QAC7D,MAAM,GAAG,GAAG,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAA;QAE5D;;;;;;WAMG;QACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAC,EAAE,EAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,SAAS,CAAC,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QACrG,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACvC,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QACzD,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,CAAA;QACjD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,8CAA8C;YAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,IAAA,6BAAU,EAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI;gBACvH,QAAQ,EAAE,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,CAAA;QAC9H,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;QAC3F,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,GAAG,IAAA,kCAAe,EAAC,GAA4B,CAAC,CAAA;QACjF,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAA,6BAAU,EAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QACzD,MAAM,GAAG,GAAG,IAAA,6BAAU,EAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAA;QAChD,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,IAAA,qCAAkB,EAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QAClE,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK;YACvF,uDAAuD;YACvD,QAAQ,EAAE,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,CAAA;IACxI,CAAC;IAED;;;;OAIG;IAGG,AAAN,KAAK,CAAC,oBAAoB,CACL,UAAkB,EACF,MAAc,EACE,SAAiB,EAC7D,OAAwB,EACoB,KAAe;QAElE,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAA;QACxC,IAAI,CAAC,qBAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAA,CAAC,SAAS;QAC1E,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAA;QAC1B,IAAI,CAAC,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,EAAE,CAAA;QAClE,MAAM,CAAC,GAAG,SAAS,IAAI,MAAM,CAAA;QAC7B,qEAAqE;QACrE,IAAI,KAAK,EAAE,CAAC;YACV,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,CAAA;YACtE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,IAAI,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,CAAA;QAC7E,CAAC;QACD,0EAA0E;QAC1E,kEAAkE;QAClE,MAAM,CAAC,GAAG,MAAM,SAAS,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC,CAAA;QAClD,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,8BAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QACpD,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAA;QAC/D,0DAA0D;QAC1D,MAAM,GAAG,GAAG,CAAC,MAAM,SAAS,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAe,CAAA;QAC/G,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAA;QACxE,MAAM,KAAK,GAAG,IAAA,qCAAkB,EAAC,GAAG,EAAE,IAAA,6BAAU,EAAC,GAAG,CAAC,CAAC,CAAA;QACtD,qDAAqD;QACrD,MAAM,KAAK,GAAG,MAAM,qBAAU,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QAC/D,MAAM,GAAG,GAAG;YACV,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,EAAE,EAAE,EAAE;YACN,OAAO,EAAE,GAAG,CAAC,MAAM;YACnB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC5B,CAAA;QACD,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,IAAI,OAAO,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;QACxE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,IAAI,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAA;IACzL,CAAC;CACF,CAAA;AA3UY,8CAAiB;AAKtB;IAJL,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,oBAAY,EAAE;QAC9B,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE,kKAAkK;KAChL,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,YAAY,CAAC,CAAA;IACjB,mBAAA,IAAA,kBAAG,EAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IACjC,mBAAA,IAAA,kBAAG,EAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IAC5C,mBAAA,IAAA,kBAAG,EAAC,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IACjD,mBAAA,IAAA,kBAAG,EAAC,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,oBAAY,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IACzD,mBAAA,IAAA,kBAAG,EAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7B,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;qDAuNP;AAYK;IALL,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,oBAAY,EAAE;QAC9B,QAAQ,EAAE,IAAI;QACd,WAAW,EACT,gUAAgU;KACnU,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,YAAY,CAAC,CAAA;IACjB,mBAAA,IAAA,kBAAG,EAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IACjC,mBAAA,IAAA,kBAAG,EAAC,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IACjD,mBAAA,IAAA,kBAAG,EAAC,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IAC/C,mBAAA,IAAA,kBAAG,EAAC,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,oBAAY,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IACzD,mBAAA,IAAA,kBAAG,GAAE,CAAA;IACL,mBAAA,IAAA,kBAAG,EAAC,aAAa,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;;;;6DAoC1D;AASK;IAFL,IAAA,wBAAS,EAAC,uGAAuG,CAAC;IAClH,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,oBAAY,EAAE,EAAE,WAAW,EAAE,6JAA6J,EAAE,CAAC;IAE/M,mBAAA,IAAA,kBAAG,EAAC,YAAY,CAAC,CAAA;IACjB,mBAAA,IAAA,kBAAG,EAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IACjC,mBAAA,IAAA,kBAAG,EAAC,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IACjD,mBAAA,IAAA,kBAAG,GAAE,CAAA;IACL,mBAAA,IAAA,kBAAG,EAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;;;;6DAkCnD;4BA1UU,iBAAiB;IAF7B,IAAA,uBAAQ,GAAE;IACV,IAAA,4BAAa,EAAC,qBAAa,CAAC;GAChB,iBAAiB,CA2U7B","sourcesContent":["import { twinLog } from '../../engine/log.js'\nimport { hydratedDate } from '../../engine/read-time.js'\nimport { Arg, Ctx, Int, Mutation, Query, Resolver, Directive, UseMiddleware } from 'type-graphql'\n\nimport { getRepository, ScalarObject, SpeakRefusals } from '@things-factory/shell'\n\nimport { TwinEngine } from '../../engine/index.js'\nimport { readSpecCoverage } from '../../engine/spec-coverage.js'\nimport { describeModelBasis, modelBasisChanged, type ModelBasis } from '../../engine/model-basis.js'\nimport { TwinEvent } from '../twin-event/twin-event.js'\nimport { GAP_SAMPLES, aggregatePoints, computeSpc, gapMetrics, learnedCalibration, type GapPoint } from './gap-analytics.js'\nimport { FORECAST_METRICS, type MetricFn } from './forecast-metrics.js'\nimport { forecastStepMs } from './forecast-tuning.js'\n\n/* ์ปค๋„ ์˜ˆ์ธก ํ•จ์ˆ˜ โ€” CJS require(twin-engine ๊ณผ ๋™์ผ ๋ฐฉ์‹). */\nconst { monteCarloForecastAsync } = require('@operato/twin-kernel')\n\n/**\n * ์ด๋ฒคํŠธ ๋ฃจํ”„์— ์ž๋ฆฌ๋ฅผ ๋‚ด์ฃผ๋Š” ๋ฐฉ๋ฒ• โ€” **์ปค๋„์ด ์•„๋‹ˆ๋ผ ์—ฌ๊ธฐ๊ฐ€ ์•ˆ๋‹ค.**\n *\n * `setImmediate` ๋Š” ๋Œ€๊ธฐ ์ค‘์ธ I/O ๋‹ค์Œ ์ฐจ๋ก€์— ๋Œ์•„์˜จ๋‹ค. ๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ(`Promise.resolve()`)๋กœ๋Š”\n * ์ž๋ฆฌ๊ฐ€ ๊ฐ€์ง€ ์•Š๋Š”๋‹ค โ€” ๊ทธ๋Ÿฌ๋ฉด ์˜ˆ์ธก์ด ๋„๋Š” ๋™์•ˆ ๋ผ์ด๋ธŒ ํ‹ฑ๋„ HTTP ๋„ ์—ฌ์ „ํžˆ ๋ฉˆ์ถ˜๋‹ค.\n *\n * โ”€โ”€ ๋‚ด์ค€ ์‹œ๊ฐ„์€ **๋ถ€ํ•˜๊ฐ€ ์•„๋‹ˆ๋‹ค** โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๋ถ€ํ•˜ ๊ณ„๊ธฐ๋Š” ใ€Œ์ด ํŠธ์œˆ์ด ๋ฃจํ”„๋ฅผ ์–ผ๋งˆ๋‚˜ ๋ถ™์žก์•˜๋‚˜ใ€๋ฅผ ์žฌ๋Š” ์ž๋‹ค. ์–‘๋ณด๋ฅผ ๋„ฃ์€ ๋’ค๋กœ ๋ฒฝ์‹œ๊ณ„ ์‹œ๊ฐ„์—๋Š”\n * ๋‚จ์—๊ฒŒ ๋„˜๊ธด ์‹œ๊ฐ„์ด ์„ž์ด๋Š”๋ฐ, ๊ทธ๊ฒƒ๊นŒ์ง€ ๋ถ€ํ•˜๋กœ ์ ์œผ๋ฉด ๊ณ„๊ธฐ๊ฐ€ ๊ฑฐ์ง“๋ง์„ ํ•œ๋‹ค โ€” ํ•˜ํ•„ ์ด ๋ฌธ์ œ๋ฅผ ์งš์–ด๋‚ธ\n * ๊ทธ ๊ณ„๊ธฐ๋‹ค. ๊ทธ๋ž˜์„œ ๋‚ด์ค€ ์‹œ๊ฐ„์„ ๋”ฐ๋กœ ์„ธ์–ด ๋นผ๊ณ  ์ ๋Š”๋‹ค.\n */\nfunction breather() {\n let yieldedMs = 0\n return {\n fn: () =>\n new Promise<void>(resolve => {\n const t = performance.now()\n setImmediate(() => {\n yieldedMs += performance.now() - t\n resolve()\n })\n }),\n get ms() {\n return yieldedMs\n }\n }\n}\n\n/*\n * ํŠธ์œˆ ์˜ˆ์ธก ์ฑ„๋„ โ€” ์ƒํ–ฅ query. ํŠธ์œˆ์˜ \"์˜ˆ์ธก(predict)\" ๋ฉด(์„ค๊ณ„ ยง3.5, ADR-0009).\n * ์ปค๋„ monteCarloForecast(ํ˜„์žฌ์—์„œ N fork โ†’ ์ง€ํ‘œ ๋ถ„ํฌ) + ๋‹จ์ผ fork ์˜ˆ์ธก ๊ถค์ . ์›๋ณธ live ๋ฌด๊ฐ„์„ญ(fork ๊ฒฉ๋ฆฌ).\n * metric ์€ ๋„๋ฉ”์ธ-์ผ๋ฐ˜(์Šค๋ƒ…์ƒท ํŒŒ์ƒ), scenario ๋Š” ๋ฏธ๋ž˜ ์ž๊ทน(๊ธฐ๋ณธ=๊ณ„์† ์ž…๊ณ , ์‹ค ์‹œ์Šคํ…œ์€ ์ธ์Šคํ„ด์Šค/์„ค์ • ํŒŒ์ƒ).\n */\nconst GTIN = 'urn:epc:idpat:sgtin:0614141.012345.*'\nconst DEFAULT_SCENARIO = {\n seed: 7,\n generators: [\n { kind: 'inbound-arrival', rate: { distribution: 'poisson', meanPerHour: 60 }, content: { skuMix: [{ gtin: GTIN, weight: 1 }], qtyPerLine: { min: 4, max: 12 } } }\n ]\n}\n/*\n * ์ง€ํ‘œ ํ‘œ๋Š” `forecast-metrics.ts` ๊ฐ€ ์†Œ์œ ํ•œ๋‹ค โ€” ์—ฌ๊ธฐ ์žˆ๋˜ ๊ฒƒ์„ ์˜ฎ๊ฒผ๋‹ค(์‹œํ—˜์ด ์ด ํŒŒ์ผ์„ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์—†๋‹ค).\n *\n * **๋ชจ๋ฅด๋Š” ์ง€ํ‘œ๋ฅผ `items` ๋กœ ๊ฐˆ์Œํ•˜์ง€ ์•Š๋Š”๋‹ค.** ์˜ˆ์ „์—๋Š” `METRICS[metric] ?? METRICS.items` ์˜€๋‹ค.\n * ์—๋„ˆ์ง€ ํŠธ์œˆ์—์„œ `peakKW` ๋ฅผ ๋ฌผ์œผ๋ฉด ์žฌ๊ณ  ๊ณก์„ ์ด ๊ทธ๋ ค์ง€๊ณ , ์žฌ๊ณ ๊ฐ€ ์—†์œผ๋‹ˆ **0 ์ด ํ‰ํ‰ํ•˜๊ฒŒ** ๋‚˜์™”๋‹ค โ€”\n * ํ™”๋ฉด์€ ๊ทธ๊ฒƒ์„ ใ€Œํ”ผํฌ๊ฐ€ 0ใ€์œผ๋กœ ์ฝ๋Š”๋‹ค. ์ง€์–ด๋‚ธ ๋‹ต๋ณด๋‹ค ๋ชจ๋ฅธ๋‹ค๊ณ  ๋งํ•˜๋Š” ํŽธ์ด ๋‚ซ๋‹ค.\n */\nfunction metricFn(metric?: string): MetricFn | null {\n if (!metric) return FORECAST_METRICS.items\n return FORECAST_METRICS[metric] ?? null\n}\n\n/* ํ•™์Šต๋œ ๋ณด์ • ์ €์žฅ(P3.2, ์ธ๋ฉ”๋ชจ๋ฆฌ) โ€” key=domain:instance:metric:horizon โ†’ {biasShift, halfWidth, โ€ฆ}.\n twinLearnCalibration ์ด ๊ฐญ์—์„œ ํ•™์Šตํ•ด ์ €์žฅํ•˜๊ณ , twinForecast ๊ฐ€ ์žˆ์œผ๋ฉด ์˜ˆ์ธก์— ์ƒ์‹œ ์ ์šฉ(๋ผ์ด๋ธŒ ๋ณด์ •).\n ๋ฐ๋ชจ ํŠธ์œˆ์€ ์žฌ๋ถ€ํŒ… ์‹œ ์ €๋„ ๋ฆฌ์…‹์ด๋ผ ์„ธ์…˜ ์Šค์ฝ”ํ”„๋กœ ์ถฉ๋ถ„ โ€” DB ์˜์†(TwinForecastScore)์€ ํ›„์†. */\nconst CALIBRATION = new Map<\n string,\n { biasShift: number; halfWidth: number; at: string; samples: number; accBefore: number | null; accAfter: number | null; basis?: ModelBasis }\n>()\nconst calKey = (d: string, i: string, m: string, h: number) => `${d}:${i}:${m}:${h}`\n\n/**\n * ์ด ํŠธ์œˆ์ด ๋ฐฑํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋Š” ๊ตฌ๊ฐ„ โ€” [์ฒซ ์ด๋ฒคํŠธ, ๋งˆ์ง€๋ง‰ ์ด๋ฒคํŠธ โˆ’ H].\n * ์ง€ํ‰ H ๋งŒํผ ์•ž์„ ๋ด์•ผ \"๊ทธ๋•Œ ์˜ˆ์ธกํ•œ ๊ฒƒ\"๊ณผ \"์‹ค์ œ๋กœ ๋ฒŒ์–ด์ง„ ๊ฒƒ\"์„ ๋งž๋Œ€ ๋ณผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋์—์„œ H ๋ฅผ ๋บ€๋‹ค.\n */\nasync function gapWindow(domainId: string, instanceId: string, H: number): Promise<{ t0: number; lastVantage: number } | null> {\n /*\n * โ”€โ”€ **์–‘ ๋์„ ์ง‘๊ณ„๋กœ ๋ฌป๋Š”๋‹ค** (2026-08-28) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n *\n * ์˜ˆ์ „์—๋Š” `findOne({ where: { domain: { id } }, order: { eventTime } })` ๋‘ ๋ฒˆ์ด์—ˆ๋‹ค. ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง„\n * ์—”ํ‹ฐํ‹ฐ์—์„œ `findOne` ์€ ๋‘ ๋‹จ๊ณ„ ์งˆ์˜๊ฐ€ ๋˜๊ณ  **์•ˆ์ชฝ์— ์ƒํ•œ์ด ์—†๋‹ค** โ€” ๊ทธ ํŠธ์œˆ์˜ ์ €๋„์„ ์ „๋ถ€ ๋งŒ๋“  ๋’ค\n * ํ•œ ์ค„์„ ๊ณ ๋ฅธ๋‹ค. ์Šนํ™”ํ‘ธ๋“œ๋Š” 337๋งŒ ํ–‰์ด๊ณ , ๊ทธ๊ฒƒ์„ ๋‘ ๋ฒˆ ํ–ˆ๋‹ค.\n *\n * `MIN`/`MAX` ๋Š” `(domain, instance, event_time)` ์ƒ‰์ธ์˜ ์–‘ ๋์„ ์ง‘์œผ๋ฏ€๋กœ ๊ฐ๊ฐ ํ•œ ์ค„์ด๋‹ค.\n * ์ด ํŒŒ์ผ์˜ ๋‹ค๋ฅธ ์ž๋ฆฌ์™€ ๊ฐ™์€ ๊ทœ์œจ์ด๋‹ค(ยง`twin-engine` ์˜ `tipOf`).\n */\n const repo = getRepository(TwinEvent)\n const edge = (agg: 'MIN' | 'MAX') =>\n repo\n .createQueryBuilder('e')\n .select(`${agg}(e.eventTime)`, 'at')\n .where('e.domain = :domainId', { domainId })\n .andWhere('e.instanceId = :instanceId', { instanceId })\n .getRawOne<{ at: unknown }>()\n const [firstRow, lastRow] = await Promise.all([edge('MIN'), edge('MAX')])\n /* ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ์ค€ ๊ฐ’์€ ์‹œ๊ฐ„๋Œ€๊ฐ€ ์—†์„ ์ˆ˜ ์žˆ๋‹ค โ€” ์ปฌ๋Ÿผ ๋ณ€ํ™˜์„ ์ง€๋‚˜๊ฒŒ ํ•œ๋‹ค(ยง`hydratedDate`). */\n const first = hydratedDate(repo, 'eventTime', firstRow?.at)\n const last = hydratedDate(repo, 'eventTime', lastRow?.at)\n if (!first || !last) return null\n const t0 = first.getTime()\n const lastVantage = last.getTime() - H\n return lastVantage > t0 ? { t0, lastVantage } : null\n}\n\n/**\n * ๊ฐญ point ๊ณ„์‚ฐ(๊ณต์šฉ) โ€” ์ฃผ์–ด์ง„ vantage ๊ฐ๊ฐ์—์„œ forecast-at-T vs actual-at-T+H(๊ฒฐ์ •์  ๋ฐฑํ…Œ์ŠคํŠธ).\n *\n * **vantage ๋Š” ๋ฐ–์—์„œ ์ค€๋‹ค.** ์˜ˆ์ „์—๋Š” ์ด ํ•จ์ˆ˜๊ฐ€ ์ž๊ธฐ ์ €๋„์˜ ์ฒซยท๋งˆ์ง€๋ง‰ ์ด๋ฒคํŠธ๋กœ ๊ฒฉ์ž๋ฅผ ์Šค์Šค๋กœ ๋งŒ๋“ค์—ˆ๋‹ค.\n * ๊ทธ๋Ÿฌ๋ฉด ํŠธ์œˆ๋งˆ๋‹ค ๊ฒฉ์ž๊ฐ€ ๋‹ฌ๋ผ์ ธ, ๊ณต๋™๋ฐฐ์น˜ ํ•ฉ์‚ฐ์—์„œ `points[3]` ๋ผ๋ฆฌ ๋”ํ•  ๋•Œ **์„œ๋กœ ๋‹ค๋ฅธ ์‹œ๊ฐ์˜ ๊ฐ’**์ด\n * ๋”ํ•ด์กŒ๋‹ค(์ž์„ธํ•œ ์‚ฌ์—ฐ์€ `aggregatePoints` ์ฃผ์„).\n *\n * ๋ฐ˜ํ™˜ ๋ฐฐ์—ด์€ ๊ฒฉ์ž์™€ **๊ฐ™์€ ๊ธธ์ด**์ด๊ณ , ๊ทธ vantage ๋ฅผ ์žฌ์ง€ ๋ชปํ–ˆ์œผ๋ฉด ๊ทธ ์ž๋ฆฌ์— `null` ์„ ๋‘”๋‹ค.\n * ๊ฑด๋„ˆ๋›ฐ๊ณ  ๋ฐ€์–ด ๋‹ด์œผ๋ฉด ๋ฐฐ์—ด ์ธ๋ฑ์Šค๊ฐ€ ์‹œ๊ฐ„์ถ•์ด๊ธฐ๋ฅผ ๊ทธ๋งŒ๋‘”๋‹ค.\n */\nasync function gapPoints(domainId: string, instanceId: string, m: (s: any) => number, H: number, grid: number[], scen: any): Promise<(any | null)[]> {\n const points: (any | null)[] = []\n for (const T of grid) {\n const k = await TwinEngine.buildForecastKernelAt(domainId, instanceId, new Date(T).toISOString()).catch(() => null)\n if (!k) { points.push(null); continue }\n const dist = await monteCarloForecastAsync(k, { runs: 12, horizonMs: H, scenario: scen, tickMs: forecastStepMs(H), metric: m, yieldFn: breather().fn })\n const naive = m(k.getSnapshot())\n const st = await TwinEngine.recover(domainId, instanceId, undefined, new Date(T + H).toISOString()).catch(() => null)\n if (!st) { points.push(null); continue }\n const a = m(st)\n const p50 = dist?.p50 ?? naive\n points.push({ t: T, p50, min: dist?.min ?? p50, max: dist?.max ?? p50, actual: a, error: a - p50, inBand: a >= (dist?.min ?? -Infinity) && a <= (dist?.max ?? Infinity), naiveAbsError: Math.abs(a - naive), modelAbsError: Math.abs(a - p50) })\n }\n return points\n}\n\n/**\n * ์—ฌ๋Ÿฌ ํŠธ์œˆ์ด **ํ•จ๊ป˜** ๋ฐฑํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋Š” ๊ตฌ๊ฐ„๊ณผ ๊ทธ ์œ„์˜ vantage ๊ฒฉ์ž.\n *\n * ๊ฒน์น˜๋Š” ๊ตฌ๊ฐ„์€ ๊ฐ์ž์˜ ๊ตฌ๊ฐ„์„ ๊ต์ง‘ํ•ฉํ•œ ๊ฒƒ โ€” ์‹œ์ž‘์€ ๊ฐ€์žฅ ๋Šฆ์€ t0, ๋์€ ๊ฐ€์žฅ ์ด๋ฅธ lastVantage.\n * ํ•œ ํŠธ์œˆ์ด๋ผ๋„ ๊ทธ ์‹œ๊ฐ์— ์ €๋„์ด ์—†์œผ๋ฉด ๊ณต์žฅ ์ด๋Ÿ‰์„ ๋งํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.\n * ๊ฒน์น˜๋Š” ๊ตฌ๊ฐ„์ด ์—†์œผ๋ฉด `null` โ€” \"0\" ์ด ์•„๋‹ˆ๋ผ \"์žด ์ˆ˜ ์—†์Œ\" ์ด๋‹ค.\n */\nfunction sharedGrid(windows: { t0: number; lastVantage: number }[], N: number): number[] | null {\n if (!windows.length || N < 2) return null\n const t0 = Math.max(...windows.map(w => w.t0))\n const lastVantage = Math.min(...windows.map(w => w.lastVantage))\n if (!(lastVantage > t0)) return null\n return Array.from({ length: N }, (_, i) => t0 + ((lastVantage - t0) * i) / (N - 1))\n}\n\n@Resolver()\n@UseMiddleware(SpeakRefusals)\nexport class TwinForecastQuery {\n @Query(returns => ScalarObject, {\n nullable: true,\n description: 'Monte-Carlo forecast of a metric over a horizon (twin prediction faculty) + a single-fork predicted trajectory. Live instance is untouched (forks are isolated).'\n })\n async twinForecast(\n @Arg('instanceId') instanceId: string,\n @Arg('metric', { nullable: true }) metric: string,\n @Arg('runs', type => Int, { nullable: true }) runs: number,\n @Arg('horizonMs', type => Int, { nullable: true }) horizonMs: number,\n @Arg('scenario', type => ScalarObject, { nullable: true }) scenario: any,\n @Arg('at', { nullable: true }) at: string,\n @Ctx() context: ResolverContext\n ): Promise<any> {\n /* vantage(at) ๊ธฐ์ค€ ์˜ˆ์ธก โ€” ํžˆ์Šคํ† ๋ฆฌ ๋…ธ๋ธŒ๊ฐ€ ๊ณผ๊ฑฐ T ๋ฉด \"๊ทธ๋•Œ ์„œ์„œ ๋ณธ ๋ฏธ๋ž˜\"(๋ฐฑํ…Œ์ŠคํŠธ).\n at ์žˆ์œผ๋ฉด T ์‹œ์  ์ปค๋„์„ ์ €๋„๋กœ ์žฌ๊ตฌ์„ฑํ•œ๋‹ค(๊ทธ๊ฑด ์šฐํšŒ๊ฐ€ ์•„๋‹ˆ๋ผ ์‹œ๊ฐ„์—ฌํ–‰์˜ ๋ณธ์งˆ).\n ์—†์œผ๋ฉด **์ง€๊ธˆ ๊ทธ ์ปค๋„**์„ ์“ด๋‹ค โ€” sim ์ด๋“  live ๋“  ์ธ์Šคํ„ด์Šค๊ฐ€ ์ปค๋„์ด๋‹ค(ํ†ตํ•ฉ P2). */\n const domainId = context.state.domain.id\n const k = at\n ? await TwinEngine.buildForecastKernelAt(domainId, instanceId, at)\n : TwinEngine.owns(domainId, instanceId)\n ? TwinEngine.kernel(domainId, instanceId)\n : undefined\n if (!k) return null\n\n const m = metricFn(metric)\n /* ์ด ํŠธ์œˆ์ด ๋ชป ์„ธ๋Š” ์ง€ํ‘œ โ€” ๋นˆ ์˜ˆ์ธก์ด ์•„๋‹ˆ๋ผ ใ€Œ๊ทธ ์ง€ํ‘œ๋Š” ์—ฌ๊ธฐ ์—†๋‹คใ€๊ณ  ๋งํ•œ๋‹ค. */\n if (!m) return { metric, unsupportedMetric: true, distribution: null, trajectory: [] }\n const H = horizonMs ?? 300000\n const R = runs ?? 30\n /*\n * ํ‹ฑ ํฌ๊ธฐ๋Š” **์ง€ํ‰์„ ์ด ์ •ํ•œ๋‹ค**(`forecast-tuning`). 1์ดˆ ๊ณ ์ •์ด๋˜ ์‹œ์ ˆ 5๋ถ„ ์ง€ํ‰์„ ์ด ํšŒ์ฐจ๋งˆ๋‹ค\n * 300ํ‹ฑ์ด์—ˆ๊ณ , 30ํšŒ์ฐจ๋ฉด 9,000ํ‹ฑยท28.5์ดˆ์˜€๋‹ค โ€” ์‹ค์ธก์œผ๋กœ 5์ดˆ ๋‹จ์œ„์™€ ๋‹ต์ด ๊ฐ™๋‹ค.\n */\n const step = forecastStepMs(H)\n const scen = scenario ?? DEFAULT_SCENARIO\n\n /*\n * ๋ถ„ํฌ: N๊ฐœ ํ™•๋ฅ ์  ๋ฏธ๋ž˜ ํ‘œ๋ณธ(fork ๋งˆ๋‹ค seed ๋ณ€์ฃผ, ์›๋ณธ ๋ณด์กด).\n *\n * **์ด๊ฒƒ์ด ์š”์ฒญ ์ฒ˜๋ฆฌ ์ค‘ ๋ฉ”์ธ ์ด๋ฒคํŠธ ๋ฃจํ”„์—์„œ ๋™๊ธฐ๋กœ ์ˆ˜ํ–‰๋œ๋‹ค.** ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ fork 30๊ฐœ ร— 300ํ‹ฑ = 9,000ํ‹ฑ.\n * ๊ณ„๊ธฐํŒ์— ๋‚จ๊ฒจ ๋‘์ง€ ์•Š์œผ๋ฉด \"์™œ ์„œ๋ฒ„๊ฐ€ ๊ตณ์—ˆ๋‚˜\" ๋ฅผ ๋‚˜์ค‘์— ์งš์„ ์ˆ˜ ์—†๋‹ค(์‹ค์ œ๋กœ ํ•œ ๋ฒˆ ๊ฒช์—ˆ๋‹ค).\n */\n const tMc = performance.now()\n const mcBreath = breather()\n const distribution = await monteCarloForecastAsync(k, { runs: R, horizonMs: H, scenario: scen, tickMs: step, metric: m, yieldFn: mcBreath.fn })\n TwinEngine.recordLoad(domainId, instanceId, 'forecast', performance.now() - tMc - mcBreath.ms)\n TwinEngine.countForks(domainId, instanceId, R)\n\n /* ํ•™์Šต๋œ ๋ณด์ • ์ƒ์‹œ ์ ์šฉ(P3.2) โ€” twinLearnCalibration ์ด ์ €์žฅํ•œ ํŽธํ–ฅยท๋ฐด๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์˜ˆ์ธก์„ ํ˜„์‹ค๋กœ ๋ณด์ •(๋ผ์ด๋ธŒ๊ฐ€ ์‹ค์ œ๋กœ ๋‚˜์•„์ง).\n ๊ฐญํŠธ๋ Œ๋“œ(gapPoints)๋Š” raw ๋ชจ๋ธ์„ ๊ทธ๋Œ€๋กœ ์ธก์ •(ํ•™์Šต ์‹ ํ˜ธ ๋ณด์กด) โ€” ๋ณด์ •์€ ํ‘œ์‹œ์šฉ forecast ์—๋งŒ. */\n const stored = CALIBRATION.get(calKey(domainId, instanceId, metric ?? 'items', H))\n /*\n * **๋ฐฐ์šด ๋ชจ๋ธ์—๋งŒ ์ ์šฉํ•œ๋‹ค.** ๋ณด์ •์€ \"๊ทธ๋•Œ ๋ชจ๋ธ์ด ์ด๋งŒํผ ์น˜์šฐ์ณ ์žˆ๋‹ค\" ๋ฅผ ๋ฐฐ์šด ๊ฒƒ์ด๋‹ค. ์†Œ์š”์‹œ๊ฐ„\n * ์ถ”์ •๊ธฐ(์‹ค์ธกยท๊ฑฐ๋ฆฌ)๋‚˜ ๊ณต์ • ๋ช…์„ธ๊ฐ€ ๋ฐ”๋€Œ์–ด ๋ชจ๋ธ์ด ๋‹ฌ๋ผ์ง€๋ฉด ๊ทธ ํŽธํ–ฅ์€ ๋” ์ด์ƒ ์‚ฌ์‹ค์ด ์•„๋‹ˆ๊ณ , ๊ทธ๋Œ€๋กœ\n * ๋ฐ€์–ด ์ฃผ๋ฉด ์ด์ค‘ ๋ณด์ •์ด ๋œ๋‹ค. ๊ทธ๋ž˜์„œ ์ง€๋ฌธ์„ ๋น„๊ตํ•˜๊ณ , ๋‹ค๋ฅด๋ฉด ์ ์šฉํ•˜์ง€ ์•Š๋˜ **๊ทธ ์‚ฌ์‹ค์„ ์‘๋‹ต์—\n * ์‹ฃ๋Š”๋‹ค** โ€” ์˜ค๋ฅ˜ ์—†์ด ์‚ฌ๋ผ์ง€๋ฉด ์‚ฌ์šฉ์ž๋Š” ํ•™์Šต์ด ์™œ ์•ˆ ๋“ฃ๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค(๋‹ค์‹œ ๋ฐฐ์šฐ๋ฉด ๋œ๋‹ค).\n * ์ง€๋ฌธ์„ ์•Œ ์ˆ˜ ์—†์„ ๋•Œ๋Š” ๋น„๊ตํ•˜์ง€ ์•Š๋Š”๋‹ค(๋ชจ๋ฅด๋Š” ๊ฒƒ์„ ๊ทผ๊ฑฐ๋กœ ๋ณด์ •์„ ๋Š์ง€ ์•Š๋Š”๋‹ค).\n */\n const basis = await TwinEngine.modelBasis(domainId, instanceId)\n const stale = !!stored && modelBasisChanged(stored.basis, basis)\n if (stale) {\n twinLog(\n `[twin-forecast] \"${instanceId}\": calibration not applied โ€” model changed since it was learned.` +\n ` learned on: ${describeModelBasis(stored!.basis)} / now: ${describeModelBasis(basis)}`\n )\n }\n /*\n * ๋ถ„์œ„์ˆ˜ โ€” ํ‘œ๋ณธ์—์„œ ์ง์ ‘ ๋ฝ‘๋Š”๋‹ค.\n *\n * ์ปค๋„์ด ํ‘œ๋ณธ ๋ฐฐ์—ด์„ ๊ทธ๋Œ€๋กœ ๋Œ๋ ค์ฃผ๋ฏ€๋กœ(forecast.ts) ์—ฌ๊ธฐ์„œ ์ •๋ ฌํ•ด p05ยทp95 ๋ฅผ ๋‚ธ๋‹ค. ์ด๊ฒƒ์ด ์—†์œผ๋ฉด\n * ํ™”๋ฉด์ด ๋ณด์—ฌ ์ค„ ์ˆ˜ ์žˆ๋Š” ํญ์€ ๊ด€์ธก **์ตœ์†Œยท์ตœ๋Œ€** ๋ฟ์ธ๋ฐ, ๊ทธ๊ฑด ์‹ ๋ขฐ๊ตฌ๊ฐ„์ด ์•„๋‹ˆ๋ผ ๊ทน๋‹จ๊ฐ’ ๋‘ ๊ฐœ๋‹ค.\n * \"์šด์ด ๋‚˜์œ 5% ์—์„œ๋Š” ์ด๋งŒํผ\" ์ด๋ผ๊ณ  ๋งํ•˜๋ ค๋ฉด ๋ถ„์œ„์ˆ˜์—ฌ์•ผ ํ•œ๋‹ค. ํ‘œ๋ณธ์ด ์ ์œผ๋ฉด(runs ๊ฐ€ ์ž‘์œผ๋ฉด)\n * ๋ถ„์œ„์ˆ˜๋„ ๊ฑฐ์น ๋‹ค โ€” ๊ทธ๋ž˜์„œ ํ‘œ๋ณธ ์ˆ˜๋ฅผ ํ•จ๊ป˜ ์‹ฃ๋Š”๋‹ค(sampleCount). ์ˆซ์ž๋งŒ ์ฃผ๊ณ  ๊ทผ๊ฑฐ๋ฅผ ๊ฐ์ถ”์ง€ ์•Š๋Š”๋‹ค.\n */\n if (distribution) {\n const samples: number[] = Array.isArray(distribution.samples) ? distribution.samples : []\n if (samples.length) {\n const sorted = [...samples].sort((a, b) => a - b)\n const pct = (p: number) => sorted[Math.min(sorted.length - 1, Math.floor(p * sorted.length))]\n distribution.p05 = pct(0.05)\n distribution.p95 = pct(0.95)\n }\n distribution.sampleCount = samples.length\n }\n\n const cal = stored && !stale ? stored : undefined\n if (cal && distribution) {\n /*\n * `p50` ์€ ์ปค๋„ ๊ณ„์•ฝ์ƒ ํ•ญ์ƒ ์žˆ๋‹ค(`MonteCarloResult.p50: number`). ๊ทธ๋ž˜๋„ ๋ฉ”์šฐ์ง€ ์•Š๋Š”๋‹ค โ€”\n * ์˜ˆ์ „์—๋Š” `?? 0` ์ด์—ˆ๋Š”๋ฐ, ๋งŒ์•ฝ ๋น„๋ฉด ๋ณด์ •๋œ p50 ์ด **ํŽธํ–ฅ๊ฐ’ ๊ทธ ์ž์ฒด**๊ฐ€ ๋˜๊ณ  minยทmax ๋Š”\n * ๊ทธ ๋‘˜๋ ˆ๋กœ ๊ทธ๋ ค์ง„๋‹ค. ์˜ˆ์ธก์ด ์•„๋‹Œ ์ˆซ์ž๊ฐ€ ์˜ˆ์ธก์˜ ์ž๋ฆฌ์— ์•‰๋Š”๋ฐ ์•„๋ฌด ์‹ ํ˜ธ๊ฐ€ ์—†๋‹ค.\n */\n if (typeof distribution.p50 !== 'number') throw new Error('forecast distribution has no p50 โ€” kernel contract broken')\n const p50c = distribution.p50 + cal.biasShift\n distribution.p50 = Math.round(p50c)\n distribution.min = Math.round(p50c - cal.halfWidth)\n distribution.max = Math.round(p50c + cal.halfWidth)\n /*\n * ๋ถ„์œ„์ˆ˜๋Š” **์˜ฎ๊ธฐ๊ธฐ๋งŒ** ํ•œ๋‹ค. ๋ณด์ •์ด ๋ฐฐ์šด ๊ฒƒ์€ \"๋ชจ๋ธ์ด ์ด๋งŒํผ ์น˜์šฐ์ณ ์žˆ๋‹ค\"(์œ„์น˜)์ด์ง€ ๋ถ„ํฌ์˜\n * ๋ชจ์–‘์ด ์•„๋‹ˆ๋‹ค. p50 ์ฒ˜๋Ÿผ ๋ฐ€์–ด ๋‘์–ด์•ผ p05~p95 ํญ์ด ํ‘œ๋ณธ์ด ๋งํ•œ ๊ทธ๋Œ€๋กœ ๋‚จ๋Š”๋‹ค.\n * (minยทmax ๋Š” ์œ„์—์„œ ํ•™์Šต ๋ฐด๋“œ๋กœ ๋Œ€์ฒด๋œ๋‹ค โ€” ๋ณด์ •์ด ๊ฑธ๋ฆฌ๋ฉด ๊ทธ ๋‘˜์˜ ๋œป์ด '๊ด€์ธก ๊ทน๋‹จ' ์—์„œ\n * 'ํ•™์Šต ๋ฐด๋“œ' ๋กœ ๋ฐ”๋€๋‹ค๋Š” ๋œป์ด๋‹ค. ํ™”๋ฉด์ด ๋‘˜์„ ๊ฐ™์€ ๊ฒƒ์œผ๋กœ ๊ทธ๋ฆฌ๋ฉด ์•ˆ ๋œ๋‹ค.)\n */\n if (distribution.p05 !== undefined) distribution.p05 = Math.round(distribution.p05 + cal.biasShift)\n if (distribution.p95 !== undefined) distribution.p95 = Math.round(distribution.p95 + cal.biasShift)\n if (distribution.p90 !== undefined) distribution.p90 = Math.round(distribution.p90 + cal.biasShift)\n distribution.calibrated = true\n }\n\n /*\n * ์˜ˆ์ธก ๊ถค์ (์˜ˆ์ธก์„ ): ๋‹จ์ผ fork ๋ฅผ horizon ๊นŒ์ง€ ์‹คํ–‰ํ•˜๋ฉฐ ์ง€ํ‘œ ๊ธฐ๋ก. ์ด๊ฒƒ๋„ ์žฐ๋‹ค.\n *\n * ์—ฌ๊ธฐ๋„ ์ž๋ฆฌ๋ฅผ ๋‚ด์ค€๋‹ค โ€” ์‹ค์ธก์œผ๋กœ ์ด ํ•œ ํšŒ์ฐจ๊ฐ€ 1.3์ดˆ์˜€๋‹ค(300ํ‹ฑ + ์Šค๋ƒ…์ƒท 300๋ฒˆ). ๋ถ„ํฌ๋งŒํผ์€\n * ์•„๋‹ˆ์ง€๋งŒ, ๋ผ์ด๋ธŒ ํ‹ฑ ๊ฐ„๊ฒฉ(1์ดˆ)๋ณด๋‹ค ๊ธธ๊ฒŒ ๋ถ™์žก์œผ๋ฉด ๊ทธ ์‚ฌ์ด ํŠธ์œˆ๋“ค์ด ํ•œ ๋ฐ•์ž์”ฉ ๋ฐ€๋ฆฐ๋‹ค.\n */\n const tTraj = performance.now()\n const trajBreath = breather()\n const fc = k.fork()\n fc.scenario.load({ ...scen, seed: 1 })\n fc.scenario.start()\n const trajectory: { t: number; value: number }[] = []\n for (let t = 0; t < H; t += step) {\n fc.tick(step)\n trajectory.push({ t: t + step, value: m(fc.getSnapshot()) })\n /* ํ‹ฑ๋งˆ๋‹ค ๋‚ด์ฃผ๋ฉด ์–‘๋ณด ์ž์ฒด๊ฐ€ ๋น„์šฉ์ด ๋œ๋‹ค โ€” ๋ผ์ด๋ธŒ ํ‹ฑ ๊ฐ„๊ฒฉ๋ณด๋‹ค ํ›จ์”ฌ ์งง์€ ๋‹จ์œ„๋กœ ๋Š๋Š”๋‹ค. */\n if (trajectory.length % 25 === 0) await trajBreath.fn()\n }\n\n TwinEngine.recordLoad(domainId, instanceId, 'forkTick', performance.now() - tTraj - trajBreath.ms)\n TwinEngine.countForks(domainId, instanceId, 1)\n\n const current = m(k.getSnapshot()) // vantage T ์˜ ์‹ค์ œ๊ฐ’(= naive '๊ทธ๋Œ€๋กœ ์œ ์ง€' ์˜ˆ์ธก์˜ ๊ธฐ์ค€)\n\n /* ์‹ค์ธก ์˜ค๋ฒ„๋ ˆ์ด + ์ฑ„์ (P1) โ€” vantage ๊ฐ€ ๊ณผ๊ฑฐ(at)์ผ ๋•Œ๋งŒ: T ์ดํ›„ ์‹ค์ œ๋กœ ์ผ์–ด๋‚œ metric ์„ Tโ†’min(now,T+H) ๋กœ ์ƒ˜ํ”Œ.\n ํ˜„์žฌ ์ดํ›„๋Š” ์‹ค์ธก์ด ์—†์Œ(๋ฏธ๋ž˜). recover(T+t) ๋กœ ๊ฐ ์ƒ˜ํ”Œ ์ƒํƒœ ์žฌ๊ตฌ์„ฑํ•ด metric ์ถ”์ถœ. ๋น„์šฉ=์ƒ˜ํ”Œ ์ˆ˜ ๋งŒํผ replay. */\n const actual: { t: number; value: number }[] = []\n let scored: any = null\n if (at) {\n const T = Date.parse(at)\n const endMs = Math.min(Date.now(), T + H)\n const span = endMs - T\n if (Number.isFinite(T) && span > 0) {\n const SAMPLES = 8\n const dt = span / SAMPLES\n for (let i = 1; i <= SAMPLES; i++) {\n const st = await TwinEngine.recover(domainId, instanceId, undefined, new Date(T + i * dt).toISOString()).catch(() => null)\n if (st) actual.push({ t: i * dt, value: m(st) })\n }\n /* ์ง€ํ‰์„ ์ด ์ง€๋‚ฌ์œผ๋ฉด(T+H โ‰ค now) ๊ทธ ์ง€์  ์‹ค์ธก vs ์˜ˆ์ธก ์ฑ„์ (๋‹จ์ผ vantage). p50 ๋Œ€๋น„ ์˜ค์ฐจยท๋ฐด๋“œ ์ ์ค‘ยทFVA(naive=ํ˜„์žฌ๊ฐ’ ์œ ์ง€ ๋Œ€๋น„). */\n if (T + H <= Date.now() && actual.length) {\n const a = actual[actual.length - 1].value\n const p50 = distribution?.p50 ?? current\n scored = {\n actual: a,\n p50,\n error: a - p50, // ๋ถ€ํ˜ธ = ํŽธํ–ฅ ๋ฐฉํ–ฅ(+ ์‹ค์ œ๊ฐ€ ๋” ๋งŽ์Œ)\n inBand: a >= (distribution?.min ?? -Infinity) && a <= (distribution?.max ?? Infinity),\n modelAbsError: Math.abs(a - p50),\n naiveAbsError: Math.abs(a - current) // naive = \"๊ทธ๋Œ€๋กœ ์œ ์ง€\"(ํ˜„์žฌ๊ฐ’). FVA = naive - model\n }\n }\n }\n }\n\n /*\n * ์‹œ๋ฎฌ ๋ช…์„ธ ์ž๊ธฐ๋ณด๊ณ ๋ฅผ ํ•จ๊ป˜ ๋‚ธ๋‹ค โ€” **์ƒ์ˆ˜๋กœ ๊ณ„์‚ฐํ•œ ์˜ˆ์ธก๊ณผ ํ˜„์žฅ ๋ช…์„ธ๋กœ ๊ณ„์‚ฐํ•œ ์˜ˆ์ธก์ด ํ™”๋ฉด์—์„œ ๊ฐ™์•„\n * ๋ณด์ด์ง€ ์•Š๊ฒŒ.** ์ฝ”๋“œยท์ˆ˜์น˜๋งŒ ์‹ฃ๊ณ  ์‚ฌ๋žŒ์ด ์ฝ๋Š” ๋ฌธ์žฅ์€ ํด๋ผ๊ฐ€ ๋งŒ๋“ ๋‹ค(์–ธ์–ด ์ค‘๋ฆฝ).\n * ์ปค๋„์ด ์ด API ๋ฅผ ๊ฐ–์ง€ ์•Š์€ ๋ฒ„์ „์ด๋ฉด ํ‚ค๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค(๋ชจ๋ฅด๋Š” ๊ฒƒ์„ \"์ „๋ถ€ ๊ธฐ๋ณธ๊ฐ’\" ์ด๋ผ ๋‹จ์ • ๊ธˆ์ง€).\n */\n /* ๋ณด๊ณ ๋Š” **์‹ค์ œ๋กœ ์‹คํ–‰ํ•œ fork** ์—์„œ ์ฝ๋Š”๋‹ค โ€” ๋ถ€๋ชจ ์ปค๋„(k)์€ tick ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ(์˜ˆ์ธก์€ fork ์—์„œ\n * ์ˆ˜ํ–‰๋œ๋‹ค) ๋ถ€๋ชจ์—์„œ ์ฝ์œผ๋ฉด ์”จ์•—์œผ๋กœ ์„ธ์šด ์˜ˆ์ธก์—์„œ๋Š” ๋Š˜ ๋น„์–ด ์žˆ๋‹ค. ์ˆซ์ž๋ฅผ ๋‚ธ ์ฃผ์ฒด๊ฐ€ ๋ณด๊ณ ํ•ด์•ผ ํ•œ๋‹ค. */\n const specCoverage = readSpecCoverage(fc) ?? readSpecCoverage(k)\n return {\n metric: metric ?? 'items', horizonMs: H, runs: R, current, distribution, trajectory, actual, scored,\n /* ์–ผ๋งˆ๋‚˜ ์ž˜๊ฒŒ ๊ตด๋ ธ๋‚˜ โ€” ์ˆซ์ž๋งŒ ์ฃผ๊ณ  ๊ทผ๊ฑฐ๋ฅผ ๊ฐ์ถ”์ง€ ์•Š๋Š”๋‹ค(๊ฐ™์€ ๊ทœ์œจ๋กœ `specCoverage` ๋„ ์‹ฃ๋Š”๋‹ค). */\n tickMs: step,\n /*\n * **๊ฐ€์ •์ด ์–ด๋–ป๊ฒŒ ๋๋‚˜** โ€” ๊ฑธ๋ฆฐ ๊ฐœ์ž…ยท๊ฑฐ์ ˆ๋œ ๊ฐœ์ž…ยท๋ฎ์–ด์“ด ์„ ์–ธ.\n *\n * ์ด๊ฒƒ์„ ๊ฐ์ถ”๋ฉด ๋‘ ๊ฐ€์ง€๊ฐ€ ๋“ค์–ด์˜จ ๊ฒƒ์ด ์—†์–ด์ง„๋‹ค: ๊ฑธ๋ฆฌ์ง€ ์•Š์€ ๊ฐ€์ •(ใ€Œ๊ฑธ์—ˆ๋Š”๋ฐ ์™œ ์•ˆ ๋ฐ”๋€Œ๋‚˜ใ€)๊ณผ, ๋ฎ์–ด์“ด\n * ์„ ์–ธ(์‚ฌ์šฉ์ž๊ฐ€ what-if ๊ฒฐ๊ณผ๋ฅผ ํŠธ์œˆ์˜ ํ˜„์žฌ ์ƒํƒœ๋กœ ์ฝ๋Š”๋‹ค). ์‹ค์ œ๋กœ ์‹คํ–‰ํ•œ fork(`fc`)์—์„œ ์ฝ๋Š”๋‹ค โ€”\n * ๊ฐ€์ •์„ ๊ฒช์€ ๊ฒƒ์€ ๊ทธ์ชฝ์ด๋‹ค.\n */\n ...(typeof (fc as any).interventionOutcomes === 'function'\n ? (() => {\n const outcomes = (fc as any).interventionOutcomes()\n return outcomes.length ? { interventions: outcomes } : {}\n })()\n : {}),\n ...(typeof (fc as any).declarationOverrides === 'function'\n ? (() => {\n const overrides = (fc as any).declarationOverrides()\n return overrides.length ? { overrides } : {}\n })()\n : {}),\n calibrated: !!cal,\n /* ํ•™์Šตํ•ด ๋’€์ง€๋งŒ ๋ชจ๋ธ์ด ๋ฐ”๋€Œ์–ด ์ ์šฉํ•˜์ง€ ์•Š์•˜๋‹ค โ€” ์‚ฌ์šฉ์ž๊ฐ€ ๋‹ค์‹œ ๋ฐฐ์šธ ์ˆ˜ ์žˆ๊ฒŒ ์•Œ๋ฆฐ๋‹ค. */\n ...(stale ? { calibrationStale: true } : {}),\n ...(specCoverage ? { specCoverage } : {}),\n /*\n * **๊ณ„๋ณด์— ๊ตฌ๋ฉ์ด ๋ช‡ ์นธ ์ƒ๊ฒผ๋‚˜** โ€” ๊ฐœ์ฒด๋ฅผ ์ž‡์ง€ ๋ชปํ•œ ์ฑ„ ๋„˜์–ด๊ฐ„ ๊ณต์ • ์ˆ˜.\n *\n * โ”€โ”€ ์™œ ์ด ๊ฐ’์„ ์˜ˆ์ธก ์‘๋‹ต์— ์‹ฃ๋‚˜ (2026-08-24) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๋ฏธ๋Ÿฌ์˜ ์˜ค๋”๋Š” ํ™•๋ณด๋ถ„์„ ๊ฐ–์ง€ ์•Š๋Š”๋‹ค(์›๋ณธ์ด ใ€Œ์–ด๋А ๊ฐœ์ฒด๊ฐ€ ์žกํ˜€ ์žˆ๋‚˜ใ€๋ฅผ ๋งํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ๊ทธ\n * ์‹œ์Šคํ…œ์˜ ์ •์ƒ์ด๋‹ค). ์ปค๋„์€ ๊ทธ ์ž๋ฆฌ์—์„œ **๋˜์ง€์ง€ ์•Š๊ณ  ๋„˜๊ธด๋‹ค** โ€” ๋‹จ๊ณ„๋ฅผ ๋„˜๋Š” ๊ฒƒ์€ ๊ณต์ •์˜\n * ์ง„ํ–‰์ด๊ณ  ๊ฐœ์ฒด ๋ฒˆํ˜ธ๊ฐ€ ํ•„์š” ์—†๋‹ค. ๋Œ€์‹  ๋„˜๊ธด ํšŸ์ˆ˜๋ฅผ ์„ผ๋‹ค.\n *\n * ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ์นด์šดํ„ฐ๋Š” **fork ์•ˆ์—** ์žˆ๊ณ  fork ๋Š” ๋ฒ„๋ ค์ง„๋‹ค. ์—ฌ๊ธฐ์„œ ์‹ฃ์ง€ ์•Š์œผ๋ฉด ์•„๋ฌด์—๊ฒŒ๋„ ๋‹ฟ์ง€\n * ์•Š๋Š”๋‹ค โ€” ๋ฆฌ๋“€์„œ๊ฐ€ ์˜ค๋ž˜ ์„ธ์–ด ์˜จ ๊ฐ’์„ ์Šค๋ƒ…์ƒท์ด ๋–จ์–ด๋œจ๋ ค ๊ทธ๊ฒƒ์„ ์ฝ๋„๋ก ์“ฐ์ธ ๊ฒ€์‚ฌ๊ฐ€ ์˜์›ํžˆ\n * ์•„๋ฌด ์‹ ํ˜ธ๋„ ๋‚ด์ง€ ์•Š์•˜๋˜ ๊ฒƒ๊ณผ **๊ฐ™์€ ์‹ค์ˆ˜**๋‹ค. ์„ธ์–ด ๋†“๊ณ  ๋‚ด๋ณด๋‚ด์ง€ ์•Š์œผ๋ฉด ์•ˆ ์„ผ ๊ฒƒ๊ณผ ๊ฐ™๋‹ค.\n *\n * ์™œ ํ™”๋ฉด์ด ์ด๊ฒƒ์„ ์•Œ์•„์•ผ ํ•˜๋‚˜: ๊ณ„๋ณด๋Š” **ํšŒ์ˆ˜ ๋ฒ”์œ„**๋ฅผ ์ •ํ•˜๋Š” ์‚ฌ์Šฌ์ด๋‹ค. ๊ตฌ๋ฉ์ด ์žˆ๋Š”๋ฐ ์˜จ์ „ํ•œ\n * ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋ฉด ํšŒ์ˆ˜๊ฐ€ ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ์ข์•„์ง„๋‹ค. ์‹ํ’ˆ์—์„œ ๊ทธ๊ฒƒ์€ ๋˜๋Œ๋ฆด ์ˆ˜ ์—†๋‹ค.\n *\n * ๋‘ ๊ณณ์—์„œ ์ฝ์–ด **ํฐ ๊ฐ’**์„ ๋‚ธ๋‹ค โ€” ๋ถ„ํฌ(ํšŒ์ฐจ R๊ฐœ์˜ ์ตœ๋Œ€)์™€ ๊ถค์  fork ๋Š” **๋‘˜ ๋‹ค ์‹ค์ œ๋กœ ์‹คํ–‰๋๋‹ค**.\n * ํ•œ์ชฝ๋งŒ ๋ณด๋ฉด ๋‹ค๋ฅธ ์ชฝ์ด ๊ฒช์€ ๊ตฌ๋ฉ์„ ์žƒ๋Š”๋‹ค.\n */\n ...(() => {\n const gaps = Math.max(\n (distribution as any)?.stepsWithoutMaterial ?? 0,\n (fc as any)?.getSnapshot?.()?.stepsWithoutMaterial ?? 0\n )\n /* 0 ์€ ์‹ฃ์ง€ ์•Š๋Š”๋‹ค โ€” ใ€Œ๊ตฌ๋ฉ์ด ์—†๋‹คใ€์™€ ใ€Œ์ด ์ถ•์„ ๋ชจ๋ฅธ๋‹คใ€๋ฅผ ํ™”๋ฉด์ด ๊ตฌ๋ณ„ํ•  ์ˆ˜ ์žˆ๊ฒŒ. */\n return gaps > 0 ? { stepsWithoutMaterial: gaps } : {}\n })()\n }\n }\n\n /*\n * ๊ฐญ ํŠธ๋ Œ๋“œ(P2) โ€” N๊ฐœ ๊ณผ๊ฑฐ vantage ๊ฐ๊ฐ์—์„œ \"๊ทธ๋•Œ ์˜ˆ์ธก vs ๊ทธ ์ง€ํ‰์„ ์˜ ์‹ค์ œ\"๋ฅผ ์žฌ๊ณ„์‚ฐ(๊ฒฐ์ •์  ๋ฐฑํ…Œ์ŠคํŠธ).\n * ์ง€ํ‰์„ ์ด ์ด๋ฏธ ์ง€๋‚œ vantage ๋งŒ([t0, tLastโˆ’H]) โ†’ actual ํ™•์ •. ์˜จ๋””๋งจ๋“œ ์žฌ๊ณ„์‚ฐ(๋ˆ„์ /์˜์†์€ ๊ธด ๊ธฐ๊ฐ„์šฉ ํ›„์† ์ตœ์ ํ™”).\n * ๋น„์šฉ = N ร— (buildForecastKernelAt replay + monteCarlo + recover replay). Nยทruns ๋ฅผ ๋‚ฎ๊ฒŒ bound. per-instance(ํด๋ผ๊ฐ€ co-located ํ•ฉ์‚ฐ).\n */\n @Query(returns => ScalarObject, {\n nullable: true,\n description:\n 'Forecast-accuracy gap diagnosis (canonical, server-computed): for N past vantages recompute forecast-at-T vs actual-at-T+h (deterministic backtest), aggregate co-located instances, and return points + SPC verdict (stability/bias) + metrics (accuracy/coverage/FVA) + learned-calibration projection. Client only renders.'\n })\n async twinForecastGapTrend(\n @Arg('instanceId') instanceId: string,\n @Arg('metric', { nullable: true }) metric: string,\n @Arg('horizonMs', type => Int, { nullable: true }) horizonMs: number,\n @Arg('samples', type => Int, { nullable: true }) samples: number,\n @Arg('scenario', type => ScalarObject, { nullable: true }) scenario: any,\n @Ctx() context: ResolverContext,\n @Arg('instanceIds', type => [String], { nullable: true }) instanceIds?: string[]\n ): Promise<any> {\n const domainId = context.state.domain.id\n const m = metricFn(metric)\n const H = horizonMs ?? 300000\n if (!m) return { metric, unsupportedMetric: true, horizonMs: H, samples: 0, points: [], spc: computeSpc([]), metrics: null, learn: null }\n const N = Math.min(30, Math.max(2, samples ?? GAP_SAMPLES)) // ํ‘œ๋ณธ์€ ์„œ๋ฒ„๊ฐ€ ๊ด€์žฅ(SPC ์‹ ๋ขฐ ํ•˜ํ•œ ~20).\n const scen = scenario ?? DEFAULT_SCENARIO\n // ๊ณต๋™๋ฐฐ์น˜(co-located) ์ง‘๊ณ„๋„ ์„œ๋ฒ„์—์„œ โ€” ๊ณต์žฅ ๋‹จ์œ„ ์ง„๋‹จ์ด canonical. ๋ฏธ์ง€์ • ์‹œ ๋‹จ๊ฑด.\n const ids = instanceIds?.length ? instanceIds : [instanceId]\n\n /*\n * ๊ฒฉ์ž๋ฅผ **๋จผ์ € ํ•˜๋‚˜** ๋งŒ๋“ ๋‹ค. ํŠธ์œˆ๋งˆ๋‹ค ์ž๊ธฐ ์ €๋„๋กœ ๊ฒฉ์ž๋ฅผ ๋งŒ๋“ค๋ฉด ๊ฐ™์€ ์ธ๋ฑ์Šค๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ\n * ์‹œ๊ฐ์ด ๋˜์–ด, ํ•ฉ์‚ฐ์ด ๋‹ค๋ฅธ ์‹œ์ ์˜ ๊ฐ’์„ ๋”ํ•œ๋‹ค(`aggregatePoints` ์ฃผ์„ ์ฐธ์กฐ).\n *\n * ์ €๋„์ด ์—†๊ฑฐ๋‚˜ ์ง€ํ‰ H ๋ฅผ ๋‹ด์„ ๋งŒํผ ๊ธธ์ง€ ์•Š์€ ํŠธ์œˆ์€ **๋ฐฑํ…Œ์ŠคํŠธ์— ์ฐธ์—ฌํ•  ์ˆ˜ ์—†๋‹ค.** ๊ทธ๋Ÿฐ ํŠธ์œˆ์€\n * ๋นผ๋˜ ๋ˆ„๊ตฌ๋ฅผ ๋บ๋Š”์ง€ ๋Œ๋ ค์ค€๋‹ค โ€” ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ๋นผ๋ฉด ํ™”๋ฉด์€ ๊ทธ ํŠธ์œˆ๊นŒ์ง€ ํฌํ•จํ•œ ๊ณต์žฅ ์ด๋Ÿ‰์œผ๋กœ ์ฝ๋Š”๋‹ค.\n */\n const windows = await Promise.all(ids.map(async id => ({ id, w: await gapWindow(domainId, id, H) })))\n const usable = windows.filter(x => x.w)\n const excluded = windows.filter(x => !x.w).map(x => x.id)\n const grid = sharedGrid(usable.map(x => x.w!), N)\n if (!grid) {\n /* ๊ฒน์น˜๋Š” ๊ตฌ๊ฐ„์ด ์—†๋‹ค โ€” ์žด ์ˆ˜ ์—†๋Š” ๊ฒƒ์ด์ง€ ์ •ํ™•๋„๊ฐ€ 0 ์ธ ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค. */\n return { metric: metric ?? 'items', horizonMs: H, samples: N, points: [], spc: computeSpc([]), metrics: null, learn: null,\n coverage: { instances: ids.length, measured: 0, excluded, vantages: N, used: 0, dropped: 0, reason: 'no-common-window' } }\n }\n\n const per = await Promise.all(usable.map(x => gapPoints(domainId, x.id, m, H, grid, scen)))\n const { points, droppedVantages } = aggregatePoints(per as (GapPoint | null)[][])\n const metrics = points.length ? gapMetrics(points) : null\n const spc = computeSpc(points.map(p => p.error))\n const learn = metrics ? learnedCalibration(points, metrics) : null\n return { metric: metric ?? 'items', horizonMs: H, samples: N, points, spc, metrics, learn,\n /* ์ด ์ˆซ์ž๊ฐ€ **๋ฌด์—‡์œผ๋กœ ๊ณ„์‚ฐ๋๋Š”์ง€**. 24์  ์ค‘ 18์ ์ด๋ฉด ํ™”๋ฉด์ด ๊ทธ๋ ‡๊ฒŒ ๋งํ•ด์•ผ ํ•œ๋‹ค. */\n coverage: { instances: ids.length, measured: usable.length, excluded, vantages: N, used: points.length, dropped: droppedVantages } }\n }\n\n /*\n * ํ•™์Šต(P3.2) โ€” ๊ฐญ์—์„œ ํŽธํ–ฅยท๋ฐด๋“œ๋ฅผ ํ•™์Šตํ•ด ์ €์žฅํ•˜๋ฉด, ์ดํ›„ twinForecast ๊ฐ€ ์ƒ์‹œ ์ ์šฉ(๋ผ์ด๋ธŒ ์˜ˆ์ธก์ด ์‹ค์ œ๋กœ ๋ณด์ •๋จ).\n * assimilation-lite: ์ž”์ฐจ(innovation)๋ฅผ ๋˜๋จน์—ฌ ์ถ”์ •์น˜๋ฅผ ํ˜„์‹ค๋กœ. per-instance(ํด๋ผ๊ฐ€ co-located ํ•ฉ์‚ฐ).\n * ๋ฐ˜ํ™˜: ํ•™์Šต๋œ ๋ณด์ • + before/after ์ •ํ™•๋„(ํšจ๊ณผ ์ •๋Ÿ‰ํ™”). ์ €์žฅ์€ ์ธ๋ฉ”๋ชจ๋ฆฌ(์„ธ์…˜) โ€” DB ์˜์†์€ ํ›„์†.\n */\n @Directive('@privilege(category: \"twin\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => ScalarObject, { description: 'Learn a forecast calibration (bias + band) from the gap trend and persist it so future forecasts apply it. Returns the calibration + before/after accuracy.' })\n async twinLearnCalibration(\n @Arg('instanceId') instanceId: string,\n @Arg('metric', { nullable: true }) metric: string,\n @Arg('horizonMs', type => Int, { nullable: true }) horizonMs: number,\n @Ctx() context: ResolverContext,\n @Arg('clear', type => Boolean, { nullable: true }) clear?: boolean\n ): Promise<any> {\n const domainId = context.state.domain.id\n if (!TwinEngine.owns(domainId, instanceId)) return { ok: false } // ํ…Œ๋„ŒํŠธ ๊ฒฉ๋ฆฌ\n const m = metricFn(metric)\n if (!m) return { ok: false, reason: 'unsupported-metric', metric }\n const H = horizonMs ?? 300000\n // ๋ณด์ • ํ•ด์ œ โ€” ์ €์žฅ๋œ calibration ์ œ๊ฑฐ(์ดํ›„ ์˜ˆ์ธก์€ raw ๋กœ ๋ณต๊ท€). ํ•™์Šต์„ ๋˜๋Œ๋ฆฌ๋Š” ์ •์งํ•œ off ์Šค์œ„์น˜.\n if (clear) {\n CALIBRATION.delete(calKey(domainId, instanceId, metric ?? 'items', H))\n return { ok: true, cleared: true, metric: metric ?? 'items', horizonMs: H }\n }\n // ํ‘œ๋ณธยท๊ณ„์‚ฐ์„ gap-analytics ๋กœ ์ผ์›ํ™”(gapTrend ์ง„๋‹จ๊ณผ ๋™์ผ Nยท๋™์ผ ์ˆ˜์‹ โ†’ ์นด๋“œ ์˜ˆ์ƒ์น˜์™€ ์‹ค์ œ ๋ณด์ • ์ผ์น˜).\n /* ํ•™์Šต์€ ๋‹จ๊ฑด์ด๋ผ ๊ฒฉ์ž๋„ ์ด ํŠธ์œˆ์˜ ๊ตฌ๊ฐ„ ํ•˜๋‚˜๋‹ค. ์ €๋„์ด ์ง€ํ‰ H ๋ฅผ ๋‹ด์„ ๋งŒํผ ๊ธธ์ง€ ์•Š์œผ๋ฉด ๋ฐฐ์šธ ๊ฒƒ์ด ์—†๋‹ค. */\n const w = await gapWindow(domainId, instanceId, H)\n const grid = w ? sharedGrid([w], GAP_SAMPLES) : null\n if (!grid) return { ok: false, reason: 'insufficient-history' }\n /* ๋ชป ์žฐ vantage ๋Š” `null` ๋กœ ์˜จ๋‹ค โ€” 0 ์œผ๋กœ ์„ธ๋ฉด ํŽธํ–ฅ ํ•™์Šต์ด ๊ทธ๋งŒํผ ๋Œ๋ ค๊ฐ„๋‹ค. */\n const pts = (await gapPoints(domainId, instanceId, m, H, grid, DEFAULT_SCENARIO)).filter(Boolean) as GapPoint[]\n if (pts.length < 3) return { ok: false, reason: 'insufficient-history' }\n const learn = learnedCalibration(pts, gapMetrics(pts))\n /* ํ•™์Šตํ•œ ๋ชจ๋ธ์˜ ์ง€๋ฌธ์„ ํ•จ๊ป˜ ๋‚จ๊ธด๋‹ค โ€” ์ดํ›„ ๋ชจ๋ธ์ด ๋ฐ”๋€Œ๋ฉด ์ด ๋ณด์ •์€ ์ ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค. */\n const basis = await TwinEngine.modelBasis(domainId, instanceId)\n const cal = {\n biasShift: learn.biasShift,\n halfWidth: learn.halfWidth,\n at: '',\n samples: pts.length,\n accBefore: learn.accBefore,\n accAfter: learn.accAfter,\n ...(basis ? { basis } : {})\n }\n CALIBRATION.set(calKey(domainId, instanceId, metric ?? 'items', H), cal)\n return { ok: true, metric: metric ?? 'items', horizonMs: H, biasShift: cal.biasShift, halfWidth: cal.halfWidth, samples: pts.length, accBefore: cal.accBefore, accAfter: cal.accAfter }\n }\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/twin-ingest-window/index.ts"],"names":[],"mappings":";;;AAAA,mEAA0D;AAC1D,+EAAqE;AAExD,QAAA,QAAQ,GAAG,CAAC,wCAAgB,CAAC,CAAA;AAC7B,QAAA,SAAS,GAAG,CAAC,mDAAqB,CAAC,CAAA;AAEhD,+EAA0E;AAAjE,yIAAA,yBAAyB,OAAA","sourcesContent":["import { TwinIngestWindow } from './twin-ingest-window.js'\nimport { TwinIngestWindowQuery } from './twin-ingest-window-query.js'\n\nexport const entities = [TwinIngestWindow]\nexport const resolvers = [TwinIngestWindowQuery]\n\nexport { installIngestWindowWriter } from './twin-ingest-window-writer.js'\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"twin-ingest-window-query.js","sourceRoot":"","sources":["../../../server/service/twin-ingest-window/twin-ingest-window-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Int, Query, Resolver } from 'type-graphql'\nimport { Between } from 'typeorm'\n\nimport { ScalarObject, getRepository } from '@things-factory/shell'\n\nimport { TwinEngine } from '../../engine/index.js'\nimport { TwinIngestWindow } from './twin-ingest-window.js'\n\n/*\n * ์ธ์ œ์ŠคํŠธ ์ฐฝ **์ด๋ ฅ** โ€” ์žฌ๊ธฐ๋™ ๋’ค์—๋„ ์ถ”์ด๋ฅผ ์ด์–ด ๋ณธ๋‹ค.\n *\n * โ”€โ”€ ์™œ ๋”ฐ๋กœ ์žˆ๋‚˜ (2026-08-20) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ฐฝ์„ ํ‘œ๋กœ ๋‚จ๊ธฐ๊ธฐ ์‹œ์ž‘ํ–ˆ๋Š”๋ฐ **์ฝ๋Š” ์ฝ”๋“œ๊ฐ€ ์—†์—ˆ๋‹ค.** 21ํ–‰์ด ์Œ“์—ฌ ์žˆ๊ณ  ์•„๋ฌด๋„ ๋ณด์ง€ ์•Š์•˜๋‹ค โ€” ์ด\n * ํ”„๋กœ์ ํŠธ๊ฐ€ ๊ฒฐํ•จ์œผ๋กœ ๋ณด๋Š” ์ƒํƒœ๋‹ค(ใ€Œํ•„๋“œ๋งŒ ๋งŒ๋“ค๊ณ  ์•„๋ฌด๋„ ์ฝ์ง€ ์•Š๋Š”๋‹คใ€). ํ‘œ๋ฅผ ๋งŒ๋“  ์ด์œ ๊ฐ€ ใ€Œ๋ฉ”๋ชจ๋ฆฌ\n * ์žฅ๋ถ€๋Š” ์žฌ๊ธฐ๋™์— ์‚ฌ๋ผ์ง€๊ณ  6์‹œ๊ฐ„๊นŒ์ง€์ธ๋ฐ ์ถ”์ด๋Š” ๊ทธ๋ณด๋‹ค ์˜ค๋ž˜ ๋ด์•ผ ํ•œ๋‹คใ€์˜€์œผ๋‹ˆ, ๋ชฉ์ ์ด ๋ฏธ์™„์ด์—ˆ๋‹ค.\n *\n * โ”€โ”€ ์™œ `twinIngestHealth` ์— ํ•ฉ์น˜์ง€ ์•Š๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๊ทธ ์กฐํšŒ๋Š” **ํ™”๋ฉด์ด ์ž์ฃผ ๋ฌป๋Š”๋‹ค**(์ƒ์„ธ๋ฅผ ์—ด ๋•Œ๋งˆ๋‹ค, ๋ชฉ๋ก์€ ์‘๋‹ต์— ์š”์•ฝ์ด ํ•จ๊ป˜ ์˜จ๋‹ค). ๊ฑฐ๊ธฐ์— DB ์ฃผ์‚ฌ๋ฅผ\n * ์–น์œผ๋ฉด ์ด ์„ธ์…˜์—์„œ ์—†์•ค ๊ฒƒ๊ณผ ๊ฐ™์€ ์ข…๋ฅ˜์˜ ๋น„์šฉ์ด ๋Œ์•„์˜จ๋‹ค โ€” ์ž์ฃผ ๋ฌป๋Š” ์กฐํšŒ๊ฐ€ ์ž๋ผ๋Š” ํ‘œ๋ฅผ ์ฝ๋Š” ๊ฒƒ.\n * ์ด๋ ฅ์€ **๋‹ค๋ฅธ ์งˆ๋ฌธ**์ด๊ณ  ๋œ ์ž์ฃผ ๋ฌป๋Š”๋‹ค: ใ€Œ๋” ๋’ค๊นŒ์ง€ ๋ณด์—ฌ ๋‹ฌ๋ผใ€.\n *\n * โ”€โ”€ ์ด์–ด ๋ถ™์ด๊ธฐ๋Š” ์„œ๋ฒ„๊ฐ€ ํ•œ๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ํ‘œ์™€ ๋ฉ”๋ชจ๋ฆฌ๋Š” ๊ฒน์นœ๋‹ค(ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‚ด์•„ ์žˆ๋Š” ๋™์•ˆ ๋‹ซํžŒ ์ฐฝ์€ ๋‘˜ ๋‹ค์— ์žˆ๋‹ค). ๊ฒน์นจ์„ ํ™”๋ฉด์ด ์ •๋ฆฌํ•˜๊ฒŒ ๋‘๋ฉด\n * ํ™”๋ฉด๋งˆ๋‹ค ๊ทœ์น™์ด ๊ฐˆ๋ฆฌ๊ณ , ๊ฐ™์€ ๊ตฌ๊ฐ„์ด ๋‘ ๋ฒˆ ๊ทธ๋ ค์ง€๊ฑฐ๋‚˜ ์‚ฌ๋ผ์ง„๋‹ค. ๊ทธ๋ž˜์„œ ์—ฌ๊ธฐ์„œ ํ•œ ๋ฒŒ๋กœ ์ด์–ด ๋ถ™์ด๊ณ \n * **์–ด๋””์„œ๋ถ€ํ„ฐ ๋ฉ”๋ชจ๋ฆฌ์ธ์ง€**(`liveFrom`)๋ฅผ ํ•จ๊ป˜ ๋‚ธ๋‹ค โ€” ํ™”๋ฉด์ด ๊ทผ๊ฑฐ๋ฅผ ๋งํ•  ์ˆ˜ ์žˆ๊ฒŒ.\n */\n\n/**\n * ํ•œ ๋ฒˆ์— ๋Œ๋ ค์ฃผ๋Š” ์ฐฝ ์ˆ˜ ์ƒํ•œ โ€” 144์ฐฝ ร— 10๋ถ„ = 24์‹œ๊ฐ„.\n *\n * ์ƒํ•œ์ด ํ•„์š”ํ•œ ์ด์œ ๋Š” ์ด ํ‘œ๊ฐ€ **์ž๋ž€๋‹ค**๋Š” ๊ฒƒ์ด๋‹ค(ํŠธ์œˆ 1,000๊ฐœ์— ํ•˜๋ฃจ 14.4๋งŒ ํ–‰). ์ƒํ•œ์—์„œ ๋ฐ€๋ ค๋‚œ\n * ์ˆ˜๋Š” **์„ธ์–ด์„œ ๋‚ธ๋‹ค** โ€” ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ์ž๋ฅด๋ฉด ํ™”๋ฉด์ด ใ€Œ๊ทธ ์•ž์—๋Š” ์•„๋ฌด ์ผ๋„ ์—†์—ˆ๋‹คใ€๋กœ ์ฝ๋Š”๋‹ค.\n */\nexport const HISTORY_WINDOW_LIMIT = 144\n\n/** ๋ฌผ์„ ์ˆ˜ ์žˆ๋Š” ๊ธฐ๊ฐ„์˜ ์ƒํ•œ(์‹œ๊ฐ„). ๋„˜๊ฒจ๋„ ์—ฌ๊ธฐ์„œ ์ž๋ฅด๊ณ , ์ž๋ฅธ ์‚ฌ์‹ค์„ ๋‚ธ๋‹ค. */\nexport const HISTORY_HOURS_MAX = 168\n\n@Resolver()\nexport class TwinIngestWindowQuery {\n @Query(returns => ScalarObject, {\n nullable: true,\n description:\n 'Ingest windows for one twin over a past span, stitched from two sources so the trend survives a restart: closed windows persisted in the table (older) and the in-memory ledger (recent, roughly the last 6 hours). Overlap is resolved here rather than on screen โ€” a window present in both is reported once, from memory, and `liveFrom` says where memory takes over so a screen can state its basis. Each window carries offered / accepted / rejected / undelivered plus the journal rows written and the write round-trips behind them; `acceptedRatio` is null when nothing was offered, because an empty window is not a perfect one. Deliberately separate from twinIngestHealth: that query is polled whenever a screen opens, and making it scan a growing table would reintroduce the cost this codebase just removed elsewhere. Counts that could not be returned are reported rather than dropped โ€” `storedDropped` when the row cap was hit and `hoursClamped` when the requested span was longer than allowed. Null if the instance is not in the current domain.'\n })\n async twinIngestHistory(\n @Arg('instanceId') instanceId: string,\n @Arg('hours', type => Int, { nullable: true, description: 'How far back to read, in hours. Defaults to 24 and is clamped to 168.' })\n hours: number | undefined,\n @Ctx() context: ResolverContext\n ): Promise<any> {\n const domainId = context.state.domain.id\n /* ํ…Œ๋„ŒํŠธ ๊ฒฉ๋ฆฌ โ€” ๋ฉˆ์ถ˜ ํŠธ์œˆ์˜ ์ด๋ ฅ๋„ ๋ณผ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค(๊ทธ๋•Œ๊ฐ€ ๊ฐ€์žฅ ๋ณด๊ณ  ์‹ถ์€ ๋•Œ๋‹ค). */\n if (!TwinEngine.owns(domainId, instanceId) && !(await TwinEngine.ownsRegistered(domainId, instanceId))) return null\n\n const asked = Number.isFinite(Number(hours)) && Number(hours) > 0 ? Math.floor(Number(hours)) : 24\n const span = Math.min(asked, HISTORY_HOURS_MAX)\n const now = Date.now()\n const fromMs = now - span * 3_600_000\n\n /*\n * ํ‘œ์—์„œ ๊ทธ ๊ตฌ๊ฐ„์˜ ๋‹ซํžŒ ์ฐฝ์„ ์ฝ๋Š”๋‹ค. **์ƒํ•œ์„ ๋‘”๋‹ค** โ€” ์ž๋ผ๋Š” ํ‘œ์ด๊ณ , ์ด ์กฐํšŒ๊ฐ€ ํ™”๋ฉด์—์„œ ์—ด๋ฆฐ๋‹ค.\n * ์ตœ์‹  ์ชฝ์ด ์ค‘์š”ํ•˜๋ฏ€๋กœ ๋‚ด๋ ค์„œ ์ •๋ ฌํ•ด ๊ฐ€์ ธ์˜ค๊ณ , ๋‚ผ ๋•Œ ๋‹ค์‹œ ์˜ฌ๋ฆฐ๋‹ค.\n */\n const repo = getRepository(TwinIngestWindow)\n const where = {\n domain: { id: domainId } as any,\n instanceId,\n closedAt: Between(new Date(fromMs), new Date(now))\n }\n const rows = await repo.find({ where, order: { closedAt: 'DESC' }, take: HISTORY_WINDOW_LIMIT })\n\n /*\n * ์ƒํ•œ์— ๋‹ฟ์•˜์œผ๋ฉด **๋ช‡ ๊ฐœ๊ฐ€ ๋ฐ€๋ ธ๋Š”์ง€ ์„ผ๋‹ค.** ใ€Œ๋” ์žˆ์Œใ€๋งŒ ๋งํ•˜๋ฉด ํ™”๋ฉด์ด ๊ทธ ์•ž์„ ์ง์ž‘ํ•˜๊ฒŒ ๋œ๋‹ค.\n * ์ƒํ•œ์— ๋‹ฟ์ง€ ์•Š์•˜์œผ๋ฉด ์…€ ํ•„์š”๊ฐ€ ์—†๋‹ค(์™•๋ณต์„ ์•„๋‚€๋‹ค).\n */\n const storedDropped = rows.length === HISTORY_WINDOW_LIMIT ? Math.max(0, (await repo.count({ where })) - rows.length) : 0\n\n const stored = rows.reverse().map(r => ({\n from: r.openedAt?.toISOString?.() ?? new Date(r.openedAt as any).toISOString(),\n to: r.closedAt?.toISOString?.() ?? new Date(r.closedAt as any).toISOString(),\n offered: r.offered,\n /* ํ†ต๊ณผ๋Š” **ํŠธ์œˆ์— ๋‹ฟ์€** ๊ฒƒ๋งŒ. ํ‘œ์˜ ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ์“ด๋‹ค โ€” ์ฝ๋Š” ์ชฝ์—์„œ ๋‹ค์‹œ ๋‚˜๋ˆ„๋ฉด ๋ฐ˜์˜ฌ๋ฆผ์ด ๊ฐˆ๋ฆฐ๋‹ค. */\n accepted: r.offered - r.rejected - (r.undelivered ?? 0),\n rejected: r.rejected,\n undelivered: r.undelivered ?? 0,\n acceptedRatio: typeof r.acceptedRatio === 'number' ? r.acceptedRatio : null,\n rows: r.journaledRows ?? 0,\n flushes: r.journalFlushes ?? 0,\n source: 'stored' as const\n }))\n\n /* ๋ฉ”๋ชจ๋ฆฌ ์žฅ๋ถ€์˜ ๋‹ซํžŒ ์ฐฝ โ€” ์ด์ชฝ์ด ์ตœ์‹ ์ด๊ณ , ๊ฒน์น˜๋Š” ๊ตฌ๊ฐ„์€ ์ด์ชฝ์„ ์“ด๋‹ค(๊ฐ™์€ ์‚ฌ์‹ค์˜ ์›๋ณธ์ด๋‹ค). */\n const live = (TwinEngine.ingestHealthOf(domainId, instanceId).trend ?? []).map((w: any) => ({\n ...w,\n source: 'live' as const\n }))\n\n /*\n * ๊ฒน์นจ ์ •๋ฆฌ โ€” ์ฐฝ์˜ **์—ฌ๋Š” ์‹œ๊ฐ**์ด ํ‚ค๋‹ค. ๊ฐ™์€ ์ฐฝ์ด ํ‘œ์™€ ๋ฉ”๋ชจ๋ฆฌ์— ๋‘˜ ๋‹ค ์žˆ์œผ๋ฉด ํ•˜๋‚˜๋งŒ ๋‚ธ๋‹ค.\n * ์‹œ๊ฐ ๋ฌธ์ž์—ด์„ ๊ทธ๋Œ€๋กœ ํ‚ค๋กœ ์“ฐ์ง€ ์•Š๋Š”๋‹ค: ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ๋ฐ€๋ฆฌ์ดˆ๋ฅผ ์ž๋ฅด๊ฑฐ๋‚˜ ํ˜•์‹์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์–ด\n * ๊ฐ™์€ ์ฐฝ์ด ๋‹ค๋ฅธ ํ‚ค๊ฐ€ ๋œ๋‹ค. epoch ๋กœ ๊ฒฌ์ค€๋‹ค.\n */\n const liveStarts = new Set(live.map((w: any) => Date.parse(w.from)))\n const windows = [...stored.filter(w => !liveStarts.has(Date.parse(w.from))), ...live]\n\n return {\n windows,\n hours: span,\n /* ๋ฌผ์€ ๊ฒƒ๋ณด๋‹ค ์งง๊ฒŒ ์ž˜๋ ธ์œผ๋ฉด ๋ฐํžŒ๋‹ค. */\n ...(span < asked ? { hoursClamped: asked } : {}),\n from: new Date(fromMs).toISOString(),\n to: new Date(now).toISOString(),\n /** ํ‘œ์—์„œ ์ฝ์€ ์ฐฝ ์ˆ˜ ยท ์ƒํ•œ์—์„œ ๋ฐ€๋ ค๋‚œ ์ˆ˜. */\n storedCount: stored.length,\n storedDropped,\n /**\n * ์–ด๋””์„œ๋ถ€ํ„ฐ ๋ฉ”๋ชจ๋ฆฌ์ธ๊ฐ€ โ€” ํ™”๋ฉด์ด ๊ทผ๊ฑฐ๋ฅผ ๋งํ•  ์ˆ˜ ์žˆ๊ฒŒ. ๋ฉ”๋ชจ๋ฆฌ์— ๋‹ซํžŒ ์ฐฝ์ด ์—†์œผ๋ฉด `null` ์ด๋‹ค\n * (์žฌ๊ธฐ๋™ ์งํ›„๊ฐ€ ๊ทธ๋ ‡๋‹ค: ๊ทธ๋•Œ ๋ณด์ด๋Š” ๊ฒƒ์€ ์ „๋ถ€ ํ‘œ์—์„œ ์˜จ ๊ฒƒ์ด๋‹ค).\n */\n liveFrom: live.length ? live[0].from : null,\n liveCount: live.length\n }\n }\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"twin-ingest-window-writer.js","sourceRoot":"","sources":["../../../server/service/twin-ingest-window/twin-ingest-window-writer.ts"],"names":[],"mappings":";;AAoBA,8DAiCC;AArDD,gDAA8C;AAC9C,iDAAqD;AAErD,oDAAkD;AAClD,mEAA0D;AAE1D;;;;;;;;;;;;;GAaG;AACH,SAAgB,yBAAyB;IACvC,qBAAU,CAAC,oBAAoB,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE;QAC7C,MAAM,IAAI,GAAG,IAAA,qBAAa,EAAC,wCAAgB,CAAC,CAAA;QAC5C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAA;QAC9B,IAAI;aACD,IAAI,CACH,IAAI,CAAC,MAAM,CAAC;YACV,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,QAAQ,EAAS;YAClC,UAAU,EAAE,EAAE,CAAC,UAAU;YACzB,QAAQ,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;YAClC,QAAQ,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;YAChC,OAAO;YACP,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,kDAAkD;YAClD,aAAa,EAAE,MAAM,CAAC,IAAI;YAC1B,cAAc,EAAE,MAAM,CAAC,OAAO;YAC9B;;;eAGG;YACH,GAAG,CAAC,OAAO,GAAG,CAAC;gBACb,CAAC,CAAC,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC,OAAO,GAAG,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,EAAE;gBACvF,CAAC,CAAC,EAAE,CAAC;SACR,CAAC,CACH;aACA,KAAK,CAAC,GAAG,CAAC,EAAE,CACX,IAAA,iBAAQ,EACN,yBAAyB,EAAE,CAAC,UAAU,sDAAsD,EAC5F,GAAG,EAAE,OAAO,IAAI,GAAG,CACpB,CACF,CAAA;IACL,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,mEAAmE;AACnE,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAA","sourcesContent":["import { twinWarn } from '../../engine/log.js'\nimport { getRepository } from '@things-factory/shell'\n\nimport { TwinEngine } from '../../engine/index.js'\nimport { TwinIngestWindow } from './twin-ingest-window.js'\n\n/*\n * ๋‹ซํžŒ ์ฐฝ์„ ํ‘œ๋กœ ์˜ฎ๊ธด๋‹ค โ€” **์˜์†์ด ๋ถ™๋Š” ์œ ์ผํ•œ ์ž๋ฆฌ.**\n *\n * ์ปค๋„ ์ธต(`engine/ingest-health.ts`)์€ ์ €์žฅ ๊ณ„์ธต์„ ๋ชจ๋ฅธ๋‹ค. ์ฐฝ์ด ๋‹ซํž ๋•Œ ๋ถ€๋ฅผ ๊ณณ์„ ์—”์ง„์ด ๋ฌธ์œผ๋กœ ์—ด์–ด\n * ๋‘์—ˆ๊ณ (`onIngestWindowClosed`), ์ด ํŒŒ์ผ์ด ๋ถ€ํŒ…์—์„œ ํ•œ ๋ฒˆ ๋“ฑ๋กํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ๊ธฐ๋ก ๊ฒฝ๋กœ๊ฐ€ ๊ฐˆ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.\n *\n * โ”€โ”€ ์‹คํŒจ๋ฅผ ์‚ผํ‚ค์ง€ ์•Š๋Š”๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์“ฐ๊ธฐ๊ฐ€ ํ„ฐ์ ธ๋„ ๋ฉ”๋ชจ๋ฆฌ ์žฅ๋ถ€๋Š” ๊ณ„์† ๊ตด๋Ÿฌ๊ฐ„๋‹ค(`rollIngestWindow` ๊ฐ€ ํ›…์„ ๊ฐ์‹ผ๋‹ค). ๋‹ค๋งŒ **์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ๋„˜๊ธฐ์ง€๋Š”\n * ์•Š๋Š”๋‹ค** โ€” ์‹คํŒจ๋ฅผ ๋กœ๊ทธ๋กœ ๋‚จ๊ธด๋‹ค. ๊ทธ๋Ÿฌ์ง€ ์•Š์œผ๋ฉด ์ถ”์ด ํ‘œ์— ๊ตฌ๋ฉ์ด ์ƒ๊ธด ์ด์œ ๋ฅผ ๋‚˜์ค‘์— ์•Œ ์ˆ˜ ์—†๋‹ค.\n *\n * โ”€โ”€ ์™œ await ํ•˜์ง€ ์•Š๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ด ํ›…์€ ์ธ์ œ์ŠคํŠธ ๊ฒฝ๋กœ์—์„œ ๋ถˆ๋ฆฐ๋‹ค(๋ผ์ด๋ธŒ ํ”ผ๋“œ์˜ ์ฝœ๋ฐฑ ์•ˆ). ์—ฌ๊ธฐ์„œ DB ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋ฉด **์œ ์ž…์ด DB ์†๋„์—\n * ๋ฌถ์ธ๋‹ค** โ€” ์ด ๊ธฐ๋Šฅ์ด ๋ง‰์œผ๋ ค๋˜ ๋ถ€ํ•˜๊ฐ€ ๊ทธ ๋ชจ์–‘์œผ๋กœ ๋Œ์•„์˜จ๋‹ค. ๊ทธ๋ž˜์„œ ๋„์›Œ ๋ณด๋‚ด๊ณ  ๊ฒฐ๊ณผ๋งŒ ๋กœ๊ทธ๋กœ ๋ฐ›๋Š”๋‹ค.\n */\nexport function installIngestWindowWriter(): void {\n TwinEngine.onIngestWindowClosed((at, closed) => {\n const repo = getRepository(TwinIngestWindow)\n const offered = closed.offered\n repo\n .save(\n repo.create({\n domain: { id: at.domainId } as any,\n instanceId: at.instanceId,\n openedAt: new Date(closed.startMs),\n closedAt: new Date(closed.endMs),\n offered,\n rejected: closed.rejected,\n undelivered: closed.undelivered,\n /* ์ ํžŒ ๊ฒƒ๋„ ๊ฐ™์€ ํ–‰์— โ€” ์ฐฝ์ด ์œ ์ž… ์—†์ด ๋‹ซํ˜”์–ด๋„(์‹œ๋ฎฌ) ์ด ๋‘ ์ˆ˜๋Š” ์‚ฌ์‹ค์ด๋‹ค. */\n journaledRows: closed.rows,\n journalFlushes: closed.flushes,\n /*\n * ์ œ์‹œ๊ฐ€ 0 ์ด๋ฉด ๋น„์›Œ ๋‘”๋‹ค โ€” 1 ๋กœ ์ฑ„์šฐ๋ฉด ใ€Œ์ „๋ถ€ ํ†ต๊ณผใ€๋กœ ์ฝํžŒ๋‹ค.\n * ํ†ต๊ณผ๋Š” **ํŠธ์œˆ์— ๋‹ฟ์€** ๊ฒƒ๋งŒ์ด๋‹ค: ๋ฒ„๋ ค์ง„ ๊ฒƒ์„ ๋นผ์ง€ ์•Š์œผ๋ฉด ๋ฉˆ์ถ˜ ํŠธ์œˆ์˜ ์ฐฝ์ด 100% ๋กœ ๋‚จ๋Š”๋‹ค.\n */\n ...(offered > 0\n ? { acceptedRatio: round4((offered - closed.rejected - closed.undelivered) / offered) }\n : {})\n })\n )\n .catch(err =>\n twinWarn(\n `[twin-ingest-window] \"${at.instanceId}\" window not persisted (trend will have a gap here):`,\n err?.message ?? err\n )\n )\n })\n}\n\n/** 0.999 ๊ฐ€ 1 ๋กœ ๋ฐ˜์˜ฌ๋ฆผ๋˜๋ฉด ใ€Œ์ „๋ถ€ ํ†ต๊ณผใ€๋กœ ์ฝํžŒ๋‹ค โ€” ์ž๋ฆฟ์ˆ˜๋ฅผ ๋„‰๋„‰ํžˆ ์ค€๋‹ค(๋ฉ”๋ชจ๋ฆฌ ์žฅ๋ถ€์™€ ๊ฐ™์€ ๊ทœ์น™). */\nconst round4 = (v: number) => Math.round(v * 10000) / 10000\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"twin-ingest-window.js","sourceRoot":"","sources":["../../../server/service/twin-ingest-window/twin-ingest-window.ts"],"names":[],"mappings":"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","sourcesContent":["import { CreateDateColumn, Entity, Index, Column, RelationId, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'\nimport { ObjectType, Field, ID, Int, Float } from 'type-graphql'\n\nimport { Domain } from '@things-factory/shell'\n\n/*\n * ์ธ์ œ์ŠคํŠธ ์ฐฝ ํ•˜๋‚˜ โ€” **๋™๊ธฐํ™” ์ถ”์ด๋ฅผ ์žฌ๊ธฐ๋™ ๋’ค์—๋„ ์ด์–ด ๋ณด๊ธฐ ์œ„ํ•œ ํ–‰.**\n *\n * โ”€โ”€ ์™œ ์ฐฝ๋งˆ๋‹ค์ด๊ณ  ๊ฑด๋งˆ๋‹ค๊ฐ€ ์•„๋‹Œ๊ฐ€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๊ฑฐ๋ถ€๋งˆ๋‹ค ํ–‰์„ ์“ฐ๋ฉด ๋ผ์ด๋ธŒ ๊ณ„์ธก ๊ทœ๋ชจ์—์„œ ์ดˆ๋‹น 1๋งŒ ํ–‰์ด๊ณ , ๊ทธ ๋ถ€ํ•˜๊ฐ€ ์ด๋ฒคํŠธ ๋ฃจํ”„๋กœ ๋Œ์•„์˜จ๋‹ค. ์ฐฝ๋งˆ๋‹ค๋ฉด\n * ํŠธ์œˆ 1,000๊ฐœ์— ํ•˜๋ฃจ 14.4๋งŒ ํ–‰(์•ฝ 14MB)์ด๋‹ค. ๊ทธ๋ž˜์„œ **๋‹ซํžŒ ์ฐฝ ํ•˜๋‚˜๊ฐ€ ์˜์†์˜ ๋‹จ์œ„**๋‹ค.\n *\n * ๊ฑด๋งˆ๋‹ค ๋‚จ๊ธฐ๋Š” ์ž๋ฆฌ๋Š” ์ด๋ฏธ ๋”ฐ๋กœ ์žˆ๋‹ค: ์‹œ๋‚˜๋ฆฌ์˜ค ๊ฒฝ๋กœ๊ฐ€ `PayloadLog` ๋กœ dead-letter ๋ฅผ ๋‚จ๊ธด๋‹ค(๋ฐฐ์น˜์„ฑ\n * ์œ ์ž…์ด๋ผ ๊ฑด์ˆ˜๊ฐ€ ๊ฐ๋‹น๋œ๋‹ค). ์ด ํ‘œ๋Š” ๊ทธ๊ฒƒ์„ ๋Œ€์‹ ํ•˜์ง€ ์•Š๊ณ  **์ถ”์ด**๋ฅผ ๋‹ตํ•œ๋‹ค.\n *\n * โ”€โ”€ ์™œ ์‚ฌ์œ ยทํ‘œ๋ณธ์€ ์—ฌ๊ธฐ ์—†๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์‚ฌ์œ  ๋ฌธ๊ตฌ๋Š” ๊ธธ๊ณ  ํ‘œ๋ณธ์—๋Š” **๊ณ ๊ฐ์˜ ๋ ˆ์ฝ”๋“œ ์›๋ฌธ**์ด ๋“ค์–ด ์žˆ๋‹ค. ๊ทธ๊ฒƒ์„ ์ฐฝ๋งˆ๋‹ค ์˜์†ํ•˜๋ฉด ํ‘œ๊ฐ€ ์ปค์ง€๊ณ \n * ๊ณ ๊ฐ ๋ฐ์ดํ„ฐ๊ฐ€ ์˜ค๋ž˜ ๋‚จ๋Š”๋‹ค. ์‚ฌ์œ ์™€ ํ‘œ๋ณธ์€ ๋ฉ”๋ชจ๋ฆฌ ์žฅ๋ถ€๊ฐ€ ๋‹ตํ•˜๊ณ (์ตœ๊ทผ 6์‹œ๊ฐ„), ์ด ํ‘œ๋Š” ์ˆซ์ž๋งŒ ๋“ ๋‹ค.\n *\n * โ”€โ”€ ๊ณ ์น˜์ง€ ์•Š๋Š”๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๋‹ซํžŒ ์ฐฝ์€ ์ง€๋‚˜๊ฐ„ ์‚ฌ์‹ค์ด๋‹ค. ๊ทธ๋ž˜์„œ `updatedAt`ยท`deletedAt` ์„ ๋‘์ง€ ์•Š๋Š”๋‹ค(์ €๋„๊ณผ ๊ฐ™์€ ๊ทœ์œจ).\n */\n@Entity()\n@Index('ix_twin_ingest_window_0', (e: TwinIngestWindow) => [e.domain, e.instanceId, e.closedAt], { unique: false })\n@ObjectType({\n description:\n 'One closed ingest window for a twin: how many records were offered, accepted and rejected between two times. Written when a window closes (about every 10 minutes per twin) so the sync trend survives a restart and reaches further back than the in-memory ledger. Reasons and rejected-record samples are deliberately not stored here โ€” they live in the in-memory ledger, which covers roughly the last 6 hours.'\n})\nexport class TwinIngestWindow {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID, { description: 'Unique identifier of the window record.' })\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain, { nullable: true, description: 'Owning tenant domain.' })\n domain?: Domain\n\n @RelationId((e: TwinIngestWindow) => e.domain)\n domainId?: string\n\n @Column()\n @Field({ description: 'Twin runtime instance this window belongs to.' })\n instanceId: string\n\n @Column()\n @Field({ description: 'When the window opened.' })\n openedAt: Date\n\n @Column()\n @Field({ description: 'When the window closed. Windows close on the next ingest after the window length elapses, so a feed that stops leaves its last window open and unwritten.' })\n closedAt: Date\n\n @Column({ type: 'int' })\n @Field(type => Int, { description: 'Records offered in this window, whether or not they were accepted.' })\n offered: number\n\n @Column({ type: 'int' })\n @Field(type => Int, { description: 'Records the kernel refused in this window because they did not map โ€” the fix is in the mapping.' })\n rejected: number\n\n /*\n * ๊ฑฐ๋ถ€์™€ ๋”ฐ๋กœ ์„ผ๋‹ค โ€” **์ฒ˜๋ฐฉ์ด ๋‹ค๋ฅด๋‹ค.**\n *\n * ํŠธ์œˆ์ด ๋ผ์ด๋ธŒ๋กœ ๋Œ์ง€ ์•Š์œผ๋ฉด ์ปค๋„์ด ๋ ˆ์ฝ”๋“œ๋ฅผ ๋ฒ„๋ฆฐ๋‹ค. ๊ทธ๊ฒƒ์„ ๊ฑฐ๋ถ€์— ํ•ฉ์น˜๋ฉด ใ€Œ๋งคํ•‘์„ ๊ณ ์ณ๋ผใ€๋กœ ์ฝํžˆ๊ณ ,\n * ํ†ต๊ณผ์— ํ•ฉ์น˜๋ฉด ๋ฉˆ์ถ˜ ํŠธ์œˆ์ด 100% ๋กœ ๋ณด์ธ๋‹ค(์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ๋–ด๋‹ค). ๊ทธ๋ž˜์„œ ์ œ3์˜ ์ˆ˜๋กœ ๋‚จ๊ธด๋‹ค.\n */\n @Column({ type: 'int', default: 0 })\n @Field(type => Int, {\n description:\n 'Records that mapped fine but never reached the twin, because the twin was not running live while the feed kept delivering. Distinct from rejected: the fix here is to start the twin or disconnect the feed, not to change the mapping. Offered minus rejected minus undelivered is what actually reached the twin.'\n })\n undelivered: number\n\n /*\n * ํ†ต๊ณผ์œจ์„ **ํ•จ๊ป˜ ์ ๋Š”๋‹ค.** ์ฝ๋Š” ์ชฝ์—์„œ ๋‚˜๋ˆ„๊ฒŒ ํ•˜๋ฉด ์†Œ๋น„์ฒ˜๋งˆ๋‹ค ๋ฐ˜์˜ฌ๋ฆผ์ด ๊ฐˆ๋ฆฌ๊ณ (0.999 ๋ฅผ 1 ๋กœ ์“ฐ๋Š”\n * ๊ณณ์ด ์ƒ๊ธด๋‹ค), ์ œ์‹œ๊ฐ€ 0 ์ธ ์ฐฝ์—์„œ 0์œผ๋กœ ๋‚˜๋ˆ„๋Š” ์‹ค์ˆ˜๊ฐ€ ๊ฐ์ž ์ƒ๊ธด๋‹ค. ์ œ์‹œ๊ฐ€ 0 ์ด๋ฉด **๋น„์–ด ๋‘”๋‹ค** โ€”\n * 1 ๋กœ ์ฑ„์šฐ๋ฉด ใ€Œ์ „๋ถ€ ํ†ต๊ณผใ€๋กœ ์ฝํžŒ๋‹ค.\n */\n @Column({ type: 'float', nullable: true })\n @Field(type => Float, {\n nullable: true,\n description:\n 'Share of offered records that reached the twin (0โ€“1), rounded to four places. Null when nothing was offered in this window โ€” an empty window is not a perfect one, and writing 1 there would read as \"everything passed\".'\n })\n acceptedRatio?: number\n\n /*\n * โ”€โ”€ ์ ํžŒ ๊ฒƒ๋„ ๊ฐ™์€ ์ฐฝ์— ๋“ ๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์œ ์ž…๊ณผ **๋‹ค๋ฅธ ์ถ•**์ด๋‹ค. ์‹œ๋ฎฌ ํŠธ์œˆ์€ ๋ฐ›๋Š” ๊ฒƒ ์—†์ด ์ž๊ธฐ๊ฐ€ ๋‚ธ ์‚ฌ์‹ค์„ ์ ์œผ๋ฏ€๋กœ `offered` ๊ฐ€ 0 ์ด๊ณ \n * `journaledRows` ๋Š” 0 ์ด ์•„๋‹ˆ๋‹ค. ์ด ์นธ์ด ์—†์œผ๋ฉด ๋„๋Š” ํŠธ์œˆ ๋Œ€๋ถ€๋ถ„์ด ์‹œ๋ฎฌ์ธ ์„œ๋ฒ„์˜ ํ™œ๋™์ด ์–ด๋А ์ถ”์ด์—๋„\n * ๋‚จ์ง€ ์•Š๋Š”๋‹ค(๊ณ„๊ธฐ๋Š” ์ง€๊ธˆ๋งŒ ๋‹ตํ•˜๊ณ  ์žฌ๊ธฐ๋™์— 0 ์œผ๋กœ ๋Œ์•„๊ฐ„๋‹ค).\n *\n * ๋‘ ์ˆ˜๋ฅผ ๋”ฐ๋กœ ์„ธ๋Š” ์ด์œ : 2026-08-20 ์— ๊ณ ์นœ ๊ฒƒ์ด **ํ–‰๋‹น ์™•๋ณต**์ด๋‹ค(๋ธํƒ€๋งˆ๋‹ค ํ•œ ๋ฒˆ โ†’ ์ฐฝ๋‹น ํ•œ ๋ฒˆ).\n * ํ–‰๋งŒ ์„ธ๋ฉด ๊ทธ ๊ฐœ์„ ๋„, ๋˜๋Œ์•„๊ฐ€๋Š” ๊ฒƒ๋„ ๋ณด์ด์ง€ ์•Š๋Š”๋‹ค.\n */\n @Column({ type: 'int', default: 0 })\n @Field(type => Int, {\n description:\n 'Journal rows written for this twin during this window. This is a different axis from ingest: a twin driven by a simulator source receives nothing (offered = 0) yet writes what it produces, so without this column its activity appears in no trend at all.'\n })\n journaledRows: number\n\n @Column({ type: 'int', default: 0 })\n @Field(type => Int, {\n description:\n 'Number of journal write round-trips (flushes) behind those rows. Counted separately from the rows themselves so that a regression back to per-delta writes โ€” the defect fixed on 2026-08-20, where each kernel delta cost one insert โ€” is visible as rows-per-flush falling back towards 1.'\n })\n journalFlushes: number\n\n @CreateDateColumn()\n @Field({ nullable: true, description: 'When this record was written.' })\n createdAt?: Date\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/twin-instance/index.ts"],"names":[],"mappings":";;;AAAA,yDAAiD;AAEpC,QAAA,QAAQ,GAAG,CAAC,+BAAY,CAAC,CAAA","sourcesContent":["import { TwinInstance } from './twin-instance.js'\n\nexport const entities = [TwinInstance]\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"twin-instance.js","sourceRoot":"","sources":["../../../server/service/twin-instance/twin-instance.ts"],"names":[],"mappings":"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","sourcesContent":["import { CreateDateColumn, Entity, Index, Column, RelationId, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'\nimport { ObjectType, Field, ID } from 'type-graphql'\n\nimport { Domain, ScalarObject } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport { modelColumnTransformer } from '../../engine/model-vocabulary.js'\n\n/*\n * TwinInstance โ€” ํŠธ์œˆ ์ธ์Šคํ„ด์Šค ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ(์žฌ๋ถ€ํŒ… ๋ณต๊ตฌ์˜ ์•ต์ปค).\n * ๋ณต๊ตฌ(DBโ†’replay)๋Š” model(๋งˆ์Šคํ„ฐ ์ฒญ์‚ฌ์ง„)๊ฐ€ ์žˆ์–ด์•ผ ์ด๋ฒคํŠธ๋ฅผ ์ƒํƒœ๋กœ ๋‹ค์‹œ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๋‹ค โ†’ modelยทkind ๋ฅผ ์˜์†.\n * ์ด๋ฒคํŠธ(TwinEvent)์™€ ๋‹ฌ๋ฆฌ ๊ฐ€๋ณ€(status ๊ฐฑ์‹ ) โ€” ์ธ์Šคํ„ด์Šค์˜ \"ํ˜„์žฌ ๋“ฑ๋ก ์ƒํƒœ\".\n * model ๋Š” simple-json(๋ฉ€ํ‹ฐDB ์ด์‹ โ€” postgres/mysql/sqlite/mssql/oracle ๊ณตํ†ต).\n * (CLAUDE.md: ๋ชจ๋“  @ObjectType/@Field ๋Š” ์˜๋ฌธ description ํ•„์ˆ˜.)\n */\n@Entity()\n@Index('ix_twin_instance_0', (e: TwinInstance) => [e.domain, e.instanceId], { unique: true })\n@Index('ix_twin_instance_1', (e: TwinInstance) => [e.domain, e.spaceId]) // ๊ณต๊ฐ„โ†’์ธ์Šคํ„ด์Šค 1๊ธ‰ ์งˆ์˜(๊ณต๊ฐ„ ์ค‘์‹ฌ ์กด์žฌ๋ก )\n@ObjectType({ description: 'Registry of a hosted twin runtime instance โ€” anchors reboot recovery (model + kind).' })\nexport class TwinInstance {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID, { description: 'Unique identifier of the registry record.' })\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain, { nullable: true, description: 'Owning tenant domain.' })\n domain?: Domain\n\n @RelationId((e: TwinInstance) => e.domain)\n domainId?: string\n\n @Column()\n @Field({ description: 'Twin runtime instance id (unique within a domain).' })\n instanceId: string\n\n /**\n * **์‚ฌ๋žŒ์ด ๋ถ€๋ฅด๋Š” ์ด๋ฆ„** โ€” ์—…๋ฌดํ‚ค(`instanceId`)์™€ ๋‚˜๋ž€ํžˆ ๋‘๋Š” ํ‘œ์‹œ๋ช…(ํ”„๋ ˆ์ž„์›Œํฌ ์—”ํ‹ฐํ‹ฐ ๊ทœ์•ฝ).\n *\n * โ”€โ”€ ์™œ ์—…๋ฌดํ‚ค์™€ ์ด๋ฆ„์„ ๋‚˜๋ˆ  ๋‘๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * `instanceId` ๋Š” URLยท์ €๋„ยท๊ตฌ๋…์ด ์ „๋ถ€ ์“ฐ๋Š” **๊ณ„์•ฝ**์ด๋ผ ๋ฐ”๊ฟ€ ์ˆ˜ ์—†๋‹ค. ๋ฐ˜๋Œ€๋กœ ์ด๋ฆ„์€ ๋ฐ”๋€Œ๊ณ ,\n * ์ค‘๋ณต๋˜๊ณ (์‚ฌ์ดํŠธ ๋‘˜์— \"๋„์žฅ\" ์ด ์žˆ๋Š” ๊ฒƒ์ด ์ •์ƒ), ์–ธ์–ด๋งˆ๋‹ค ๋‹ค๋ฅด๋‹ค. ๋‘˜์„ ํ•œ ์ปฌ๋Ÿผ์— ๋‹ด์œผ๋ฉด ๊ฐœ๋ช…์ด\n * ๊ณง ๋‹ค๋ฅธ ํŠธ์œˆ์ด ๋˜๊ณ  ์žฌ๋™๊ธฐ๊ฐ€ ๋Š๊ธด๋‹ค โ€” ๊ทธ๋ž˜์„œ ๋‚˜๋ˆˆ๋‹ค(์ด ์ €์žฅ์†Œ์—์„œ ์‹๋ณ„์ž๊ฐ€ ๋ฐ–์—์„œ ์˜ค๋Š” ๊ฒƒ์€\n * ์ „๋ถ€ ์ด ๊ทœ์•ฝ์„ ์“ด๋‹ค: `spaceId`ยท`locationId`ยท`equipmentId`ยท`operationKey`).\n *\n * ๋‚˜๋ˆด์œผ๋ฉด **์ด๋ฆ„์„ ๋ฐ˜๋“œ์‹œ ํ•จ๊ป˜ ๋‘ฌ์•ผ ํ•œ๋‹ค.** ์ด ์ž๋ฆฌ๊ฐ€ ์—†๋˜ ๋™์•ˆ ์‚ฌ์ดํŠธ ์ด๋ฆ„์€ model ์•ˆ์—๋งŒ ์žˆ์–ด์„œ\n * ๋ชฉ๋ก์ด `crew-two` ๋งŒ ๋ณด์˜€๋‹ค โ€” ๋‚˜๋ˆ„๊ธฐ๋งŒ ํ•˜๊ณ  ์ ˆ๋ฐ˜์„ ๋นผ๋จน์œผ๋ฉด ํ™”๋ฉด์—๋Š” id ๋งŒ ๋‚จ๋Š”๋‹ค.\n *\n * ์›๋ณธ์ด ์ด๋ฆ„์„ ๋งํ•˜์ง€ ์•Š์œผ๋ฉด ๋น„์šด๋‹ค(id ๋ฅผ ๋ฒ ๋ผ์ง€ ์•Š๋Š”๋‹ค).\n */\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Human name of this twin (the site name from its master). Empty when the source does not name it โ€” never copied from instanceId.' })\n name?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Longer description when the source provides one.' })\n description?: string\n\n /* ์–ด๋А ๋„๋ฉ”์ธ ์ปค๋„์ด ์ด ํŠธ์œˆ์„ ์šด์˜ํ•˜๋Š”๊ฐ€. ์ปค๋„ ์—†๋Š” ํŠธ์œˆ์€ ์—†์œผ๋ฏ€๋กœ ๋น„์–ด ์žˆ์„ ์ˆ˜ ์—†๋‹ค\n (`TwinEngine.start`ยท`register` ๋ชจ๋‘ ํ•„์ˆ˜ ์ธ์ž๋กœ ๋ฐ›๋Š”๋‹ค). */\n @Column()\n @Field({ description: 'Domain kernel kind: wms | yms | mes.' })\n kind: string\n\n /*\n * **์žฌ๊ธฐ๋™ ์ •์ฑ…** โ€” ์ด ํŠธ์œˆ์€ ๋‹ค์‹œ ์„ธ์›Œ์งˆ ๋•Œ ์ž๊ธฐ ๊ณผ๊ฑฐ๋ฅผ ์–ด๋–ป๊ฒŒ ๋Œ€ํ•˜๋‚˜(ADR-0029 ยง2).\n *\n * 'resync' = ์™ธ๋ถ€ ์‹ค๋ฌผ์—์„œ ๋‹ค์‹œ ์ฝ๋Š”๋‹ค(์›๋ณธ์ด ์ง„์‹ค์ด๋ฏ€๋กœ ์šฐ๋ฆฌ ๊ณผ๊ฑฐ๋ฅผ ์ด์–ด ๋ถ™์ด์ง€ ์•Š๋Š”๋‹ค โ†’ startLive).\n * 'resume' = ์ €๋„์„ ์ด์–ด ์„ธ์šด๋‹ค(์ด ํŠธ์œˆ์ด ๋‚ณ์€ ํƒ€์ž„๋ผ์ธ์ด ๊ณง ์‚ฌ์‹ค์ด๋‹ค).\n * 'reset' = ์ €๋„์„ ๋น„์šฐ๊ณ  ์”จ์•—๋ถ€ํ„ฐ ๋‹ค์‹œ ๋Œ๋ฆฐ๋‹ค(์žฌํ˜„ ๊ฐ€๋Šฅํ•œ ์‹คํ—˜ โ€” ๋ฐฑ์ง€ ์‹œ์ž‘์ด ์„ ์–ธ๋œ ๊ฑฐ๋™์ด๋‹ค).\n *\n * โ”€โ”€ ์™œ ํŠธ์œˆ์— ๋‚จ์•˜๋‚˜ (์˜› ์ด๋ฆ„ `realityMode`) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ใ€Œํ˜„์‹ค์ด ์–ด๋””์„œ ์˜ค๋‚˜ใ€๋Š” ADR-0029 ๊ฐ€ **์›๋ณธ์˜ ์ข…๋ฅ˜**๋กœ ์˜ฎ๊ธด ๋ฌผ์Œ์ด๋‹ค(`TwinReference.adapterType`) โ€”\n * ํŠธ์œˆ์€ ํ•œ ์ข…๋ฅ˜์ด๊ณ  ์–ธ์ œ๋‚˜ ์›๋ณธ์„ ๋ฐ˜์˜ํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ฝ”๋“œ๊ฐ€ ์ด ์ถ•์œผ๋กœ ์‹ค์ œ๋กœ ๊ฐ€๋ฅธ ๊ฒƒ์€ **์žฌ๊ธฐ๋™ ๊ฑฐ๋™\n * ํ•˜๋‚˜**์˜€๊ณ , ๊ทธ๊ฒƒ์€ ์›๋ณธ์˜ ์„ฑ์งˆ์ด ์•„๋‹ˆ๋ผ **ํŠธ์œˆ๊ณผ ์ž๊ธฐ ๊ณผ๊ฑฐ์˜ ๊ด€๊ณ„**๋‹ค: ๊ฐ™์€ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ ์›๋ณธ์„ ๋ณด๋Š” ๋‘\n * ํŠธ์œˆ์ด ํ•˜๋‚˜๋Š” ์ด์–ด๊ฐ€๊ณ  ํ•˜๋‚˜๋Š” ๋งค๋ฒˆ ์ฒ˜์Œ๋ถ€ํ„ฐ ์žฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ถ•์€ ๋‚จ๊ณ  ์ด๋ฆ„๋งŒ ๋ฐ”๋€Œ์—ˆ๋‹ค.\n *\n * **๋น„์–ด ์žˆ์„ ์ˆ˜ ์—†๊ณ , ๊ธฐ๋ณธ๊ฐ’๋„ ์—†๋‹ค.** ์˜ˆ์ „์—๋Š” ๋ฏธ์„ ์–ธ์ด ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  `sim-experiment`(=์ €๋„ ์ดˆ๊ธฐํ™”)๋กœ\n * ๋–จ์–ด์กŒ๋‹ค โ€” ๊ฐ’์ด ํ•˜๋‚˜ ์–ด๊ธ‹๋‚˜๋Š” ์ˆœ๊ฐ„ ์ด๋ ฅ์„ ์ง€์šฐ๋Š” ๊ธธ์ด๋‹ค. ์ด์ œ ์ฝ๋Š” ์ชฝ์ด **์˜ค๋ฅ˜๋ฅผ ๋‚ธ๋‹ค**\n * (`engine/restart-policy.ts`). ์„ ์–ธ์€ ํ”„๋กœ๋น„์ €๋‹ํ•˜๋Š” ์ชฝ์˜ ๋ชซ์ด๋‹ค.\n */\n @Column()\n @Field({ description: \"Restart policy: 'resync' (read again from the external source) | 'resume' (continue this twin's own journal) | 'reset' (wipe and replay from the seed). No default โ€” an unspecified policy is refused.\" })\n restartPolicy: string\n\n /* ์ฝ์„ ๋•Œ ์–ดํœ˜ ์„ธ๋Œ€๋ฅผ ํก์ˆ˜ํ•œ๋‹ค(`nodes`/`movers`/`equipmentList` โ†’ `locations`/`equipment`). (vocabulary-guard: allow โ€” ์„ธ๋Œ€ ์ด๋ฆ„ ์—†์ด๋Š” ์„ค๋ช…ํ•  ์ˆ˜ ์—†๋‹ค.)\n ์ž๋ฆฌ๋งˆ๋‹ค ๋ฆฌ๋”๋ฅผ ์“ฐ๊ฒŒ ํ•˜๋ฉด ๋‹ค์Œ์— ์ถ”๊ฐ€๋˜๋Š” ์ž๋ฆฌ๊ฐ€ ๋˜ ๋น ์ง€๊ณ , ๋น ์ง„ ๊ฒƒ์€ ์˜ค๋ฅ˜๊ฐ€ ์•„๋‹ˆ๋ผ **๋นˆ ๊ณต์žฅ**์ด๋ผ\n ๋“ค์–ด์˜จ ๊ฒƒ์ด ์—†๋‹ค(2026-08-06: ๋ชจ๋ธ๋Ÿฌ ์—”ํ‹ฐํ‹ฐ ๋ชฉ๋ก์ด ํ†ต์งธ๋กœ ๋น„์—ˆ๋‹ค). ์ƒ์„ธ `engine/model-vocabulary.ts`. */\n @Column({ type: 'simple-json', nullable: true, transformer: modelColumnTransformer })\n @Field(type => ScalarObject, { nullable: true, description: 'TwinModelDef blueprint (locations/equipment) required to replay events into state. Older stored boards used nodes/movers/equipmentList; they are normalised on read so consumers see one vocabulary.' }) // vocabulary-guard: allow โ€” ์˜› ์–ดํœ˜๋ฅผ ํก์ˆ˜ํ•˜๋Š” ๊ฒƒ์ด ์ด ์ฝ”๋“œ์˜ ์ผ์ด๋‹ค(์„ธ๋Œ€ ์ด๋ฆ„์„ ์ ์–ด์•ผ ํก์ˆ˜ํ•  ์ˆ˜ ์žˆ๋‹ค)\n model?: any\n\n /*\n * ๋กœ์ปฌ ์„ ์–ธ ๊ฒน โ€” **๊ตฌ์กฐ๋Š” ์›์ฒœ์ด, ์ˆ˜๋Š” ์šฐ๋ฆฌ๊ฐ€.**\n *\n * ์š”๊ธˆ ๋‹จ๊ฐ€ยท๊ณ„์•ฝ ์ •๋ณดยท์ถ•์ „์ง€ ์ถฉ์ „์œจ์ฒ˜๋Ÿผ ์› ์‹œ์Šคํ…œ์ด ๋ชจ๋ฅด๋Š” ๊ฐ’์„ ๋„ฃ๋Š” ์ž๋ฆฌ๋‹ค. `model` ์— ์ง์ ‘ ์“ฐ์ง€\n * ์•Š๋Š” ์ด์œ ๋Š” ๊ทธ๊ฒƒ์ด **์›์ฒœ์˜ ์‚ฌ๋ณธ**์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค: ๋‹ค์‹œ ์ฝ๊ธฐ๊ฐ€ ์‚ฌ๋ณธ์„ ์ƒˆ๋กœ ๊ทธ๋ฆฌ๋ฉด ์ง์ ‘ ์“ด ๊ฐ’์€ ์•Œ๋ฆฌ์ง€ ์•Š๊ณ \n * ์‚ฌ๋ผ์ง„๋‹ค(์š”๊ธˆ์ด ์‚ฌ๋ผ์ง€๋ฉด ๊ธˆ์•ก๋„ ์‚ฌ๋ผ์ง€๊ณ , ์‚ฌ์šฉ์ž๋Š” ์ด์œ ๋ฅผ ์•Œ ์ˆ˜ ์—†๋‹ค).\n *\n * ๊ทธ๋ž˜์„œ ์—ฌ๊ธฐ ๋‚จ๊ธฐ๊ณ , ๋ชจ๋ธ์„ ๊ทธ๋ฆด ๋•Œ๋งˆ๋‹ค ๊ทธ ์œ„์— ์–น๋Š”๋‹ค(`engine/local-declarations`). ์–นํžŒ ๊ฐ’์—๋Š”\n * `source: 'local'` ์ด ๋ถ™๋Š”๋‹ค โ€” ์ปค๋„ ๊ณ„์•ฝ์˜ `PropertySource` ์ถ•(`reference` โ†” `local`)์ด๊ณ , ใ€Œ๋ฐ–์—์„œ\n * ์ฐธ์กฐํ•ด ์˜จ ๊ฐ’์ด๋ƒ, ์ด ์•ˆ์—์„œ ์ •ํ•œ ๊ฐ’์ด๋ƒใ€์— ๋‹ตํ•œ๋‹ค.\n *\n * **์ด๋ฆ„์— ์žฅ์†Œ ๋‚ฑ๋ง์„ ์“ฐ์ง€ ์•Š๋Š”๋‹ค**(์˜› ์ด๋ฆ„ `siteDeclarations`): ์ด ์ฝ”๋“œ์—์„œ `site` ๋Š” **์™ธ๋ถ€\n * ์‹œ์Šคํ…œ์ด ๋ถ€๋ฅด๋Š” ์‚ฌ์—…์žฅ**์ด๊ณ (SAP `P3`ยทOracle `W01` ์ด ๊ฐ™์€ ํ˜„์žฅ), ์—ฌ๊ธฐ ๋‹ด๊ธฐ๋Š” ๊ฒƒ์€ ๊ทธ ์™ธ๋ถ€ ์‹œ์Šคํ…œ์ด\n * **๋ชจ๋ฅด๋Š”** ๊ฐ’์ด๋‹ค โ€” ์ด๋ฆ„์ด ๋‚ด์šฉ๊ณผ ์ •๋ฐ˜๋Œ€์˜€๋‹ค. `space` ๋„ ์•„๋‹ˆ๋‹ค: ๊ทธ๊ฒƒ์€ ใ€Œ์–ด๋””ใ€์— ๋‹ตํ•˜๊ณ  ์ด ์ถ•์€\n * ใ€Œ๋ˆ„๊ฐ€ ๋งํ–ˆ๋‚˜ใ€์— ๋‹ตํ•œ๋‹ค.\n */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: \"Locally-declared values layered on top of the reference-derived model (tariff, contract, state of charge) โ€” values whose authority sits here, not in the source system. Kept apart from `model` so a resync cannot silently drop them.\" })\n localDeclarations?: any\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Owning space id (co-location anchor). Promoted from model.spaceId โ€” first-class \"space โ†’ its twins\" query (space-centered ontology).' })\n spaceId?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Owning area id within the space (optional scope). Promoted from model.areaId.' })\n areaId?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Lifecycle status: running | stopped.' })\n status?: string\n\n /*\n * purpose โ€” ์ด ์ธ์Šคํ„ด์Šค๊ฐ€ ์šด์˜ ํŠธ์œˆ์ธ์ง€, ๊ฒฉ๋ฆฌ๋œ ๋ฒค์น˜ ์‚ฌ๋ณธ์ธ์ง€ 1๊ธ‰ ์„ ์–ธ(์ด๋ฆ„ ์ ‘๋‘์‚ฌ๊ฐ€ ์•„๋‹ˆ๋ผ ์†์„ฑ์œผ๋กœ ๊ตฌ๋ณ„).\n * 'bench' ๋Š” ๊ทœ๋ชจ/๋ถ€ํ•˜ ์‹คํ—˜์šฉ ๊ฒฉ๋ฆฌ ์‚ฌ๋ณธ โ€” ๋ชฉ๋กยท์ •๋ฆฌยท์•ˆ์ „ ๊ฐ€๋“œ๊ฐ€ ์ด ์†์„ฑ์„ ํ‚ค๋กœ ๋™์ž‘(์šด์˜ ํŠธ์œˆ ๋ฌด์˜ค์—ผ ๋ณด์žฅ).\n *\n * **๋น„์–ด ์žˆ์„ ์ˆ˜ ์—†๋‹ค.** ํ”„๋กœ๋น„์ €๋‹์ด `register` ์—์„œ 'operational' ๋กœ ๊ฐ์ธํ•˜๊ณ , ๋ฒค์น˜ ์‚ฌ๋ณธ๋งŒ\n * `setPurpose` ๋กœ ๋’ค์ง‘๋Š”๋‹ค. ์˜ˆ์ „์—๋Š” ๋น„์›Œ ๋‘” ์ฑ„ ์ฝ๋Š” ์ชฝ์—์„œ ๋ฉ”์› ๋Š”๋ฐ, ๊ทธ๋Ÿฌ๋ฉด \"์šด์˜์ด๋ผ๊ณ  ์„ ์–ธ๋œ ๊ฒƒ\"\n * ๊ณผ \"์•„๋ฌด๋„ ๋งํ•˜์ง€ ์•Š์€ ๊ฒƒ\" ์ด ๊ฐ™์€ ๊ฐ’์œผ๋กœ ๋ณด์—ฌ์„œ ๋ฒค์น˜ ๊ฒฉ๋ฆฌ๊ฐ€ ์ถ”์ธก์— ๊ธฐ๋Œ€๊ฒŒ ๋œ๋‹ค.\n */\n @Column()\n @Field({ description: \"Instance purpose: 'operational' (real twin) | 'bench' (isolated copy for scale/load experiments).\" })\n purpose: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'For a bench copy: the source spaceId it was copied from (provenance).' })\n copyOf?: string\n\n /**\n * **์ด ํŠธ์œˆ์„ ๋‹ค์‹œ ์ฝ๋Š” ๋ฐฉ๋ฒ•** โ€” ์–ด๋–ค ์›๋ณธ์—์„œ ๋‚˜์™”๋‚˜(`MasterOrigin`).\n *\n * ํŠธ์œˆ์€ ์›๋ณธ์„ ๋น„์ถœ ๋ฟ์ด๋ฏ€๋กœ(ADR-0028) ์›๋ณธ์ด ๋‹ฌ๋ผ์ง€๋ฉด ๋‹ค์‹œ ์ฝ์–ด์•ผ ํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด ์ž๋ฆฌ๊ฐ€ ์—†๋˜\n * ๋™์•ˆ ํŠธ์œˆ์€ **์ž๊ธฐ๊ฐ€ ๋ฌด์—‡์—์„œ ๋‚˜์™”๋Š”์ง€ ๋ชฐ๋ž๋‹ค** โ€” ์–ด๋Œ‘ํ„ฐ๋กœ ๋“ค์–ด์˜จ ํŠธ์œˆ์€ `TwinReference` ํ–‰์ด\n * ์žˆ์—ˆ์ง€๋งŒ ํ…œํ”Œ๋ฆฟ์œผ๋กœ ์„ธ์šด ํŠธ์œˆ์—๋Š” ์•„๋ฌด ํ‘œ์‹๋„ ์—†์—ˆ๊ณ , ๊ทธ๋ž˜์„œ ์ฒซ๋‚ ์˜ ๋ชจ์Šต์— ์˜์›ํžˆ ๋จธ๋ฌด๋Š”\n * ํŠธ์œˆ์ด ๋งŒ๋“ค์–ด์กŒ๋‹ค. ์›์ฒœ์ด ๋ฌด์—‡์ด๋“  ์—ฌ๊ธฐ ํ•œ ์ž๋ฆฌ์— ๋‚จ๊ธด๋‹ค.\n *\n * **๋น„์–ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค** โ€” ์ด ์ž๋ฆฌ๊ฐ€ ์ƒ๊ธฐ๊ธฐ ์ „์— ๋งŒ๋“ค์–ด์ง„ ํŠธ์œˆ์ด ๊ทธ๋ ‡๋‹ค. ๊ทธ๋•Œ๋Š” \"๋‹ค์‹œ ์ฝ์„ ์ˆ˜\n * ์—†๋‹ค\" ๊ฐ€ ์‚ฌ์‹ค์ด๋ฏ€๋กœ ํ™”๋ฉด์ด ๊ทธ๋Œ€๋กœ ๋งํ•œ๋‹ค(์ง์ž‘ํ•ด ์ฑ„์šฐ์ง€ ์•Š๋Š”๋‹ค).\n */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, {\n nullable: true,\n description:\n \"How this twin's master can be produced again โ€” {kind:'reference', source} or {kind:'template', templateId, params}. Absent means this twin cannot be re-read from its source.\"\n })\n origin?: any\n\n /*\n * `revision` ์ปฌ๋Ÿผ์€ **์—†์•ด๋‹ค**(2026-08-08).\n *\n * `ADR-0015` ๊ฐ€ \"์ •์˜๋งŒ ์žˆ๊ณ  write ์•ˆ ๋จ โ€” ํ”„๋กœ๋น„์ €๋‹์—์„œ ์ตœ์‹  ์ €๋„ revision ์„ ๋ฐ˜์˜ํ•˜๋„๋ก\n * ์ฑ„์šด๋‹ค\" ๊ณ  ์ ์–ด ๋‘์—ˆ๋Š”๋ฐ, ์ฑ„์šฐ์ง€ ์•Š๋Š” ํŽธ์ด ๋งž๋‹ค. ์ €๋„์˜ ์ตœ์‹  ๋ฒˆํ˜ธ๋Š” **์ €๋„์ด ์•„๋Š” ์‚ฌ์‹ค**์ด๊ณ \n * (`TwinEngine.list` ๊ฐ€ `MAX(revision)` ์œผ๋กœ ๋‚ธ๋‹ค), ์—ฌ๊ธฐ ๋ณต์ œํ•˜๋ฉด **๊ฐ™์€ ์‚ฌ์‹ค์˜ ์ง‘์ด ๋‘˜**์ด ๋œ๋‹ค.\n * ์ด ์„ธ์…˜์—๋งŒ ๊ทธ ๋ถ€๋ฅ˜๋ฅผ ์…‹ ๊ฒช์—ˆ๋‹ค(`model.operations` ๋‘ ์ง‘ ยท `materials` ๋‘ ์ง‘ ยท tenantId ์ค‘๋ณต).\n *\n * ๋ณต์ œํ•œ ๊ฐ’์€ ๋ฐ˜๋“œ์‹œ ์–ด๊ธ‹๋‚œ๋‹ค โ€” ์ €๋„์€ ํ‹ฑ๋งˆ๋‹ค ๋Š˜๊ณ  ์ด ์ปฌ๋Ÿผ์€ ์ €์žฅํ•  ๋•Œ๋งŒ ๊ฐฑ์‹ ๋˜๋ฏ€๋กœ, ํ™”๋ฉด์ด\n * ์–ด๋А ์ชฝ์„ ์ฝ๋А๋ƒ๋กœ ๋‹ค๋ฅธ ์ˆซ์ž๊ฐ€ ๋‚˜์˜จ๋‹ค. ๊ทธ ๋“ค์–ด์˜จ ๊ฒƒ์ด ์—†๋Š” ์–ด๊ธ‹๋‚จ์„ ๋งŒ๋“ค ์ด์œ ๊ฐ€ ์—†๋‹ค.\n */\n\n @CreateDateColumn()\n @Field({ nullable: true, description: 'Timestamp when the instance was first registered.' })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true, description: 'Timestamp when the instance registry row was last updated.' })\n updatedAt?: Date\n\n /*\n * ๋ˆ„๊ฐ€ ๋งŒ๋“ค๊ณ  ๋ˆ„๊ฐ€ ๊ณ ์ณค๋‚˜ โ€” **์ด ํ–‰์€ ์‚ฌ๋žŒ์ด ๋งŒ๋“ ๋‹ค**(ํ”„๋กœ๋น„์ €๋‹์€ ์‚ฌ์šฉ์ž ํ–‰์œ„)์ด๋ฏ€๋กœ ๊ทœ์•ฝ์˜\n * ํ’€์„ธํŠธ๋ฅผ ๊ฐ–๋Š”๋‹ค. ํˆฌ์˜ ํ–‰(์ž๋ฆฌยท์„ค๋น„ยท๊ณต์ •)์€ ๋ฐ˜๋Œ€๋กœ ์ธ์ œ์ŠคํŠธ๊ฐ€ ๊ทธ๋ฆฐ ๊ฒƒ์ด๋ผ ์ €์ž๊ฐ€ ์‚ฌ๋žŒ์ด ์•„๋‹ˆ๊ณ ,\n * ๊ทธ ์ €์ž๋Š” `sourceRef`+`ingestedAt` ์ด ์ด๋ฏธ ๋งํ•œ๋‹ค โ€” ๊ทธ๋ž˜์„œ ๊ทธ์ชฝ์—๋Š” ๋‘์ง€ ์•Š๋Š”๋‹ค.\n *\n * ๋น„์–ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค: ๋ถ€ํŒ… ์ž๋™ ํ”„๋กœ๋น„์ €๋‹์ฒ˜๋Ÿผ **์‚ฌ๋žŒ์ด ์—†๋Š” ๊ฒฝ๋กœ**๋กœ ๋งŒ๋“ค์–ด์ง„ ํ–‰์ด ๊ทธ๋ ‡๋‹ค.\n * ๊ทธ๋•Œ ์•„๋ฌด ์‚ฌ์šฉ์ž๋ฅผ ์ ์–ด ๋„ฃ์œผ๋ฉด ๊ฐ์‚ฌ ๊ธฐ๋ก์ด ๊ฑฐ์ง“์ด ๋œ๋‹ค.\n */\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true, description: 'The user who first provisioned this twin. Empty when it was created by a system path (boot provisioning).' })\n creator?: User\n\n @RelationId((e: TwinInstance) => e.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true, description: 'The user who last changed this twin registry row.' })\n updater?: User\n\n @RelationId((e: TwinInstance) => e.updater)\n updaterId?: string\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"event-type-split-shape.js","sourceRoot":"","sources":["../../../server/service/twin-journal/event-type-split-shape.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * **์ด ๋ฌผ์Œ์ด ใ€Œ์—ฌ๋Ÿฌ ์ข…๋ฅ˜๋ฅผ ์‹œ๊ฐ์ˆœ์œผ๋กœใ€์ธ๊ฐ€** โ€” ์ˆœ์ˆ˜ ํŒ๋‹จ๋งŒ ์—ฌ๊ธฐ ๋‘”๋‹ค.\n *\n * ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๋ถ€๋ฅด์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ž˜์„œ ์‹œํ—˜์ด ์ด ํŒŒ์ผ์„ ๊ทธ๋Œ€๋กœ ๋ถ€๋ฅผ ์ˆ˜ ์žˆ๋‹ค(๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์—†๋‹ค).\n * ํŒ๋‹จ์ด ์กฐํšŒ ์ฝ”๋“œ ์•ˆ์— ์„ž์—ฌ ์žˆ์œผ๋ฉด ๊ทธ ํŒ๋‹จ๋งŒ ํ™•์ธํ•  ๋ฐฉ๋ฒ•์ด ์—†๊ณ , ๊ทธ๋Ÿฌ๋ฉด ใ€Œ์–ด๋–ค ๋ฌผ์Œ์ด ๋‚˜๋ˆ  ๋ฌป๋Š”\n * ๊ฐˆ๋ž˜๋กœ ๊ฐ€๋Š”๊ฐ€ใ€๊ฐ€ ์•„๋ฌด๋„ ์ฝ์ง€ ๋ชปํ•˜๋Š” ๊ทœ์น™์ด ๋œ๋‹ค.\n *\n * ์‹ค์ธก ๊ทผ๊ฑฐ์™€ ๊ณ ์นจ์˜ ๋œป์€ `event-type-split.ts` ๋จธ๋ฆฌ์— ์žˆ๋‹ค.\n */\nimport { absoluteTime } from '../../engine/read-time.js'\n\n/** ์งˆ์˜๋ฅผ ๋ช‡ ๊ฐœ๊นŒ์ง€ ๋‚˜๋ˆŒ๊นŒ โ€” ๋Œ€์ƒ ร— ์ข…๋ฅ˜. ์ด ์ด์ƒ์ด๋ฉด ๋‚˜๋ˆ„๋Š” ๊ฒƒ์ด ์†ํ•ด๋‹ค. */\nexport const MAX_SPLIT = 24\n\n/** ์ข…๋ฅ˜ ๋ชฉ๋ก์˜ ์ƒํ•œ โ€” ์ด๋ณด๋‹ค ๋งŽ์œผ๋ฉด ใ€Œ์ด ์ข…๋ฅ˜๋งŒใ€์ด ์•„๋‹ˆ๋ผ ์‚ฌ์‹ค์ƒ ์ „์ฒด๋‹ค. */\nconst MAX_TYPES = 12\n\nexport interface SplitShape {\n eventTypes: string[]\n /**\n * ๊ณต์ • ๋‹จ๊ณ„ ํ•˜๋‚˜๋กœ ์ขํžŒ ๊ฒฝ์šฐ โ€” ๊ทธ ๊ฐ’์„ ๊ฐˆ๋ž˜๋งˆ๋‹ค ํ•จ๊ป˜ ๊ฑด๋‹ค.\n *\n * ์ด ํ•„ํ„ฐ๋ฅผ ๋งŒ๋‚˜๋ฉด ๊ฐˆ๋ž˜๋ฅผ ํฌ๊ธฐํ•˜๋˜ ๊ฒƒ์„ ๊ณ ์ณค๋‹ค(2026-08-29). ์›์žฅ์€ ์ข…๋ฅ˜๋ฅผ ๋‹ด์•„ ๋ฌป๊ณ  ๊ทธ ์œ„์— ๋‹จ๊ณ„\n * ์นฉ์„ ๊ฒน์น˜๋Š”๋ฐ, ์นฉ์„ ๊ณ ๋ฅธ ์ˆœ๊ฐ„ ์˜ˆ์ „ ๊ฒฝ๋กœ๋กœ ๋–จ์–ด์ ธ **๊ณ ๋ฅด์ง€ ์•Š์€ ์ชฝ์ด ๋” ๋นจ๋ž๋‹ค.**\n *\n * ๋‹จ๊ณ„ ์ปฌ๋Ÿผ์—๋Š” ์ƒ‰์ธ์ด ์—†๋‹ค. ๊ทธ๋ž˜๋„ ๋А๋ ค์ง€์ง€ ์•Š๋Š”๋‹ค โ€” ์ข…๋ฅ˜ ์ •ํ™•์ผ์น˜๊ฐ€ ์ƒ‰์ธ์œผ๋กœ ์‹œ๊ฐ ์ˆœ์„œ๊นŒ์ง€ ์ฃผ๊ณ ,\n * ๋‹จ๊ณ„๋Š” ๊ทธ ์•ˆ์—์„œ ํ–‰๋งˆ๋‹ค ํ™•์ธํ•˜๋Š” ์กฐ๊ฑด์ด๋‹ค(๊ฑท๋Š” ํ–‰์ด ๊ทธ ์ข…๋ฅ˜์˜ ๊ฒƒ์œผ๋กœ ์ด๋ฏธ ์ขํ˜€์ ธ ์žˆ๋‹ค).\n */\n bizStep?: string\n untilTime?: Date\n fromTime?: Date\n}\n\n/**\n * ์ด ๋ฌผ์Œ์ด ใ€Œ์—ฌ๋Ÿฌ ์ข…๋ฅ˜๋ฅผ ์‹œ๊ฐ์ˆœ์œผ๋กœใ€์ธ๊ฐ€ โ€” ์•„๋‹ˆ๋ฉด `null`.\n *\n * ๋ฐ›๋Š” ๋ชจ์–‘\n * `eventType` ์„ `in` ์œผ๋กœ ยท ์‹œ๊ฐ ์ƒํ•œ์ด๋‚˜ ๊ตฌ๊ฐ„ ยท ์‹œ๊ฐ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ\n *\n * ๋ณด๋‚ด๋Š” ๋ชจ์–‘(์ผ๋ฐ˜ ๊ฒฝ๋กœ๋กœ)\n * ์ž์œ  ๊ฒ€์ƒ‰์–ด ยท ๊ทธ ๋ฐ–์˜ ํ•„ํ„ฐ(์ถ•ยท์ƒ๊ด€ ์‹๋ณ„์žยท์—…๋ฌด ๋‹จ๊ณ„) ยท ๊ทธ ๋ฐ–์˜ ์ •๋ ฌ์ด๋‚˜ ์—ฐ์‚ฐ์ž\n */\nexport function splitShape(params: any, sortings: any[]): SplitShape | null {\n const filters: any[] = Array.isArray(params?.filters) ? params.filters : []\n if (typeof params?.search === 'string' && params.search.trim()) return null\n if (sortings.length !== 1 || sortings[0]?.name !== 'eventTime' || sortings[0]?.desc !== true) return null\n\n let eventTypes: string[] | undefined\n let untilTime: Date | undefined\n let fromTime: Date | undefined\n let bizStep: string | undefined\n for (const f of filters) {\n if (f?.name === 'eventType') {\n if (f.operator !== 'in' || !Array.isArray(f.value)) return null\n const types: string[] = f.value.map((v: unknown) => String(v ?? '').trim()).filter((t: string) => !!t)\n /* ํ•˜๋‚˜๋ฉด ๋‚˜๋ˆŒ ๊ฒƒ์ด ์—†๋‹ค(์ด๋ฏธ ์ •ํ™•์ผ์น˜๋ผ ์ƒ‰์ธ์„ ํƒ„๋‹ค). ๋„ˆ๋ฌด ๋งŽ์œผ๋ฉด ์‚ฌ์‹ค์ƒ ์ „์ฒด๋‹ค. */\n if (types.length < 2 || types.length > MAX_TYPES) return null\n if (eventTypes) return null\n eventTypes = [...new Set(types)]\n } else if (f?.name === 'bizStep') {\n /* ํ•˜๋‚˜๋กœ ์ขํžŒ ๊ฒฝ์šฐ๋งŒ ๋ฐ›๋Š”๋‹ค โ€” ์—ฌ๋Ÿฌ ๊ฐ’์ด๋ฉด ์ข…๋ฅ˜ ร— ๋‹จ๊ณ„๋กœ ๊ฐˆ๋ž˜๊ฐ€ ๊ณฑํ•ด์ง„๋‹ค. */\n if (f.operator !== 'eq') return null\n const v = String(f.value ?? '').trim()\n if (!v) return null\n if (bizStep) return null\n bizStep = v\n } else if (f?.name === 'eventTime') {\n if (f.operator === 'lte' || f.operator === 'lt') {\n untilTime = absoluteTime(f.value) ?? undefined\n if (!untilTime) return null\n } else if (f.operator === 'between' && Array.isArray(f.value)) {\n fromTime = absoluteTime(f.value[0]) ?? undefined\n untilTime = absoluteTime(f.value[1]) ?? undefined\n if (!fromTime || !untilTime) return null\n } else return null\n } else return null\n }\n return eventTypes ? { eventTypes, untilTime, fromTime, bizStep } : null\n}\n\n/**\n * **๋‚˜๋ˆ  ๋ฌผ์€ ๊ฐˆ๋ž˜๋“ค์„ ํ•ฉ์ณ ์•ž์—์„œ `limit` ๊ฐœ** โ€” ์ด ๊ทœ์œจ์ด ์ •ํ™•์„ฑ์˜ ๊ทผ๊ฑฐ๋‹ค.\n *\n * โ”€โ”€ ์™œ ๊ฐˆ๋ž˜๋งˆ๋‹ค `limit` ๊นŒ์ง€ ๋ฐ›์•„์•ผ ํ•˜๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๊ฐˆ๋ž˜๋งˆ๋‹ค `limit` ๊ฐœ๋ฅผ ๋ฐ›์•„ ํ•ฉ์น˜๋ฉด, ํ•ฉ์นœ ๊ฒƒ์˜ ์•ž `limit` ๊ฐœ๋Š” **์ „์ฒด์—์„œ๋„** ์•ž `limit` ๊ฐœ๋‹ค.\n * ์–ด๋–ค ๊ฐˆ๋ž˜์—์„œ ๋น ์ง„ ํ–‰์€ ๊ทธ ๊ฐˆ๋ž˜์˜ `limit` ๋ฒˆ์งธ๋ณด๋‹ค ๋’ค์ด๊ณ , ์šฐ๋ฆฌ๋Š” ์ „์ฒด์—์„œ `limit` ๊ฐœ๋งŒ ์ทจํ•˜๋ฏ€๋กœ\n * ๊ทธ ํ–‰์ด ์ด ํŽ˜์ด์ง€์— ๋“ค์–ด์˜ฌ ์ˆ˜ ์—†๋‹ค.\n *\n * ๊ฐˆ๋ž˜๋งˆ๋‹ค **๋” ์ ๊ฒŒ** ๋ฐ›์œผ๋ฉด ๊ทธ ์„ฑ์งˆ์ด ๊นจ์ง„๋‹ค. ํ•œ ๊ฐˆ๋ž˜๊ฐ€ ์•ž์„ ๋‹ค ์ฐจ์ง€ํ•˜๋Š” ๊ฒฝ์šฐ\n * (์ข…๋ฅ˜ A ์˜ ๋งˆ์ง€๋ง‰์ด ์ข…๋ฅ˜ B ์˜ ์ฒซ์งธ๋ณด๋‹ค ์•ž์„ ๋‹ค) ๊ทธ ๊ฐˆ๋ž˜์—์„œ ๋ชป ๋ฐ›์€ ๊ฒƒ์ด ๋น ์ง€๊ณ , ๊ฒฐ๊ณผ๋Š” ๊ตฌ๊ฐ„์˜\n * ์•ž๋ถ€๋ถ„๋งŒ ๊ณ„์‚ฐํ•œ ๊ฒƒ์ด ๋œ๋‹ค โ€” ๊ทธ๋Ÿฐ๋ฐ ํ™”๋ฉด์€ ใ€Œ์ผ๋ถ€๋งŒ ์ฝ์—ˆ๋‹คใ€๊ณ ๋งŒ ๋งํ•˜๊ณ  ์–ด๋А ๋ถ€๋ถ„์ธ์ง€๋Š” ๋งํ•˜์ง€ ๋ชปํ•œ๋‹ค.\n * (2026-08-28 ยท UX ๋ ˆ์ธ์ด ๋ฏธ๋ฆฌ ์งš์–ด ์ค€ ํ•จ์ •์ด๋‹ค.)\n *\n * ๊ทธ๋ž˜์„œ ์ด ํ•จ์ˆ˜๋Š” **`limit` ๋ฏธ๋งŒ์œผ๋กœ ๋ฐ›์€ ๊ฐˆ๋ž˜๊ฐ€ ์žˆ์œผ๋ฉด ๊ทธ๊ฒƒ์„ ๋งํ•œ๋‹ค** โ€” ๋ถ€๋ฅด๋Š” ์ชฝ์ด ๊ทธ ์ƒํƒœ๋กœ\n * ๋‹ตํ•˜์ง€ ์•Š๊ฒŒ.\n */\nexport function mergeStreams<T>(\n streams: readonly T[][],\n limit: number,\n /** ์•ž์— ์™€์•ผ ํ•˜๋Š” ๊ฒƒ์ด ์Œ์ˆ˜ โ€” `Array.prototype.sort` ์™€ ๊ฐ™์€ ๊ทœ์•ฝ. */\n compare: (a: T, b: T) => number\n): { items: T[]; capped: boolean; underfilled: boolean } {\n const underfilled = streams.some(s => s.length > limit)\n const merged = streams.flat().sort(compare)\n return {\n items: merged.slice(0, limit),\n /* ํ•ฉ์นœ ๊ฒƒ์ด ์ƒํ•œ์„ ๋„˜์—ˆ์œผ๋ฉด ๋” ์žˆ์—ˆ๋‹ค๋Š” ๋œป์ด๋‹ค โ€” ์ž˜๋ž๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋ถ€๋ฅด๋Š” ์ชฝ์ด ๋งํ•ด์•ผ ํ•œ๋‹ค. */\n capped: merged.length > limit || streams.some(s => s.length >= limit),\n /* ๊ฐˆ๋ž˜๊ฐ€ ์ƒํ•œ๋ณด๋‹ค ๋งŽ์ด ๋ฐ›์•„ ์™”๋‹ค โ€” ์žˆ์„ ์ˆ˜ ์—†๋Š” ์ผ์ด๋ฏ€๋กœ ๋ถ€๋ฅด๋Š” ์ชฝ์ด ์•Œ์•„์•ผ ํ•œ๋‹ค. */\n underfilled\n }\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"event-type-split.js","sourceRoot":"","sources":["../../../server/service/twin-journal/event-type-split.ts"],"names":[],"mappings":";;AAoDA,gDAwEC;AA5HD,iDAAqD;AAErD,+DAAuD;AACvD,4DAAwD;AACxD,2EAAwE;AA0CxE;;;;;GAKG;AACI,KAAK,UAAU,kBAAkB,CACtC,QAAgB,EAChB,WAAqB,EACrB,KAAiB,EACjB,KAAa;AACb,mEAAmE;AACnE,QAA2B,EAC3B,KAAc;IAEd,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,CAAA;IAC1D,IAAI,CAAC,KAAK,IAAI,KAAK,GAAG,qCAAS;QAAE,OAAO,IAAI,CAAA;IAE5C,IAAI,MAAM,GAA8C,IAAI,CAAA;IAC5D,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAA;QAChC,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAA;IAC1B,CAAC;IAED,MAAM,IAAI,GAAkB,EAAE,CAAA;IAC9B,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACrC,KAAK,MAAM,SAAS,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;YACzC,MAAM,EAAE,GAAG,IAAA,qBAAa,EAAC,yBAAS,CAAC;iBAChC,kBAAkB,CAAC,GAAG,CAAC;iBACvB,KAAK,CAAC,sBAAsB,EAAE,EAAE,QAAQ,EAAE,CAAC;iBAC3C,QAAQ,CAAC,4BAA4B,EAAE,EAAE,UAAU,EAAE,CAAC;gBACvD,kDAAkD;iBACjD,QAAQ,CAAC,0BAA0B,EAAE,EAAE,SAAS,EAAE,CAAC,CAAA;YACtD,qDAAqD;YACrD,IAAI,KAAK,CAAC,OAAO;gBAAE,EAAE,CAAC,QAAQ,CAAC,sBAAsB,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;YAClF,IAAI,KAAK,CAAC,QAAQ;gBAAE,EAAE,CAAC,QAAQ,CAAC,0BAA0B,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;YACzF,IAAI,KAAK,CAAC,SAAS;gBAAE,EAAE,CAAC,QAAQ,CAAC,2BAA2B,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAA;YAC7F,IAAI,MAAM,EAAE,CAAC;gBACX,EAAE,CAAC,QAAQ,CAAC,wDAAwD,QAAQ,cAAc,EAAE;oBAC1F,KAAK,EAAE,MAAM,CAAC,EAAE;oBAChB,MAAM,EAAE,MAAM,CAAC,GAAG;iBACnB,CAAC,CAAA;YACJ,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,EAAE;iBAClB,OAAO,CAAC,aAAa,EAAE,MAAM,CAAC;iBAC9B,UAAU,CAAC,KAAK,QAAQ,EAAE,EAAE,MAAM,CAAC;iBACnC,KAAK,CAAC,KAAK,CAAC;iBACZ,OAAO,EAAE;iBACT,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;YACpB,oDAAoD;YACpD,IAAI,CAAC,IAAI;gBAAE,OAAO,IAAI,CAAA;YACtB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACjB,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,MAAM,MAAM,GAAG,IAAI;SAChB,IAAI,EAAE;SACN,IAAI,CAAC,CAAC,CAAM,EAAE,CAAM,EAAE,EAAE;QACvB,kEAAkE;QAClE,MAAM,EAAE,GAAI,CAAC,CAAC,SAAkB,CAAC,OAAO,EAAE,GAAI,CAAC,CAAC,SAAkB,CAAC,OAAO,EAAE,CAAA;QAC5E,IAAI,EAAE,KAAK,CAAC;YAAE,OAAO,EAAE,CAAA;QACvB,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAA;QACrB,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAA;QACrB,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACrC,CAAC,CAAC;SACD,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;IAElB,MAAM,IAAI,GAAQ,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAC3C,MAAM,UAAU,GACd,MAAM,CAAC,MAAM,KAAK,KAAK,IAAI,IAAI,EAAE,SAAS,YAAY,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,SAAS;QACxF,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAClD,CAAC,CAAC,SAAS,CAAA;IAEf,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAA;AACtC,CAAC;AAED,+DAA+D;AAC/D,SAAS,gBAAgB,CAAC,EAAQ,EAAE,GAAoB;IACtD,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;AAC7E,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAc;IACtC,IAAI,MAAe,CAAA;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAA;IACxE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IAC9D,MAAM,EAAE,GAAG,IAAA,2BAAY,EAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;IAClC,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;IACrB,IAAI,CAAC,EAAE,IAAI,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAO,GAAG,KAAK,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAA;IAC5E,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,CAAA;AACpB,CAAC","sourcesContent":["import { getRepository } from '@things-factory/shell'\n\nimport { TwinEvent } from '../twin-event/twin-event.js'\nimport { absoluteTime } from '../../engine/read-time.js'\nimport { MAX_SPLIT, type SplitShape } from './event-type-split-shape.js'\n\n/*\n * **์—ฌ๋Ÿฌ ์ข…๋ฅ˜๋ฅผ ์‹œ๊ฐ์ˆœ์œผ๋กœ โ€” ์ข…๋ฅ˜๋ฅผ ํ•˜๋‚˜์”ฉ ๋‚˜๋ˆ  ๋ฌป๋Š”๋‹ค** (2026-08-28 ์‹ค์ธก).\n *\n * โ”€โ”€ ๋ฌด์—‡์ด ๋А๋ ธ๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์—๋„ˆ์ง€ ์›์žฅ์€ ใ€Œ์ด ์—ฌ๋Ÿ ์ข…๋ฅ˜๋ฅผ ์‹œ๊ฐ ๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ 50๊ฑดใ€์„ ๋ฌป๋Š”๋‹ค. ๊ทธ ๋ชจ์–‘์—์„œ sqlite ๋Š” ์ข…๋ฅ˜ ์ƒ‰์ธ์„\n * **๋ฒ„๋ฆฐ๋‹ค**:\n *\n * ์ข…๋ฅ˜ IN + ์‹œ๊ฐ์ˆœ SEARCH USING INDEX ix_twin_event_1 (domain, instance) 37.181์ดˆ ยท ๊ฒฐ๊ณผ 0๊ฑด\n * ๊ฐ™์€ ์กฐ๊ฑด ยท ์ •๋ ฌ ์—†์Œ SEARCH USING INDEX ix_twin_event_7 (โ€ฆ, event_type=?) 0.003์ดˆ\n * ์ข…๋ฅ˜ ํ•˜๋‚˜ + ์‹œ๊ฐ์ˆœ SEARCH USING INDEX ix_twin_event_7 (โ€ฆ, event_type=?) 0.003์ดˆ\n *\n * ์ •๋ ฌ์„ ๋ถ™์ด๋Š” ์ˆœ๊ฐ„ ์—ฌ๋Ÿฌ ์ข…๋ฅ˜์˜ ์ˆœ์„œ๋ฅผ ํ•ฉ์น  ๋ฐฉ๋ฒ•์ด ์—†์–ด, ์‹œ๊ฐ ์ƒ‰์ธ์œผ๋กœ 337๋งŒ ํ–‰์„ ๊ฑธ์œผ๋ฉฐ ํ–‰๋งˆ๋‹ค\n * ์ข…๋ฅ˜๋ฅผ ํ™•์ธํ•œ๋‹ค. ์Šนํ™”ํ‘ธ๋“œ์— ์—๋„ˆ์ง€ ์‚ฌ๊ฑด์€ 0๊ฑด์ด๋‹ค โ€” **์—†๋Š” ๊ฒƒ์„ ์ฐพ๋А๋ผ 37์ดˆ**๋ฅผ ์“ด๋‹ค.\n *\n * 360 ์ด๋ ฅ์ด 64์ดˆ์˜€๋˜ ๊ฒƒ๊ณผ ๊ฐ™์€ ๋ถ€๋ฅ˜๋‹ค: **๊ฑฐ๋ฅด๋Š” ์ถ•๊ณผ ์ •๋ ฌ ์ถ•์ด ์–ด๊ธ‹๋‚œ๋‹ค.**\n *\n * โ”€โ”€ ๊ณ ์นจ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ข…๋ฅ˜๋ฅผ **์ •ํ™•์ผ์น˜๋กœ ํ•˜๋‚˜์”ฉ** ๋ฌผ์œผ๋ฉด ์ƒ‰์ธ์ด ์‹œ๊ฐ ์ˆœ์„œ๊นŒ์ง€ ๊ทธ๋Œ€๋กœ ์ค€๋‹ค(์ •๋ ฌ์ด ์‚ฌ๋ผ์ง„๋‹ค). ์—ฌ๋Ÿ ์ข…๋ฅ˜๋ฉด\n * ์งˆ์˜ ์—ฌ๋Ÿ ๊ฐœ์ด๊ณ  ๊ฐ 0.003์ดˆ๋‹ค. ๋ฐ›์€ ๊ฒƒ์„ ์‹œ๊ฐ์ˆœ์œผ๋กœ ํ•ฉ์ณ ํ•œ ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ ๋‹ค.\n *\n * ์ƒˆ ์ƒ‰์ธ๋„, ์ƒˆ ํ…Œ์ด๋ธ”๋„ ํ•„์š” ์—†๋‹ค โ€” ์žˆ๋Š” ์ƒ‰์ธ์„ ์“ฐ๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ด ์ „๋ถ€๋‹ค.\n *\n * โ”€โ”€ ์ข๊ฒŒ ์žก๋Š”๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ด ๋ชจ์–‘์ด ์•„๋‹Œ ๋ฌผ์Œ์€ ๋‹ตํ•˜์ง€ ์•Š๊ณ (`null`) ์ €๋„์˜ ์ผ๋ฐ˜ ๊ฒฝ๋กœ๋กœ ๋ณด๋‚ธ๋‹ค. ์–ต์ง€๋กœ ๋‹ตํ•˜๋ฉด ๋ชฉ๋ก์ด ์•Œ๋ฆฌ์ง€\n * ์•Š๊ณ  ๋‹ฌ๋ผ์ง„๋‹ค.\n *\n * โ”€โ”€ โ˜… **์ด ๊ฐˆ๋ž˜๋ฅผ ๊ฑท์„ ์กฐ๊ฑด** โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์•ฑ์—์„œ ์ข…๋ฅ˜๋ฅผ ์—ฌ๋Ÿฌ ๊ฐ’์œผ๋กœ ๋ณด๋‚ด๋Š” ๊ณณ์€ **์—๋„ˆ์ง€ ์›์žฅ ํ•œ ๊ณณ๋ฟ**์ด๋‹ค(2026-08-28 ํ™•์ธ). ๊ทธ ํ™”๋ฉด์ด\n * ์ข…๋ฅ˜๋ฅผ ํ•˜๋‚˜์”ฉ ๊ณ ๋ฅด๋Š” ๋ชจ์–‘์œผ๋กœ ๋ฐ”๋€Œ๋ฉด ์ด ๊ฐˆ๋ž˜๋ฅผ ๋ถ€๋ฅด๋Š” ๋ฐ๊ฐ€ ์—†์–ด์ง„๋‹ค โ€” ๊ทธ๋•Œ **์ง€์šด๋‹ค.**\n *\n * ๋ถ€๋ฅด๋Š” ๋ฐ๊ฐ€ ์—†๋Š” ๊ฐˆ๋ž˜๋ฅผ ๋“ค๊ณ  ์žˆ์œผ๋ฉด, ๊ทธ๊ฒƒ์ด ๋ฌด์–ธ๊ฐ€๋ฅผ ๋ฐ›์ณ ์ฃผ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋ฉด์„œ ์‹ค์ œ๋กœ๋Š” ์•„๋ฌด๊ฒƒ๋„\n * ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ง€๊ธˆ ์‚ด๋ ค ๋‘๋Š” ์ด์œ ๋Š” ํ•˜๋‚˜๋‹ค: ์‹ค ๊ณ ๊ฐ ํŠธ์œˆ์—์„œ 37์ดˆ ์งˆ์˜๊ฐ€ ๋Œ๊ณ  ์žˆ๊ณ  ํ™”๋ฉด ์ˆ˜์ •์€\n * ๋‹ค๋ฅธ ๋ ˆ์ธ์˜ ์ผ์ด๋‹ค.\n */\n\nexport interface SplitPage {\n items: TwinEvent[]\n nextCursor?: string\n}\n\n/**\n * ๋‚˜๋ˆ  ๋ฌป๊ณ  ํ•ฉ์ณ ํ•œ ํŽ˜์ด์ง€ โ€” ๋‹ตํ•  ์ˆ˜ ์—†์œผ๋ฉด `null`.\n *\n * ์ด์–ด ์ฝ๊ธฐ ์ง€์ ์€ **๋ชจ๋“  ๊ฐˆ๋ž˜์— ๊ฐ™์ด** ๊ฑด๋‹ค. ๊ทธ๋ž˜์•ผ ํ•ฉ์นœ ๊ฒฐ๊ณผ๊ฐ€ ์ปค์„œ ์•„๋ž˜์—์„œ๋งŒ ๋‚˜์˜จ๋‹ค โ€” ๊ฐˆ๋ž˜๋งˆ๋‹ค\n * ๋‹ค๋ฅด๊ฒŒ ๊ฑธ๋ฉด ์–ด๋–ค ์ข…๋ฅ˜๋Š” ์ด๋ฏธ ์ง€๋‚˜๊ฐ„ ๊ตฌ๊ฐ„์„ ๋‹ค์‹œ ๋‚ธ๋‹ค.\n */\nexport async function eventTypeSplitPage(\n domainId: string,\n instanceIds: string[],\n shape: SplitShape,\n limit: number,\n /** ๋™์‹œ๊ฐ์„ ๊ฐ€๋ฆฌ๋Š” ์ถ• โ€” ํŠธ์œˆ ํ•˜๋‚˜๋ฉด `revision`, ์—ฌ๋Ÿฟ์ด๋ฉด ๊ธฐ๋ณธํ‚ค(ยง`cursorTiebreak`). */\n tiebreak: 'revision' | 'id',\n after?: string\n): Promise<SplitPage | null> {\n const pairs = instanceIds.length * shape.eventTypes.length\n if (!pairs || pairs > MAX_SPLIT) return null\n\n let cursor: { at: Date; tie: string | number } | null = null\n if (after) {\n cursor = decodeCursorPair(after)\n if (!cursor) return null\n }\n\n const rows: TwinEvent[][] = []\n for (const instanceId of instanceIds) {\n for (const eventType of shape.eventTypes) {\n const qb = getRepository(TwinEvent)\n .createQueryBuilder('e')\n .where('e.domain = :domainId', { domainId })\n .andWhere('e.instanceId = :instanceId', { instanceId })\n /* **์ •ํ™•์ผ์น˜**๊ฐ€ ์š”์ ์ด๋‹ค โ€” ๊ทธ๋ž˜์•ผ ์ƒ‰์ธ์ด ์‹œ๊ฐ ์ˆœ์„œ๊นŒ์ง€ ์ค€๋‹ค(ยง ์œ„ ์‹ค์ธก). */\n .andWhere('e.eventType = :eventType', { eventType })\n /* ๋‹จ๊ณ„๋Š” ์ƒ‰์ธ์ด ์•„๋‹ˆ๋ผ ํ–‰ ์กฐ๊ฑด์ด๋‹ค โ€” ์ข…๋ฅ˜ ์ •ํ™•์ผ์น˜๊ฐ€ ์ด๋ฏธ ๊ฑท๋Š” ๋ฒ”์œ„๋ฅผ ์ขํ˜€ ๋†“์•˜๋‹ค. */\n if (shape.bizStep) qb.andWhere('e.bizStep = :bizStep', { bizStep: shape.bizStep })\n if (shape.fromTime) qb.andWhere('e.eventTime >= :fromTime', { fromTime: shape.fromTime })\n if (shape.untilTime) qb.andWhere('e.eventTime <= :untilTime', { untilTime: shape.untilTime })\n if (cursor) {\n qb.andWhere(`(e.eventTime < :curAt OR (e.eventTime = :curAt AND e.${tiebreak} < :curTie))`, {\n curAt: cursor.at,\n curTie: cursor.tie\n })\n }\n const page = await qb\n .orderBy('e.eventTime', 'DESC')\n .addOrderBy(`e.${tiebreak}`, 'DESC')\n .limit(limit)\n .getMany()\n .catch(() => null)\n /* ํ•œ ๊ฐˆ๋ž˜๋ผ๋„ ๋ชป ์ฝ์œผ๋ฉด ํ•ฉ์นœ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐ˜์ชฝ์ด๋‹ค โ€” ๋ฐ˜์ชฝ์„ ์ „๋ถ€์ธ ๊ฒƒ์ฒ˜๋Ÿผ ๋‚ด์ง€ ์•Š๋Š”๋‹ค. */\n if (!page) return null\n rows.push(page)\n }\n }\n\n /*\n * ํ•ฉ์นœ๋‹ค. ๊ฐˆ๋ž˜๋งˆ๋‹ค `limit` ๊นŒ์ง€ ๋ฐ›์•˜์œผ๋ฏ€๋กœ, ํ•ฉ์ณ์„œ ์•ž์˜ `limit` ๊ฐœ๋Š” **์ „์ฒด์—์„œ๋„** ์•ž์˜ `limit` ๊ฐœ๋‹ค\n * (๊ฐ ๊ฐˆ๋ž˜๊ฐ€ ์ž๊ธฐ ์•ˆ์—์„œ ์ •๋ ฌ๋ผ ์žˆ๊ณ  ๊ทธ๋ณด๋‹ค ์•ž์„  ๊ฒƒ์„ ๋น ๋œจ๋ฆด ์ˆ˜ ์—†๋‹ค).\n */\n const merged = rows\n .flat()\n .sort((a: any, b: any) => {\n /* `getMany` ๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ฃผ๋ฏ€๋กœ ์‹œ๊ฐ์ด ์ด๋ฏธ ๋‚ ์งœ๋‹ค โ€” ๊ฐ์‹ธ๋ฉด ๋“œ๋ผ์ด๋ฒ„ ๊ฐ’์„ ์†์œผ๋กœ ์ฝ๋Š” ๋ชจ์–‘์ด ๋œ๋‹ค. */\n const at = (b.eventTime as Date).getTime() - (a.eventTime as Date).getTime()\n if (at !== 0) return at\n const x = a[tiebreak]\n const y = b[tiebreak]\n return x === y ? 0 : x < y ? 1 : -1\n })\n .slice(0, limit)\n\n const last: any = merged[merged.length - 1]\n const nextCursor =\n merged.length === limit && last?.eventTime instanceof Date && last[tiebreak] !== undefined\n ? encodeCursorPair(last.eventTime, last[tiebreak])\n : undefined\n\n return { items: merged, nextCursor }\n}\n\n/** ์ €๋„ ๊ฒฝ๋กœ์™€ ๊ฐ™์€ ์ปค์„œ โ€” `[eventTime, ๋™์‹œ๊ฐ ์ถ•]`(ยง`buildNextCursor`). */\nfunction encodeCursorPair(at: Date, tie: string | number): string {\n return Buffer.from(JSON.stringify([at, tie]), 'utf8').toString('base64url')\n}\n\nfunction decodeCursorPair(cursor: string): { at: Date; tie: string | number } | null {\n let values: unknown\n try {\n values = JSON.parse(Buffer.from(cursor, 'base64url').toString('utf8'))\n } catch {\n return null\n }\n if (!Array.isArray(values) || values.length !== 2) return null\n const at = absoluteTime(values[0])\n const tie = values[1]\n if (!at || (typeof tie !== 'string' && typeof tie !== 'number')) return null\n return { at, tie }\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/twin-journal/index.ts"],"names":[],"mappings":";;;AAAA,mEAA0D;AAE7C,QAAA,SAAS,GAAG,CAAC,wCAAgB,CAAC,CAAA","sourcesContent":["import { TwinJournalQuery } from './twin-journal-query.js'\n\nexport const resolvers = [TwinJournalQuery]\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"journal-order.js","sourceRoot":"","sources":["../../../server/service/twin-journal/journal-order.ts"],"names":[],"mappings":";;AAMA,oCAaC;AAnBD;;;;;GAKG;AACH,SAAgB,YAAY,CAAC,CAK5B;IAIC,iEAAiE;IACjE,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,IAAI,IAAI,IAAI,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAA;IACxD,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,YAAY,IAAI,IAAI,IAAI,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC;QAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;IAC5F,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;AAChD,CAAC","sourcesContent":["/**\n * ์ง€๋‚œ ๊ธฐ๋ก ์กฐํšŒ์˜ ์ •๋ ฌ ์ถ• โ€” **๋ถ€๋ฅด๋Š” ์ชฝ์ด ๋ฌด์—‡์œผ๋กœ ๋ฌผ์—ˆ๋Š”์ง€์— ๋งž์ถ˜๋‹ค.**\n *\n * ๋ฆฌ์กธ๋ฒ„ ์•ˆ์— ๋‘๋ฉด ์ด ๊ทœ์น™์„ ํ™•์ธํ•  ๋ฐฉ๋ฒ•์ด ์†Œ์Šค๋ฅผ ๊ธ€์ž๋กœ ์ „์ˆ˜ ์กฐํšŒํ•˜๋Š” ๊ฒƒ๋ฟ์ด๋‹ค. ๊ทœ์น™ ์ž์ฒด๋ฅผ ๋ถ€๋ฅผ ์ˆ˜ ์žˆ๊ฒŒ\n * ๋ฐ–์œผ๋กœ ๋บ€๋‹ค(`test/journal-order-axis.test.ts`).\n */\nexport function journalOrder(q: {\n untilTime?: string | null\n fromTime?: string | null\n fromRevision?: number | null\n toRevision?: number | null\n}): {\n eventTime?: 'DESC'\n revision: 'DESC'\n} {\n /* `revision` ์œผ๋กœ ๋ฌผ์—ˆ์œผ๋ฉด ๊ทธ ์ˆœ์„œ๊ฐ€ ๋ฌผ์Œ์˜ ๋‹ต์ด๋‹ค. ๊ฑฐ๋ฅด๋Š” ์ถ•๊ณผ ์ •๋ ฌ ์ถ•์„ ๋งž์ถ”๋Š” ๊ทœ์น™๊ณผ๋„ ๊ฐ™๋‹ค. */\n const byTime = q.untilTime != null || q.fromTime != null\n if (!byTime && (q.fromRevision != null || q.toRevision != null)) return { revision: 'DESC' }\n return { eventTime: 'DESC', revision: 'DESC' }\n}\n"]}