@things-factory/headless-twin 10.0.18 โ†’ 10.1.0

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 (331) hide show
  1. package/dist-server/engine/canonical-ingest.d.ts +10 -1
  2. package/dist-server/engine/canonical-ingest.js +110 -33
  3. package/dist-server/engine/canonical-ingest.js.map +1 -1
  4. package/dist-server/engine/event-time.d.ts +25 -0
  5. package/dist-server/engine/event-time.js +98 -0
  6. package/dist-server/engine/event-time.js.map +1 -0
  7. package/dist-server/engine/index.d.ts +2 -0
  8. package/dist-server/engine/index.js +23 -0
  9. package/dist-server/engine/index.js.map +1 -1
  10. package/dist-server/engine/ingest-dedupe.d.ts +18 -6
  11. package/dist-server/engine/ingest-dedupe.js +201 -15
  12. package/dist-server/engine/ingest-dedupe.js.map +1 -1
  13. package/dist-server/engine/ingest-health.d.ts +60 -1
  14. package/dist-server/engine/ingest-health.js +43 -8
  15. package/dist-server/engine/ingest-health.js.map +1 -1
  16. package/dist-server/engine/kpi-fold.d.ts +19 -0
  17. package/dist-server/engine/kpi-fold.js +4 -1
  18. package/dist-server/engine/kpi-fold.js.map +1 -1
  19. package/dist-server/engine/kpi-query.js +23 -3
  20. package/dist-server/engine/kpi-query.js.map +1 -1
  21. package/dist-server/engine/oee-accumulator.d.ts +35 -2
  22. package/dist-server/engine/oee-accumulator.js +56 -4
  23. package/dist-server/engine/oee-accumulator.js.map +1 -1
  24. package/dist-server/engine/twin-engine.d.ts +72 -3
  25. package/dist-server/engine/twin-engine.js +118 -5
  26. package/dist-server/engine/twin-engine.js.map +1 -1
  27. package/dist-server/index.js +21 -0
  28. package/dist-server/index.js.map +1 -1
  29. package/dist-server/migrations/1786600000000-RenameOperatoMesAdapterType.d.ts +5 -0
  30. package/dist-server/migrations/1786600000000-RenameOperatoMesAdapterType.js +66 -0
  31. package/dist-server/migrations/1786600000000-RenameOperatoMesAdapterType.js.map +1 -0
  32. package/dist-server/migrations/1786700000000-AddDispatchRetryColumns.d.ts +5 -0
  33. package/dist-server/migrations/1786700000000-AddDispatchRetryColumns.js +79 -0
  34. package/dist-server/migrations/1786700000000-AddDispatchRetryColumns.js.map +1 -0
  35. package/dist-server/migrations/index.js +5 -1
  36. package/dist-server/migrations/index.js.map +1 -1
  37. package/dist-server/routes.js +19 -16
  38. package/dist-server/routes.js.map +1 -1
  39. package/dist-server/service/actuation/actuation-advisor.d.ts +60 -0
  40. package/dist-server/service/actuation/actuation-advisor.js +53 -0
  41. package/dist-server/service/actuation/actuation-advisor.js.map +1 -0
  42. package/dist-server/service/actuation/actuation-outcome.d.ts +52 -0
  43. package/dist-server/service/actuation/actuation-outcome.js +34 -0
  44. package/dist-server/service/actuation/actuation-outcome.js.map +1 -0
  45. package/dist-server/service/actuation/actuation-rule-resolver.d.ts +19 -0
  46. package/dist-server/service/actuation/actuation-rule-resolver.js +161 -0
  47. package/dist-server/service/actuation/actuation-rule-resolver.js.map +1 -0
  48. package/dist-server/service/actuation/actuation-rule.d.ts +55 -0
  49. package/dist-server/service/actuation/actuation-rule.js +130 -0
  50. package/dist-server/service/actuation/actuation-rule.js.map +1 -0
  51. package/dist-server/service/actuation/approval-gateway.d.ts +20 -0
  52. package/dist-server/service/actuation/approval-gateway.js +14 -0
  53. package/dist-server/service/actuation/approval-gateway.js.map +1 -0
  54. package/dist-server/service/actuation/catch-up-effects.d.ts +16 -0
  55. package/dist-server/service/actuation/catch-up-effects.js +120 -0
  56. package/dist-server/service/actuation/catch-up-effects.js.map +1 -0
  57. package/dist-server/service/actuation/command-dispatcher.d.ts +230 -0
  58. package/dist-server/service/actuation/command-dispatcher.js +269 -0
  59. package/dist-server/service/actuation/command-dispatcher.js.map +1 -0
  60. package/dist-server/service/actuation/command-store.d.ts +11 -0
  61. package/dist-server/service/actuation/command-store.js +219 -0
  62. package/dist-server/service/actuation/command-store.js.map +1 -0
  63. package/dist-server/service/actuation/dispatch-after-approval.d.ts +11 -0
  64. package/dist-server/service/actuation/dispatch-after-approval.js +73 -0
  65. package/dist-server/service/actuation/dispatch-after-approval.js.map +1 -0
  66. package/dist-server/service/actuation/effect-match.d.ts +53 -0
  67. package/dist-server/service/actuation/effect-match.js +65 -0
  68. package/dist-server/service/actuation/effect-match.js.map +1 -0
  69. package/dist-server/service/actuation/index.d.ts +25 -0
  70. package/dist-server/service/actuation/index.js +30 -0
  71. package/dist-server/service/actuation/index.js.map +1 -0
  72. package/dist-server/service/actuation/retry-plan.d.ts +63 -0
  73. package/dist-server/service/actuation/retry-plan.js +99 -0
  74. package/dist-server/service/actuation/retry-plan.js.map +1 -0
  75. package/dist-server/service/actuation/rule-evaluate.d.ts +127 -0
  76. package/dist-server/service/actuation/rule-evaluate.js +205 -0
  77. package/dist-server/service/actuation/rule-evaluate.js.map +1 -0
  78. package/dist-server/service/actuation/rule-loop.d.ts +5 -0
  79. package/dist-server/service/actuation/rule-loop.js +156 -0
  80. package/dist-server/service/actuation/rule-loop.js.map +1 -0
  81. package/dist-server/service/actuation/rule-runner.d.ts +52 -0
  82. package/dist-server/service/actuation/rule-runner.js +135 -0
  83. package/dist-server/service/actuation/rule-runner.js.map +1 -0
  84. package/dist-server/service/actuation/rule-wiring.d.ts +24 -0
  85. package/dist-server/service/actuation/rule-wiring.js +80 -0
  86. package/dist-server/service/actuation/rule-wiring.js.map +1 -0
  87. package/dist-server/service/actuation/settle-effects.d.ts +21 -0
  88. package/dist-server/service/actuation/settle-effects.js +101 -0
  89. package/dist-server/service/actuation/settle-effects.js.map +1 -0
  90. package/dist-server/service/actuation/sweep-dispatch.d.ts +37 -0
  91. package/dist-server/service/actuation/sweep-dispatch.js +125 -0
  92. package/dist-server/service/actuation/sweep-dispatch.js.map +1 -0
  93. package/dist-server/service/actuation/twin-command-resolver.d.ts +120 -0
  94. package/dist-server/service/actuation/twin-command-resolver.js +406 -0
  95. package/dist-server/service/actuation/twin-command-resolver.js.map +1 -0
  96. package/dist-server/service/actuation/twin-command.d.ts +111 -0
  97. package/dist-server/service/actuation/twin-command.js +170 -0
  98. package/dist-server/service/actuation/twin-command.js.map +1 -0
  99. package/dist-server/service/actuation/twin-now.d.ts +41 -0
  100. package/dist-server/service/actuation/twin-now.js +65 -0
  101. package/dist-server/service/actuation/twin-now.js.map +1 -0
  102. package/dist-server/service/index.d.ts +5 -2
  103. package/dist-server/service/index.js +28 -17
  104. package/dist-server/service/index.js.map +1 -1
  105. package/dist-server/service/reference/actuation-routing.d.ts +60 -0
  106. package/dist-server/service/reference/actuation-routing.js +126 -0
  107. package/dist-server/service/reference/actuation-routing.js.map +1 -0
  108. package/dist-server/service/reference/actuation-target.d.ts +65 -0
  109. package/dist-server/service/reference/actuation-target.js +94 -0
  110. package/dist-server/service/reference/actuation-target.js.map +1 -0
  111. package/dist-server/service/reference/connection-portability-resolver.d.ts +29 -0
  112. package/dist-server/service/reference/connection-portability-resolver.js +181 -0
  113. package/dist-server/service/reference/connection-portability-resolver.js.map +1 -0
  114. package/dist-server/service/reference/connection-portability.d.ts +138 -0
  115. package/dist-server/service/reference/connection-portability.js +230 -0
  116. package/dist-server/service/reference/connection-portability.js.map +1 -0
  117. package/dist-server/service/reference/fill-cadence.d.ts +17 -0
  118. package/dist-server/service/reference/fill-cadence.js +31 -0
  119. package/dist-server/service/reference/fill-cadence.js.map +1 -0
  120. package/dist-server/service/reference/fill-dedupe.d.ts +16 -0
  121. package/dist-server/service/reference/fill-dedupe.js +63 -0
  122. package/dist-server/service/reference/fill-dedupe.js.map +1 -0
  123. package/dist-server/service/reference/fill-loop.d.ts +35 -0
  124. package/dist-server/service/reference/fill-loop.js +187 -0
  125. package/dist-server/service/reference/fill-loop.js.map +1 -0
  126. package/dist-server/service/reference/fill-span.d.ts +10 -0
  127. package/dist-server/service/reference/fill-span.js +37 -0
  128. package/dist-server/service/reference/fill-span.js.map +1 -0
  129. package/dist-server/service/reference/hook-contract.d.ts +149 -22
  130. package/dist-server/service/reference/hook-contract.js +236 -23
  131. package/dist-server/service/reference/hook-contract.js.map +1 -1
  132. package/dist-server/service/reference/hook-rejected.d.ts +25 -0
  133. package/dist-server/service/reference/hook-rejected.js +48 -0
  134. package/dist-server/service/reference/hook-rejected.js.map +1 -0
  135. package/dist-server/service/reference/hook-store.d.ts +3 -0
  136. package/dist-server/service/reference/hook-store.js +28 -0
  137. package/dist-server/service/reference/hook-store.js.map +1 -0
  138. package/dist-server/service/reference/index.d.ts +4 -1
  139. package/dist-server/service/reference/index.js +5 -1
  140. package/dist-server/service/reference/index.js.map +1 -1
  141. package/dist-server/service/reference/live-cadence.d.ts +68 -0
  142. package/dist-server/service/reference/live-cadence.js +44 -0
  143. package/dist-server/service/reference/live-cadence.js.map +1 -0
  144. package/dist-server/service/reference/live-feed-lease.d.ts +15 -0
  145. package/dist-server/service/reference/live-feed-lease.js +56 -0
  146. package/dist-server/service/reference/live-feed-lease.js.map +1 -0
  147. package/dist-server/service/reference/live-ingest.d.ts +21 -0
  148. package/dist-server/service/reference/live-ingest.js +66 -0
  149. package/dist-server/service/reference/live-ingest.js.map +1 -0
  150. package/dist-server/service/reference/reference-adapter.d.ts +355 -2
  151. package/dist-server/service/reference/reference-adapter.js +19 -1
  152. package/dist-server/service/reference/reference-adapter.js.map +1 -1
  153. package/dist-server/service/reference/reference-fill-run.d.ts +50 -0
  154. package/dist-server/service/reference/reference-fill-run.js +142 -0
  155. package/dist-server/service/reference/reference-fill-run.js.map +1 -0
  156. package/dist-server/service/reference/reference-fill.d.ts +90 -0
  157. package/dist-server/service/reference/reference-fill.js +141 -0
  158. package/dist-server/service/reference/reference-fill.js.map +1 -0
  159. package/dist-server/service/reference/reference-hook.d.ts +64 -6
  160. package/dist-server/service/reference/reference-hook.js +265 -27
  161. package/dist-server/service/reference/reference-hook.js.map +1 -1
  162. package/dist-server/service/reference/reference-link-groups.d.ts +10 -0
  163. package/dist-server/service/reference/reference-link-groups.js +15 -0
  164. package/dist-server/service/reference/reference-link-groups.js.map +1 -0
  165. package/dist-server/service/reference/reference-links.d.ts +14 -0
  166. package/dist-server/service/reference/reference-links.js +73 -0
  167. package/dist-server/service/reference/reference-links.js.map +1 -0
  168. package/dist-server/service/reference/reference-live.d.ts +1 -0
  169. package/dist-server/service/reference/reference-live.js +32 -6
  170. package/dist-server/service/reference/reference-live.js.map +1 -1
  171. package/dist-server/service/reference/reference-master.d.ts +56 -2
  172. package/dist-server/service/reference/reference-master.js +33 -3
  173. package/dist-server/service/reference/reference-master.js.map +1 -1
  174. package/dist-server/service/reference/reference-resolver.d.ts +27 -0
  175. package/dist-server/service/reference/reference-resolver.js +79 -1
  176. package/dist-server/service/reference/reference-resolver.js.map +1 -1
  177. package/dist-server/service/twin-event/twin-event-keys.d.ts +31 -3
  178. package/dist-server/service/twin-event/twin-event-keys.js +36 -4
  179. package/dist-server/service/twin-event/twin-event-keys.js.map +1 -1
  180. package/dist-server/service/twin-event/twin-event.d.ts +1 -0
  181. package/dist-server/service/twin-event/twin-event.js +11 -2
  182. package/dist-server/service/twin-event/twin-event.js.map +1 -1
  183. package/dist-server/service/twin-model/choose-recipe.d.ts +15 -0
  184. package/dist-server/service/twin-model/choose-recipe.js +33 -0
  185. package/dist-server/service/twin-model/choose-recipe.js.map +1 -0
  186. package/dist-server/service/twin-model/external-resolver.d.ts +76 -0
  187. package/dist-server/service/twin-model/external-resolver.js +109 -0
  188. package/dist-server/service/twin-model/external-resolver.js.map +1 -0
  189. package/dist-server/service/twin-model/project-structure.js +16 -3
  190. package/dist-server/service/twin-model/project-structure.js.map +1 -1
  191. package/dist-server/service/twin-model/twin-equipment.d.ts +17 -0
  192. package/dist-server/service/twin-model/twin-equipment.js +10 -0
  193. package/dist-server/service/twin-model/twin-equipment.js.map +1 -1
  194. package/dist-server/service/twin-model/twin-lineage-query.js +75 -1
  195. package/dist-server/service/twin-model/twin-lineage-query.js.map +1 -1
  196. package/dist-server/service/twin-model/twin-model-item-query.js +94 -5
  197. package/dist-server/service/twin-model/twin-model-item-query.js.map +1 -1
  198. package/dist-server/service/twin-model/twin-model-tree-query.js.map +1 -1
  199. package/dist-server/service/twin-space/twin-space.d.ts +29 -0
  200. package/dist-server/service/twin-space/twin-space.js +13 -0
  201. package/dist-server/service/twin-space/twin-space.js.map +1 -1
  202. package/dist-server/service/twin-subject/event-subjects.d.ts +3 -1
  203. package/dist-server/service/twin-subject/event-subjects.js +8 -1
  204. package/dist-server/service/twin-subject/event-subjects.js.map +1 -1
  205. package/dist-shared/entity-delta.js +1 -1
  206. package/dist-shared/entity-delta.js.map +1 -1
  207. package/package.json +7 -7
  208. package/server/engine/canonical-ingest.ts +119 -33
  209. package/server/engine/event-time.ts +96 -0
  210. package/server/engine/index.ts +20 -0
  211. package/server/engine/ingest-dedupe.ts +203 -27
  212. package/server/engine/ingest-health.ts +91 -6
  213. package/server/engine/kpi-fold.ts +24 -1
  214. package/server/engine/kpi-query.ts +23 -4
  215. package/server/engine/oee-accumulator.ts +80 -8
  216. package/server/engine/twin-engine.ts +119 -5
  217. package/server/index.ts +23 -0
  218. package/server/migrations/1786600000000-RenameOperatoMesAdapterType.ts +66 -0
  219. package/server/migrations/1786700000000-AddDispatchRetryColumns.ts +82 -0
  220. package/server/migrations/index.ts +5 -1
  221. package/server/routes.ts +19 -20
  222. package/server/service/actuation/actuation-advisor.ts +124 -0
  223. package/server/service/actuation/actuation-outcome.ts +97 -0
  224. package/server/service/actuation/actuation-rule-resolver.ts +147 -0
  225. package/server/service/actuation/actuation-rule.ts +139 -0
  226. package/server/service/actuation/approval-gateway.ts +44 -0
  227. package/server/service/actuation/catch-up-effects.ts +152 -0
  228. package/server/service/actuation/command-dispatcher.ts +511 -0
  229. package/server/service/actuation/command-store.ts +236 -0
  230. package/server/service/actuation/dispatch-after-approval.ts +71 -0
  231. package/server/service/actuation/effect-match.ts +124 -0
  232. package/server/service/actuation/index.ts +27 -0
  233. package/server/service/actuation/retry-plan.ts +145 -0
  234. package/server/service/actuation/rule-evaluate.ts +352 -0
  235. package/server/service/actuation/rule-loop.ts +160 -0
  236. package/server/service/actuation/rule-runner.ts +216 -0
  237. package/server/service/actuation/rule-wiring.ts +84 -0
  238. package/server/service/actuation/settle-effects.ts +115 -0
  239. package/server/service/actuation/sweep-dispatch.ts +179 -0
  240. package/server/service/actuation/twin-command-resolver.ts +387 -0
  241. package/server/service/actuation/twin-command.ts +232 -0
  242. package/server/service/actuation/twin-now.ts +97 -0
  243. package/server/service/index.ts +11 -0
  244. package/server/service/reference/actuation-routing.ts +165 -0
  245. package/server/service/reference/actuation-target.ts +163 -0
  246. package/server/service/reference/connection-portability-resolver.ts +171 -0
  247. package/server/service/reference/connection-portability.ts +285 -0
  248. package/server/service/reference/fill-cadence.ts +29 -0
  249. package/server/service/reference/fill-dedupe.ts +66 -0
  250. package/server/service/reference/fill-loop.ts +153 -0
  251. package/server/service/reference/fill-span.ts +31 -0
  252. package/server/service/reference/hook-contract.ts +280 -22
  253. package/server/service/reference/hook-rejected.ts +53 -0
  254. package/server/service/reference/hook-store.ts +28 -0
  255. package/server/service/reference/index.ts +5 -1
  256. package/server/service/reference/live-cadence.ts +129 -0
  257. package/server/service/reference/live-feed-lease.ts +56 -0
  258. package/server/service/reference/live-ingest.ts +94 -0
  259. package/server/service/reference/reference-adapter.ts +392 -5
  260. package/server/service/reference/reference-fill-run.ts +165 -0
  261. package/server/service/reference/reference-fill.ts +223 -0
  262. package/server/service/reference/reference-hook.ts +355 -32
  263. package/server/service/reference/reference-link-groups.ts +21 -0
  264. package/server/service/reference/reference-links.ts +77 -0
  265. package/server/service/reference/reference-live.ts +30 -5
  266. package/server/service/reference/reference-master.ts +90 -5
  267. package/server/service/reference/reference-resolver.ts +77 -2
  268. package/server/service/twin-event/twin-event-keys.ts +37 -4
  269. package/server/service/twin-event/twin-event.ts +18 -1
  270. package/server/service/twin-model/choose-recipe.ts +31 -0
  271. package/server/service/twin-model/external-resolver.ts +161 -0
  272. package/server/service/twin-model/project-structure.ts +16 -3
  273. package/server/service/twin-model/twin-equipment.ts +22 -0
  274. package/server/service/twin-model/twin-lineage-query.ts +82 -1
  275. package/server/service/twin-model/twin-model-item-query.ts +95 -4
  276. package/server/service/twin-model/twin-model-tree-query.ts +1 -1
  277. package/server/service/twin-space/twin-space.ts +39 -0
  278. package/server/service/twin-subject/event-subjects.ts +8 -1
  279. package/shared/entity-delta.ts +1 -1
  280. package/test/ack-shape-alignment.test.ts +97 -0
  281. package/test/actuation-approval-door.test.ts +421 -0
  282. package/test/actuation-dispatch.test.ts +209 -0
  283. package/test/actuation-effect.test.ts +162 -0
  284. package/test/actuation-outcome.test.ts +152 -0
  285. package/test/actuation-rule-runner.test.ts +281 -0
  286. package/test/actuation-rule.test.ts +266 -0
  287. package/test/actuation-seam.test.ts +249 -0
  288. package/test/actuation-settle.test.ts +164 -0
  289. package/test/actuation-target.test.ts +145 -0
  290. package/test/canonical-ingest-vocabularies.test.ts +49 -2
  291. package/test/capability-mapping.test.ts +1 -1
  292. package/test/choose-recipe.test.ts +117 -0
  293. package/test/command-store-writes-columns.test.ts +126 -0
  294. package/test/connection-portability-doors.test.ts +87 -0
  295. package/test/connector-capability-declaration.test.ts +54 -4
  296. package/test/declaration-reaches-model.test.ts +43 -0
  297. package/test/dedupe-transformation.test.ts +112 -0
  298. package/test/entity-delta.test.ts +1 -1
  299. package/test/event-subjects.test.ts +2 -1
  300. package/test/external-resolver.test.ts +171 -0
  301. package/test/fill-dedupe.test.ts +59 -0
  302. package/test/fill-loop.test.ts +35 -0
  303. package/test/first-envelope.test.ts +153 -0
  304. package/test/fold-shift-dst.test.ts +110 -0
  305. package/test/home-in-area.test.ts +90 -0
  306. package/test/hook-rejected-shape.test.ts +86 -0
  307. package/test/hook-response-sum.test.ts +193 -0
  308. package/test/hook-sequence.test.ts +333 -0
  309. package/test/ingest-dedupe.test.ts +56 -0
  310. package/test/ingest-expected-quiet.test.ts +111 -0
  311. package/test/ingest-idempotent.test.ts +79 -0
  312. package/test/ingest-reconcile-four-ways.test.ts +97 -0
  313. package/test/ingest-rules-header.test.ts +100 -0
  314. package/test/ingest-window-rolls-unobserved.test.ts +72 -0
  315. package/test/intake-mapping-parity.test.ts +175 -0
  316. package/test/live-cadence.test.ts +170 -0
  317. package/test/live-feed-lease.test.ts +63 -0
  318. package/test/live-mirror-parity.test.ts +1 -1
  319. package/test/oee-accumulator.test.ts +3 -3
  320. package/test/oee-site-calendar.test.ts +146 -0
  321. package/test/order-and-transaction-split.test.ts +107 -0
  322. package/test/reference-fill.test.ts +235 -0
  323. package/test/reference-hook.test.ts +114 -23
  324. package/test/reference-links.test.ts +56 -0
  325. package/test/retry-plan.test.ts +139 -0
  326. package/test/sweep-dispatch.test.ts +191 -0
  327. package/test/twin-event-keys.test.ts +20 -6
  328. package/test/twin-model-item-db.test.ts +6 -6
  329. package/test/twin-model-tree-db.test.ts +6 -6
  330. package/tsconfig.shared.tsbuildinfo +1 -1
  331. package/tsconfig.tsbuildinfo +1 -1
@@ -1,9 +1,5 @@
1
- /**
2
- * ์ด ๋ด‰ํˆฌ๊ฐ€ ๋งํ•˜๋Š” ์‚ฌ์‹ค์˜ ์ •์ฒด โ€” ๊ฐ™์œผ๋ฉด ๊ฐ™์€ ์‚ฌ์‹ค์ด๋‹ค.
3
- *
4
- * ๋Œ€์ƒ์ด๋‚˜ ์‹œ๊ฐ์„ ์•Œ ์ˆ˜ ์—†์œผ๋ฉด **์ •์ฒด๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค**(`undefined`). ๊ทธ๋•Œ๋Š” ๊ฑฐ๋ฅด์ง€ ์•Š๊ณ  ํ†ต๊ณผ์‹œํ‚จ๋‹ค โ€”
5
- * ๋ชจ๋ฅด๋Š” ๊ฒƒ์„ ๊ฐ™๋‹ค๊ณ  ํŒ๋‹จํ•˜๋ฉด ์„œ๋กœ ๋‹ค๋ฅธ ์‚ฌ์‹ค์ด ํ•˜๋‚˜๋กœ ํ•ฉ์ณ์ง„๋‹ค. ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ์žƒ๋Š” ๊ฒƒ๋ณด๋‹ค ๋‘ ๋ฒˆ ์„ธ๋Š” ๊ฒƒ์ด ๋‚ซ๋‹ค.
6
- */
1
+ /** ์ง€๊ธˆ๊นŒ์ง€ ์ •์ฒด๋ฅผ ๋ชป ๋งŒ๋“  ๊ฒƒ โ€” ์ข…๋ฅ˜๋ณ„. ์ฝ๊ณ  ๋น„์šด๋‹ค. */
2
+ export declare function takeUnidentified(): Record<string, number>;
7
3
  export declare function factIdentity(envelope: any): string | undefined;
8
4
  /**
9
5
  * ์ตœ๊ทผ์— ๋ณธ ์ •์ฒด๋ฅผ ๊ธฐ์–ตํ•œ๋‹ค โ€” **ํฌ๊ธฐ์— ์ƒํ•œ์„ ๋‘”๋‹ค.**
@@ -21,6 +17,22 @@ export declare class FactDeduper {
21
17
  static WINDOW: number;
22
18
  private seen;
23
19
  private order;
20
+ /**
21
+ * ์ด๋ฏธ ์•„๋Š” ๊ฒƒ์œผ๋กœ **๋ฏธ๋ฆฌ ๊ธฐ์–ตํ•œ๋‹ค** โ€” ์ €๋„์—์„œ ์ฝ์–ด ์ฑ„์šธ ๋•Œ.
22
+ *
23
+ * โ”€โ”€ ์™œ ํ•„์š”ํ•œ๊ฐ€ (2026-09-06 ์ธก์ •) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
24
+ * ์ด ๊ธฐ์–ต์€ ํ”„๋กœ์„ธ์Šค ์•ˆ์—๋งŒ ์žˆ๋‹ค. ์žฌ๊ธฐ๋™ํ•˜๋ฉด ๋น„์›Œ์ง€๊ณ , ๊ทธ ๋’ค backfill ์„ ๋Œ๋ฆฌ๋ฉด **์ด๋ฏธ ์ €๋„์—
25
+ * ์žˆ๋Š” ์‚ฌ์‹ค๋„ ใ€Œ์ฒ˜์Œ ๋ณธ ๊ฒƒใ€**์ด ๋œ๋‹ค.
26
+ *
27
+ * ์‹ค์ œ๋กœ ๊ทธ๋žฌ๋‹ค. `mes-line-a` ๋ฅผ ์žฌ๊ธฐ๋™ ๋’ค backfill ํ•˜๋‹ˆ 39๊ฑด์ด ์ „๋ถ€ ๋‹ค์‹œ ์•‰์•„ ์ €๋„์ด
28
+ * 44 โ†’ 83๊ฑด์ด ๋˜๊ณ  44๊ฐ€์ง€๊ฐ€ ์ค‘๋ณต์ด ๋๋‹ค.
29
+ *
30
+ * push ๊ฒฝ๋กœ์—์„œ๋Š” ์•ˆ ๋ณด์ธ๋‹ค. ์žฌ์ „์†ก์ด ๋ช‡ ๋ถ„ ์•ˆ์— ์˜ค๋ฏ€๋กœ ์ฐฝ ์•ˆ์—์„œ ๊ฑธ๋ฆฐ๋‹ค. **backfill ์ด ๊ทธ ์ „์ œ๋ฅผ
31
+ * ๊นฌ๋‹ค** โ€” ๋ช‡ ๋‹ฌ ์ „ ์‚ฌ์‹ค์„ ์ง€๊ธˆ ๋ฐ›์œผ๋‹ˆ ์žฌ๊ธฐ๋™ ํ•œ ๋ฒˆ์ด๋ฉด ๊ทธ ๊ตฌ๊ฐ„์ด ํ†ต์งธ๋กœ ๋‹ค์‹œ ์•‰๋Š”๋‹ค.
32
+ *
33
+ * ๊ทธ๋ž˜์„œ backfill ์ด ๋ถ€๋ฅด๊ธฐ ์ „์— ๊ทธ ๊ตฌ๊ฐ„์˜ ์ •์ฒด๋ฅผ ์ €๋„์—์„œ ์ฝ์–ด ์—ฌ๊ธฐ ๋„ฃ๋Š”๋‹ค.
34
+ */
35
+ remember(identities: readonly string[]): number;
24
36
  /** ์ด ์‚ฌ์‹ค์„ ๋ณธ ์ ์ด ์žˆ๋‚˜ โ€” ์—†์œผ๋ฉด ๊ธฐ์–ตํ•˜๊ณ  `false`. */
25
37
  private known;
26
38
  /**
@@ -37,6 +37,7 @@
37
37
  */
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.FactDeduper = void 0;
40
+ exports.takeUnidentified = takeUnidentified;
40
41
  exports.factIdentity = factIdentity;
41
42
  /** ์‹œ๊ฐ์„ ๋ฐ€๋ฆฌ์ดˆ๋กœ โ€” ์—ฐ๊ฒฐ๋œ ์‹œ์Šคํ…œ์ด ์ค€ ์‹œ๊ฐ์ด ๋จผ์ €, ์—†์œผ๋ฉด ๋ด‰ํˆฌ์˜ ์‹œ๊ฐ. */
42
43
  function timeOf(envelope) {
@@ -48,22 +49,158 @@ function timeOf(envelope) {
48
49
  return undefined;
49
50
  }
50
51
  /**
51
- * ์ด ๋ด‰ํˆฌ๊ฐ€ ๋งํ•˜๋Š” ๋Œ€์ƒ โ€” ์–ดํœ˜๋งˆ๋‹ค ์ด๋ฆ„์ด ๋‹ค๋ฅด๋ฏ€๋กœ ์•„๋Š” ์ด๋ฆ„์„ ๋ชจ๋‘ ๋ณธ๋‹ค.
52
+ * ์ด ๋ด‰ํˆฌ๊ฐ€ ๋งํ•˜๋Š” ๊ฒƒ์„ **๊ฐ€๋ฅด๋Š” ๊ฐ’๋“ค** โ€” ํ•˜๋‚˜๋ผ๋„ ๋‹ค๋ฅด๋ฉด ๋‹ค๋ฅธ ์‚ฌ์‹ค์ด๋‹ค.
52
53
  *
53
- * ์ˆœ์„œ๊ฐ€ ๋œป์„ ๊ฐ–๋Š”๋‹ค: ์ฃผ์ฒด๋ฅผ ๋จผ์ € ๋ณธ๋‹ค. ์„ค๋น„ ์‚ฌ์‹ค์€ ใ€Œ์ง€๊ธˆ ๋ถ™์–ด ์žˆ๋Š” ์ž‘์—…ใ€์„ ํ•จ๊ป˜ ์‹ฃ๊ณ , ์ž‘์—… ์‚ฌ์‹ค์€
54
- * ใ€Œ์†Œ์† ์˜ค๋”ใ€๋ฅผ ํ•จ๊ป˜ ์‹ฃ๋Š”๋‹ค. ์•„๋ฌด ์ด๋ฆ„์ด๋‚˜ ๋จผ์ € ๋ณด๋ฉด ์ฐธ์กฐ๋ฅผ ์ฃผ์ฒด๋กœ ์ฝ๋Š”๋‹ค(์Šน๊ฒฉ ํ‚ค์—์„œ ๊ฒช์€ ๊ฒƒ๊ณผ ๊ฐ™๋‹ค).
54
+ * โ”€โ”€ ์˜ˆ์ „์—๋Š” ํ•˜๋‚˜๋งŒ ๊ณจ๋ž๋‹ค (2026-09-05 ์‹ค์ธก) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
55
+ * ์•„๋Š” ์ด๋ฆ„์„ ์ˆœ์„œ๋Œ€๋กœ ๋ณด๊ณ  **๋จผ์ € ๊ฑธ๋ฆฌ๋Š” ํ•˜๋‚˜**๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์‚ผ์•˜๋‹ค. ใ€Œ์ฃผ์ฒด๋ฅผ ๋จผ์ € ๋ณธ๋‹คใ€๋Š” ํŒ๋‹จ
56
+ * ์ž์ฒด๋Š” ์˜ณ๋‹ค โ€” ์„ค๋น„ ์‚ฌ์‹ค์€ ใ€Œ์ง€๊ธˆ ๋ถ™์–ด ์žˆ๋Š” ์ž‘์—…ใ€์„ ์ฐธ์กฐ๋กœ ์‹ฃ๋Š”๋‹ค. ๊ทธ๋Ÿฐ๋ฐ **๊ณ ๋ฅด๊ณ  ๋‚˜๋จธ์ง€๋ฅผ
57
+ * ๋ฒ„๋ฆฐ ๊ฒƒ**์ด ๊ฒฐํ•จ์ด์—ˆ๋‹ค.
58
+ *
59
+ * ์‹ค์ œ๋กœ ๋‚œ ์ผ: plant ์ด ์‹ค์  ๋‘˜์„ ๋ณด๋ƒˆ๋Š”๋ฐ ํ•œ ๊ฑด์ด ์ €๋„์— ์•ˆ ๋‚จ์•˜๋‹ค.
60
+ *
61
+ * seq 36 quality.output moverId EQ-CT-MWELD-01 ยท taskId PR-CT-WIRE-01 ยท goodCount 12
62
+ * seq 41 quality.output moverId EQ-CT-MWELD-01 ยท taskId PR-CT-WIRE-02 ยท goodCount 9
63
+ *
64
+ * ๋‘ ์‹ค์ ์˜ ์‹œ๊ฐ์ด ๊ฐ™์•˜๊ณ (์›๋ณธ์ด ๋์‹œ๊ฐ์„ ๋ณต์‚ฌ) `moverId` ๊ฐ€ `taskId` ๋ณด๋‹ค ๋จผ์ €๋ผ **๋‘˜์ด ํ•œ ์‚ฌ์‹ค์ด
65
+ * ๋๋‹ค.** ๊ฑฐ๋ถ€๊ฐ€ ์•„๋‹ˆ๋ผ ๋˜ํ’€์ด๋กœ ์„ธ์–ด์กŒ๋‹ค โ€” `offered 5 ยท rejected 0 ยท journaled 3`.
66
+ *
67
+ * **๊ตฌ๋ณ„ํ•  ๊ฐ’์ด ์ด๋ฏธ ๋ด‰ํˆฌ ์•ˆ์— ์žˆ์—ˆ๋Š”๋ฐ ํŒ์ •์ด ๊ทธ๊ฒƒ์„ ์•ˆ ๋ดค๋‹ค.**
68
+ *
69
+ * โ”€โ”€ ๊ทธ๋ฆฌ๊ณ  EPCIS ๋„ ๊ฐ™์•˜๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
70
+ * ์ €๋„ 246๋งŒ ๊ฑด์— ํ˜„์žฌ ๊ทœ์น™์„ ๋‹ค์‹œ ๊ฑธ์–ด ๋ณด๋‹ˆ ๊ฒน์น˜๋Š” ๋ฌถ์Œ์ด ์—ฌ์„ฏ์ด์—ˆ๊ณ , ์ „๋ถ€ ์ด ๋ชจ์–‘์ด๋‹ค.
71
+ *
72
+ * ๊ฐ™์€ EPC ยท ๊ฐ™์€ ๋ฐ€๋ฆฌ์ดˆ
73
+ * โ‘  bizStep receiving action ADD disposition sellable_accessible
74
+ * โ‘ก bizStep commissioning action OBSERVE disposition reserved
75
+ *
76
+ * **ํ•œ ๊ฐœ์ฒด์˜ ์„œ๋กœ ๋‹ค๋ฅธ ๊ด€์ธก**์ด๋‹ค. EPCIS ์—์„œ ์ด์ƒํ•œ ์ผ์ด ์•„๋‹Œ๋ฐ ๊ทœ์น™์ด ๊ทธ ์…‹์„ ์•ˆ ๋ดค๋‹ค.
77
+ *
78
+ * โ”€โ”€ ์™œ ๋„“ํžˆ๋Š” ์ชฝ์ด ๋งž๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
79
+ * ์ด ํŒŒ์ผ์ด ์Šค์Šค๋กœ ์ ์–ด ๋‘” ๊ฐ’์ด ๊ทธ๊ฒƒ์ด๋‹ค โ€” ใ€Œ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ์žƒ๋Š” ๊ฒƒ๋ณด๋‹ค ๋‘ ๋ฒˆ ์„ธ๋Š” ๊ฒƒ์ด ๋‚ซ๋‹คใ€.
80
+ * ์ง€๊ธˆ ๊ฑฐ๋™์€ **์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ์žƒ๋Š” ์ชฝ**์ด์—ˆ๋‹ค.
81
+ *
82
+ * ๋„“ํ˜€๋„ ๋˜ํ’€์ด๋Š” ๊ทธ๋Œ€๋กœ ๊ฑธ๋ฆฐ๋‹ค: ๊ฐ™์€ ๋ด‰ํˆฌ๋ฅผ ๋‹ค์‹œ ๋ณด๋‚ด๋ฉด **์ด ๊ฐ’๋“ค์ด ์ „๋ถ€ ๊ฐ™๋‹ค.** ๋„“ํžˆ๋Š” ๊ฒƒ์€
83
+ * ใ€Œ๋‹ค๋ฅธ ์‚ฌ์‹ค์„ ํ•ฉ์น˜์ง€ ์•Š๋Š”๋‹คใ€๋งŒ ๊ฐ•ํ•ด์ง€๊ณ  ใ€Œ๋˜ํ’€์ด๋ฅผ ์žก๋Š”๋‹คใ€๋Š” ์•ˆ ์•ฝํ•ด์ง„๋‹ค.
55
84
  */
56
- function targetOf(envelope) {
85
+ function discriminatorsOf(envelope) {
57
86
  const d = envelope?.data ?? {};
58
- const first = (...vals) => {
59
- for (const v of vals) {
60
- const s = String(v ?? '').trim();
61
- if (s)
62
- return s;
63
- }
64
- return undefined;
87
+ const out = [];
88
+ const put = (name, v) => {
89
+ const t = String(v ?? '').trim();
90
+ if (t)
91
+ out.push(`${name}=${t}`);
65
92
  };
66
- return first(d.meterId, d.equipmentId, d.moverId, d.taskId, d.orderId, d.personId, d.assetId, d.locationId, d.epcList?.[0], d.parentID, d.quantityList?.[0]?.epcClass, d.transformationID);
93
+ /*
94
+ * ์ฃผ์ฒดยท์ฐธ์กฐ๋ฅผ **๋‹ค ์ ๋Š”๋‹ค.** ์ˆœ์„œ๋Š” ๊ฐ’์ด ์•„๋‹ˆ๋ผ ์ด๋ฆ„์œผ๋กœ ๊ณ ์ •๋˜๋ฏ€๋กœ ๋ด‰ํˆฌ๋งˆ๋‹ค ํ”๋“ค๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.
95
+ *
96
+ * โš  **์ด ๋ชฉ๋ก์€ ๊ณ„์•ฝ์˜ `identity` ์„ ์–ธ์„ ์†์œผ๋กœ ์˜ฎ๊ธด ๊ฒƒ์ด๋‹ค.** ๊ณ„์•ฝ์ด kind ๋งˆ๋‹ค ๋ฌด์—‡์ด ๊ทธ ์‚ฌ์‹ค์„
97
+ * ๊ฐ€๋ฆฌํ‚ค๋Š”์ง€ ์ด๋ฏธ ์„ ์–ธํ•˜๋Š”๋ฐ(`operational-ingest.ts` ์˜ `SPECS[kind].identity`), ๊ทธ๊ฒƒ์„ ๋‚ด๋ณด๋‚ด์ง€
98
+ * ์•Š์•„์„œ ์—ฌ๊ธฐ๊ฐ€ ๋”ฐ๋กœ ๋“ค๊ณ  ์žˆ๋‹ค.
99
+ *
100
+ * ๊ทธ๋ž˜์„œ ์ƒˆ kind ๊ฐ€ ์ƒ๊ธฐ๋ฉด ์—ฌ๊ธฐ๊ฐ€ ์กฐ์šฉํžˆ ๋’ค์ฒ˜์ง„๋‹ค. ์‹ค์ œ๋กœ ๋‘ ๋ฒˆ ๊ทธ๋žฌ๋‹ค โ€” `subjectId`(์ฒ˜๋ถ„)์™€
101
+ * `testableObjectId`(์‹œํ—˜)๊ฐ€ ๋น ์ ธ ์žˆ์—ˆ๊ณ , ๊ทธ๋™์•ˆ ๊ทธ ๋‘ ์ข…๋ฅ˜๋Š” ์ •์ฒด๋ฅผ ๋ชป ๋งŒ๋“ค๊ฑฐ๋‚˜ ์„œ๋กœ ๋‹ค๋ฅธ ์‚ฌ์‹ค์ด
102
+ * ๋ญ‰์น  ์ˆ˜ ์žˆ์—ˆ๋‹ค.
103
+ *
104
+ * ๊ณ„์•ฝ์ด `operationalIdentityField(kind)` ๋ฅผ ๋‚ด๋ณด๋‚ด๋ฉด ์ด ๋ชฉ๋ก์„ ์ง€์šด๋‹ค. ๊ทธ ๋ฌธ์„ ์—ด์–ด ๋‘์—ˆ๊ณ 
105
+ * ๋ฐฐํฌ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
106
+ */
107
+ put('meter', d.meterId);
108
+ put('equipment', d.equipmentId);
109
+ put('mover', d.moverId); // vocabulary-guard: allow โ€” ๋ด‰ํˆฌ์˜ ์˜› ์„ธ๋Œ€ ํ•„๋“œ ์ด๋ฆ„(์ €์žฅ๋œ ๊ณ„์•ฝ)
110
+ put('task', d.taskId);
111
+ put('order', d.orderId);
112
+ put('person', d.personId);
113
+ put('asset', d.assetId);
114
+ put('location', d.locationId); // vocabulary-guard: allow โ€” ๊ฐ™์Œ
115
+ put('epc', d.epcList?.[0]);
116
+ put('parent', d.parentID);
117
+ put('class', d.quantityList?.[0]?.epcClass);
118
+ put('transformation', d.transformationID);
119
+ /*
120
+ * โ”€โ”€ ์ฃผ์ฒด๊ฐ€ `subjectId` ์ธ ์‚ฌ์‹ค์ด ์žˆ๋‹ค (2026-09-06 ์ธก์ •) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
121
+ * ๋ถ€์ ํ•ฉ ์ฒ˜๋ถ„๊ณผ ์‹œํ—˜ ๊ฒฐ๊ณผ๋Š” **ํ‘œ์ค€ `TestableObjectID` ์™€ ๊ฐ™์€ ์ž๋ฆฌ**๋ฅผ ์“ด๋‹ค(๋กœํŠธ ยท ์„ค๋น„ ยท ์ž๋ฆฌ์—
122
+ * ๋‘๋ฃจ ์“ฐ๋Š” ํ•˜๋‚˜์˜ ์ด๋ฆ„). ๊ทธ ์ด๋ฆ„์ด ์—ฌ๊ธฐ ์—†์–ด์„œ ๋‘ ์ข…๋ฅ˜๊ฐ€ **์ •์ฒด๋ฅผ ๋ชป ๋งŒ๋“ค์—ˆ๋‹ค** โ€”
123
+ * `parts` ๊ฐ€ ๋น„๋ฉด `factIdentity` ๊ฐ€ `undefined` ๋ฅผ ๋‚ด๊ณ , ๊ทธ๋Ÿฌ๋ฉด dedupe ๋ฐ–์ด๋‹ค.
124
+ *
125
+ * ์‹ค์ œ๋กœ ๊ทธ๋žฌ๋‹ค. `fillTwinScope` ๋ฅผ ๋‘ ๋ฒˆ ๋Œ๋ฆด ๋•Œ๋งˆ๋‹ค ๊ทธ ๋‘˜์ด 7๊ฑด์”ฉ ๋‹ค์‹œ ์•‰์•˜๋‹ค(์ฒ˜๋ถ„ 4 ยท ์‹œํ—˜ 3).
126
+ * ๋‚˜๋จธ์ง€ 34๊ฑด์€ ๊ฑธ๋Ÿฌ์กŒ๋Š”๋ฐ ์ด ๋‘˜๋งŒ ๊ณ„์† ๋Š˜์—ˆ๋‹ค.
127
+ */
128
+ put('subject', d.subjectId);
129
+ put('spec', d.specId);
130
+ /*
131
+ * ์‹œํ—˜ ๊ฒฐ๊ณผ์˜ ์ฃผ์ฒด๋Š” `testableObjectId` ๋‹ค โ€” ํ‘œ์ค€ `TestableObjectID` ์˜ ์ด๋ฆ„์„ ๊ทธ๋Œ€๋กœ ์“ด๋‹ค.
132
+ *
133
+ * ์ด ์ด๋ฆ„์ด ์—†์–ด์„œ **๊ฐ™์€ ๋ช…์„ธ๋กœ ๊ฐ™์€ ์‹œ๊ฐ์— ์žฐ ์„œ๋กœ ๋‹ค๋ฅธ ๋กœํŠธ๊ฐ€ ํ•œ ์‚ฌ์‹ค๋กœ ๋ญ‰์ณค๋‹ค.** ์ค‘๋ณต์ด ์ƒ๊ธฐ๋Š”
134
+ * ๊ฒƒ๋ณด๋‹ค ๋‚˜์˜๋‹ค โ€” ๋‘ ๋กœํŠธ์˜ ์‹œํ—˜ ๊ฒฐ๊ณผ ์ค‘ ํ•˜๋‚˜๊ฐ€ ์‚ฌ๋ผ์ง„๋‹ค.
135
+ *
136
+ * ์‹ค์ œ๋กœ `mes-miratek` ์— ๊ฐ™์€ ์‹œํ—˜ ๊ฒฐ๊ณผ๊ฐ€ 10๊ฑด ์žˆ์—ˆ๋‹ค(2026-09-06 ํ™•์ธ). ๊ทธ๊ฒƒ์€ ๋ญ‰์นœ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ
137
+ * ๋ฐ˜๋Œ€๋กœ dedupe ๋ฅผ ๋ชป ์ง€๋‚œ ๊ฒƒ์ธ๋ฐ, ๊ฐ™์€ ์ž๋ฆฌ์—์„œ ๋ญ‰์น˜๋Š” ์ชฝ๋„ ์—ด๋ ค ์žˆ์—ˆ๋‹ค.
138
+ */
139
+ put('object', d.testableObjectId);
140
+ /* ์™„๋ฃŒ ์„ ์–ธ์˜ ์ฃผ์ฒด โ€” ใ€Œ์ด ์ถ•์€ ์—ฌ๊ธฐ๊นŒ์ง€๊ฐ€ ์ „๋ถ€๋‹คใ€๋ฅผ ๋งํ•˜๋Š” ์ถ• ์ด๋ฆ„. */
141
+ put('axis', d.completeAxis);
142
+ /*
143
+ * EPCIS ๋Š” ใ€Œ๋ฌด์—‡์„ ๋งํ•˜๋Š” ๊ด€์ธก์ธ๊ฐ€ใ€๊ฐ€ ์ด ์…‹์œผ๋กœ ๊ฐˆ๋ฆฐ๋‹ค. ํ•œ ๊ฐœ์ฒด๊ฐ€ ํ•œ ์ˆœ๊ฐ„์— ๋‘ ๊ด€์ธก์„ ๊ฐ–๋Š”
144
+ * ๊ฒƒ์€ ํ‘œ์ค€์—์„œ ์ •์ƒ์ด๊ณ , ์ด๊ฒƒ์„ ์•ˆ ๋ณด๋ฉด ๋’ค์—ฃ๊ฒƒ์ด ์‚ฌ๋ผ์ง„๋‹ค.
145
+ */
146
+ put('bizStep', d.bizStep);
147
+ put('action', d.action);
148
+ put('disposition', d.disposition);
149
+ /*
150
+ * โ”€โ”€ ๋ณ€ํ™˜์€ **๋ฌด์—‡์ด ๋ฌด์—‡์œผ๋กœ ๋˜์—ˆ๋‚˜**๋กœ ๊ฐˆ๋ฆฐ๋‹ค (2026-09-07 ์ธก์ •) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
151
+ * ์ด ์ž๋ฆฌ๊ฐ€ ์—†์–ด์„œ **์‚ฌ์‹ค ํ•˜๋‚˜๊ฐ€ ์—†์–ด์กŒ์Šต๋‹ˆ๋‹ค.** ๊ฑฐ์ ˆ์ด ์•„๋‹ˆ๋ผ ๋˜ํ’€์ด๋กœ ์„ธ์–ด์ ธ์„œ ๊ฒฝ๊ณ ๋„ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.
152
+ *
153
+ * ```
154
+ * plant outbox seq 37 in LOT-CT-SIDE-001 24๊ฐœ โ†’ out LOT-CT-MAIN-003 12๊ฐœ
155
+ * plant outbox seq 42 in LOT-CT-SIDE-001 18๊ฐœ โ†’ out LOT-CT-MAIN-004 9๊ฐœ
156
+ * transformationID ยท bizStep ยท ์ดˆ๊นŒ์ง€ ์ „๋ถ€ ๊ฐ™๋‹ค
157
+ * ์ €๋„์— ๋‚จ์€ ๊ฒƒ LOT-CT-MAIN-003 ํ•˜๋‚˜
158
+ * ```
159
+ *
160
+ * `LOT-CT-MAIN-004` ๋ฅผ ์–ด๋А ํŒจ๋„๋กœ ๋งŒ๋“ค์—ˆ๋Š”์ง€ ํŠธ์œˆ์ด ๋‹ตํ•˜์ง€ ๋ชปํ•˜๋Š” ์ƒํƒœ์˜€์Šต๋‹ˆ๋‹ค.
161
+ *
162
+ * ๊ทธ๋ฆฌ๊ณ  **๊ตฌ๋ณ„ํ•  ๊ฐ’์ด ๋ด‰ํˆฌ ์•ˆ์— ์ด๋ฏธ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค** โ€” `outputQuantityList[0].epcClass` ๊ฐ€ ์„œ๋กœ
163
+ * ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ์ด ํŒŒ์ผ ๋จธ๋ฆฌ๋ง์ด ์ ์–ด ๋‘” ๊ทธ ๋ชจ์–‘ ๊ทธ๋Œ€๋กœ์ž…๋‹ˆ๋‹ค: ํŒ์ •์ด ๊ทธ๊ฒƒ์„ ์•ˆ ๋ดค์Šต๋‹ˆ๋‹ค.
164
+ *
165
+ * ์‚ฐ์ถœ๋งŒ ๋ณด์ง€ ์•Š๊ณ  **์ž…๋ ฅ๋„ ๋ด…๋‹ˆ๋‹ค.** ๊ฐ™์€ ๋กœํŠธ๋ฅผ ๊ฐ™์€ ์ดˆ์— ๋‘ ๋ฒˆ ์†Œ๋น„ํ•˜๋ฉด์„œ ์‚ฐ์ถœ ์ด๋ฆ„์ด ๊ฐ™์€
166
+ * ๊ฒฝ์šฐ(์ˆ˜๋Ÿ‰๋งŒ ๋‹ค๋ฅธ ๋ถ„ํ• )๊ฐ€ ๋‚จ๊ณ , ๊ทธ๋•Œ ์ž…๋ ฅ ์ˆ˜๋Ÿ‰์ด ์œ ์ผํ•œ ์ฐจ์ด์ž…๋‹ˆ๋‹ค. ์ˆ˜๋Ÿ‰๊นŒ์ง€ ๋„ฃ๋Š” ์ด์œ ๊ฐ€ ๊ทธ๊ฒƒ์ž…๋‹ˆ๋‹ค.
167
+ */
168
+ put('inClass', classOf(d.inputQuantityList));
169
+ put('inEpc', d.inputEPCList?.[0]);
170
+ put('inQty', qtyOf(d.inputQuantityList));
171
+ put('outClass', classOf(d.outputQuantityList));
172
+ put('outEpc', d.outputEPCList?.[0]);
173
+ put('outQty', qtyOf(d.outputQuantityList));
174
+ /*
175
+ * ๋‹ด๊น€์˜ ์ž์‹๋„ ๊ฐ™์€ ์ด์œ ๋กœ ๋ณธ๋‹ค โ€” ํ•œ ํŒ”๋ ˆํŠธ์— ์„œ๋กœ ๋‹ค๋ฅธ ๋ฌถ์Œ์„ ๊ฐ™์€ ์ดˆ์— ๋‘ ๋ฒˆ ์‹ค์œผ๋ฉด ๋’ค์—ฃ๊ฒƒ์ด
176
+ * ์‚ฌ๋ผ์ง„๋‹ค. ์œ„ ๋ณ€ํ™˜์—์„œ ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ์žƒ์—ˆ์œผ๋‹ˆ ์—ฌ๊ธฐ๋„ ํ•จ๊ป˜ ๋ง‰๋Š”๋‹ค(ํ•œ ์ข…๋ฅ˜๋งŒ ๊ณ ์น˜๋ฉด ๋‚˜๋จธ์ง€์— ๋‚จ๋Š”๋‹ค).
177
+ */
178
+ put('childEpc', d.childEPCs?.[0]);
179
+ put('childClass', classOf(d.childQuantityList));
180
+ put('childQty', qtyOf(d.childQuantityList));
181
+ /*
182
+ * ์–ด๋А ์˜ค๋”์˜ ์‚ฌ์‹ค์ธ๊ฐ€๋„ ์ •์ฒด์˜ ์ผ๋ถ€๋‹ค. ๊ฐ™์€ ๊ณต์ •์„ ๊ฐ™์€ ์ดˆ์— ๋‘ ์˜ค๋”๋กœ ๋Œ๋ฆฌ๋Š” ๊ฒƒ์€ ์ •์ƒ์ด๊ณ ,
183
+ * ์ด๊ฒƒ์„ ์•ˆ ๋ณด๋ฉด ๋’ค์—ฃ๊ฒƒ์ด ์‚ฌ๋ผ์ง„๋‹ค.
184
+ */
185
+ put('tx', d.bizTransactionList?.[0]?.bizTransaction);
186
+ return out;
187
+ }
188
+ /** ์ˆ˜๋Ÿ‰ ๋ชฉ๋ก์˜ ์ฒซ ์ข…๋ฅ˜ โ€” ๋ชฉ๋ก์ด ๋น„๋ฉด `undefined`(๋นˆ ๋ฌธ์ž์—ด์„ ๋„ฃ์ง€ ์•Š๋Š”๋‹ค). */
189
+ function classOf(list) {
190
+ const first = Array.isArray(list) ? list[0] : undefined;
191
+ const v = first?.epcClass;
192
+ return typeof v === 'string' && v.trim() ? v : undefined;
193
+ }
194
+ /**
195
+ * ์ˆ˜๋Ÿ‰ ๋ชฉ๋ก์„ ์ˆ˜๊นŒ์ง€ ์ ๋Š”๋‹ค โ€” ์ข…๋ฅ˜๊ฐ€ ๊ฐ™๊ณ  ์ˆ˜๋Ÿ‰๋งŒ ๋‹ค๋ฅธ ์‚ฌ์‹ค์„ ๊ฐ€๋ฅธ๋‹ค.
196
+ *
197
+ * ๋ชฉ๋ก ์ „์ฒด๋ฅผ ์ ๋Š”๋‹ค. ์ฒซ ์›์†Œ๋งŒ ๋ณด๋ฉด ใ€Œ๊ฐ™์€ ๊ฒƒ ๋‘˜ + ๋‹ค๋ฅธ ๊ฒƒ ํ•˜๋‚˜ใ€๊ฐ€ ์ฒซ ์›์†Œ๋กœ๋Š” ๊ตฌ๋ณ„๋˜์ง€ ์•Š๋Š”๋‹ค.
198
+ */
199
+ function qtyOf(list) {
200
+ if (!Array.isArray(list) || !list.length)
201
+ return undefined;
202
+ const parts = list.map((x) => `${x?.epcClass ?? ''}:${x?.quantity ?? ''}${x?.uom ? '/' + x.uom : ''}`);
203
+ return parts.join('|');
67
204
  }
68
205
  /**
69
206
  * ์ด ๋ด‰ํˆฌ๊ฐ€ ๋งํ•˜๋Š” ์‚ฌ์‹ค์˜ ์ •์ฒด โ€” ๊ฐ™์œผ๋ฉด ๊ฐ™์€ ์‚ฌ์‹ค์ด๋‹ค.
@@ -71,17 +208,42 @@ function targetOf(envelope) {
71
208
  * ๋Œ€์ƒ์ด๋‚˜ ์‹œ๊ฐ์„ ์•Œ ์ˆ˜ ์—†์œผ๋ฉด **์ •์ฒด๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค**(`undefined`). ๊ทธ๋•Œ๋Š” ๊ฑฐ๋ฅด์ง€ ์•Š๊ณ  ํ†ต๊ณผ์‹œํ‚จ๋‹ค โ€”
72
209
  * ๋ชจ๋ฅด๋Š” ๊ฒƒ์„ ๊ฐ™๋‹ค๊ณ  ํŒ๋‹จํ•˜๋ฉด ์„œ๋กœ ๋‹ค๋ฅธ ์‚ฌ์‹ค์ด ํ•˜๋‚˜๋กœ ํ•ฉ์ณ์ง„๋‹ค. ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ์žƒ๋Š” ๊ฒƒ๋ณด๋‹ค ๋‘ ๋ฒˆ ์„ธ๋Š” ๊ฒƒ์ด ๋‚ซ๋‹ค.
73
210
  */
211
+ /**
212
+ * ์ •์ฒด๋ฅผ ๋ชป ๋งŒ๋“  ์‚ฌ์‹ค์„ **์ข…๋ฅ˜๋ณ„๋กœ** ์„ผ๋‹ค โ€” dedupe ๋ฐ–์œผ๋กœ ๋‚˜๊ฐ„ ๊ฒƒ๋“ค.
213
+ *
214
+ * ์ด ์ˆ˜๊ฐ€ 0์ด ์•„๋‹ˆ๋ฉด ๊ทธ ์ข…๋ฅ˜๋Š” ๋‹ค์‹œ ๋ฐ›์„ ๋•Œ๋งˆ๋‹ค ์ €๋„์— ๋‹ค์‹œ ์•‰๋Š”๋‹ค. ๊ทธ ์ข…๋ฅ˜์˜ ์ฃผ์ฒด ์ด๋ฆ„์„
215
+ * `discriminatorsOf` ์— ๋”ํ•ด์•ผ ํ•œ๋‹ค.
216
+ */
217
+ const unidentified = {};
218
+ /** ์ง€๊ธˆ๊นŒ์ง€ ์ •์ฒด๋ฅผ ๋ชป ๋งŒ๋“  ๊ฒƒ โ€” ์ข…๋ฅ˜๋ณ„. ์ฝ๊ณ  ๋น„์šด๋‹ค. */
219
+ function takeUnidentified() {
220
+ const out = { ...unidentified };
221
+ for (const k of Object.keys(unidentified))
222
+ delete unidentified[k];
223
+ return out;
224
+ }
74
225
  function factIdentity(envelope) {
75
226
  const type = String(envelope?.eventType ?? '').trim();
76
227
  if (!type)
77
228
  return undefined;
78
- const target = targetOf(envelope);
79
- if (!target)
229
+ const parts = discriminatorsOf(envelope);
230
+ /*
231
+ * **์ •์ฒด๋ฅผ ๋ชป ๋งŒ๋“ค๋ฉด dedupe ๋ฐ–์ด๋‹ค** โ€” ๊ทธ ์‚ฌ์‹ค์€ ๋‹ค์‹œ ๋ฐ›์„ ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ ์•‰๋Š”๋‹ค.
232
+ *
233
+ * ์˜ค๋Š˜ ๊ทธ๊ฒƒ์œผ๋กœ ์ €๋„์ด ๋ถ€ํ’€์—ˆ๋‹ค(์ฒ˜๋ถ„ยท์‹œํ—˜์ด `subjectId` ๋ฅผ ์ฃผ์ฒด๋กœ ์“ฐ๋Š”๋ฐ ๊ทธ ์ด๋ฆ„์ด ์œ„ ๋ชฉ๋ก์—
234
+ * ์—†์—ˆ๋‹ค). ์กฐ์šฉํžˆ `undefined` ๋ฅผ ๋‚ด๋ฉด ๋‹ค์Œ ์ข…๋ฅ˜์—์„œ ๋˜ ๋‚˜๊ณ  ๊ทธ๋•Œ๋„ ์•„๋ฌด ํ”์ ์ด ์—†๋‹ค.
235
+ *
236
+ * ๊ทธ๋ž˜์„œ ๋ฌด์—‡์ด ์ •์ฒด๋ฅผ ๋ชป ๋งŒ๋“ค์—ˆ๋Š”์ง€ ์„ผ๋‹ค(`unidentified`). ์„ธ๋Š” ๊ฒƒ์ด์ง€ ๋ง‰๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค โ€”
237
+ * ์ •์ฒด๋ฅผ ๋ชป ๋งŒ๋“ ๋‹ค๊ณ  ์‚ฌ์‹ค์„ ๋ฒ„๋ฆฌ๋ฉด ๊ทธ๊ฒƒ์ด ๋” ๋‚˜์˜๋‹ค.
238
+ */
239
+ if (!parts.length) {
240
+ unidentified[type] = (unidentified[type] ?? 0) + 1;
80
241
  return undefined;
242
+ }
81
243
  const at = timeOf(envelope);
82
244
  if (at === undefined)
83
245
  return undefined;
84
- return `${type}|${target}|${at}`;
246
+ return `${type}|${parts.join('&')}|${at}`;
85
247
  }
86
248
  /**
87
249
  * ์ตœ๊ทผ์— ๋ณธ ์ •์ฒด๋ฅผ ๊ธฐ์–ตํ•œ๋‹ค โ€” **ํฌ๊ธฐ์— ์ƒํ•œ์„ ๋‘”๋‹ค.**
@@ -101,6 +263,30 @@ class FactDeduper {
101
263
  }
102
264
  /** ๊ธฐ์–ตํ•˜๋Š” ์ •์ฒด์˜ ์ˆ˜ โ€” ์ฐฝ. */
103
265
  static { this.WINDOW = 20_000; }
266
+ /**
267
+ * ์ด๋ฏธ ์•„๋Š” ๊ฒƒ์œผ๋กœ **๋ฏธ๋ฆฌ ๊ธฐ์–ตํ•œ๋‹ค** โ€” ์ €๋„์—์„œ ์ฝ์–ด ์ฑ„์šธ ๋•Œ.
268
+ *
269
+ * โ”€โ”€ ์™œ ํ•„์š”ํ•œ๊ฐ€ (2026-09-06 ์ธก์ •) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
270
+ * ์ด ๊ธฐ์–ต์€ ํ”„๋กœ์„ธ์Šค ์•ˆ์—๋งŒ ์žˆ๋‹ค. ์žฌ๊ธฐ๋™ํ•˜๋ฉด ๋น„์›Œ์ง€๊ณ , ๊ทธ ๋’ค backfill ์„ ๋Œ๋ฆฌ๋ฉด **์ด๋ฏธ ์ €๋„์—
271
+ * ์žˆ๋Š” ์‚ฌ์‹ค๋„ ใ€Œ์ฒ˜์Œ ๋ณธ ๊ฒƒใ€**์ด ๋œ๋‹ค.
272
+ *
273
+ * ์‹ค์ œ๋กœ ๊ทธ๋žฌ๋‹ค. `mes-line-a` ๋ฅผ ์žฌ๊ธฐ๋™ ๋’ค backfill ํ•˜๋‹ˆ 39๊ฑด์ด ์ „๋ถ€ ๋‹ค์‹œ ์•‰์•„ ์ €๋„์ด
274
+ * 44 โ†’ 83๊ฑด์ด ๋˜๊ณ  44๊ฐ€์ง€๊ฐ€ ์ค‘๋ณต์ด ๋๋‹ค.
275
+ *
276
+ * push ๊ฒฝ๋กœ์—์„œ๋Š” ์•ˆ ๋ณด์ธ๋‹ค. ์žฌ์ „์†ก์ด ๋ช‡ ๋ถ„ ์•ˆ์— ์˜ค๋ฏ€๋กœ ์ฐฝ ์•ˆ์—์„œ ๊ฑธ๋ฆฐ๋‹ค. **backfill ์ด ๊ทธ ์ „์ œ๋ฅผ
277
+ * ๊นฌ๋‹ค** โ€” ๋ช‡ ๋‹ฌ ์ „ ์‚ฌ์‹ค์„ ์ง€๊ธˆ ๋ฐ›์œผ๋‹ˆ ์žฌ๊ธฐ๋™ ํ•œ ๋ฒˆ์ด๋ฉด ๊ทธ ๊ตฌ๊ฐ„์ด ํ†ต์งธ๋กœ ๋‹ค์‹œ ์•‰๋Š”๋‹ค.
278
+ *
279
+ * ๊ทธ๋ž˜์„œ backfill ์ด ๋ถ€๋ฅด๊ธฐ ์ „์— ๊ทธ ๊ตฌ๊ฐ„์˜ ์ •์ฒด๋ฅผ ์ €๋„์—์„œ ์ฝ์–ด ์—ฌ๊ธฐ ๋„ฃ๋Š”๋‹ค.
280
+ */
281
+ remember(identities) {
282
+ let added = 0;
283
+ for (const id of identities)
284
+ if (id && !this.seen.has(id)) {
285
+ this.known(id);
286
+ added++;
287
+ }
288
+ return added;
289
+ }
104
290
  /** ์ด ์‚ฌ์‹ค์„ ๋ณธ ์ ์ด ์žˆ๋‚˜ โ€” ์—†์œผ๋ฉด ๊ธฐ์–ตํ•˜๊ณ  `false`. */
105
291
  known(identity) {
106
292
  if (this.seen.has(identity))
@@ -1 +1 @@
1
- {"version":3,"file":"ingest-dedupe.js","sourceRoot":"","sources":["../../server/engine/ingest-dedupe.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * ๊ฐ™์€ ์‚ฌ์‹ค์„ ๋‘ ๋ฒˆ ๋ฐ›์œผ๋ฉด ํ•œ ๋ฒˆ๋งŒ ๋ฐ˜์˜ํ•œ๋‹ค โ€” **์œ ์ž… ๊ฒฝ๊ณ„ ํ•œ ๊ณณ์—์„œ.**\n *\n * โ”€โ”€ ์™œ ํ•„์š”ํ•œ๊ฐ€ (2026-08-26) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ง€๊ธˆ ์ค‘๋ณต์„ ๋ง‰๋Š” ๊ฒƒ์€ ์ปค๋„ฅํ„ฐ๋งˆ๋‹ค ๊ฐ์ž ํ•˜๊ณ  ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ปค๋„ฅํ„ฐ๊ฐ€ ๊ทธ๊ฒƒ์„ ์žŠ์œผ๋ฉด ํŠธ์œˆ์ด ๊ทธ๋Œ€๋กœ ๋‘ ๋ฒˆ\n * ์„ผ๋‹ค. ์‹ค์ œ๋กœ ๊ทธ๋žฌ๋‹ค: ํƒœ์–‘๊ด‘ ์ปค๋„ฅํ„ฐ๊ฐ€ 10์ดˆ๋งˆ๋‹ค ๋ฌผ์œผ๋ฉด์„œ 10๋ถ„๋งˆ๋‹ค ๋ฐ”๋€Œ๋Š” ๊ฐ’์„ ๋งค๋ฒˆ ๋‹ค์‹œ ๋ณด๋ƒˆ๊ณ ,\n * ํ•œ ์ฃผ๊ธฐ์— 76๊ฑด์ด ๋˜ํ’€์ด๋๋‹ค(์ปค๋„ฅํ„ฐ์—์„œ ๊ณ ์ณ์„œ 2๊ฑด์ด ๋๋‹ค).\n *\n * ๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์€ ์›นํ›…์œผ๋กœ ๋ฐ›์„ ๋•Œ ๋” ์ž์ฃผ ๋‚œ๋‹ค. ๋ฐ€์–ด ์ฃผ๋Š” ๋ฐฉ์‹์€ ์žฌ์ „์†ก์ด ์ •์ƒ์ด๋‹ค โ€” ๊ทธ์ชฝ์ด ์‘๋‹ต์„\n * ๋ชป ๋ฐ›์œผ๋ฉด ๊ฐ™์€ ๊ฒƒ์„ ๋‹ค์‹œ ๋ณด๋‚ธ๋‹ค.\n *\n * โ”€โ”€ ๋ฌด์—‡์ด ๋‘ ๋ฒˆ ์„ธ์–ด์ง€๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ ˆ๋Œ€๊ฐ’์œผ๋กœ ๋งํ•˜๋Š” ์‚ฌ์‹ค์€ ์—ฌ๋Ÿฌ ๋ฒˆ ๋ฐ˜์˜ํ•ด๋„ ๊ฒฐ๊ณผ๊ฐ€ ๊ฐ™๋‹ค(์ž”๋Ÿ‰ ยท ์ƒํƒœ ยท ์ ์‚ฐ ยท ์ˆœ๊ฐ„ kW). ๊ทธ๋Ÿฐ๋ฐ ์„ธ๋Š”\n * ๊ฐ’์€ ๊ทธ๋ ‡์ง€ ์•Š๋‹ค.\n *\n * ๊ตฌ๊ฐ„์˜ ํ‘œ๋ณธ ์ˆ˜ ยท ํ‰๊ท  ๋ถ€ํ•˜(ํ‘œ๋ณธ ์ˆ˜๋กœ ๋‚˜๋ˆˆ๋‹ค) ยท OEE ์นด์šดํ„ฐ ยท ์œ ์ž… ๊ณ„์ˆ˜\n * ๊ทธ๋ฆฌ๊ณ  ์ง€๋‚œ ๊ธฐ๋ก์— ๊ฐ™์€ ์‚ฌ์‹ค์ด ๋‘ ์ค„๋กœ ๋‚จ๋Š”๋‹ค โ€” ๋‚˜์ค‘์— ๊ทธ ๊ธฐ๋ก์œผ๋กœ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜๋ฉด ๋˜ ๋‘ ๋ฒˆ ์„ผ๋‹ค\n *\n * โ”€โ”€ ์ •์ฒด๋ฅผ ๋ฌด์—‡์œผ๋กœ ๋ณด๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๋ด‰ํˆฌ์˜ `eventId` ๋กœ๋Š” ํŒ๋‹จํ•  ์ˆ˜ ์—†๋‹ค. ๋ณด๋‚ธ ์ชฝ์ด ๋งค๋ฒˆ ์ƒˆ๋กœ ๋งŒ๋“œ๋Š” ์ˆœ๋ฒˆ์ด๊ณ (`โ€ฆ-energy-1` ์ฒ˜๋Ÿผ ํ˜ธ์ถœ๋งˆ๋‹ค\n * 1๋ถ€ํ„ฐ ๋‹ค์‹œ ์‹œ์ž‘ํ•œ๋‹ค), ๊ฐ™์€ ์‚ฌ์‹ค์„ ๋‘ ๋ฒˆ ๋ณด๋‚ด๋ฉด ๋‹ค๋ฅธ ๋ฒˆํ˜ธ๊ฐ€ ๋ถ™๋Š”๋‹ค. ๋‹ค๋ฅธ ์‚ฌ์‹ค์— ๊ฐ™์€ ๋ฒˆํ˜ธ๊ฐ€ ๋ถ™๋Š” ์ผ๋„\n * ์ƒ๊ธด๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ **์‚ฌ์‹ค ์ž์ฒด๋กœ** ํŒ๋‹จํ•œ๋‹ค.\n *\n * ๋ฌด์—‡์— ๋Œ€ํ•œ ๊ฒƒ์ธ๊ฐ€ ์„ค๋น„ ยท ๊ณ„๋Ÿ‰ ์ง€์  ยท ๋ฌผํ’ˆ ยท ์ž‘์—… ยท ์˜ค๋” ยท ์ž๋ฆฌ\n * ์–ด๋–ค ์ข…๋ฅ˜์ธ๊ฐ€ ์‚ฌ๊ฑด ์ข…๋ฅ˜(eventType)\n * ์–ธ์ œ ์žฐ ๊ฒƒ์ธ๊ฐ€ ์—ฐ๊ฒฐ๋œ ์‹œ์Šคํ…œ์ด ์ค€ ์‹œ๊ฐ\n *\n * ์ด ์…‹์ด ๊ฐ™์œผ๋ฉด ๊ฐ™์€ ์‚ฌ์‹ค์ด๋‹ค. ํƒœ์–‘๊ด‘ ์ปค๋„ฅํ„ฐ๊ฐ€ `collectedAt` ์œผ๋กœ ํŒ๋‹จํ•œ ๊ฒƒ๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์ด๊ณ , ๊ทธ๊ฒƒ์„\n * ์ปค๋„ฅํ„ฐ๋งˆ๋‹ค ํ•˜์ง€ ์•Š๋„๋ก ์—ฌ๊ธฐ๋กœ ์˜ฌ๋ฆฐ๋‹ค.\n *\n * โ”€โ”€ ์ •ํ™•ํžˆ ๊ฐ™์€ ๊ฒƒ๋งŒ ๋ฒ„๋ฆฐ๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๋Šฆ๊ฒŒ ๋„์ฐฉํ•œ ์˜› ์‚ฌ์‹ค์€ ๋ฒ„๋ฆฌ์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๊ฒƒ์ด ์™”๋‹ค๋Š” ๊ฒƒ ์ž์ฒด๊ฐ€ ์‚ฌ์‹ค์ด๊ณ , ์ƒํƒœ์— ๋ฐ˜์˜๋˜์ง€ ์•Š๋Š” ๊ฒƒ์€\n * ์ปค๋„์˜ ์ˆœ์„œ ํŒ๋‹จ์ด ์ด๋ฏธ ๋งก๋Š”๋‹ค. ์—ฌ๊ธฐ์„œ ๋ฒ„๋ฆฌ๋Š” ๊ฒƒ์€ **์ •์ฒด๊ฐ€ ์™„์ „ํžˆ ๊ฐ™์€ ๊ฒƒ**๋ฟ์ด๋‹ค.\n */\n\n/** ์‹œ๊ฐ์„ ๋ฐ€๋ฆฌ์ดˆ๋กœ โ€” ์—ฐ๊ฒฐ๋œ ์‹œ์Šคํ…œ์ด ์ค€ ์‹œ๊ฐ์ด ๋จผ์ €, ์—†์œผ๋ฉด ๋ด‰ํˆฌ์˜ ์‹œ๊ฐ. */\nfunction timeOf(envelope: any): number | undefined {\n for (const v of [envelope?.data?.at, envelope?.data?.eventTime, envelope?.eventTime]) {\n const t = Date.parse(String(v ?? ''))\n if (Number.isFinite(t)) return t\n }\n return undefined\n}\n\n/**\n * ์ด ๋ด‰ํˆฌ๊ฐ€ ๋งํ•˜๋Š” ๋Œ€์ƒ โ€” ์–ดํœ˜๋งˆ๋‹ค ์ด๋ฆ„์ด ๋‹ค๋ฅด๋ฏ€๋กœ ์•„๋Š” ์ด๋ฆ„์„ ๋ชจ๋‘ ๋ณธ๋‹ค.\n *\n * ์ˆœ์„œ๊ฐ€ ๋œป์„ ๊ฐ–๋Š”๋‹ค: ์ฃผ์ฒด๋ฅผ ๋จผ์ € ๋ณธ๋‹ค. ์„ค๋น„ ์‚ฌ์‹ค์€ ใ€Œ์ง€๊ธˆ ๋ถ™์–ด ์žˆ๋Š” ์ž‘์—…ใ€์„ ํ•จ๊ป˜ ์‹ฃ๊ณ , ์ž‘์—… ์‚ฌ์‹ค์€\n * ใ€Œ์†Œ์† ์˜ค๋”ใ€๋ฅผ ํ•จ๊ป˜ ์‹ฃ๋Š”๋‹ค. ์•„๋ฌด ์ด๋ฆ„์ด๋‚˜ ๋จผ์ € ๋ณด๋ฉด ์ฐธ์กฐ๋ฅผ ์ฃผ์ฒด๋กœ ์ฝ๋Š”๋‹ค(์Šน๊ฒฉ ํ‚ค์—์„œ ๊ฒช์€ ๊ฒƒ๊ณผ ๊ฐ™๋‹ค).\n */\nfunction targetOf(envelope: any): string | undefined {\n const d = envelope?.data ?? {}\n const first = (...vals: unknown[]) => {\n for (const v of vals) {\n const s = String(v ?? '').trim()\n if (s) return s\n }\n return undefined\n }\n return first(\n d.meterId,\n d.equipmentId,\n d.moverId,\n d.taskId,\n d.orderId,\n d.personId,\n d.assetId,\n d.locationId,\n d.epcList?.[0],\n d.parentID,\n d.quantityList?.[0]?.epcClass,\n d.transformationID\n )\n}\n\n/**\n * ์ด ๋ด‰ํˆฌ๊ฐ€ ๋งํ•˜๋Š” ์‚ฌ์‹ค์˜ ์ •์ฒด โ€” ๊ฐ™์œผ๋ฉด ๊ฐ™์€ ์‚ฌ์‹ค์ด๋‹ค.\n *\n * ๋Œ€์ƒ์ด๋‚˜ ์‹œ๊ฐ์„ ์•Œ ์ˆ˜ ์—†์œผ๋ฉด **์ •์ฒด๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค**(`undefined`). ๊ทธ๋•Œ๋Š” ๊ฑฐ๋ฅด์ง€ ์•Š๊ณ  ํ†ต๊ณผ์‹œํ‚จ๋‹ค โ€”\n * ๋ชจ๋ฅด๋Š” ๊ฒƒ์„ ๊ฐ™๋‹ค๊ณ  ํŒ๋‹จํ•˜๋ฉด ์„œ๋กœ ๋‹ค๋ฅธ ์‚ฌ์‹ค์ด ํ•˜๋‚˜๋กœ ํ•ฉ์ณ์ง„๋‹ค. ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ์žƒ๋Š” ๊ฒƒ๋ณด๋‹ค ๋‘ ๋ฒˆ ์„ธ๋Š” ๊ฒƒ์ด ๋‚ซ๋‹ค.\n */\nexport function factIdentity(envelope: any): string | undefined {\n const type = String(envelope?.eventType ?? '').trim()\n if (!type) return undefined\n const target = targetOf(envelope)\n if (!target) return undefined\n const at = timeOf(envelope)\n if (at === undefined) return undefined\n return `${type}|${target}|${at}`\n}\n\n/**\n * ์ตœ๊ทผ์— ๋ณธ ์ •์ฒด๋ฅผ ๊ธฐ์–ตํ•œ๋‹ค โ€” **ํฌ๊ธฐ์— ์ƒํ•œ์„ ๋‘”๋‹ค.**\n *\n * ์ „๋ถ€ ๊ธฐ์–ตํ•  ์ˆ˜๋Š” ์—†๋‹ค(ํŠธ์œˆ ํ•˜๋‚˜๊ฐ€ ์ˆ˜์ฒœ๋งŒ ์‚ฌ๊ฑด์„ ๊ฐ–๋Š”๋‹ค). ์ฐฝ์„ ๋„˜์œผ๋ฉด ์˜ค๋ž˜๋œ ๊ฒƒ๋ถ€ํ„ฐ ์žŠ๋Š”๋‹ค. ์ฐฝ ๋ฐ–์˜\n * ์žฌ์ „์†ก์€ ๋‹ค์‹œ ํ†ต๊ณผํ•˜๋Š”๋ฐ, ๊ทธ๊ฒƒ์€ ์ ˆ๋Œ€๊ฐ’ ์‚ฌ์‹ค์ด๋ผ ์ƒํƒœ์— ํ•ด๊ฐ€ ์—†๊ณ  ์ง€๋‚œ ๊ธฐ๋ก์— ํ•œ ์ค„ ๋” ๋‚จ๋Š”๋‹ค.\n * ์ฐฝ์„ ํฌ๊ฒŒ ์žก์œผ๋ฉด ๊ทธ๋งŒํผ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์“ด๋‹ค โ€” ๊ทธ ๊ฐ’์„ ์—ฌ๊ธฐ์„œ ์ด๋ฆ„์œผ๋กœ ๋ชป ๋ฐ•๋Š”๋‹ค.\n *\n * **์žฌ๊ธฐ๋™์„ ๊ฑด๋„ˆ์ง€ ๋ชปํ•œ๋‹ค.** ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ƒˆ๋กœ ๋œจ๋ฉด ๊ธฐ์–ต์ด ๋น„์–ด ์žˆ์œผ๋ฏ€๋กœ, ์žฌ๊ธฐ๋™ ์งํ›„ ์ฒซ ์ฃผ๊ธฐ๊ฐ€ ๊ฐ™์€\n * ๊ฐ’์„ ๋‹ค์‹œ ๋ณด๋‚ด๋ฉด ๊ฑธ๋Ÿฌ์ง€์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๊ฒƒ์„ ๋ง‰์œผ๋ ค๋ฉด ์ด ๊ธฐ์–ต์ด ์ €์žฅ๋ผ์•ผ ํ•˜๊ณ , ๊ทธ๊ฒƒ์€ ๋‹ค์Œ ๊ฑธ์Œ์ด๋‹ค.\n * ์ง€๊ธˆ์€ ๊ทธ ์‚ฌ์‹ค์„ ์—ฌ๊ธฐ ์ ์–ด ๋‘”๋‹ค โ€” ์ ์–ด ๋‘์ง€ ์•Š์œผ๋ฉด ใ€Œ์ค‘๋ณต์€ ์ด์ œ ์—†๋‹คใ€๋กœ ์ฝํžŒ๋‹ค.\n */\nexport class FactDeduper {\n /** ๊ธฐ์–ตํ•˜๋Š” ์ •์ฒด์˜ ์ˆ˜ โ€” ์ฐฝ. */\n static WINDOW = 20_000\n\n private seen = new Set<string>()\n private order: string[] = []\n\n /** ์ด ์‚ฌ์‹ค์„ ๋ณธ ์ ์ด ์žˆ๋‚˜ โ€” ์—†์œผ๋ฉด ๊ธฐ์–ตํ•˜๊ณ  `false`. */\n private known(identity: string): boolean {\n if (this.seen.has(identity)) return true\n this.seen.add(identity)\n this.order.push(identity)\n if (this.order.length > FactDeduper.WINDOW) {\n const gone = this.order.splice(0, this.order.length - FactDeduper.WINDOW)\n for (const g of gone) this.seen.delete(g)\n }\n return false\n }\n\n /**\n * ์ฒ˜์Œ ๋ณด๋Š” ๊ฒƒ๋งŒ ๋Œ๋ ค์ค€๋‹ค โ€” ๊ทธ๋ฆฌ๊ณ  ๋ช‡ ๊ฐœ๋ฅผ ๋ฒ„๋ ธ๋Š”์ง€ ํ•จ๊ป˜ ๋‚ธ๋‹ค.\n *\n * ๋ฒ„๋ฆฐ ์ˆ˜๋ฅผ ํ•จ๊ป˜ ๋‚ด๋Š” ์ด์œ : ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ๋ฒ„๋ฆฌ๋ฉด ใ€Œ๋ณด๋‚ธ ์ˆ˜ใ€์™€ ใ€Œ๋ฐ˜์˜๋œ ์ˆ˜ใ€๊ฐ€ ์–ด๊ธ‹๋‚˜๋Š”๋ฐ ์•„๋ฌด๋„ ๊ทธ\n * ์ด์œ ๋ฅผ ๋ชจ๋ฅธ๋‹ค. ๊ทธ ์ˆ˜๊ฐ€ ํฌ๋ฉด ๋ณด๋‚ด๋Š” ์ชฝ์ด ๋˜ํ’€์ด ๋ณด๋‚ด๊ณ  ์žˆ๋‹ค๋Š” ๋œป์ด๊ณ , ๊ทธ๊ฒƒ์€ ๊ณ ์น  ์ผ์ด๋‹ค.\n */\n filter<T>(envelopes: readonly T[]): { fresh: T[]; duplicates: number } {\n const fresh: T[] = []\n let duplicates = 0\n for (const e of envelopes) {\n const id = factIdentity(e)\n if (id === undefined) {\n fresh.push(e)\n continue\n }\n if (this.known(id)) duplicates++\n else fresh.push(e)\n }\n return { fresh, duplicates }\n }\n\n /** ๊ธฐ์–ตํ•˜๊ณ  ์žˆ๋Š” ์ •์ฒด์˜ ์ˆ˜ โ€” ๊ณ„๊ธฐ๊ฐ€ ์ฝ๋Š”๋‹ค. */\n size(): number {\n return this.seen.size\n }\n}\n"]}
1
+ {"version":3,"file":"ingest-dedupe.js","sourceRoot":"","sources":["../../server/engine/ingest-dedupe.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * ๊ฐ™์€ ์‚ฌ์‹ค์„ ๋‘ ๋ฒˆ ๋ฐ›์œผ๋ฉด ํ•œ ๋ฒˆ๋งŒ ๋ฐ˜์˜ํ•œ๋‹ค โ€” **์œ ์ž… ๊ฒฝ๊ณ„ ํ•œ ๊ณณ์—์„œ.**\n *\n * โ”€โ”€ ์™œ ํ•„์š”ํ•œ๊ฐ€ (2026-08-26) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ง€๊ธˆ ์ค‘๋ณต์„ ๋ง‰๋Š” ๊ฒƒ์€ ์ปค๋„ฅํ„ฐ๋งˆ๋‹ค ๊ฐ์ž ํ•˜๊ณ  ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ปค๋„ฅํ„ฐ๊ฐ€ ๊ทธ๊ฒƒ์„ ์žŠ์œผ๋ฉด ํŠธ์œˆ์ด ๊ทธ๋Œ€๋กœ ๋‘ ๋ฒˆ\n * ์„ผ๋‹ค. ์‹ค์ œ๋กœ ๊ทธ๋žฌ๋‹ค: ํƒœ์–‘๊ด‘ ์ปค๋„ฅํ„ฐ๊ฐ€ 10์ดˆ๋งˆ๋‹ค ๋ฌผ์œผ๋ฉด์„œ 10๋ถ„๋งˆ๋‹ค ๋ฐ”๋€Œ๋Š” ๊ฐ’์„ ๋งค๋ฒˆ ๋‹ค์‹œ ๋ณด๋ƒˆ๊ณ ,\n * ํ•œ ์ฃผ๊ธฐ์— 76๊ฑด์ด ๋˜ํ’€์ด๋๋‹ค(์ปค๋„ฅํ„ฐ์—์„œ ๊ณ ์ณ์„œ 2๊ฑด์ด ๋๋‹ค).\n *\n * ๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์€ ์›นํ›…์œผ๋กœ ๋ฐ›์„ ๋•Œ ๋” ์ž์ฃผ ๋‚œ๋‹ค. ๋ฐ€์–ด ์ฃผ๋Š” ๋ฐฉ์‹์€ ์žฌ์ „์†ก์ด ์ •์ƒ์ด๋‹ค โ€” ๊ทธ์ชฝ์ด ์‘๋‹ต์„\n * ๋ชป ๋ฐ›์œผ๋ฉด ๊ฐ™์€ ๊ฒƒ์„ ๋‹ค์‹œ ๋ณด๋‚ธ๋‹ค.\n *\n * โ”€โ”€ ๋ฌด์—‡์ด ๋‘ ๋ฒˆ ์„ธ์–ด์ง€๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ ˆ๋Œ€๊ฐ’์œผ๋กœ ๋งํ•˜๋Š” ์‚ฌ์‹ค์€ ์—ฌ๋Ÿฌ ๋ฒˆ ๋ฐ˜์˜ํ•ด๋„ ๊ฒฐ๊ณผ๊ฐ€ ๊ฐ™๋‹ค(์ž”๋Ÿ‰ ยท ์ƒํƒœ ยท ์ ์‚ฐ ยท ์ˆœ๊ฐ„ kW). ๊ทธ๋Ÿฐ๋ฐ ์„ธ๋Š”\n * ๊ฐ’์€ ๊ทธ๋ ‡์ง€ ์•Š๋‹ค.\n *\n * ๊ตฌ๊ฐ„์˜ ํ‘œ๋ณธ ์ˆ˜ ยท ํ‰๊ท  ๋ถ€ํ•˜(ํ‘œ๋ณธ ์ˆ˜๋กœ ๋‚˜๋ˆˆ๋‹ค) ยท OEE ์นด์šดํ„ฐ ยท ์œ ์ž… ๊ณ„์ˆ˜\n * ๊ทธ๋ฆฌ๊ณ  ์ง€๋‚œ ๊ธฐ๋ก์— ๊ฐ™์€ ์‚ฌ์‹ค์ด ๋‘ ์ค„๋กœ ๋‚จ๋Š”๋‹ค โ€” ๋‚˜์ค‘์— ๊ทธ ๊ธฐ๋ก์œผ๋กœ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜๋ฉด ๋˜ ๋‘ ๋ฒˆ ์„ผ๋‹ค\n *\n * โ”€โ”€ ์ •์ฒด๋ฅผ ๋ฌด์—‡์œผ๋กœ ๋ณด๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๋ด‰ํˆฌ์˜ `eventId` ๋กœ๋Š” ํŒ๋‹จํ•  ์ˆ˜ ์—†๋‹ค. ๋ณด๋‚ธ ์ชฝ์ด ๋งค๋ฒˆ ์ƒˆ๋กœ ๋งŒ๋“œ๋Š” ์ˆœ๋ฒˆ์ด๊ณ (`โ€ฆ-energy-1` ์ฒ˜๋Ÿผ ํ˜ธ์ถœ๋งˆ๋‹ค\n * 1๋ถ€ํ„ฐ ๋‹ค์‹œ ์‹œ์ž‘ํ•œ๋‹ค), ๊ฐ™์€ ์‚ฌ์‹ค์„ ๋‘ ๋ฒˆ ๋ณด๋‚ด๋ฉด ๋‹ค๋ฅธ ๋ฒˆํ˜ธ๊ฐ€ ๋ถ™๋Š”๋‹ค. ๋‹ค๋ฅธ ์‚ฌ์‹ค์— ๊ฐ™์€ ๋ฒˆํ˜ธ๊ฐ€ ๋ถ™๋Š” ์ผ๋„\n * ์ƒ๊ธด๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ **์‚ฌ์‹ค ์ž์ฒด๋กœ** ํŒ๋‹จํ•œ๋‹ค.\n *\n * ๋ฌด์—‡์— ๋Œ€ํ•œ ๊ฒƒ์ธ๊ฐ€ ์„ค๋น„ ยท ๊ณ„๋Ÿ‰ ์ง€์  ยท ๋ฌผํ’ˆ ยท ์ž‘์—… ยท ์˜ค๋” ยท ์ž๋ฆฌ\n * ์–ด๋–ค ์ข…๋ฅ˜์ธ๊ฐ€ ์‚ฌ๊ฑด ์ข…๋ฅ˜(eventType)\n * ์–ธ์ œ ์žฐ ๊ฒƒ์ธ๊ฐ€ ์—ฐ๊ฒฐ๋œ ์‹œ์Šคํ…œ์ด ์ค€ ์‹œ๊ฐ\n *\n * ์ด ์…‹์ด ๊ฐ™์œผ๋ฉด ๊ฐ™์€ ์‚ฌ์‹ค์ด๋‹ค. ํƒœ์–‘๊ด‘ ์ปค๋„ฅํ„ฐ๊ฐ€ `collectedAt` ์œผ๋กœ ํŒ๋‹จํ•œ ๊ฒƒ๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์ด๊ณ , ๊ทธ๊ฒƒ์„\n * ์ปค๋„ฅํ„ฐ๋งˆ๋‹ค ํ•˜์ง€ ์•Š๋„๋ก ์—ฌ๊ธฐ๋กœ ์˜ฌ๋ฆฐ๋‹ค.\n *\n * โ”€โ”€ ์ •ํ™•ํžˆ ๊ฐ™์€ ๊ฒƒ๋งŒ ๋ฒ„๋ฆฐ๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๋Šฆ๊ฒŒ ๋„์ฐฉํ•œ ์˜› ์‚ฌ์‹ค์€ ๋ฒ„๋ฆฌ์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๊ฒƒ์ด ์™”๋‹ค๋Š” ๊ฒƒ ์ž์ฒด๊ฐ€ ์‚ฌ์‹ค์ด๊ณ , ์ƒํƒœ์— ๋ฐ˜์˜๋˜์ง€ ์•Š๋Š” ๊ฒƒ์€\n * ์ปค๋„์˜ ์ˆœ์„œ ํŒ๋‹จ์ด ์ด๋ฏธ ๋งก๋Š”๋‹ค. ์—ฌ๊ธฐ์„œ ๋ฒ„๋ฆฌ๋Š” ๊ฒƒ์€ **์ •์ฒด๊ฐ€ ์™„์ „ํžˆ ๊ฐ™์€ ๊ฒƒ**๋ฟ์ด๋‹ค.\n */\n\n/** ์‹œ๊ฐ์„ ๋ฐ€๋ฆฌ์ดˆ๋กœ โ€” ์—ฐ๊ฒฐ๋œ ์‹œ์Šคํ…œ์ด ์ค€ ์‹œ๊ฐ์ด ๋จผ์ €, ์—†์œผ๋ฉด ๋ด‰ํˆฌ์˜ ์‹œ๊ฐ. */\nfunction timeOf(envelope: any): number | undefined {\n for (const v of [envelope?.data?.at, envelope?.data?.eventTime, envelope?.eventTime]) {\n const t = Date.parse(String(v ?? ''))\n if (Number.isFinite(t)) return t\n }\n return undefined\n}\n\n/**\n * ์ด ๋ด‰ํˆฌ๊ฐ€ ๋งํ•˜๋Š” ๊ฒƒ์„ **๊ฐ€๋ฅด๋Š” ๊ฐ’๋“ค** โ€” ํ•˜๋‚˜๋ผ๋„ ๋‹ค๋ฅด๋ฉด ๋‹ค๋ฅธ ์‚ฌ์‹ค์ด๋‹ค.\n *\n * โ”€โ”€ ์˜ˆ์ „์—๋Š” ํ•˜๋‚˜๋งŒ ๊ณจ๋ž๋‹ค (2026-09-05 ์‹ค์ธก) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์•„๋Š” ์ด๋ฆ„์„ ์ˆœ์„œ๋Œ€๋กœ ๋ณด๊ณ  **๋จผ์ € ๊ฑธ๋ฆฌ๋Š” ํ•˜๋‚˜**๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์‚ผ์•˜๋‹ค. ใ€Œ์ฃผ์ฒด๋ฅผ ๋จผ์ € ๋ณธ๋‹คใ€๋Š” ํŒ๋‹จ\n * ์ž์ฒด๋Š” ์˜ณ๋‹ค โ€” ์„ค๋น„ ์‚ฌ์‹ค์€ ใ€Œ์ง€๊ธˆ ๋ถ™์–ด ์žˆ๋Š” ์ž‘์—…ใ€์„ ์ฐธ์กฐ๋กœ ์‹ฃ๋Š”๋‹ค. ๊ทธ๋Ÿฐ๋ฐ **๊ณ ๋ฅด๊ณ  ๋‚˜๋จธ์ง€๋ฅผ\n * ๋ฒ„๋ฆฐ ๊ฒƒ**์ด ๊ฒฐํ•จ์ด์—ˆ๋‹ค.\n *\n * ์‹ค์ œ๋กœ ๋‚œ ์ผ: plant ์ด ์‹ค์  ๋‘˜์„ ๋ณด๋ƒˆ๋Š”๋ฐ ํ•œ ๊ฑด์ด ์ €๋„์— ์•ˆ ๋‚จ์•˜๋‹ค.\n *\n * seq 36 quality.output moverId EQ-CT-MWELD-01 ยท taskId PR-CT-WIRE-01 ยท goodCount 12\n * seq 41 quality.output moverId EQ-CT-MWELD-01 ยท taskId PR-CT-WIRE-02 ยท goodCount 9\n *\n * ๋‘ ์‹ค์ ์˜ ์‹œ๊ฐ์ด ๊ฐ™์•˜๊ณ (์›๋ณธ์ด ๋์‹œ๊ฐ์„ ๋ณต์‚ฌ) `moverId` ๊ฐ€ `taskId` ๋ณด๋‹ค ๋จผ์ €๋ผ **๋‘˜์ด ํ•œ ์‚ฌ์‹ค์ด\n * ๋๋‹ค.** ๊ฑฐ๋ถ€๊ฐ€ ์•„๋‹ˆ๋ผ ๋˜ํ’€์ด๋กœ ์„ธ์–ด์กŒ๋‹ค โ€” `offered 5 ยท rejected 0 ยท journaled 3`.\n *\n * **๊ตฌ๋ณ„ํ•  ๊ฐ’์ด ์ด๋ฏธ ๋ด‰ํˆฌ ์•ˆ์— ์žˆ์—ˆ๋Š”๋ฐ ํŒ์ •์ด ๊ทธ๊ฒƒ์„ ์•ˆ ๋ดค๋‹ค.**\n *\n * โ”€โ”€ ๊ทธ๋ฆฌ๊ณ  EPCIS ๋„ ๊ฐ™์•˜๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ €๋„ 246๋งŒ ๊ฑด์— ํ˜„์žฌ ๊ทœ์น™์„ ๋‹ค์‹œ ๊ฑธ์–ด ๋ณด๋‹ˆ ๊ฒน์น˜๋Š” ๋ฌถ์Œ์ด ์—ฌ์„ฏ์ด์—ˆ๊ณ , ์ „๋ถ€ ์ด ๋ชจ์–‘์ด๋‹ค.\n *\n * ๊ฐ™์€ EPC ยท ๊ฐ™์€ ๋ฐ€๋ฆฌ์ดˆ\n * โ‘  bizStep receiving action ADD disposition sellable_accessible\n * โ‘ก bizStep commissioning action OBSERVE disposition reserved\n *\n * **ํ•œ ๊ฐœ์ฒด์˜ ์„œ๋กœ ๋‹ค๋ฅธ ๊ด€์ธก**์ด๋‹ค. EPCIS ์—์„œ ์ด์ƒํ•œ ์ผ์ด ์•„๋‹Œ๋ฐ ๊ทœ์น™์ด ๊ทธ ์…‹์„ ์•ˆ ๋ดค๋‹ค.\n *\n * โ”€โ”€ ์™œ ๋„“ํžˆ๋Š” ์ชฝ์ด ๋งž๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ด ํŒŒ์ผ์ด ์Šค์Šค๋กœ ์ ์–ด ๋‘” ๊ฐ’์ด ๊ทธ๊ฒƒ์ด๋‹ค โ€” ใ€Œ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ์žƒ๋Š” ๊ฒƒ๋ณด๋‹ค ๋‘ ๋ฒˆ ์„ธ๋Š” ๊ฒƒ์ด ๋‚ซ๋‹คใ€.\n * ์ง€๊ธˆ ๊ฑฐ๋™์€ **์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ์žƒ๋Š” ์ชฝ**์ด์—ˆ๋‹ค.\n *\n * ๋„“ํ˜€๋„ ๋˜ํ’€์ด๋Š” ๊ทธ๋Œ€๋กœ ๊ฑธ๋ฆฐ๋‹ค: ๊ฐ™์€ ๋ด‰ํˆฌ๋ฅผ ๋‹ค์‹œ ๋ณด๋‚ด๋ฉด **์ด ๊ฐ’๋“ค์ด ์ „๋ถ€ ๊ฐ™๋‹ค.** ๋„“ํžˆ๋Š” ๊ฒƒ์€\n * ใ€Œ๋‹ค๋ฅธ ์‚ฌ์‹ค์„ ํ•ฉ์น˜์ง€ ์•Š๋Š”๋‹คใ€๋งŒ ๊ฐ•ํ•ด์ง€๊ณ  ใ€Œ๋˜ํ’€์ด๋ฅผ ์žก๋Š”๋‹คใ€๋Š” ์•ˆ ์•ฝํ•ด์ง„๋‹ค.\n */\nfunction discriminatorsOf(envelope: any): string[] {\n const d = envelope?.data ?? {}\n const out: string[] = []\n const put = (name: string, v: unknown) => {\n const t = String(v ?? '').trim()\n if (t) out.push(`${name}=${t}`)\n }\n\n /*\n * ์ฃผ์ฒดยท์ฐธ์กฐ๋ฅผ **๋‹ค ์ ๋Š”๋‹ค.** ์ˆœ์„œ๋Š” ๊ฐ’์ด ์•„๋‹ˆ๋ผ ์ด๋ฆ„์œผ๋กœ ๊ณ ์ •๋˜๋ฏ€๋กœ ๋ด‰ํˆฌ๋งˆ๋‹ค ํ”๋“ค๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.\n *\n * โš  **์ด ๋ชฉ๋ก์€ ๊ณ„์•ฝ์˜ `identity` ์„ ์–ธ์„ ์†์œผ๋กœ ์˜ฎ๊ธด ๊ฒƒ์ด๋‹ค.** ๊ณ„์•ฝ์ด kind ๋งˆ๋‹ค ๋ฌด์—‡์ด ๊ทธ ์‚ฌ์‹ค์„\n * ๊ฐ€๋ฆฌํ‚ค๋Š”์ง€ ์ด๋ฏธ ์„ ์–ธํ•˜๋Š”๋ฐ(`operational-ingest.ts` ์˜ `SPECS[kind].identity`), ๊ทธ๊ฒƒ์„ ๋‚ด๋ณด๋‚ด์ง€\n * ์•Š์•„์„œ ์—ฌ๊ธฐ๊ฐ€ ๋”ฐ๋กœ ๋“ค๊ณ  ์žˆ๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ ์ƒˆ kind ๊ฐ€ ์ƒ๊ธฐ๋ฉด ์—ฌ๊ธฐ๊ฐ€ ์กฐ์šฉํžˆ ๋’ค์ฒ˜์ง„๋‹ค. ์‹ค์ œ๋กœ ๋‘ ๋ฒˆ ๊ทธ๋žฌ๋‹ค โ€” `subjectId`(์ฒ˜๋ถ„)์™€\n * `testableObjectId`(์‹œํ—˜)๊ฐ€ ๋น ์ ธ ์žˆ์—ˆ๊ณ , ๊ทธ๋™์•ˆ ๊ทธ ๋‘ ์ข…๋ฅ˜๋Š” ์ •์ฒด๋ฅผ ๋ชป ๋งŒ๋“ค๊ฑฐ๋‚˜ ์„œ๋กœ ๋‹ค๋ฅธ ์‚ฌ์‹ค์ด\n * ๋ญ‰์น  ์ˆ˜ ์žˆ์—ˆ๋‹ค.\n *\n * ๊ณ„์•ฝ์ด `operationalIdentityField(kind)` ๋ฅผ ๋‚ด๋ณด๋‚ด๋ฉด ์ด ๋ชฉ๋ก์„ ์ง€์šด๋‹ค. ๊ทธ ๋ฌธ์„ ์—ด์–ด ๋‘์—ˆ๊ณ \n * ๋ฐฐํฌ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.\n */\n put('meter', d.meterId)\n put('equipment', d.equipmentId)\n put('mover', d.moverId) // vocabulary-guard: allow โ€” ๋ด‰ํˆฌ์˜ ์˜› ์„ธ๋Œ€ ํ•„๋“œ ์ด๋ฆ„(์ €์žฅ๋œ ๊ณ„์•ฝ)\n put('task', d.taskId)\n put('order', d.orderId)\n put('person', d.personId)\n put('asset', d.assetId)\n put('location', d.locationId) // vocabulary-guard: allow โ€” ๊ฐ™์Œ\n put('epc', d.epcList?.[0])\n put('parent', d.parentID)\n put('class', d.quantityList?.[0]?.epcClass)\n put('transformation', d.transformationID)\n /*\n * โ”€โ”€ ์ฃผ์ฒด๊ฐ€ `subjectId` ์ธ ์‚ฌ์‹ค์ด ์žˆ๋‹ค (2026-09-06 ์ธก์ •) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ๋ถ€์ ํ•ฉ ์ฒ˜๋ถ„๊ณผ ์‹œํ—˜ ๊ฒฐ๊ณผ๋Š” **ํ‘œ์ค€ `TestableObjectID` ์™€ ๊ฐ™์€ ์ž๋ฆฌ**๋ฅผ ์“ด๋‹ค(๋กœํŠธ ยท ์„ค๋น„ ยท ์ž๋ฆฌ์—\n * ๋‘๋ฃจ ์“ฐ๋Š” ํ•˜๋‚˜์˜ ์ด๋ฆ„). ๊ทธ ์ด๋ฆ„์ด ์—ฌ๊ธฐ ์—†์–ด์„œ ๋‘ ์ข…๋ฅ˜๊ฐ€ **์ •์ฒด๋ฅผ ๋ชป ๋งŒ๋“ค์—ˆ๋‹ค** โ€”\n * `parts` ๊ฐ€ ๋น„๋ฉด `factIdentity` ๊ฐ€ `undefined` ๋ฅผ ๋‚ด๊ณ , ๊ทธ๋Ÿฌ๋ฉด dedupe ๋ฐ–์ด๋‹ค.\n *\n * ์‹ค์ œ๋กœ ๊ทธ๋žฌ๋‹ค. `fillTwinScope` ๋ฅผ ๋‘ ๋ฒˆ ๋Œ๋ฆด ๋•Œ๋งˆ๋‹ค ๊ทธ ๋‘˜์ด 7๊ฑด์”ฉ ๋‹ค์‹œ ์•‰์•˜๋‹ค(์ฒ˜๋ถ„ 4 ยท ์‹œํ—˜ 3).\n * ๋‚˜๋จธ์ง€ 34๊ฑด์€ ๊ฑธ๋Ÿฌ์กŒ๋Š”๋ฐ ์ด ๋‘˜๋งŒ ๊ณ„์† ๋Š˜์—ˆ๋‹ค.\n */\n put('subject', d.subjectId)\n put('spec', d.specId)\n /*\n * ์‹œํ—˜ ๊ฒฐ๊ณผ์˜ ์ฃผ์ฒด๋Š” `testableObjectId` ๋‹ค โ€” ํ‘œ์ค€ `TestableObjectID` ์˜ ์ด๋ฆ„์„ ๊ทธ๋Œ€๋กœ ์“ด๋‹ค.\n *\n * ์ด ์ด๋ฆ„์ด ์—†์–ด์„œ **๊ฐ™์€ ๋ช…์„ธ๋กœ ๊ฐ™์€ ์‹œ๊ฐ์— ์žฐ ์„œ๋กœ ๋‹ค๋ฅธ ๋กœํŠธ๊ฐ€ ํ•œ ์‚ฌ์‹ค๋กœ ๋ญ‰์ณค๋‹ค.** ์ค‘๋ณต์ด ์ƒ๊ธฐ๋Š”\n * ๊ฒƒ๋ณด๋‹ค ๋‚˜์˜๋‹ค โ€” ๋‘ ๋กœํŠธ์˜ ์‹œํ—˜ ๊ฒฐ๊ณผ ์ค‘ ํ•˜๋‚˜๊ฐ€ ์‚ฌ๋ผ์ง„๋‹ค.\n *\n * ์‹ค์ œ๋กœ `mes-miratek` ์— ๊ฐ™์€ ์‹œํ—˜ ๊ฒฐ๊ณผ๊ฐ€ 10๊ฑด ์žˆ์—ˆ๋‹ค(2026-09-06 ํ™•์ธ). ๊ทธ๊ฒƒ์€ ๋ญ‰์นœ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ\n * ๋ฐ˜๋Œ€๋กœ dedupe ๋ฅผ ๋ชป ์ง€๋‚œ ๊ฒƒ์ธ๋ฐ, ๊ฐ™์€ ์ž๋ฆฌ์—์„œ ๋ญ‰์น˜๋Š” ์ชฝ๋„ ์—ด๋ ค ์žˆ์—ˆ๋‹ค.\n */\n put('object', d.testableObjectId)\n /* ์™„๋ฃŒ ์„ ์–ธ์˜ ์ฃผ์ฒด โ€” ใ€Œ์ด ์ถ•์€ ์—ฌ๊ธฐ๊นŒ์ง€๊ฐ€ ์ „๋ถ€๋‹คใ€๋ฅผ ๋งํ•˜๋Š” ์ถ• ์ด๋ฆ„. */\n put('axis', d.completeAxis)\n\n /*\n * EPCIS ๋Š” ใ€Œ๋ฌด์—‡์„ ๋งํ•˜๋Š” ๊ด€์ธก์ธ๊ฐ€ใ€๊ฐ€ ์ด ์…‹์œผ๋กœ ๊ฐˆ๋ฆฐ๋‹ค. ํ•œ ๊ฐœ์ฒด๊ฐ€ ํ•œ ์ˆœ๊ฐ„์— ๋‘ ๊ด€์ธก์„ ๊ฐ–๋Š”\n * ๊ฒƒ์€ ํ‘œ์ค€์—์„œ ์ •์ƒ์ด๊ณ , ์ด๊ฒƒ์„ ์•ˆ ๋ณด๋ฉด ๋’ค์—ฃ๊ฒƒ์ด ์‚ฌ๋ผ์ง„๋‹ค.\n */\n put('bizStep', d.bizStep)\n put('action', d.action)\n put('disposition', d.disposition)\n\n /*\n * โ”€โ”€ ๋ณ€ํ™˜์€ **๋ฌด์—‡์ด ๋ฌด์—‡์œผ๋กœ ๋˜์—ˆ๋‚˜**๋กœ ๊ฐˆ๋ฆฐ๋‹ค (2026-09-07 ์ธก์ •) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ด ์ž๋ฆฌ๊ฐ€ ์—†์–ด์„œ **์‚ฌ์‹ค ํ•˜๋‚˜๊ฐ€ ์—†์–ด์กŒ์Šต๋‹ˆ๋‹ค.** ๊ฑฐ์ ˆ์ด ์•„๋‹ˆ๋ผ ๋˜ํ’€์ด๋กœ ์„ธ์–ด์ ธ์„œ ๊ฒฝ๊ณ ๋„ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.\n *\n * ```\n * plant outbox seq 37 in LOT-CT-SIDE-001 24๊ฐœ โ†’ out LOT-CT-MAIN-003 12๊ฐœ\n * plant outbox seq 42 in LOT-CT-SIDE-001 18๊ฐœ โ†’ out LOT-CT-MAIN-004 9๊ฐœ\n * transformationID ยท bizStep ยท ์ดˆ๊นŒ์ง€ ์ „๋ถ€ ๊ฐ™๋‹ค\n * ์ €๋„์— ๋‚จ์€ ๊ฒƒ LOT-CT-MAIN-003 ํ•˜๋‚˜\n * ```\n *\n * `LOT-CT-MAIN-004` ๋ฅผ ์–ด๋А ํŒจ๋„๋กœ ๋งŒ๋“ค์—ˆ๋Š”์ง€ ํŠธ์œˆ์ด ๋‹ตํ•˜์ง€ ๋ชปํ•˜๋Š” ์ƒํƒœ์˜€์Šต๋‹ˆ๋‹ค.\n *\n * ๊ทธ๋ฆฌ๊ณ  **๊ตฌ๋ณ„ํ•  ๊ฐ’์ด ๋ด‰ํˆฌ ์•ˆ์— ์ด๋ฏธ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค** โ€” `outputQuantityList[0].epcClass` ๊ฐ€ ์„œ๋กœ\n * ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ์ด ํŒŒ์ผ ๋จธ๋ฆฌ๋ง์ด ์ ์–ด ๋‘” ๊ทธ ๋ชจ์–‘ ๊ทธ๋Œ€๋กœ์ž…๋‹ˆ๋‹ค: ํŒ์ •์ด ๊ทธ๊ฒƒ์„ ์•ˆ ๋ดค์Šต๋‹ˆ๋‹ค.\n *\n * ์‚ฐ์ถœ๋งŒ ๋ณด์ง€ ์•Š๊ณ  **์ž…๋ ฅ๋„ ๋ด…๋‹ˆ๋‹ค.** ๊ฐ™์€ ๋กœํŠธ๋ฅผ ๊ฐ™์€ ์ดˆ์— ๋‘ ๋ฒˆ ์†Œ๋น„ํ•˜๋ฉด์„œ ์‚ฐ์ถœ ์ด๋ฆ„์ด ๊ฐ™์€\n * ๊ฒฝ์šฐ(์ˆ˜๋Ÿ‰๋งŒ ๋‹ค๋ฅธ ๋ถ„ํ• )๊ฐ€ ๋‚จ๊ณ , ๊ทธ๋•Œ ์ž…๋ ฅ ์ˆ˜๋Ÿ‰์ด ์œ ์ผํ•œ ์ฐจ์ด์ž…๋‹ˆ๋‹ค. ์ˆ˜๋Ÿ‰๊นŒ์ง€ ๋„ฃ๋Š” ์ด์œ ๊ฐ€ ๊ทธ๊ฒƒ์ž…๋‹ˆ๋‹ค.\n */\n put('inClass', classOf(d.inputQuantityList))\n put('inEpc', d.inputEPCList?.[0])\n put('inQty', qtyOf(d.inputQuantityList))\n put('outClass', classOf(d.outputQuantityList))\n put('outEpc', d.outputEPCList?.[0])\n put('outQty', qtyOf(d.outputQuantityList))\n /*\n * ๋‹ด๊น€์˜ ์ž์‹๋„ ๊ฐ™์€ ์ด์œ ๋กœ ๋ณธ๋‹ค โ€” ํ•œ ํŒ”๋ ˆํŠธ์— ์„œ๋กœ ๋‹ค๋ฅธ ๋ฌถ์Œ์„ ๊ฐ™์€ ์ดˆ์— ๋‘ ๋ฒˆ ์‹ค์œผ๋ฉด ๋’ค์—ฃ๊ฒƒ์ด\n * ์‚ฌ๋ผ์ง„๋‹ค. ์œ„ ๋ณ€ํ™˜์—์„œ ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ์žƒ์—ˆ์œผ๋‹ˆ ์—ฌ๊ธฐ๋„ ํ•จ๊ป˜ ๋ง‰๋Š”๋‹ค(ํ•œ ์ข…๋ฅ˜๋งŒ ๊ณ ์น˜๋ฉด ๋‚˜๋จธ์ง€์— ๋‚จ๋Š”๋‹ค).\n */\n put('childEpc', d.childEPCs?.[0])\n put('childClass', classOf(d.childQuantityList))\n put('childQty', qtyOf(d.childQuantityList))\n /*\n * ์–ด๋А ์˜ค๋”์˜ ์‚ฌ์‹ค์ธ๊ฐ€๋„ ์ •์ฒด์˜ ์ผ๋ถ€๋‹ค. ๊ฐ™์€ ๊ณต์ •์„ ๊ฐ™์€ ์ดˆ์— ๋‘ ์˜ค๋”๋กœ ๋Œ๋ฆฌ๋Š” ๊ฒƒ์€ ์ •์ƒ์ด๊ณ ,\n * ์ด๊ฒƒ์„ ์•ˆ ๋ณด๋ฉด ๋’ค์—ฃ๊ฒƒ์ด ์‚ฌ๋ผ์ง„๋‹ค.\n */\n put('tx', d.bizTransactionList?.[0]?.bizTransaction)\n\n return out\n}\n\n/** ์ˆ˜๋Ÿ‰ ๋ชฉ๋ก์˜ ์ฒซ ์ข…๋ฅ˜ โ€” ๋ชฉ๋ก์ด ๋น„๋ฉด `undefined`(๋นˆ ๋ฌธ์ž์—ด์„ ๋„ฃ์ง€ ์•Š๋Š”๋‹ค). */\nfunction classOf(list: unknown): string | undefined {\n const first = Array.isArray(list) ? (list[0] as any) : undefined\n const v = first?.epcClass\n return typeof v === 'string' && v.trim() ? v : undefined\n}\n\n/**\n * ์ˆ˜๋Ÿ‰ ๋ชฉ๋ก์„ ์ˆ˜๊นŒ์ง€ ์ ๋Š”๋‹ค โ€” ์ข…๋ฅ˜๊ฐ€ ๊ฐ™๊ณ  ์ˆ˜๋Ÿ‰๋งŒ ๋‹ค๋ฅธ ์‚ฌ์‹ค์„ ๊ฐ€๋ฅธ๋‹ค.\n *\n * ๋ชฉ๋ก ์ „์ฒด๋ฅผ ์ ๋Š”๋‹ค. ์ฒซ ์›์†Œ๋งŒ ๋ณด๋ฉด ใ€Œ๊ฐ™์€ ๊ฒƒ ๋‘˜ + ๋‹ค๋ฅธ ๊ฒƒ ํ•˜๋‚˜ใ€๊ฐ€ ์ฒซ ์›์†Œ๋กœ๋Š” ๊ตฌ๋ณ„๋˜์ง€ ์•Š๋Š”๋‹ค.\n */\nfunction qtyOf(list: unknown): string | undefined {\n if (!Array.isArray(list) || !list.length) return undefined\n const parts = list.map((x: any) => `${x?.epcClass ?? ''}:${x?.quantity ?? ''}${x?.uom ? '/' + x.uom : ''}`)\n return parts.join('|')\n}\n\n/**\n * ์ด ๋ด‰ํˆฌ๊ฐ€ ๋งํ•˜๋Š” ์‚ฌ์‹ค์˜ ์ •์ฒด โ€” ๊ฐ™์œผ๋ฉด ๊ฐ™์€ ์‚ฌ์‹ค์ด๋‹ค.\n *\n * ๋Œ€์ƒ์ด๋‚˜ ์‹œ๊ฐ์„ ์•Œ ์ˆ˜ ์—†์œผ๋ฉด **์ •์ฒด๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค**(`undefined`). ๊ทธ๋•Œ๋Š” ๊ฑฐ๋ฅด์ง€ ์•Š๊ณ  ํ†ต๊ณผ์‹œํ‚จ๋‹ค โ€”\n * ๋ชจ๋ฅด๋Š” ๊ฒƒ์„ ๊ฐ™๋‹ค๊ณ  ํŒ๋‹จํ•˜๋ฉด ์„œ๋กœ ๋‹ค๋ฅธ ์‚ฌ์‹ค์ด ํ•˜๋‚˜๋กœ ํ•ฉ์ณ์ง„๋‹ค. ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ์žƒ๋Š” ๊ฒƒ๋ณด๋‹ค ๋‘ ๋ฒˆ ์„ธ๋Š” ๊ฒƒ์ด ๋‚ซ๋‹ค.\n */\n/**\n * ์ •์ฒด๋ฅผ ๋ชป ๋งŒ๋“  ์‚ฌ์‹ค์„ **์ข…๋ฅ˜๋ณ„๋กœ** ์„ผ๋‹ค โ€” dedupe ๋ฐ–์œผ๋กœ ๋‚˜๊ฐ„ ๊ฒƒ๋“ค.\n *\n * ์ด ์ˆ˜๊ฐ€ 0์ด ์•„๋‹ˆ๋ฉด ๊ทธ ์ข…๋ฅ˜๋Š” ๋‹ค์‹œ ๋ฐ›์„ ๋•Œ๋งˆ๋‹ค ์ €๋„์— ๋‹ค์‹œ ์•‰๋Š”๋‹ค. ๊ทธ ์ข…๋ฅ˜์˜ ์ฃผ์ฒด ์ด๋ฆ„์„\n * `discriminatorsOf` ์— ๋”ํ•ด์•ผ ํ•œ๋‹ค.\n */\nconst unidentified: Record<string, number> = {}\n\n/** ์ง€๊ธˆ๊นŒ์ง€ ์ •์ฒด๋ฅผ ๋ชป ๋งŒ๋“  ๊ฒƒ โ€” ์ข…๋ฅ˜๋ณ„. ์ฝ๊ณ  ๋น„์šด๋‹ค. */\nexport function takeUnidentified(): Record<string, number> {\n const out = { ...unidentified }\n for (const k of Object.keys(unidentified)) delete unidentified[k]\n return out\n}\n\nexport function factIdentity(envelope: any): string | undefined {\n const type = String(envelope?.eventType ?? '').trim()\n if (!type) return undefined\n const parts = discriminatorsOf(envelope)\n /*\n * **์ •์ฒด๋ฅผ ๋ชป ๋งŒ๋“ค๋ฉด dedupe ๋ฐ–์ด๋‹ค** โ€” ๊ทธ ์‚ฌ์‹ค์€ ๋‹ค์‹œ ๋ฐ›์„ ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ ์•‰๋Š”๋‹ค.\n *\n * ์˜ค๋Š˜ ๊ทธ๊ฒƒ์œผ๋กœ ์ €๋„์ด ๋ถ€ํ’€์—ˆ๋‹ค(์ฒ˜๋ถ„ยท์‹œํ—˜์ด `subjectId` ๋ฅผ ์ฃผ์ฒด๋กœ ์“ฐ๋Š”๋ฐ ๊ทธ ์ด๋ฆ„์ด ์œ„ ๋ชฉ๋ก์—\n * ์—†์—ˆ๋‹ค). ์กฐ์šฉํžˆ `undefined` ๋ฅผ ๋‚ด๋ฉด ๋‹ค์Œ ์ข…๋ฅ˜์—์„œ ๋˜ ๋‚˜๊ณ  ๊ทธ๋•Œ๋„ ์•„๋ฌด ํ”์ ์ด ์—†๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ ๋ฌด์—‡์ด ์ •์ฒด๋ฅผ ๋ชป ๋งŒ๋“ค์—ˆ๋Š”์ง€ ์„ผ๋‹ค(`unidentified`). ์„ธ๋Š” ๊ฒƒ์ด์ง€ ๋ง‰๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค โ€”\n * ์ •์ฒด๋ฅผ ๋ชป ๋งŒ๋“ ๋‹ค๊ณ  ์‚ฌ์‹ค์„ ๋ฒ„๋ฆฌ๋ฉด ๊ทธ๊ฒƒ์ด ๋” ๋‚˜์˜๋‹ค.\n */\n if (!parts.length) {\n unidentified[type] = (unidentified[type] ?? 0) + 1\n return undefined\n }\n const at = timeOf(envelope)\n if (at === undefined) return undefined\n return `${type}|${parts.join('&')}|${at}`\n}\n\n/**\n * ์ตœ๊ทผ์— ๋ณธ ์ •์ฒด๋ฅผ ๊ธฐ์–ตํ•œ๋‹ค โ€” **ํฌ๊ธฐ์— ์ƒํ•œ์„ ๋‘”๋‹ค.**\n *\n * ์ „๋ถ€ ๊ธฐ์–ตํ•  ์ˆ˜๋Š” ์—†๋‹ค(ํŠธ์œˆ ํ•˜๋‚˜๊ฐ€ ์ˆ˜์ฒœ๋งŒ ์‚ฌ๊ฑด์„ ๊ฐ–๋Š”๋‹ค). ์ฐฝ์„ ๋„˜์œผ๋ฉด ์˜ค๋ž˜๋œ ๊ฒƒ๋ถ€ํ„ฐ ์žŠ๋Š”๋‹ค. ์ฐฝ ๋ฐ–์˜\n * ์žฌ์ „์†ก์€ ๋‹ค์‹œ ํ†ต๊ณผํ•˜๋Š”๋ฐ, ๊ทธ๊ฒƒ์€ ์ ˆ๋Œ€๊ฐ’ ์‚ฌ์‹ค์ด๋ผ ์ƒํƒœ์— ํ•ด๊ฐ€ ์—†๊ณ  ์ง€๋‚œ ๊ธฐ๋ก์— ํ•œ ์ค„ ๋” ๋‚จ๋Š”๋‹ค.\n * ์ฐฝ์„ ํฌ๊ฒŒ ์žก์œผ๋ฉด ๊ทธ๋งŒํผ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์“ด๋‹ค โ€” ๊ทธ ๊ฐ’์„ ์—ฌ๊ธฐ์„œ ์ด๋ฆ„์œผ๋กœ ๋ชป ๋ฐ•๋Š”๋‹ค.\n *\n * **์žฌ๊ธฐ๋™์„ ๊ฑด๋„ˆ์ง€ ๋ชปํ•œ๋‹ค.** ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ƒˆ๋กœ ๋œจ๋ฉด ๊ธฐ์–ต์ด ๋น„์–ด ์žˆ์œผ๋ฏ€๋กœ, ์žฌ๊ธฐ๋™ ์งํ›„ ์ฒซ ์ฃผ๊ธฐ๊ฐ€ ๊ฐ™์€\n * ๊ฐ’์„ ๋‹ค์‹œ ๋ณด๋‚ด๋ฉด ๊ฑธ๋Ÿฌ์ง€์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๊ฒƒ์„ ๋ง‰์œผ๋ ค๋ฉด ์ด ๊ธฐ์–ต์ด ์ €์žฅ๋ผ์•ผ ํ•˜๊ณ , ๊ทธ๊ฒƒ์€ ๋‹ค์Œ ๊ฑธ์Œ์ด๋‹ค.\n * ์ง€๊ธˆ์€ ๊ทธ ์‚ฌ์‹ค์„ ์—ฌ๊ธฐ ์ ์–ด ๋‘”๋‹ค โ€” ์ ์–ด ๋‘์ง€ ์•Š์œผ๋ฉด ใ€Œ์ค‘๋ณต์€ ์ด์ œ ์—†๋‹คใ€๋กœ ์ฝํžŒ๋‹ค.\n */\nexport class FactDeduper {\n /** ๊ธฐ์–ตํ•˜๋Š” ์ •์ฒด์˜ ์ˆ˜ โ€” ์ฐฝ. */\n static WINDOW = 20_000\n\n private seen = new Set<string>()\n private order: string[] = []\n\n /**\n * ์ด๋ฏธ ์•„๋Š” ๊ฒƒ์œผ๋กœ **๋ฏธ๋ฆฌ ๊ธฐ์–ตํ•œ๋‹ค** โ€” ์ €๋„์—์„œ ์ฝ์–ด ์ฑ„์šธ ๋•Œ.\n *\n * โ”€โ”€ ์™œ ํ•„์š”ํ•œ๊ฐ€ (2026-09-06 ์ธก์ •) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ด ๊ธฐ์–ต์€ ํ”„๋กœ์„ธ์Šค ์•ˆ์—๋งŒ ์žˆ๋‹ค. ์žฌ๊ธฐ๋™ํ•˜๋ฉด ๋น„์›Œ์ง€๊ณ , ๊ทธ ๋’ค backfill ์„ ๋Œ๋ฆฌ๋ฉด **์ด๋ฏธ ์ €๋„์—\n * ์žˆ๋Š” ์‚ฌ์‹ค๋„ ใ€Œ์ฒ˜์Œ ๋ณธ ๊ฒƒใ€**์ด ๋œ๋‹ค.\n *\n * ์‹ค์ œ๋กœ ๊ทธ๋žฌ๋‹ค. `mes-line-a` ๋ฅผ ์žฌ๊ธฐ๋™ ๋’ค backfill ํ•˜๋‹ˆ 39๊ฑด์ด ์ „๋ถ€ ๋‹ค์‹œ ์•‰์•„ ์ €๋„์ด\n * 44 โ†’ 83๊ฑด์ด ๋˜๊ณ  44๊ฐ€์ง€๊ฐ€ ์ค‘๋ณต์ด ๋๋‹ค.\n *\n * push ๊ฒฝ๋กœ์—์„œ๋Š” ์•ˆ ๋ณด์ธ๋‹ค. ์žฌ์ „์†ก์ด ๋ช‡ ๋ถ„ ์•ˆ์— ์˜ค๋ฏ€๋กœ ์ฐฝ ์•ˆ์—์„œ ๊ฑธ๋ฆฐ๋‹ค. **backfill ์ด ๊ทธ ์ „์ œ๋ฅผ\n * ๊นฌ๋‹ค** โ€” ๋ช‡ ๋‹ฌ ์ „ ์‚ฌ์‹ค์„ ์ง€๊ธˆ ๋ฐ›์œผ๋‹ˆ ์žฌ๊ธฐ๋™ ํ•œ ๋ฒˆ์ด๋ฉด ๊ทธ ๊ตฌ๊ฐ„์ด ํ†ต์งธ๋กœ ๋‹ค์‹œ ์•‰๋Š”๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ backfill ์ด ๋ถ€๋ฅด๊ธฐ ์ „์— ๊ทธ ๊ตฌ๊ฐ„์˜ ์ •์ฒด๋ฅผ ์ €๋„์—์„œ ์ฝ์–ด ์—ฌ๊ธฐ ๋„ฃ๋Š”๋‹ค.\n */\n remember(identities: readonly string[]): number {\n let added = 0\n for (const id of identities) if (id && !this.seen.has(id)) { this.known(id); added++ }\n return added\n }\n\n /** ์ด ์‚ฌ์‹ค์„ ๋ณธ ์ ์ด ์žˆ๋‚˜ โ€” ์—†์œผ๋ฉด ๊ธฐ์–ตํ•˜๊ณ  `false`. */\n private known(identity: string): boolean {\n if (this.seen.has(identity)) return true\n this.seen.add(identity)\n this.order.push(identity)\n if (this.order.length > FactDeduper.WINDOW) {\n const gone = this.order.splice(0, this.order.length - FactDeduper.WINDOW)\n for (const g of gone) this.seen.delete(g)\n }\n return false\n }\n\n /**\n * ์ฒ˜์Œ ๋ณด๋Š” ๊ฒƒ๋งŒ ๋Œ๋ ค์ค€๋‹ค โ€” ๊ทธ๋ฆฌ๊ณ  ๋ช‡ ๊ฐœ๋ฅผ ๋ฒ„๋ ธ๋Š”์ง€ ํ•จ๊ป˜ ๋‚ธ๋‹ค.\n *\n * ๋ฒ„๋ฆฐ ์ˆ˜๋ฅผ ํ•จ๊ป˜ ๋‚ด๋Š” ์ด์œ : ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ๋ฒ„๋ฆฌ๋ฉด ใ€Œ๋ณด๋‚ธ ์ˆ˜ใ€์™€ ใ€Œ๋ฐ˜์˜๋œ ์ˆ˜ใ€๊ฐ€ ์–ด๊ธ‹๋‚˜๋Š”๋ฐ ์•„๋ฌด๋„ ๊ทธ\n * ์ด์œ ๋ฅผ ๋ชจ๋ฅธ๋‹ค. ๊ทธ ์ˆ˜๊ฐ€ ํฌ๋ฉด ๋ณด๋‚ด๋Š” ์ชฝ์ด ๋˜ํ’€์ด ๋ณด๋‚ด๊ณ  ์žˆ๋‹ค๋Š” ๋œป์ด๊ณ , ๊ทธ๊ฒƒ์€ ๊ณ ์น  ์ผ์ด๋‹ค.\n */\n filter<T>(envelopes: readonly T[]): { fresh: T[]; duplicates: number } {\n const fresh: T[] = []\n let duplicates = 0\n for (const e of envelopes) {\n const id = factIdentity(e)\n if (id === undefined) {\n fresh.push(e)\n continue\n }\n if (this.known(id)) duplicates++\n else fresh.push(e)\n }\n return { fresh, duplicates }\n }\n\n /** ๊ธฐ์–ตํ•˜๊ณ  ์žˆ๋Š” ์ •์ฒด์˜ ์ˆ˜ โ€” ๊ณ„๊ธฐ๊ฐ€ ์ฝ๋Š”๋‹ค. */\n size(): number {\n return this.seen.size\n }\n}\n"]}
@@ -34,6 +34,8 @@ export interface IngestWindow {
34
34
  * ์„ธ๋ฉด ๊ทธ ๊ฐœ์„ ๋„, ๋˜๋Œ์•„๊ฐ€๋Š” ๊ฒƒ๋„ ๋ณด์ด์ง€ ์•Š๋Š”๋‹ค.
35
35
  */
36
36
  flushes: number;
37
+ /** ์ด ์ฐฝ์—์„œ ์ €๋„์— ์•ˆ ๊ฐ„ ์–ดํœ˜ ์š”์†Œ์˜ ์ˆ˜ โ€” ์‚ฌ๋ผ์ง„ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ €๋„๋กœ ๊ฐ€์ง€ ์•Š๋Š” ๊ฒƒ์ด๋‹ค. */
38
+ vocabulary: number;
37
39
  }
38
40
  /** ๊ฑฐ๋ถ€ ํ‘œ๋ณธ ํ•˜๋‚˜ โ€” ๋งคํ•‘์„ ๊ณ ์น˜๋ ค๋ฉด ์‹ค์ œ ๋ชจ์–‘์„ ๋ด์•ผ ํ•œ๋‹ค. */
39
41
  export interface RejectSample {
@@ -54,6 +56,17 @@ export interface IngestLedger {
54
56
  /** ๋ˆ„์  ์ œ์‹œยท๊ฑฐ๋ถ€ยท๋ฏธ์ „๋‹ฌ. */
55
57
  offered: number;
56
58
  rejected: number;
59
+ /**
60
+ * **์ €๋„์— ์•ˆ ๊ฐ€๋Š” ์–ดํœ˜ ์š”์†Œ์˜ ์ˆ˜** โ€” ๋กœํŠธ ๋ฒˆํ˜ธยท์†Œ๋น„๊ธฐํ•œ์ฒ˜๋Ÿผ ์‹œ๊ฐ์ถ•์ด ์—†๋Š” ๊ฐ’.
61
+ *
62
+ * โ”€โ”€ ์™œ ์„ธ๋‚˜ (2026-09-05, ์ธํ‹ฐ๊ทธ๋ ˆ์ด์…˜ ๋ ˆ์ธ์ด ์…ˆ์œผ๋กœ ์ฐพ์Œ) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
63
+ * ์–ดํœ˜๋Š” ์ผ๋ถ€๋Ÿฌ ์ €๋„๋กœ ์•ˆ ๊ฐ„๋‹ค(ยง`canonical-ingest`) โ€” ๊ทธ๊ฒƒ์ด ์˜ณ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ **๊ทธ ์ˆ˜๋ฅผ ๋นผ ์ฃผ๋Š”
64
+ * ์ž๋ฆฌ๊ฐ€ ์—†์–ด์„œ** ใ€Œ๋ณด๋‚ธ ๊ฒƒ โˆ’ ์•‰์€ ๊ฒƒใ€์ด ์•ˆ ๋งž๊ณ , ๊ทธ ์ฐจ์ด๋ฅผ ใ€Œ์‚ฌ๋ผ์กŒ๋‹คใ€๋กœ ์ฝ๊ฒŒ ๋œ๋‹ค.
65
+ *
66
+ * ์‹ค์ œ๋กœ ๊ทธ๋žฌ๋‹ค: ์ปค์„œ 20 ยท ์ €๋„ 17 ยท ์–ดํœ˜ 1 โ†’ ์‚ฌ๋žŒ์ด ์†์œผ๋กœ ์„ธ์„œ ใ€Œ๋‘˜์ด ๋นˆ๋‹คใ€๋ฅผ ์ฐพ์•˜๋‹ค. ๊ทธ
67
+ * ๋บ„์…ˆ์„ ์ฝ”๋“œ๊ฐ€ ํ•˜๋ ค๋ฉด ์ด ํ•ญ์ด ์žˆ์–ด์•ผ ํ•œ๋‹ค.
68
+ */
69
+ vocabulary: number;
57
70
  undelivered: number;
58
71
  /** ๋ˆ„์  โ€” ์ ํžŒ ํ–‰๊ณผ ๋‘๋“œ๋ฆฐ ํšŸ์ˆ˜. */
59
72
  rows: number;
@@ -265,6 +278,16 @@ export declare function recordCursorStall(ledger: IngestLedger, reason: string,
265
278
  */
266
279
  export declare function recordIngestSource(ledger: IngestLedger, source: string, count: number, nowMs: number): void;
267
280
  /** ๊ฐ™์€ ์‚ฌ์‹ค์ด ๋‘ ๋ฒˆ ์™€์„œ ๋ฒ„๋ฆฐ ์ˆ˜ โ€” ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ๋ฒ„๋ฆฌ์ง€ ์•Š๋Š”๋‹ค. */
281
+ /**
282
+ * **์ €๋„์— ์•ˆ ๊ฐ„ ์–ดํœ˜ ์š”์†Œ๋ฅผ ์„ผ๋‹ค** โ€” ์—†์–ด์ง„ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ €๋„๋กœ ๊ฐ€์ง€ ์•Š๋Š” ๊ฒƒ์ด๋‹ค.
283
+ *
284
+ * ์–ดํœ˜(๋กœํŠธ ๋ฒˆํ˜ธยท์†Œ๋น„๊ธฐํ•œ ๋“ฑ)๋Š” ์‹œ๊ฐ์ถ•์ด ์—†์–ด ์ผ๋ถ€๋Ÿฌ ์ €๋„๋กœ ์•ˆ ๊ฐ„๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ์ˆ˜๋ฅผ ๋นผ ์ฃผ๋Š” ์ž๋ฆฌ๊ฐ€
285
+ * ์—†์œผ๋ฉด ใ€Œ๋ณด๋‚ธ ๊ฒƒ โˆ’ ์•‰์€ ๊ฒƒใ€์ด ์•ˆ ๋งž๊ณ , ๊ทธ ์ฐจ์ด๋ฅผ **์‚ฌ๋ผ์ง„ ๊ฒƒ์œผ๋กœ ์ฝ๊ฒŒ ๋œ๋‹ค.**
286
+ *
287
+ * ์ฐฝ์„ ๊ตด๋ฆฌ์ง€ ์•Š๋Š”๋‹ค โ€” ๋ถ€๋ฅด๋Š” ์ชฝ(`recordIngest`)์ด ์ด๋ฏธ ๊ตด๋ฆฐ ๋’ค์— ๋ถ€๋ฅธ๋‹ค. ์—ฌ๊ธฐ์„œ ๋˜ ๊ตด๋ฆฌ๋ฉด ํ•œ
288
+ * ์œ ์ž…์ด ๋‘ ์ฐฝ์— ๊ฑธ์นœ๋‹ค.
289
+ */
290
+ export declare function recordVocabulary(ledger: IngestLedger, count: number): void;
268
291
  export declare function recordDuplicates(ledger: IngestLedger, count: number, nowMs: number): void;
269
292
  export declare function recordWithheld(ledger: IngestLedger, reason: string, count: number, nowMs: number): void;
270
293
  /** ์ฐฝ์„ ๋„˜๊ฒผ์œผ๋ฉด ์ง€์šด๋‹ค โ€” ํ’€๋ฆฐ ์ •์ฒด๊ฐ€ ํ™”๋ฉด์— ๋‚จ์•„ ์žˆ์œผ๋ฉด ๊ทธ๊ฒƒ๋„ ๊ฑฐ์ง“์ด๋‹ค. */
@@ -371,7 +394,22 @@ export type SyncVerdict = 'syncing' /** ์œ ์ž…์ด ์žˆ๊ณ  ํ†ต๊ณผ์œจ์ด ๋ฌธํ„ฑ ์ด
371
394
  * ๊ทธ๋ž˜์„œ **ํ™”๋ฉด ๋ฌธ๊ตฌ๋Š” ๊ด€์ธก ๊ทธ๋Œ€๋กœ** ์ ๋Š”๋‹ค(ใ€ŒํŠธ์œˆ์— ๋‹ฟ์ง€ ์•Š๊ณ  ๋ฒ„๋ ค์ง€๋Š” ์ค‘ใ€). ์ด ํ‚ค ์ด๋ฆ„์€ ์„œ๋ฒ„ยทํ™”๋ฉดยท
372
395
  * ์‹œํ—˜์— ๊ฑธ์นœ ๊ณ„์•ฝ ๋ฌธ์ž์—ด์ด๋ผ ๊ทธ๋Œ€๋กœ ๋‘์ง€๋งŒ, ์ด๋ฆ„์„ ์›์ธ์œผ๋กœ ์ฝ์ง€ ์•Š๋Š”๋‹ค.
373
396
  */
374
- | 'twin-not-running' | 'no-traffic' /** ํ”ผ๋“œ๋Š” ๋ถ™์—ˆ๋Š”๋ฐ ์ œ์‹œ๊ฐ€ 0 โ€” ์›์ฒœยท๋ง์„ ๋ณธ๋‹ค */ | 'not-connected' /** ํ”ผ๋“œ ์ž์ฒด๊ฐ€ ์—†๋‹ค โ€” ๊ฒฐ์„ ํ•œ๋‹ค */ | 'not-applicable' /** ์›๋ณธ์ด ๋จน์ด์ง€ ์•Š๋Š” ํŠธ์œˆ(์‹œ๋ฎฌ)ยท๋ฉˆ์ถ˜ ํŠธ์œˆ โ€” ๋ฌผ์„ ๋Œ€์ƒ์ด ์•„๋‹ˆ๋‹ค */ | 'unknown'; /** ํ•œ ๋ฒˆ๋„ ๋ฐ›์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ์ฐฝ์ด ์•„์ง ๋‹ซํžˆ์ง€ ์•Š์•˜๋‹ค โ€” ๊ธฐ๋‹ค๋ฆฐ๋‹ค */
397
+ | 'twin-not-running' | 'no-traffic' /** ํ”ผ๋“œ๋Š” ๋ถ™์—ˆ๋Š”๋ฐ ์ œ์‹œ๊ฐ€ 0 โ€” ์›์ฒœยท๋ง์„ ๋ณธ๋‹ค */ | 'not-connected' /** ํ”ผ๋“œ ์ž์ฒด๊ฐ€ ์—†๋‹ค โ€” ๊ฒฐ์„ ํ•œ๋‹ค */ | 'not-applicable' /** ์›๋ณธ์ด ๋จน์ด์ง€ ์•Š๋Š” ํŠธ์œˆ(์‹œ๋ฎฌ)ยท๋ฉˆ์ถ˜ ํŠธ์œˆ โ€” ๋ฌผ์„ ๋Œ€์ƒ์ด ์•„๋‹ˆ๋‹ค */
398
+ /**
399
+ * **์ง€๊ธˆ์€ ์กฐ์šฉํ•œ ๊ฒƒ์ด ์ •์ƒ์ด๋‹ค** โ€” ์›์ฒœ์ด ์ง€๊ธˆ ์‹œ๊ฐ์— ๋‚ด๋†“์ง€ ์•Š๋Š”๋‹ค.
400
+ *
401
+ * โ”€โ”€ ์™œ ์ดˆ๋ก๋„ ๋นจ๊ฐ•๋„ ์•„๋‹Œ๊ฐ€ (2026-09-04) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
402
+ * ํƒœ์–‘๊ด‘์€ ๋ฐค์— ๋ฐœ์ „ํ•˜์ง€ ์•Š๊ณ , ์—…๋ฌด์‹œ๊ฐ„๋งŒ ๋„๋Š” ์›์ฒœ์€ ์ €๋…์— ์•„๋ฌด๊ฒƒ๋„ ๋‚ด์ง€ ์•Š๋Š”๋‹ค. ๊ทธ ์นจ๋ฌต์„
403
+ * `no-traffic` ์œผ๋กœ ๋ถ€๋ฅด๋ฉด **์ •์ƒ์ธ ๋ฐค๋งˆ๋‹ค ์ ˆ๋ฐ˜์ด ๋นจ๊ฐ›๊ฒŒ ๋‚œ๋‹ค.** ๊ฑฐ์ง“ ๋นจ๊ฐ•์ด ์Œ“์ด๋ฉด ์ง„์งœ ๋นจ๊ฐ•๋„
404
+ * ๊ฐ™์ด ์•ˆ ์ฝํžŒ๋‹ค โ€” ์˜ค๋Š˜ UX ๋ ˆ์ธ์ด ใ€Œ๋Š˜ ์ฐธ์ธ ๊ฒฝ๊ณ ๋Š” ๋ฒฝ์ง€๊ฐ€ ๋œ๋‹คใ€๊ณ  ํ•œ ๊ฒƒ๊ณผ ๊ฐ™์€ ๋ถ€๋ฅ˜๋‹ค.
405
+ *
406
+ * ๊ทธ๋ ‡๋‹ค๊ณ  `syncing` ๋„ ์•„๋‹ˆ๋‹ค. ์ง€๊ธˆ ๋ฐ›๊ณ  ์žˆ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๊ณ , ์ดˆ๋ก์œผ๋กœ ์น ํ•˜๋ฉด **๋ฐค์— ์ •๋ง ๋Š๊ธด
407
+ * ์›์ฒœ**์„ ์•„์นจ๊นŒ์ง€ ์•„๋ฌด๋„ ๋ชจ๋ฅธ๋‹ค.
408
+ *
409
+ * ๊ทธ๋ž˜์„œ ์…‹์งธ ๊ฐ’์ด๋‹ค: ใ€Œ์ง€๊ธˆ์€ ์•ˆ ์˜ค๋Š” ๊ฒƒ์ด ๋งž๋‹คใ€. ํ™”๋ฉด์€ ์ด๊ฒƒ์„ ํšŒ์ƒ‰์œผ๋กœ ๊ทธ๋ฆฌ๊ณ , ๋‹ค์Œ์— ์˜ฌ
410
+ * ์‹œ๊ฐ์„ ํ•จ๊ป˜ ๋งํ•  ์ˆ˜ ์žˆ๋‹ค.
411
+ */
412
+ | 'expected-quiet' | 'unknown'; /** ํ•œ ๋ฒˆ๋„ ๋ฐ›์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ์ฐฝ์ด ์•„์ง ๋‹ซํžˆ์ง€ ์•Š์•˜๋‹ค โ€” ๊ธฐ๋‹ค๋ฆฐ๋‹ค */
375
413
  export declare function syncVerdictOf(args: {
376
414
  /** `live-feed-registry.liveFeedStateOf` ์˜ ๋‹ต์„ ๊ทธ๋Œ€๋กœ ๋ฐ›๋Š”๋‹ค โ€” ํŒ์ • ์–ดํœ˜๋ฅผ ๋‘ ๋ฒŒ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค. */
377
415
  feedState: 'attached' | 'detached' | 'not-applicable';
@@ -386,6 +424,27 @@ export declare function syncVerdictOf(args: {
386
424
  nowMs?: number;
387
425
  /** ๋งˆ์ง€๋ง‰์œผ๋กœ **๋ฒ„๋ ค์ง„** ์‹œ๊ฐ. ํ•œ ๋ฒˆ๋„ ์—†์œผ๋ฉด `-1`. */
388
426
  lastUndeliveredAtMs?: number;
427
+ /**
428
+ * **์ด ์›์ฒœ์€ ์ด๋งŒํผ ์กฐ์šฉํ•ด๋„ ์ •์ƒ์ด๋‹ค** โ€” ๊ธท๋Š” ์ฃผ๊ธฐ๋ฅผ ์›์ฒœ ์ชฝ์ด ์„ ์–ธํ•œ ๊ฐ’.
429
+ *
430
+ * ์—†์œผ๋ฉด ์ฐฝ ํ•˜๋‚˜(`STALE_AFTER_MS`)๋กœ ๊ฒฌ์ค€๋‹ค(์ง€๊ธˆ๊นŒ์ง€์˜ ๊ฑฐ๋™). 15๋ถ„๋งˆ๋‹ค ๊ธท๋Š” ์›์ฒœ์€ ๊ทธ ๊ฐ’์„
431
+ * ์„ ์–ธํ•ด์•ผ ํ•˜๊ณ , ์•ˆ ํ•˜๋ฉด ๊ธท๋Š” ์‚ฌ์ด๋งˆ๋‹ค ใ€Œ์œ ์ž… ์—†์Œใ€์œผ๋กœ ๋ณด์ธ๋‹ค โ€” ์ด ํŒŒ์ผ์ด ์•„๋ž˜์—์„œ ๊ทธ ํ•œ๊ณ„๋ฅผ
432
+ * ์Šค์Šค๋กœ ์ ์–ด ๋‘๊ณ  ์žˆ์—ˆ๋‹ค.
433
+ *
434
+ * ์žฅ๋ถ€๋Š” ์›์ฒœ์˜ ์ฃผ๊ธฐ๋ฅผ ์•Œ ์ˆ˜ ์—†๋‹ค. **์„ ์–ธ๋งŒ์ด ๊ทธ๊ฒƒ์„ ์•„๋Š” ์œ ์ผํ•œ ๊ธธ์ด๋‹ค.**
435
+ */
436
+ expectedSilenceMs?: number;
437
+ /**
438
+ * **์ง€๊ธˆ์ด ๊ทธ ์›์ฒœ์˜ ์กฐ์šฉํ•œ ์‹œ๊ฐ„์ธ๊ฐ€** โ€” ๊ทผ๋ฌด ๋‹ฌ๋ ฅ ํŒ์ •์˜ ๊ฒฐ๊ณผ๋งŒ ๋ฐ›๋Š”๋‹ค.
439
+ *
440
+ * ๋‹ฌ๋ ฅ ์ž์ฒด๋ฅผ ์—ฌ๊ธฐ์„œ ๋ณด์ง€ ์•Š๋Š”๋‹ค: ์ด ํ•จ์ˆ˜๋Š” ์ˆœ์ˆ˜ํ•˜๊ณ , ๋‹ฌ๋ ฅยท์‹œ๊ฐ„๋Œ€ยท์‹œ๊ฐ ํ•ด์„์€ ๊ณ„์•ฝ์ด ์ด๋ฏธ
441
+ * ํ•œ ์ž๋ฆฌ์—์„œ ํ•œ๋‹ค(`inWorkCalendar`ยท`offCalendarAt`). ๋ถ€๋ฅด๋Š” ์ชฝ์ด ๊ทธ๊ฒƒ์„ ๋ถˆ๋Ÿฌ ์ฐธยท๊ฑฐ์ง“๋งŒ ์ค€๋‹ค โ€”
442
+ * `capabilityOf` ๊ฐ€ `requiredTests` ๋ฅผ ๋ฐ›๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๊ทœ์œจ์ด๋‹ค.
443
+ *
444
+ * **๋ชจ๋ฅด๋ฉด ์ฃผ์ง€ ์•Š๋Š”๋‹ค.** `false` ๋กœ ์ฑ„์šฐ๋ฉด ใ€Œ์ง€๊ธˆ์€ ํ™œ๋™ ์‹œ๊ฐ„์ด๋‹คใ€๋ฅผ ๋‹จ์–ธํ•˜๋Š” ๊ฒƒ์ด ๋˜๊ณ , ๋‹ฌ๋ ฅ์„
445
+ * ์„ ์–ธํ•˜์ง€ ์•Š์€ ์›์ฒœ์ด ์ „๋ถ€ ๊ทธ๋ ‡๊ฒŒ ์ฝํžŒ๋‹ค.
446
+ */
447
+ quietNow?: boolean;
389
448
  /**
390
449
  * ์ง€๊ธˆ๊นŒ์ง€ ์ œ์‹œ๋œ ๋ˆ„์  ์ˆ˜ โ€” **ใ€Œ๋ฐ›๊ณ  ์žˆ๋Š” ์ค‘ใ€๊ณผ ใ€Œ์˜ค๋Š” ๊ฒƒ์ด ์—†๋‹คใ€๋ฅผ ๊ฐ€๋ฅด๋Š” ์‚ฌ์‹ค**์ด๋‹ค.
391
450
  *
@@ -34,6 +34,7 @@ exports.recordRecovered = recordRecovered;
34
34
  exports.clearReadFailure = clearReadFailure;
35
35
  exports.recordCursorStall = recordCursorStall;
36
36
  exports.recordIngestSource = recordIngestSource;
37
+ exports.recordVocabulary = recordVocabulary;
37
38
  exports.recordDuplicates = recordDuplicates;
38
39
  exports.recordWithheld = recordWithheld;
39
40
  exports.clearCursorStall = clearCursorStall;
@@ -134,6 +135,21 @@ function recordIngestSource(ledger, source, count, nowMs) {
134
135
  cur.lastAtMs = nowMs;
135
136
  }
136
137
  /** ๊ฐ™์€ ์‚ฌ์‹ค์ด ๋‘ ๋ฒˆ ์™€์„œ ๋ฒ„๋ฆฐ ์ˆ˜ โ€” ์•Œ๋ฆฌ์ง€ ์•Š๊ณ  ๋ฒ„๋ฆฌ์ง€ ์•Š๋Š”๋‹ค. */
138
+ /**
139
+ * **์ €๋„์— ์•ˆ ๊ฐ„ ์–ดํœ˜ ์š”์†Œ๋ฅผ ์„ผ๋‹ค** โ€” ์—†์–ด์ง„ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ €๋„๋กœ ๊ฐ€์ง€ ์•Š๋Š” ๊ฒƒ์ด๋‹ค.
140
+ *
141
+ * ์–ดํœ˜(๋กœํŠธ ๋ฒˆํ˜ธยท์†Œ๋น„๊ธฐํ•œ ๋“ฑ)๋Š” ์‹œ๊ฐ์ถ•์ด ์—†์–ด ์ผ๋ถ€๋Ÿฌ ์ €๋„๋กœ ์•ˆ ๊ฐ„๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ์ˆ˜๋ฅผ ๋นผ ์ฃผ๋Š” ์ž๋ฆฌ๊ฐ€
142
+ * ์—†์œผ๋ฉด ใ€Œ๋ณด๋‚ธ ๊ฒƒ โˆ’ ์•‰์€ ๊ฒƒใ€์ด ์•ˆ ๋งž๊ณ , ๊ทธ ์ฐจ์ด๋ฅผ **์‚ฌ๋ผ์ง„ ๊ฒƒ์œผ๋กœ ์ฝ๊ฒŒ ๋œ๋‹ค.**
143
+ *
144
+ * ์ฐฝ์„ ๊ตด๋ฆฌ์ง€ ์•Š๋Š”๋‹ค โ€” ๋ถ€๋ฅด๋Š” ์ชฝ(`recordIngest`)์ด ์ด๋ฏธ ๊ตด๋ฆฐ ๋’ค์— ๋ถ€๋ฅธ๋‹ค. ์—ฌ๊ธฐ์„œ ๋˜ ๊ตด๋ฆฌ๋ฉด ํ•œ
145
+ * ์œ ์ž…์ด ๋‘ ์ฐฝ์— ๊ฑธ์นœ๋‹ค.
146
+ */
147
+ function recordVocabulary(ledger, count) {
148
+ if (!Number.isFinite(count) || count <= 0)
149
+ return;
150
+ ledger.vocabulary += count;
151
+ ledger.window.vocabulary += count;
152
+ }
137
153
  function recordDuplicates(ledger, count, nowMs) {
138
154
  if (count <= 0)
139
155
  return;
@@ -201,7 +217,7 @@ exports.RECORD_MAX = 2000;
201
217
  exports.HEALTHY_ACCEPTED_RATIO = 0.95;
202
218
  function newIngestLedger() {
203
219
  return {
204
- window: { startMs: -1, endMs: -1, offered: 0, rejected: 0, undelivered: 0, rows: 0, flushes: 0 },
220
+ window: { startMs: -1, endMs: -1, offered: 0, rejected: 0, vocabulary: 0, undelivered: 0, rows: 0, flushes: 0 },
205
221
  trend: [],
206
222
  trendDropped: 0,
207
223
  offered: 0,
@@ -213,6 +229,7 @@ function newIngestLedger() {
213
229
  lastUndeliveredAtMs: -1,
214
230
  bySource: {},
215
231
  duplicates: 0,
232
+ vocabulary: 0,
216
233
  lastDuplicateAtMs: -1,
217
234
  byReason: {},
218
235
  reasonsCapped: false,
@@ -244,7 +261,7 @@ function rollIngestWindow(ledger, nowMs, windowMs = exports.INGEST_WINDOW_MS, on
244
261
  return;
245
262
  const closed = { ...ledger.window, endMs: nowMs };
246
263
  ledger.trend.push(closed);
247
- ledger.window = { startMs: nowMs, endMs: -1, offered: 0, rejected: 0, undelivered: 0, rows: 0, flushes: 0 };
264
+ ledger.window = { startMs: nowMs, endMs: -1, offered: 0, rejected: 0, vocabulary: 0, undelivered: 0, rows: 0, flushes: 0 };
248
265
  if (ledger.trend.length > exports.TREND_LIMIT) {
249
266
  const drop = ledger.trend.length - exports.TREND_LIMIT;
250
267
  ledger.trend.splice(0, drop);
@@ -397,11 +414,27 @@ function syncVerdictOf(args) {
397
414
  * ํ•œ๊ณ„ โ€” ํ•œ ์ฐฝ(10๋ถ„)๋ณด๋‹ค **๋А๋ฆฌ๊ฒŒ ๊ธท๋Š” ์›์ฒœ**์€ ๊ธท๋Š” ์‚ฌ์ด์— ใ€Œ์œ ์ž… ์—†์Œใ€์œผ๋กœ ๋ณด์ธ๋‹ค. ์žฅ๋ถ€๋Š” ์›์ฒœ์˜
398
415
  * ์ฃผ๊ธฐ๋ฅผ ๋ชจ๋ฅด๋ฏ€๋กœ ์ด๋ณด๋‹ค ์ •ํ™•ํžˆ ๋‹ตํ•  ์ˆ˜ ์—†๋‹ค. ์ฃผ๊ธฐ๋ฅผ ์•Œ๊ฒŒ ๋˜๋ฉด ๊ทธ ๊ฐ’์œผ๋กœ ๊ฒฌ์ฃผ๋Š” ๊ฒƒ์ด ๋งž๋‹ค.
399
416
  */
417
+ /*
418
+ * ๊ฒฌ์ค„ ๊ธธ์ด๋Š” **์›์ฒœ์ด ์„ ์–ธํ•œ ๊ฐ’์ด ์žˆ์œผ๋ฉด ๊ทธ๊ฒƒ**์ด๋‹ค(ยง`expectedSilenceMs`). ์—†์œผ๋ฉด ์ฐฝ ํ•˜๋‚˜ โ€”
419
+ * ์œ„ ํ•œ๊ณ„ ๋ฌธ๋‹จ์ด ๋งํ•˜๋Š” ๊ทธ๋Œ€๋กœ๋‹ค.
420
+ */
421
+ const silenceLimitMs = typeof args.expectedSilenceMs === 'number' && args.expectedSilenceMs > 0
422
+ ? args.expectedSilenceMs
423
+ : exports.STALE_AFTER_MS;
400
424
  if (typeof args.lastAtMs === 'number' && typeof args.nowMs === 'number') {
401
- if (args.lastAtMs < 0)
402
- return 'unknown'; /* ๋ถ™์—ˆ์ง€๋งŒ ํ•œ ๋ฒˆ๋„ ๋ฐ›์ง€ ์•Š์•˜๋‹ค โ€” ๊ธฐ๋‹ค๋ฆฐ๋‹ค */
403
- if (args.nowMs - args.lastAtMs > exports.STALE_AFTER_MS)
404
- return 'no-traffic';
425
+ if (args.lastAtMs < 0) {
426
+ /* ํ•œ ๋ฒˆ๋„ ๋ฐ›์ง€ ์•Š์•˜๋Š”๋ฐ ์ง€๊ธˆ์ด ์กฐ์šฉํ•œ ์‹œ๊ฐ„์ด๋ฉด ใ€Œ๊ธฐ๋‹ค๋ฆฐ๋‹คใ€๊ฐ€ ์•„๋‹ˆ๋ผ ใ€Œ์ง€๊ธˆ์€ ๋งž๋‹คใ€๋‹ค. */
427
+ return args.quietNow === true ? 'expected-quiet' : 'unknown';
428
+ }
429
+ if (args.nowMs - args.lastAtMs > silenceLimitMs) {
430
+ /*
431
+ * ์˜ค๋ž˜ ์กฐ์šฉํ•˜๋‹ค. **์ง€๊ธˆ์ด ๊ทธ ์›์ฒœ์˜ ์กฐ์šฉํ•œ ์‹œ๊ฐ„์ด๋ฉด ๊ทธ๊ฒƒ์ด ์ •์ƒ์ด๋‹ค.**
432
+ *
433
+ * ์ด ๊ฐˆ๋ž˜๋ฅผ ์œ„์ชฝ(๋ฒ„๋ ค์ง€๋Š” ์ค‘ยทํ”ผ๋“œ ์—†์Œ)๋ณด๋‹ค ๋’ค์— ๋‘๋Š” ์ด์œ : ์‚ฌ์‹ค์ด ์‚ฌ๋ผ์ง€๊ณ  ์žˆ๊ฑฐ๋‚˜ ๊ฒฐ์„ ์ด
434
+ * ์—†๋Š” ๊ฒƒ์€ **๋ช‡ ์‹œ๋“  ๋ฌธ์ œ**๋‹ค. ๋ฐค์ด๋ผ๊ณ  ๋ฎ์œผ๋ฉด ๋ฐค์ƒˆ ์ƒˆ๋Š” ๊ฒƒ์„ ์•„์นจ์— ์•ˆ๋‹ค.
435
+ */
436
+ return args.quietNow === true ? 'expected-quiet' : 'no-traffic';
437
+ }
405
438
  }
406
439
  /*
407
440
  * โ”€โ”€ **๋‹ฟ์•˜๋Š”๋ฐ ์˜ค๋Š” ๊ฒƒ์ด ์—†๋‹ค** ๋ฅผ ใ€Œ๋ชจ๋ฅธ๋‹คใ€๋กœ ๋‹ตํ•˜์ง€ ์•Š๋Š”๋‹ค (2026-08-28) โ”€โ”€โ”€โ”€
@@ -424,10 +457,12 @@ function syncVerdictOf(args) {
424
457
  if (!args.recent) {
425
458
  const touched = typeof args.lastAtMs === 'number' && args.lastAtMs >= 0;
426
459
  const nothingOffered = (args.offeredTotal ?? 0) <= 0;
427
- return touched && nothingOffered ? 'no-traffic' : 'unknown';
460
+ if (touched && nothingOffered)
461
+ return args.quietNow === true ? 'expected-quiet' : 'no-traffic';
462
+ return 'unknown';
428
463
  }
429
464
  if (args.recent.offered <= 0)
430
- return 'no-traffic';
465
+ return args.quietNow === true ? 'expected-quiet' : 'no-traffic';
431
466
  const ratio = (args.recent.offered - args.recent.rejected) / args.recent.offered;
432
467
  return ratio >= (args.threshold ?? exports.HEALTHY_ACCEPTED_RATIO) ? 'syncing' : 'mapping-blocked';
433
468
  }