@things-factory/headless-twin 10.1.278 → 10.1.279

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (614) hide show
  1. package/package.json +21 -7
  2. package/dist-server/engine/attention-digest.js.map +0 -1
  3. package/dist-server/engine/canonical-ingest.js.map +0 -1
  4. package/dist-server/engine/checkpoint-fold.js.map +0 -1
  5. package/dist-server/engine/command-routing.js.map +0 -1
  6. package/dist-server/engine/declared-stimulus.js.map +0 -1
  7. package/dist-server/engine/energy-topology.js.map +0 -1
  8. package/dist-server/engine/event-time.js.map +0 -1
  9. package/dist-server/engine/index.js.map +0 -1
  10. package/dist-server/engine/ingest-dedupe.js.map +0 -1
  11. package/dist-server/engine/ingest-health.js.map +0 -1
  12. package/dist-server/engine/integration-coverage.js.map +0 -1
  13. package/dist-server/engine/integration-probes.js.map +0 -1
  14. package/dist-server/engine/integration-runner.js.map +0 -1
  15. package/dist-server/engine/integration-target-profile.js.map +0 -1
  16. package/dist-server/engine/kpi-baseline.js.map +0 -1
  17. package/dist-server/engine/kpi-fold.js.map +0 -1
  18. package/dist-server/engine/kpi-query.js.map +0 -1
  19. package/dist-server/engine/kpi-target.js.map +0 -1
  20. package/dist-server/engine/live-attentions.js.map +0 -1
  21. package/dist-server/engine/live-feed-registry.js.map +0 -1
  22. package/dist-server/engine/load-meter.js.map +0 -1
  23. package/dist-server/engine/local-declarations.js.map +0 -1
  24. package/dist-server/engine/log.js.map +0 -1
  25. package/dist-server/engine/loop-lag.js.map +0 -1
  26. package/dist-server/engine/measured-estimator.js.map +0 -1
  27. package/dist-server/engine/measured-yield.js.map +0 -1
  28. package/dist-server/engine/model-basis.js.map +0 -1
  29. package/dist-server/engine/model-gap.js.map +0 -1
  30. package/dist-server/engine/model-refusal.js.map +0 -1
  31. package/dist-server/engine/model-vocabulary.js.map +0 -1
  32. package/dist-server/engine/oee-accumulator.js.map +0 -1
  33. package/dist-server/engine/operation-basis.js.map +0 -1
  34. package/dist-server/engine/producer-guard.js.map +0 -1
  35. package/dist-server/engine/property-effects.js.map +0 -1
  36. package/dist-server/engine/read-time.js.map +0 -1
  37. package/dist-server/engine/restart-policy.js.map +0 -1
  38. package/dist-server/engine/runtime-key.js.map +0 -1
  39. package/dist-server/engine/spec-coverage.js.map +0 -1
  40. package/dist-server/engine/stage-path.js.map +0 -1
  41. package/dist-server/engine/state-axes.js.map +0 -1
  42. package/dist-server/engine/structure-diff.js.map +0 -1
  43. package/dist-server/engine/travel-estimator.js.map +0 -1
  44. package/dist-server/engine/twin-engine.js.map +0 -1
  45. package/dist-server/engine/twin-state-channel.js.map +0 -1
  46. package/dist-server/engine/warm-start.js.map +0 -1
  47. package/dist-server/index.js.map +0 -1
  48. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js.map +0 -1
  49. package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js.map +0 -1
  50. package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js.map +0 -1
  51. package/dist-server/migrations/1786300000000-IndexEventTypeByTime.js.map +0 -1
  52. package/dist-server/migrations/1786400000000-IndexEventCreatedAt.js.map +0 -1
  53. package/dist-server/migrations/1786500000000-CreateTwinSubjectEvents.js.map +0 -1
  54. package/dist-server/migrations/1786600000000-RenameOperatoMesAdapterType.js.map +0 -1
  55. package/dist-server/migrations/1786700000000-AddDispatchRetryColumns.js.map +0 -1
  56. package/dist-server/migrations/1786800000000-CreateTwinReferenceReconciliations.js.map +0 -1
  57. package/dist-server/migrations/index.js.map +0 -1
  58. package/dist-server/routes.js.map +0 -1
  59. package/dist-server/service/actuation/actuation-advisor.js.map +0 -1
  60. package/dist-server/service/actuation/actuation-outcome.js.map +0 -1
  61. package/dist-server/service/actuation/actuation-rule-resolver.js.map +0 -1
  62. package/dist-server/service/actuation/actuation-rule.js.map +0 -1
  63. package/dist-server/service/actuation/approval-gateway.js.map +0 -1
  64. package/dist-server/service/actuation/catch-up-effects.js.map +0 -1
  65. package/dist-server/service/actuation/command-dispatcher.js.map +0 -1
  66. package/dist-server/service/actuation/command-store.js.map +0 -1
  67. package/dist-server/service/actuation/dispatch-after-approval.js.map +0 -1
  68. package/dist-server/service/actuation/effect-match.js.map +0 -1
  69. package/dist-server/service/actuation/index.js.map +0 -1
  70. package/dist-server/service/actuation/retry-plan.js.map +0 -1
  71. package/dist-server/service/actuation/rule-evaluate.js.map +0 -1
  72. package/dist-server/service/actuation/rule-loop.js.map +0 -1
  73. package/dist-server/service/actuation/rule-runner.js.map +0 -1
  74. package/dist-server/service/actuation/rule-wiring.js.map +0 -1
  75. package/dist-server/service/actuation/settle-effects.js.map +0 -1
  76. package/dist-server/service/actuation/sweep-dispatch.js.map +0 -1
  77. package/dist-server/service/actuation/twin-command-resolver.js.map +0 -1
  78. package/dist-server/service/actuation/twin-command.js.map +0 -1
  79. package/dist-server/service/actuation/twin-now.js.map +0 -1
  80. package/dist-server/service/index.js.map +0 -1
  81. package/dist-server/service/reference/actuation-routing.js.map +0 -1
  82. package/dist-server/service/reference/actuation-target.js.map +0 -1
  83. package/dist-server/service/reference/actuation-verification.js.map +0 -1
  84. package/dist-server/service/reference/attention-lane.js.map +0 -1
  85. package/dist-server/service/reference/connection-portability-resolver.js.map +0 -1
  86. package/dist-server/service/reference/connection-portability.js.map +0 -1
  87. package/dist-server/service/reference/control-routing.js.map +0 -1
  88. package/dist-server/service/reference/discovery-result.js.map +0 -1
  89. package/dist-server/service/reference/fill-cadence.js.map +0 -1
  90. package/dist-server/service/reference/fill-dedupe.js.map +0 -1
  91. package/dist-server/service/reference/fill-loop.js.map +0 -1
  92. package/dist-server/service/reference/fill-span.js.map +0 -1
  93. package/dist-server/service/reference/hook-contract.js.map +0 -1
  94. package/dist-server/service/reference/hook-rejected.js.map +0 -1
  95. package/dist-server/service/reference/hook-store.js.map +0 -1
  96. package/dist-server/service/reference/index.js.map +0 -1
  97. package/dist-server/service/reference/ingest-space.js.map +0 -1
  98. package/dist-server/service/reference/knob-defaults.js.map +0 -1
  99. package/dist-server/service/reference/live-cadence.js.map +0 -1
  100. package/dist-server/service/reference/live-feed-lease.js.map +0 -1
  101. package/dist-server/service/reference/live-ingest.js.map +0 -1
  102. package/dist-server/service/reference/reference-adapter.js.map +0 -1
  103. package/dist-server/service/reference/reference-assessment.js.map +0 -1
  104. package/dist-server/service/reference/reference-fill-run.js.map +0 -1
  105. package/dist-server/service/reference/reference-fill.js.map +0 -1
  106. package/dist-server/service/reference/reference-hook.js.map +0 -1
  107. package/dist-server/service/reference/reference-link-groups.js.map +0 -1
  108. package/dist-server/service/reference/reference-links.js.map +0 -1
  109. package/dist-server/service/reference/reference-live.js.map +0 -1
  110. package/dist-server/service/reference/reference-master.js.map +0 -1
  111. package/dist-server/service/reference/reference-probe.js.map +0 -1
  112. package/dist-server/service/reference/reference-progress-channel.js.map +0 -1
  113. package/dist-server/service/reference/reference-progress-subscription.js.map +0 -1
  114. package/dist-server/service/reference/reference-progress.js.map +0 -1
  115. package/dist-server/service/reference/reference-reconciliation-query.js.map +0 -1
  116. package/dist-server/service/reference/reference-reconciliation-writer.js.map +0 -1
  117. package/dist-server/service/reference/reference-reconciliation.js.map +0 -1
  118. package/dist-server/service/reference/reference-registry.js.map +0 -1
  119. package/dist-server/service/reference/reference-resolver.js.map +0 -1
  120. package/dist-server/service/reference/template-registry.js.map +0 -1
  121. package/dist-server/service/reference/twin-reference-reconciliation.js.map +0 -1
  122. package/dist-server/service/reference/twin-reference.js.map +0 -1
  123. package/dist-server/service/twin-attention/index.js.map +0 -1
  124. package/dist-server/service/twin-attention/twin-attention-query.js.map +0 -1
  125. package/dist-server/service/twin-audit/command-audit.js.map +0 -1
  126. package/dist-server/service/twin-audit/index.js.map +0 -1
  127. package/dist-server/service/twin-audit/twin-audit-event.js.map +0 -1
  128. package/dist-server/service/twin-audit/twin-audit-query.js.map +0 -1
  129. package/dist-server/service/twin-backfill/backfill-period-facts.js.map +0 -1
  130. package/dist-server/service/twin-backfill/backfill-shape.js.map +0 -1
  131. package/dist-server/service/twin-backfill/index.js.map +0 -1
  132. package/dist-server/service/twin-backfill/twin-backfill-resolver.js.map +0 -1
  133. package/dist-server/service/twin-control/index.js.map +0 -1
  134. package/dist-server/service/twin-control/twin-control-mutation.js.map +0 -1
  135. package/dist-server/service/twin-event/index.js.map +0 -1
  136. package/dist-server/service/twin-event/journal-count.js.map +0 -1
  137. package/dist-server/service/twin-event/twin-event-keys.js.map +0 -1
  138. package/dist-server/service/twin-event/twin-event-type.js.map +0 -1
  139. package/dist-server/service/twin-event/twin-event.js.map +0 -1
  140. package/dist-server/service/twin-forecast/forecast-metrics.js.map +0 -1
  141. package/dist-server/service/twin-forecast/forecast-tuning.js.map +0 -1
  142. package/dist-server/service/twin-forecast/gap-analytics.js.map +0 -1
  143. package/dist-server/service/twin-forecast/index.js.map +0 -1
  144. package/dist-server/service/twin-forecast/twin-forecast-query.js.map +0 -1
  145. package/dist-server/service/twin-ingest-window/index.js.map +0 -1
  146. package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js.map +0 -1
  147. package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js.map +0 -1
  148. package/dist-server/service/twin-ingest-window/twin-ingest-window.js.map +0 -1
  149. package/dist-server/service/twin-instance/index.js.map +0 -1
  150. package/dist-server/service/twin-instance/twin-instance.js.map +0 -1
  151. package/dist-server/service/twin-journal/event-type-split-shape.js.map +0 -1
  152. package/dist-server/service/twin-journal/event-type-split.js.map +0 -1
  153. package/dist-server/service/twin-journal/index.js.map +0 -1
  154. package/dist-server/service/twin-journal/journal-order.js.map +0 -1
  155. package/dist-server/service/twin-journal/twin-journal-query.js.map +0 -1
  156. package/dist-server/service/twin-lifecycle/domain-catalog.js.map +0 -1
  157. package/dist-server/service/twin-lifecycle/index.js.map +0 -1
  158. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +0 -1
  159. package/dist-server/service/twin-metrics/index.js.map +0 -1
  160. package/dist-server/service/twin-metrics/twin-metrics-query.js.map +0 -1
  161. package/dist-server/service/twin-model/axis-journal-evidence.js.map +0 -1
  162. package/dist-server/service/twin-model/choose-recipe.js.map +0 -1
  163. package/dist-server/service/twin-model/epcis-coverage.js.map +0 -1
  164. package/dist-server/service/twin-model/external-resolver.js.map +0 -1
  165. package/dist-server/service/twin-model/iec61850-coverage.js.map +0 -1
  166. package/dist-server/service/twin-model/index.js.map +0 -1
  167. package/dist-server/service/twin-model/isa95-coverage.js.map +0 -1
  168. package/dist-server/service/twin-model/item-ref.js.map +0 -1
  169. package/dist-server/service/twin-model/name-index.js.map +0 -1
  170. package/dist-server/service/twin-model/project-structure.js.map +0 -1
  171. package/dist-server/service/twin-model/standard-coverage.js.map +0 -1
  172. package/dist-server/service/twin-model/status-tally.js.map +0 -1
  173. package/dist-server/service/twin-model/twin-equipment.js.map +0 -1
  174. package/dist-server/service/twin-model/twin-lineage-query.js.map +0 -1
  175. package/dist-server/service/twin-model/twin-location.js.map +0 -1
  176. package/dist-server/service/twin-model/twin-model-item-query.js.map +0 -1
  177. package/dist-server/service/twin-model/twin-model-mutation.js.map +0 -1
  178. package/dist-server/service/twin-model/twin-model-query.js.map +0 -1
  179. package/dist-server/service/twin-model/twin-model-tree-query.js.map +0 -1
  180. package/dist-server/service/twin-model/twin-operation.js.map +0 -1
  181. package/dist-server/service/twin-readiness/index.js.map +0 -1
  182. package/dist-server/service/twin-readiness/twin-readiness-query.js.map +0 -1
  183. package/dist-server/service/twin-space/area-resolver.js.map +0 -1
  184. package/dist-server/service/twin-space/index.js.map +0 -1
  185. package/dist-server/service/twin-space/move-space.js.map +0 -1
  186. package/dist-server/service/twin-space/representation-role.js.map +0 -1
  187. package/dist-server/service/twin-space/space-integrity.js.map +0 -1
  188. package/dist-server/service/twin-space/twin-area.js.map +0 -1
  189. package/dist-server/service/twin-space/twin-space-area.js.map +0 -1
  190. package/dist-server/service/twin-space/twin-space-representation.js.map +0 -1
  191. package/dist-server/service/twin-space/twin-space-resolver.js.map +0 -1
  192. package/dist-server/service/twin-space/twin-space.js.map +0 -1
  193. package/dist-server/service/twin-state/index.js.map +0 -1
  194. package/dist-server/service/twin-state/twin-state-subscription.js.map +0 -1
  195. package/dist-server/service/twin-structure/index.js.map +0 -1
  196. package/dist-server/service/twin-structure/twin-structure.js.map +0 -1
  197. package/dist-server/service/twin-subject/event-subjects.js.map +0 -1
  198. package/dist-server/service/twin-subject/index.js.map +0 -1
  199. package/dist-server/service/twin-subject/item-resolver.js.map +0 -1
  200. package/dist-server/service/twin-subject/subject-query-shape.js.map +0 -1
  201. package/dist-server/service/twin-subject/twin-subject-backfill.js.map +0 -1
  202. package/dist-server/service/twin-subject/twin-subject-event.js.map +0 -1
  203. package/dist-server/service/twin-subject/twin-subject-fast-path.js.map +0 -1
  204. package/dist-server/service/twin-subject/twin-subject-query.js.map +0 -1
  205. package/dist-server/service/twin-subject/twin-subject-writer.js.map +0 -1
  206. package/dist-server/service/twin-target/index.js.map +0 -1
  207. package/dist-server/service/twin-target/twin-target-resolver.js.map +0 -1
  208. package/dist-server/service/twin-target/twin-target.js.map +0 -1
  209. package/dist-shared/axis-read.js.map +0 -1
  210. package/dist-shared/entity-delta.js.map +0 -1
  211. package/dist-shared/kpi-broadcast.js.map +0 -1
  212. package/dist-shared/touched-items.js.map +0 -1
  213. package/dist-shared/twin-level.js.map +0 -1
  214. package/server/engine/attention-digest.ts +0 -102
  215. package/server/engine/canonical-ingest.ts +0 -511
  216. package/server/engine/checkpoint-fold.ts +0 -12
  217. package/server/engine/command-routing.ts +0 -67
  218. package/server/engine/declared-stimulus.ts +0 -66
  219. package/server/engine/energy-topology.ts +0 -189
  220. package/server/engine/event-time.ts +0 -96
  221. package/server/engine/index.ts +0 -51
  222. package/server/engine/ingest-dedupe.ts +0 -24
  223. package/server/engine/ingest-health.ts +0 -24
  224. package/server/engine/integration-coverage.ts +0 -147
  225. package/server/engine/integration-probes.ts +0 -144
  226. package/server/engine/integration-runner.ts +0 -95
  227. package/server/engine/integration-target-profile.ts +0 -103
  228. package/server/engine/kpi-baseline.ts +0 -202
  229. package/server/engine/kpi-fold.ts +0 -1516
  230. package/server/engine/kpi-query.ts +0 -1210
  231. package/server/engine/kpi-target.ts +0 -248
  232. package/server/engine/live-attentions.ts +0 -30
  233. package/server/engine/live-feed-registry.ts +0 -59
  234. package/server/engine/load-meter.ts +0 -393
  235. package/server/engine/local-declarations.ts +0 -779
  236. package/server/engine/log.ts +0 -72
  237. package/server/engine/loop-lag.ts +0 -120
  238. package/server/engine/measured-estimator.ts +0 -91
  239. package/server/engine/measured-yield.ts +0 -89
  240. package/server/engine/model-basis.ts +0 -162
  241. package/server/engine/model-gap.ts +0 -168
  242. package/server/engine/model-refusal.ts +0 -31
  243. package/server/engine/model-vocabulary.ts +0 -82
  244. package/server/engine/oee-accumulator.ts +0 -195
  245. package/server/engine/operation-basis.ts +0 -131
  246. package/server/engine/producer-guard.ts +0 -64
  247. package/server/engine/property-effects.ts +0 -216
  248. package/server/engine/read-time.ts +0 -77
  249. package/server/engine/restart-policy.ts +0 -55
  250. package/server/engine/runtime-key.ts +0 -58
  251. package/server/engine/spec-coverage.ts +0 -105
  252. package/server/engine/stage-path.ts +0 -172
  253. package/server/engine/state-axes.ts +0 -60
  254. package/server/engine/structure-diff.ts +0 -88
  255. package/server/engine/travel-estimator.ts +0 -138
  256. package/server/engine/twin-engine.ts +0 -4979
  257. package/server/engine/twin-state-channel.ts +0 -39
  258. package/server/engine/warm-start.ts +0 -265
  259. package/server/index.ts +0 -90
  260. package/server/migrations/1786000000000-RenameTwinInstanceBoardToModel.ts +0 -43
  261. package/server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.ts +0 -54
  262. package/server/migrations/1786200000000-CarryLiveFeedCursor.ts +0 -53
  263. package/server/migrations/1786300000000-IndexEventTypeByTime.ts +0 -48
  264. package/server/migrations/1786400000000-IndexEventCreatedAt.ts +0 -38
  265. package/server/migrations/1786500000000-CreateTwinSubjectEvents.ts +0 -93
  266. package/server/migrations/1786600000000-RenameOperatoMesAdapterType.ts +0 -66
  267. package/server/migrations/1786700000000-AddDispatchRetryColumns.ts +0 -82
  268. package/server/migrations/1786800000000-CreateTwinReferenceReconciliations.ts +0 -39
  269. package/server/migrations/index.ts +0 -25
  270. package/server/routes.ts +0 -75
  271. package/server/service/actuation/actuation-advisor.ts +0 -131
  272. package/server/service/actuation/actuation-outcome.ts +0 -97
  273. package/server/service/actuation/actuation-rule-resolver.ts +0 -147
  274. package/server/service/actuation/actuation-rule.ts +0 -139
  275. package/server/service/actuation/approval-gateway.ts +0 -44
  276. package/server/service/actuation/catch-up-effects.ts +0 -152
  277. package/server/service/actuation/command-dispatcher.ts +0 -474
  278. package/server/service/actuation/command-store.ts +0 -236
  279. package/server/service/actuation/dispatch-after-approval.ts +0 -71
  280. package/server/service/actuation/effect-match.ts +0 -124
  281. package/server/service/actuation/index.ts +0 -27
  282. package/server/service/actuation/retry-plan.ts +0 -145
  283. package/server/service/actuation/rule-evaluate.ts +0 -352
  284. package/server/service/actuation/rule-loop.ts +0 -160
  285. package/server/service/actuation/rule-runner.ts +0 -216
  286. package/server/service/actuation/rule-wiring.ts +0 -84
  287. package/server/service/actuation/settle-effects.ts +0 -115
  288. package/server/service/actuation/sweep-dispatch.ts +0 -179
  289. package/server/service/actuation/twin-command-resolver.ts +0 -387
  290. package/server/service/actuation/twin-command.ts +0 -232
  291. package/server/service/actuation/twin-now.ts +0 -97
  292. package/server/service/index.ts +0 -100
  293. package/server/service/reference/actuation-routing.ts +0 -192
  294. package/server/service/reference/actuation-target.ts +0 -163
  295. package/server/service/reference/actuation-verification.ts +0 -85
  296. package/server/service/reference/attention-lane.ts +0 -21
  297. package/server/service/reference/connection-portability-resolver.ts +0 -171
  298. package/server/service/reference/connection-portability.ts +0 -329
  299. package/server/service/reference/control-routing.ts +0 -62
  300. package/server/service/reference/discovery-result.ts +0 -95
  301. package/server/service/reference/fill-cadence.ts +0 -29
  302. package/server/service/reference/fill-dedupe.ts +0 -66
  303. package/server/service/reference/fill-loop.ts +0 -153
  304. package/server/service/reference/fill-span.ts +0 -31
  305. package/server/service/reference/hook-contract.ts +0 -364
  306. package/server/service/reference/hook-rejected.ts +0 -53
  307. package/server/service/reference/hook-store.ts +0 -28
  308. package/server/service/reference/index.ts +0 -18
  309. package/server/service/reference/ingest-space.ts +0 -104
  310. package/server/service/reference/knob-defaults.ts +0 -59
  311. package/server/service/reference/live-cadence.ts +0 -129
  312. package/server/service/reference/live-feed-lease.ts +0 -56
  313. package/server/service/reference/live-ingest.ts +0 -94
  314. package/server/service/reference/reference-adapter.ts +0 -985
  315. package/server/service/reference/reference-assessment.ts +0 -250
  316. package/server/service/reference/reference-fill-run.ts +0 -179
  317. package/server/service/reference/reference-fill.ts +0 -223
  318. package/server/service/reference/reference-hook.ts +0 -479
  319. package/server/service/reference/reference-link-groups.ts +0 -21
  320. package/server/service/reference/reference-links.ts +0 -77
  321. package/server/service/reference/reference-live.ts +0 -420
  322. package/server/service/reference/reference-master.ts +0 -999
  323. package/server/service/reference/reference-probe.ts +0 -264
  324. package/server/service/reference/reference-progress-channel.ts +0 -26
  325. package/server/service/reference/reference-progress-subscription.ts +0 -78
  326. package/server/service/reference/reference-progress.ts +0 -95
  327. package/server/service/reference/reference-reconciliation-query.ts +0 -28
  328. package/server/service/reference/reference-reconciliation-writer.ts +0 -38
  329. package/server/service/reference/reference-reconciliation.ts +0 -55
  330. package/server/service/reference/reference-registry.ts +0 -17
  331. package/server/service/reference/reference-resolver.ts +0 -969
  332. package/server/service/reference/template-registry.ts +0 -85
  333. package/server/service/reference/twin-reference-reconciliation.ts +0 -27
  334. package/server/service/reference/twin-reference.ts +0 -190
  335. package/server/service/twin-attention/index.ts +0 -3
  336. package/server/service/twin-attention/twin-attention-query.ts +0 -70
  337. package/server/service/twin-audit/command-audit.ts +0 -114
  338. package/server/service/twin-audit/index.ts +0 -5
  339. package/server/service/twin-audit/twin-audit-event.ts +0 -158
  340. package/server/service/twin-audit/twin-audit-query.ts +0 -72
  341. package/server/service/twin-backfill/backfill-period-facts.ts +0 -168
  342. package/server/service/twin-backfill/backfill-shape.ts +0 -86
  343. package/server/service/twin-backfill/index.ts +0 -3
  344. package/server/service/twin-backfill/twin-backfill-resolver.ts +0 -35
  345. package/server/service/twin-control/index.ts +0 -3
  346. package/server/service/twin-control/twin-control-mutation.ts +0 -150
  347. package/server/service/twin-event/index.ts +0 -3
  348. package/server/service/twin-event/journal-count.ts +0 -53
  349. package/server/service/twin-event/twin-event-keys.ts +0 -215
  350. package/server/service/twin-event/twin-event-type.ts +0 -68
  351. package/server/service/twin-event/twin-event.ts +0 -250
  352. package/server/service/twin-forecast/forecast-metrics.ts +0 -106
  353. package/server/service/twin-forecast/forecast-tuning.ts +0 -40
  354. package/server/service/twin-forecast/gap-analytics.ts +0 -139
  355. package/server/service/twin-forecast/index.ts +0 -3
  356. package/server/service/twin-forecast/twin-forecast-query.ts +0 -486
  357. package/server/service/twin-ingest-window/index.ts +0 -7
  358. package/server/service/twin-ingest-window/twin-ingest-window-query.ts +0 -125
  359. package/server/service/twin-ingest-window/twin-ingest-window-writer.ts +0 -57
  360. package/server/service/twin-ingest-window/twin-ingest-window.ts +0 -113
  361. package/server/service/twin-instance/index.ts +0 -3
  362. package/server/service/twin-instance/twin-instance.ts +0 -199
  363. package/server/service/twin-journal/event-type-split-shape.ts +0 -112
  364. package/server/service/twin-journal/event-type-split.ts +0 -144
  365. package/server/service/twin-journal/index.ts +0 -3
  366. package/server/service/twin-journal/journal-order.ts +0 -20
  367. package/server/service/twin-journal/twin-journal-query.ts +0 -615
  368. package/server/service/twin-lifecycle/domain-catalog.ts +0 -51
  369. package/server/service/twin-lifecycle/index.ts +0 -3
  370. package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +0 -285
  371. package/server/service/twin-metrics/index.ts +0 -3
  372. package/server/service/twin-metrics/twin-metrics-query.ts +0 -172
  373. package/server/service/twin-model/axis-journal-evidence.ts +0 -57
  374. package/server/service/twin-model/choose-recipe.ts +0 -31
  375. package/server/service/twin-model/epcis-coverage.ts +0 -251
  376. package/server/service/twin-model/external-resolver.ts +0 -173
  377. package/server/service/twin-model/iec61850-coverage.ts +0 -111
  378. package/server/service/twin-model/index.ts +0 -25
  379. package/server/service/twin-model/isa95-coverage.ts +0 -320
  380. package/server/service/twin-model/item-ref.ts +0 -80
  381. package/server/service/twin-model/name-index.ts +0 -94
  382. package/server/service/twin-model/project-structure.ts +0 -213
  383. package/server/service/twin-model/standard-coverage.ts +0 -35
  384. package/server/service/twin-model/status-tally.ts +0 -37
  385. package/server/service/twin-model/twin-equipment.ts +0 -191
  386. package/server/service/twin-model/twin-lineage-query.ts +0 -327
  387. package/server/service/twin-model/twin-location.ts +0 -147
  388. package/server/service/twin-model/twin-model-item-query.ts +0 -1029
  389. package/server/service/twin-model/twin-model-mutation.ts +0 -503
  390. package/server/service/twin-model/twin-model-query.ts +0 -792
  391. package/server/service/twin-model/twin-model-tree-query.ts +0 -211
  392. package/server/service/twin-model/twin-operation.ts +0 -157
  393. package/server/service/twin-readiness/index.ts +0 -3
  394. package/server/service/twin-readiness/twin-readiness-query.ts +0 -96
  395. package/server/service/twin-space/area-resolver.ts +0 -75
  396. package/server/service/twin-space/index.ts +0 -8
  397. package/server/service/twin-space/move-space.ts +0 -262
  398. package/server/service/twin-space/representation-role.ts +0 -15
  399. package/server/service/twin-space/space-integrity.ts +0 -293
  400. package/server/service/twin-space/twin-area.ts +0 -63
  401. package/server/service/twin-space/twin-space-area.ts +0 -66
  402. package/server/service/twin-space/twin-space-representation.ts +0 -99
  403. package/server/service/twin-space/twin-space-resolver.ts +0 -582
  404. package/server/service/twin-space/twin-space.ts +0 -148
  405. package/server/service/twin-state/index.ts +0 -3
  406. package/server/service/twin-state/twin-state-subscription.ts +0 -62
  407. package/server/service/twin-structure/index.ts +0 -3
  408. package/server/service/twin-structure/twin-structure.ts +0 -96
  409. package/server/service/twin-subject/event-subjects.ts +0 -162
  410. package/server/service/twin-subject/index.ts +0 -10
  411. package/server/service/twin-subject/item-resolver.ts +0 -92
  412. package/server/service/twin-subject/subject-query-shape.ts +0 -84
  413. package/server/service/twin-subject/twin-subject-backfill.ts +0 -196
  414. package/server/service/twin-subject/twin-subject-event.ts +0 -101
  415. package/server/service/twin-subject/twin-subject-fast-path.ts +0 -346
  416. package/server/service/twin-subject/twin-subject-query.ts +0 -210
  417. package/server/service/twin-subject/twin-subject-writer.ts +0 -189
  418. package/server/service/twin-target/index.ts +0 -5
  419. package/server/service/twin-target/twin-target-resolver.ts +0 -142
  420. package/server/service/twin-target/twin-target.ts +0 -97
  421. package/server/types/global.d.ts +0 -22
  422. package/shared/axis-read.ts +0 -28
  423. package/shared/entity-delta.ts +0 -335
  424. package/shared/kpi-broadcast.ts +0 -13
  425. package/shared/touched-items.ts +0 -73
  426. package/shared/twin-level.ts +0 -48
  427. package/test/ack-shape-alignment.test.ts +0 -97
  428. package/test/actuation-advisor.test.ts +0 -55
  429. package/test/actuation-approval-door.test.ts +0 -411
  430. package/test/actuation-dispatch.test.ts +0 -209
  431. package/test/actuation-effect.test.ts +0 -162
  432. package/test/actuation-outcome.test.ts +0 -152
  433. package/test/actuation-rule-runner.test.ts +0 -281
  434. package/test/actuation-rule.test.ts +0 -266
  435. package/test/actuation-seam.test.ts +0 -255
  436. package/test/actuation-settle.test.ts +0 -164
  437. package/test/actuation-target.test.ts +0 -145
  438. package/test/actuation-verification-state.test.ts +0 -139
  439. package/test/adopt-structure-live.test.ts +0 -133
  440. package/test/aggregate-not-findone.test.ts +0 -112
  441. package/test/area-resolver-db.test.ts +0 -110
  442. package/test/attention-digest.test.ts +0 -161
  443. package/test/axis-declaration-passthrough-db.test.ts +0 -152
  444. package/test/axis-journal-evidence.test.ts +0 -71
  445. package/test/axis-read.test.ts +0 -188
  446. package/test/backfill-shape.test.ts +0 -89
  447. package/test/boot-resume.test.ts +0 -287
  448. package/test/broadcast-cost-baseline.test.ts +0 -201
  449. package/test/broadcast-period.test.ts +0 -58
  450. package/test/broadcast-queue-overflow.test.ts +0 -244
  451. package/test/canonical-ingest-vocabularies.test.ts +0 -451
  452. package/test/canonical-quantity-door.test.ts +0 -61
  453. package/test/capability-mapping.test.ts +0 -89
  454. package/test/checkpoint-refuses-empty.test.ts +0 -103
  455. package/test/choose-recipe.test.ts +0 -117
  456. package/test/column-type-portability.test.ts +0 -122
  457. package/test/command-routing.test.ts +0 -61
  458. package/test/command-store-writes-columns.test.ts +0 -126
  459. package/test/connection-portability-doors.test.ts +0 -87
  460. package/test/connector-capability-declaration.test.ts +0 -195
  461. package/test/contract-layer-guard.test.ts +0 -48
  462. package/test/control-capability.test.ts +0 -98
  463. package/test/cursor-stall-not-read-failure.test.ts +0 -126
  464. package/test/declaration-reaches-model.test.ts +0 -226
  465. package/test/declared-location-types.test.ts +0 -89
  466. package/test/declared-stimulus.test.ts +0 -88
  467. package/test/dedupe-transformation.test.ts +0 -112
  468. package/test/discovery-result.test.ts +0 -75
  469. package/test/dispatch-after-approval-source.test.ts +0 -81
  470. package/test/duration-estimators.test.ts +0 -144
  471. package/test/energy-topology.test.ts +0 -113
  472. package/test/entity-delta.test.ts +0 -352
  473. package/test/equipment-identity-reaches.test.ts +0 -57
  474. package/test/event-subjects.test.ts +0 -148
  475. package/test/event-time-column.test.ts +0 -67
  476. package/test/event-type-split.test.ts +0 -178
  477. package/test/external-resolver.test.ts +0 -177
  478. package/test/fact-scope-wiring.test.ts +0 -96
  479. package/test/fill-dedupe.test.ts +0 -59
  480. package/test/fill-loop.test.ts +0 -35
  481. package/test/first-envelope.test.ts +0 -153
  482. package/test/fold-gap-speaks.test.ts +0 -53
  483. package/test/fold-shift-dst.test.ts +0 -110
  484. package/test/forecast-metrics.test.ts +0 -157
  485. package/test/forecast-tuning.test.ts +0 -42
  486. package/test/gap-analytics.test.ts +0 -113
  487. package/test/generated-not-counted.test.ts +0 -99
  488. package/test/guard-roots.ts +0 -76
  489. package/test/home-in-area.test.ts +0 -90
  490. package/test/hook-address.test.ts +0 -28
  491. package/test/hook-rejected-shape.test.ts +0 -86
  492. package/test/hook-response-sum.test.ts +0 -193
  493. package/test/hook-sequence.test.ts +0 -333
  494. package/test/ingest-bench.test.ts +0 -70
  495. package/test/ingest-dedupe.test.ts +0 -56
  496. package/test/ingest-expected-quiet.test.ts +0 -111
  497. package/test/ingest-health-engine.test.ts +0 -248
  498. package/test/ingest-health-wiring.test.ts +0 -120
  499. package/test/ingest-health.test.ts +0 -306
  500. package/test/ingest-history.test.ts +0 -247
  501. package/test/ingest-idempotent.test.ts +0 -211
  502. package/test/ingest-reconcile-four-ways.test.ts +0 -97
  503. package/test/ingest-rules-header.test.ts +0 -100
  504. package/test/ingest-running-guard.test.ts +0 -136
  505. package/test/ingest-space.test.ts +0 -78
  506. package/test/ingest-window-rolls-unobserved.test.ts +0 -72
  507. package/test/ingest-wiring-guard.test.ts +0 -197
  508. package/test/instance-cache-lifecycle.test.ts +0 -110
  509. package/test/intake-mapping-parity.test.ts +0 -175
  510. package/test/integration-probes.test.ts +0 -103
  511. package/test/integration-runner.test.ts +0 -95
  512. package/test/item-ref.test.ts +0 -78
  513. package/test/journal-order-axis.test.ts +0 -80
  514. package/test/journal-read-discipline.test.ts +0 -186
  515. package/test/journal-retention.test.ts +0 -275
  516. package/test/journal-sort-axis.test.ts +0 -142
  517. package/test/journal-write-door.test.ts +0 -110
  518. package/test/journal-write-trend.test.ts +0 -115
  519. package/test/kernel-kind-guard.test.ts +0 -98
  520. package/test/knob-defaults.test.ts +0 -72
  521. package/test/kpi-baseline-db.test.ts +0 -216
  522. package/test/kpi-baseline.test.ts +0 -196
  523. package/test/kpi-fold.test.ts +0 -1456
  524. package/test/kpi-query-bench.test.ts +0 -130
  525. package/test/lens-own-places.test.ts +0 -50
  526. package/test/lineage-survives-restart.test.ts +0 -234
  527. package/test/live-cadence.test.ts +0 -170
  528. package/test/live-cursor-wiring.test.ts +0 -87
  529. package/test/live-feed-lease.test.ts +0 -63
  530. package/test/live-feed-registry.test.ts +0 -75
  531. package/test/live-kernel-facts.test.ts +0 -161
  532. package/test/live-mirror-parity.test.ts +0 -286
  533. package/test/load-meter.test.ts +0 -328
  534. package/test/local-declarations.test.ts +0 -662
  535. package/test/log-stamp.test.ts +0 -59
  536. package/test/loop-lag.test.ts +0 -82
  537. package/test/master-to-twin.test.ts +0 -279
  538. package/test/measured-yield.test.ts +0 -90
  539. package/test/merge-streams.test.ts +0 -70
  540. package/test/mirror-resumes-from-checkpoint.test.ts +0 -192
  541. package/test/model-basis.test.ts +0 -141
  542. package/test/model-gap.test.ts +0 -153
  543. package/test/model-refusal.test.ts +0 -75
  544. package/test/model-vocabulary.test.ts +0 -114
  545. package/test/move-space.test.ts +0 -149
  546. package/test/mutation-gate.test.ts +0 -122
  547. package/test/oee-accumulator.test.ts +0 -204
  548. package/test/oee-site-calendar.test.ts +0 -146
  549. package/test/open-doors.test.ts +0 -197
  550. package/test/operation-basis.test.ts +0 -127
  551. package/test/operational-vocabulary.test.ts +0 -108
  552. package/test/operations-capability-db.test.ts +0 -165
  553. package/test/order-and-transaction-split.test.ts +0 -107
  554. package/test/order-fold-host.test.ts +0 -112
  555. package/test/producer-guard.test.ts +0 -66
  556. package/test/project-structure-db.test.ts +0 -226
  557. package/test/projection-reaches-screen.test.ts +0 -277
  558. package/test/projection-reads-declared.test.ts +0 -109
  559. package/test/property-effects.test.ts +0 -128
  560. package/test/provenance-promotion.test.ts +0 -99
  561. package/test/read-failure-ledger.test.ts +0 -106
  562. package/test/read-failure-visible.test.ts +0 -145
  563. package/test/read-time.test.ts +0 -118
  564. package/test/reference-fill.test.ts +0 -235
  565. package/test/reference-grounding.test.ts +0 -70
  566. package/test/reference-hook.test.ts +0 -177
  567. package/test/reference-links.test.ts +0 -56
  568. package/test/reference-reconciliation.test.ts +0 -39
  569. package/test/registry-key-guard.test.ts +0 -80
  570. package/test/rejection-carries-event-id.test.ts +0 -101
  571. package/test/rename-twin.test.ts +0 -89
  572. package/test/resolve-ts-siblings.mjs +0 -52
  573. package/test/restart-policy.test.ts +0 -111
  574. package/test/resync-origin-site.test.ts +0 -83
  575. package/test/retry-plan.test.ts +0 -139
  576. package/test/revision-axis.test.ts +0 -110
  577. package/test/runtime-key.test.ts +0 -66
  578. package/test/save-intake-collision.test.ts +0 -91
  579. package/test/scale-twin-bench.test.ts +0 -103
  580. package/test/secrets-at-rest.test.ts +0 -135
  581. package/test/snapshot-freshness.test.ts +0 -60
  582. package/test/source-outcome-audit.test.ts +0 -104
  583. package/test/space-integrity.test.ts +0 -223
  584. package/test/space-representation.test.ts +0 -66
  585. package/test/space-scope-includes-stopped.test.ts +0 -55
  586. package/test/spec-coverage.test.ts +0 -113
  587. package/test/stage-path.test.ts +0 -95
  588. package/test/standard-coverage.test.ts +0 -148
  589. package/test/state-axes.test.ts +0 -74
  590. package/test/status-tally.test.ts +0 -55
  591. package/test/streamline-e2e.test.ts +0 -76
  592. package/test/structure-revision-db.test.ts +0 -315
  593. package/test/subject-fast-path.test.ts +0 -148
  594. package/test/subject-read-model.test.ts +0 -175
  595. package/test/sweep-dispatch.test.ts +0 -191
  596. package/test/tenant-registry-db.test.ts +0 -149
  597. package/test/time-range.test.ts +0 -152
  598. package/test/touched-items.test.ts +0 -61
  599. package/test/twin-audit.test.ts +0 -83
  600. package/test/twin-event-keys.test.ts +0 -193
  601. package/test/twin-model-item-db.test.ts +0 -319
  602. package/test/twin-model-parent-relation-db.test.ts +0 -125
  603. package/test/twin-model-tree-db.test.ts +0 -209
  604. package/test/twin-origin-resync.test.ts +0 -133
  605. package/test/twin-state-channel.test.ts +0 -111
  606. package/test/vocabulary-guard.test.ts +0 -43
  607. package/test/warm-start-seam.test.ts +0 -162
  608. package/test/warm-start.test.ts +0 -297
  609. package/test/withheld-door.test.ts +0 -95
  610. package/test/yield-loop.test.ts +0 -199
  611. package/tsconfig.json +0 -15
  612. package/tsconfig.shared.json +0 -23
  613. package/tsconfig.shared.tsbuildinfo +0 -1
  614. package/tsconfig.tsbuildinfo +0 -1
@@ -1,110 +0,0 @@
1
- /*
2
- * **저널을 쓰는 문은 하나다** — 그리고 멈출 때 남은 것을 흘린다 (ingest-scale §7.1, 2026-08-20).
3
- *
4
- * ── 무엇이 관측됐나 ─────────────────────────────────────────────────────────
5
- * 데모 자극을 켠 트윈 23개가 도는 서버에서 프로세스가 CPU 81~112% 를 계속 쓰고, 아무 일도 하지 않는
6
- * 질의가 `twinLoad` 8초 · `twinInstanceList` 14초였다. `sample` 프로파일은 `JSON.parse`·대형 GC·
7
- * 스레드풀을 가리켰고, 계기는 **틱의 몫이 16%** 라고 말했다 — 틱이 아니었다.
8
- *
9
- * 코드가 이유였다: 기록 경로가 둘인데 **배치는 라이브만**이었다.
10
- * · 라이브 — 200ms 마다 모아 벌크 저장
11
- * · 시뮬 — 커널이 낸 **델타 하나마다** 행 하나 저장(그리고 그 안에서 구조 리비전을 물었다)
12
- *
13
- * 같은 파일이 **브로드캐스팅**에서 같은 함정을 이미 겪고 고쳤다(틱 하나가 35초). 쓰기만 단건으로 남아 있었다.
14
- * ADR-0030 이 *"기록 경로가 둘인 것은 시뮬만 옆문으로 들어오기 때문"* 이라 예고한 그 자리다.
15
- *
16
- * ── 성능을 사려고 사실을 팔지 않는다 ────────────────────────────────────────
17
- * 배치로 옮기면 주기 사이에 멈출 때 그 구간이 사라진다 — **라이브도 이미 그랬다**(최대 200ms). 그래서
18
- * 정지 때 남은 것을 흘리는 자리를 함께 만들었다. 상태만 남기고 저널을 잃으면 「왜 그렇게 됐나」가 빈다.
19
- *
20
- * 이 시험은 소스로 규율을 지킨다(DB 없이 도는 스위트다). 정량화는 들어온 것이 없는 서버의 `journalRate` 가 답한다.
21
- */
22
- import { test } from 'node:test'
23
- import assert from 'node:assert/strict'
24
- import { readFileSync } from 'node:fs'
25
- import { fileURLToPath } from 'node:url'
26
-
27
- const engine = readFileSync(fileURLToPath(new URL('../server/engine/twin-engine.ts', import.meta.url)), 'utf-8')
28
-
29
- /**
30
- * 메서드 본문만 — 다른 자리의 같은 낱말에 걸리지 않게.
31
- *
32
- * **다음 메서드 선언에서 끊는다.** 길이로 자르면 옆 메서드가 딸려 와, 「이 메서드가 몇 번 부르나」를
33
- * 세는 단정이 오류 없이 틀린 값을 낸다(실제로 그렇게 2를 세었다).
34
- */
35
- function methodOf(src: string, name: string): string {
36
- const at = src.indexOf(`${name}(`)
37
- assert.ok(at >= 0, `${name} 가 없다`)
38
- const rest = src.slice(at + name.length)
39
- const next = rest.search(/\n (static|private static|async|[a-zA-Z]+\()/)
40
- return rest.slice(0, next > 0 ? next : 3000)
41
- }
42
-
43
- test('시뮬이 델타마다 행을 쓰지 않는다 — 모아서 한 문으로 보낸다', () => {
44
- const at = engine.indexOf("if (msg.kind === 'delta')")
45
- const body = engine.slice(at, at + 2600)
46
- assert.match(body, /pendingJournal/, '델타는 버퍼에 담긴다')
47
- assert.equal(/this\.persist\(domainId, id, msg\)/.test(body), false, '단건 저장으로 되돌아갔다')
48
- })
49
-
50
- test('단건 저장 경로가 아예 없다 — 남겨 두면 다시 부를 자리가 된다', () => {
51
- assert.equal(/static async persist\(domainId/.test(engine), false, '`persist` 가 되살아났다')
52
- /* 쓰는 문은 둘이지만 **부르는 자리는 하나**다(`flushJournal`). */
53
- /* 약속을 돌려준다 — 정지가 기다릴 수 있어야 한다(기다리지 않으면 웜스타트가 빈 저널을 읽는다). */
54
- assert.match(engine, /private static flushJournal\(inst: InstanceRuntime\): Promise<void>/)
55
- assert.match(engine, /await this\.flushJournal\(i\)/, '정지는 흘리기를 기다린다')
56
- assert.match(engine, /static async persistBatch\(/)
57
- assert.match(engine, /static async persistCarried\(/)
58
- /* 넣기만 한다 — `save` 는 행마다 SELECT 를 한 번 더 한다(시험 로그에서 그 질의가 보였다). */
59
- assert.match(engine, /private static async insertRows\(/)
60
- assert.equal(/repo\.save\(rows, \{ chunk: 500 \}\)/.test(engine), false, '저널을 save 로 넣는 모양으로 되돌아갔다')
61
- })
62
-
63
- test('커널이 매긴 리비전을 호스트가 다시 번호 붙이지 않는다 — 시간여행이 그것을 딛는다', () => {
64
- const flush = methodOf(engine, 'private static flushJournal')
65
- /* 시뮬은 자기 리비전을 들고 오고(`{ event, revision }`), 라이브는 flush 에서 이어 붙인다. */
66
- assert.match(flush, /typeof b\.revision === 'number'/, '들고 온 리비전을 가려낸다')
67
- assert.match(flush, /inst\.revision = start \+ plain\.length/, '라이브만 이어 붙인다')
68
- const carried = methodOf(engine, 'static async persistCarried')
69
- assert.match(carried, /it\.revision/, '들고 온 리비전을 그대로 쓴다')
70
- /* 구조 리비전은 배치에 **한 번**만 묻는다 — 행마다 묻던 것이 문제였다. */
71
- assert.equal((carried.match(/structureRevOf/g) ?? []).length, 1)
72
- })
73
-
74
- test('멈출 때 남은 것을 흘린다 — 성능을 사려고 사실을 팔지 않는다', () => {
75
- const stop = methodOf(engine, 'static async stop')
76
- assert.match(stop, /this\.flushJournal\(i\)/, '정지 경로가 버퍼를 흘린다')
77
- const flushAt = stop.indexOf('this.flushJournal(i)')
78
- const dropAt = stop.indexOf('delete this.instances')
79
- assert.ok(flushAt >= 0 && dropAt >= 0 && flushAt < dropAt, '런타임을 버리기 전에 흘려야 한다')
80
- })
81
-
82
- test('두 구동이 같은 계기를 든다 — 세지 않는 개선은 되돌려도 아무도 모른다', () => {
83
- /*
84
- * 계기(`inst.metrics`)가 `startLive` 에만 있었다. 그래서 도는 트윈 22개가 시뮬인 서버에서 「초당 몇 행을
85
- * 쓰나」·「밀린 게 있나」를 물을 자리가 없었고, 모니터 목록에서도 시뮬이 알리지 않고 빠졌다(계기가 null 이라
86
- * 걸러졌다) — 부하가 거의 없는 것처럼 보였다.
87
- */
88
- assert.match(engine, /private static newMetrics\(\): TwinMetrics/, '계기 한 벌을 한 곳에서 만든다')
89
- const sim = engine.slice(engine.indexOf("mode: 'sim'"), engine.indexOf("mode: 'sim'") + 1200)
90
- assert.match(sim, /metrics: this\.newMetrics\(\)/, '시뮬도 계기를 든다')
91
- /* 비율 갱신이 라이브만 보면 시뮬 칸은 영원히 0 이다. */
92
- assert.equal(/const m = isLive \? inst\.metrics : undefined/.test(engine), false, '비율 갱신이 시뮬을 다시 잘라 냈다')
93
- })
94
-
95
- test('적은 것을 장부에 남긴다 — 계기는 지금만 답하고 재기동에 0 으로 돌아간다', () => {
96
- const flush = methodOf(engine, 'private static flushJournal')
97
- /* 실패한 배치를 「남았다」고 세지 않으려면 **쓴 뒤에** 적어야 한다. */
98
- assert.match(flush, /this\.recordJournalWrite\(inst\.domainId, inst\.id, written\)/)
99
- const thenAt = flush.indexOf('.then(')
100
- const recAt = flush.indexOf('this.recordJournalWrite')
101
- assert.ok(thenAt >= 0 && recAt > thenAt, '약속이 풀린 뒤에 적는다 — 터진 배치를 세지 않게')
102
- })
103
-
104
- test('구조 리비전은 「없다」도 기억한다 — 없는 트윈이 부를 때마다 질의하지 않게', () => {
105
- const body = methodOf(engine, 'static async structureRevOf')
106
- assert.match(body, /this\.structureRevCache\[key\] = latest \? latest\.rev : null/, '미스를 기억한다')
107
- assert.equal(/if \(latest\) this\.structureRevCache/.test(body), false, '미스를 흘려버리는 모양으로 되돌아갔다')
108
- /* 캐시가 `null` 을 담으므로 「모름」과 구별된다 — 형이 그 사실을 말해야 다음 사람이 0 으로 읽지 않는다. */
109
- assert.match(engine, /structureRevCache: Record<string, number \| null>/)
110
- })
@@ -1,115 +0,0 @@
1
- /*
2
- * **적은 것도 추이로 남는다** — 「저널이 얼마나 쓰이고 있나」를 나중에도 물을 수 있게 (2026-08-20).
3
- *
4
- * ── 왜 필요한가 ─────────────────────────────────────────────────────────────
5
- * 계기(`journalRate`·`journaledTotal`)는 **지금**만 답한다. 프로세스를 다시 띄우면 0 에서 시작하므로
6
- * 「어제 이 시각에도 이랬나」·「고친 뒤로 정말 줄었나」를 물을 자리가 없었다. 그런데 2026-08-20 에 고친
7
- * 것이 바로 쓰기 경로(델타마다 한 행 → 창당 한 번)다. 세지 않는 개선은 되돌아가도 아무도 모른다.
8
- *
9
- * ── 왜 새 장부를 만들지 않았나 ──────────────────────────────────────────────
10
- * 유입 창은 「닫힌 창만 최근」·「0 과 없음을 가른다」·「밀려난 것을 세어 드러낸다」를 이미 지키고, 닫힐 때
11
- * 행으로 남는다. 같은 규율을 두 벌 만들면 한 벌만 고쳐진다. 그래서 그 창에 칸을 더했다.
12
- *
13
- * ── 이 시험이 지키는 것 ─────────────────────────────────────────────────────
14
- * ① 유입이 한 번도 없어도 쓰기가 창을 넘긴다 — 시뮬 트윈이 추이에서 사라지지 않게.
15
- * ② 행과 왕복을 **따로** 센다 — 행당 왕복이 1 로 되돌아가면 그것이 보인다.
16
- * ③ 쓰기는 **「마지막 유입」을 갱신하지 않는다** — 섞으면 끊긴 피드가 옛 창으로 초록을 낸다.
17
- * ④ 없는 것을 0 건 쓰기로 만들지 않는다.
18
- * ⑤ 쓰기만 있는 장부의 시각이 1969년으로 뜨지 않는다.
19
- */
20
- import { test } from 'node:test'
21
- import assert from 'node:assert/strict'
22
-
23
- import {
24
- INGEST_WINDOW_MS,
25
- STALE_AFTER_MS,
26
- ingestHealth,
27
- newIngestLedger,
28
- recordIngest,
29
- recordJournalWrite
30
- } from '../server/engine/ingest-health.ts'
31
-
32
- const T0 = 1_700_000_000_000
33
-
34
- /* ── ① 유입 없이도 추이가 생긴다 ──────────────────────────────────────────── */
35
-
36
- test('받는 것 없이 적기만 하는 트윈도 추이에 남는다 — 시뮬이 오류 없이 빠지지 않게', () => {
37
- const l = newIngestLedger()
38
- const closed: any[] = []
39
-
40
- recordJournalWrite(l, 40, T0, w => closed.push(w))
41
- recordJournalWrite(l, 60, T0 + 1000, w => closed.push(w))
42
- /* 창 길이를 넘긴 뒤의 쓰기가 앞 창을 닫는다. */
43
- recordJournalWrite(l, 10, T0 + INGEST_WINDOW_MS + 1, w => closed.push(w))
44
-
45
- assert.equal(closed.length, 1, '창이 닫혀 영속 훅까지 불린다')
46
- assert.equal(closed[0].rows, 100)
47
- assert.equal(closed[0].offered, 0, '유입은 0 이다 — 그것도 사실이다')
48
-
49
- const view = ingestHealth(l, 'not-applicable', undefined, T0 + INGEST_WINDOW_MS + 2)
50
- assert.equal(view.trend.length, 1, '유입 시각이 없다는 이유로 빈 화면을 내지 않는다')
51
- assert.equal(view.trend[0].rows, 100)
52
- assert.equal(view.total.rows, 110, '누적은 열린 창까지 센다')
53
- })
54
-
55
- /* ── ② 행과 왕복을 따로 센다 ──────────────────────────────────────────────── */
56
-
57
- test('행과 왕복을 따로 센다 — 행당 왕복이 1 로 되돌아가면 그것이 보인다', () => {
58
- const batched = newIngestLedger()
59
- recordJournalWrite(batched, 500, T0)
60
- recordJournalWrite(batched, 500, T0 + 200)
61
- assert.equal(batched.rows, 1000)
62
- assert.equal(batched.flushes, 2, '모아 보낸 것은 두 번이다')
63
-
64
- /* 되돌아간 모양 — 같은 1,000행에 왕복 1,000번. 행 수만 세면 두 장부가 똑같이 보인다. */
65
- const perDelta = newIngestLedger()
66
- for (let i = 0; i < 1000; i++) recordJournalWrite(perDelta, 1, T0 + i)
67
- assert.equal(perDelta.rows, batched.rows, '행 수는 같다 — 그래서 행만으로는 가려낼 수 없다')
68
- assert.ok(perDelta.flushes > batched.flushes * 100, '왕복 수가 그 차이를 드러낸다')
69
- })
70
-
71
- /* ── ③ 축을 섞지 않는다 ───────────────────────────────────────────────────── */
72
-
73
- test('쓰기가 「마지막 유입」을 갱신하지 않는다 — 끊긴 피드가 초록으로 보이지 않게', () => {
74
- const l = newIngestLedger()
75
- /* 건강한 유입이 한동안 있었고, 그 뒤 피드가 끊겼다. */
76
- recordIngest(l, 100, [], T0)
77
- recordIngest(l, 100, [], T0 + INGEST_WINDOW_MS + 1) /* 앞 창을 닫아 「최근」을 만든다 */
78
-
79
- const muchLater = T0 + INGEST_WINDOW_MS + STALE_AFTER_MS + 60_000
80
- /* 그 사이에도 트윈은 틱이 만든 델타를 계속 적는다 — 라이브에서 실제로 그렇다. */
81
- for (let t = T0 + 60_000; t < muchLater; t += 60_000) recordJournalWrite(l, 5, t)
82
-
83
- const view = ingestHealth(l, 'attached', undefined, muchLater)
84
- /*
85
- * 판정이 초록이 아니어야 한다. 어떤 말로 부르는지는 창의 모양에 달렸다(마지막 닫힌 창이 유입 0 이면
86
- * 「유입 없음」, 창이 아직 안 닫혔으면 「끊긴 피드」) — 둘 다 「받고 있지 않다」다. 못 박는 것은 **적고
87
- * 있다는 사실이 「받고 있다」로 번역되지 않는다**는 것이다.
88
- */
89
- assert.notEqual(view.verdict, 'healthy', '적고 있다는 사실이 「받고 있다」로 번역되지 않는다')
90
- assert.equal(view.lastAt, new Date(T0 + INGEST_WINDOW_MS + 1).toISOString(), '마지막 유입 시각이 쓰기로 밀리지 않는다')
91
- assert.equal(view.lastWriteAt, new Date(muchLater - 60_000).toISOString(), '적은 시각은 따로 낸다')
92
- })
93
-
94
- /* ── ④⑤ 없는 것과 0 ──────────────────────────────────────────────────────── */
95
-
96
- test('없는 것을 0 건 쓰기로 만들지 않는다', () => {
97
- const l = newIngestLedger()
98
- for (const bad of [0, -3, NaN, Infinity]) recordJournalWrite(l, bad as number, T0)
99
- assert.equal(l.flushes, 0, '아무 일도 없었으면 왕복도 없다')
100
- assert.equal(l.rows, 0)
101
- assert.equal(l.lastWriteAtMs, -1, '적지 않았으면 적은 시각도 없다')
102
- assert.equal(ingestHealth(l, 'not-applicable', undefined, T0).lastWriteAt, null)
103
- })
104
-
105
- test('쓰기만 있는 장부의 시각이 1969년으로 뜨지 않는다 — `-1` 을 시각으로 읽지 않는다', () => {
106
- const l = newIngestLedger()
107
- recordJournalWrite(l, 7, T0)
108
- recordJournalWrite(l, 7, T0 + INGEST_WINDOW_MS + 1)
109
-
110
- const view = ingestHealth(l, 'not-applicable', undefined, T0 + INGEST_WINDOW_MS + 2)
111
- assert.equal(view.lastAt, null, '받은 적이 없으면 유입 시각은 **없다**(0 이 아니다)')
112
- for (const w of [...view.trend, view.recent!]) {
113
- assert.ok(new Date(w.to).getUTCFullYear() >= 2023, `창 끝 시각이 ${w.to} 로 떴다`)
114
- }
115
- })
@@ -1,98 +0,0 @@
1
- /*
2
- * 커널 선택 가드 — **모르는 종류로는 뜨지 않는다.**
3
- *
4
- * ── 무엇이 있었나 (2026-08-08) ───────────────────────────────────────────────
5
- * 커널을 고르는 자리 셋이 모두 이랬다:
6
- *
7
- * const Kernel = KERNELS[reg.kind ?? 'wms'] ?? WmsKernel
8
- *
9
- * 폴백이 둘 겹쳐 있었다. ①은 컬럼이 비었을 때, ②는 표에 없는 값일 때. 그리고 `kind` 는
10
- * 검증 없는 자유 문자열이다(`@Arg('kind') kind: string` — enum 도 화이트리스트도 없다).
11
- * 그래서 오타 하나·대소문자 하나로 **야드/생산 트윈이 오류 없이 창고 커널로 돌았다.**
12
- * 오류가 없으니 화면에는 트윈이 정상으로 보이고, 안에서 도는 규칙만 다른 도메인의 것이다.
13
- * 예측 경로가 가장 나빴다 — 야드의 미래를 창고 규칙으로 굴려 놓고 숫자만 뜬다.
14
- *
15
- * ── 왜 검사로 남기나 ────────────────────────────────────────────────────────
16
- * 자리를 고치는 것만으로는 부족하다. 커널 종류가 늘 때(다음은 TMS 든 무엇이든) 새 자리가
17
- * 생기고, `?? WmsKernel` 은 "안전한 기본값" 처럼 보여서 다시 자란다. 실제로 세 자리에
18
- * 똑같이 자라 있었다. 틀린 공장을 알리지 않고 띄우는 것보다 뜨지 않는 편이 낫다.
19
- *
20
- * 이 검사가 막는 것은 **표를 밖에서 직접 색인하는 것**이다. 종류→커널 해소는 `kernelFor`
21
- * 하나만 한다. 새 자리를 쓸 때 이 검사가 걸리면, 폴백을 붙이지 말고 `kernelFor` 를 부를 것.
22
- */
23
- import { test } from 'node:test'
24
- import assert from 'node:assert/strict'
25
- import { readdirSync, readFileSync, statSync } from 'node:fs'
26
- import { join } from 'node:path'
27
-
28
- import { guardRoots } from './guard-roots.ts'
29
-
30
- const ENGINE = new URL('../server/engine/twin-engine.ts', import.meta.url).pathname
31
- const MUTATION = new URL('../server/service/twin-lifecycle/twin-lifecycle-mutation.ts', import.meta.url).pathname
32
-
33
- /*
34
- * 종류 폴백은 **한 패키지에 갇혀 있지 않다.** 처음에 twin-engine 두 자리만 고쳤더니, 라이브 미러를
35
- * 띄우는 호출자 넷(operato-twin 의 벤치·부하시험·프리셋 프로비저닝, headless 의 reference-live)이
36
- * `det.kind ?? 'wms'` 로 **엔진이 오류를 내기 전에 먼저 값을 정하고** 있었다. 커넥터 spec 도 마찬가지였다.
37
- * 그래서 두 패키지의 서버 코드를 함께 훑는다.
38
- */
39
- const ROOTS = guardRoots(import.meta.url, ['../server'])
40
-
41
- /**
42
- * 코드만 본다 — 주석은 **과거를 설명하느라 옛 코드를 그대로 인용한다**(바로 위 머리말이 그렇다).
43
- * 줄 단위로 `*`·`//` 만 걸러내면 여러 줄 주석의 둘째 줄부터 새어 나오므로 블록을 통째로 지운다.
44
- */
45
- function codeOf(path: string): string[] {
46
- return readFileSync(path, 'utf-8')
47
- .replace(/\/\*[\s\S]*?\*\//g, '') // 블록 주석
48
- .split('\n')
49
- .map(l => l.replace(/\/\/.*$/, '')) // 줄 주석
50
- .filter(l => l.trim())
51
- }
52
-
53
- test('커널 폴백이 없다 — 모르는 종류는 창고로 떨어지지 않는다', () => {
54
- const offenders = codeOf(ENGINE).filter(l => /\?\?\s*WmsKernel|\|\|\s*WmsKernel/.test(l))
55
- assert.deepEqual(offenders, [], '커널 선택에 폴백이 다시 생겼다 — kernelFor 가 오류를 내게 할 것')
56
- })
57
-
58
- test('종류→커널 해소는 kernelFor 한 곳만 한다', () => {
59
- /* 표를 직접 색인하는 줄. 정의부(`const KERNELS: Record…`)와 kernelFor 내부는 제외. */
60
- const indexing = codeOf(ENGINE).filter(l => /KERNELS\[/.test(l) && !/const K = KERNELS\[kind\]/.test(l))
61
- assert.deepEqual(indexing, [], 'KERNELS 를 밖에서 색인하고 있다 — kernelFor(kind) 를 쓸 것')
62
- })
63
-
64
- test('kernelFor 는 모르는 종류에 오류를 낸다 — 알리지 않고 고르지 않는다', () => {
65
- const src = readFileSync(ENGINE, 'utf-8')
66
- const fn = src.slice(src.indexOf('function kernelFor'))
67
- assert.match(fn.slice(0, 300), /throw new Error/, 'kernelFor 가 오류를 내지 않으면 이 계약이 무너진다')
68
- })
69
-
70
- test("board 를 주는 기동은 kind 를 요구한다 — `kind ?? 'wms'` 로 메우지 않는다", () => {
71
- const offenders = codeOf(MUTATION).filter(l => /kind\s*\?\?\s*['"]/.test(l))
72
- assert.deepEqual(offenders, [], '종류를 빠뜨린 프로비저닝이 다시 창고로 기동한다')
73
- })
74
-
75
- /** 두 패키지의 서버 .ts 전부. */
76
- function serverFiles(): string[] {
77
- const out: string[] = []
78
- const walk = (dir: string) => {
79
- for (const e of readdirSync(dir)) {
80
- const p = join(dir, e)
81
- if (statSync(p).isDirectory()) walk(p)
82
- else if (p.endsWith('.ts') && !p.endsWith('.d.ts')) out.push(p)
83
- }
84
- }
85
- for (const r of ROOTS) walk(r)
86
- return out
87
- }
88
-
89
- test('어느 서버 코드도 커널 종류를 리터럴로 메우지 않는다 — 호출자가 엔진의 검증을 앞질렀다', () => {
90
- /* 예시 JSON 안의 `system: 'wms'` 는 필드를 보여 주는 것이라 대상이 아니다 — 폴백 연산자만 본다. */
91
- const offenders: string[] = []
92
- for (const f of serverFiles()) {
93
- codeOf(f).forEach(l => {
94
- if (/(\?\?|\|\|)\s*['"](wms|yms|mes)['"]/.test(l)) offenders.push(`${f.split('/packages/')[1]}: ${l.trim().slice(0, 90)}`)
95
- })
96
- }
97
- assert.deepEqual(offenders, [], '종류 폴백이 다시 생겼다 — 선언이 없으면 메우지 말고 던질 것')
98
- })
@@ -1,72 +0,0 @@
1
- /*
2
- * 노브 기본값 — **알리지 않고 아무것도 안 하는 트윈**이 만들어지지 않게.
3
- *
4
- * 기본값을 아는 곳은 노브 스키마(계약)인데 그것을 적용하는 곳이 위자드뿐이었다. 그래서 화면을 거치지
5
- * 않는 호출자가 파라미터를 일부만 주면 템플릿 안에서 발생률이 0 이 되고, 이벤트를 하나도 만들지 않는
6
- * 트윈이 아무 말 없이 생겼다(실제로 밟았고 템플릿이 깨진 것으로 오진했다).
7
- */
8
- import { test } from 'node:test'
9
- import assert from 'node:assert/strict'
10
-
11
- import { applyKnobDefaults, filledKnobKeys } from '../server/service/reference/knob-defaults.ts'
12
-
13
- const KNOBS = [
14
- { key: 'id', default: 'wms-new' },
15
- { key: 'inboundRate', default: 40 },
16
- { key: 'outboundRate', default: 30 },
17
- { key: 'geo', default: { lat: 37.5, lon: 127.0 } },
18
- { key: 'noDefault' } // 기본값을 선언하지 않은 노브
19
- ]
20
-
21
- test('빠진 노브를 기본값으로 채운다 — 부분 파라미터 호출이 죽은 트윈을 만들지 않게', () => {
22
- const out = applyKnobDefaults(KNOBS, { id: 'mine' })
23
- assert.equal(out.id, 'mine', '준 값은 그대로')
24
- assert.equal(out.inboundRate, 40)
25
- assert.equal(out.outboundRate, 30)
26
- assert.deepEqual(out.geo, { lat: 37.5, lon: 127.0 })
27
- assert.ok(!('noDefault' in out), '기본값 없는 노브는 만들어 내지 않는다')
28
- })
29
-
30
- test('0 은 덮지 않는다 — "자극 없이 구조만" 이라는 선언을 뒤집지 않게', () => {
31
- /* falsy 로 판정해 덮으면 발생률 0(도착 없음)이 40 으로 바뀐다. 없는 것과 0 은 다르다. */
32
- const out = applyKnobDefaults(KNOBS, { inboundRate: 0, outboundRate: 0 })
33
- assert.equal(out.inboundRate, 0)
34
- assert.equal(out.outboundRate, 0)
35
- })
36
-
37
- test('빈 문자열·false 도 뜻 있는 값이라 덮지 않는다', () => {
38
- const out = applyKnobDefaults([{ key: 'name', default: 'New site' }, { key: 'flag', default: true }], { name: '', flag: false })
39
- assert.equal(out.name, '')
40
- assert.equal(out.flag, false)
41
- })
42
-
43
- test('null 은 "주지 않음" 으로 본다 — JSON·GraphQL 경로가 그렇게 보낸다', () => {
44
- const out = applyKnobDefaults(KNOBS, { inboundRate: null as any })
45
- assert.equal(out.inboundRate, 40)
46
- })
47
-
48
- test('선언 밖 파라미터는 손대지 않는다 — 템플릿의 폴백 경로를 끊지 않게', () => {
49
- /* 템플릿은 `geo` 대신 `lat`/`lon` 을 읽는 폴백을 가진다. 모르는 키를 걷어내면 그 경로가 끊긴다. */
50
- const out = applyKnobDefaults(KNOBS, { lat: 1, lon: 2 })
51
- assert.equal(out.lat, 1)
52
- assert.equal(out.lon, 2)
53
- })
54
-
55
- test('입력을 바꾸지 않는다 — 호출자의 객체가 몰래 변하면 추적이 어렵다', () => {
56
- const given = { id: 'mine' }
57
- applyKnobDefaults(KNOBS, given)
58
- assert.deepEqual(given, { id: 'mine' })
59
- })
60
-
61
- test('노브가 없거나 파라미터가 없어도 무너지지 않는다', () => {
62
- assert.deepEqual(applyKnobDefaults(null, { a: 1 }), { a: 1 })
63
- assert.deepEqual(applyKnobDefaults(KNOBS, null).inboundRate, 40)
64
- assert.deepEqual(applyKnobDefaults(undefined, undefined), {})
65
- })
66
-
67
- test('무엇을 채웠는지 알린다 — 준 적 없는 값으로 만들어진 것을 밝히게', () => {
68
- assert.deepEqual(filledKnobKeys(KNOBS, { id: 'mine', inboundRate: 0 }), ['outboundRate', 'geo'],
69
- '준 것과 0 은 채운 목록에 없다')
70
- assert.deepEqual(filledKnobKeys(KNOBS, null), ['id', 'inboundRate', 'outboundRate', 'geo'])
71
- assert.deepEqual(filledKnobKeys(KNOBS, { id: 'a', inboundRate: 1, outboundRate: 2, geo: {} }), [], '다 주면 빈 목록')
72
- })
@@ -1,216 +0,0 @@
1
- /*
2
- * ★ 여러 구간 동시 비교 — **실 DB로 배관을 넘어 본다.**
3
- *
4
- * 분포 산수는 `kpi-baseline.test.ts`(순수)가 지킨다. 여기서 지키는 것은 **호스트 배관**이다:
5
- * 창을 하루씩 뒤로 옮겨 **각 창을 따로 읽는가** · 그 창을 같은 규칙으로 계산하는가 · 지표 값을 정본 표
6
- * (`TWIN_METRIC`)로 꺼내는가 · 기록 없는 날을 결측으로 남기는가.
7
- *
8
- * 이 배관은 **경계를 넘어야만** 틀리는 것이 드러난다. 실제로 앱의 시뮬 트윈은 저널이 두 시간 남짓이라
9
- * "지난 7일" 을 물어도 과거 창이 모두 비어 있어(정직하게 자리를 거부한다) 분포 경로를 한 번도 밟지
10
- * 못했다. 그래서 여러 날에 걸친 저널을 손으로 심어 그 경로를 통과시킨다.
11
- *
12
- * 실 엔티티·실 네이밍 전략의 sqlite in-memory 스키마에 **빌드 산출물**을 실행한다.
13
- * **소스를 고친 뒤에는 `npm run build:server` 를 먼저 돌려야 반영된다.**
14
- */
15
- import { test, before, after } from 'node:test'
16
- import assert from 'node:assert/strict'
17
- import { createRequire } from 'node:module'
18
- import type { DataSource } from 'typeorm'
19
-
20
- const req = createRequire(import.meta.url)
21
- const { NamingStrategy, addDataSource, entities: shellEntities, Domain } = req('@things-factory/shell')
22
- const { entities: authEntities } = req('@things-factory/auth-base')
23
- const { entities: twinEntities } = req('../dist-server/service/index.js')
24
- const { computeTwinKpi } = req('../dist-server/engine/index.js')
25
- const { TwinEvent } = req('../dist-server/service/twin-event/twin-event.js')
26
- const { TwinInstance } = req('../dist-server/service/twin-instance/twin-instance.js')
27
- const { DataSource: TypeOrmDataSource } = req('typeorm')
28
-
29
- let ds: DataSource
30
- let domainId: string
31
-
32
- const INSTANCE = 'baseline-probe'
33
- const MS_DAY = 24 * 60 * 60_000
34
-
35
- /** 창의 끝 — 고정 시각을 쓴다(테스트가 벽시계에 흔들리지 않게). */
36
- const TO = Date.parse('2026-03-10T10:00:00.000Z')
37
- const FROM = TO - 60 * 60_000
38
-
39
- /**
40
- * 완료 한 건 = 시작 + 완료 두 줄. 소요시간이 짝맞춤에서 나오므로 둘 다 필요하다.
41
- * 완료 시각이 창 안에 들면 그 창의 성과로 센다.
42
- */
43
- function taskRows(dayBack: number, count: number, workMs: number, revBase: number) {
44
- const rows: any[] = []
45
- const endBase = TO - dayBack * MS_DAY - 60_000 // 창 끝 1분 전에 완료
46
- for (let i = 0; i < count; i++) {
47
- const taskId = `t-${dayBack}-${i}`
48
- const done = endBase - i * 1000
49
- const started = done - workMs
50
- rows.push(
51
- {
52
- domain: { id: domainId },
53
- instanceId: INSTANCE,
54
- revision: revBase + i * 2,
55
- eventType: 'task.status',
56
- eventTime: new Date(started).toISOString(),
57
- payload: { data: { taskId, status: 'in-progress', resourceRef: 'fk-1' } }
58
- },
59
- {
60
- domain: { id: domainId },
61
- instanceId: INSTANCE,
62
- revision: revBase + i * 2 + 1,
63
- eventType: 'task.status',
64
- eventTime: new Date(done).toISOString(),
65
- /* 완료 어휘는 **커널이 소유한다**(`foldTaskRecords`) — 'done' 이 아니라 'completed' 다.
66
- 처음에 'done' 으로 심었더니 창은 잡히는데 건수가 0 이었다(이 DB 스펙이 그것을 잡았다). */
67
- payload: { data: { taskId, status: 'completed', resourceRef: 'fk-1' } }
68
- }
69
- )
70
- }
71
- return rows
72
- }
73
-
74
- before(async () => {
75
- ds = new TypeOrmDataSource({
76
- type: 'sqlite',
77
- database: ':memory:',
78
- synchronize: true,
79
- dropSchema: true,
80
- namingStrategy: new NamingStrategy(),
81
- entities: [...shellEntities, ...authEntities, ...twinEntities],
82
- logging: false
83
- })
84
- await ds.initialize()
85
- addDataSource('default', ds)
86
- const d = await ds.getRepository(Domain).save({ name: 'baseline-test', subdomain: 'baseline-test' } as any)
87
- domainId = d.id
88
-
89
- await ds.getRepository(TwinInstance).save({
90
- domain: { id: domainId },
91
- instanceId: INSTANCE,
92
- kind: 'wms',
93
- restartPolicy: 'reset', /* 선언은 이제 필수 — 비워 두면 읽는 자리마다 기본값을 고른다 */
94
- purpose: 'operational',
95
- status: 'stopped',
96
- model: { locations: [{ id: 'dock', type: 'dock', capacity: 10 }], equipment: [{ id: 'fk-1', kind: 'forklift', homeLocation: 'dock' }] }
97
- } as any)
98
-
99
- /*
100
- * 지금 창 20건 · 어제 40건 · 그제 60건 · **3일 전은 기록 없음** · 4일 전 80건.
101
- * 3일 전을 비워 두는 것이 이 스펙의 요점이다 — 그 날이 결측으로 남고 분포에서 빠지는지 본다
102
- * (알리지 않고 빼면 "지난 4일" 이 실제로는 3일이었다는 것을 아무도 모른다).
103
- */
104
- const rows = [
105
- ...taskRows(0, 20, 30_000, 1000),
106
- ...taskRows(1, 40, 40_000, 3000),
107
- ...taskRows(2, 60, 50_000, 6000),
108
- ...taskRows(4, 80, 60_000, 9000)
109
- ]
110
- await ds.getRepository(TwinEvent).save(rows)
111
- })
112
-
113
- after(async () => {
114
- await ds?.destroy()
115
- })
116
-
117
- const kpi = (periods: number, stride?: 'day' | 'week') =>
118
- computeTwinKpi({
119
- domainId,
120
- instanceId: INSTANCE,
121
- fromTime: new Date(FROM).toISOString(),
122
- toTime: new Date(TO).toISOString(),
123
- baseline: { periods, ...(stride ? { stride } : {}) }
124
- })
125
-
126
- test('과거 창을 하루씩 따로 읽어 분포를 만든다', async () => {
127
- const out: any = await kpi(4)
128
- const tasks = out.baseline.metrics.find((m: any) => m.metric === 'throughput.tasks')
129
-
130
- assert.equal(out.baseline.stride, 'day')
131
- assert.equal(out.baseline.periods, 4)
132
- assert.equal(tasks.current, 20, '지금 창')
133
- /* 어제 40 · 그제 60 · 3일 전 없음 · 4일 전 80. */
134
- assert.deepEqual([tasks.min, tasks.median, tasks.max], [40, 60, 80])
135
- })
136
-
137
- test('기록 없는 날을 **결측으로 남긴다** — 요청한 창 수와 측정된 수를 함께 답한다', async () => {
138
- const out: any = await kpi(4)
139
- const tasks = out.baseline.metrics.find((m: any) => m.metric === 'throughput.tasks')
140
-
141
- assert.equal(tasks.requested, 4)
142
- assert.equal(tasks.measuredCount, 3, '3일 전은 기록이 없다')
143
- assert.equal(tasks.samples.length, 4, '창 자체는 네 개 모두 돌려준다')
144
- assert.deepEqual(tasks.samples.map((s: any) => s.measured), [true, true, false, true])
145
- assert.deepEqual(tasks.samples.map((s: any) => s.value), [40, 60, undefined, 80])
146
- })
147
-
148
- test('처리량이 지난 며칠 중 가장 낮으면 worst — 이 축이 답하려던 질문', async () => {
149
- /* 예전에는 "어제보다 나아졌나" 까지만 답할 수 있었다. 지금 창(20)은 어제(40)보다도 낮고
150
- 최근 어느 날보다도 낮다 — 그것을 한 번에 말할 수 있어야 한다. */
151
- const out: any = await kpi(4)
152
- const tasks = out.baseline.metrics.find((m: any) => m.metric === 'throughput.tasks')
153
-
154
- assert.equal(tasks.standing, 'worst')
155
- assert.equal(tasks.rank, 1, '오름차순 첫째')
156
- assert.equal(tasks.rankOf, 4, '표본 3 + 현재 1')
157
- })
158
-
159
- test('방향은 지표가 안다 — 작업시간이 가장 짧으면 best', async () => {
160
- const out: any = await kpi(4)
161
- const work = out.baseline.metrics.find((m: any) => m.metric === 'workTime.p50Ms')
162
-
163
- assert.equal(work.current, 30_000)
164
- assert.deepEqual([work.min, work.max], [40_000, 60_000])
165
- assert.equal(work.standing, 'best', '짧을수록 좋다')
166
- })
167
-
168
- test('구간 수를 줄이면 그만큼만 본다 — 창을 지어내지 않는다', async () => {
169
- const out: any = await kpi(1)
170
- const tasks = out.baseline.metrics.find((m: any) => m.metric === 'throughput.tasks')
171
-
172
- assert.equal(tasks.requested, 1)
173
- assert.equal(tasks.measuredCount, 1)
174
- /* 표본 하나는 분포가 아니다. */
175
- assert.equal(tasks.noPosition, 'too-few-samples')
176
- assert.equal(tasks.standing, undefined)
177
- })
178
-
179
- test('주 단위는 같은 요일을 본다 — 하루 전 기록에 걸리지 않는다', async () => {
180
- const out: any = await kpi(2, 'week')
181
- const tasks = out.baseline.metrics.find((m: any) => m.metric === 'throughput.tasks')
182
-
183
- assert.equal(out.baseline.stride, 'week')
184
- /* 심어 둔 기록은 최근 나흘뿐이라 지난주 같은 요일에는 아무것도 없다 — 지어내지 않는다. */
185
- assert.equal(tasks.measuredCount, 0)
186
- assert.equal(tasks.noPosition, 'too-few-samples')
187
- })
188
-
189
- test('요청하지 않으면 분포를 만들지 않는다 — 조회가 공짜가 아니다', async () => {
190
- const out: any = await computeTwinKpi({
191
- domainId,
192
- instanceId: INSTANCE,
193
- fromTime: new Date(FROM).toISOString(),
194
- toTime: new Date(TO).toISOString()
195
- })
196
-
197
- assert.equal(out.baseline, undefined)
198
- })
199
-
200
- test('지금 창에 기록이 없어도 분포는 낸다 — 그때가 가장 알고 싶은 순간이다', async () => {
201
- /* 심어 둔 기록이 없는 시각을 창으로 잡는다(3일 전). 평소엔 일이 있었는데 지금 없다 = 멈춘 신호. */
202
- const quietTo = TO - 3 * MS_DAY
203
- const out: any = await computeTwinKpi({
204
- domainId,
205
- instanceId: INSTANCE,
206
- fromTime: new Date(quietTo - 60 * 60_000).toISOString(),
207
- toTime: new Date(quietTo).toISOString(),
208
- baseline: { periods: 2 }
209
- })
210
-
211
- assert.equal(out.measured, false, '지금 창에는 측정할 기록이 없다')
212
- assert.ok(out.baseline, '그래도 분포는 낸다')
213
- const tasks = out.baseline.metrics.find((m: any) => m.metric === 'throughput.tasks')
214
- assert.equal(tasks.measuredCount, 1, '4일 전 하루만 걸린다(5일 전은 기록 없음)')
215
- assert.equal(tasks.samples.find((s: any) => s.measured).value, 80)
216
- })