@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
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cadenceOf = cadenceOf;
4
+ exports.ingestExpectation = ingestExpectation;
5
+ /** 그 축의 선언을 찾는다 — 없으면 `undefined`(옛 거동으로 견준다). */
6
+ function cadenceOf(cadences, axis) {
7
+ return cadences?.find(c => c.axis === axis);
8
+ }
9
+ /**
10
+ * 유입 건강이 이 축을 어떻게 견줄 것인가 — **판정에 넘길 두 값으로 옮긴다.**
11
+ *
12
+ * `syncVerdictOf` 가 받는 모양(§`ingest-health.ts`)에 맞춘다. 그 함수는 순수하고 달력을 보지
13
+ * 않으므로, 창 판정은 여기서 끝내고 참·거짓만 넘긴다 — `capabilityOf` 가 `requiredTests` 를 받는
14
+ * 것과 같은 규율이다.
15
+ *
16
+ * ── 「보내면 온다」는 침묵으로 판정하지 않는다 ──────────────────────────────
17
+ * `pushed` 면 `quietNow` 를 늘 참으로 낸다. 그러면 침묵이 「유입 없음」이 되지 않는다. **다른
18
+ * 갈래는 그대로 산다** — 버려지는 중·결선 없음은 몇 시든 문제이고 그것들이 이 값보다 앞선다.
19
+ *
20
+ * ── 모르면 아무것도 답하지 않는다 ──────────────────────────────────────────
21
+ * 선언이 없으면 둘 다 비운다. 그때 판정은 지금까지처럼 창 하나로 견준다 — 「모른다」를 「안 와도
22
+ * 된다」로 접으면 정말 끊긴 원천이 통째로 조용해진다.
23
+ */
24
+ function ingestExpectation(cadence, ctx) {
25
+ if (!cadence)
26
+ return {};
27
+ const out = {};
28
+ if (typeof cadence.expectedSilenceMs === 'number' && cadence.expectedSilenceMs > 0) {
29
+ out.expectedSilenceMs = cadence.expectedSilenceMs;
30
+ }
31
+ if (cadence.pushed) {
32
+ /* 보낼 것이 없으면 안 보내는 것이 정상이다 — 침묵을 근거로 삼지 않는다. */
33
+ out.quietNow = true;
34
+ return out;
35
+ }
36
+ /*
37
+ * 창이 있으면 그것으로 판정한다. **판정할 수단을 안 받았으면 답하지 않는다** — 부르는 쪽이
38
+ * 달력 판정 함수를 주지 않았는데 우리가 「활동 시각이다」로 단언하면 그것이 지어낸 값이다.
39
+ */
40
+ if (cadence.window?.length && ctx.inWindow)
41
+ out.quietNow = !ctx.inWindow(cadence.window);
42
+ return out;
43
+ }
44
+ //# sourceMappingURL=live-cadence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-cadence.js","sourceRoot":"","sources":["../../../server/service/reference/live-cadence.ts"],"names":[],"mappings":";;AAoFA,8BAEC;AAiBD,8CAyBC;AA7CD,kDAAkD;AAClD,SAAgB,SAAS,CAAC,QAA4C,EAAE,IAAY;IAClF,OAAO,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAA;AAC7C,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAgB,iBAAiB,CAC/B,OAAgC,EAChC,GAA+G;IAE/G,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAA;IAEvB,MAAM,GAAG,GAAuD,EAAE,CAAA;IAElE,IAAI,OAAO,OAAO,CAAC,iBAAiB,KAAK,QAAQ,IAAI,OAAO,CAAC,iBAAiB,GAAG,CAAC,EAAE,CAAC;QACnF,GAAG,CAAC,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAA;IACnD,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,+CAA+C;QAC/C,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAA;QACnB,OAAO,GAAG,CAAA;IACZ,CAAC;IAED;;;OAGG;IACH,IAAI,OAAO,CAAC,MAAM,EAAE,MAAM,IAAI,GAAG,CAAC,QAAQ;QAAE,GAAG,CAAC,QAAQ,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;IAExF,OAAO,GAAG,CAAA;AACZ,CAAC","sourcesContent":["/*\n * **원천이 축마다 언제·얼마나 자주 내놓나** — 유입 건강이 이 선언으로 견준다.\n *\n * ── 왜 필요한가 (2026-09-04 실측) ──────────────────────────────────────────\n * 유입 건강이 **한 자로 전부를 쟀다.** 10분 안에 아무것도 오지 않으면 「유입 없음」이다. 그런데\n * 원천마다 시간의 결이 다르다.\n *\n * 태양광 발전 일몰에 멈춘다 — 두 사이트가 같은 분 19:25 에 함께\n * 부하 계측 밤에도 온다 · 15분마다\n * 인증서 가격 화·목만 거래된다 · 그 날 하루 한 번\n * MES · 주방 현장 근무시간 밖에는 사실이 안 난다 · 훅이라 「보내면 온다」\n *\n * 그래서 **정상인데 매일 밤 절반이 빨갛게 났다.** 거짓 빨강이 쌓이면 진짜 빨강도 같이 안 읽힌다.\n *\n * ── 두 축이고 서로 다르다 ───────────────────────────────────────────────────\n * window 지금이 그 축의 활동 시각인가 → 아니면 조용한 것이 정상\n * expectedSilenceMs 활동 시각 안에서 이만큼 조용해도 정상 → 넘기면 유입 없음\n *\n * 주기를 넘겼어도 활동 시각 밖이면 정상이다. 한 값으로 접을 수 없다 — 인증서 가격이 그 증거다.\n * 「매일 와야 한다」로 재면 주 5일 중 3일이 빨갛고, 「주 2회」로 재면 이어 쓴 날을 못 본다.\n *\n * ── 커널이 일출·일몰을 계산하지 않는다 ─────────────────────────────────────\n * 굴절·고위도·박명 정의가 다 선택이고, 우리가 정하면 그 순간 방언이다. 그리고 계약이 같은 문제에\n * 이미 답해 뒀다(§`TwinModelDef.utcOffsetMinutes`): 「긴 지평선의 정확한 답은 호스트가 표준대로\n * **절대 구간**을 계산해 넣는 것이다」.\n *\n * 그래서 원천은 `windowKind: 'daylight'` 로 **종류만** 선언하고, 좌표를 아는 호스트가 날마다\n * 구체적인 구간을 채운다. **고정 시각을 선언에 박지 않는다** — 일몰 19:25 는 오늘 잰 값이고 두 달\n * 뒤에는 틀리다. 그것을 박으면 겨울마다 거짓 빨강이 다시 난다.\n *\n * ── 「주기 없음」과 「모른다」는 다르다 ──────────────────────────────────────\n * MES 는 훅으로 밀어 준다 — 몇 분마다가 아니라 「보내면 온다」다. 보낼 것이 없으면 안 보내는 것이\n * 정상이고, 그것을 침묵으로 판정하면 안 된다.\n *\n * 선언하지 않은 축은 **지금까지처럼** 창 하나로 견준다(옛 거동). 「모른다」를 「안 와도 된다」로\n * 접지 않는다 — 그러면 정말 끊긴 원천이 통째로 조용해진다.\n */\nimport type { WorkCalendarEntry } from '@operato/ops-contract'\n\n/**\n * 창의 종류 — **호스트가 채워야 하는 것**만 이름이 있다.\n *\n * 지금은 하나다. 늘리기 전에 「호스트가 그것을 계산할 근거를 갖고 있나」를 먼저 물어야 한다 —\n * 좌표 없이 `daylight` 를 선언하면 호스트가 채울 것이 없고, 그러면 그 축은 창이 없는 것과 같다.\n */\nexport type LiveWindowKind = 'daylight'\n\n/** 한 축의 시간성 — 어느 사실이 언제·얼마나 자주 오나. */\nexport interface LiveCadence {\n /**\n * 어느 축인가 — **`OP_EVENT` 의 값 그대로**(`equipment.status` · `quality.output` …).\n *\n * 새 낱말을 만들지 않는다. 만들면 커넥터가 부르는 이름과 장부가 세는 이름이 갈리고, 그때\n * 선언이 조용히 아무 축에도 안 붙는다.\n */\n axis: string\n /**\n * 활동 시각 안에서 **이만큼 조용해도 정상**(ms). 없으면 창 하나로 견준다.\n *\n * 15분마다 긷는 원천은 이 값을 선언해야 한다 — 안 하면 긷는 사이마다 「유입 없음」으로 보인다.\n */\n expectedSilenceMs?: number\n /**\n * 이 축이 **활동하는 창** — 근무 달력 어휘 그대로(요일·시간대·휴일).\n *\n * 계약이 이미 그 셋을 표현한다. 새 모양을 만들지 않는 이유는 판정하는 함수가 이미 하나\n * 있기 때문이다(`inWorkCalendar`) — 두 벌이면 화면과 커널이 다른 답을 낸다.\n */\n window?: readonly WorkCalendarEntry[]\n /**\n * 창을 **호스트가 채우는 종류** — 좌표·표준으로 계산해야 하는 것.\n *\n * `window` 와 함께 선언하면 호스트가 채운 것이 이긴다(계산이 선언보다 그 날에 맞다).\n */\n windowKind?: LiveWindowKind\n /**\n * **보내면 온다** — 이 축은 침묵으로 판정하지 않는다(훅·구독).\n *\n * 「주기가 없다」와 「모른다」를 가르는 값이다. 훅은 보낼 것이 없으면 안 보내고, 그것이 정상이다.\n */\n pushed?: boolean\n}\n\n/** 그 축의 선언을 찾는다 — 없으면 `undefined`(옛 거동으로 견준다). */\nexport function cadenceOf(cadences: readonly LiveCadence[] | undefined, axis: string): LiveCadence | undefined {\n return cadences?.find(c => c.axis === axis)\n}\n\n/**\n * 유입 건강이 이 축을 어떻게 견줄 것인가 — **판정에 넘길 두 값으로 옮긴다.**\n *\n * `syncVerdictOf` 가 받는 모양(§`ingest-health.ts`)에 맞춘다. 그 함수는 순수하고 달력을 보지\n * 않으므로, 창 판정은 여기서 끝내고 참·거짓만 넘긴다 — `capabilityOf` 가 `requiredTests` 를 받는\n * 것과 같은 규율이다.\n *\n * ── 「보내면 온다」는 침묵으로 판정하지 않는다 ──────────────────────────────\n * `pushed` 면 `quietNow` 를 늘 참으로 낸다. 그러면 침묵이 「유입 없음」이 되지 않는다. **다른\n * 갈래는 그대로 산다** — 버려지는 중·결선 없음은 몇 시든 문제이고 그것들이 이 값보다 앞선다.\n *\n * ── 모르면 아무것도 답하지 않는다 ──────────────────────────────────────────\n * 선언이 없으면 둘 다 비운다. 그때 판정은 지금까지처럼 창 하나로 견준다 — 「모른다」를 「안 와도\n * 된다」로 접으면 정말 끊긴 원천이 통째로 조용해진다.\n */\nexport function ingestExpectation(\n cadence: LiveCadence | undefined,\n ctx: { nowMs: number; utcOffsetMinutes?: number; inWindow?: (window: readonly WorkCalendarEntry[]) => boolean }\n): { expectedSilenceMs?: number; quietNow?: boolean } {\n if (!cadence) return {}\n\n const out: { expectedSilenceMs?: number; quietNow?: boolean } = {}\n\n if (typeof cadence.expectedSilenceMs === 'number' && cadence.expectedSilenceMs > 0) {\n out.expectedSilenceMs = cadence.expectedSilenceMs\n }\n\n if (cadence.pushed) {\n /* 보낼 것이 없으면 안 보내는 것이 정상이다 — 침묵을 근거로 삼지 않는다. */\n out.quietNow = true\n return out\n }\n\n /*\n * 창이 있으면 그것으로 판정한다. **판정할 수단을 안 받았으면 답하지 않는다** — 부르는 쪽이\n * 달력 판정 함수를 주지 않았는데 우리가 「활동 시각이다」로 단언하면 그것이 지어낸 값이다.\n */\n if (cadence.window?.length && ctx.inWindow) out.quietNow = !ctx.inWindow(cadence.window)\n\n return out\n}\n"]}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The lease name for one twin's feed.
3
+ *
4
+ * ── Domain and instance are required; the source is not ───────────────────
5
+ * A feed is registered per instance, so domain plus instance already names it
6
+ * uniquely. The source is appended when known because it is what a person
7
+ * reading `task_leases` wants to see — which system this channel talks to.
8
+ *
9
+ * Missing a domain or an instance is refused rather than filled in. A blank
10
+ * there would collapse two different feeds onto one name, and the failure
11
+ * would be that one of them silently stops: it would look exactly like
12
+ * "someone else holds it", which is the ordinary case on every instance but
13
+ * one, so nothing would be logged.
14
+ */
15
+ export declare function liveFeedLeaseName(domainId: string, instanceId: string, source?: string): string;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ /*
3
+ * What a live feed takes its task lease under — pure naming, one place.
4
+ *
5
+ * ── Why the name is built here and not by the adapter ──────────────────────
6
+ * `TaskLease` deliberately has no domain column: the thing made exclusive is a
7
+ * loop, not a tenant's slice of one, and a task that does need to be per-tenant
8
+ * puts the tenant in its name so the unique index keeps meaning what it says.
9
+ *
10
+ * An adapter cannot honour that. It receives `cfg` and `site`, and neither
11
+ * carries a domain — so a name built from `siteId` would let two domains that
12
+ * happen to share a plant code block each other's channel. It would look
13
+ * exactly like "someone else holds it", which is the ordinary case on every
14
+ * instance but one, so nothing would be logged and nothing would look wrong.
15
+ *
16
+ * ── Why the source and not the site ───────────────────────────────────────
17
+ * One reference is one connection to one system, and that connection is what a
18
+ * second instance must not open twice. A source that discovers several sites
19
+ * still reads them over that one connection.
20
+ *
21
+ * ── Why the parts are joined with `::` ────────────────────────────────────
22
+ * The same separator the push cursor key already uses (`instanceId::scope`), so
23
+ * a person reading `task_leases` during an incident sees the same shape they
24
+ * see in `liveCursor`.
25
+ */
26
+ Object.defineProperty(exports, "__esModule", { value: true });
27
+ exports.liveFeedLeaseName = liveFeedLeaseName;
28
+ /** Marks the name as a live feed, so a lease table read tells you what kind of task it is. */
29
+ const PREFIX = 'twin-live';
30
+ /**
31
+ * The lease name for one twin's feed.
32
+ *
33
+ * ── Domain and instance are required; the source is not ───────────────────
34
+ * A feed is registered per instance, so domain plus instance already names it
35
+ * uniquely. The source is appended when known because it is what a person
36
+ * reading `task_leases` wants to see — which system this channel talks to.
37
+ *
38
+ * Missing a domain or an instance is refused rather than filled in. A blank
39
+ * there would collapse two different feeds onto one name, and the failure
40
+ * would be that one of them silently stops: it would look exactly like
41
+ * "someone else holds it", which is the ordinary case on every instance but
42
+ * one, so nothing would be logged.
43
+ */
44
+ function liveFeedLeaseName(domainId, instanceId, source) {
45
+ for (const [what, value] of [
46
+ ['domainId', domainId],
47
+ ['instanceId', instanceId]
48
+ ]) {
49
+ if (!value || !String(value).trim()) {
50
+ throw new Error(`cannot name a live feed lease without ${what} — two feeds would share one name`);
51
+ }
52
+ }
53
+ const named = source && String(source).trim();
54
+ return named ? `${PREFIX}::${domainId}::${instanceId}::${named}` : `${PREFIX}::${domainId}::${instanceId}`;
55
+ }
56
+ //# sourceMappingURL=live-feed-lease.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-feed-lease.js","sourceRoot":"","sources":["../../../server/service/reference/live-feed-lease.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;;AAmBH,8CAaC;AA9BD,8FAA8F;AAC9F,MAAM,MAAM,GAAG,WAAW,CAAA;AAE1B;;;;;;;;;;;;;GAaG;AACH,SAAgB,iBAAiB,CAAC,QAAgB,EAAE,UAAkB,EAAE,MAAe;IACrF,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI;QAC1B,CAAC,UAAU,EAAE,QAAQ,CAAC;QACtB,CAAC,YAAY,EAAE,UAAU,CAAC;KAClB,EAAE,CAAC;QACX,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,yCAAyC,IAAI,mCAAmC,CAAC,CAAA;QACnG,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAA;IAE7C,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,KAAK,QAAQ,KAAK,UAAU,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,KAAK,QAAQ,KAAK,UAAU,EAAE,CAAA;AAC5G,CAAC","sourcesContent":["/*\n * What a live feed takes its task lease under — pure naming, one place.\n *\n * ── Why the name is built here and not by the adapter ──────────────────────\n * `TaskLease` deliberately has no domain column: the thing made exclusive is a\n * loop, not a tenant's slice of one, and a task that does need to be per-tenant\n * puts the tenant in its name so the unique index keeps meaning what it says.\n *\n * An adapter cannot honour that. It receives `cfg` and `site`, and neither\n * carries a domain — so a name built from `siteId` would let two domains that\n * happen to share a plant code block each other's channel. It would look\n * exactly like \"someone else holds it\", which is the ordinary case on every\n * instance but one, so nothing would be logged and nothing would look wrong.\n *\n * ── Why the source and not the site ───────────────────────────────────────\n * One reference is one connection to one system, and that connection is what a\n * second instance must not open twice. A source that discovers several sites\n * still reads them over that one connection.\n *\n * ── Why the parts are joined with `::` ────────────────────────────────────\n * The same separator the push cursor key already uses (`instanceId::scope`), so\n * a person reading `task_leases` during an incident sees the same shape they\n * see in `liveCursor`.\n */\n\n/** Marks the name as a live feed, so a lease table read tells you what kind of task it is. */\nconst PREFIX = 'twin-live'\n\n/**\n * The lease name for one twin's feed.\n *\n * ── Domain and instance are required; the source is not ───────────────────\n * A feed is registered per instance, so domain plus instance already names it\n * uniquely. The source is appended when known because it is what a person\n * reading `task_leases` wants to see — which system this channel talks to.\n *\n * Missing a domain or an instance is refused rather than filled in. A blank\n * there would collapse two different feeds onto one name, and the failure\n * would be that one of them silently stops: it would look exactly like\n * \"someone else holds it\", which is the ordinary case on every instance but\n * one, so nothing would be logged.\n */\nexport function liveFeedLeaseName(domainId: string, instanceId: string, source?: string): string {\n for (const [what, value] of [\n ['domainId', domainId],\n ['instanceId', instanceId]\n ] as const) {\n if (!value || !String(value).trim()) {\n throw new Error(`cannot name a live feed lease without ${what} — two feeds would share one name`)\n }\n }\n\n const named = source && String(source).trim()\n\n return named ? `${PREFIX}::${domainId}::${instanceId}::${named}` : `${PREFIX}::${domainId}::${instanceId}`\n}\n"]}
@@ -0,0 +1,21 @@
1
+ import type { IngestResult } from './reference-hook.js';
2
+ /**
3
+ * 레코드를 넣고 **네 갈래로 답한다.**
4
+ *
5
+ * 두 갈래로는 셈이 안 닫힙니다(인티그레이션 레인 실측 2026-09-05).
6
+ *
7
+ * ```
8
+ * 두 갈래 157 − 46 − 2 = 109 「설명 못 함」 진실은 되풀이 108 + 어휘 1
9
+ * 네 갈래 157 − 46 − 2 − 108 − 1 = 0
10
+ * ```
11
+ *
12
+ * 109 를 「사라졌다」로 내면 그날부터 아무도 그 수를 안 봅니다. 늘 참인 경고는 벽지가 됩니다.
13
+ *
14
+ * `vocabulary` 는 저널에 안 가는 어휘 요소의 수입니다. 사라진 것이 아닙니다.
15
+ *
16
+ * @param via 유입 장부에 남길 길 이름 — `hook`(밀어 받음) · `fill`(빠진 구간을 다시 받음)
17
+ */
18
+ export declare function liveIngest(domainId: string, instanceId: string, records: unknown[], via: string): IngestResult & {
19
+ vocabulary: number;
20
+ undated?: Record<string, number>;
21
+ };
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.liveIngest = liveIngest;
4
+ const index_js_1 = require("../../engine/index.js");
5
+ const canonical_ingest_js_1 = require("../../engine/canonical-ingest.js");
6
+ const index_js_2 = require("../actuation/index.js");
7
+ const event_time_js_1 = require("../../engine/event-time.js");
8
+ const log_js_1 = require("../../engine/log.js");
9
+ /**
10
+ * 레코드를 넣고 **네 갈래로 답한다.**
11
+ *
12
+ * 두 갈래로는 셈이 안 닫힙니다(인티그레이션 레인 실측 2026-09-05).
13
+ *
14
+ * ```
15
+ * 두 갈래 157 − 46 − 2 = 109 「설명 못 함」 진실은 되풀이 108 + 어휘 1
16
+ * 네 갈래 157 − 46 − 2 − 108 − 1 = 0
17
+ * ```
18
+ *
19
+ * 109 를 「사라졌다」로 내면 그날부터 아무도 그 수를 안 봅니다. 늘 참인 경고는 벽지가 됩니다.
20
+ *
21
+ * `vocabulary` 는 저널에 안 가는 어휘 요소의 수입니다. 사라진 것이 아닙니다.
22
+ *
23
+ * @param via 유입 장부에 남길 길 이름 — `hook`(밀어 받음) · `fill`(빠진 구간을 다시 받음)
24
+ */
25
+ function liveIngest(domainId, instanceId, records, via) {
26
+ const { accepted, rejected, masterData, undated } = (0, canonical_ingest_js_1.ingestCanonicalRecords)(records, domainId, new Date().toISOString(), index_js_1.TwinEngine.factScope(domainId, instanceId));
27
+ /* 사건이 아닌 것은 상태만 세운다 — 두 길이 같은 규율이다(§`applyMasterData`). */
28
+ if (masterData.length)
29
+ index_js_1.TwinEngine.applyMasterData(domainId, instanceId, masterData);
30
+ const { applied, duplicates } = index_js_1.TwinEngine.ingestLiveResult(domainId, instanceId, accepted, via);
31
+ /*
32
+ * **나간 지시와 잇는다** — 폐루프. 기다리지 않습니다: 훅의 응답이 이것 때문에 늦으면 보내는 쪽이
33
+ * 되풀이하고, 그러면 같은 관측이 두 번 옵니다. 실패해도 관측 유입은 멈추지 않습니다.
34
+ */
35
+ void (0, index_js_2.settleEffects)({ domainId, envelopes: accepted, store: (0, index_js_2.databaseCommandStore)() });
36
+ /*
37
+ * 커널이 받지 못한 수를 이름으로 남깁니다 — 트윈이 멈춘 사이 버려진 레코드를 「통과」로 세면
38
+ * 화면이 100% 라고 말합니다. 중복으로 걸러진 것은 버려진 것이 아니므로 빼고 셉니다.
39
+ */
40
+ const undelivered = Math.max(0, accepted.length - applied - duplicates);
41
+ index_js_1.TwinEngine.recordIngestResult(domainId, instanceId, records.length, rejected, Date.now(), undelivered, masterData.length);
42
+ /*
43
+ * 떨어진 것을 **수가 아니라 목록으로** 넘깁니다 — 응답에 실어야 보내는 쪽이 그것만 따로 둘 수
44
+ * 있습니다. 수만 주면 배치 전체를 다시 보내거나 전부 버리는 두 갈래밖에 없습니다.
45
+ */
46
+ /*
47
+ * **표에 있는 type 인데 시각을 못 읽었으면 그것은 결함이다.** 그 fact 는 자기 시각을 싣기로 되어
48
+ * 있는데 안 실려 온 것이고, 그대로 두면 ingest 시각이 그 사실의 시각으로 저장된다.
49
+ *
50
+ * 표에 없는 type 은 세기만 한다 — 절대값 snapshot 은 polling 순간이 맞는 시각이다.
51
+ */
52
+ const wrong = Object.entries(undated ?? {}).filter(([type]) => (0, event_time_js_1.shouldHaveTime)(type));
53
+ if (wrong.length) {
54
+ (0, log_js_1.twinWarn)(`[twin-ingest] "${instanceId}" — 시각을 실어야 하는 fact 가 시각 없이 왔습니다: ` +
55
+ wrong.map(([t, n]) => `${t} ${n}건`).join(' · ') +
56
+ `. 그 사실들은 지금 시각으로 저널에 앉습니다`);
57
+ }
58
+ return {
59
+ applied,
60
+ duplicates,
61
+ vocabulary: masterData.length,
62
+ rejected,
63
+ ...(undated && Object.keys(undated).length ? { undated } : {})
64
+ };
65
+ }
66
+ //# sourceMappingURL=live-ingest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-ingest.js","sourceRoot":"","sources":["../../../server/service/reference/live-ingest.ts"],"names":[],"mappings":";;AAsCA,gCAuDC;AA7ED,oDAAkD;AAClD,0EAAyE;AACzE,oDAA2E;AAC3E,8DAA2D;AAC3D,gDAA8C;AAE9C;;;;;;;;;;;;;;;GAeG;AACH,SAAgB,UAAU,CACxB,QAAgB,EAChB,UAAkB,EAClB,OAAkB,EAClB,GAAW;IAEX,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,IAAA,4CAAsB,EACxE,OAAc,EACd,QAAQ,EACR,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EACxB,qBAAU,CAAC,SAAS,CAAC,QAAQ,EAAE,UAAU,CAAC,CAC3C,CAAA;IACD,2DAA2D;IAC3D,IAAI,UAAU,CAAC,MAAM;QAAE,qBAAU,CAAC,eAAe,CAAC,QAAQ,EAAE,UAAU,EAAE,UAAU,CAAC,CAAA;IACnF,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,qBAAU,CAAC,gBAAgB,CAAC,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAA;IAEhG;;;OAGG;IACH,KAAK,IAAA,wBAAa,EAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAA,+BAAoB,GAAE,EAAE,CAAC,CAAA;IAEpF;;;OAGG;IACH,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,OAAO,GAAG,UAAU,CAAC,CAAA;IACvE,qBAAU,CAAC,kBAAkB,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,UAAU,CAAC,MAAM,CAAC,CAAA;IAEzH;;;OAGG;IACH;;;;;OAKG;IACH,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAA,8BAAc,EAAC,IAAI,CAAC,CAAC,CAAA;IACpF,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjB,IAAA,iBAAQ,EACN,kBAAkB,UAAU,oCAAoC;YAC9D,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;YAC/C,2BAA2B,CAC9B,CAAA;IACH,CAAC;IAED,OAAO;QACL,OAAO;QACP,UAAU;QACV,UAAU,EAAE,UAAU,CAAC,MAAM;QAC7B,QAAQ;QACR,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/D,CAAA;AACH,CAAC","sourcesContent":["/*\n * **원본이 준 레코드를 트윈에 넣는다** — 밀어 받는 길과 backfill 이 같이 쓴다.\n *\n * ── 왜 한 곳에 두나 ─────────────────────────────────────────────────────────\n * 이 몸통이 `routes.ts` 의 훅 안에 박혀 있었습니다. backfill 문을 만들면서 복사하면 두 길이 서로\n * 다른 규칙으로 받게 되고, 한쪽만 수정되는 날이 옵니다.\n *\n * 실제로 그 위험이 이 자리에 있습니다. 유입 장부의 네 갈래(앉음 · 되풀이 · 어휘 · 거절)를\n * 2026-09-05 에 고쳤는데, 그때 이 몸통이 두 벌이었다면 한쪽 셈만 닫혔을 것입니다.\n *\n * ── 커널을 직접 부르지 않는 쪽이 넘겨받는다 ────────────────────────────────\n * 훅 판정(`reference-hook.ts`)은 이 함수를 인자로 받습니다. 그 파일이 엔진을 직접 부르면 테스트할\n * 때 엔진이 필요해집니다. 그 규율은 그대로 두고, 이 파일이 엔진을 아는 유일한 자리가 됩니다.\n */\nimport type { IngestResult } from './reference-hook.js'\n\nimport { TwinEngine } from '../../engine/index.js'\nimport { ingestCanonicalRecords } from '../../engine/canonical-ingest.js'\nimport { databaseCommandStore, settleEffects } from '../actuation/index.js'\nimport { shouldHaveTime } from '../../engine/event-time.js'\nimport { twinWarn } from '../../engine/log.js'\n\n/**\n * 레코드를 넣고 **네 갈래로 답한다.**\n *\n * 두 갈래로는 셈이 안 닫힙니다(인티그레이션 레인 실측 2026-09-05).\n *\n * ```\n * 두 갈래 157 − 46 − 2 = 109 「설명 못 함」 진실은 되풀이 108 + 어휘 1\n * 네 갈래 157 − 46 − 2 − 108 − 1 = 0\n * ```\n *\n * 109 를 「사라졌다」로 내면 그날부터 아무도 그 수를 안 봅니다. 늘 참인 경고는 벽지가 됩니다.\n *\n * `vocabulary` 는 저널에 안 가는 어휘 요소의 수입니다. 사라진 것이 아닙니다.\n *\n * @param via 유입 장부에 남길 길 이름 — `hook`(밀어 받음) · `fill`(빠진 구간을 다시 받음)\n */\nexport function liveIngest(\n domainId: string,\n instanceId: string,\n records: unknown[],\n via: string\n): IngestResult & { vocabulary: number; undated?: Record<string, number> } {\n const { accepted, rejected, masterData, undated } = ingestCanonicalRecords(\n records as any,\n domainId,\n new Date().toISOString(),\n TwinEngine.factScope(domainId, instanceId)\n )\n /* 사건이 아닌 것은 상태만 세운다 — 두 길이 같은 규율이다(§`applyMasterData`). */\n if (masterData.length) TwinEngine.applyMasterData(domainId, instanceId, masterData)\n const { applied, duplicates } = TwinEngine.ingestLiveResult(domainId, instanceId, accepted, via)\n\n /*\n * **나간 지시와 잇는다** — 폐루프. 기다리지 않습니다: 훅의 응답이 이것 때문에 늦으면 보내는 쪽이\n * 되풀이하고, 그러면 같은 관측이 두 번 옵니다. 실패해도 관측 유입은 멈추지 않습니다.\n */\n void settleEffects({ domainId, envelopes: accepted, store: databaseCommandStore() })\n\n /*\n * 커널이 받지 못한 수를 이름으로 남깁니다 — 트윈이 멈춘 사이 버려진 레코드를 「통과」로 세면\n * 화면이 100% 라고 말합니다. 중복으로 걸러진 것은 버려진 것이 아니므로 빼고 셉니다.\n */\n const undelivered = Math.max(0, accepted.length - applied - duplicates)\n TwinEngine.recordIngestResult(domainId, instanceId, records.length, rejected, Date.now(), undelivered, masterData.length)\n\n /*\n * 떨어진 것을 **수가 아니라 목록으로** 넘깁니다 — 응답에 실어야 보내는 쪽이 그것만 따로 둘 수\n * 있습니다. 수만 주면 배치 전체를 다시 보내거나 전부 버리는 두 갈래밖에 없습니다.\n */\n /*\n * **표에 있는 type 인데 시각을 못 읽었으면 그것은 결함이다.** 그 fact 는 자기 시각을 싣기로 되어\n * 있는데 안 실려 온 것이고, 그대로 두면 ingest 시각이 그 사실의 시각으로 저장된다.\n *\n * 표에 없는 type 은 세기만 한다 — 절대값 snapshot 은 polling 순간이 맞는 시각이다.\n */\n const wrong = Object.entries(undated ?? {}).filter(([type]) => shouldHaveTime(type))\n if (wrong.length) {\n twinWarn(\n `[twin-ingest] \"${instanceId}\" — 시각을 실어야 하는 fact 가 시각 없이 왔습니다: ` +\n wrong.map(([t, n]) => `${t} ${n}건`).join(' · ') +\n `. 그 사실들은 지금 시각으로 저널에 앉습니다`\n )\n }\n\n return {\n applied,\n duplicates,\n vocabulary: masterData.length,\n rejected,\n ...(undated && Object.keys(undated).length ? { undated } : {})\n }\n}\n"]}