@things-factory/headless-twin 10.1.277 → 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,286 +0,0 @@
1
- /*
2
- * ★ 라이브 미러 시임 — projector→payload vs 커널→payload (sim↔live).
3
- * P0(live-모드 런타임, face2-inbound-live) 디리스크. 같은 이벤트를 두 드라이버에 넣고 data(tag) payload 를 비교.
4
- *
5
- * 결론(검증됨):
6
- * - 핵심 관측 상태(점유·용량·위치·아이템 = "사진에 찍힌 것")는 이벤트만으로 재구성 → sim↔live **완전 일치**.
7
- * - 파생 지표(설비 OEE·location status = "계산해서 만든 통계")는 이벤트에 없음 → live 미러엔 **부재**.
8
- * 이는 라우팅 결함이 아니라(통로는 온전), live 에서 파생 지표를 **누가 생산하나**의 데이터원 결정 사항.
9
- * (실 텔레메트리 / projector 계산 / 별도 분석 층 — face2-inbound-live §6, reference-management P3.)
10
- */
11
- import { test } from 'node:test'
12
- import assert from 'node:assert/strict'
13
-
14
- import { WmsKernel, StateProjector, deriveAttentions } from '@operato/twin-kernel'
15
- /* OEE 공식은 계약에 있다 — 시뮬·미러·MES 셋이 같은 것을 부른다. */
16
- import { computeOee } from '@operato/ops-contract'
17
- import { masterToTwin } from '../server/service/reference/reference-master.ts'
18
- import { buildEntityDeltas } from '../shared/entity-delta.ts'
19
- import { withLiveAttentions } from '../server/engine/live-attentions.ts'
20
-
21
- const GTIN = 'urn:epc:idpat:sgtin:0614141.099999.*'
22
-
23
- const master = () => ({
24
- source: 'mirror',
25
- system: 'wms' as const,
26
- siteName: 'M',
27
- /* 이 픽스처가 식별자를 만드는 이름공간 — **픽스처마다 다르게** 둔다(같은 접두 아래에서 서로 다른
28
- 시험의 번호가 부딪치면 표준의 유일성 요구를 깬다, CBV 2.0 §8.2.4). 커널은 선언 없이 팔레트·문서를
29
- 만들지 않는다(0.7.45 에서 날조 프리픽스를 지웠다). */
30
- identity: { namespaces: ['https://twin.test/live-mirror-parity'] },
31
- space: { width: 90, depth: 40, unit: 'm' },
32
- locations: [
33
- { id: 'a-dc', type: 'warehouse', role: 'area' as const, name: '창고' },
34
- { id: 'dock-recv', type: 'dock', role: 'location' as const, capacity: 100 },
35
- { id: 'rack-1', type: 'storage', role: 'location' as const, capacity: 60 },
36
- { id: 'rack-2', type: 'storage', role: 'location' as const, capacity: 60 },
37
- { id: 'staging', type: 'staging', role: 'location' as const, capacity: 80 },
38
- { id: 'dock-ship', type: 'dock-ship', role: 'location' as const, capacity: 100 }
39
- ],
40
- equipment: [{ id: 'fk-1', kind: 'forklift', homeLocationId: 'dock-recv' }]
41
- })
42
-
43
- /** 커널 sim 구동 + 방출 이벤트 수집(커널 face2 테스트 패턴). */
44
- function runSim() {
45
- const model = masterToTwin(master()).model
46
- const kernel = new WmsKernel('t')
47
- const events: any[] = []
48
- kernel.onEvent((e: any) => events.push(e))
49
- kernel.loadTwinModel(model)
50
- kernel.scenario.load({ seed: 42, generators: [{ kind: 'inbound-arrival', rate: { distribution: 'constant', meanPerHour: 120 }, content: { skuMix: [{ gtin: GTIN, weight: 1 }], qtyPerLine: { min: 1, max: 1 } } }] })
51
- kernel.scenario.start()
52
- for (let i = 0; i < 300; i++) kernel.tick(1000)
53
- kernel.scenario.pause()
54
- for (let i = 0; i < 60; i++) kernel.tick(1000)
55
- return { model, kernel, events }
56
- }
57
-
58
- const sortByTag = (arr: any[]) => [...arr].sort((a, b) => (a.tag < b.tag ? -1 : a.tag > b.tag ? 1 : 0))
59
-
60
- /** 파생/sim-계산 필드 제거 → "핵심 관측 상태"만 남긴다.
61
- * location.status = 커널 기본값(파생), equipment.oee = 커널 계산 지표(파생). 이벤트에 없어 live 미러 부재. */
62
- /**
63
- * 설계상 두 구동이 다른 자리만 걷어낸다 — **여기 없는 차이는 결함이다.**
64
- *
65
- * 엔티티 마커가 `kind` → `entity` 로 바뀌었을 때(도메인 kind 를 마커가 덮어쓰던 문제) 이 필터가
66
- * 따라가지 못해 **아무것도 걸러내지 못하고 있었다.** 그래서 실패가 "정합성 결함" 처럼 보였다.
67
- *
68
- * 지금 남는 차이는 하나뿐이다:
69
- * · `oee` — 시뮬은 자기가 계측하고, 라이브는 **호스트**가 이벤트를 적분해 채운다(withLiveOee).
70
- * 커널 층에서만 비대칭이고 호스트가 닫는다(커널 적합성 하네스도 같은 예외를 선언한다).
71
- * · `__orders__.finished` — 「최근 T 완료」 창의 오른쪽 끝은 그 구동의 「지금」이다(ADR-0092). 시뮬은 시계,
72
- * 호스트의 미러는 관측 모드 커널이 마지막으로 들은 시각을 싣는다. 이 시험의 `StateProjector` 는 저널 재생용이라
73
- * 「지금」이 없고, 그래서 창을 싣지 않는다 — 0 으로 메우지 않는 것이 설계다. 창 수의 정합은 order-fold-host 시험이 본다.
74
- * (`location.status` 는 예외였다가 해소됐다 — 저장값이 아니라 포화도 파생이라 두 구동이 같은 값을 낸다.)
75
- */
76
- const coreOnly = (d: any) => {
77
- const c = { ...d }
78
- if (c.entity === 'equipment') delete c.oee
79
- if (c.entity === 'orders') delete c.finished
80
- return c
81
- }
82
-
83
- /** sim(커널) · live(projector 재투영) payload 를 태그로 정렬해 나란히. */
84
- function bothPayloads() {
85
- const { model, kernel, events } = runSim()
86
- assert.ok(events.length > 0, 'sim 이벤트 생성됨')
87
- const proj = new StateProjector(model)
88
- for (const env of events) proj.apply(env)
89
- return {
90
- sim: sortByTag(buildEntityDeltas(kernel.getSnapshot(), 't1')),
91
- live: sortByTag(buildEntityDeltas(proj.snapshot(), 't1'))
92
- }
93
- }
94
-
95
- test('라이브 미러: 엔티티 태그 집합 sim↔live 동일(모든 엔티티 미러)', () => {
96
- const { sim, live } = bothPayloads()
97
- assert.deepEqual(live.map(d => d.tag), sim.map(d => d.tag), '태그 집합 동일')
98
- })
99
-
100
- test('★ 라이브 미러: 핵심 관측 상태(점유·용량·위치·아이템) sim↔live 완전 일치', () => {
101
- const { sim, live } = bothPayloads()
102
- const simCore = sim.map(d => ({ tag: d.tag, data: coreOnly(d.data) }))
103
- const liveCore = live.map(d => ({ tag: d.tag, data: coreOnly(d.data) }))
104
- // 통로(라우팅)는 온전 — 이벤트로 재구성되는 관측 상태는 두 드라이버가 동일 → 모델이 동일 렌더.
105
- assert.deepEqual(liveCore, simCore, 'occupancy/capacity/location/item 등 핵심 관측 상태 일치')
106
- })
107
-
108
- /* 고장 주입(mtbf) + 소용량 랙(병목) + 고부하 — 파생 층(attentions·oee·motion·clock)을 최대 노출. 드레인 안 함. */
109
- function runSimRich() {
110
- const m = {
111
- source: 'rich', system: 'wms' as const, siteName: 'R',
112
- /* 같은 파일이라도 픽스처가 다르면 이름공간도 다르다 — 두 픽스처의 번호가 한 공간에서 겹치지 않게. */
113
- identity: { namespaces: ['https://twin.test/live-mirror-parity/rich'] },
114
- space: { width: 90, depth: 40, unit: 'm' },
115
- locations: [
116
- { id: 'a', type: 'warehouse', role: 'area' as const, name: '창고' },
117
- { id: 'dock-recv', type: 'dock', role: 'location' as const, capacity: 100 },
118
- { id: 'rack-1', type: 'storage', role: 'location' as const, capacity: 6 }, // 소용량 → 병목
119
- { id: 'staging', type: 'staging', role: 'location' as const, capacity: 80 },
120
- { id: 'dock-ship', type: 'dock-ship', role: 'location' as const, capacity: 100 }
121
- ],
122
- equipment: [
123
- { id: 'fk-1', kind: 'forklift', homeLocationId: 'dock-recv', mtbfMs: 5000, mttrMs: 8000 }, // 고장
124
- { id: 'fk-2', kind: 'forklift', homeLocationId: 'dock-recv' }
125
- ]
126
- }
127
- const model = masterToTwin(m).model
128
- const kernel = new WmsKernel('t')
129
- const events: any[] = []
130
- kernel.onEvent((e: any) => events.push(e))
131
- kernel.loadTwinModel(model)
132
- kernel.scenario.load({ seed: 7, generators: [{ kind: 'inbound-arrival', rate: { distribution: 'constant', meanPerHour: 600 }, content: { skuMix: [{ gtin: GTIN, weight: 1 }], qtyPerLine: { min: 1, max: 1 } } }] })
133
- kernel.scenario.start()
134
- for (let i = 0; i < 120; i++) kernel.tick(1000) // 이동중·고장·병목이 살아있는 시점
135
- const proj = new StateProjector(model)
136
- for (const env of events) proj.apply(env)
137
- return { sim: kernel.getSnapshot() as any, live: proj.snapshot() as any }
138
- }
139
-
140
- /*
141
- * ★ 명시(완전 목록): sim 이 "계산"하는 모든 파생 층은 live 미러에 부재/부분 — 라우팅 결함 아님(관측은 미러됨).
142
- * live 모드는 projector(관측) + 커널 derive 함수(계산 층) 로 이 층을 복원해야 한다(P0). face2-inbound-live §6.
143
- */
144
- test('명시: 파생 층(attentions·OEE·motion·clock)은 live 미러 부재/부분 — live derive 층 필요', () => {
145
- const { sim, live } = runSimRich()
146
-
147
- // 1) attentions(주목/알람) — 모니터링 핵심. projector 미계산 → live 부재. (현재 상태 순수함수라 재계산 가능.)
148
- assert.ok((sim.attentions?.length ?? 0) > 0, 'sim: attentions 계산됨(예: breakdown)')
149
- assert.equal(sim.attentions.length > 0 && (live.attentions?.length ?? 0), 0, 'live: attentions 부재 — computeAttentions 를 미러 State 에 재적용해야 복원')
150
-
151
- // 2) OEE(계산 지표) — 시간 누적. live 부재.
152
- const simFk = sim.equipment.find((x: any) => x.id === 'fk-1')
153
- const liveFk = live.equipment.find((x: any) => x.id === 'fk-1')
154
- assert.ok(simFk?.oee, 'sim: 설비 OEE 계산됨')
155
- assert.equal(liveFk?.oee, undefined, 'live: OEE 부재(시간 누적 지표)')
156
-
157
- // 3) simClockMs(sim 클럭) — live 는 실시간이 클럭원.
158
- assert.equal(typeof sim.simClockMs, 'number', 'sim: simClockMs 있음')
159
- assert.equal(live.simClockMs, undefined, 'live: sim 클럭 없음(실시간이 클럭원)')
160
-
161
- // 4) 관측 status 는 일치(이벤트 기반) — 라우팅/통로가 온전함의 재확인.
162
- assert.equal(simFk?.status, liveFk?.status, 'operable status 는 sim↔live 일치(관측)')
163
- // (motion 은 부분 재구성 — move 이벤트로 일부만. 완전 보간은 live derive 층 몫.)
164
- })
165
-
166
- /*
167
- * ★ derive 층 복원: sim/live 가 계산 층(deriveAttentions)을 공유 — 커널 함수를 projector 미러 State 에 재적용해
168
- * live 에 없던 관측기반 attentions(breakdown·bottleneck·hold)를 복원. (OEE 등 metric 층은 별도.)
169
- * → face2-inbound-live §1.1 "live = projector(관측) + derive 층(계산)" 을 attentions 로 실증.
170
- */
171
- test('★ derive 층: computeAttentions 를 projector 미러에 재적용 → 관측기반 attentions 복원', () => {
172
- const { sim, live } = runSimRich()
173
-
174
- // (a) 순수 함수가 커널 자체 attentions 를 재현 — 추출 정확성(sim state 로 호출 == 커널 계산 관측기반).
175
- const simDerivedKinds = new Set(deriveAttentions({ equipment: sim.equipment, locations: sim.locations, orders: sim.orders }).map(a => a.kind))
176
- for (const a of sim.attentions ?? []) {
177
- if (['breakdown', 'bottleneck', 'hold'].includes(a.kind)) {
178
- assert.ok(simDerivedKinds.has(a.kind), `순수 함수가 sim 관측기반 attention '${a.kind}' 재현`)
179
- }
180
- }
181
-
182
- // (b) ★ projector 미러 State 에 재적용 → live 원본엔 없던 attentions 복원.
183
- assert.equal(live.attentions?.length ?? 0, 0, 'live projector 원본엔 attentions 없음(계산 안 함)')
184
- const liveKinds = new Set(deriveAttentions({ equipment: live.equipment, locations: live.locations, orders: live.orders }).map(a => a.kind))
185
- assert.ok(liveKinds.has('breakdown') || liveKinds.has('bottleneck'),
186
- 'derive 재적용 → live 에 관측기반 attention(breakdown/bottleneck) 복원')
187
- })
188
-
189
- test('★ withLiveAttentions: projector 미러 스냅샷에 attentions 보강 (attention 질의 live 결선)', () => {
190
- const { live } = runSimRich()
191
- // 원 갭: projector 미러 스냅샷엔 attentions 없음.
192
- assert.equal(live.attentions?.length ?? 0, 0, 'projector 미러엔 attentions 부재')
193
- // 보강 → 스냅샷에 attentions(관측기반) 포함 → TwinEngine.snapshot(live) 이 이걸 질의에 노출.
194
- const enriched = withLiveAttentions(live)
195
- const kinds = new Set((enriched.attentions ?? []).map((a: any) => a.kind))
196
- assert.ok(kinds.has('breakdown') || kinds.has('bottleneck'), 'withLiveAttentions → 스냅샷 attentions 보강(sim 동형)')
197
- })
198
-
199
- /*
200
- * ★ OEE derive: attentions 와 달리 OEE 입력(누적 카운터)은 관측 State·이벤트에 없다 → 미러만으론 재계산 불가.
201
- * 그러나 **공식 computeOee 는 sim/live 공유** — live 가 카운터(실 텔레메트리 또는 이벤트 누적기)를 공급하면 재생산.
202
- * 이 테스트는 공식이 공급된 카운터로 sim OEE 를 재생산함을 증명(= 입력원만 결정하면 live OEE 성립).
203
- */
204
- test('★ OEE derive: 공유 공식 computeOee 가 공급된 카운터로 OEE 재생산 (live=텔레메트리/누적기 카운터 + 공식)', () => {
205
- const { sim } = runSimRich()
206
- const m = sim.equipment.find((x: any) => x.oee && (x.oee.runMs > 0 || x.oee.downMs > 0)) ?? sim.equipment.find((x: any) => x.oee)
207
- assert.ok(m?.oee, 'sim 무버 oee 존재')
208
- const o = m.oee
209
-
210
- /*
211
- * live 텔레메트리/누적기가 공급할 카운터 + **계측 창** 으로 공식 재적용.
212
- *
213
- * 창을 명시한다(`metricsSinceMs: 0` 부터 `planned` 까지). 예전 이 검사는 창을 넘기지 않고 공식이
214
- * 그것을 epoch(0)로 메우는 것에 **기대고** 있었다 — 그 메움이 화면에 56,000년 유휴를 세운 결함이라
215
- * 없앴다. 이제 창을 모르면 잰 시간이 없으므로, 재생산에는 창이 함께 와야 한다. 라이브 공급자가
216
- * 실제로 하는 일이 그것이다(누적기는 첫 이벤트 시각을 창으로 낸다).
217
- */
218
- const planned = o.runMs + o.setupMs + o.downMs + o.delayMs
219
- const derived = computeOee(
220
- { runMs: o.runMs, setupMs: o.setupMs, downMs: o.downMs, goodCount: o.goodCount, nonconformingCount: o.nonconformingCount, metricsSinceMs: 0 },
221
- planned
222
- )
223
- /* 세 비율은 근거가 없으면 없다 — 양쪽 다 없는 것도 재생산이다(계약 0.5.0). */
224
- const near = (a?: number, b?: number) => (a == null && b == null) || (a != null && b != null && Math.abs(a - b) < 1e-6)
225
- assert.ok(near(derived.availability, o.availability), `availability 재생산 (${derived.availability} vs ${o.availability})`)
226
- assert.ok(near(derived.performance, o.performance), 'performance 재생산')
227
- assert.ok(near(derived.quality, o.quality), 'quality 재생산')
228
- assert.ok(near(derived.overall, o.overall), 'overall 재생산')
229
- })
230
-
231
- /*
232
- * ── 배선 감시: 라이브가 커널에 **모든 채널을 넘기는가** ──────────────────────
233
- *
234
- * 규칙(deriveAttentions)은 커널 테스트가 지킨다. 지켜지지 않던 것은 **배선**이다 —
235
- * `withLiveAttentions` 가 채널 하나를 안 넘기면 같은 공장이 시뮬에서는 막혔다고 하고 라이브에서는
236
- * 멀쩡하다고 답한다. 규칙은 멀쩡하니 규칙 테스트는 통과하고, 어긋남은 아무 데서도 안 잡힌다.
237
- * (`tasks` 를 새로 넣을 때 실제로 그럴 뻔했다.)
238
- *
239
- * 그래서 채널마다 신호가 하나씩 나오는 상태를 만들고, **넷이 다 나오는지** 본다. 앞으로 채널이
240
- * 하나 더 늘고 라이브 배선만 빠지면 여기서 깨진다.
241
- */
242
- test('★ withLiveAttentions 는 채널을 하나도 떨어뜨리지 않는다(설비·자리·오더·작업)', () => {
243
- const state = {
244
- nowTime: '2026-03-02T12:00:00.000Z',
245
- equipment: [{ id: 'rbt-1', status: 'down', location: 'wc-1' }],
246
- locations: [{ id: 'wc-1', capacity: 2, occupancy: 2 }],
247
- orders: [{ id: 'ord-1', held: true, status: 'released' }],
248
- tasks: Array.from({ length: 8 }, (_, i) => ({ id: `t${i}`, kind: 'paint', status: 'created' }))
249
- }
250
- const kinds = new Set((withLiveAttentions(state as any).attentions ?? []).map((a: any) => a.kind))
251
- for (const expected of ['breakdown', 'bottleneck', 'hold', 'work-backlog'])
252
- assert.ok(kinds.has(expected), `라이브 배선이 '${expected}' 채널을 떨어뜨렸다 — 넘긴 것: ${[...kinds].join(', ') || '없음'}`)
253
- })
254
-
255
- /*
256
- * ── 되짚은 상태에도 신호가 있어야 한다 (2026-08-05) ────────────────────────
257
- * 라이브·시뮬은 커널이 신호를 스스로 내지만, 저널을 계산하는 경로는 프로젝터 상태만 낸다 — 신호 키가
258
- * 아예 없었다. 지도는 `snap.attentions` 를 읽으므로 **과거를 되짚으면 주의 레일이 텅 비었고**,
259
- * 기동돼 있지 않은 트윈을 보는 화면도 같았다. 실 저널로 재 보니 `rosarito-wms` 는 246건이 비어 있었다.
260
- *
261
- * 신호는 상태에서 계산되는 것이므로 같은 공식으로 채우면 된다(두 벌을 두지 않는다). 다만 "늦었나"
262
- * 판정이 `nowTime` 을 보므로 그 값이 먼저다 — 되짚은 시점의 정직한 "지금" 은 물어본 시각이고,
263
- * 벽시계를 끼워 넣으면 과거 화면이 "지금 기준으로 늦었다" 고 말한다.
264
- */
265
- test('★ 프로젝터 폴드 상태에는 신호 키가 없다 — 보강이 필요한 이유', () => {
266
- const { model, events } = runSim()
267
- const proj = new StateProjector(model)
268
- for (const env of events) proj.apply(env)
269
- const raw: any = proj.snapshot()
270
- assert.equal(raw.attentions, undefined, '계산한 상태는 신호를 스스로 내지 않는다(커널이 아니다)')
271
- })
272
-
273
- test('★ 보강하면 다시 계산한 상태에도 신호가 있다 — 지도의 주의 레일이 비지 않게', () => {
274
- /* 용량 1 자리를 채워 병목이 스스로 성립하게 만든다(신호를 손으로 넣지 않는다). */
275
- const st: any = {
276
- revision: 3,
277
- nowTime: '2026-08-05T00:00:00.000Z',
278
- locations: [{ id: 'bin-tight', type: 'storage', capacity: 1, occupancy: 1 }],
279
- equipment: [],
280
- orders: [],
281
- tasks: []
282
- }
283
- const out = withLiveAttentions(st)
284
- assert.ok((out.attentions ?? []).length > 0, '계산한 상태에서도 규칙이 신호를 낸다')
285
- assert.equal(out.attentions![0].kind, 'bottleneck')
286
- })
@@ -1,328 +0,0 @@
1
- /*
2
- * 부하 계기판 — **어떤 작업이 루프를 얼마나 쓰는지.**
3
- *
4
- * 지키는 것: ① 작업별로 따로 쌓인다 ② 무거운 것부터 나온다 ③ 몫이 합계와 맞는다 ④ 잰 적이 없으면
5
- * `null`(0 이 아니다) ⑤ 예산 초과를 세되 경고는 쿨다운을 둔다 ⑥ 경고 문구가 **무엇이 느린지** 말한다.
6
- *
7
- * ④가 특히 중요하다. 재지 않은 것을 0 으로 채우면 "0ms 다"(= 아주 빠르다)로 읽혀 **재지 않았다는 사실과
8
- * 정반대의 뜻**이 된다. 이 세션에서 같은 종류의 착각을 여러 번 겪었다 — 포트가 열렸다고 서버가 응답하는
9
- * 줄 알았던 것도 그것이다.
10
- */
11
- import { test } from 'node:test'
12
- import assert from 'node:assert/strict'
13
-
14
- import { LOAD_PHASES, fleetLoad, newCpuSampler, sampleCpu, judgeCycle, loadSummary, newLoadMeter, recordFork, recordPhase, rollWindow, slowTickMessage, TICK_BUDGET_RATIO, WARN_COOLDOWN_MS, WINDOW_MS } from '../server/engine/load-meter.ts'
15
-
16
- const TICK = 1000
17
-
18
- test('작업별로 따로 쌓이고, 무거운 것부터 나온다', () => {
19
- const m = newLoadMeter()
20
- recordPhase(m, 'tick', 300)
21
- recordPhase(m, 'tick', 500)
22
- recordPhase(m, 'snapshot', 100)
23
- recordPhase(m, 'publish', 20)
24
-
25
- const s = loadSummary(m, TICK)!.total!
26
- assert.deepEqual(s.phases.map(p => p.phase), ['tick', 'snapshot', 'publish'], '총 시간 순')
27
-
28
- const tick = s.phases[0]
29
- assert.equal(tick.count, 2)
30
- assert.equal(tick.lastMs, 500)
31
- assert.equal(tick.maxMs, 500)
32
- assert.equal(tick.avgMs, 400)
33
- assert.equal(tick.totalMs, 800)
34
- })
35
-
36
- test('몫이 잰 작업들의 합과 맞는다 — 어디를 고칠지 이 값이 정한다', () => {
37
- const m = newLoadMeter()
38
- recordPhase(m, 'tick', 750)
39
- recordPhase(m, 'snapshot', 250)
40
-
41
- const s = loadSummary(m, TICK)!.total!
42
- assert.equal(s.measuredTotalMs, 1000)
43
- assert.equal(s.phases.find(p => p.phase === 'tick')!.share, 0.75)
44
- assert.equal(s.phases.find(p => p.phase === 'snapshot')!.share, 0.25)
45
- assert.equal(
46
- +s.phases.reduce((a, p) => a + p.share, 0).toFixed(2),
47
- 1,
48
- '몫의 합은 1 — 다만 재지 않은 작업은 분모에 없다'
49
- )
50
- })
51
-
52
- test('잰 적이 없으면 null 이다 — 0 으로 채우면 "빠르다" 로 읽힌다', () => {
53
- assert.equal(loadSummary(undefined, TICK), null, '계기판 자체가 없을 때')
54
- assert.equal(loadSummary(newLoadMeter(), TICK), null, '있지만 한 번도 안 쟀을 때')
55
-
56
- const m = newLoadMeter()
57
- recordPhase(m, 'publish', 5)
58
- assert.equal(loadSummary(m, TICK)!.loadRatio, null, '틱을 안 쟀으면 루프 점유율도 없다 — 0 이 아니다')
59
- })
60
-
61
- test('음수·NaN 은 기록하지 않는다 — 시계가 뒤로 가도 평균이 거짓이 되지 않게', () => {
62
- const m = newLoadMeter()
63
- recordPhase(m, 'tick', -5)
64
- recordPhase(m, 'tick', NaN)
65
- recordPhase(m, 'tick', Infinity)
66
-
67
- assert.equal(loadSummary(m, TICK), null, '아무것도 안 쌓였다')
68
- })
69
-
70
- test('예산은 간격의 절반 — 넘으면 센다', () => {
71
- const m = newLoadMeter()
72
- const under = judgeCycle(m, TICK * TICK_BUDGET_RATIO - 1, TICK, 0)
73
- assert.equal(under.over, false)
74
- assert.equal(m.overBudget, 0)
75
-
76
- const over = judgeCycle(m, TICK * TICK_BUDGET_RATIO + 1, TICK, 0)
77
- assert.equal(over.over, true)
78
- assert.equal(over.budgetMs, 500)
79
- assert.equal(m.overBudget, 1)
80
- })
81
-
82
- test('경고는 쿨다운을 둔다 — 느린 트윈이 매 틱 경고하면 로그가 원인을 덮는다', () => {
83
- const m = newLoadMeter()
84
- const slow = 900
85
-
86
- assert.equal(judgeCycle(m, slow, TICK, 1000).warn, true, '처음엔 말한다')
87
- assert.equal(judgeCycle(m, slow, TICK, 2000).warn, false, '쿨다운 안에는 알리지 않고')
88
- assert.equal(judgeCycle(m, slow, TICK, 1000 + WARN_COOLDOWN_MS).warn, true, '쿨다운이 지나면 다시')
89
-
90
- assert.equal(m.overBudget, 3, '말하지 않아도 세기는 한다')
91
- })
92
-
93
- test('경고 문구가 무엇이 느린지 알린다 — "틱 800ms" 만으로는 볼 곳을 모른다', () => {
94
- const m = newLoadMeter()
95
- recordPhase(m, 'tick', 800)
96
- recordPhase(m, 'snapshot', 600)
97
- recordPhase(m, 'publish', 100)
98
-
99
- const msg = slowTickMessage('wms-1', 800, 500, m)
100
- assert.match(msg, /wms-1/)
101
- assert.match(msg, /800ms/)
102
- assert.match(msg, /예산 500ms/)
103
- assert.match(msg, /tick .*%/, '가장 무거운 작업과 몫')
104
- assert.match(msg, /snapshot/, '두 번째로 무거운 것까지')
105
- assert.match(msg, /메인 이벤트 루프/, '왜 문제인지도 말한다')
106
- })
107
-
108
- test('실시간(최근 창)과 누적을 따로 낸다 — 지금 아픈 것과 오래 쌓인 것은 다르다', () => {
109
- const m = newLoadMeter()
110
- recordPhase(m, 'tick', 100, 0) // 첫 창 시작
111
- recordPhase(m, 'tick', 100, 1000)
112
- recordPhase(m, 'tick', 700, WINDOW_MS + 1) // 창이 닫히고 새 창에 쌓인다
113
-
114
- const s = loadSummary(m, TICK)!
115
- assert.equal(s.total!.phases[0].totalMs, 900, '누적은 전부')
116
- assert.equal(s.recent!.measuredTotalMs, 200, '최근은 닫힌 창만 — 채우는 중인 창은 과소 집계라 안 쓴다')
117
- assert.equal(s.recent!.spanMs, WINDOW_MS + 1)
118
- assert.equal(s.recent!.busyRatio, 0.02, '창의 2%를 썼다')
119
- })
120
-
121
- test('창이 하나도 안 닫혔으면 최근은 null — 채우는 중인 값을 실시간이라 하지 않는다', () => {
122
- const m = newLoadMeter()
123
- recordPhase(m, 'tick', 300, 0)
124
- recordPhase(m, 'tick', 300, 500)
125
-
126
- const s = loadSummary(m, TICK)!
127
- assert.equal(s.recent, null)
128
- assert.equal(s.total!.measuredTotalMs, 600)
129
- assert.equal(s.total!.spanMs, null, '누적은 구간을 모른다')
130
- assert.equal(s.total!.busyRatio, null, '구간을 모르면 비율도 없다 — 0 이 아니다')
131
- })
132
-
133
- test('fork 수를 센다 — 예측 한 번이 수십 개를 만든다', () => {
134
- const m = newLoadMeter()
135
- recordFork(m, 30)
136
- recordFork(m)
137
-
138
- assert.equal(loadSummary(m, TICK)!.forksCreated, 31, '아무 작업도 안 쟀어도 fork 수는 보인다')
139
- })
140
-
141
- test('전체 한눈에 — 최근 부하가 큰 순서로, 대수와 fork 총수까지', () => {
142
- const mk = (busy: number, forks = 0) => {
143
- const m = newLoadMeter()
144
- recordPhase(m, 'tick', busy, 0)
145
- recordFork(m, forks)
146
- rollWindow(m, WINDOW_MS) // 창을 닫아 '최근' 으로 만든다
147
- return m
148
- }
149
-
150
- const f = fleetLoad(
151
- [
152
- { instanceId: 'idle-1', mode: 'sim', meter: mk(10) },
153
- { instanceId: 'hot-1', mode: 'sim', meter: mk(4000, 30) },
154
- { instanceId: 'live-1', mode: 'live', meter: mk(50) },
155
- { instanceId: 'fresh-1', mode: 'sim' } // 아직 아무것도 안 쟀다
156
- ],
157
- TICK
158
- )
159
-
160
- assert.equal(f.instances, 4)
161
- assert.deepEqual(f.byMode, { sim: 3, live: 1 })
162
- assert.equal(f.forksCreated, 30)
163
- assert.equal(f.slowest[0].instanceId, 'hot-1', '지금 아픈 것이 맨 위')
164
- assert.equal(f.slowest[0].topPhase, 'tick')
165
- assert.equal(f.slowest.at(-1)!.instanceId, 'fresh-1', '안 잰 것은 0 으로 맨 아래')
166
- assert.equal(f.recentBusyMs, 4060)
167
- assert.equal(f.recentSpanMs, WINDOW_MS)
168
- assert.equal(f.fleetBusyRatio, 0.406, '창의 40.6% — 1 을 넘으면 한 틱 안에 다 못 끝낸다')
169
- })
170
-
171
- test('전체 뷰: 닫힌 창이 하나도 없으면 비율을 지어내지 않는다', () => {
172
- const f = fleetLoad([{ instanceId: 'a', mode: 'sim', meter: newLoadMeter() }], TICK)
173
-
174
- assert.equal(f.recentSpanMs, null)
175
- assert.equal(f.fleetBusyRatio, null)
176
- assert.equal(f.recentBusyMs, 0)
177
- })
178
-
179
- test('아주 작은 비율이 0 으로 사라지지 않는다 — 재서 나온 값과 없는 값은 다르다', () => {
180
- const m = newLoadMeter()
181
- recordPhase(m, 'tick', 24, 0)
182
- rollWindow(m, 11_000)
183
-
184
- const r = loadSummary(m, TICK)!.recent!
185
- assert.ok(r.busyRatio! > 0, `0 이 되면 "안 쓴다" 로 읽힌다 — 실제 ${r.busyRatio}`)
186
- assert.equal(r.busyRatio, 0.0022)
187
- })
188
-
189
- test('도메인별 점유 — 어느 테넌트가 루프를 먹나', () => {
190
- const mk = (busy: number) => {
191
- const m = newLoadMeter()
192
- recordPhase(m, 'tick', busy, 0)
193
- rollWindow(m, WINDOW_MS)
194
- return m
195
- }
196
-
197
- const f = fleetLoad(
198
- [
199
- { instanceId: 'a1', mode: 'sim', domainId: 'D1', domainLabel: 'acme', meter: mk(300) },
200
- { instanceId: 'a2', mode: 'sim', domainId: 'D1', domainLabel: 'acme', meter: mk(500) },
201
- { instanceId: 'b1', mode: 'live', domainId: 'D2', meter: mk(200) },
202
- { instanceId: 'c1', mode: 'sim' } // 도메인도 계측도 없다
203
- ],
204
- TICK
205
- )
206
-
207
- assert.deepEqual(
208
- f.byDomain.map(d => `${d.label} ${d.instances} ${d.recentBusyMs}ms ${Math.round(d.share * 100)}%`),
209
- ['acme 2 800ms 80%', 'D2 1 200ms 20%', '(unknown) 1 0ms 0%'],
210
- '무거운 순 · 이름을 모르면 id 를 그대로 쓴다(지어내지 않는다)'
211
- )
212
- assert.equal(
213
- +f.byDomain.reduce((a, d) => a + d.share, 0).toFixed(2),
214
- 1,
215
- '몫의 합은 1 — 잰 트윈들 사이의 비율이다'
216
- )
217
- })
218
-
219
- test('도메인별 점유: 아무도 안 쟀으면 몫이 0 이고 비율을 지어내지 않는다', () => {
220
- const f = fleetLoad([{ instanceId: 'a', mode: 'sim', domainId: 'D1' }], TICK)
221
-
222
- assert.equal(f.byDomain.length, 1)
223
- assert.equal(f.byDomain[0].share, 0)
224
- assert.equal(f.fleetBusyRatio, null)
225
- })
226
-
227
- test('보이는 부분의 합이 보이는 합계와 맞는다 — 도메인 = 그 도메인 트윈들의 합', () => {
228
- /* 실제로 어긋났던 값: 잎마다 따로 반올림해서 도메인 0.08ms 인데 트윈 둘은 0.08+0.01=0.09ms 였다. */
229
- const mk = (busy: number) => {
230
- const m = newLoadMeter()
231
- recordPhase(m, 'tick', busy, 0)
232
- rollWindow(m, WINDOW_MS)
233
- return m
234
- }
235
-
236
- const f = fleetLoad(
237
- [
238
- { instanceId: 'big', mode: 'sim', domainId: 'D1', domainLabel: 'hatiolab', meter: mk(39.114) },
239
- { instanceId: 's1', mode: 'sim', domainId: 'D2', domainLabel: 'system', meter: mk(0.084) },
240
- { instanceId: 's2', mode: 'sim', domainId: 'D2', domainLabel: 'system', meter: mk(0.014) }
241
- ],
242
- TICK
243
- )
244
-
245
- for (const d of f.byDomain) {
246
- const mine = f.slowest.filter(s => s.domainId === d.domainId)
247
- assert.equal(
248
- d.recentBusyMs,
249
- +mine.reduce((a, s) => a + s.recentBusyMs, 0).toFixed(2),
250
- `${d.label} 의 합계가 그 트윈들의 합과 다르다`
251
- )
252
- }
253
-
254
- assert.equal(
255
- f.recentBusyMs,
256
- +f.byDomain.reduce((a, d) => a + d.recentBusyMs, 0).toFixed(2),
257
- '전체 합계가 도메인들의 합과 다르다'
258
- )
259
- })
260
-
261
- test('도메인 몫의 합은 1 이다 — 백분율로 읽어 100% 가 된다', () => {
262
- const mk = (busy: number) => {
263
- const m = newLoadMeter()
264
- recordPhase(m, 'tick', busy, 0)
265
- rollWindow(m, WINDOW_MS)
266
- return m
267
- }
268
-
269
- const f = fleetLoad(
270
- [
271
- { instanceId: 'a', mode: 'sim', domainId: 'D1', meter: mk(39.11) },
272
- { instanceId: 'b', mode: 'sim', domainId: 'D2', meter: mk(0.08) },
273
- { instanceId: 'c', mode: 'sim', domainId: 'D3', meter: mk(0.01) }
274
- ],
275
- TICK
276
- )
277
-
278
- assert.equal(+f.byDomain.reduce((a, d) => a + d.share, 0).toFixed(3), 1)
279
- })
280
-
281
- test('프로세스 CPU 는 첫 표본에서 null 이다 — 잰 구간이 없으면 0 이 아니다', () => {
282
- const s = newCpuSampler()
283
- assert.equal(sampleCpu(s, 1_000_000, 1000), null, '비교할 앞 표본이 없다')
284
- })
285
-
286
- test('프로세스 CPU 는 두 표본 사이의 점유율이다 — 코어를 여럿 쓰면 1 을 넘는다', () => {
287
- const s = newCpuSampler()
288
- sampleCpu(s, 1_000_000, 0)
289
-
290
- assert.deepEqual(sampleCpu(s, 1_500_000, 1000), { ratio: 0.5, spanMs: 1000 }, '1초에 0.5초 = 50%')
291
- assert.deepEqual(sampleCpu(s, 2_600_000, 2000), { ratio: 1.1, spanMs: 1000 }, '1초에 1.1초 = 110%, 코어 여러 개')
292
- })
293
-
294
- test('시계가 뒤로 가거나 구간이 0 이면 비율을 지어내지 않는다', () => {
295
- const s = newCpuSampler()
296
- sampleCpu(s, 1_000_000, 1000)
297
-
298
- assert.equal(sampleCpu(s, 1_200_000, 1000), null, '구간 0')
299
- assert.equal(sampleCpu(newCpuSampler(), 5, 5), null)
300
- })
301
-
302
- /*
303
- * ── 부팅 구간도 재는 이름을 갖는다 (2026-08-22) ─────────────────────────────
304
- * 실측으로 부팅이 620~717초였고 트윈 하나를 세우는 데 15~93초였는데, **어느 작업이 그 시간을 쓰는지
305
- * 답할 이름이 없었다** — 재는 이름이 도는 중의 작업뿐이었다. 그래서 짐작으로 원인을 적을 수밖에
306
- * 없었고, 그것은 이 프로젝트가 금하는 일이다.
307
- */
308
- test('부팅 구간을 재는 이름이 있다 — 웜스타트와 자극 시작', () => {
309
- assert.ok(LOAD_PHASES.includes('warmStart' as any), '상태 심기를 재는 이름이 있어야 한다')
310
- assert.ok(LOAD_PHASES.includes('stimulus' as any), '자극 시작을 재는 이름이 있어야 한다')
311
-
312
- /* 계기가 그 값을 실제로 들고 답한다 — 이름만 있고 담기지 않으면 화면이 빈칸을 보인다. */
313
- const m = newLoadMeter()
314
- recordPhase(m, 'warmStart', 93_000, 1_000)
315
- recordPhase(m, 'stimulus', 72_000, 1_000)
316
- assert.equal(m.phases.warmStart?.maxMs, 93_000)
317
- assert.equal(m.phases.stimulus?.maxMs, 72_000)
318
- })
319
-
320
- test('부팅 구간은 틱 예산으로 판정하지 않는다 — 한 번뿐인 일이다', () => {
321
- /*
322
- * 웜스타트는 트윈을 세울 때 한 번이고 몇십 초가 정상일 수 있다. 그것을 틱 예산(간격의 절반)으로
323
- * 재면 부팅마다 「느린 주기」가 쏟아진다 — 거짓 경보는 참 경보를 죽인다. 판정은 틱만 받는다.
324
- */
325
- const m = newLoadMeter()
326
- recordPhase(m, 'warmStart', 93_000, 1_000)
327
- assert.equal(m.overBudget, 0, '기록만으로는 판정하지 않는다')
328
- })