@things-factory/headless-twin 10.1.278 → 10.1.280

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (614) hide show
  1. package/package.json +21 -7
  2. package/dist-server/engine/attention-digest.js.map +0 -1
  3. package/dist-server/engine/canonical-ingest.js.map +0 -1
  4. package/dist-server/engine/checkpoint-fold.js.map +0 -1
  5. package/dist-server/engine/command-routing.js.map +0 -1
  6. package/dist-server/engine/declared-stimulus.js.map +0 -1
  7. package/dist-server/engine/energy-topology.js.map +0 -1
  8. package/dist-server/engine/event-time.js.map +0 -1
  9. package/dist-server/engine/index.js.map +0 -1
  10. package/dist-server/engine/ingest-dedupe.js.map +0 -1
  11. package/dist-server/engine/ingest-health.js.map +0 -1
  12. package/dist-server/engine/integration-coverage.js.map +0 -1
  13. package/dist-server/engine/integration-probes.js.map +0 -1
  14. package/dist-server/engine/integration-runner.js.map +0 -1
  15. package/dist-server/engine/integration-target-profile.js.map +0 -1
  16. package/dist-server/engine/kpi-baseline.js.map +0 -1
  17. package/dist-server/engine/kpi-fold.js.map +0 -1
  18. package/dist-server/engine/kpi-query.js.map +0 -1
  19. package/dist-server/engine/kpi-target.js.map +0 -1
  20. package/dist-server/engine/live-attentions.js.map +0 -1
  21. package/dist-server/engine/live-feed-registry.js.map +0 -1
  22. package/dist-server/engine/load-meter.js.map +0 -1
  23. package/dist-server/engine/local-declarations.js.map +0 -1
  24. package/dist-server/engine/log.js.map +0 -1
  25. package/dist-server/engine/loop-lag.js.map +0 -1
  26. package/dist-server/engine/measured-estimator.js.map +0 -1
  27. package/dist-server/engine/measured-yield.js.map +0 -1
  28. package/dist-server/engine/model-basis.js.map +0 -1
  29. package/dist-server/engine/model-gap.js.map +0 -1
  30. package/dist-server/engine/model-refusal.js.map +0 -1
  31. package/dist-server/engine/model-vocabulary.js.map +0 -1
  32. package/dist-server/engine/oee-accumulator.js.map +0 -1
  33. package/dist-server/engine/operation-basis.js.map +0 -1
  34. package/dist-server/engine/producer-guard.js.map +0 -1
  35. package/dist-server/engine/property-effects.js.map +0 -1
  36. package/dist-server/engine/read-time.js.map +0 -1
  37. package/dist-server/engine/restart-policy.js.map +0 -1
  38. package/dist-server/engine/runtime-key.js.map +0 -1
  39. package/dist-server/engine/spec-coverage.js.map +0 -1
  40. package/dist-server/engine/stage-path.js.map +0 -1
  41. package/dist-server/engine/state-axes.js.map +0 -1
  42. package/dist-server/engine/structure-diff.js.map +0 -1
  43. package/dist-server/engine/travel-estimator.js.map +0 -1
  44. package/dist-server/engine/twin-engine.js.map +0 -1
  45. package/dist-server/engine/twin-state-channel.js.map +0 -1
  46. package/dist-server/engine/warm-start.js.map +0 -1
  47. package/dist-server/index.js.map +0 -1
  48. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js.map +0 -1
  49. package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js.map +0 -1
  50. package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js.map +0 -1
  51. package/dist-server/migrations/1786300000000-IndexEventTypeByTime.js.map +0 -1
  52. package/dist-server/migrations/1786400000000-IndexEventCreatedAt.js.map +0 -1
  53. package/dist-server/migrations/1786500000000-CreateTwinSubjectEvents.js.map +0 -1
  54. package/dist-server/migrations/1786600000000-RenameOperatoMesAdapterType.js.map +0 -1
  55. package/dist-server/migrations/1786700000000-AddDispatchRetryColumns.js.map +0 -1
  56. package/dist-server/migrations/1786800000000-CreateTwinReferenceReconciliations.js.map +0 -1
  57. package/dist-server/migrations/index.js.map +0 -1
  58. package/dist-server/routes.js.map +0 -1
  59. package/dist-server/service/actuation/actuation-advisor.js.map +0 -1
  60. package/dist-server/service/actuation/actuation-outcome.js.map +0 -1
  61. package/dist-server/service/actuation/actuation-rule-resolver.js.map +0 -1
  62. package/dist-server/service/actuation/actuation-rule.js.map +0 -1
  63. package/dist-server/service/actuation/approval-gateway.js.map +0 -1
  64. package/dist-server/service/actuation/catch-up-effects.js.map +0 -1
  65. package/dist-server/service/actuation/command-dispatcher.js.map +0 -1
  66. package/dist-server/service/actuation/command-store.js.map +0 -1
  67. package/dist-server/service/actuation/dispatch-after-approval.js.map +0 -1
  68. package/dist-server/service/actuation/effect-match.js.map +0 -1
  69. package/dist-server/service/actuation/index.js.map +0 -1
  70. package/dist-server/service/actuation/retry-plan.js.map +0 -1
  71. package/dist-server/service/actuation/rule-evaluate.js.map +0 -1
  72. package/dist-server/service/actuation/rule-loop.js.map +0 -1
  73. package/dist-server/service/actuation/rule-runner.js.map +0 -1
  74. package/dist-server/service/actuation/rule-wiring.js.map +0 -1
  75. package/dist-server/service/actuation/settle-effects.js.map +0 -1
  76. package/dist-server/service/actuation/sweep-dispatch.js.map +0 -1
  77. package/dist-server/service/actuation/twin-command-resolver.js.map +0 -1
  78. package/dist-server/service/actuation/twin-command.js.map +0 -1
  79. package/dist-server/service/actuation/twin-now.js.map +0 -1
  80. package/dist-server/service/index.js.map +0 -1
  81. package/dist-server/service/reference/actuation-routing.js.map +0 -1
  82. package/dist-server/service/reference/actuation-target.js.map +0 -1
  83. package/dist-server/service/reference/actuation-verification.js.map +0 -1
  84. package/dist-server/service/reference/attention-lane.js.map +0 -1
  85. package/dist-server/service/reference/connection-portability-resolver.js.map +0 -1
  86. package/dist-server/service/reference/connection-portability.js.map +0 -1
  87. package/dist-server/service/reference/control-routing.js.map +0 -1
  88. package/dist-server/service/reference/discovery-result.js.map +0 -1
  89. package/dist-server/service/reference/fill-cadence.js.map +0 -1
  90. package/dist-server/service/reference/fill-dedupe.js.map +0 -1
  91. package/dist-server/service/reference/fill-loop.js.map +0 -1
  92. package/dist-server/service/reference/fill-span.js.map +0 -1
  93. package/dist-server/service/reference/hook-contract.js.map +0 -1
  94. package/dist-server/service/reference/hook-rejected.js.map +0 -1
  95. package/dist-server/service/reference/hook-store.js.map +0 -1
  96. package/dist-server/service/reference/index.js.map +0 -1
  97. package/dist-server/service/reference/ingest-space.js.map +0 -1
  98. package/dist-server/service/reference/knob-defaults.js.map +0 -1
  99. package/dist-server/service/reference/live-cadence.js.map +0 -1
  100. package/dist-server/service/reference/live-feed-lease.js.map +0 -1
  101. package/dist-server/service/reference/live-ingest.js.map +0 -1
  102. package/dist-server/service/reference/reference-adapter.js.map +0 -1
  103. package/dist-server/service/reference/reference-assessment.js.map +0 -1
  104. package/dist-server/service/reference/reference-fill-run.js.map +0 -1
  105. package/dist-server/service/reference/reference-fill.js.map +0 -1
  106. package/dist-server/service/reference/reference-hook.js.map +0 -1
  107. package/dist-server/service/reference/reference-link-groups.js.map +0 -1
  108. package/dist-server/service/reference/reference-links.js.map +0 -1
  109. package/dist-server/service/reference/reference-live.js.map +0 -1
  110. package/dist-server/service/reference/reference-master.js.map +0 -1
  111. package/dist-server/service/reference/reference-probe.js.map +0 -1
  112. package/dist-server/service/reference/reference-progress-channel.js.map +0 -1
  113. package/dist-server/service/reference/reference-progress-subscription.js.map +0 -1
  114. package/dist-server/service/reference/reference-progress.js.map +0 -1
  115. package/dist-server/service/reference/reference-reconciliation-query.js.map +0 -1
  116. package/dist-server/service/reference/reference-reconciliation-writer.js.map +0 -1
  117. package/dist-server/service/reference/reference-reconciliation.js.map +0 -1
  118. package/dist-server/service/reference/reference-registry.js.map +0 -1
  119. package/dist-server/service/reference/reference-resolver.js.map +0 -1
  120. package/dist-server/service/reference/template-registry.js.map +0 -1
  121. package/dist-server/service/reference/twin-reference-reconciliation.js.map +0 -1
  122. package/dist-server/service/reference/twin-reference.js.map +0 -1
  123. package/dist-server/service/twin-attention/index.js.map +0 -1
  124. package/dist-server/service/twin-attention/twin-attention-query.js.map +0 -1
  125. package/dist-server/service/twin-audit/command-audit.js.map +0 -1
  126. package/dist-server/service/twin-audit/index.js.map +0 -1
  127. package/dist-server/service/twin-audit/twin-audit-event.js.map +0 -1
  128. package/dist-server/service/twin-audit/twin-audit-query.js.map +0 -1
  129. package/dist-server/service/twin-backfill/backfill-period-facts.js.map +0 -1
  130. package/dist-server/service/twin-backfill/backfill-shape.js.map +0 -1
  131. package/dist-server/service/twin-backfill/index.js.map +0 -1
  132. package/dist-server/service/twin-backfill/twin-backfill-resolver.js.map +0 -1
  133. package/dist-server/service/twin-control/index.js.map +0 -1
  134. package/dist-server/service/twin-control/twin-control-mutation.js.map +0 -1
  135. package/dist-server/service/twin-event/index.js.map +0 -1
  136. package/dist-server/service/twin-event/journal-count.js.map +0 -1
  137. package/dist-server/service/twin-event/twin-event-keys.js.map +0 -1
  138. package/dist-server/service/twin-event/twin-event-type.js.map +0 -1
  139. package/dist-server/service/twin-event/twin-event.js.map +0 -1
  140. package/dist-server/service/twin-forecast/forecast-metrics.js.map +0 -1
  141. package/dist-server/service/twin-forecast/forecast-tuning.js.map +0 -1
  142. package/dist-server/service/twin-forecast/gap-analytics.js.map +0 -1
  143. package/dist-server/service/twin-forecast/index.js.map +0 -1
  144. package/dist-server/service/twin-forecast/twin-forecast-query.js.map +0 -1
  145. package/dist-server/service/twin-ingest-window/index.js.map +0 -1
  146. package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js.map +0 -1
  147. package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js.map +0 -1
  148. package/dist-server/service/twin-ingest-window/twin-ingest-window.js.map +0 -1
  149. package/dist-server/service/twin-instance/index.js.map +0 -1
  150. package/dist-server/service/twin-instance/twin-instance.js.map +0 -1
  151. package/dist-server/service/twin-journal/event-type-split-shape.js.map +0 -1
  152. package/dist-server/service/twin-journal/event-type-split.js.map +0 -1
  153. package/dist-server/service/twin-journal/index.js.map +0 -1
  154. package/dist-server/service/twin-journal/journal-order.js.map +0 -1
  155. package/dist-server/service/twin-journal/twin-journal-query.js.map +0 -1
  156. package/dist-server/service/twin-lifecycle/domain-catalog.js.map +0 -1
  157. package/dist-server/service/twin-lifecycle/index.js.map +0 -1
  158. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +0 -1
  159. package/dist-server/service/twin-metrics/index.js.map +0 -1
  160. package/dist-server/service/twin-metrics/twin-metrics-query.js.map +0 -1
  161. package/dist-server/service/twin-model/axis-journal-evidence.js.map +0 -1
  162. package/dist-server/service/twin-model/choose-recipe.js.map +0 -1
  163. package/dist-server/service/twin-model/epcis-coverage.js.map +0 -1
  164. package/dist-server/service/twin-model/external-resolver.js.map +0 -1
  165. package/dist-server/service/twin-model/iec61850-coverage.js.map +0 -1
  166. package/dist-server/service/twin-model/index.js.map +0 -1
  167. package/dist-server/service/twin-model/isa95-coverage.js.map +0 -1
  168. package/dist-server/service/twin-model/item-ref.js.map +0 -1
  169. package/dist-server/service/twin-model/name-index.js.map +0 -1
  170. package/dist-server/service/twin-model/project-structure.js.map +0 -1
  171. package/dist-server/service/twin-model/standard-coverage.js.map +0 -1
  172. package/dist-server/service/twin-model/status-tally.js.map +0 -1
  173. package/dist-server/service/twin-model/twin-equipment.js.map +0 -1
  174. package/dist-server/service/twin-model/twin-lineage-query.js.map +0 -1
  175. package/dist-server/service/twin-model/twin-location.js.map +0 -1
  176. package/dist-server/service/twin-model/twin-model-item-query.js.map +0 -1
  177. package/dist-server/service/twin-model/twin-model-mutation.js.map +0 -1
  178. package/dist-server/service/twin-model/twin-model-query.js.map +0 -1
  179. package/dist-server/service/twin-model/twin-model-tree-query.js.map +0 -1
  180. package/dist-server/service/twin-model/twin-operation.js.map +0 -1
  181. package/dist-server/service/twin-readiness/index.js.map +0 -1
  182. package/dist-server/service/twin-readiness/twin-readiness-query.js.map +0 -1
  183. package/dist-server/service/twin-space/area-resolver.js.map +0 -1
  184. package/dist-server/service/twin-space/index.js.map +0 -1
  185. package/dist-server/service/twin-space/move-space.js.map +0 -1
  186. package/dist-server/service/twin-space/representation-role.js.map +0 -1
  187. package/dist-server/service/twin-space/space-integrity.js.map +0 -1
  188. package/dist-server/service/twin-space/twin-area.js.map +0 -1
  189. package/dist-server/service/twin-space/twin-space-area.js.map +0 -1
  190. package/dist-server/service/twin-space/twin-space-representation.js.map +0 -1
  191. package/dist-server/service/twin-space/twin-space-resolver.js.map +0 -1
  192. package/dist-server/service/twin-space/twin-space.js.map +0 -1
  193. package/dist-server/service/twin-state/index.js.map +0 -1
  194. package/dist-server/service/twin-state/twin-state-subscription.js.map +0 -1
  195. package/dist-server/service/twin-structure/index.js.map +0 -1
  196. package/dist-server/service/twin-structure/twin-structure.js.map +0 -1
  197. package/dist-server/service/twin-subject/event-subjects.js.map +0 -1
  198. package/dist-server/service/twin-subject/index.js.map +0 -1
  199. package/dist-server/service/twin-subject/item-resolver.js.map +0 -1
  200. package/dist-server/service/twin-subject/subject-query-shape.js.map +0 -1
  201. package/dist-server/service/twin-subject/twin-subject-backfill.js.map +0 -1
  202. package/dist-server/service/twin-subject/twin-subject-event.js.map +0 -1
  203. package/dist-server/service/twin-subject/twin-subject-fast-path.js.map +0 -1
  204. package/dist-server/service/twin-subject/twin-subject-query.js.map +0 -1
  205. package/dist-server/service/twin-subject/twin-subject-writer.js.map +0 -1
  206. package/dist-server/service/twin-target/index.js.map +0 -1
  207. package/dist-server/service/twin-target/twin-target-resolver.js.map +0 -1
  208. package/dist-server/service/twin-target/twin-target.js.map +0 -1
  209. package/dist-shared/axis-read.js.map +0 -1
  210. package/dist-shared/entity-delta.js.map +0 -1
  211. package/dist-shared/kpi-broadcast.js.map +0 -1
  212. package/dist-shared/touched-items.js.map +0 -1
  213. package/dist-shared/twin-level.js.map +0 -1
  214. package/server/engine/attention-digest.ts +0 -102
  215. package/server/engine/canonical-ingest.ts +0 -511
  216. package/server/engine/checkpoint-fold.ts +0 -12
  217. package/server/engine/command-routing.ts +0 -67
  218. package/server/engine/declared-stimulus.ts +0 -66
  219. package/server/engine/energy-topology.ts +0 -189
  220. package/server/engine/event-time.ts +0 -96
  221. package/server/engine/index.ts +0 -51
  222. package/server/engine/ingest-dedupe.ts +0 -24
  223. package/server/engine/ingest-health.ts +0 -24
  224. package/server/engine/integration-coverage.ts +0 -147
  225. package/server/engine/integration-probes.ts +0 -144
  226. package/server/engine/integration-runner.ts +0 -95
  227. package/server/engine/integration-target-profile.ts +0 -103
  228. package/server/engine/kpi-baseline.ts +0 -202
  229. package/server/engine/kpi-fold.ts +0 -1516
  230. package/server/engine/kpi-query.ts +0 -1210
  231. package/server/engine/kpi-target.ts +0 -248
  232. package/server/engine/live-attentions.ts +0 -30
  233. package/server/engine/live-feed-registry.ts +0 -59
  234. package/server/engine/load-meter.ts +0 -393
  235. package/server/engine/local-declarations.ts +0 -779
  236. package/server/engine/log.ts +0 -72
  237. package/server/engine/loop-lag.ts +0 -120
  238. package/server/engine/measured-estimator.ts +0 -91
  239. package/server/engine/measured-yield.ts +0 -89
  240. package/server/engine/model-basis.ts +0 -162
  241. package/server/engine/model-gap.ts +0 -168
  242. package/server/engine/model-refusal.ts +0 -31
  243. package/server/engine/model-vocabulary.ts +0 -82
  244. package/server/engine/oee-accumulator.ts +0 -195
  245. package/server/engine/operation-basis.ts +0 -131
  246. package/server/engine/producer-guard.ts +0 -64
  247. package/server/engine/property-effects.ts +0 -216
  248. package/server/engine/read-time.ts +0 -77
  249. package/server/engine/restart-policy.ts +0 -55
  250. package/server/engine/runtime-key.ts +0 -58
  251. package/server/engine/spec-coverage.ts +0 -105
  252. package/server/engine/stage-path.ts +0 -172
  253. package/server/engine/state-axes.ts +0 -60
  254. package/server/engine/structure-diff.ts +0 -88
  255. package/server/engine/travel-estimator.ts +0 -138
  256. package/server/engine/twin-engine.ts +0 -4979
  257. package/server/engine/twin-state-channel.ts +0 -39
  258. package/server/engine/warm-start.ts +0 -265
  259. package/server/index.ts +0 -90
  260. package/server/migrations/1786000000000-RenameTwinInstanceBoardToModel.ts +0 -43
  261. package/server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.ts +0 -54
  262. package/server/migrations/1786200000000-CarryLiveFeedCursor.ts +0 -53
  263. package/server/migrations/1786300000000-IndexEventTypeByTime.ts +0 -48
  264. package/server/migrations/1786400000000-IndexEventCreatedAt.ts +0 -38
  265. package/server/migrations/1786500000000-CreateTwinSubjectEvents.ts +0 -93
  266. package/server/migrations/1786600000000-RenameOperatoMesAdapterType.ts +0 -66
  267. package/server/migrations/1786700000000-AddDispatchRetryColumns.ts +0 -82
  268. package/server/migrations/1786800000000-CreateTwinReferenceReconciliations.ts +0 -39
  269. package/server/migrations/index.ts +0 -25
  270. package/server/routes.ts +0 -75
  271. package/server/service/actuation/actuation-advisor.ts +0 -131
  272. package/server/service/actuation/actuation-outcome.ts +0 -97
  273. package/server/service/actuation/actuation-rule-resolver.ts +0 -147
  274. package/server/service/actuation/actuation-rule.ts +0 -139
  275. package/server/service/actuation/approval-gateway.ts +0 -44
  276. package/server/service/actuation/catch-up-effects.ts +0 -152
  277. package/server/service/actuation/command-dispatcher.ts +0 -474
  278. package/server/service/actuation/command-store.ts +0 -236
  279. package/server/service/actuation/dispatch-after-approval.ts +0 -71
  280. package/server/service/actuation/effect-match.ts +0 -124
  281. package/server/service/actuation/index.ts +0 -27
  282. package/server/service/actuation/retry-plan.ts +0 -145
  283. package/server/service/actuation/rule-evaluate.ts +0 -352
  284. package/server/service/actuation/rule-loop.ts +0 -160
  285. package/server/service/actuation/rule-runner.ts +0 -216
  286. package/server/service/actuation/rule-wiring.ts +0 -84
  287. package/server/service/actuation/settle-effects.ts +0 -115
  288. package/server/service/actuation/sweep-dispatch.ts +0 -179
  289. package/server/service/actuation/twin-command-resolver.ts +0 -387
  290. package/server/service/actuation/twin-command.ts +0 -232
  291. package/server/service/actuation/twin-now.ts +0 -97
  292. package/server/service/index.ts +0 -100
  293. package/server/service/reference/actuation-routing.ts +0 -192
  294. package/server/service/reference/actuation-target.ts +0 -163
  295. package/server/service/reference/actuation-verification.ts +0 -85
  296. package/server/service/reference/attention-lane.ts +0 -21
  297. package/server/service/reference/connection-portability-resolver.ts +0 -171
  298. package/server/service/reference/connection-portability.ts +0 -329
  299. package/server/service/reference/control-routing.ts +0 -62
  300. package/server/service/reference/discovery-result.ts +0 -95
  301. package/server/service/reference/fill-cadence.ts +0 -29
  302. package/server/service/reference/fill-dedupe.ts +0 -66
  303. package/server/service/reference/fill-loop.ts +0 -153
  304. package/server/service/reference/fill-span.ts +0 -31
  305. package/server/service/reference/hook-contract.ts +0 -364
  306. package/server/service/reference/hook-rejected.ts +0 -53
  307. package/server/service/reference/hook-store.ts +0 -28
  308. package/server/service/reference/index.ts +0 -18
  309. package/server/service/reference/ingest-space.ts +0 -104
  310. package/server/service/reference/knob-defaults.ts +0 -59
  311. package/server/service/reference/live-cadence.ts +0 -129
  312. package/server/service/reference/live-feed-lease.ts +0 -56
  313. package/server/service/reference/live-ingest.ts +0 -94
  314. package/server/service/reference/reference-adapter.ts +0 -985
  315. package/server/service/reference/reference-assessment.ts +0 -250
  316. package/server/service/reference/reference-fill-run.ts +0 -179
  317. package/server/service/reference/reference-fill.ts +0 -223
  318. package/server/service/reference/reference-hook.ts +0 -479
  319. package/server/service/reference/reference-link-groups.ts +0 -21
  320. package/server/service/reference/reference-links.ts +0 -77
  321. package/server/service/reference/reference-live.ts +0 -420
  322. package/server/service/reference/reference-master.ts +0 -999
  323. package/server/service/reference/reference-probe.ts +0 -264
  324. package/server/service/reference/reference-progress-channel.ts +0 -26
  325. package/server/service/reference/reference-progress-subscription.ts +0 -78
  326. package/server/service/reference/reference-progress.ts +0 -95
  327. package/server/service/reference/reference-reconciliation-query.ts +0 -28
  328. package/server/service/reference/reference-reconciliation-writer.ts +0 -38
  329. package/server/service/reference/reference-reconciliation.ts +0 -55
  330. package/server/service/reference/reference-registry.ts +0 -17
  331. package/server/service/reference/reference-resolver.ts +0 -969
  332. package/server/service/reference/template-registry.ts +0 -85
  333. package/server/service/reference/twin-reference-reconciliation.ts +0 -27
  334. package/server/service/reference/twin-reference.ts +0 -190
  335. package/server/service/twin-attention/index.ts +0 -3
  336. package/server/service/twin-attention/twin-attention-query.ts +0 -70
  337. package/server/service/twin-audit/command-audit.ts +0 -114
  338. package/server/service/twin-audit/index.ts +0 -5
  339. package/server/service/twin-audit/twin-audit-event.ts +0 -158
  340. package/server/service/twin-audit/twin-audit-query.ts +0 -72
  341. package/server/service/twin-backfill/backfill-period-facts.ts +0 -168
  342. package/server/service/twin-backfill/backfill-shape.ts +0 -86
  343. package/server/service/twin-backfill/index.ts +0 -3
  344. package/server/service/twin-backfill/twin-backfill-resolver.ts +0 -35
  345. package/server/service/twin-control/index.ts +0 -3
  346. package/server/service/twin-control/twin-control-mutation.ts +0 -150
  347. package/server/service/twin-event/index.ts +0 -3
  348. package/server/service/twin-event/journal-count.ts +0 -53
  349. package/server/service/twin-event/twin-event-keys.ts +0 -215
  350. package/server/service/twin-event/twin-event-type.ts +0 -68
  351. package/server/service/twin-event/twin-event.ts +0 -250
  352. package/server/service/twin-forecast/forecast-metrics.ts +0 -106
  353. package/server/service/twin-forecast/forecast-tuning.ts +0 -40
  354. package/server/service/twin-forecast/gap-analytics.ts +0 -139
  355. package/server/service/twin-forecast/index.ts +0 -3
  356. package/server/service/twin-forecast/twin-forecast-query.ts +0 -486
  357. package/server/service/twin-ingest-window/index.ts +0 -7
  358. package/server/service/twin-ingest-window/twin-ingest-window-query.ts +0 -125
  359. package/server/service/twin-ingest-window/twin-ingest-window-writer.ts +0 -57
  360. package/server/service/twin-ingest-window/twin-ingest-window.ts +0 -113
  361. package/server/service/twin-instance/index.ts +0 -3
  362. package/server/service/twin-instance/twin-instance.ts +0 -199
  363. package/server/service/twin-journal/event-type-split-shape.ts +0 -112
  364. package/server/service/twin-journal/event-type-split.ts +0 -144
  365. package/server/service/twin-journal/index.ts +0 -3
  366. package/server/service/twin-journal/journal-order.ts +0 -20
  367. package/server/service/twin-journal/twin-journal-query.ts +0 -615
  368. package/server/service/twin-lifecycle/domain-catalog.ts +0 -51
  369. package/server/service/twin-lifecycle/index.ts +0 -3
  370. package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +0 -285
  371. package/server/service/twin-metrics/index.ts +0 -3
  372. package/server/service/twin-metrics/twin-metrics-query.ts +0 -172
  373. package/server/service/twin-model/axis-journal-evidence.ts +0 -57
  374. package/server/service/twin-model/choose-recipe.ts +0 -31
  375. package/server/service/twin-model/epcis-coverage.ts +0 -251
  376. package/server/service/twin-model/external-resolver.ts +0 -173
  377. package/server/service/twin-model/iec61850-coverage.ts +0 -111
  378. package/server/service/twin-model/index.ts +0 -25
  379. package/server/service/twin-model/isa95-coverage.ts +0 -320
  380. package/server/service/twin-model/item-ref.ts +0 -80
  381. package/server/service/twin-model/name-index.ts +0 -94
  382. package/server/service/twin-model/project-structure.ts +0 -213
  383. package/server/service/twin-model/standard-coverage.ts +0 -35
  384. package/server/service/twin-model/status-tally.ts +0 -37
  385. package/server/service/twin-model/twin-equipment.ts +0 -191
  386. package/server/service/twin-model/twin-lineage-query.ts +0 -327
  387. package/server/service/twin-model/twin-location.ts +0 -147
  388. package/server/service/twin-model/twin-model-item-query.ts +0 -1029
  389. package/server/service/twin-model/twin-model-mutation.ts +0 -503
  390. package/server/service/twin-model/twin-model-query.ts +0 -792
  391. package/server/service/twin-model/twin-model-tree-query.ts +0 -211
  392. package/server/service/twin-model/twin-operation.ts +0 -157
  393. package/server/service/twin-readiness/index.ts +0 -3
  394. package/server/service/twin-readiness/twin-readiness-query.ts +0 -96
  395. package/server/service/twin-space/area-resolver.ts +0 -75
  396. package/server/service/twin-space/index.ts +0 -8
  397. package/server/service/twin-space/move-space.ts +0 -262
  398. package/server/service/twin-space/representation-role.ts +0 -15
  399. package/server/service/twin-space/space-integrity.ts +0 -293
  400. package/server/service/twin-space/twin-area.ts +0 -63
  401. package/server/service/twin-space/twin-space-area.ts +0 -66
  402. package/server/service/twin-space/twin-space-representation.ts +0 -99
  403. package/server/service/twin-space/twin-space-resolver.ts +0 -582
  404. package/server/service/twin-space/twin-space.ts +0 -148
  405. package/server/service/twin-state/index.ts +0 -3
  406. package/server/service/twin-state/twin-state-subscription.ts +0 -62
  407. package/server/service/twin-structure/index.ts +0 -3
  408. package/server/service/twin-structure/twin-structure.ts +0 -96
  409. package/server/service/twin-subject/event-subjects.ts +0 -162
  410. package/server/service/twin-subject/index.ts +0 -10
  411. package/server/service/twin-subject/item-resolver.ts +0 -92
  412. package/server/service/twin-subject/subject-query-shape.ts +0 -84
  413. package/server/service/twin-subject/twin-subject-backfill.ts +0 -196
  414. package/server/service/twin-subject/twin-subject-event.ts +0 -101
  415. package/server/service/twin-subject/twin-subject-fast-path.ts +0 -346
  416. package/server/service/twin-subject/twin-subject-query.ts +0 -210
  417. package/server/service/twin-subject/twin-subject-writer.ts +0 -189
  418. package/server/service/twin-target/index.ts +0 -5
  419. package/server/service/twin-target/twin-target-resolver.ts +0 -142
  420. package/server/service/twin-target/twin-target.ts +0 -97
  421. package/server/types/global.d.ts +0 -22
  422. package/shared/axis-read.ts +0 -28
  423. package/shared/entity-delta.ts +0 -335
  424. package/shared/kpi-broadcast.ts +0 -13
  425. package/shared/touched-items.ts +0 -73
  426. package/shared/twin-level.ts +0 -48
  427. package/test/ack-shape-alignment.test.ts +0 -97
  428. package/test/actuation-advisor.test.ts +0 -55
  429. package/test/actuation-approval-door.test.ts +0 -411
  430. package/test/actuation-dispatch.test.ts +0 -209
  431. package/test/actuation-effect.test.ts +0 -162
  432. package/test/actuation-outcome.test.ts +0 -152
  433. package/test/actuation-rule-runner.test.ts +0 -281
  434. package/test/actuation-rule.test.ts +0 -266
  435. package/test/actuation-seam.test.ts +0 -255
  436. package/test/actuation-settle.test.ts +0 -164
  437. package/test/actuation-target.test.ts +0 -145
  438. package/test/actuation-verification-state.test.ts +0 -139
  439. package/test/adopt-structure-live.test.ts +0 -133
  440. package/test/aggregate-not-findone.test.ts +0 -112
  441. package/test/area-resolver-db.test.ts +0 -110
  442. package/test/attention-digest.test.ts +0 -161
  443. package/test/axis-declaration-passthrough-db.test.ts +0 -152
  444. package/test/axis-journal-evidence.test.ts +0 -71
  445. package/test/axis-read.test.ts +0 -188
  446. package/test/backfill-shape.test.ts +0 -89
  447. package/test/boot-resume.test.ts +0 -287
  448. package/test/broadcast-cost-baseline.test.ts +0 -201
  449. package/test/broadcast-period.test.ts +0 -58
  450. package/test/broadcast-queue-overflow.test.ts +0 -244
  451. package/test/canonical-ingest-vocabularies.test.ts +0 -451
  452. package/test/canonical-quantity-door.test.ts +0 -61
  453. package/test/capability-mapping.test.ts +0 -89
  454. package/test/checkpoint-refuses-empty.test.ts +0 -103
  455. package/test/choose-recipe.test.ts +0 -117
  456. package/test/column-type-portability.test.ts +0 -122
  457. package/test/command-routing.test.ts +0 -61
  458. package/test/command-store-writes-columns.test.ts +0 -126
  459. package/test/connection-portability-doors.test.ts +0 -87
  460. package/test/connector-capability-declaration.test.ts +0 -195
  461. package/test/contract-layer-guard.test.ts +0 -48
  462. package/test/control-capability.test.ts +0 -98
  463. package/test/cursor-stall-not-read-failure.test.ts +0 -126
  464. package/test/declaration-reaches-model.test.ts +0 -226
  465. package/test/declared-location-types.test.ts +0 -89
  466. package/test/declared-stimulus.test.ts +0 -88
  467. package/test/dedupe-transformation.test.ts +0 -112
  468. package/test/discovery-result.test.ts +0 -75
  469. package/test/dispatch-after-approval-source.test.ts +0 -81
  470. package/test/duration-estimators.test.ts +0 -144
  471. package/test/energy-topology.test.ts +0 -113
  472. package/test/entity-delta.test.ts +0 -352
  473. package/test/equipment-identity-reaches.test.ts +0 -57
  474. package/test/event-subjects.test.ts +0 -148
  475. package/test/event-time-column.test.ts +0 -67
  476. package/test/event-type-split.test.ts +0 -178
  477. package/test/external-resolver.test.ts +0 -177
  478. package/test/fact-scope-wiring.test.ts +0 -96
  479. package/test/fill-dedupe.test.ts +0 -59
  480. package/test/fill-loop.test.ts +0 -35
  481. package/test/first-envelope.test.ts +0 -153
  482. package/test/fold-gap-speaks.test.ts +0 -53
  483. package/test/fold-shift-dst.test.ts +0 -110
  484. package/test/forecast-metrics.test.ts +0 -157
  485. package/test/forecast-tuning.test.ts +0 -42
  486. package/test/gap-analytics.test.ts +0 -113
  487. package/test/generated-not-counted.test.ts +0 -99
  488. package/test/guard-roots.ts +0 -76
  489. package/test/home-in-area.test.ts +0 -90
  490. package/test/hook-address.test.ts +0 -28
  491. package/test/hook-rejected-shape.test.ts +0 -86
  492. package/test/hook-response-sum.test.ts +0 -193
  493. package/test/hook-sequence.test.ts +0 -333
  494. package/test/ingest-bench.test.ts +0 -70
  495. package/test/ingest-dedupe.test.ts +0 -56
  496. package/test/ingest-expected-quiet.test.ts +0 -111
  497. package/test/ingest-health-engine.test.ts +0 -248
  498. package/test/ingest-health-wiring.test.ts +0 -120
  499. package/test/ingest-health.test.ts +0 -306
  500. package/test/ingest-history.test.ts +0 -247
  501. package/test/ingest-idempotent.test.ts +0 -211
  502. package/test/ingest-reconcile-four-ways.test.ts +0 -97
  503. package/test/ingest-rules-header.test.ts +0 -100
  504. package/test/ingest-running-guard.test.ts +0 -136
  505. package/test/ingest-space.test.ts +0 -78
  506. package/test/ingest-window-rolls-unobserved.test.ts +0 -72
  507. package/test/ingest-wiring-guard.test.ts +0 -197
  508. package/test/instance-cache-lifecycle.test.ts +0 -110
  509. package/test/intake-mapping-parity.test.ts +0 -175
  510. package/test/integration-probes.test.ts +0 -103
  511. package/test/integration-runner.test.ts +0 -95
  512. package/test/item-ref.test.ts +0 -78
  513. package/test/journal-order-axis.test.ts +0 -80
  514. package/test/journal-read-discipline.test.ts +0 -186
  515. package/test/journal-retention.test.ts +0 -275
  516. package/test/journal-sort-axis.test.ts +0 -142
  517. package/test/journal-write-door.test.ts +0 -110
  518. package/test/journal-write-trend.test.ts +0 -115
  519. package/test/kernel-kind-guard.test.ts +0 -98
  520. package/test/knob-defaults.test.ts +0 -72
  521. package/test/kpi-baseline-db.test.ts +0 -216
  522. package/test/kpi-baseline.test.ts +0 -196
  523. package/test/kpi-fold.test.ts +0 -1456
  524. package/test/kpi-query-bench.test.ts +0 -130
  525. package/test/lens-own-places.test.ts +0 -50
  526. package/test/lineage-survives-restart.test.ts +0 -234
  527. package/test/live-cadence.test.ts +0 -170
  528. package/test/live-cursor-wiring.test.ts +0 -87
  529. package/test/live-feed-lease.test.ts +0 -63
  530. package/test/live-feed-registry.test.ts +0 -75
  531. package/test/live-kernel-facts.test.ts +0 -161
  532. package/test/live-mirror-parity.test.ts +0 -286
  533. package/test/load-meter.test.ts +0 -328
  534. package/test/local-declarations.test.ts +0 -662
  535. package/test/log-stamp.test.ts +0 -59
  536. package/test/loop-lag.test.ts +0 -82
  537. package/test/master-to-twin.test.ts +0 -279
  538. package/test/measured-yield.test.ts +0 -90
  539. package/test/merge-streams.test.ts +0 -70
  540. package/test/mirror-resumes-from-checkpoint.test.ts +0 -192
  541. package/test/model-basis.test.ts +0 -141
  542. package/test/model-gap.test.ts +0 -153
  543. package/test/model-refusal.test.ts +0 -75
  544. package/test/model-vocabulary.test.ts +0 -114
  545. package/test/move-space.test.ts +0 -149
  546. package/test/mutation-gate.test.ts +0 -122
  547. package/test/oee-accumulator.test.ts +0 -204
  548. package/test/oee-site-calendar.test.ts +0 -146
  549. package/test/open-doors.test.ts +0 -197
  550. package/test/operation-basis.test.ts +0 -127
  551. package/test/operational-vocabulary.test.ts +0 -108
  552. package/test/operations-capability-db.test.ts +0 -165
  553. package/test/order-and-transaction-split.test.ts +0 -107
  554. package/test/order-fold-host.test.ts +0 -112
  555. package/test/producer-guard.test.ts +0 -66
  556. package/test/project-structure-db.test.ts +0 -226
  557. package/test/projection-reaches-screen.test.ts +0 -277
  558. package/test/projection-reads-declared.test.ts +0 -109
  559. package/test/property-effects.test.ts +0 -128
  560. package/test/provenance-promotion.test.ts +0 -99
  561. package/test/read-failure-ledger.test.ts +0 -106
  562. package/test/read-failure-visible.test.ts +0 -145
  563. package/test/read-time.test.ts +0 -118
  564. package/test/reference-fill.test.ts +0 -235
  565. package/test/reference-grounding.test.ts +0 -70
  566. package/test/reference-hook.test.ts +0 -177
  567. package/test/reference-links.test.ts +0 -56
  568. package/test/reference-reconciliation.test.ts +0 -39
  569. package/test/registry-key-guard.test.ts +0 -80
  570. package/test/rejection-carries-event-id.test.ts +0 -101
  571. package/test/rename-twin.test.ts +0 -89
  572. package/test/resolve-ts-siblings.mjs +0 -52
  573. package/test/restart-policy.test.ts +0 -111
  574. package/test/resync-origin-site.test.ts +0 -83
  575. package/test/retry-plan.test.ts +0 -139
  576. package/test/revision-axis.test.ts +0 -110
  577. package/test/runtime-key.test.ts +0 -66
  578. package/test/save-intake-collision.test.ts +0 -91
  579. package/test/scale-twin-bench.test.ts +0 -103
  580. package/test/secrets-at-rest.test.ts +0 -135
  581. package/test/snapshot-freshness.test.ts +0 -60
  582. package/test/source-outcome-audit.test.ts +0 -104
  583. package/test/space-integrity.test.ts +0 -223
  584. package/test/space-representation.test.ts +0 -66
  585. package/test/space-scope-includes-stopped.test.ts +0 -55
  586. package/test/spec-coverage.test.ts +0 -113
  587. package/test/stage-path.test.ts +0 -95
  588. package/test/standard-coverage.test.ts +0 -148
  589. package/test/state-axes.test.ts +0 -74
  590. package/test/status-tally.test.ts +0 -55
  591. package/test/streamline-e2e.test.ts +0 -76
  592. package/test/structure-revision-db.test.ts +0 -315
  593. package/test/subject-fast-path.test.ts +0 -148
  594. package/test/subject-read-model.test.ts +0 -175
  595. package/test/sweep-dispatch.test.ts +0 -191
  596. package/test/tenant-registry-db.test.ts +0 -149
  597. package/test/time-range.test.ts +0 -152
  598. package/test/touched-items.test.ts +0 -61
  599. package/test/twin-audit.test.ts +0 -83
  600. package/test/twin-event-keys.test.ts +0 -193
  601. package/test/twin-model-item-db.test.ts +0 -319
  602. package/test/twin-model-parent-relation-db.test.ts +0 -125
  603. package/test/twin-model-tree-db.test.ts +0 -209
  604. package/test/twin-origin-resync.test.ts +0 -133
  605. package/test/twin-state-channel.test.ts +0 -111
  606. package/test/vocabulary-guard.test.ts +0 -43
  607. package/test/warm-start-seam.test.ts +0 -162
  608. package/test/warm-start.test.ts +0 -297
  609. package/test/withheld-door.test.ts +0 -95
  610. package/test/yield-loop.test.ts +0 -199
  611. package/tsconfig.json +0 -15
  612. package/tsconfig.shared.json +0 -23
  613. package/tsconfig.shared.tsbuildinfo +0 -1
  614. package/tsconfig.tsbuildinfo +0 -1
@@ -1,114 +0,0 @@
1
- /*
2
- * 저장된 모델의 어휘 세대 흡수 — **빈 공장으로 읽히지 않게.**
3
- *
4
- * ── 계기 (2026-08-06, 사용자 신고) ───────────────────────────────────────────
5
- * 모델러의 엔티티 목록이 통째로 비어 있었다. **오류는 없었다.** 저장된 모델가 옛 어휘(`nodes`/`movers`)
6
- * 인데 화면과 호스트가 새 어휘를 읽었기 때문이다. 같은 원인이 구조 서명(`N[]M[]` — 서로 다른 두 공장이
7
- * 같아 보인다)·주행 추정기·설비 동기까지 알리지 않고 망가뜨리고 있었다.
8
- *
9
- * 그래서 **DB에서 읽는 순간** 한 번 정규화한다. 이 테스트가 지키는 것은 그 정규화가 ① 세 세대를 다
10
- * 흡수하고 ② 나머지 속성을 하나도 잃지 않고 ③ 새 모델에는 아무 일도 하지 않는 것이다.
11
- */
12
- import { test } from 'node:test'
13
- import assert from 'node:assert/strict'
14
-
15
- import { readFileSync } from 'node:fs'
16
-
17
- import { modelColumnTransformer, canonicalModel } from '../server/engine/model-vocabulary.ts'
18
-
19
- const LOC = [{ id: 'dock', type: 'dock', capacity: 10 }]
20
- const EQ = [{ id: 'fk-1', kind: 'forklift', homeLocation: 'dock' }]
21
-
22
- test('가장 오래된 세대(nodes·movers)를 흡수한다 — 사용자가 본 증상의 원인', () => {
23
- const out = canonicalModel({ nodes: LOC, movers: EQ, spaceId: 'site-1' })
24
-
25
- assert.deepEqual(out.locations, LOC)
26
- assert.deepEqual(out.equipment, EQ)
27
- })
28
-
29
- test('중간 세대(equipmentList)도 흡수한다 — 세 세대가 저장돼 있다', () => {
30
- const out = canonicalModel({ nodes: LOC, equipmentList: EQ })
31
-
32
- assert.deepEqual(out.equipment, EQ)
33
- })
34
-
35
- test('옛 키를 **내보내지 않는다** — 소비처가 두 어휘를 다시 보지 않게', () => {
36
- const out: any = canonicalModel({ nodes: LOC, movers: EQ, equipmentList: [] })
37
-
38
- for (const k of ['nodes', 'movers', 'equipmentList']) assert.equal(k in out, false, `${k} 가 남았다`)
39
- })
40
-
41
- test('나머지 속성을 하나도 잃지 않는다 — 곁가지로 보이는 값이 전제다', () => {
42
- /* 이 도메인에서 사소한 속성은 없다: 좌표·시각기준·명세는 소요시간·교대·생산의 전제다. */
43
- const model = {
44
- nodes: LOC,
45
- movers: EQ,
46
- spaceId: 'site-1',
47
- areaId: 'zone-a',
48
- layout: { dock: { x: 1, y: 2 } },
49
- utcOffsetMinutes: 540,
50
- unit: 'm',
51
- productionSpec: { definition: { operations: [] } },
52
- operations: [{ id: 'op-1' }]
53
- }
54
- const out: any = canonicalModel(model)
55
-
56
- for (const k of ['spaceId', 'areaId', 'layout', 'utcOffsetMinutes', 'unit', 'productionSpec', 'operations']) {
57
- assert.deepEqual(out[k], (model as any)[k], `${k} 가 사라졌다`)
58
- }
59
- })
60
-
61
- test('새 어휘 모델에는 아무 일도 하지 않는다 — 멱등', () => {
62
- const model = { locations: LOC, equipment: EQ, spaceId: 'site-1' }
63
-
64
- const once: any = canonicalModel(model)
65
- const twice: any = canonicalModel(once)
66
-
67
- assert.deepEqual(once, model)
68
- assert.deepEqual(twice, once)
69
- })
70
-
71
- test('컬렉션이 없으면 빈 배열이 된다 — 소비처가 `?? []` 를 다시 적지 않게', () => {
72
- const out = canonicalModel({ spaceId: 'site-1' })
73
-
74
- assert.deepEqual(out.locations, [])
75
- assert.deepEqual(out.equipment, [])
76
- })
77
-
78
- test('모델이 아닌 것은 그대로 통과시킨다 — 모양을 짐작해 고치지 않는다', () => {
79
- for (const v of [null, undefined, 0, '', 'board', [1, 2]]) {
80
- assert.deepEqual(canonicalModel(v as any), v as any, JSON.stringify(v))
81
- }
82
- })
83
-
84
- test('변환기는 **읽을 때만** 정규화한다 — 쓰기는 준 그대로', () => {
85
- const old = { nodes: LOC, movers: EQ }
86
-
87
- assert.deepEqual(modelColumnTransformer.from(old).equipment, EQ)
88
- /* 쓰기를 손대면 "저장된 것" 과 "준 것" 이 달라져 추적이 어려워진다. 읽기가 정규화되므로 다음 저장에서
89
- 자연히 새 어휘가 된다. */
90
- assert.equal(modelColumnTransformer.to(old), old)
91
- })
92
-
93
- test('두 옛 모델이 구조적으로 구별된다 — 서명이 빈 문자열로 축약되지 않는다', () => {
94
- /* 정규화 전에는 둘 다 `locations: undefined` 라 서명이 `N[]M[]` 로 같았다(변경 감지가 죽는다). */
95
- const a = canonicalModel({ nodes: [{ id: 'a', type: 'dock', capacity: 1 }], movers: [] })
96
- const b = canonicalModel({ nodes: [{ id: 'b', type: 'storage', capacity: 9 }], movers: [] })
97
-
98
- assert.notDeepEqual(a.locations, b.locations)
99
- assert.equal(a.locations.length, 1)
100
- assert.equal(b.locations.length, 1)
101
- })
102
-
103
- test('보드를 저장하는 엔티티가 **변환기를 달고 있다** — 결선이 빠지면 순수 모듈은 그린인데 화면은 빈다', () => {
104
- /* 이 결함이 정확히 그랬다: 리더는 커널에 있었고 목록만 그것을 거쳤다. 결선은 알리지 않고 빠질 수 있으므로
105
- 기계가 지킨다. 새 엔티티가 보드를 담게 되면 여기 함께 올린다. */
106
- const owners = ['server/service/twin-instance/twin-instance.ts', 'server/service/twin-structure/twin-structure.ts']
107
-
108
- for (const rel of owners) {
109
- const src = readFileSync(new URL('../' + rel, import.meta.url).pathname, 'utf-8')
110
- const boardColumn = src.split('\n').find(l => l.includes('@Column') && l.includes('transformer'))
111
- assert.ok(boardColumn, `${rel}: model 컬럼에 transformer 가 없다`)
112
- assert.match(boardColumn as string, /modelColumnTransformer/, `${rel}: 다른 변환기가 달려 있다`)
113
- }
114
- })
@@ -1,149 +0,0 @@
1
- /*
2
- * 기존 트윈을 다른 현장으로 가져오기 — 판정이 잃을 것을 말하는지 본다.
3
- *
4
- * 엔진 본체는 DB 를 물고 있어 단위테스트로 부를 수 없다. 그래서 **결정만** 순수 모듈로 떼어 놓고
5
- * 여기서 본다(엔진은 사실을 조회해 넘기는 일만 한다 — `ingest-space` 와 같은 구조).
6
- */
7
- import { test } from 'node:test'
8
- import assert from 'node:assert/strict'
9
-
10
- import { judgeMoveTwinSpace, judgeDetachTwinSpace } from '../server/service/twin-space/move-space.ts'
11
-
12
- /** 잃을 것이 없는 가장 단순한 이전 — 같은 시간대, 구역 참조 없음, 옛 표현 없음. */
13
- const CLEAN = {
14
- instanceId: 'wms-a',
15
- fromSpaceId: 'wms-a-site',
16
- toSpaceId: 'rosarito-site',
17
- toSpaceExists: true,
18
- fromTimezone: 'America/Los_Angeles',
19
- toTimezone: 'America/Los_Angeles'
20
- }
21
-
22
- test('잃을 것이 없으면 경고도 없다 — 정상 경로를 시끄럽게 만들지 않는다', () => {
23
- const j = judgeMoveTwinSpace(CLEAN)
24
- assert.equal(j.refusal, undefined)
25
- assert.deepEqual(j.warnings, [])
26
- })
27
-
28
- test('없는 현장으로는 옮기지 않는다 — 알리지 않고 새 공간을 만들지 않는다', () => {
29
- const j = judgeMoveTwinSpace({ ...CLEAN, toSpaceExists: false })
30
- assert.equal(j.refusal?.code, 'space-not-found')
31
- assert.equal(j.refusal?.params?.spaceId, 'rosarito-site')
32
- })
33
-
34
- test('같은 현장으로 옮기는 것은 거절한다 — 할 일이 없는데 쓴 것처럼 답하지 않는다', () => {
35
- const j = judgeMoveTwinSpace({ ...CLEAN, toSpaceId: 'wms-a-site' })
36
- assert.equal(j.refusal?.code, 'same-space')
37
- })
38
-
39
- test('없는 트윈은 거절한다', () => {
40
- const j = judgeMoveTwinSpace({ ...CLEAN, instanceId: undefined })
41
- assert.equal(j.refusal?.code, 'twin-not-found')
42
- })
43
-
44
- test('벤치 사본은 옮기지 않는다 — 무엇의 측정인지 말할 수 없게 된다', () => {
45
- const j = judgeMoveTwinSpace({ ...CLEAN, purpose: 'bench' })
46
- assert.equal(j.refusal?.code, 'bench-copy')
47
- })
48
-
49
- test('현장이 없던 트윈도 옮길 수 있다 — 옛 트윈을 고칠 길을 막지 않는다', () => {
50
- const j = judgeMoveTwinSpace({ ...CLEAN, fromSpaceId: undefined, fromTimezone: undefined, toTimezone: undefined })
51
- assert.equal(j.refusal, undefined)
52
- })
53
-
54
- test('새 공간에 없는 구역을 가리키는 로케이션은 소속이 끊긴다고 말한다', () => {
55
- const j = judgeMoveTwinSpace({
56
- ...CLEAN,
57
- areaRefs: ['bldg-1', 'floor-2', undefined, 'bldg-1', ''],
58
- toAreaIds: ['floor-2']
59
- })
60
- const w = j.warnings.find(x => x.code === 'areas-left-behind')
61
- assert.ok(w, '끊기는 소속을 말해야 한다')
62
- assert.equal(w.params?.count, 1, '중복·빈 값은 세지 않는다')
63
- assert.equal(w.params?.areas, 'bldg-1')
64
- assert.equal(j.refusal, undefined, '막지는 않는다 — 새 공간에서 구역을 다시 그리는 것이 정상이다')
65
- })
66
-
67
- test('구역이 모두 새 공간에 있으면 그 경고는 없다', () => {
68
- const j = judgeMoveTwinSpace({ ...CLEAN, areaRefs: ['bldg-1'], toAreaIds: ['bldg-1', 'floor-2'] })
69
- assert.equal(j.warnings.find(x => x.code === 'areas-left-behind'), undefined)
70
- })
71
-
72
- test('시간대가 다르면 말한다 — 같은 저널이 다른 시각으로 읽힌다', () => {
73
- const j = judgeMoveTwinSpace({ ...CLEAN, fromTimezone: 'Asia/Seoul', toTimezone: 'America/Los_Angeles' })
74
- const w = j.warnings.find(x => x.code === 'timezone-differs')
75
- assert.ok(w)
76
- assert.equal(w.params?.from, 'Asia/Seoul')
77
- assert.equal(w.params?.to, 'America/Los_Angeles')
78
- })
79
-
80
- test('시간대를 선언하지 않은 공간도 다름으로 센다 — 모르는 것을 같다고 하지 않는다', () => {
81
- const j = judgeMoveTwinSpace({ ...CLEAN, fromTimezone: 'Asia/Seoul', toTimezone: undefined })
82
- assert.ok(j.warnings.find(x => x.code === 'timezone-differs'))
83
- })
84
-
85
- test('옛 공간의 표현은 남는다고 말한다 — 그 화면에서 이 트윈이 사라진다', () => {
86
- const j = judgeMoveTwinSpace({ ...CLEAN, fromRepresentationCount: 3 })
87
- const w = j.warnings.find(x => x.code === 'representations-left-behind')
88
- assert.ok(w)
89
- assert.equal(w.params?.count, 3)
90
- assert.equal(w.params?.spaceId, 'wms-a-site')
91
- })
92
-
93
- test('실행 중 + 시간대 변화면 재기동 뒤에 적용된다고 말한다', () => {
94
- const j = judgeMoveTwinSpace({ ...CLEAN, running: true, fromTimezone: 'Asia/Seoul', toTimezone: 'UTC' })
95
- assert.ok(j.warnings.find(x => x.code === 'running'))
96
- })
97
-
98
- test('실행 중이지만 시간대가 같으면 말할 것이 없다 — 없는 걱정을 만들지 않는다', () => {
99
- const j = judgeMoveTwinSpace({ ...CLEAN, running: true })
100
- assert.equal(j.warnings.find(x => x.code === 'running'), undefined)
101
- })
102
-
103
- test('거절이면 경고를 함께 내지 않는다 — 일어나지 않을 일을 설명하지 않는다', () => {
104
- const j = judgeMoveTwinSpace({
105
- ...CLEAN,
106
- toSpaceExists: false,
107
- areaRefs: ['bldg-1'],
108
- toAreaIds: [],
109
- fromRepresentationCount: 2,
110
- fromTimezone: 'Asia/Seoul',
111
- toTimezone: 'UTC'
112
- })
113
- assert.ok(j.refusal)
114
- assert.deepEqual(j.warnings, [])
115
- })
116
-
117
- /* ── 현장에서 떼기 ─────────────────────────────────────────────────────────── */
118
-
119
- test('현장이 없는 트윈은 뗄 것이 없다 — 아무 일도 없는데 했다고 답하지 않는다', () => {
120
- const j = judgeDetachTwinSpace({ instanceId: 'wms-a', fromSpaceId: undefined })
121
- assert.equal(j.refusal?.code, 'no-space')
122
- })
123
-
124
- test('벤치 사본은 떼지 않는다 — 무엇의 측정인지 말할 수 없게 된다', () => {
125
- const j = judgeDetachTwinSpace({ instanceId: 'bench-1', fromSpaceId: 'rosarito-site', purpose: 'bench' })
126
- assert.equal(j.refusal?.code, 'bench-copy')
127
- })
128
-
129
- test('떼면 볼 무대가 없어진다고 반드시 말한다 — 사용자가 고장으로 읽지 않게', () => {
130
- const j = judgeDetachTwinSpace({ instanceId: 'wms-a', fromSpaceId: 'rosarito-site' })
131
- assert.equal(j.refusal, undefined)
132
- assert.ok(j.warnings.find(w => w.code === 'no-stage'), '무대가 없어진다는 말은 언제나 있다')
133
- })
134
-
135
- test('옛 현장의 표현과 시간 기준을 말한다 — 남는 것을 밝힌다', () => {
136
- const j = judgeDetachTwinSpace({
137
- instanceId: 'wms-a',
138
- fromSpaceId: 'rosarito-site',
139
- fromRepresentationCount: 2,
140
- fromTimezone: 'America/Los_Angeles'
141
- })
142
- assert.equal(j.warnings.find(w => w.code === 'representations-left-behind')?.params?.count, 2)
143
- assert.equal(j.warnings.find(w => w.code === 'timebase-kept')?.params?.timezone, 'America/Los_Angeles')
144
- })
145
-
146
- test('시간대를 선언하지 않은 현장이면 시간 기준을 말하지 않는다 — 없는 사실을 만들지 않는다', () => {
147
- const j = judgeDetachTwinSpace({ instanceId: 'wms-a', fromSpaceId: 'rosarito-site' })
148
- assert.equal(j.warnings.find(w => w.code === 'timebase-kept'), undefined)
149
- })
@@ -1,122 +0,0 @@
1
- /*
2
- * 뮤테이션 게이트 가드 — **트윈을 바꾸는 문은 전부 잠겨 있다.**
3
- *
4
- * ── 계기 (2026-08-06) ──────────────────────────────────────────────────────
5
- * 권한 모델을 손대며 세어 보니 트윈 뮤테이션 24개 중 **22개에 게이트가 없었다.** 인스턴스 삭제와
6
- * 레퍼런스 자격정보 저장까지 로그인만 하면 누구나 부를 수 있었다. 발견은 사람 눈이었다 — 즉
7
- * 25번째 뮤테이션이 게이트 없이 들어오면 아무것도 잡지 못한다. 그래서 기계가 센다.
8
- *
9
- * ── 왜 문자열을 그대로 비교하나 ─────────────────────────────────────────────
10
- * "게이트가 있나" 만 보면 `domainOwnerGranted: false` 로 약해지거나 category 가 다른 값으로 갈라져도
11
- * 통과한다. 게이트는 **한 문장이어야** 서버·클라·관리 화면이 같은 권한을 말한다. 그래서 정본 문장과
12
- * 글자까지 같은지 본다.
13
- *
14
- * ── 조회는 왜 검사하지 않나 (ADR-0027) ──────────────────────────────────────
15
- * 조회에는 게이트를 두지 않기로 했다 — `twinKpi` 가 같은 판정을 게이트 없이 이미 내주므로, 일부
16
- * 조회만 잠그면 보안이 아니라 화면 고장이 된다. 이 결정이 바뀌면 아래 "정본 문장" 검사가 먼저
17
- * 깨진다. 그때는 테스트를 고치지 말고 **ADR 을 먼저 고친다.**
18
- */
19
- import { test } from 'node:test'
20
- import assert from 'node:assert/strict'
21
- import { readdirSync, readFileSync, statSync } from 'node:fs'
22
- import { join } from 'node:path'
23
-
24
- /** 정본 게이트 — 트윈을 **바꾸는** 모든 작업이 요구하는 단 하나의 권한. */
25
- const GATE =
26
- `@Directive('@privilege(category: "twin", privilege: "mutation", ` + `domainOwnerGranted: true, superUserGranted: true)')`
27
-
28
- /**
29
- * 두 번째 게이트 — **테넌트를 넘어 읽는 운영 계기판** (ADR-0027 예외, 2026-08-07).
30
- *
31
- * ADR-0027 의 전제는 "읽기의 경계는 테넌트 소속" 이라 조회에는 게이트를 붙이지 않는다. 그런데 프로세스
32
- * 부하 계기판(`twinLoad`)은 이벤트 루프가 프로세스 공유이므로 **일부러 전 테넌트를 합산한다** — 소속이
33
- * 경계가 되지 못한다. 그래서 시스템 소유만 본다. **권한 이름을 만들지 않았다**(category·privilege 없음).
34
- *
35
- * 늘리지 말 것. 조건은 ADR-0027 의 예외 절에 있고, 셋 중 하나라도 아니면 조회 무게이트가 그대로다.
36
- */
37
- const OPS_GATE = `@Directive('@privilege(superUserGranted: true)')`
38
-
39
- const ALLOWED = [GATE, OPS_GATE]
40
-
41
- const SERVER = new URL('../server', import.meta.url).pathname
42
-
43
- function walk(dir: string, out: string[] = []): string[] {
44
- let entries: string[]
45
- try {
46
- entries = readdirSync(dir)
47
- } catch {
48
- return out
49
- }
50
- for (const e of entries) {
51
- const p = join(dir, e)
52
- if (statSync(p).isDirectory()) walk(p, out)
53
- else if (p.endsWith('.ts') && !p.endsWith('.d.ts')) out.push(p)
54
- }
55
- return out
56
- }
57
-
58
- /**
59
- * `@Mutation` 위에 붙은 데코레이터·주석 덩이를 거꾸로 모은다.
60
- *
61
- * 데코레이터가 바로 붙어 있다고 가정하지 않는다 — 나중에 다른 데코레이터가 끼어들어도 게이트를
62
- * 찾아야 한다. 덩이의 끝은 코드(다른 메서드의 `}` 등)를 만나는 자리다.
63
- */
64
- function decoratorBlockAbove(lines: string[], at: number): string[] {
65
- const block: string[] = []
66
- for (let i = at - 1; i >= 0; i--) {
67
- const t = lines[i].trim()
68
- if (!t) continue /* 주석과 데코레이터 사이의 빈 줄은 덩이를 끊지 않는다 */
69
- const isBlockPart = t.startsWith('@') || t.startsWith('*') || t.startsWith('/*') || t.startsWith('//')
70
- if (!isBlockPart) break
71
- block.push(t)
72
- }
73
- return block
74
- }
75
-
76
- const files = walk(SERVER)
77
-
78
- test('트윈을 바꾸는 뮤테이션은 전부 정본 게이트를 달고 있다', () => {
79
- const ungated: string[] = []
80
- let mutations = 0
81
-
82
- for (const f of files) {
83
- const lines = readFileSync(f, 'utf-8').split('\n')
84
- lines.forEach((line, i) => {
85
- if (!line.trim().startsWith('@Mutation')) return
86
- mutations++
87
- if (!decoratorBlockAbove(lines, i).some(l => l === GATE)) {
88
- /* 어느 뮤테이션인지 이름으로 말한다 — 줄번호만 주면 고치는 사람이 다시 찾아야 한다. */
89
- const name = (lines.slice(i, i + 6).join(' ').match(/async\s+(\w+)/) ?? [, '?'])[1]
90
- ungated.push(`${f.split('/').slice(-2).join('/')}:${i + 1} ${name}`)
91
- }
92
- })
93
- }
94
-
95
- /* 훑기가 망가져 0건이 되면 "위반 없음" 으로 보인다 — 그 거짓 통과를 막는다. */
96
- assert.ok(mutations >= 20, `뮤테이션을 ${mutations}개만 찾았다 — 소스 훑기가 망가졌다`)
97
- assert.deepEqual(
98
- ungated,
99
- [],
100
- `게이트 없는 뮤테이션 ${ungated.length}건 — 로그인만 하면 누구나 부를 수 있다:\n${ungated.join('\n')}`
101
- )
102
- })
103
-
104
- test('권한 문장이 하나로 통일되어 있다 — 약해지거나 서로 어긋나지 않았다', () => {
105
- const odd: string[] = []
106
- for (const f of files) {
107
- readFileSync(f, 'utf-8')
108
- .split('\n')
109
- .forEach((line, i) => {
110
- const t = line.trim()
111
- if (!t.startsWith("@Directive('@privilege")) return
112
- if (!ALLOWED.includes(t)) odd.push(`${f.split('/').slice(-2).join('/')}:${i + 1} ${t}`)
113
- })
114
- }
115
- assert.deepEqual(
116
- odd,
117
- [],
118
- `정본과 다른 권한 문장 ${odd.length}건. 쓰기는 GATE 하나, 테넌트를 넘어 읽는 운영 계기판만 ` +
119
- `OPS_GATE. 그 밖으로 늘리는 것이 의도라면 ADR-0027 을 먼저 고치고 이 검사의 정본을 함께 옮긴다:` +
120
- `\n${odd.join('\n')}`
121
- )
122
- })
@@ -1,204 +0,0 @@
1
- /*
2
- * ★ OEE 이벤트 누적기 검증 — equipment.status 스트림으로 카운터 근사 생산 → computeOee.
3
- * live 가 실 텔레메트리 없이도 OEE 를 근사 산출하는 경로(face2-inbound-live §1.1 option ②).
4
- * 정확 검증: downMs(고장 시간) == sim, busyMs == sim(run+setup). 근사 한계 명시: quality=1(good/scrap 이벤트 부재).
5
- */
6
- import { test } from 'node:test'
7
- import assert from 'node:assert/strict'
8
-
9
- import { WmsKernel, StateProjector } from '@operato/twin-kernel'
10
- import { masterToTwin } from '../server/service/reference/reference-master.ts'
11
- import { buildEntityDeltas } from '../shared/entity-delta.ts'
12
- import { OeeAccumulator, withLiveOee } from '../server/engine/oee-accumulator.ts'
13
-
14
- const BASE_EPOCH = Date.parse('2026-01-01T00:00:00Z') // 커널 now() 고정 오프셋(flow-engine BASE_EPOCH)
15
- const GTIN = 'urn:epc:idpat:sgtin:0614141.099999.*'
16
- const TICK = 1000
17
-
18
- function runSimCollect() {
19
- const m = {
20
- source: 'oee', system: 'wms' as const, siteName: 'O',
21
- /* 이 픽스처가 식별자를 만드는 이름공간 — **픽스처마다 다르게** 둔다(같은 접두 아래에서 서로 다른
22
- 시험의 번호가 부딪치면 표준의 유일성 요구를 깬다, CBV 2.0 §8.2.4). 커널은 선언 없이 팔레트·문서를
23
- 만들지 않는다(0.7.45 에서 날조 프리픽스를 지웠다). */
24
- identity: { namespaces: ['https://twin.test/oee-accumulator'] },
25
- space: { width: 90, depth: 40, unit: 'm' },
26
- locations: [
27
- { id: 'a', type: 'warehouse', role: 'area' as const },
28
- { id: 'dock-recv', type: 'dock', role: 'location' as const, capacity: 100 },
29
- { id: 'rack-1', type: 'storage', role: 'location' as const, capacity: 60 },
30
- { id: 'staging', type: 'staging', role: 'location' as const, capacity: 80 },
31
- { id: 'dock-ship', type: 'dock-ship', role: 'location' as const, capacity: 100 }
32
- ],
33
- equipment: [{ id: 'fk-1', kind: 'forklift', homeLocationId: 'dock-recv', mtbfMs: 5000, mttrMs: 8000 }]
34
- }
35
- const model = masterToTwin(m).model
36
- const k = new WmsKernel('t')
37
- const events: any[] = []
38
- k.onEvent((e: any) => events.push(e))
39
- k.loadTwinModel(model)
40
- k.scenario.load({ seed: 9, generators: [{ kind: 'inbound-arrival', rate: { distribution: 'constant', meanPerHour: 300 }, content: { skuMix: [{ gtin: GTIN, weight: 1 }], qtyPerLine: { min: 1, max: 1 } } }] })
41
- k.scenario.start()
42
- for (let i = 0; i < 200; i++) k.tick(TICK)
43
- return { events, snap: k.getSnapshot() as any, model }
44
- }
45
-
46
- test('★ OEE 누적기: downMs 정확 · busyMs=run+setup · 근사 OEE 유효', () => {
47
- const { events, snap } = runSimCollect()
48
- const simOee = snap.equipment.find((x: any) => x.id === 'fk-1')?.oee
49
- assert.ok(simOee, 'sim fk-1 oee 존재')
50
- assert.ok(simOee.downMs > 0, '시나리오가 고장(down) 유발 — 검증 의미 있음')
51
-
52
- const acc = new OeeAccumulator()
53
- for (const e of events) acc.apply(e)
54
- const nowMs = BASE_EPOCH + snap.simClockMs
55
- const c = acc.counters('fk-1', nowMs)
56
-
57
- // 정확: downMs(고장 시간) — 이벤트 down 구간 합 == sim(tick 누적). availability 핵심 입력. tick 경계 오차 ≤ 1 tick.
58
- assert.ok(Math.abs(c.downMs - simOee.downMs) <= TICK, `downMs 정확 (acc ${c.downMs} vs sim ${simOee.downMs})`)
59
- // busyMs ≈ run+setup, 단 **진행중 task 작업분 포함**(runMs 는 완료분만 누적) → busyMs ≥ 완료 run+setup.
60
- // 이벤트로 setup 분리 불가라 busy 를 run 으로 근사. 한 task 규모의 초과는 정상(진행중분).
61
- const completed = simOee.runMs + simOee.setupMs
62
- assert.ok(c.runMs >= completed - TICK, `busyMs ≥ 완료 run+setup (acc ${c.runMs} vs sim ${completed})`)
63
- assert.ok(c.runMs - completed <= 30000, `초과분(진행중 task)이 task 규모 이내 (${c.runMs - completed})`)
64
-
65
- // 근사 OEE 유효 + 한계 명시.
66
- const oee = acc.oee('fk-1', nowMs)
67
- /*
68
- * 총합은 **없을 수 있다.** 표준 시간(PRI)이 없으면 성능률이 안 나오고, 그러면 곱도 안 나온다
69
- * (계약 0.5.0, ISO 22400 대조). 누적기는 사건에서 표준 시간을 알 수 없으므로 여기서는 없는 것이 정상이다.
70
- *
71
- * 예전에는 근거 없이 1 을 내서 총합이 늘 값을 가졌다. 그때 이 단언은 아무것도 지키지 않았다.
72
- */
73
- if (oee.overall === undefined) {
74
- assert.ok(oee.missing?.includes('planned-run-time-per-item'), `총합이 없으면 이유가 있어야 한다: ${JSON.stringify(oee.missing)}`)
75
- } else {
76
- assert.ok(oee.overall >= 0 && oee.overall <= 1, 'OEE overall ∈ [0,1]')
77
- }
78
- assert.ok((oee.availability as number) >= 0 && (oee.availability as number) <= 1, 'availability ∈ [0,1]')
79
- /*
80
- * WMS 는 품질 개념이 없어 산출을 기록하지 않는다. 만든 것이 없으면 양품률은 **모름**이다.
81
- * 예전에는 1 을 냈고, 그래서 품질을 재지도 않는 창고 설비가 「품질 100%」로 보였다.
82
- */
83
- assert.equal(oee.quality, undefined, 'WMS 는 산출 기록이 없으므로 양품률은 모름이다')
84
- assert.ok(oee.missing?.includes('produced-quantity'))
85
- })
86
-
87
- test('★ OEE 누적기: quality.output 델타 소비 → quality 정확 (good/scrap 도출)', () => {
88
- const acc = new OeeAccumulator()
89
- const T0 = Date.parse('2026-01-01T00:00:00Z')
90
- const ev = (ms: number, type: string, data: any): any => ({ eventId: 'x', eventType: type, eventTime: new Date(T0 + ms).toISOString(), tenantId: 't', data })
91
-
92
- acc.apply(ev(0, 'equipment.status', { moverId: 'w1', status: 'busy' }))
93
- acc.apply(ev(1000, 'quality.output', { moverId: 'w1', good: false, goodCount: 0, nonconformingCount: 1 }))
94
- acc.apply(ev(2000, 'quality.output', { moverId: 'w1', good: true, goodCount: 8, nonconformingCount: 2 })) // 누적값 최신화
95
- acc.apply(ev(3000, 'equipment.status', { moverId: 'w1', status: 'idle' }))
96
-
97
- const c = acc.counters('w1', T0 + 4000)
98
- assert.equal(c.goodCount, 8, 'goodCount 추적(누적 최신)')
99
- assert.equal(c.nonconformingCount, 2, 'nonconformingCount 추적')
100
- const oee = acc.oee('w1', T0 + 4000)
101
- assert.ok(Math.abs(oee.quality - 0.8) < 1e-9, 'quality = good/(good+scrap) = 0.8 (텔레메트리 없이 이벤트로 도출)')
102
- })
103
-
104
- test('★ withLiveOee: projector 미러(oee 없음) + 누적기 → live 설비 payload 에 oee 포함 (원 갭 종료)', () => {
105
- const { events, model } = runSimCollect()
106
- const proj = new StateProjector(model)
107
- const acc = new OeeAccumulator()
108
- for (const e of events) { proj.apply(e); acc.apply(e) }
109
-
110
- const rawLive = proj.snapshot() as any
111
- // 원 갭: projector 미러 설비엔 oee 없음.
112
- assert.equal(rawLive.equipment.find((m: any) => m.id === 'fk-1')?.oee, undefined, 'projector 미러엔 oee 부재(원 갭)')
113
-
114
- // withLiveOee 로 보강 → buildEntityDeltas payload 에 oee 포함(sim 과 동일 형상 = 보드 OEE 컴포넌트 live 렌더).
115
- const enriched = withLiveOee(rawLive, acc)
116
- const fk = buildEntityDeltas(enriched, 't1').find(d => d.tag === 'fk-1')!.data as any
117
- assert.ok(fk.oee, 'withLiveOee 후 설비 data(tag) payload 에 oee 포함 — live OEE 갭 종료')
118
- // buildEntityDeltas shapeOee = 정수 퍼센트(0-100), raw ms 제외.
119
- assert.ok(fk.oee.overall >= 0 && fk.oee.overall <= 100, 'oee.overall ∈ [0,100] 정수 퍼센트')
120
- assert.ok(fk.oee.availability < 100, 'availability < 100 (고장 시간 반영 — 누적기 downMs)')
121
- })
122
-
123
- /*
124
- * ── 되짚은 화면에도 가동 이력이 있어야 한다 (2026-08-05) ────────────────────
125
- * OEE 는 원 시스템이 누적을 보내 주지 않아 호스트가 상태 전이를 적분해 만든다. 그런데 그 누적기는
126
- * **라이브에서만** 돌았고, 저널을 계산하는 경로는 그 계산을 하지 않았다 — 과거를 되짚으면 모든 설비가
127
- * "가동 이력이 전혀 없음" 으로 보였다(실 저널: `rosarito-mes` 18대, `hatiolab-wms` 22대가 그랬다).
128
- *
129
- * 없는 것은 데이터가 아니라 계산이다: 입력은 저널에 다 있다. 그래서 같은 누적기에 같은 이벤트를
130
- * 태운다 — 이 테스트는 그 재계산이 라이브와 **같은 값**을 내는지, 그리고 시간여행에서 **그 시점까지만**
131
- * 세는지를 못 박는다.
132
- */
133
- test('★ 저널을 다시 태우면 라이브와 같은 계측이 나온다 — 규칙이 하나이므로', () => {
134
- const T0 = Date.parse('2026-08-05T00:00:00.000Z')
135
- const ev = (ms: number, id: string, status: string) => ({
136
- eventId: `e${ms}`,
137
- eventType: 'equipment.status',
138
- eventTime: new Date(T0 + ms).toISOString(),
139
- tenantId: 't',
140
- data: { equipmentId: id, moverId: id, status }
141
- })
142
- const stream = [ev(0, 'fk-1', 'idle'), ev(10_000, 'fk-1', 'busy'), ev(40_000, 'fk-1', 'down'), ev(70_000, 'fk-1', 'idle')]
143
-
144
- /* 라이브 — 이벤트가 도착하는 대로 누적. */
145
- const live = new OeeAccumulator()
146
- for (const e of stream) live.apply(e as any)
147
-
148
- /* 되짚기 — 저널에서 같은 순서로 다시 태운다. */
149
- const replayed = new OeeAccumulator()
150
- for (const e of stream) replayed.apply(e as any)
151
-
152
- const at = T0 + 70_000
153
- assert.deepEqual(replayed.oee('fk-1', at), live.oee('fk-1', at), '같은 이벤트·같은 시점이면 같은 값이어야 한다')
154
- assert.equal(replayed.oee('fk-1', at).downMs, 30_000, '고장 30초가 잡혀야 한다')
155
- })
156
-
157
- test('★ 시간여행은 그 시점까지만 센다 — 뒤에 일어난 고장이 과거 화면에 섞이지 않게', () => {
158
- const T0 = Date.parse('2026-08-05T00:00:00.000Z')
159
- const ev = (ms: number, status: string) => ({
160
- eventId: `e${ms}`,
161
- eventType: 'equipment.status',
162
- eventTime: new Date(T0 + ms).toISOString(),
163
- tenantId: 't',
164
- data: { equipmentId: 'fk-1', moverId: 'fk-1', status }
165
- })
166
- const all = [ev(0, 'busy'), ev(30_000, 'down'), ev(60_000, 'idle')]
167
-
168
- /* 30초 시점까지만 태운다(호스트가 잘라 낸 이벤트만 태우는 것과 같다). */
169
- const past = new OeeAccumulator()
170
- for (const e of all.slice(0, 2)) past.apply(e as any)
171
- assert.equal(past.oee('fk-1', T0 + 30_000).downMs, 0, '아직 고장이 시작된 시점 — 고장 시간은 0 이다')
172
-
173
- const now = new OeeAccumulator()
174
- for (const e of all) now.apply(e as any)
175
- assert.equal(now.oee('fk-1', T0 + 60_000).downMs, 30_000, '지금 화면에서는 고장 30초가 잡힌다')
176
- })
177
-
178
- test('★ 계측 시점을 벽시계로 재지 않는다 — 과거 화면의 가용률이 시간이 갈수록 떨어지지 않게', () => {
179
- const T0 = Date.parse('2026-08-05T00:00:00.000Z')
180
- const acc = new OeeAccumulator()
181
- acc.apply({ eventId: 'e1', eventType: 'equipment.status', eventTime: new Date(T0).toISOString(), tenantId: 't', data: { equipmentId: 'fk-1', moverId: 'fk-1', status: 'busy' } } as any)
182
- const atThen = acc.oee('fk-1', T0 + 10_000)
183
- const atMuchLater = acc.oee('fk-1', T0 + 10_000_000)
184
- assert.notDeepEqual(atThen, atMuchLater, '시점을 넘기면 값이 달라진다 — 그래서 그 화면의 시각을 넘겨야 한다')
185
- })
186
-
187
- /*
188
- * ★ 못 본 설비의 계측 창 — **없으면 없다고 한다.**
189
- *
190
- * 예전에는 `metricsSinceMs: 0` 을 돌려줬다. 시각이 epoch 밀리초라서 그 창은 곧 "1970년부터" 가 되고,
191
- * 공식의 분모가 지금 시각 전체가 된다 — 화면에 `idleMs 1767226603000`(약 56,000년) 유휴가 섰다.
192
- * 그 값은 availability·overall 의 분모이기도 해서 **성과 숫자 전체가 알리지 않고 거짓**이 됐다.
193
- */
194
- test('이벤트를 못 본 설비는 계측 창을 만들지 않는다 — epoch 를 창으로 삼지 않는다', () => {
195
- const acc = new OeeAccumulator()
196
- const c = acc.counters('never-seen', Date.parse('2026-01-01T00:00:00.000Z'))
197
- assert.equal(c.metricsSinceMs, undefined, '모르는 창을 0 으로 메우면 1970년부터 쟀다는 말이 된다')
198
-
199
- /*
200
- * 그다음(창이 없을 때 유휴는 0)은 **공식의 책임**이고 공식은 커널에 있다 — 커널의
201
- * `test/oee-window` 가 못 박는다. 여기서 그 결과까지 단정하면 이 검사는 커널 발행 시점에
202
- * 묶이고, 남의 책임을 자기 검사에 넣은 것이 된다.
203
- */
204
- })