@things-factory/headless-twin 10.1.278 → 10.1.279

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (614) hide show
  1. package/package.json +21 -7
  2. package/dist-server/engine/attention-digest.js.map +0 -1
  3. package/dist-server/engine/canonical-ingest.js.map +0 -1
  4. package/dist-server/engine/checkpoint-fold.js.map +0 -1
  5. package/dist-server/engine/command-routing.js.map +0 -1
  6. package/dist-server/engine/declared-stimulus.js.map +0 -1
  7. package/dist-server/engine/energy-topology.js.map +0 -1
  8. package/dist-server/engine/event-time.js.map +0 -1
  9. package/dist-server/engine/index.js.map +0 -1
  10. package/dist-server/engine/ingest-dedupe.js.map +0 -1
  11. package/dist-server/engine/ingest-health.js.map +0 -1
  12. package/dist-server/engine/integration-coverage.js.map +0 -1
  13. package/dist-server/engine/integration-probes.js.map +0 -1
  14. package/dist-server/engine/integration-runner.js.map +0 -1
  15. package/dist-server/engine/integration-target-profile.js.map +0 -1
  16. package/dist-server/engine/kpi-baseline.js.map +0 -1
  17. package/dist-server/engine/kpi-fold.js.map +0 -1
  18. package/dist-server/engine/kpi-query.js.map +0 -1
  19. package/dist-server/engine/kpi-target.js.map +0 -1
  20. package/dist-server/engine/live-attentions.js.map +0 -1
  21. package/dist-server/engine/live-feed-registry.js.map +0 -1
  22. package/dist-server/engine/load-meter.js.map +0 -1
  23. package/dist-server/engine/local-declarations.js.map +0 -1
  24. package/dist-server/engine/log.js.map +0 -1
  25. package/dist-server/engine/loop-lag.js.map +0 -1
  26. package/dist-server/engine/measured-estimator.js.map +0 -1
  27. package/dist-server/engine/measured-yield.js.map +0 -1
  28. package/dist-server/engine/model-basis.js.map +0 -1
  29. package/dist-server/engine/model-gap.js.map +0 -1
  30. package/dist-server/engine/model-refusal.js.map +0 -1
  31. package/dist-server/engine/model-vocabulary.js.map +0 -1
  32. package/dist-server/engine/oee-accumulator.js.map +0 -1
  33. package/dist-server/engine/operation-basis.js.map +0 -1
  34. package/dist-server/engine/producer-guard.js.map +0 -1
  35. package/dist-server/engine/property-effects.js.map +0 -1
  36. package/dist-server/engine/read-time.js.map +0 -1
  37. package/dist-server/engine/restart-policy.js.map +0 -1
  38. package/dist-server/engine/runtime-key.js.map +0 -1
  39. package/dist-server/engine/spec-coverage.js.map +0 -1
  40. package/dist-server/engine/stage-path.js.map +0 -1
  41. package/dist-server/engine/state-axes.js.map +0 -1
  42. package/dist-server/engine/structure-diff.js.map +0 -1
  43. package/dist-server/engine/travel-estimator.js.map +0 -1
  44. package/dist-server/engine/twin-engine.js.map +0 -1
  45. package/dist-server/engine/twin-state-channel.js.map +0 -1
  46. package/dist-server/engine/warm-start.js.map +0 -1
  47. package/dist-server/index.js.map +0 -1
  48. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js.map +0 -1
  49. package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js.map +0 -1
  50. package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js.map +0 -1
  51. package/dist-server/migrations/1786300000000-IndexEventTypeByTime.js.map +0 -1
  52. package/dist-server/migrations/1786400000000-IndexEventCreatedAt.js.map +0 -1
  53. package/dist-server/migrations/1786500000000-CreateTwinSubjectEvents.js.map +0 -1
  54. package/dist-server/migrations/1786600000000-RenameOperatoMesAdapterType.js.map +0 -1
  55. package/dist-server/migrations/1786700000000-AddDispatchRetryColumns.js.map +0 -1
  56. package/dist-server/migrations/1786800000000-CreateTwinReferenceReconciliations.js.map +0 -1
  57. package/dist-server/migrations/index.js.map +0 -1
  58. package/dist-server/routes.js.map +0 -1
  59. package/dist-server/service/actuation/actuation-advisor.js.map +0 -1
  60. package/dist-server/service/actuation/actuation-outcome.js.map +0 -1
  61. package/dist-server/service/actuation/actuation-rule-resolver.js.map +0 -1
  62. package/dist-server/service/actuation/actuation-rule.js.map +0 -1
  63. package/dist-server/service/actuation/approval-gateway.js.map +0 -1
  64. package/dist-server/service/actuation/catch-up-effects.js.map +0 -1
  65. package/dist-server/service/actuation/command-dispatcher.js.map +0 -1
  66. package/dist-server/service/actuation/command-store.js.map +0 -1
  67. package/dist-server/service/actuation/dispatch-after-approval.js.map +0 -1
  68. package/dist-server/service/actuation/effect-match.js.map +0 -1
  69. package/dist-server/service/actuation/index.js.map +0 -1
  70. package/dist-server/service/actuation/retry-plan.js.map +0 -1
  71. package/dist-server/service/actuation/rule-evaluate.js.map +0 -1
  72. package/dist-server/service/actuation/rule-loop.js.map +0 -1
  73. package/dist-server/service/actuation/rule-runner.js.map +0 -1
  74. package/dist-server/service/actuation/rule-wiring.js.map +0 -1
  75. package/dist-server/service/actuation/settle-effects.js.map +0 -1
  76. package/dist-server/service/actuation/sweep-dispatch.js.map +0 -1
  77. package/dist-server/service/actuation/twin-command-resolver.js.map +0 -1
  78. package/dist-server/service/actuation/twin-command.js.map +0 -1
  79. package/dist-server/service/actuation/twin-now.js.map +0 -1
  80. package/dist-server/service/index.js.map +0 -1
  81. package/dist-server/service/reference/actuation-routing.js.map +0 -1
  82. package/dist-server/service/reference/actuation-target.js.map +0 -1
  83. package/dist-server/service/reference/actuation-verification.js.map +0 -1
  84. package/dist-server/service/reference/attention-lane.js.map +0 -1
  85. package/dist-server/service/reference/connection-portability-resolver.js.map +0 -1
  86. package/dist-server/service/reference/connection-portability.js.map +0 -1
  87. package/dist-server/service/reference/control-routing.js.map +0 -1
  88. package/dist-server/service/reference/discovery-result.js.map +0 -1
  89. package/dist-server/service/reference/fill-cadence.js.map +0 -1
  90. package/dist-server/service/reference/fill-dedupe.js.map +0 -1
  91. package/dist-server/service/reference/fill-loop.js.map +0 -1
  92. package/dist-server/service/reference/fill-span.js.map +0 -1
  93. package/dist-server/service/reference/hook-contract.js.map +0 -1
  94. package/dist-server/service/reference/hook-rejected.js.map +0 -1
  95. package/dist-server/service/reference/hook-store.js.map +0 -1
  96. package/dist-server/service/reference/index.js.map +0 -1
  97. package/dist-server/service/reference/ingest-space.js.map +0 -1
  98. package/dist-server/service/reference/knob-defaults.js.map +0 -1
  99. package/dist-server/service/reference/live-cadence.js.map +0 -1
  100. package/dist-server/service/reference/live-feed-lease.js.map +0 -1
  101. package/dist-server/service/reference/live-ingest.js.map +0 -1
  102. package/dist-server/service/reference/reference-adapter.js.map +0 -1
  103. package/dist-server/service/reference/reference-assessment.js.map +0 -1
  104. package/dist-server/service/reference/reference-fill-run.js.map +0 -1
  105. package/dist-server/service/reference/reference-fill.js.map +0 -1
  106. package/dist-server/service/reference/reference-hook.js.map +0 -1
  107. package/dist-server/service/reference/reference-link-groups.js.map +0 -1
  108. package/dist-server/service/reference/reference-links.js.map +0 -1
  109. package/dist-server/service/reference/reference-live.js.map +0 -1
  110. package/dist-server/service/reference/reference-master.js.map +0 -1
  111. package/dist-server/service/reference/reference-probe.js.map +0 -1
  112. package/dist-server/service/reference/reference-progress-channel.js.map +0 -1
  113. package/dist-server/service/reference/reference-progress-subscription.js.map +0 -1
  114. package/dist-server/service/reference/reference-progress.js.map +0 -1
  115. package/dist-server/service/reference/reference-reconciliation-query.js.map +0 -1
  116. package/dist-server/service/reference/reference-reconciliation-writer.js.map +0 -1
  117. package/dist-server/service/reference/reference-reconciliation.js.map +0 -1
  118. package/dist-server/service/reference/reference-registry.js.map +0 -1
  119. package/dist-server/service/reference/reference-resolver.js.map +0 -1
  120. package/dist-server/service/reference/template-registry.js.map +0 -1
  121. package/dist-server/service/reference/twin-reference-reconciliation.js.map +0 -1
  122. package/dist-server/service/reference/twin-reference.js.map +0 -1
  123. package/dist-server/service/twin-attention/index.js.map +0 -1
  124. package/dist-server/service/twin-attention/twin-attention-query.js.map +0 -1
  125. package/dist-server/service/twin-audit/command-audit.js.map +0 -1
  126. package/dist-server/service/twin-audit/index.js.map +0 -1
  127. package/dist-server/service/twin-audit/twin-audit-event.js.map +0 -1
  128. package/dist-server/service/twin-audit/twin-audit-query.js.map +0 -1
  129. package/dist-server/service/twin-backfill/backfill-period-facts.js.map +0 -1
  130. package/dist-server/service/twin-backfill/backfill-shape.js.map +0 -1
  131. package/dist-server/service/twin-backfill/index.js.map +0 -1
  132. package/dist-server/service/twin-backfill/twin-backfill-resolver.js.map +0 -1
  133. package/dist-server/service/twin-control/index.js.map +0 -1
  134. package/dist-server/service/twin-control/twin-control-mutation.js.map +0 -1
  135. package/dist-server/service/twin-event/index.js.map +0 -1
  136. package/dist-server/service/twin-event/journal-count.js.map +0 -1
  137. package/dist-server/service/twin-event/twin-event-keys.js.map +0 -1
  138. package/dist-server/service/twin-event/twin-event-type.js.map +0 -1
  139. package/dist-server/service/twin-event/twin-event.js.map +0 -1
  140. package/dist-server/service/twin-forecast/forecast-metrics.js.map +0 -1
  141. package/dist-server/service/twin-forecast/forecast-tuning.js.map +0 -1
  142. package/dist-server/service/twin-forecast/gap-analytics.js.map +0 -1
  143. package/dist-server/service/twin-forecast/index.js.map +0 -1
  144. package/dist-server/service/twin-forecast/twin-forecast-query.js.map +0 -1
  145. package/dist-server/service/twin-ingest-window/index.js.map +0 -1
  146. package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js.map +0 -1
  147. package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js.map +0 -1
  148. package/dist-server/service/twin-ingest-window/twin-ingest-window.js.map +0 -1
  149. package/dist-server/service/twin-instance/index.js.map +0 -1
  150. package/dist-server/service/twin-instance/twin-instance.js.map +0 -1
  151. package/dist-server/service/twin-journal/event-type-split-shape.js.map +0 -1
  152. package/dist-server/service/twin-journal/event-type-split.js.map +0 -1
  153. package/dist-server/service/twin-journal/index.js.map +0 -1
  154. package/dist-server/service/twin-journal/journal-order.js.map +0 -1
  155. package/dist-server/service/twin-journal/twin-journal-query.js.map +0 -1
  156. package/dist-server/service/twin-lifecycle/domain-catalog.js.map +0 -1
  157. package/dist-server/service/twin-lifecycle/index.js.map +0 -1
  158. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +0 -1
  159. package/dist-server/service/twin-metrics/index.js.map +0 -1
  160. package/dist-server/service/twin-metrics/twin-metrics-query.js.map +0 -1
  161. package/dist-server/service/twin-model/axis-journal-evidence.js.map +0 -1
  162. package/dist-server/service/twin-model/choose-recipe.js.map +0 -1
  163. package/dist-server/service/twin-model/epcis-coverage.js.map +0 -1
  164. package/dist-server/service/twin-model/external-resolver.js.map +0 -1
  165. package/dist-server/service/twin-model/iec61850-coverage.js.map +0 -1
  166. package/dist-server/service/twin-model/index.js.map +0 -1
  167. package/dist-server/service/twin-model/isa95-coverage.js.map +0 -1
  168. package/dist-server/service/twin-model/item-ref.js.map +0 -1
  169. package/dist-server/service/twin-model/name-index.js.map +0 -1
  170. package/dist-server/service/twin-model/project-structure.js.map +0 -1
  171. package/dist-server/service/twin-model/standard-coverage.js.map +0 -1
  172. package/dist-server/service/twin-model/status-tally.js.map +0 -1
  173. package/dist-server/service/twin-model/twin-equipment.js.map +0 -1
  174. package/dist-server/service/twin-model/twin-lineage-query.js.map +0 -1
  175. package/dist-server/service/twin-model/twin-location.js.map +0 -1
  176. package/dist-server/service/twin-model/twin-model-item-query.js.map +0 -1
  177. package/dist-server/service/twin-model/twin-model-mutation.js.map +0 -1
  178. package/dist-server/service/twin-model/twin-model-query.js.map +0 -1
  179. package/dist-server/service/twin-model/twin-model-tree-query.js.map +0 -1
  180. package/dist-server/service/twin-model/twin-operation.js.map +0 -1
  181. package/dist-server/service/twin-readiness/index.js.map +0 -1
  182. package/dist-server/service/twin-readiness/twin-readiness-query.js.map +0 -1
  183. package/dist-server/service/twin-space/area-resolver.js.map +0 -1
  184. package/dist-server/service/twin-space/index.js.map +0 -1
  185. package/dist-server/service/twin-space/move-space.js.map +0 -1
  186. package/dist-server/service/twin-space/representation-role.js.map +0 -1
  187. package/dist-server/service/twin-space/space-integrity.js.map +0 -1
  188. package/dist-server/service/twin-space/twin-area.js.map +0 -1
  189. package/dist-server/service/twin-space/twin-space-area.js.map +0 -1
  190. package/dist-server/service/twin-space/twin-space-representation.js.map +0 -1
  191. package/dist-server/service/twin-space/twin-space-resolver.js.map +0 -1
  192. package/dist-server/service/twin-space/twin-space.js.map +0 -1
  193. package/dist-server/service/twin-state/index.js.map +0 -1
  194. package/dist-server/service/twin-state/twin-state-subscription.js.map +0 -1
  195. package/dist-server/service/twin-structure/index.js.map +0 -1
  196. package/dist-server/service/twin-structure/twin-structure.js.map +0 -1
  197. package/dist-server/service/twin-subject/event-subjects.js.map +0 -1
  198. package/dist-server/service/twin-subject/index.js.map +0 -1
  199. package/dist-server/service/twin-subject/item-resolver.js.map +0 -1
  200. package/dist-server/service/twin-subject/subject-query-shape.js.map +0 -1
  201. package/dist-server/service/twin-subject/twin-subject-backfill.js.map +0 -1
  202. package/dist-server/service/twin-subject/twin-subject-event.js.map +0 -1
  203. package/dist-server/service/twin-subject/twin-subject-fast-path.js.map +0 -1
  204. package/dist-server/service/twin-subject/twin-subject-query.js.map +0 -1
  205. package/dist-server/service/twin-subject/twin-subject-writer.js.map +0 -1
  206. package/dist-server/service/twin-target/index.js.map +0 -1
  207. package/dist-server/service/twin-target/twin-target-resolver.js.map +0 -1
  208. package/dist-server/service/twin-target/twin-target.js.map +0 -1
  209. package/dist-shared/axis-read.js.map +0 -1
  210. package/dist-shared/entity-delta.js.map +0 -1
  211. package/dist-shared/kpi-broadcast.js.map +0 -1
  212. package/dist-shared/touched-items.js.map +0 -1
  213. package/dist-shared/twin-level.js.map +0 -1
  214. package/server/engine/attention-digest.ts +0 -102
  215. package/server/engine/canonical-ingest.ts +0 -511
  216. package/server/engine/checkpoint-fold.ts +0 -12
  217. package/server/engine/command-routing.ts +0 -67
  218. package/server/engine/declared-stimulus.ts +0 -66
  219. package/server/engine/energy-topology.ts +0 -189
  220. package/server/engine/event-time.ts +0 -96
  221. package/server/engine/index.ts +0 -51
  222. package/server/engine/ingest-dedupe.ts +0 -24
  223. package/server/engine/ingest-health.ts +0 -24
  224. package/server/engine/integration-coverage.ts +0 -147
  225. package/server/engine/integration-probes.ts +0 -144
  226. package/server/engine/integration-runner.ts +0 -95
  227. package/server/engine/integration-target-profile.ts +0 -103
  228. package/server/engine/kpi-baseline.ts +0 -202
  229. package/server/engine/kpi-fold.ts +0 -1516
  230. package/server/engine/kpi-query.ts +0 -1210
  231. package/server/engine/kpi-target.ts +0 -248
  232. package/server/engine/live-attentions.ts +0 -30
  233. package/server/engine/live-feed-registry.ts +0 -59
  234. package/server/engine/load-meter.ts +0 -393
  235. package/server/engine/local-declarations.ts +0 -779
  236. package/server/engine/log.ts +0 -72
  237. package/server/engine/loop-lag.ts +0 -120
  238. package/server/engine/measured-estimator.ts +0 -91
  239. package/server/engine/measured-yield.ts +0 -89
  240. package/server/engine/model-basis.ts +0 -162
  241. package/server/engine/model-gap.ts +0 -168
  242. package/server/engine/model-refusal.ts +0 -31
  243. package/server/engine/model-vocabulary.ts +0 -82
  244. package/server/engine/oee-accumulator.ts +0 -195
  245. package/server/engine/operation-basis.ts +0 -131
  246. package/server/engine/producer-guard.ts +0 -64
  247. package/server/engine/property-effects.ts +0 -216
  248. package/server/engine/read-time.ts +0 -77
  249. package/server/engine/restart-policy.ts +0 -55
  250. package/server/engine/runtime-key.ts +0 -58
  251. package/server/engine/spec-coverage.ts +0 -105
  252. package/server/engine/stage-path.ts +0 -172
  253. package/server/engine/state-axes.ts +0 -60
  254. package/server/engine/structure-diff.ts +0 -88
  255. package/server/engine/travel-estimator.ts +0 -138
  256. package/server/engine/twin-engine.ts +0 -4979
  257. package/server/engine/twin-state-channel.ts +0 -39
  258. package/server/engine/warm-start.ts +0 -265
  259. package/server/index.ts +0 -90
  260. package/server/migrations/1786000000000-RenameTwinInstanceBoardToModel.ts +0 -43
  261. package/server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.ts +0 -54
  262. package/server/migrations/1786200000000-CarryLiveFeedCursor.ts +0 -53
  263. package/server/migrations/1786300000000-IndexEventTypeByTime.ts +0 -48
  264. package/server/migrations/1786400000000-IndexEventCreatedAt.ts +0 -38
  265. package/server/migrations/1786500000000-CreateTwinSubjectEvents.ts +0 -93
  266. package/server/migrations/1786600000000-RenameOperatoMesAdapterType.ts +0 -66
  267. package/server/migrations/1786700000000-AddDispatchRetryColumns.ts +0 -82
  268. package/server/migrations/1786800000000-CreateTwinReferenceReconciliations.ts +0 -39
  269. package/server/migrations/index.ts +0 -25
  270. package/server/routes.ts +0 -75
  271. package/server/service/actuation/actuation-advisor.ts +0 -131
  272. package/server/service/actuation/actuation-outcome.ts +0 -97
  273. package/server/service/actuation/actuation-rule-resolver.ts +0 -147
  274. package/server/service/actuation/actuation-rule.ts +0 -139
  275. package/server/service/actuation/approval-gateway.ts +0 -44
  276. package/server/service/actuation/catch-up-effects.ts +0 -152
  277. package/server/service/actuation/command-dispatcher.ts +0 -474
  278. package/server/service/actuation/command-store.ts +0 -236
  279. package/server/service/actuation/dispatch-after-approval.ts +0 -71
  280. package/server/service/actuation/effect-match.ts +0 -124
  281. package/server/service/actuation/index.ts +0 -27
  282. package/server/service/actuation/retry-plan.ts +0 -145
  283. package/server/service/actuation/rule-evaluate.ts +0 -352
  284. package/server/service/actuation/rule-loop.ts +0 -160
  285. package/server/service/actuation/rule-runner.ts +0 -216
  286. package/server/service/actuation/rule-wiring.ts +0 -84
  287. package/server/service/actuation/settle-effects.ts +0 -115
  288. package/server/service/actuation/sweep-dispatch.ts +0 -179
  289. package/server/service/actuation/twin-command-resolver.ts +0 -387
  290. package/server/service/actuation/twin-command.ts +0 -232
  291. package/server/service/actuation/twin-now.ts +0 -97
  292. package/server/service/index.ts +0 -100
  293. package/server/service/reference/actuation-routing.ts +0 -192
  294. package/server/service/reference/actuation-target.ts +0 -163
  295. package/server/service/reference/actuation-verification.ts +0 -85
  296. package/server/service/reference/attention-lane.ts +0 -21
  297. package/server/service/reference/connection-portability-resolver.ts +0 -171
  298. package/server/service/reference/connection-portability.ts +0 -329
  299. package/server/service/reference/control-routing.ts +0 -62
  300. package/server/service/reference/discovery-result.ts +0 -95
  301. package/server/service/reference/fill-cadence.ts +0 -29
  302. package/server/service/reference/fill-dedupe.ts +0 -66
  303. package/server/service/reference/fill-loop.ts +0 -153
  304. package/server/service/reference/fill-span.ts +0 -31
  305. package/server/service/reference/hook-contract.ts +0 -364
  306. package/server/service/reference/hook-rejected.ts +0 -53
  307. package/server/service/reference/hook-store.ts +0 -28
  308. package/server/service/reference/index.ts +0 -18
  309. package/server/service/reference/ingest-space.ts +0 -104
  310. package/server/service/reference/knob-defaults.ts +0 -59
  311. package/server/service/reference/live-cadence.ts +0 -129
  312. package/server/service/reference/live-feed-lease.ts +0 -56
  313. package/server/service/reference/live-ingest.ts +0 -94
  314. package/server/service/reference/reference-adapter.ts +0 -985
  315. package/server/service/reference/reference-assessment.ts +0 -250
  316. package/server/service/reference/reference-fill-run.ts +0 -179
  317. package/server/service/reference/reference-fill.ts +0 -223
  318. package/server/service/reference/reference-hook.ts +0 -479
  319. package/server/service/reference/reference-link-groups.ts +0 -21
  320. package/server/service/reference/reference-links.ts +0 -77
  321. package/server/service/reference/reference-live.ts +0 -420
  322. package/server/service/reference/reference-master.ts +0 -999
  323. package/server/service/reference/reference-probe.ts +0 -264
  324. package/server/service/reference/reference-progress-channel.ts +0 -26
  325. package/server/service/reference/reference-progress-subscription.ts +0 -78
  326. package/server/service/reference/reference-progress.ts +0 -95
  327. package/server/service/reference/reference-reconciliation-query.ts +0 -28
  328. package/server/service/reference/reference-reconciliation-writer.ts +0 -38
  329. package/server/service/reference/reference-reconciliation.ts +0 -55
  330. package/server/service/reference/reference-registry.ts +0 -17
  331. package/server/service/reference/reference-resolver.ts +0 -969
  332. package/server/service/reference/template-registry.ts +0 -85
  333. package/server/service/reference/twin-reference-reconciliation.ts +0 -27
  334. package/server/service/reference/twin-reference.ts +0 -190
  335. package/server/service/twin-attention/index.ts +0 -3
  336. package/server/service/twin-attention/twin-attention-query.ts +0 -70
  337. package/server/service/twin-audit/command-audit.ts +0 -114
  338. package/server/service/twin-audit/index.ts +0 -5
  339. package/server/service/twin-audit/twin-audit-event.ts +0 -158
  340. package/server/service/twin-audit/twin-audit-query.ts +0 -72
  341. package/server/service/twin-backfill/backfill-period-facts.ts +0 -168
  342. package/server/service/twin-backfill/backfill-shape.ts +0 -86
  343. package/server/service/twin-backfill/index.ts +0 -3
  344. package/server/service/twin-backfill/twin-backfill-resolver.ts +0 -35
  345. package/server/service/twin-control/index.ts +0 -3
  346. package/server/service/twin-control/twin-control-mutation.ts +0 -150
  347. package/server/service/twin-event/index.ts +0 -3
  348. package/server/service/twin-event/journal-count.ts +0 -53
  349. package/server/service/twin-event/twin-event-keys.ts +0 -215
  350. package/server/service/twin-event/twin-event-type.ts +0 -68
  351. package/server/service/twin-event/twin-event.ts +0 -250
  352. package/server/service/twin-forecast/forecast-metrics.ts +0 -106
  353. package/server/service/twin-forecast/forecast-tuning.ts +0 -40
  354. package/server/service/twin-forecast/gap-analytics.ts +0 -139
  355. package/server/service/twin-forecast/index.ts +0 -3
  356. package/server/service/twin-forecast/twin-forecast-query.ts +0 -486
  357. package/server/service/twin-ingest-window/index.ts +0 -7
  358. package/server/service/twin-ingest-window/twin-ingest-window-query.ts +0 -125
  359. package/server/service/twin-ingest-window/twin-ingest-window-writer.ts +0 -57
  360. package/server/service/twin-ingest-window/twin-ingest-window.ts +0 -113
  361. package/server/service/twin-instance/index.ts +0 -3
  362. package/server/service/twin-instance/twin-instance.ts +0 -199
  363. package/server/service/twin-journal/event-type-split-shape.ts +0 -112
  364. package/server/service/twin-journal/event-type-split.ts +0 -144
  365. package/server/service/twin-journal/index.ts +0 -3
  366. package/server/service/twin-journal/journal-order.ts +0 -20
  367. package/server/service/twin-journal/twin-journal-query.ts +0 -615
  368. package/server/service/twin-lifecycle/domain-catalog.ts +0 -51
  369. package/server/service/twin-lifecycle/index.ts +0 -3
  370. package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +0 -285
  371. package/server/service/twin-metrics/index.ts +0 -3
  372. package/server/service/twin-metrics/twin-metrics-query.ts +0 -172
  373. package/server/service/twin-model/axis-journal-evidence.ts +0 -57
  374. package/server/service/twin-model/choose-recipe.ts +0 -31
  375. package/server/service/twin-model/epcis-coverage.ts +0 -251
  376. package/server/service/twin-model/external-resolver.ts +0 -173
  377. package/server/service/twin-model/iec61850-coverage.ts +0 -111
  378. package/server/service/twin-model/index.ts +0 -25
  379. package/server/service/twin-model/isa95-coverage.ts +0 -320
  380. package/server/service/twin-model/item-ref.ts +0 -80
  381. package/server/service/twin-model/name-index.ts +0 -94
  382. package/server/service/twin-model/project-structure.ts +0 -213
  383. package/server/service/twin-model/standard-coverage.ts +0 -35
  384. package/server/service/twin-model/status-tally.ts +0 -37
  385. package/server/service/twin-model/twin-equipment.ts +0 -191
  386. package/server/service/twin-model/twin-lineage-query.ts +0 -327
  387. package/server/service/twin-model/twin-location.ts +0 -147
  388. package/server/service/twin-model/twin-model-item-query.ts +0 -1029
  389. package/server/service/twin-model/twin-model-mutation.ts +0 -503
  390. package/server/service/twin-model/twin-model-query.ts +0 -792
  391. package/server/service/twin-model/twin-model-tree-query.ts +0 -211
  392. package/server/service/twin-model/twin-operation.ts +0 -157
  393. package/server/service/twin-readiness/index.ts +0 -3
  394. package/server/service/twin-readiness/twin-readiness-query.ts +0 -96
  395. package/server/service/twin-space/area-resolver.ts +0 -75
  396. package/server/service/twin-space/index.ts +0 -8
  397. package/server/service/twin-space/move-space.ts +0 -262
  398. package/server/service/twin-space/representation-role.ts +0 -15
  399. package/server/service/twin-space/space-integrity.ts +0 -293
  400. package/server/service/twin-space/twin-area.ts +0 -63
  401. package/server/service/twin-space/twin-space-area.ts +0 -66
  402. package/server/service/twin-space/twin-space-representation.ts +0 -99
  403. package/server/service/twin-space/twin-space-resolver.ts +0 -582
  404. package/server/service/twin-space/twin-space.ts +0 -148
  405. package/server/service/twin-state/index.ts +0 -3
  406. package/server/service/twin-state/twin-state-subscription.ts +0 -62
  407. package/server/service/twin-structure/index.ts +0 -3
  408. package/server/service/twin-structure/twin-structure.ts +0 -96
  409. package/server/service/twin-subject/event-subjects.ts +0 -162
  410. package/server/service/twin-subject/index.ts +0 -10
  411. package/server/service/twin-subject/item-resolver.ts +0 -92
  412. package/server/service/twin-subject/subject-query-shape.ts +0 -84
  413. package/server/service/twin-subject/twin-subject-backfill.ts +0 -196
  414. package/server/service/twin-subject/twin-subject-event.ts +0 -101
  415. package/server/service/twin-subject/twin-subject-fast-path.ts +0 -346
  416. package/server/service/twin-subject/twin-subject-query.ts +0 -210
  417. package/server/service/twin-subject/twin-subject-writer.ts +0 -189
  418. package/server/service/twin-target/index.ts +0 -5
  419. package/server/service/twin-target/twin-target-resolver.ts +0 -142
  420. package/server/service/twin-target/twin-target.ts +0 -97
  421. package/server/types/global.d.ts +0 -22
  422. package/shared/axis-read.ts +0 -28
  423. package/shared/entity-delta.ts +0 -335
  424. package/shared/kpi-broadcast.ts +0 -13
  425. package/shared/touched-items.ts +0 -73
  426. package/shared/twin-level.ts +0 -48
  427. package/test/ack-shape-alignment.test.ts +0 -97
  428. package/test/actuation-advisor.test.ts +0 -55
  429. package/test/actuation-approval-door.test.ts +0 -411
  430. package/test/actuation-dispatch.test.ts +0 -209
  431. package/test/actuation-effect.test.ts +0 -162
  432. package/test/actuation-outcome.test.ts +0 -152
  433. package/test/actuation-rule-runner.test.ts +0 -281
  434. package/test/actuation-rule.test.ts +0 -266
  435. package/test/actuation-seam.test.ts +0 -255
  436. package/test/actuation-settle.test.ts +0 -164
  437. package/test/actuation-target.test.ts +0 -145
  438. package/test/actuation-verification-state.test.ts +0 -139
  439. package/test/adopt-structure-live.test.ts +0 -133
  440. package/test/aggregate-not-findone.test.ts +0 -112
  441. package/test/area-resolver-db.test.ts +0 -110
  442. package/test/attention-digest.test.ts +0 -161
  443. package/test/axis-declaration-passthrough-db.test.ts +0 -152
  444. package/test/axis-journal-evidence.test.ts +0 -71
  445. package/test/axis-read.test.ts +0 -188
  446. package/test/backfill-shape.test.ts +0 -89
  447. package/test/boot-resume.test.ts +0 -287
  448. package/test/broadcast-cost-baseline.test.ts +0 -201
  449. package/test/broadcast-period.test.ts +0 -58
  450. package/test/broadcast-queue-overflow.test.ts +0 -244
  451. package/test/canonical-ingest-vocabularies.test.ts +0 -451
  452. package/test/canonical-quantity-door.test.ts +0 -61
  453. package/test/capability-mapping.test.ts +0 -89
  454. package/test/checkpoint-refuses-empty.test.ts +0 -103
  455. package/test/choose-recipe.test.ts +0 -117
  456. package/test/column-type-portability.test.ts +0 -122
  457. package/test/command-routing.test.ts +0 -61
  458. package/test/command-store-writes-columns.test.ts +0 -126
  459. package/test/connection-portability-doors.test.ts +0 -87
  460. package/test/connector-capability-declaration.test.ts +0 -195
  461. package/test/contract-layer-guard.test.ts +0 -48
  462. package/test/control-capability.test.ts +0 -98
  463. package/test/cursor-stall-not-read-failure.test.ts +0 -126
  464. package/test/declaration-reaches-model.test.ts +0 -226
  465. package/test/declared-location-types.test.ts +0 -89
  466. package/test/declared-stimulus.test.ts +0 -88
  467. package/test/dedupe-transformation.test.ts +0 -112
  468. package/test/discovery-result.test.ts +0 -75
  469. package/test/dispatch-after-approval-source.test.ts +0 -81
  470. package/test/duration-estimators.test.ts +0 -144
  471. package/test/energy-topology.test.ts +0 -113
  472. package/test/entity-delta.test.ts +0 -352
  473. package/test/equipment-identity-reaches.test.ts +0 -57
  474. package/test/event-subjects.test.ts +0 -148
  475. package/test/event-time-column.test.ts +0 -67
  476. package/test/event-type-split.test.ts +0 -178
  477. package/test/external-resolver.test.ts +0 -177
  478. package/test/fact-scope-wiring.test.ts +0 -96
  479. package/test/fill-dedupe.test.ts +0 -59
  480. package/test/fill-loop.test.ts +0 -35
  481. package/test/first-envelope.test.ts +0 -153
  482. package/test/fold-gap-speaks.test.ts +0 -53
  483. package/test/fold-shift-dst.test.ts +0 -110
  484. package/test/forecast-metrics.test.ts +0 -157
  485. package/test/forecast-tuning.test.ts +0 -42
  486. package/test/gap-analytics.test.ts +0 -113
  487. package/test/generated-not-counted.test.ts +0 -99
  488. package/test/guard-roots.ts +0 -76
  489. package/test/home-in-area.test.ts +0 -90
  490. package/test/hook-address.test.ts +0 -28
  491. package/test/hook-rejected-shape.test.ts +0 -86
  492. package/test/hook-response-sum.test.ts +0 -193
  493. package/test/hook-sequence.test.ts +0 -333
  494. package/test/ingest-bench.test.ts +0 -70
  495. package/test/ingest-dedupe.test.ts +0 -56
  496. package/test/ingest-expected-quiet.test.ts +0 -111
  497. package/test/ingest-health-engine.test.ts +0 -248
  498. package/test/ingest-health-wiring.test.ts +0 -120
  499. package/test/ingest-health.test.ts +0 -306
  500. package/test/ingest-history.test.ts +0 -247
  501. package/test/ingest-idempotent.test.ts +0 -211
  502. package/test/ingest-reconcile-four-ways.test.ts +0 -97
  503. package/test/ingest-rules-header.test.ts +0 -100
  504. package/test/ingest-running-guard.test.ts +0 -136
  505. package/test/ingest-space.test.ts +0 -78
  506. package/test/ingest-window-rolls-unobserved.test.ts +0 -72
  507. package/test/ingest-wiring-guard.test.ts +0 -197
  508. package/test/instance-cache-lifecycle.test.ts +0 -110
  509. package/test/intake-mapping-parity.test.ts +0 -175
  510. package/test/integration-probes.test.ts +0 -103
  511. package/test/integration-runner.test.ts +0 -95
  512. package/test/item-ref.test.ts +0 -78
  513. package/test/journal-order-axis.test.ts +0 -80
  514. package/test/journal-read-discipline.test.ts +0 -186
  515. package/test/journal-retention.test.ts +0 -275
  516. package/test/journal-sort-axis.test.ts +0 -142
  517. package/test/journal-write-door.test.ts +0 -110
  518. package/test/journal-write-trend.test.ts +0 -115
  519. package/test/kernel-kind-guard.test.ts +0 -98
  520. package/test/knob-defaults.test.ts +0 -72
  521. package/test/kpi-baseline-db.test.ts +0 -216
  522. package/test/kpi-baseline.test.ts +0 -196
  523. package/test/kpi-fold.test.ts +0 -1456
  524. package/test/kpi-query-bench.test.ts +0 -130
  525. package/test/lens-own-places.test.ts +0 -50
  526. package/test/lineage-survives-restart.test.ts +0 -234
  527. package/test/live-cadence.test.ts +0 -170
  528. package/test/live-cursor-wiring.test.ts +0 -87
  529. package/test/live-feed-lease.test.ts +0 -63
  530. package/test/live-feed-registry.test.ts +0 -75
  531. package/test/live-kernel-facts.test.ts +0 -161
  532. package/test/live-mirror-parity.test.ts +0 -286
  533. package/test/load-meter.test.ts +0 -328
  534. package/test/local-declarations.test.ts +0 -662
  535. package/test/log-stamp.test.ts +0 -59
  536. package/test/loop-lag.test.ts +0 -82
  537. package/test/master-to-twin.test.ts +0 -279
  538. package/test/measured-yield.test.ts +0 -90
  539. package/test/merge-streams.test.ts +0 -70
  540. package/test/mirror-resumes-from-checkpoint.test.ts +0 -192
  541. package/test/model-basis.test.ts +0 -141
  542. package/test/model-gap.test.ts +0 -153
  543. package/test/model-refusal.test.ts +0 -75
  544. package/test/model-vocabulary.test.ts +0 -114
  545. package/test/move-space.test.ts +0 -149
  546. package/test/mutation-gate.test.ts +0 -122
  547. package/test/oee-accumulator.test.ts +0 -204
  548. package/test/oee-site-calendar.test.ts +0 -146
  549. package/test/open-doors.test.ts +0 -197
  550. package/test/operation-basis.test.ts +0 -127
  551. package/test/operational-vocabulary.test.ts +0 -108
  552. package/test/operations-capability-db.test.ts +0 -165
  553. package/test/order-and-transaction-split.test.ts +0 -107
  554. package/test/order-fold-host.test.ts +0 -112
  555. package/test/producer-guard.test.ts +0 -66
  556. package/test/project-structure-db.test.ts +0 -226
  557. package/test/projection-reaches-screen.test.ts +0 -277
  558. package/test/projection-reads-declared.test.ts +0 -109
  559. package/test/property-effects.test.ts +0 -128
  560. package/test/provenance-promotion.test.ts +0 -99
  561. package/test/read-failure-ledger.test.ts +0 -106
  562. package/test/read-failure-visible.test.ts +0 -145
  563. package/test/read-time.test.ts +0 -118
  564. package/test/reference-fill.test.ts +0 -235
  565. package/test/reference-grounding.test.ts +0 -70
  566. package/test/reference-hook.test.ts +0 -177
  567. package/test/reference-links.test.ts +0 -56
  568. package/test/reference-reconciliation.test.ts +0 -39
  569. package/test/registry-key-guard.test.ts +0 -80
  570. package/test/rejection-carries-event-id.test.ts +0 -101
  571. package/test/rename-twin.test.ts +0 -89
  572. package/test/resolve-ts-siblings.mjs +0 -52
  573. package/test/restart-policy.test.ts +0 -111
  574. package/test/resync-origin-site.test.ts +0 -83
  575. package/test/retry-plan.test.ts +0 -139
  576. package/test/revision-axis.test.ts +0 -110
  577. package/test/runtime-key.test.ts +0 -66
  578. package/test/save-intake-collision.test.ts +0 -91
  579. package/test/scale-twin-bench.test.ts +0 -103
  580. package/test/secrets-at-rest.test.ts +0 -135
  581. package/test/snapshot-freshness.test.ts +0 -60
  582. package/test/source-outcome-audit.test.ts +0 -104
  583. package/test/space-integrity.test.ts +0 -223
  584. package/test/space-representation.test.ts +0 -66
  585. package/test/space-scope-includes-stopped.test.ts +0 -55
  586. package/test/spec-coverage.test.ts +0 -113
  587. package/test/stage-path.test.ts +0 -95
  588. package/test/standard-coverage.test.ts +0 -148
  589. package/test/state-axes.test.ts +0 -74
  590. package/test/status-tally.test.ts +0 -55
  591. package/test/streamline-e2e.test.ts +0 -76
  592. package/test/structure-revision-db.test.ts +0 -315
  593. package/test/subject-fast-path.test.ts +0 -148
  594. package/test/subject-read-model.test.ts +0 -175
  595. package/test/sweep-dispatch.test.ts +0 -191
  596. package/test/tenant-registry-db.test.ts +0 -149
  597. package/test/time-range.test.ts +0 -152
  598. package/test/touched-items.test.ts +0 -61
  599. package/test/twin-audit.test.ts +0 -83
  600. package/test/twin-event-keys.test.ts +0 -193
  601. package/test/twin-model-item-db.test.ts +0 -319
  602. package/test/twin-model-parent-relation-db.test.ts +0 -125
  603. package/test/twin-model-tree-db.test.ts +0 -209
  604. package/test/twin-origin-resync.test.ts +0 -133
  605. package/test/twin-state-channel.test.ts +0 -111
  606. package/test/vocabulary-guard.test.ts +0 -43
  607. package/test/warm-start-seam.test.ts +0 -162
  608. package/test/warm-start.test.ts +0 -297
  609. package/test/withheld-door.test.ts +0 -95
  610. package/test/yield-loop.test.ts +0 -199
  611. package/tsconfig.json +0 -15
  612. package/tsconfig.shared.json +0 -23
  613. package/tsconfig.shared.tsbuildinfo +0 -1
  614. package/tsconfig.tsbuildinfo +0 -1
@@ -1,247 +0,0 @@
1
- /*
2
- * ★ 인제스트 이력 — **재기동 뒤에도 추이가 이어진다.**
3
- *
4
- * ── 무엇이 미완이었나 (2026-08-20) ──────────────────────────────────────────
5
- * 닫힌 창을 표로 남기기 시작했는데 **읽는 코드가 없었다.** 21행이 쌓여 있고 아무도 보지 않았다 —
6
- * 이 프로젝트가 결함으로 보는 상태다(「필드만 만들고 아무도 읽지 않는다」). 표를 만든 이유가
7
- * 「메모리 장부는 재기동에 사라지고 6시간까지인데 추이는 그보다 오래 봐야 한다」였으니 목적이
8
- * 절반만 서 있었다.
9
- *
10
- * ── 지키는 것 ───────────────────────────────────────────────────────────────
11
- * ① 표와 메모리를 이어 붙이되 **겹친 창을 두 번 내지 않는다** — 같은 구간이 두 번 그려지면 추이가
12
- * 거짓이 된다. 겹치면 메모리 쪽을 쓴다(같은 사실의 원본이다).
13
- * ② 어디서부터 메모리인지 밝힌다(`liveFrom`) — 화면이 근거를 말할 수 있게. 재기동 직후에는 `null`
14
- * 이고, 그때 보이는 것은 전부 표에서 온 것이다.
15
- * ③ **알리지 않고 자르지 않는다** — 상한에서 밀려난 창 수와, 물은 기간이 잘렸다는 사실을 함께 낸다.
16
- * ④ 남의 도메인·남의 트윈의 창을 집지 않는다.
17
- * ⑤ 제시가 0 인 창의 통과율은 `null` 이다 — 빈 창은 완벽한 창이 아니다.
18
- */
19
- import { test, before, after } from 'node:test'
20
- import assert from 'node:assert/strict'
21
- import { createRequire } from 'node:module'
22
- import type { DataSource } from 'typeorm'
23
-
24
- const req = createRequire(import.meta.url)
25
- const { NamingStrategy, addDataSource, entities: shellEntities, Domain } = req('@things-factory/shell')
26
- const { entities: authEntities } = req('@things-factory/auth-base')
27
- const { entities: twinEntities } = req('../dist-server/service/index.js')
28
- const { TwinEngine } = req('../dist-server/engine/index.js')
29
- const { INGEST_WINDOW_MS } = req('../dist-server/engine/ingest-health.js')
30
- const { TwinIngestWindow } = req('../dist-server/service/twin-ingest-window/twin-ingest-window.js')
31
- const { TwinIngestWindowQuery, HISTORY_WINDOW_LIMIT, HISTORY_HOURS_MAX } = req(
32
- '../dist-server/service/twin-ingest-window/twin-ingest-window-query.js'
33
- )
34
- const { TwinInstance } = req('../dist-server/service/twin-instance/twin-instance.js')
35
- const { DataSource: TypeOrmDataSource } = req('typeorm')
36
-
37
- let ds: DataSource
38
- let domainId: string
39
- let otherDomainId: string
40
-
41
- const TWIN = 'hist-twin'
42
- const HOUR = 3_600_000
43
-
44
- const resolver = new TwinIngestWindowQuery()
45
- const ask = (instanceId: string, hours?: number, domain = domainId) =>
46
- resolver.twinIngestHistory(instanceId, hours, { state: { domain: { id: domain } } } as any)
47
-
48
- /** 표에 닫힌 창 하나 — 시각은 「몇 시간 전」으로 준다. */
49
- async function storedWindow(instanceId: string, hoursAgo: number, offered: number, rejected = 0, domain = domainId) {
50
- const closed = new Date(Date.now() - hoursAgo * HOUR)
51
- const opened = new Date(closed.getTime() - 600_000)
52
- const repo = ds.getRepository(TwinIngestWindow)
53
- await repo.save(
54
- repo.create({
55
- domain: { id: domain } as any,
56
- instanceId,
57
- openedAt: opened,
58
- closedAt: closed,
59
- offered,
60
- rejected,
61
- undelivered: 0,
62
- journaledRows: 0,
63
- journalFlushes: 0,
64
- ...(offered > 0 ? { acceptedRatio: (offered - rejected) / offered } : {})
65
- } as any)
66
- )
67
- return opened.toISOString()
68
- }
69
-
70
- async function instance(instanceId: string, domain = domainId) {
71
- const repo = ds.getRepository(TwinInstance)
72
- await repo.save(
73
- repo.create({
74
- domain: { id: domain } as any,
75
- instanceId,
76
- spaceId: 'hist-space',
77
- kind: 'wms',
78
- status: 'stopped',
79
- restartPolicy: 'reset',
80
- purpose: 'operational'
81
- } as any)
82
- )
83
- }
84
-
85
- before(async () => {
86
- ds = new TypeOrmDataSource({
87
- type: 'sqlite',
88
- database: ':memory:',
89
- synchronize: true,
90
- dropSchema: true,
91
- namingStrategy: new NamingStrategy(),
92
- entities: [...shellEntities, ...authEntities, ...twinEntities],
93
- logging: false
94
- })
95
- await ds.initialize()
96
- addDataSource('default', ds)
97
-
98
- domainId = (await ds.getRepository(Domain).save({ name: 'hist', subdomain: 'hist' } as any)).id
99
- otherDomainId = (await ds.getRepository(Domain).save({ name: 'hist-other', subdomain: 'hist-other' } as any)).id
100
- await instance(TWIN)
101
- })
102
-
103
- after(async () => {
104
- await ds?.destroy()
105
- })
106
-
107
- test('표에 남은 창을 읽어 온다 — 재기동으로 메모리가 비어도 추이가 있다', async () => {
108
- await storedWindow(TWIN, 5, 100, 4)
109
- await storedWindow(TWIN, 3, 200, 0)
110
-
111
- const r = await ask(TWIN)
112
- assert.equal(r.windows.length, 2)
113
- assert.equal(r.storedCount, 2)
114
- assert.equal(r.liveCount, 0, '메모리에는 닫힌 창이 없다(이 트윈은 이 프로세스에서 받은 적이 없다)')
115
- assert.equal(r.liveFrom, null, '그래서 「여기서부터 메모리」가 없다 — 0 이나 지금으로 채우지 않는다')
116
- })
117
-
118
- test('오래된 것이 앞, 최신이 뒤 — 추이는 시간순이어야 그림이 된다', async () => {
119
- const r = await ask(TWIN)
120
- const times = r.windows.map((w: any) => Date.parse(w.from))
121
- assert.deepEqual(times, [...times].sort((a, b) => a - b), '오름차순')
122
- })
123
-
124
- test('통과는 트윈에 닿은 것만 — 표의 통과율을 그대로 쓴다', async () => {
125
- const r = await ask(TWIN)
126
- const w = r.windows.find((x: any) => x.offered === 100)
127
- assert.equal(w.rejected, 4)
128
- assert.equal(w.accepted, 96)
129
- assert.equal(w.acceptedRatio, 0.96)
130
- })
131
-
132
- test('제시가 0 인 창의 통과율은 「없음」이다 — 빈 창은 완벽한 창이 아니다', async () => {
133
- await storedWindow(TWIN, 2, 0, 0)
134
-
135
- const r = await ask(TWIN)
136
- const empty = r.windows.find((x: any) => x.offered === 0)
137
- assert.equal(empty.acceptedRatio, null)
138
- })
139
-
140
- test('물은 기간 밖의 창은 오지 않는다', async () => {
141
- await storedWindow(TWIN, 40, 999, 0) // 40시간 전
142
-
143
- const r = await ask(TWIN, 24)
144
- assert.ok(
145
- !r.windows.some((w: any) => w.offered === 999),
146
- '24시간을 물었으면 40시간 전 창은 안 온다'
147
- )
148
-
149
- const wide = await ask(TWIN, 48)
150
- assert.ok(
151
- wide.windows.some((w: any) => w.offered === 999),
152
- '48시간을 물으면 온다'
153
- )
154
- })
155
-
156
- test('기간 상한을 넘겨 물으면 자르고, 자른 사실을 낸다', async () => {
157
- const r = await ask(TWIN, HISTORY_HOURS_MAX + 100)
158
-
159
- assert.equal(r.hours, HISTORY_HOURS_MAX, '상한까지만 본다')
160
- assert.equal(r.hoursClamped, HISTORY_HOURS_MAX + 100, '얼마를 물었는지 밝힌다 — 알리지 않고 자르지 않는다')
161
- })
162
-
163
- test('상한 안에서는 잘렸다고 말하지 않는다 — 없는 문제를 만들지 않는다', async () => {
164
- const r = await ask(TWIN, 24)
165
- assert.equal(r.hoursClamped, undefined)
166
- assert.equal(r.storedDropped, 0)
167
- })
168
-
169
- test('창 수 상한에서 밀려난 수를 센다', async () => {
170
- const many = 'hist-many'
171
- await instance(many)
172
- /* 상한 + 5개를 심는다. 10분 간격이므로 상한을 넘기려면 그만큼의 창이 필요하다. */
173
- for (let i = 0; i < HISTORY_WINDOW_LIMIT + 5; i++) await storedWindow(many, 1 + i * 0.01, 10, 0)
174
-
175
- const r = await ask(many, HISTORY_HOURS_MAX)
176
- assert.equal(r.windows.length, HISTORY_WINDOW_LIMIT, '상한까지만 낸다')
177
- assert.equal(r.storedDropped, 5, '밀려난 수를 말한다')
178
- })
179
-
180
- test('남의 도메인 창을 집지 않는다', async () => {
181
- await instance('hist-shared', otherDomainId)
182
- await storedWindow('hist-shared', 1, 777, 0, otherDomainId)
183
-
184
- /* 같은 instanceId 를 내 도메인에서 물어도 남의 창이 오면 안 된다. */
185
- await instance('hist-shared')
186
- const mine = await ask('hist-shared')
187
- assert.ok(
188
- !mine.windows.some((w: any) => w.offered === 777),
189
- '남의 도메인 창이 새지 않는다'
190
- )
191
- })
192
-
193
- test('내 도메인에 없는 트윈은 「없음」이다 — 남의 것이라 말하지 않는다', async () => {
194
- assert.equal(await ask('does-not-exist'), null)
195
- })
196
-
197
- test('겹친 창을 두 번 내지 않는다 — 같은 구간이 두 번 그려지면 추이가 거짓이 된다', async () => {
198
- /*
199
- * 프로세스가 살아 있는 동안 닫힌 창은 **표와 메모리에 둘 다** 있다(영속 훅이 창이 닫힐 때 쓴다).
200
- * 정리하지 않으면 그 구간이 추이에 두 번 들어가 유입이 두 배로 보인다.
201
- */
202
- const twin = 'hist-overlap'
203
- await instance(twin)
204
-
205
- /* 메모리에 닫힌 창 하나를 만든다 — 창은 다음 유입이 있을 때 닫힌다. */
206
- const t0 = Date.now() - Math.floor(INGEST_WINDOW_MS * 1.4)
207
- TwinEngine.recordIngestResult(domainId, twin, 50, [], t0)
208
- TwinEngine.recordIngestResult(domainId, twin, 1, [], t0 + INGEST_WINDOW_MS + 1)
209
-
210
- const live = TwinEngine.ingestHealthOf(domainId, twin).trend
211
- assert.equal(live.length, 1, '메모리에 닫힌 창 하나')
212
-
213
- /* 같은 창을 표에도 심는다(영속 훅이 했을 일). 값은 일부러 다르게 두어 어느 쪽이 이겼는지 본다. */
214
- const repo = ds.getRepository(TwinIngestWindow)
215
- await repo.save(
216
- repo.create({
217
- domain: { id: domainId } as any,
218
- instanceId: twin,
219
- openedAt: new Date(Date.parse(live[0].from)),
220
- closedAt: new Date(Date.parse(live[0].to)),
221
- offered: 999,
222
- rejected: 0,
223
- undelivered: 0,
224
- journaledRows: 0,
225
- journalFlushes: 0,
226
- acceptedRatio: 1
227
- } as any)
228
- )
229
-
230
- const r = await ask(twin)
231
- const sameStart = r.windows.filter((w: any) => Date.parse(w.from) === Date.parse(live[0].from))
232
- assert.equal(sameStart.length, 1, '한 번만 낸다')
233
- assert.equal(sameStart[0].source, 'live', '겹치면 메모리 쪽 — 같은 사실의 원본이다')
234
- assert.equal(sameStart[0].offered, 50, '표의 999 가 아니라 메모리의 50')
235
- assert.equal(r.liveFrom, live[0].from, '어디서부터 메모리인지 밝힌다')
236
- })
237
-
238
- test('겹치지 않는 표의 창은 메모리 앞에 이어 붙는다', async () => {
239
- const twin = 'hist-overlap'
240
- /* 메모리 창보다 오래된 것 — 이건 표에서만 온다. */
241
- await storedWindow(twin, 6, 30, 1)
242
-
243
- const r = await ask(twin)
244
- assert.equal(r.windows.length, 2, '표 하나 + 메모리 하나')
245
- assert.equal(r.windows[0].source, 'stored', '오래된 것이 앞')
246
- assert.equal(r.windows[1].source, 'live')
247
- })
@@ -1,211 +0,0 @@
1
- /*
2
- * ★ 같은 사실을 두 번 받으면 한 번만 반영한다.
3
- *
4
- * ── 왜 이것이 핵심인가 (2026-08-26 · 사용자) ─────────────────────────────────
5
- * 「웹훅 이벤트이건 폴링 데이터이건 아이뎀포턴트를 유지할 수 있도록 로직을 세우는 것」이 핵심이다.
6
- * 그것이 서면 가져오는 방식이 무엇이든 트윈이 안전하고, 커넥터마다 각자 조심하지 않아도 된다.
7
- *
8
- * ── 무엇이 났나 ─────────────────────────────────────────────────────────────
9
- * 지금까지 중복은 커넥터마다 각자 막았다. 태양광 커넥터가 10초마다 물으면서 10분마다 바뀌는 값을 매번
10
- * 다시 보냈고, 한 주기에 76건이 되풀이됐다(커넥터를 고쳐 2건이 됐다). 다음 커넥터가 잊으면 또 난다.
11
- * 밀어 주는 방식으로 받으면 더 자주 난다 — 재전송이 정상이다.
12
- *
13
- * ── 정체를 무엇으로 보나 ────────────────────────────────────────────────────
14
- * 봉투의 `eventId` 로는 판단할 수 없다. 보낸 쪽이 매번 새로 만드는 순번이고, 호출마다 1부터 다시
15
- * 시작한다. 그래서 사실 자체로 판단한다 — 대상 · 사건 종류 · 연결된 시스템이 준 시각.
16
- */
17
- import { test } from 'node:test'
18
- import assert from 'node:assert/strict'
19
- import { factIdentity, FactDeduper } from '../server/engine/ingest-dedupe.js'
20
-
21
- const at = '2026-08-26T00:00:00.000Z'
22
-
23
- const energy = (equipmentId: string, kWh: number, when = at, eventId = 'x') => ({
24
- eventId,
25
- eventType: 'energy.generated',
26
- eventTime: when,
27
- tenantId: 't',
28
- data: { equipmentId, kWh, at: when }
29
- })
30
-
31
- const status = (moverId: string, s: string, when = at) => ({
32
- eventId: `s-${moverId}`,
33
- eventType: 'equipment.status',
34
- eventTime: when,
35
- tenantId: 't',
36
- data: { moverId, kind: 'pv-array', status: s, at: when }
37
- })
38
-
39
- test('★ 같은 사실이 두 번 오면 한 번만 지난다 — 보낸 쪽이 되풀이 보내도 트윈이 틀리지 않는다', () => {
40
- const d = new FactDeduper()
41
- const { fresh, duplicates } = d.filter([energy('inv-1', 574.8), energy('inv-1', 574.8)])
42
- assert.equal(fresh.length, 1)
43
- assert.equal(duplicates, 1)
44
- })
45
-
46
- test('★ 봉투의 순번이 달라도 같은 사실이면 한 번이다 — eventId 로는 판단할 수 없다', () => {
47
- /* 같은 측정을 두 번 보내면 보낸 쪽이 새 순번을 붙인다. 그것으로 판단하면 중복을 못 잡는다. */
48
- const d = new FactDeduper()
49
- const { fresh, duplicates } = d.filter([energy('inv-1', 574.8, at, 't-energy-1'), energy('inv-1', 574.8, at, 't-energy-2')])
50
- assert.equal(fresh.length, 1)
51
- assert.equal(duplicates, 1)
52
- })
53
-
54
- test('★ 다른 사실은 지난다 — 대상이 다르면 다른 사실이다', () => {
55
- const d = new FactDeduper()
56
- const { fresh, duplicates } = d.filter([energy('inv-1', 574.8), energy('inv-2', 577.2)])
57
- assert.equal(fresh.length, 2)
58
- assert.equal(duplicates, 0)
59
- })
60
-
61
- test('★ 잰 시각이 나아가면 다른 사실이다 — 그것이 새 측정이다', () => {
62
- const d = new FactDeduper()
63
- const { fresh } = d.filter([energy('inv-1', 574.8, at), energy('inv-1', 580.1, '2026-08-26T00:10:00.000Z')])
64
- assert.equal(fresh.length, 2)
65
- })
66
-
67
- test('★ 사건 종류가 다르면 다른 사실이다 — 같은 설비의 같은 시각이어도', () => {
68
- const d = new FactDeduper()
69
- const { fresh } = d.filter([energy('inv-1', 574.8), status('inv-1', 'busy')])
70
- assert.equal(fresh.length, 2)
71
- })
72
-
73
- test('★ 정체를 알 수 없으면 거르지 않는다 — 모르는 것을 같다고 하면 다른 사실이 하나로 합쳐진다', () => {
74
- const d = new FactDeduper()
75
- const noTarget = { eventId: 'a', eventType: 'energy.demand.window', eventTime: at, tenantId: 't', data: { maxKW: 3 } }
76
- const noTime = { eventId: 'b', eventType: 'equipment.status', tenantId: 't', data: { moverId: 'inv-9', status: 'idle' } }
77
- assert.equal(factIdentity(noTarget), undefined)
78
- assert.equal(factIdentity(noTime), undefined)
79
- const { fresh, duplicates } = d.filter([noTarget, noTarget, noTime, noTime])
80
- assert.equal(fresh.length, 4, '거르지 않고 통과시킨다')
81
- assert.equal(duplicates, 0)
82
- })
83
-
84
- test('★ 늦게 도착한 옛 사실은 버리지 않는다 — 그것이 왔다는 것도 사실이다', () => {
85
- /*
86
- * 상태에 반영하지 않는 판단은 커널이 한다(시각 비교). 여기서 버리면 지난 기록에서 사라지고,
87
- * 「늦게 왔다」는 사실 자체를 아무도 알 수 없게 된다.
88
- */
89
- const d = new FactDeduper()
90
- const { fresh, duplicates } = d.filter([
91
- energy('inv-1', 580.1, '2026-08-26T00:10:00.000Z'),
92
- energy('inv-1', 574.8, at)
93
- ])
94
- assert.equal(fresh.length, 2)
95
- assert.equal(duplicates, 0)
96
- })
97
-
98
- test('★ 창을 넘으면 잊는다 — 전부 기억할 수는 없다', () => {
99
- const window = FactDeduper.WINDOW
100
- try {
101
- FactDeduper.WINDOW = 3
102
- const d = new FactDeduper()
103
- d.filter([energy('inv-1', 1, '2026-08-26T00:00:00.000Z')])
104
- d.filter([
105
- energy('inv-1', 2, '2026-08-26T00:01:00.000Z'),
106
- energy('inv-1', 3, '2026-08-26T00:02:00.000Z'),
107
- energy('inv-1', 4, '2026-08-26T00:03:00.000Z')
108
- ])
109
- /* 첫 사실은 창 밖으로 밀려났으므로 다시 오면 통과한다 — 그 사실을 시험으로 못 박는다. */
110
- const { duplicates } = d.filter([energy('inv-1', 1, '2026-08-26T00:00:00.000Z')])
111
- assert.equal(duplicates, 0)
112
- assert.ok(d.size() <= 3)
113
- } finally {
114
- FactDeduper.WINDOW = window
115
- }
116
- })
117
-
118
- test('버린 수를 함께 낸다 — 알리지 않고 버리지 않는다', () => {
119
- const d = new FactDeduper()
120
- const same = [energy('inv-1', 1), energy('inv-1', 1), energy('inv-1', 1), energy('inv-2', 2)]
121
- const { fresh, duplicates } = d.filter(same)
122
- assert.equal(fresh.length, 2)
123
- assert.equal(duplicates, 2)
124
- })
125
-
126
- test('트윈마다 따로 센다 — 한 트윈의 되풀이가 다른 트윈을 막지 않는다', () => {
127
- const a = new FactDeduper()
128
- const b = new FactDeduper()
129
- a.filter([energy('inv-1', 1)])
130
- const { duplicates } = b.filter([energy('inv-1', 1)])
131
- assert.equal(duplicates, 0)
132
- })
133
-
134
- /* ════════════════════════════════════════════════════════════════════════════
135
- * ★ **구별할 값이 봉투 안에 있으면 다 본다** — 골라 쓰고 나머지를 버리던 자리.
136
- *
137
- * ── 실측 (2026-09-05, 인티그레이션·plant 레인) ─────────────────────────────
138
- * plant 이 실적 둘을 보냈는데 한 건이 저널에 안 남았다.
139
- *
140
- * seq 36 quality.output moverId EQ-CT-MWELD-01 · taskId PR-CT-WIRE-01 · goodCount 12
141
- * seq 41 quality.output moverId EQ-CT-MWELD-01 · taskId PR-CT-WIRE-02 · goodCount 9
142
- *
143
- * 시각이 같았고(원본이 끝시각을 복사) 대상을 **먼저 걸리는 하나**로 골라서 `moverId` 가 이겼다.
144
- * 거부가 아니라 **되풀이로 세어졌다** — 유입 장부에 `offered 5 · rejected 0 · journaled 3`.
145
- *
146
- * 원인이 시험 데이터였다고 해서 거동이 옳아지지 않는다. 두 봉투는 `taskId` 도 수량도 달랐고,
147
- * **구별할 값이 이미 봉투 안에 있었는데 판정이 그것을 안 봤다.**
148
- *
149
- * ── 이 파일이 스스로 적어 둔 값 ───────────────────────────────────────────
150
- * 「모르는 것을 같다고 판단하면 서로 다른 사실이 하나로 합쳐진다.
151
- * 알리지 않고 잃는 것보다 두 번 세는 것이 낫다.」
152
- *
153
- * 지금 거동은 **알리지 않고 잃는 쪽**이었다.
154
- * ════════════════════════════════════════════════════════════════════════════ */
155
-
156
- const AT_36 = '2026-09-05T06:50:00.000Z'
157
- const quality = (taskId: string, goodCount: number) => ({
158
- eventType: 'quality.output',
159
- data: { moverId: 'EQ-CT-MWELD-01', taskId, goodCount, at: AT_36 }
160
- })
161
-
162
- test('★ 한 설비가 두 작업을 같은 시각에 보고해도 두 사실이다 — 실제로 한 건을 잃던 그 줄', () => {
163
- const a = factIdentity(quality('PR-CT-WIRE-01', 12))
164
- const b = factIdentity(quality('PR-CT-WIRE-02', 9))
165
-
166
- assert.ok(a && b, '정체를 못 만들면 거르지 않는다 — 이 검사가 뜻이 없다')
167
- assert.notEqual(a, b, '작업이 다른 두 실적이 한 사실이 됐다')
168
- })
169
-
170
- test('★ 같은 봉투를 다시 보내면 여전히 같은 사실이다 — 넓혀도 되풀이는 잡힌다', () => {
171
- /*
172
- * 넓히는 것이 「되풀이를 놓친다」로 이어지지 않는다는 것이 이 변경의 근거다. 같은 봉투는 이
173
- * 값들이 전부 같으므로 정체도 같다.
174
- */
175
- assert.equal(factIdentity(quality('PR-CT-WIRE-01', 12)), factIdentity(quality('PR-CT-WIRE-01', 12)))
176
- })
177
-
178
- test('★ 한 개체의 서로 다른 관측을 가른다 — EPCIS 는 그것이 정상이다', () => {
179
- /*
180
- * 저널 246만 건에 옛 규칙을 다시 걸어 여섯 묶음이 나왔고 전부 이 모양이었다. 한 물건이 한
181
- * 순간에 입고이면서 개시일 수 있다 — 표준에서 이상한 일이 아닌데 규칙이 그 셋을 안 봤다.
182
- */
183
- const epc = 'urn:epc:id:sgtin:9521321.011111.1'
184
- const receiving = {
185
- eventType: 'epcis.ObjectEvent',
186
- data: { epcList: [epc], bizStep: 'receiving', action: 'ADD', disposition: 'sellable_accessible', eventTime: AT_36 }
187
- }
188
- const commissioning = {
189
- eventType: 'epcis.ObjectEvent',
190
- data: { epcList: [epc], bizStep: 'commissioning', action: 'OBSERVE', disposition: 'reserved', eventTime: AT_36 }
191
- }
192
-
193
- assert.notEqual(factIdentity(receiving), factIdentity(commissioning), '입고와 개시가 한 사실이 됐다')
194
- })
195
-
196
- test('★ 참조가 달라도 갈린다 — 주체만 보고 나머지를 버리지 않는다', () => {
197
- /*
198
- * 「주체를 먼저 본다」는 판단 자체는 옳았다. 틀린 것은 **고르고 나머지를 버린 것**이다.
199
- */
200
- const one = { eventType: 'task.status', data: { taskId: 'T-1', orderId: 'order-1', at: AT_36 } }
201
- const two = { eventType: 'task.status', data: { taskId: 'T-1', orderId: 'order-2', at: AT_36 } }
202
-
203
- assert.notEqual(factIdentity(one), factIdentity(two))
204
- })
205
-
206
- test('★ 이 검사가 실제로 무언가를 잰다 — 견준 것이 0이면 빨강', () => {
207
- /* 가르는 값이 하나도 없으면 정체를 안 만든다(거르지 않고 통과) — 그 경계가 살아 있는지. */
208
- assert.equal(factIdentity({ eventType: 'x', data: { at: AT_36 } }), undefined, '대상 없는 봉투에 정체를 만들었다')
209
- assert.equal(factIdentity({ eventType: 'x', data: { taskId: 'T-1' } }), undefined, '시각 없는 봉투에 정체를 만들었다')
210
- assert.ok(factIdentity(quality('T-1', 1))!.includes('task=T-1'), '작업이 정체에 안 들어갔다')
211
- })
@@ -1,97 +0,0 @@
1
- /*
2
- * ★ **셈이 닫혀야 한다** — 두 갈래로는 큰 수가 「사라졌다」로 떠 있게 된다.
3
- *
4
- * ── 실측 (2026-09-05, 인티그레이션·plant 레인) ─────────────────────────────
5
- * plant 아웃박스와 저널을 손으로 맞춰 보니 정확히 닫혔다.
6
- *
7
- * 나간 것 157 = 앉은 것 46 + 거절 2 + 어휘 1 + 되풀이 108
8
- *
9
- * 되풀이 108은 하네스가 같은 실적을 같은 시각으로 다시 보낸 것이고 **합친 것이 옳은 거동**이다.
10
- * 어휘 1은 저널에 안 가는 것이 옳다(시각축이 없다).
11
- *
12
- * ── 왜 두 갈래로는 안 되나 ────────────────────────────────────────────────
13
- * 두 갈래 157 − 46 − 2 = 109 「설명 못 함」
14
- * 네 갈래 157 − 46 − 2 − 108 − 1 = 0
15
- *
16
- * **109 를 「사라졌다」로 내면 그날부터 아무도 그 수를 안 본다.** 늘 큰 수가 떠 있으면 진짜로 하나
17
- * 사라진 날을 못 본다 — 오늘 이 저장소에서 「늘 참인 경고는 벽지가 된다」로 여러 번 나온 것이다.
18
- *
19
- * ── 그리고 되풀이 108은 잰 값이 아니었다 ──────────────────────────────────
20
- * 뺄셈으로만 구할 수 있었다. 어휘 항이 없어서다. 그 뺄셈을 코드가 하려면 넷이 다 있어야 한다.
21
- */
22
- import { test } from 'node:test'
23
- import assert from 'node:assert/strict'
24
-
25
- import {
26
- newIngestLedger,
27
- recordIngest,
28
- recordDuplicates,
29
- recordVocabulary,
30
- recordJournalWrite
31
- } from '../server/engine/ingest-health.js'
32
-
33
- const T0 = 1_757_000_000_000
34
-
35
- test('★ 넷을 다 세면 셈이 0으로 닫힌다 — 실측한 그 수로', () => {
36
- const ledger = newIngestLedger()
37
-
38
- /* 나간 것 157 · 거절 2 */
39
- recordIngest(ledger, 157, [{ errors: ['x'] }, { errors: ['y'] }], T0)
40
- /* 저널에 앉은 것 46 */
41
- recordJournalWrite(ledger, 46, T0)
42
- /* 합친 것 108 */
43
- recordDuplicates(ledger, 108, T0)
44
- /* 저널에 안 가는 어휘 1 */
45
- recordVocabulary(ledger, 1)
46
-
47
- const w = ledger.window
48
- const unexplained = w.offered - w.rows - w.rejected - ledger.duplicates - w.vocabulary
49
-
50
- assert.equal(unexplained, 0, `설명 못 한 것이 ${unexplained} 남았다 — 셈이 안 닫힌다`)
51
- })
52
-
53
- test('★ 어휘 항이 없으면 그 수가 「사라졌다」로 남는다 — 이 항의 존재 이유', () => {
54
- const ledger = newIngestLedger()
55
- recordIngest(ledger, 20, undefined, T0)
56
- recordJournalWrite(ledger, 17, T0)
57
- recordVocabulary(ledger, 1)
58
-
59
- const w = ledger.window
60
- /* 어휘를 안 빼면 셋이 빈 것으로 보인다 — 실제로 사라진 것은 둘이다. */
61
- assert.equal(w.offered - w.rows, 3, '실측 상황을 못 만들고 있다')
62
- assert.equal(w.offered - w.rows - w.vocabulary, 2, '어휘를 빼도 수가 안 맞는다')
63
- })
64
-
65
- test('★ 어휘는 저널 수에 안 들어간다 — 두 번 세면 셈이 음수가 된다', () => {
66
- const ledger = newIngestLedger()
67
- recordIngest(ledger, 1, undefined, T0)
68
- recordVocabulary(ledger, 1)
69
-
70
- assert.equal(ledger.window.rows, 0, '어휘가 저널 수에 섞였다')
71
- assert.equal(ledger.window.vocabulary, 1)
72
- })
73
-
74
- test('★ 창이 갈리면 각 창이 자기 어휘를 든다 — 누적으로 비교하면 안 된다', () => {
75
- /*
76
- * 인티그레이션 레인이 짚은 것: `mes-line-a` 가 커서 48 · 저널 11 인데 결함이 아니다(그 사이
77
- * 저널을 비웠다). **창 단위로** 맞춰야 한다.
78
- */
79
- const ledger = newIngestLedger()
80
- recordIngest(ledger, 5, undefined, T0)
81
- recordVocabulary(ledger, 2)
82
- assert.equal(ledger.window.vocabulary, 2)
83
-
84
- /* 창을 넘긴다 — 새 창은 0에서 시작한다. */
85
- recordIngest(ledger, 5, undefined, T0 + 700_000)
86
- assert.equal(ledger.window.vocabulary, 0, '새 창이 앞 창의 어휘를 물고 왔다')
87
- assert.equal(ledger.vocabulary, 2, '누적은 남아야 한다')
88
- })
89
-
90
- test('★ 이 검사가 실제로 무언가를 잰다 — 견준 것이 0이면 빨강', () => {
91
- const ledger = newIngestLedger()
92
- assert.equal(ledger.window.vocabulary, 0, '새 창에 그 항이 없다')
93
- recordVocabulary(ledger, 0)
94
- assert.equal(ledger.vocabulary, 0, '0을 세었다 — 모르면 안 적는다')
95
- recordVocabulary(ledger, -3)
96
- assert.equal(ledger.vocabulary, 0, '음수를 세었다')
97
- })
@@ -1,100 +0,0 @@
1
- /*
2
- * 트윈의 고정 유입 규칙이 **표준 헤더 필드를 세 갈래 모두에서** 통과시키나.
3
- *
4
- * ── 왜 필요한가 (2026-09-07) ────────────────────────────────────────────────
5
- * 같은 결함이 이 저장소에서 네 번 났고, 네 번 다 **층이 달랐다.**
6
- *
7
- * ```
8
- * 1 EpcisHeaderOptions 에 칸이 없다 objectEvent 만 자기 인자로 갖고 있었다
9
- * 2 매핑 스펙에 칸이 없다 커넥터가 선언할 자리가 없었다
10
- * 3 이 파일의 규칙 셋에 칸이 없다 선언해도 여기서 사라졌다
11
- * 4 받는 쪽 — 이건 처음부터 서 있었다
12
- * ```
13
- *
14
- * 세 층이 각각 새는 자리였고, **아래 두 층을 고친 뒤에도 위층에서 계속 사라졌다.** 계약을 열고
15
- * 「됐다」고 한 것이 아니라 인티그레이션 레인이 이 규칙 그대로 `mapRecord` 를 돌려 봐서 찾았다.
16
- *
17
- * 그래서 이 시험은 **계약이 아니라 이 파일의 규칙**을 돌린다. 계약 쪽 시험이 초록이어도 여기서
18
- * 사라질 수 있다는 것이 오늘 실제로 일어난 일이다.
19
- */
20
- import test from 'node:test'
21
- import assert from 'node:assert/strict'
22
-
23
- import { mapRecordChecked } from '@operato/ops-contract'
24
-
25
- import { canonicalRulesForTest } from '../server/engine/canonical-ingest.js'
26
-
27
- const AT = '2026-09-07T02:00:00.000Z'
28
-
29
- /** 세 갈래가 각자 성립하는 최소 레코드 — 헤더 값은 같은 것을 싣는다. */
30
- const HEADER = {
31
- bizStep: 'urn:epcglobal:cbv:bizstep:storing',
32
- disposition: 'urn:epcglobal:cbv:disp:in_progress',
33
- readPoint: 'urn:epc:id:sgln:0614141.00001.0',
34
- bizLocation: 'urn:epc:id:sgln:0614141.00002.0',
35
- bizTransactionList: [{ type: 'urn:epcglobal:cbv:btt:po', bizTransaction: 'urn:epcglobal:cbv:bt:0614141:order-33' }],
36
- errorDeclaration: { declarationTime: AT, reason: 'urn:epcglobal:cbv:er:incorrect_data' }
37
- }
38
-
39
- const RECORDS: { sourceType: string; record: Record<string, unknown> }[] = [
40
- { sourceType: 'twin', record: { ...HEADER, action: 'OBSERVE', epc: 'urn:epc:id:sgtin:0614141.107346.2018' } },
41
- {
42
- sourceType: 'twin-transformation',
43
- record: {
44
- ...HEADER,
45
- inputEPCList: ['urn:epc:id:sgtin:0614141.107346.1000'],
46
- outputEPCList: ['urn:epc:id:sgtin:0614141.107346.2000'],
47
- transformationID: 'urn:uuid:11111111-2222-3333-4444-555555555555'
48
- }
49
- },
50
- {
51
- sourceType: 'twin-aggregation',
52
- record: { ...HEADER, action: 'ADD', parentID: 'urn:epc:id:sscc:0614141.1234567890', childEPCs: ['urn:epc:id:sgtin:0614141.107346.2018'] }
53
- }
54
- ]
55
-
56
- function mapWith(sourceType: string, record: Record<string, unknown>): any {
57
- const rule = canonicalRulesForTest().find(r => r.sourceType === sourceType)
58
-
59
- assert.ok(rule, `${sourceType} 규칙이 없다 — 갈래가 사라졌다`)
60
-
61
- return mapRecordChecked(record as any, rule!.mapping as any, AT)
62
- }
63
-
64
- test('규칙이 셋이다 — 갈래가 줄면 그 사실이 조용히 사라진다', () => {
65
- assert.deepEqual(
66
- canonicalRulesForTest().map(r => r.sourceType).sort(),
67
- ['twin', 'twin-aggregation', 'twin-transformation']
68
- )
69
- })
70
-
71
- for (const { sourceType, record } of RECORDS) {
72
- test(`${sourceType} 이 오더 참조를 커널까지 넘긴다 — 이 파일에서 사라지던 자리다`, () => {
73
- const { event, errors } = mapWith(sourceType, record)
74
-
75
- assert.deepEqual(errors, [], `${sourceType}: 성립하는 레코드인데 오류가 났다`)
76
- assert.deepEqual(
77
- event.bizTransactionList,
78
- HEADER.bizTransactionList,
79
- `${sourceType}: 오더 참조가 사라졌다 — 커넥터가 실어도 저널의 biz_transaction 이 빈다`
80
- )
81
- })
82
-
83
- test(`${sourceType} 이 나머지 헤더 필드도 함께 넘긴다 — 하나만 보면 다음 것이 또 샌다`, () => {
84
- const { event } = mapWith(sourceType, record)
85
-
86
- assert.equal(event.bizStep, HEADER.bizStep)
87
- assert.equal(event.disposition, HEADER.disposition)
88
- assert.equal(event.readPoint?.id, HEADER.readPoint)
89
- assert.equal(event.bizLocation?.id, HEADER.bizLocation)
90
- assert.equal(event.errorDeclaration?.declarationTime, AT)
91
- })
92
- }
93
-
94
- test('오더 참조를 안 실으면 그 칸을 만들지 않는다 — 빈 배열은 「참조가 없다」와 다르다', () => {
95
- const { bizTransactionList: _drop, ...bare } = RECORDS[0].record
96
- const { event, errors } = mapWith('twin', bare)
97
-
98
- assert.deepEqual(errors, [])
99
- assert.equal('bizTransactionList' in event, false)
100
- })