@things-factory/headless-twin 10.1.278 → 10.1.280

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (614) hide show
  1. package/package.json +21 -7
  2. package/dist-server/engine/attention-digest.js.map +0 -1
  3. package/dist-server/engine/canonical-ingest.js.map +0 -1
  4. package/dist-server/engine/checkpoint-fold.js.map +0 -1
  5. package/dist-server/engine/command-routing.js.map +0 -1
  6. package/dist-server/engine/declared-stimulus.js.map +0 -1
  7. package/dist-server/engine/energy-topology.js.map +0 -1
  8. package/dist-server/engine/event-time.js.map +0 -1
  9. package/dist-server/engine/index.js.map +0 -1
  10. package/dist-server/engine/ingest-dedupe.js.map +0 -1
  11. package/dist-server/engine/ingest-health.js.map +0 -1
  12. package/dist-server/engine/integration-coverage.js.map +0 -1
  13. package/dist-server/engine/integration-probes.js.map +0 -1
  14. package/dist-server/engine/integration-runner.js.map +0 -1
  15. package/dist-server/engine/integration-target-profile.js.map +0 -1
  16. package/dist-server/engine/kpi-baseline.js.map +0 -1
  17. package/dist-server/engine/kpi-fold.js.map +0 -1
  18. package/dist-server/engine/kpi-query.js.map +0 -1
  19. package/dist-server/engine/kpi-target.js.map +0 -1
  20. package/dist-server/engine/live-attentions.js.map +0 -1
  21. package/dist-server/engine/live-feed-registry.js.map +0 -1
  22. package/dist-server/engine/load-meter.js.map +0 -1
  23. package/dist-server/engine/local-declarations.js.map +0 -1
  24. package/dist-server/engine/log.js.map +0 -1
  25. package/dist-server/engine/loop-lag.js.map +0 -1
  26. package/dist-server/engine/measured-estimator.js.map +0 -1
  27. package/dist-server/engine/measured-yield.js.map +0 -1
  28. package/dist-server/engine/model-basis.js.map +0 -1
  29. package/dist-server/engine/model-gap.js.map +0 -1
  30. package/dist-server/engine/model-refusal.js.map +0 -1
  31. package/dist-server/engine/model-vocabulary.js.map +0 -1
  32. package/dist-server/engine/oee-accumulator.js.map +0 -1
  33. package/dist-server/engine/operation-basis.js.map +0 -1
  34. package/dist-server/engine/producer-guard.js.map +0 -1
  35. package/dist-server/engine/property-effects.js.map +0 -1
  36. package/dist-server/engine/read-time.js.map +0 -1
  37. package/dist-server/engine/restart-policy.js.map +0 -1
  38. package/dist-server/engine/runtime-key.js.map +0 -1
  39. package/dist-server/engine/spec-coverage.js.map +0 -1
  40. package/dist-server/engine/stage-path.js.map +0 -1
  41. package/dist-server/engine/state-axes.js.map +0 -1
  42. package/dist-server/engine/structure-diff.js.map +0 -1
  43. package/dist-server/engine/travel-estimator.js.map +0 -1
  44. package/dist-server/engine/twin-engine.js.map +0 -1
  45. package/dist-server/engine/twin-state-channel.js.map +0 -1
  46. package/dist-server/engine/warm-start.js.map +0 -1
  47. package/dist-server/index.js.map +0 -1
  48. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js.map +0 -1
  49. package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js.map +0 -1
  50. package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js.map +0 -1
  51. package/dist-server/migrations/1786300000000-IndexEventTypeByTime.js.map +0 -1
  52. package/dist-server/migrations/1786400000000-IndexEventCreatedAt.js.map +0 -1
  53. package/dist-server/migrations/1786500000000-CreateTwinSubjectEvents.js.map +0 -1
  54. package/dist-server/migrations/1786600000000-RenameOperatoMesAdapterType.js.map +0 -1
  55. package/dist-server/migrations/1786700000000-AddDispatchRetryColumns.js.map +0 -1
  56. package/dist-server/migrations/1786800000000-CreateTwinReferenceReconciliations.js.map +0 -1
  57. package/dist-server/migrations/index.js.map +0 -1
  58. package/dist-server/routes.js.map +0 -1
  59. package/dist-server/service/actuation/actuation-advisor.js.map +0 -1
  60. package/dist-server/service/actuation/actuation-outcome.js.map +0 -1
  61. package/dist-server/service/actuation/actuation-rule-resolver.js.map +0 -1
  62. package/dist-server/service/actuation/actuation-rule.js.map +0 -1
  63. package/dist-server/service/actuation/approval-gateway.js.map +0 -1
  64. package/dist-server/service/actuation/catch-up-effects.js.map +0 -1
  65. package/dist-server/service/actuation/command-dispatcher.js.map +0 -1
  66. package/dist-server/service/actuation/command-store.js.map +0 -1
  67. package/dist-server/service/actuation/dispatch-after-approval.js.map +0 -1
  68. package/dist-server/service/actuation/effect-match.js.map +0 -1
  69. package/dist-server/service/actuation/index.js.map +0 -1
  70. package/dist-server/service/actuation/retry-plan.js.map +0 -1
  71. package/dist-server/service/actuation/rule-evaluate.js.map +0 -1
  72. package/dist-server/service/actuation/rule-loop.js.map +0 -1
  73. package/dist-server/service/actuation/rule-runner.js.map +0 -1
  74. package/dist-server/service/actuation/rule-wiring.js.map +0 -1
  75. package/dist-server/service/actuation/settle-effects.js.map +0 -1
  76. package/dist-server/service/actuation/sweep-dispatch.js.map +0 -1
  77. package/dist-server/service/actuation/twin-command-resolver.js.map +0 -1
  78. package/dist-server/service/actuation/twin-command.js.map +0 -1
  79. package/dist-server/service/actuation/twin-now.js.map +0 -1
  80. package/dist-server/service/index.js.map +0 -1
  81. package/dist-server/service/reference/actuation-routing.js.map +0 -1
  82. package/dist-server/service/reference/actuation-target.js.map +0 -1
  83. package/dist-server/service/reference/actuation-verification.js.map +0 -1
  84. package/dist-server/service/reference/attention-lane.js.map +0 -1
  85. package/dist-server/service/reference/connection-portability-resolver.js.map +0 -1
  86. package/dist-server/service/reference/connection-portability.js.map +0 -1
  87. package/dist-server/service/reference/control-routing.js.map +0 -1
  88. package/dist-server/service/reference/discovery-result.js.map +0 -1
  89. package/dist-server/service/reference/fill-cadence.js.map +0 -1
  90. package/dist-server/service/reference/fill-dedupe.js.map +0 -1
  91. package/dist-server/service/reference/fill-loop.js.map +0 -1
  92. package/dist-server/service/reference/fill-span.js.map +0 -1
  93. package/dist-server/service/reference/hook-contract.js.map +0 -1
  94. package/dist-server/service/reference/hook-rejected.js.map +0 -1
  95. package/dist-server/service/reference/hook-store.js.map +0 -1
  96. package/dist-server/service/reference/index.js.map +0 -1
  97. package/dist-server/service/reference/ingest-space.js.map +0 -1
  98. package/dist-server/service/reference/knob-defaults.js.map +0 -1
  99. package/dist-server/service/reference/live-cadence.js.map +0 -1
  100. package/dist-server/service/reference/live-feed-lease.js.map +0 -1
  101. package/dist-server/service/reference/live-ingest.js.map +0 -1
  102. package/dist-server/service/reference/reference-adapter.js.map +0 -1
  103. package/dist-server/service/reference/reference-assessment.js.map +0 -1
  104. package/dist-server/service/reference/reference-fill-run.js.map +0 -1
  105. package/dist-server/service/reference/reference-fill.js.map +0 -1
  106. package/dist-server/service/reference/reference-hook.js.map +0 -1
  107. package/dist-server/service/reference/reference-link-groups.js.map +0 -1
  108. package/dist-server/service/reference/reference-links.js.map +0 -1
  109. package/dist-server/service/reference/reference-live.js.map +0 -1
  110. package/dist-server/service/reference/reference-master.js.map +0 -1
  111. package/dist-server/service/reference/reference-probe.js.map +0 -1
  112. package/dist-server/service/reference/reference-progress-channel.js.map +0 -1
  113. package/dist-server/service/reference/reference-progress-subscription.js.map +0 -1
  114. package/dist-server/service/reference/reference-progress.js.map +0 -1
  115. package/dist-server/service/reference/reference-reconciliation-query.js.map +0 -1
  116. package/dist-server/service/reference/reference-reconciliation-writer.js.map +0 -1
  117. package/dist-server/service/reference/reference-reconciliation.js.map +0 -1
  118. package/dist-server/service/reference/reference-registry.js.map +0 -1
  119. package/dist-server/service/reference/reference-resolver.js.map +0 -1
  120. package/dist-server/service/reference/template-registry.js.map +0 -1
  121. package/dist-server/service/reference/twin-reference-reconciliation.js.map +0 -1
  122. package/dist-server/service/reference/twin-reference.js.map +0 -1
  123. package/dist-server/service/twin-attention/index.js.map +0 -1
  124. package/dist-server/service/twin-attention/twin-attention-query.js.map +0 -1
  125. package/dist-server/service/twin-audit/command-audit.js.map +0 -1
  126. package/dist-server/service/twin-audit/index.js.map +0 -1
  127. package/dist-server/service/twin-audit/twin-audit-event.js.map +0 -1
  128. package/dist-server/service/twin-audit/twin-audit-query.js.map +0 -1
  129. package/dist-server/service/twin-backfill/backfill-period-facts.js.map +0 -1
  130. package/dist-server/service/twin-backfill/backfill-shape.js.map +0 -1
  131. package/dist-server/service/twin-backfill/index.js.map +0 -1
  132. package/dist-server/service/twin-backfill/twin-backfill-resolver.js.map +0 -1
  133. package/dist-server/service/twin-control/index.js.map +0 -1
  134. package/dist-server/service/twin-control/twin-control-mutation.js.map +0 -1
  135. package/dist-server/service/twin-event/index.js.map +0 -1
  136. package/dist-server/service/twin-event/journal-count.js.map +0 -1
  137. package/dist-server/service/twin-event/twin-event-keys.js.map +0 -1
  138. package/dist-server/service/twin-event/twin-event-type.js.map +0 -1
  139. package/dist-server/service/twin-event/twin-event.js.map +0 -1
  140. package/dist-server/service/twin-forecast/forecast-metrics.js.map +0 -1
  141. package/dist-server/service/twin-forecast/forecast-tuning.js.map +0 -1
  142. package/dist-server/service/twin-forecast/gap-analytics.js.map +0 -1
  143. package/dist-server/service/twin-forecast/index.js.map +0 -1
  144. package/dist-server/service/twin-forecast/twin-forecast-query.js.map +0 -1
  145. package/dist-server/service/twin-ingest-window/index.js.map +0 -1
  146. package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js.map +0 -1
  147. package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js.map +0 -1
  148. package/dist-server/service/twin-ingest-window/twin-ingest-window.js.map +0 -1
  149. package/dist-server/service/twin-instance/index.js.map +0 -1
  150. package/dist-server/service/twin-instance/twin-instance.js.map +0 -1
  151. package/dist-server/service/twin-journal/event-type-split-shape.js.map +0 -1
  152. package/dist-server/service/twin-journal/event-type-split.js.map +0 -1
  153. package/dist-server/service/twin-journal/index.js.map +0 -1
  154. package/dist-server/service/twin-journal/journal-order.js.map +0 -1
  155. package/dist-server/service/twin-journal/twin-journal-query.js.map +0 -1
  156. package/dist-server/service/twin-lifecycle/domain-catalog.js.map +0 -1
  157. package/dist-server/service/twin-lifecycle/index.js.map +0 -1
  158. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +0 -1
  159. package/dist-server/service/twin-metrics/index.js.map +0 -1
  160. package/dist-server/service/twin-metrics/twin-metrics-query.js.map +0 -1
  161. package/dist-server/service/twin-model/axis-journal-evidence.js.map +0 -1
  162. package/dist-server/service/twin-model/choose-recipe.js.map +0 -1
  163. package/dist-server/service/twin-model/epcis-coverage.js.map +0 -1
  164. package/dist-server/service/twin-model/external-resolver.js.map +0 -1
  165. package/dist-server/service/twin-model/iec61850-coverage.js.map +0 -1
  166. package/dist-server/service/twin-model/index.js.map +0 -1
  167. package/dist-server/service/twin-model/isa95-coverage.js.map +0 -1
  168. package/dist-server/service/twin-model/item-ref.js.map +0 -1
  169. package/dist-server/service/twin-model/name-index.js.map +0 -1
  170. package/dist-server/service/twin-model/project-structure.js.map +0 -1
  171. package/dist-server/service/twin-model/standard-coverage.js.map +0 -1
  172. package/dist-server/service/twin-model/status-tally.js.map +0 -1
  173. package/dist-server/service/twin-model/twin-equipment.js.map +0 -1
  174. package/dist-server/service/twin-model/twin-lineage-query.js.map +0 -1
  175. package/dist-server/service/twin-model/twin-location.js.map +0 -1
  176. package/dist-server/service/twin-model/twin-model-item-query.js.map +0 -1
  177. package/dist-server/service/twin-model/twin-model-mutation.js.map +0 -1
  178. package/dist-server/service/twin-model/twin-model-query.js.map +0 -1
  179. package/dist-server/service/twin-model/twin-model-tree-query.js.map +0 -1
  180. package/dist-server/service/twin-model/twin-operation.js.map +0 -1
  181. package/dist-server/service/twin-readiness/index.js.map +0 -1
  182. package/dist-server/service/twin-readiness/twin-readiness-query.js.map +0 -1
  183. package/dist-server/service/twin-space/area-resolver.js.map +0 -1
  184. package/dist-server/service/twin-space/index.js.map +0 -1
  185. package/dist-server/service/twin-space/move-space.js.map +0 -1
  186. package/dist-server/service/twin-space/representation-role.js.map +0 -1
  187. package/dist-server/service/twin-space/space-integrity.js.map +0 -1
  188. package/dist-server/service/twin-space/twin-area.js.map +0 -1
  189. package/dist-server/service/twin-space/twin-space-area.js.map +0 -1
  190. package/dist-server/service/twin-space/twin-space-representation.js.map +0 -1
  191. package/dist-server/service/twin-space/twin-space-resolver.js.map +0 -1
  192. package/dist-server/service/twin-space/twin-space.js.map +0 -1
  193. package/dist-server/service/twin-state/index.js.map +0 -1
  194. package/dist-server/service/twin-state/twin-state-subscription.js.map +0 -1
  195. package/dist-server/service/twin-structure/index.js.map +0 -1
  196. package/dist-server/service/twin-structure/twin-structure.js.map +0 -1
  197. package/dist-server/service/twin-subject/event-subjects.js.map +0 -1
  198. package/dist-server/service/twin-subject/index.js.map +0 -1
  199. package/dist-server/service/twin-subject/item-resolver.js.map +0 -1
  200. package/dist-server/service/twin-subject/subject-query-shape.js.map +0 -1
  201. package/dist-server/service/twin-subject/twin-subject-backfill.js.map +0 -1
  202. package/dist-server/service/twin-subject/twin-subject-event.js.map +0 -1
  203. package/dist-server/service/twin-subject/twin-subject-fast-path.js.map +0 -1
  204. package/dist-server/service/twin-subject/twin-subject-query.js.map +0 -1
  205. package/dist-server/service/twin-subject/twin-subject-writer.js.map +0 -1
  206. package/dist-server/service/twin-target/index.js.map +0 -1
  207. package/dist-server/service/twin-target/twin-target-resolver.js.map +0 -1
  208. package/dist-server/service/twin-target/twin-target.js.map +0 -1
  209. package/dist-shared/axis-read.js.map +0 -1
  210. package/dist-shared/entity-delta.js.map +0 -1
  211. package/dist-shared/kpi-broadcast.js.map +0 -1
  212. package/dist-shared/touched-items.js.map +0 -1
  213. package/dist-shared/twin-level.js.map +0 -1
  214. package/server/engine/attention-digest.ts +0 -102
  215. package/server/engine/canonical-ingest.ts +0 -511
  216. package/server/engine/checkpoint-fold.ts +0 -12
  217. package/server/engine/command-routing.ts +0 -67
  218. package/server/engine/declared-stimulus.ts +0 -66
  219. package/server/engine/energy-topology.ts +0 -189
  220. package/server/engine/event-time.ts +0 -96
  221. package/server/engine/index.ts +0 -51
  222. package/server/engine/ingest-dedupe.ts +0 -24
  223. package/server/engine/ingest-health.ts +0 -24
  224. package/server/engine/integration-coverage.ts +0 -147
  225. package/server/engine/integration-probes.ts +0 -144
  226. package/server/engine/integration-runner.ts +0 -95
  227. package/server/engine/integration-target-profile.ts +0 -103
  228. package/server/engine/kpi-baseline.ts +0 -202
  229. package/server/engine/kpi-fold.ts +0 -1516
  230. package/server/engine/kpi-query.ts +0 -1210
  231. package/server/engine/kpi-target.ts +0 -248
  232. package/server/engine/live-attentions.ts +0 -30
  233. package/server/engine/live-feed-registry.ts +0 -59
  234. package/server/engine/load-meter.ts +0 -393
  235. package/server/engine/local-declarations.ts +0 -779
  236. package/server/engine/log.ts +0 -72
  237. package/server/engine/loop-lag.ts +0 -120
  238. package/server/engine/measured-estimator.ts +0 -91
  239. package/server/engine/measured-yield.ts +0 -89
  240. package/server/engine/model-basis.ts +0 -162
  241. package/server/engine/model-gap.ts +0 -168
  242. package/server/engine/model-refusal.ts +0 -31
  243. package/server/engine/model-vocabulary.ts +0 -82
  244. package/server/engine/oee-accumulator.ts +0 -195
  245. package/server/engine/operation-basis.ts +0 -131
  246. package/server/engine/producer-guard.ts +0 -64
  247. package/server/engine/property-effects.ts +0 -216
  248. package/server/engine/read-time.ts +0 -77
  249. package/server/engine/restart-policy.ts +0 -55
  250. package/server/engine/runtime-key.ts +0 -58
  251. package/server/engine/spec-coverage.ts +0 -105
  252. package/server/engine/stage-path.ts +0 -172
  253. package/server/engine/state-axes.ts +0 -60
  254. package/server/engine/structure-diff.ts +0 -88
  255. package/server/engine/travel-estimator.ts +0 -138
  256. package/server/engine/twin-engine.ts +0 -4979
  257. package/server/engine/twin-state-channel.ts +0 -39
  258. package/server/engine/warm-start.ts +0 -265
  259. package/server/index.ts +0 -90
  260. package/server/migrations/1786000000000-RenameTwinInstanceBoardToModel.ts +0 -43
  261. package/server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.ts +0 -54
  262. package/server/migrations/1786200000000-CarryLiveFeedCursor.ts +0 -53
  263. package/server/migrations/1786300000000-IndexEventTypeByTime.ts +0 -48
  264. package/server/migrations/1786400000000-IndexEventCreatedAt.ts +0 -38
  265. package/server/migrations/1786500000000-CreateTwinSubjectEvents.ts +0 -93
  266. package/server/migrations/1786600000000-RenameOperatoMesAdapterType.ts +0 -66
  267. package/server/migrations/1786700000000-AddDispatchRetryColumns.ts +0 -82
  268. package/server/migrations/1786800000000-CreateTwinReferenceReconciliations.ts +0 -39
  269. package/server/migrations/index.ts +0 -25
  270. package/server/routes.ts +0 -75
  271. package/server/service/actuation/actuation-advisor.ts +0 -131
  272. package/server/service/actuation/actuation-outcome.ts +0 -97
  273. package/server/service/actuation/actuation-rule-resolver.ts +0 -147
  274. package/server/service/actuation/actuation-rule.ts +0 -139
  275. package/server/service/actuation/approval-gateway.ts +0 -44
  276. package/server/service/actuation/catch-up-effects.ts +0 -152
  277. package/server/service/actuation/command-dispatcher.ts +0 -474
  278. package/server/service/actuation/command-store.ts +0 -236
  279. package/server/service/actuation/dispatch-after-approval.ts +0 -71
  280. package/server/service/actuation/effect-match.ts +0 -124
  281. package/server/service/actuation/index.ts +0 -27
  282. package/server/service/actuation/retry-plan.ts +0 -145
  283. package/server/service/actuation/rule-evaluate.ts +0 -352
  284. package/server/service/actuation/rule-loop.ts +0 -160
  285. package/server/service/actuation/rule-runner.ts +0 -216
  286. package/server/service/actuation/rule-wiring.ts +0 -84
  287. package/server/service/actuation/settle-effects.ts +0 -115
  288. package/server/service/actuation/sweep-dispatch.ts +0 -179
  289. package/server/service/actuation/twin-command-resolver.ts +0 -387
  290. package/server/service/actuation/twin-command.ts +0 -232
  291. package/server/service/actuation/twin-now.ts +0 -97
  292. package/server/service/index.ts +0 -100
  293. package/server/service/reference/actuation-routing.ts +0 -192
  294. package/server/service/reference/actuation-target.ts +0 -163
  295. package/server/service/reference/actuation-verification.ts +0 -85
  296. package/server/service/reference/attention-lane.ts +0 -21
  297. package/server/service/reference/connection-portability-resolver.ts +0 -171
  298. package/server/service/reference/connection-portability.ts +0 -329
  299. package/server/service/reference/control-routing.ts +0 -62
  300. package/server/service/reference/discovery-result.ts +0 -95
  301. package/server/service/reference/fill-cadence.ts +0 -29
  302. package/server/service/reference/fill-dedupe.ts +0 -66
  303. package/server/service/reference/fill-loop.ts +0 -153
  304. package/server/service/reference/fill-span.ts +0 -31
  305. package/server/service/reference/hook-contract.ts +0 -364
  306. package/server/service/reference/hook-rejected.ts +0 -53
  307. package/server/service/reference/hook-store.ts +0 -28
  308. package/server/service/reference/index.ts +0 -18
  309. package/server/service/reference/ingest-space.ts +0 -104
  310. package/server/service/reference/knob-defaults.ts +0 -59
  311. package/server/service/reference/live-cadence.ts +0 -129
  312. package/server/service/reference/live-feed-lease.ts +0 -56
  313. package/server/service/reference/live-ingest.ts +0 -94
  314. package/server/service/reference/reference-adapter.ts +0 -985
  315. package/server/service/reference/reference-assessment.ts +0 -250
  316. package/server/service/reference/reference-fill-run.ts +0 -179
  317. package/server/service/reference/reference-fill.ts +0 -223
  318. package/server/service/reference/reference-hook.ts +0 -479
  319. package/server/service/reference/reference-link-groups.ts +0 -21
  320. package/server/service/reference/reference-links.ts +0 -77
  321. package/server/service/reference/reference-live.ts +0 -420
  322. package/server/service/reference/reference-master.ts +0 -999
  323. package/server/service/reference/reference-probe.ts +0 -264
  324. package/server/service/reference/reference-progress-channel.ts +0 -26
  325. package/server/service/reference/reference-progress-subscription.ts +0 -78
  326. package/server/service/reference/reference-progress.ts +0 -95
  327. package/server/service/reference/reference-reconciliation-query.ts +0 -28
  328. package/server/service/reference/reference-reconciliation-writer.ts +0 -38
  329. package/server/service/reference/reference-reconciliation.ts +0 -55
  330. package/server/service/reference/reference-registry.ts +0 -17
  331. package/server/service/reference/reference-resolver.ts +0 -969
  332. package/server/service/reference/template-registry.ts +0 -85
  333. package/server/service/reference/twin-reference-reconciliation.ts +0 -27
  334. package/server/service/reference/twin-reference.ts +0 -190
  335. package/server/service/twin-attention/index.ts +0 -3
  336. package/server/service/twin-attention/twin-attention-query.ts +0 -70
  337. package/server/service/twin-audit/command-audit.ts +0 -114
  338. package/server/service/twin-audit/index.ts +0 -5
  339. package/server/service/twin-audit/twin-audit-event.ts +0 -158
  340. package/server/service/twin-audit/twin-audit-query.ts +0 -72
  341. package/server/service/twin-backfill/backfill-period-facts.ts +0 -168
  342. package/server/service/twin-backfill/backfill-shape.ts +0 -86
  343. package/server/service/twin-backfill/index.ts +0 -3
  344. package/server/service/twin-backfill/twin-backfill-resolver.ts +0 -35
  345. package/server/service/twin-control/index.ts +0 -3
  346. package/server/service/twin-control/twin-control-mutation.ts +0 -150
  347. package/server/service/twin-event/index.ts +0 -3
  348. package/server/service/twin-event/journal-count.ts +0 -53
  349. package/server/service/twin-event/twin-event-keys.ts +0 -215
  350. package/server/service/twin-event/twin-event-type.ts +0 -68
  351. package/server/service/twin-event/twin-event.ts +0 -250
  352. package/server/service/twin-forecast/forecast-metrics.ts +0 -106
  353. package/server/service/twin-forecast/forecast-tuning.ts +0 -40
  354. package/server/service/twin-forecast/gap-analytics.ts +0 -139
  355. package/server/service/twin-forecast/index.ts +0 -3
  356. package/server/service/twin-forecast/twin-forecast-query.ts +0 -486
  357. package/server/service/twin-ingest-window/index.ts +0 -7
  358. package/server/service/twin-ingest-window/twin-ingest-window-query.ts +0 -125
  359. package/server/service/twin-ingest-window/twin-ingest-window-writer.ts +0 -57
  360. package/server/service/twin-ingest-window/twin-ingest-window.ts +0 -113
  361. package/server/service/twin-instance/index.ts +0 -3
  362. package/server/service/twin-instance/twin-instance.ts +0 -199
  363. package/server/service/twin-journal/event-type-split-shape.ts +0 -112
  364. package/server/service/twin-journal/event-type-split.ts +0 -144
  365. package/server/service/twin-journal/index.ts +0 -3
  366. package/server/service/twin-journal/journal-order.ts +0 -20
  367. package/server/service/twin-journal/twin-journal-query.ts +0 -615
  368. package/server/service/twin-lifecycle/domain-catalog.ts +0 -51
  369. package/server/service/twin-lifecycle/index.ts +0 -3
  370. package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +0 -285
  371. package/server/service/twin-metrics/index.ts +0 -3
  372. package/server/service/twin-metrics/twin-metrics-query.ts +0 -172
  373. package/server/service/twin-model/axis-journal-evidence.ts +0 -57
  374. package/server/service/twin-model/choose-recipe.ts +0 -31
  375. package/server/service/twin-model/epcis-coverage.ts +0 -251
  376. package/server/service/twin-model/external-resolver.ts +0 -173
  377. package/server/service/twin-model/iec61850-coverage.ts +0 -111
  378. package/server/service/twin-model/index.ts +0 -25
  379. package/server/service/twin-model/isa95-coverage.ts +0 -320
  380. package/server/service/twin-model/item-ref.ts +0 -80
  381. package/server/service/twin-model/name-index.ts +0 -94
  382. package/server/service/twin-model/project-structure.ts +0 -213
  383. package/server/service/twin-model/standard-coverage.ts +0 -35
  384. package/server/service/twin-model/status-tally.ts +0 -37
  385. package/server/service/twin-model/twin-equipment.ts +0 -191
  386. package/server/service/twin-model/twin-lineage-query.ts +0 -327
  387. package/server/service/twin-model/twin-location.ts +0 -147
  388. package/server/service/twin-model/twin-model-item-query.ts +0 -1029
  389. package/server/service/twin-model/twin-model-mutation.ts +0 -503
  390. package/server/service/twin-model/twin-model-query.ts +0 -792
  391. package/server/service/twin-model/twin-model-tree-query.ts +0 -211
  392. package/server/service/twin-model/twin-operation.ts +0 -157
  393. package/server/service/twin-readiness/index.ts +0 -3
  394. package/server/service/twin-readiness/twin-readiness-query.ts +0 -96
  395. package/server/service/twin-space/area-resolver.ts +0 -75
  396. package/server/service/twin-space/index.ts +0 -8
  397. package/server/service/twin-space/move-space.ts +0 -262
  398. package/server/service/twin-space/representation-role.ts +0 -15
  399. package/server/service/twin-space/space-integrity.ts +0 -293
  400. package/server/service/twin-space/twin-area.ts +0 -63
  401. package/server/service/twin-space/twin-space-area.ts +0 -66
  402. package/server/service/twin-space/twin-space-representation.ts +0 -99
  403. package/server/service/twin-space/twin-space-resolver.ts +0 -582
  404. package/server/service/twin-space/twin-space.ts +0 -148
  405. package/server/service/twin-state/index.ts +0 -3
  406. package/server/service/twin-state/twin-state-subscription.ts +0 -62
  407. package/server/service/twin-structure/index.ts +0 -3
  408. package/server/service/twin-structure/twin-structure.ts +0 -96
  409. package/server/service/twin-subject/event-subjects.ts +0 -162
  410. package/server/service/twin-subject/index.ts +0 -10
  411. package/server/service/twin-subject/item-resolver.ts +0 -92
  412. package/server/service/twin-subject/subject-query-shape.ts +0 -84
  413. package/server/service/twin-subject/twin-subject-backfill.ts +0 -196
  414. package/server/service/twin-subject/twin-subject-event.ts +0 -101
  415. package/server/service/twin-subject/twin-subject-fast-path.ts +0 -346
  416. package/server/service/twin-subject/twin-subject-query.ts +0 -210
  417. package/server/service/twin-subject/twin-subject-writer.ts +0 -189
  418. package/server/service/twin-target/index.ts +0 -5
  419. package/server/service/twin-target/twin-target-resolver.ts +0 -142
  420. package/server/service/twin-target/twin-target.ts +0 -97
  421. package/server/types/global.d.ts +0 -22
  422. package/shared/axis-read.ts +0 -28
  423. package/shared/entity-delta.ts +0 -335
  424. package/shared/kpi-broadcast.ts +0 -13
  425. package/shared/touched-items.ts +0 -73
  426. package/shared/twin-level.ts +0 -48
  427. package/test/ack-shape-alignment.test.ts +0 -97
  428. package/test/actuation-advisor.test.ts +0 -55
  429. package/test/actuation-approval-door.test.ts +0 -411
  430. package/test/actuation-dispatch.test.ts +0 -209
  431. package/test/actuation-effect.test.ts +0 -162
  432. package/test/actuation-outcome.test.ts +0 -152
  433. package/test/actuation-rule-runner.test.ts +0 -281
  434. package/test/actuation-rule.test.ts +0 -266
  435. package/test/actuation-seam.test.ts +0 -255
  436. package/test/actuation-settle.test.ts +0 -164
  437. package/test/actuation-target.test.ts +0 -145
  438. package/test/actuation-verification-state.test.ts +0 -139
  439. package/test/adopt-structure-live.test.ts +0 -133
  440. package/test/aggregate-not-findone.test.ts +0 -112
  441. package/test/area-resolver-db.test.ts +0 -110
  442. package/test/attention-digest.test.ts +0 -161
  443. package/test/axis-declaration-passthrough-db.test.ts +0 -152
  444. package/test/axis-journal-evidence.test.ts +0 -71
  445. package/test/axis-read.test.ts +0 -188
  446. package/test/backfill-shape.test.ts +0 -89
  447. package/test/boot-resume.test.ts +0 -287
  448. package/test/broadcast-cost-baseline.test.ts +0 -201
  449. package/test/broadcast-period.test.ts +0 -58
  450. package/test/broadcast-queue-overflow.test.ts +0 -244
  451. package/test/canonical-ingest-vocabularies.test.ts +0 -451
  452. package/test/canonical-quantity-door.test.ts +0 -61
  453. package/test/capability-mapping.test.ts +0 -89
  454. package/test/checkpoint-refuses-empty.test.ts +0 -103
  455. package/test/choose-recipe.test.ts +0 -117
  456. package/test/column-type-portability.test.ts +0 -122
  457. package/test/command-routing.test.ts +0 -61
  458. package/test/command-store-writes-columns.test.ts +0 -126
  459. package/test/connection-portability-doors.test.ts +0 -87
  460. package/test/connector-capability-declaration.test.ts +0 -195
  461. package/test/contract-layer-guard.test.ts +0 -48
  462. package/test/control-capability.test.ts +0 -98
  463. package/test/cursor-stall-not-read-failure.test.ts +0 -126
  464. package/test/declaration-reaches-model.test.ts +0 -226
  465. package/test/declared-location-types.test.ts +0 -89
  466. package/test/declared-stimulus.test.ts +0 -88
  467. package/test/dedupe-transformation.test.ts +0 -112
  468. package/test/discovery-result.test.ts +0 -75
  469. package/test/dispatch-after-approval-source.test.ts +0 -81
  470. package/test/duration-estimators.test.ts +0 -144
  471. package/test/energy-topology.test.ts +0 -113
  472. package/test/entity-delta.test.ts +0 -352
  473. package/test/equipment-identity-reaches.test.ts +0 -57
  474. package/test/event-subjects.test.ts +0 -148
  475. package/test/event-time-column.test.ts +0 -67
  476. package/test/event-type-split.test.ts +0 -178
  477. package/test/external-resolver.test.ts +0 -177
  478. package/test/fact-scope-wiring.test.ts +0 -96
  479. package/test/fill-dedupe.test.ts +0 -59
  480. package/test/fill-loop.test.ts +0 -35
  481. package/test/first-envelope.test.ts +0 -153
  482. package/test/fold-gap-speaks.test.ts +0 -53
  483. package/test/fold-shift-dst.test.ts +0 -110
  484. package/test/forecast-metrics.test.ts +0 -157
  485. package/test/forecast-tuning.test.ts +0 -42
  486. package/test/gap-analytics.test.ts +0 -113
  487. package/test/generated-not-counted.test.ts +0 -99
  488. package/test/guard-roots.ts +0 -76
  489. package/test/home-in-area.test.ts +0 -90
  490. package/test/hook-address.test.ts +0 -28
  491. package/test/hook-rejected-shape.test.ts +0 -86
  492. package/test/hook-response-sum.test.ts +0 -193
  493. package/test/hook-sequence.test.ts +0 -333
  494. package/test/ingest-bench.test.ts +0 -70
  495. package/test/ingest-dedupe.test.ts +0 -56
  496. package/test/ingest-expected-quiet.test.ts +0 -111
  497. package/test/ingest-health-engine.test.ts +0 -248
  498. package/test/ingest-health-wiring.test.ts +0 -120
  499. package/test/ingest-health.test.ts +0 -306
  500. package/test/ingest-history.test.ts +0 -247
  501. package/test/ingest-idempotent.test.ts +0 -211
  502. package/test/ingest-reconcile-four-ways.test.ts +0 -97
  503. package/test/ingest-rules-header.test.ts +0 -100
  504. package/test/ingest-running-guard.test.ts +0 -136
  505. package/test/ingest-space.test.ts +0 -78
  506. package/test/ingest-window-rolls-unobserved.test.ts +0 -72
  507. package/test/ingest-wiring-guard.test.ts +0 -197
  508. package/test/instance-cache-lifecycle.test.ts +0 -110
  509. package/test/intake-mapping-parity.test.ts +0 -175
  510. package/test/integration-probes.test.ts +0 -103
  511. package/test/integration-runner.test.ts +0 -95
  512. package/test/item-ref.test.ts +0 -78
  513. package/test/journal-order-axis.test.ts +0 -80
  514. package/test/journal-read-discipline.test.ts +0 -186
  515. package/test/journal-retention.test.ts +0 -275
  516. package/test/journal-sort-axis.test.ts +0 -142
  517. package/test/journal-write-door.test.ts +0 -110
  518. package/test/journal-write-trend.test.ts +0 -115
  519. package/test/kernel-kind-guard.test.ts +0 -98
  520. package/test/knob-defaults.test.ts +0 -72
  521. package/test/kpi-baseline-db.test.ts +0 -216
  522. package/test/kpi-baseline.test.ts +0 -196
  523. package/test/kpi-fold.test.ts +0 -1456
  524. package/test/kpi-query-bench.test.ts +0 -130
  525. package/test/lens-own-places.test.ts +0 -50
  526. package/test/lineage-survives-restart.test.ts +0 -234
  527. package/test/live-cadence.test.ts +0 -170
  528. package/test/live-cursor-wiring.test.ts +0 -87
  529. package/test/live-feed-lease.test.ts +0 -63
  530. package/test/live-feed-registry.test.ts +0 -75
  531. package/test/live-kernel-facts.test.ts +0 -161
  532. package/test/live-mirror-parity.test.ts +0 -286
  533. package/test/load-meter.test.ts +0 -328
  534. package/test/local-declarations.test.ts +0 -662
  535. package/test/log-stamp.test.ts +0 -59
  536. package/test/loop-lag.test.ts +0 -82
  537. package/test/master-to-twin.test.ts +0 -279
  538. package/test/measured-yield.test.ts +0 -90
  539. package/test/merge-streams.test.ts +0 -70
  540. package/test/mirror-resumes-from-checkpoint.test.ts +0 -192
  541. package/test/model-basis.test.ts +0 -141
  542. package/test/model-gap.test.ts +0 -153
  543. package/test/model-refusal.test.ts +0 -75
  544. package/test/model-vocabulary.test.ts +0 -114
  545. package/test/move-space.test.ts +0 -149
  546. package/test/mutation-gate.test.ts +0 -122
  547. package/test/oee-accumulator.test.ts +0 -204
  548. package/test/oee-site-calendar.test.ts +0 -146
  549. package/test/open-doors.test.ts +0 -197
  550. package/test/operation-basis.test.ts +0 -127
  551. package/test/operational-vocabulary.test.ts +0 -108
  552. package/test/operations-capability-db.test.ts +0 -165
  553. package/test/order-and-transaction-split.test.ts +0 -107
  554. package/test/order-fold-host.test.ts +0 -112
  555. package/test/producer-guard.test.ts +0 -66
  556. package/test/project-structure-db.test.ts +0 -226
  557. package/test/projection-reaches-screen.test.ts +0 -277
  558. package/test/projection-reads-declared.test.ts +0 -109
  559. package/test/property-effects.test.ts +0 -128
  560. package/test/provenance-promotion.test.ts +0 -99
  561. package/test/read-failure-ledger.test.ts +0 -106
  562. package/test/read-failure-visible.test.ts +0 -145
  563. package/test/read-time.test.ts +0 -118
  564. package/test/reference-fill.test.ts +0 -235
  565. package/test/reference-grounding.test.ts +0 -70
  566. package/test/reference-hook.test.ts +0 -177
  567. package/test/reference-links.test.ts +0 -56
  568. package/test/reference-reconciliation.test.ts +0 -39
  569. package/test/registry-key-guard.test.ts +0 -80
  570. package/test/rejection-carries-event-id.test.ts +0 -101
  571. package/test/rename-twin.test.ts +0 -89
  572. package/test/resolve-ts-siblings.mjs +0 -52
  573. package/test/restart-policy.test.ts +0 -111
  574. package/test/resync-origin-site.test.ts +0 -83
  575. package/test/retry-plan.test.ts +0 -139
  576. package/test/revision-axis.test.ts +0 -110
  577. package/test/runtime-key.test.ts +0 -66
  578. package/test/save-intake-collision.test.ts +0 -91
  579. package/test/scale-twin-bench.test.ts +0 -103
  580. package/test/secrets-at-rest.test.ts +0 -135
  581. package/test/snapshot-freshness.test.ts +0 -60
  582. package/test/source-outcome-audit.test.ts +0 -104
  583. package/test/space-integrity.test.ts +0 -223
  584. package/test/space-representation.test.ts +0 -66
  585. package/test/space-scope-includes-stopped.test.ts +0 -55
  586. package/test/spec-coverage.test.ts +0 -113
  587. package/test/stage-path.test.ts +0 -95
  588. package/test/standard-coverage.test.ts +0 -148
  589. package/test/state-axes.test.ts +0 -74
  590. package/test/status-tally.test.ts +0 -55
  591. package/test/streamline-e2e.test.ts +0 -76
  592. package/test/structure-revision-db.test.ts +0 -315
  593. package/test/subject-fast-path.test.ts +0 -148
  594. package/test/subject-read-model.test.ts +0 -175
  595. package/test/sweep-dispatch.test.ts +0 -191
  596. package/test/tenant-registry-db.test.ts +0 -149
  597. package/test/time-range.test.ts +0 -152
  598. package/test/touched-items.test.ts +0 -61
  599. package/test/twin-audit.test.ts +0 -83
  600. package/test/twin-event-keys.test.ts +0 -193
  601. package/test/twin-model-item-db.test.ts +0 -319
  602. package/test/twin-model-parent-relation-db.test.ts +0 -125
  603. package/test/twin-model-tree-db.test.ts +0 -209
  604. package/test/twin-origin-resync.test.ts +0 -133
  605. package/test/twin-state-channel.test.ts +0 -111
  606. package/test/vocabulary-guard.test.ts +0 -43
  607. package/test/warm-start-seam.test.ts +0 -162
  608. package/test/warm-start.test.ts +0 -297
  609. package/test/withheld-door.test.ts +0 -95
  610. package/test/yield-loop.test.ts +0 -199
  611. package/tsconfig.json +0 -15
  612. package/tsconfig.shared.json +0 -23
  613. package/tsconfig.shared.tsbuildinfo +0 -1
  614. package/tsconfig.tsbuildinfo +0 -1
@@ -1,136 +0,0 @@
1
- /*
2
- * ★ 가동 중 인제스트 — **거절할 것이면 아무것도 쓰기 전에 거절한다.**
3
- *
4
- * 가동 중 재프로비저닝은 `provision` 이 막는다. 그런데 그 호출은 `ingestMaster` 의 **맨 끝**이었고,
5
- * 그때까지 공간·표현·구역(TwinArea)은 이미 저장된 뒤였다. 사용자 화면에는 "인제스트 실패" 가
6
- * 뜨는데 실제로는 절반이 적용된 상태다 — **실패라고 말하면서 데이터를 바꾸는 것**이 가장 나쁘다.
7
- *
8
- * 이 검사는 그 경계 하나를 지킨다: 거절된 인제스트는 **흔적을 남기지 않는다.**
9
- *
10
- * 순수 함수로는 확인되지 않는다. 부분 쓰기는 정의상 "여러 표에 걸쳐 무엇이 남았나" 이므로 실
11
- * DataSource 가 있어야 한다(멀티DB 규약상 sqlite 가 5개 드라이버 공통의 최소선이다).
12
- *
13
- * 이 제약 자체는 최종형이 아니다 — 커널에는 가동 중 구조 교체(`adoptStructure`)가 이미 있고
14
- * 재생은 리비전 경계마다 그것을 쓴다. 라이브에 배선되면 이 거절은 사라지고 이 검사도 함께 간다.
15
- */
16
- import { test, before, after } from 'node:test'
17
- import assert from 'node:assert/strict'
18
- import { createRequire } from 'node:module'
19
- import type { DataSource } from 'typeorm'
20
-
21
- const req = createRequire(import.meta.url)
22
- const { NamingStrategy, addDataSource, entities: shellEntities, Domain } = req('@things-factory/shell')
23
- const { entities: authEntities } = req('@things-factory/auth-base')
24
- const { entities: twinEntities } = req('../dist-server/service/index.js')
25
- const { TwinEngine } = req('../dist-server/engine/index.js')
26
- const { TwinInstance } = req('../dist-server/service/twin-instance/twin-instance.js')
27
- const { TwinStructure } = req('../dist-server/service/twin-structure/twin-structure.js')
28
- const { TwinArea } = req('../dist-server/service/twin-space/twin-area.js')
29
- const { TwinSpace } = req('../dist-server/service/twin-space/twin-space.js')
30
- const { TwinLocation } = req('../dist-server/service/twin-model/twin-location.js')
31
- const { DataSource: TypeOrmDataSource } = req('typeorm')
32
-
33
- let ds: DataSource
34
- let domainId: string
35
-
36
- const INSTANCE = 'guard-probe'
37
-
38
- /** WMS 마스터 — `bins` 로 규모를, `siteName`·구역 이름으로 "무엇이 바뀌려 했나" 를 다이얼한다. */
39
- const master = (bins: number, siteName: string, areaName: string): any => ({
40
- source: INSTANCE,
41
- system: 'wms',
42
- siteName,
43
- space: { width: 60, depth: 30, unit: 'm' },
44
- locations: [
45
- { id: 'a-dc', type: 'warehouse', role: 'area', name: areaName },
46
- { id: 'dock-recv', type: 'dock', role: 'location', name: '입고 도크', capacity: 100 },
47
- ...Array.from({ length: bins }, (_, i) => ({
48
- id: `bin-${i + 1}`,
49
- type: 'storage',
50
- role: 'location',
51
- name: `빈${i + 1}`,
52
- parentId: 'a-dc',
53
- capacity: 20
54
- }))
55
- ],
56
- equipment: [{ id: 'fk-1', kind: 'forklift', homeLocationId: 'dock-recv' }]
57
- })
58
-
59
- /** 지금 DB 에 남아 있는 모든 흔적 — 인제스트가 건드리는 표를 한 줌으로 뜬다. */
60
- async function trace() {
61
- const inst = await ds.getRepository(TwinInstance).findOne({ where: { instanceId: INSTANCE } })
62
- const space = await ds.getRepository(TwinSpace).findOne({ where: { spaceId: `${INSTANCE}-site` } })
63
- const areas = await ds.getRepository(TwinArea).find({ order: { areaId: 'ASC' } })
64
- const revs = await ds.getRepository(TwinStructure).find({ order: { rev: 'ASC' } })
65
- return {
66
- boardLocations: (inst?.model?.locations ?? []).length,
67
- spaceName: space?.name,
68
- areaNames: areas.map((a: any) => a.name),
69
- revs: revs.map((r: any) => r.rev),
70
- rows: await ds.getRepository(TwinLocation).count()
71
- }
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: 'guard-test', subdomain: 'guard-test' } as any)
87
- domainId = d.id
88
-
89
- await TwinEngine.ingestMaster(domainId, master(3, '서울 창고', '보관 구역'), 'reset')
90
- })
91
-
92
- after(async () => {
93
- await TwinEngine.stop(domainId, INSTANCE).catch(() => {})
94
- await ds?.destroy()
95
- })
96
-
97
- test('멈춰 있으면 재인제스트가 통한다 — 막는 것은 가동 중일 때뿐이다', async () => {
98
- await TwinEngine.ingestMaster(domainId, master(5, '서울 창고', '보관 구역'), 'reset')
99
- const t = await trace()
100
- assert.equal(t.boardLocations, 6, '자리 6개(도크 1 + 빈 5)로 갱신된다')
101
- assert.deepEqual(t.revs, [1, 2], '구조가 달라졌으니 리비전이 하나 늘어난다')
102
- assert.equal(t.rows, 6, '표도 함께 다시 그려진다')
103
- })
104
-
105
- test('가동 중이면 거절하고 — **아무것도 바꾸지 않는다**', async () => {
106
- await TwinEngine.startFromRegistry(domainId, INSTANCE, 'reset')
107
- const before = await trace()
108
-
109
- /*
110
- * 바뀔 것을 **일부러 전부** 흔든다. 구조(빈 5→9)뿐 아니라 공간 이름·구역 이름까지 —
111
- * 부분 쓰기는 앞쪽(공간·구역)에서 일어났으므로, 구조만 확인하면 예전 결함을 못 잡는다.
112
- */
113
- await assert.rejects(
114
- () => TwinEngine.ingestMaster(domainId, master(9, '부산 창고', '다른 구역'), 'reset'),
115
- /is running/,
116
- '가동 중에는 거절해야 한다'
117
- )
118
-
119
- assert.deepEqual(await trace(), before, '거절된 인제스트는 어느 표에도 흔적을 남기지 않는다')
120
- })
121
-
122
- test('멈추면 다시 통한다 — 거절은 잠금이 아니라 순서다', async () => {
123
- await TwinEngine.stop(domainId, INSTANCE)
124
- await TwinEngine.ingestMaster(domainId, master(9, '부산 창고', '다른 구역'), 'reset')
125
-
126
- const t = await trace()
127
- assert.equal(t.boardLocations, 10, '아까 거절당한 그 구조가 이제 들어간다')
128
- assert.deepEqual(t.revs, [1, 2, 3])
129
- assert.equal(t.rows, 10)
130
- /*
131
- * 공간 이름은 **안 바뀐다** — 이미 있는 공간의 이름은 인제스트가 덮지 않는다(공유 공간에서
132
- * 먼저 쓴 값이 이긴다). 거절 검사가 "안 바뀌었다" 를 확인할 때 이 성질에 기대지 않도록,
133
- * 여기서 그것이 별개의 규칙임을 못 박아 둔다.
134
- */
135
- assert.equal(t.spaceName, '서울 창고', '기존 공간 이름은 재인제스트가 덮지 않는다(별개 규칙)')
136
- })
@@ -1,78 +0,0 @@
1
- /*
2
- * 인제스트 공간 판정 — "이 현장에 더한다" 가 알리지 않고 빗나가지 않게.
3
- *
4
- * 엔진 본체는 DB·TypeORM 을 물고 있어 단위테스트로 부를 수 없다. 그래서 **결정만** 순수 모듈로
5
- * 떼어 놓고 여기서 본다(엔진은 공간 존재 여부를 조회해 넘기는 일만 한다).
6
- */
7
- import { test } from 'node:test'
8
- import assert from 'node:assert/strict'
9
-
10
- import { resolveIngestSpace, refuseImportSpace, collidingIds, INGEST_SPACE_NOT_FOUND } from '../server/service/reference/ingest-space.ts'
11
-
12
- test('고르지 않으면 마스터가 파생한 공간으로 — 지금까지의 거동을 바꾸지 않는다', () => {
13
- for (const req of [undefined, null, '', ' ']) {
14
- const c = resolveIngestSpace('hatiolab-wms-site', req as any, false)
15
- assert.deepEqual(c, { spaceId: 'hatiolab-wms-site', joined: false }, `요청=${JSON.stringify(req)}`)
16
- }
17
- })
18
-
19
- test('기존 현장을 고르면 그 공간으로 들어가고 합치기로 표시된다', () => {
20
- const c = resolveIngestSpace('trailer-yard-new-site', 'rosarito-site', true)
21
- assert.deepEqual(c, { spaceId: 'rosarito-site', joined: true })
22
- })
23
-
24
- test('마스터가 이미 그 공간이면 합치기가 아니다 — 같은 공간의 재인제스트다', () => {
25
- const c = resolveIngestSpace('rosarito-site', 'rosarito-site', true)
26
- assert.deepEqual(c, { spaceId: 'rosarito-site', joined: false })
27
- })
28
-
29
- test('없는 현장은 거절한다 — 알리지 않고 새 공간을 만들지 않는다', () => {
30
- /* 여기서 새 공간을 만들어 주면 사용자는 합쳤다고 믿고 화면은 따로 논다. 그때는 이미 양쪽에
31
- 이벤트가 쌓여 있어 손으로 합치는 것이 훨씬 비싸다. */
32
- assert.throws(
33
- () => resolveIngestSpace('a-site', 'typo-site', false),
34
- (e: any) => e.code === INGEST_SPACE_NOT_FOUND && /typo-site/.test(e.message)
35
- )
36
- })
37
-
38
- test('앞뒤 공백은 다듬는다 — 사용자가 붙여 넣은 id 로 거절당하지 않게', () => {
39
- const c = resolveIngestSpace('a-site', ' rosarito-site ', true)
40
- assert.equal(c.spaceId, 'rosarito-site')
41
- })
42
-
43
- test('같은 id 를 쓰는 것들을 찾아낸다 — 합쳐지는 것을 모르고 지나가지 않게', () => {
44
- const existing = [{ id: 'a-yard' }, { id: 'a-dock' }]
45
- const incoming = [{ id: 'a-yard' }, { id: 'a-line' }, { id: 'a-dock' }]
46
- assert.deepEqual(collidingIds(existing, incoming), ['a-dock', 'a-yard'], '정렬된 교집합')
47
- assert.deepEqual(collidingIds(existing, [{ id: 'a-line' }]), [], '겹치지 않으면 빈 배열')
48
- assert.deepEqual(collidingIds(undefined, undefined), [], '없는 쪽은 빈 것으로 본다')
49
- assert.deepEqual(collidingIds([{}, { id: '' }], [{ id: '' }]), [], 'id 없는 항목은 세지 않는다')
50
- })
51
-
52
- /* ── 실 시스템 import 의 현장 선택 (2026-08-13) ───────────────────────────── */
53
-
54
- test('현장을 고르지 않으면 사이트가 몇이든 진행한다 — 지금까지의 거동', () => {
55
- for (const n of [0, 1, 5, 40]) {
56
- assert.equal(refuseImportSpace(n, undefined), undefined)
57
- assert.equal(refuseImportSpace(n, ''), undefined)
58
- }
59
- })
60
-
61
- test('사이트 하나면 그 현장에 넣는다 — 렌즈를 더하는 정상 경로', () => {
62
- assert.equal(refuseImportSpace(1, 'rosarito-site'), undefined)
63
- })
64
-
65
- test('사이트 여럿을 한 현장에 넣는 것은 거절한다 — 서로 다른 현장이 알리지 않고 합쳐진다', () => {
66
- const r = refuseImportSpace(3, 'rosarito-site')
67
- assert.ok(r, '거절해야 한다')
68
- assert.equal(r.code, 'space-with-multiple-sites')
69
- assert.equal(r.params?.count, 3)
70
- assert.equal(r.params?.spaceId, 'rosarito-site')
71
- assert.match(r.message, /pick one site/)
72
- })
73
-
74
- test('거절 사유는 코드로 낸다 — 화면이 다섯 언어로 번역할 수 있게', () => {
75
- const r = refuseImportSpace(2, ' rosarito-site ')
76
- assert.equal(r?.code, 'space-with-multiple-sites')
77
- assert.equal(r?.params?.spaceId, 'rosarito-site', '앞뒤 공백은 다듬어 낸다')
78
- })
@@ -1,72 +0,0 @@
1
- /*
2
- * ★ **보는 사람이 없어도 창이 닫힌다** — 아무도 안 보는 트윈일수록 기록이 없었다.
3
- *
4
- * ── 실측 (2026-09-05) ──────────────────────────────────────────────────────
5
- * mes-miratek 사실 46건 · 62분에 흩어짐 창 1개
6
- * mes-line-a 사실 11건 창 48개
7
- *
8
- * **사실 수와 창 수가 거꾸로다.** 창은 「다음 사건이 왔을 때」와 「누가 물어볼 때」만 굴렀고,
9
- * `ingestHealthOf()` 가 굴리는 쪽이 실제로 창을 만들고 있었다 — 점검표·화면이 계속 묻는 트윈만
10
- * 기록이 쌓였다.
11
- *
12
- * 그래서 **아무도 안 보는 트윈일수록 기록이 없었다.** 사실이 조용히 사라지는 것을 잡으려고 만든
13
- * 장부가 정확히 그 반대로 돌았다. 실제로 137봉투가 장부 없이 지나갔다(인티그레이션 레인 실측).
14
- *
15
- * ── 왜 주기인가 ────────────────────────────────────────────────────────────
16
- * 창이 닫히는 이유는 **시간이 지난 것**이다. 사건도 질의도 그것을 알려 주는 신호일 뿐이고 둘 다
17
- * 안 올 수 있다. 시간은 늘 지나므로 주기가 그 사실에 맞는 신호다.
18
- */
19
- import { test } from 'node:test'
20
- import assert from 'node:assert/strict'
21
-
22
- import { INGEST_WINDOW_MS, newIngestLedger, recordJournalWrite, rollIngestWindow } from '../server/engine/ingest-health.js'
23
-
24
- const T0 = 1_757_000_000_000
25
-
26
- test('★ 사건도 질의도 없이 시간만 지나면 창이 닫힌다', () => {
27
- const ledger = newIngestLedger()
28
- const closed: any[] = []
29
-
30
- /* 사실 하나가 들어와 창이 열린다. */
31
- recordJournalWrite(ledger, 1, T0, w => closed.push(w))
32
- assert.equal(closed.length, 0, '열리자마자 닫히면 안 된다')
33
-
34
- /* 그 뒤로 아무 일도 없다 — 주기만 온다. */
35
- rollIngestWindow(ledger, T0 + INGEST_WINDOW_MS + 1, INGEST_WINDOW_MS, w => closed.push(w))
36
-
37
- assert.equal(closed.length, 1, '시간이 지났는데 창이 안 닫혔다 — 기록이 안 남는다')
38
- assert.equal(closed[0].rows, 1, '닫힌 창이 그 사실을 안 들었다')
39
- })
40
-
41
- test('★ 창 길이 전에는 안 닫는다 — 주기가 창을 잘게 쪼개면 안 된다', () => {
42
- const ledger = newIngestLedger()
43
- const closed: any[] = []
44
- recordJournalWrite(ledger, 1, T0)
45
-
46
- /* 주기(30초)가 창 길이(10분)보다 짧다 — 여러 번 와도 안 닫혀야 한다. */
47
- for (let i = 1; i <= 10; i++) rollIngestWindow(ledger, T0 + i * 30_000, INGEST_WINDOW_MS, w => closed.push(w))
48
-
49
- assert.equal(closed.length, 0, `주기가 창을 ${closed.length}개로 쪼갰다`)
50
- })
51
-
52
- test('★ 조용한 구간도 창으로 남는다 — expected-quiet 판정이 그 기록 위에 선다', () => {
53
- /*
54
- * 사실이 하나도 안 온 구간이 표에 남아야 「조용한 것이 정상인가」를 판정할 수 있다. 그 구간이
55
- * 아예 기록되지 않으면 조용함과 기록 없음이 구별되지 않는다.
56
- */
57
- const ledger = newIngestLedger()
58
- const closed: any[] = []
59
- recordJournalWrite(ledger, 1, T0, w => closed.push(w))
60
-
61
- /* 두 창을 통째로 건너뛴다 — 그 사이 아무 사실도 없었다. */
62
- rollIngestWindow(ledger, T0 + INGEST_WINDOW_MS * 2 + 1, INGEST_WINDOW_MS, w => closed.push(w))
63
-
64
- assert.ok(closed.length >= 1, '건너뛴 구간이 하나도 안 남았다')
65
- })
66
-
67
- test('★ 이 검사가 실제로 무언가를 잰다 — 견준 것이 0이면 빨강', () => {
68
- assert.ok(INGEST_WINDOW_MS > 0, `창 길이가 ${INGEST_WINDOW_MS} 다`)
69
- const ledger = newIngestLedger()
70
- recordJournalWrite(ledger, 3, T0)
71
- assert.equal(ledger.window.rows, 3, '장부가 사실을 안 세고 있다 — 이 검사가 아무것도 안 잰다')
72
- })
@@ -1,197 +0,0 @@
1
- /*
2
- * 유입 배선 감시 — **커널이 문을 열었는데 그 문으로 가는 길이 없는 것**을 잡는다.
3
- *
4
- * ── 왜 있나 (2026-08-30) ────────────────────────────────────────────────────
5
- * 2026-08-29 하루에 이 부류가 다섯 번 났다. 커널에 새 어휘의 문을 만들고, 정규 유입의 갈림에
6
- * 그 길을 내지 않은 것이다. 그때마다 레코드는 **거부되지도 않고 아무 문에도 들어가지 못한 채**
7
- * 사라졌다 — 커넥터는 보냈다고 믿고, 화면은 값이 없다고 말한다. 사람이 하나씩 찾아냈다.
8
- *
9
- * 다음 날 같은 부류의 **두 번째 얼굴**이 드러났다. EPCIS 갈래는 「나머지 전부」라, 새 어휘를 그
10
- * 목록에서 빼 주지 않으면 레코드가 제 문으로 가면서 **EPCIS 문으로도 들어가 거부된다.** 받아들여
11
- * 지기도 하고 거부되기도 하는 상태가 되어, 유입 장부의 거부 수가 늘고 사람이 그것을 진짜 결함으로
12
- * 읽는다.
13
- *
14
- * ── 무엇을 지키나 ──────────────────────────────────────────────────────────
15
- * ① 커널의 유입 함수마다 부르는 곳이 있다
16
- * ② 어휘마다 **정확히 한 문**으로 간다 — 어느 문에도 못 가거나 두 문에 걸치지 않는다
17
- *
18
- * ── 목록을 손으로 적지 않는다 ──────────────────────────────────────────────
19
- * 커널이 내보내는 이름에서 읽는다. 커널이 문을 늘리면 이 시험이 먼저 빨갛게 난다. 손 목록을 두면
20
- * 늘어난 것을 모른다 — 이 저장소가 이미 그 실패를 겪었다(`vocabulary-labels` 의 주석).
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
- import { dirname, join } from 'node:path'
27
-
28
- /* 유입 문과 판별 함수는 계약에 있다 — 커널은 엔진만 내보낸다(2026-08-30 층 분리). */
29
- import * as kernel from '@operato/ops-contract'
30
- import { ingestCanonicalRecords } from '../server/engine/canonical-ingest.ts'
31
-
32
- const here = dirname(fileURLToPath(import.meta.url))
33
- const routerSource = readFileSync(join(here, '..', 'server', 'engine', 'canonical-ingest.ts'), 'utf-8')
34
-
35
- /**
36
- * 정규 유입이 부르지 **않아도 되는** 것 — 각각 이유가 있다.
37
- *
38
- * 이 목록에 올릴 때는 이유를 함께 적는다. 이유 없이 올리면 이 시험은 아무것도 지키지 않는다.
39
- */
40
- const NOT_ROUTED: Record<string, string> = {
41
- /* 물류 어휘의 진입점 자체다 — 갈림이 이것을 부른다(이름이 `ingest` 하나뿐이라 규칙에 안 걸린다). */
42
- ingest: 'EPCIS 어휘의 진입점. 갈림이 직접 부른다',
43
- /* 마스터 데이터는 사건이 아니라 어휘 갱신이라 다른 경로로 간다. */
44
- ingestMasterData: '사건이 아니라 어휘 갱신 — 참조 계층이 부른다'
45
- }
46
-
47
- test('★ 커널의 유입 함수마다 부르는 곳이 있다', () => {
48
- const ingests = Object.keys(kernel).filter(n => /^ingest/.test(n))
49
- assert.ok(ingests.length >= 8, `유입 함수를 못 읽었다(${ingests.length}개) — 커널을 다시 읽어야 한다`)
50
-
51
- const unrouted = ingests.filter(n => !NOT_ROUTED[n] && !routerSource.includes(n))
52
- assert.deepEqual(
53
- unrouted,
54
- [],
55
- `커널이 문을 열었는데 정규 유입에 길이 없다:\n${unrouted.join('\n')}\n` +
56
- '그 문으로 보내는 레코드는 거부되지도 않고 사라진다.\n' +
57
- '갈림에 길을 내거나, 부르지 않아도 되는 이유를 NOT_ROUTED 에 적어라.'
58
- )
59
- })
60
-
61
- test('부르지 않아도 되는 목록에 이유가 적혀 있다', () => {
62
- for (const [name, why] of Object.entries(NOT_ROUTED)) {
63
- assert.ok(why.trim().length > 5, `${name} 에 이유가 없다`)
64
- }
65
- })
66
-
67
- /**
68
- * 어휘마다 대표 레코드 하나 — **그 문으로만 가야 한다.**
69
- *
70
- * 값은 실제로 오는 모양에서 가져왔다(2026-08-29 실측). 지어낸 모양으로 검사하면 실제 레코드가
71
- * 다른 문으로 가는 것을 놓친다.
72
- */
73
- const NOW = '2026-08-30T00:00:00.000Z'
74
- const SAMPLES: { vocabulary: string; eventType: string; record: Record<string, unknown> }[] = [
75
- {
76
- vocabulary: '물품 관측(EPCIS)',
77
- eventType: 'epcis.ObjectEvent',
78
- record: {
79
- epc: 'urn:epc:id:sgtin:0614141.107346.2017',
80
- action: 'OBSERVE',
81
- bizStep: 'urn:epcglobal:cbv:bizstep:storing',
82
- readPoint: 'rack-1'
83
- }
84
- },
85
- { vocabulary: '계량 표본', eventType: 'energy.measured', record: { meterId: 'incoming', kW: 100, at: NOW } },
86
- {
87
- vocabulary: '설비 상태',
88
- eventType: 'energy.equipment',
89
- record: { equipmentId: 'inv-1', generatedKW: 24.6, dcVoltage: 469.13, at: NOW }
90
- },
91
- { vocabulary: '발전 적산', eventType: 'energy.generated', record: { equipmentId: 'inv-1', kWh: 174, at: NOW } },
92
- {
93
- vocabulary: '마감된 사용 구간',
94
- eventType: 'energy.usage.period',
95
- record: {
96
- meterId: 'incoming',
97
- from: '2026-08-29T15:00:00.000Z',
98
- to: '2026-08-29T16:00:00.000Z',
99
- kWh: 474.48,
100
- maxKW: 478.08,
101
- unitPrice: 87.3,
102
- currency: 'KRW',
103
- basis: 'provider'
104
- }
105
- },
106
- {
107
- vocabulary: '요금 기준',
108
- eventType: 'energy.tariff.basis',
109
- record: {
110
- /* 기준 선언은 **끝나지 않은 달**이 정상이다 — 사건 시각이 기간의 시작이라 미래에 적히지 않는다. */
111
- from: '2026-07-31T15:00:00.000Z',
112
- to: '2026-08-31T15:00:00.000Z',
113
- billingDemandKW: 1650,
114
- demandChargePerKW: 8320,
115
- currency: 'KRW'
116
- }
117
- },
118
- {
119
- vocabulary: '청구서',
120
- eventType: 'energy.bill',
121
- record: {
122
- /*
123
- * 청구서는 **마감된 달**이다. 처음 이 표본은 끝나지 않은 8월을 담고 있었는데, 그것은 실제로
124
- * 들어와 있던 잘못된 데이터를 그대로 베낀 것이었다(2026-08-30). 그 데이터 때문에 한 현장의
125
- * 성과 구간이 미래로 밀려 화면이 비어 있었다. 표본이 결함을 베끼면 시험이 결함을 지킨다.
126
- */
127
- from: '2026-06-30T15:00:00.000Z',
128
- to: '2026-07-31T15:00:00.000Z',
129
- demandCharge: 13_728_000,
130
- currency: 'KRW',
131
- billingDemandKW: 1650
132
- }
133
- },
134
- {
135
- vocabulary: '발전 단가',
136
- eventType: 'energy.generation.price',
137
- record: { from: '2026-08-29T15:00:00.000Z', to: '2026-08-30T15:00:00.000Z', unitPrice: 148.61, currency: 'KRW' }
138
- },
139
- {
140
- /*
141
- * 라이브에서는 커널이 스스로 마감해 내지만, **지난 기록을 채울 때**는 밖에서 들어온다.
142
- * 구간이 있으므로 적산의 문(`energy.generated`)이 아니라 이쪽으로 가야 한다 — 겹치면 지난
143
- * 기록이 「지금 적산」으로도 읽혀 트윈의 시계가 과거로 끌린다.
144
- */
145
- vocabulary: '마감된 발전 기간',
146
- eventType: 'energy.generation.period',
147
- record: {
148
- equipmentId: '001',
149
- from: '2026-08-28T15:00:00.000Z',
150
- to: '2026-08-29T15:00:00.000Z',
151
- kWh: 394.3,
152
- accumulation: 'daily'
153
- }
154
- }
155
- ]
156
-
157
- test('★ 어휘마다 정확히 한 문으로 간다 — 사라지지도, 두 문에 걸치지도 않는다', () => {
158
- const wrong: string[] = []
159
- for (const s of SAMPLES) {
160
- const r = ingestCanonicalRecords([s.record] as any, 't', NOW)
161
- const accepted = (r.accepted as any[]).map(e => e.eventType)
162
- if (r.rejected.length) {
163
- wrong.push(`${s.vocabulary}: 거부됐다 — ${JSON.stringify(r.rejected[0]?.errors)}`)
164
- continue
165
- }
166
- if (accepted.length !== 1) {
167
- wrong.push(`${s.vocabulary}: 봉투가 ${accepted.length}개다(${accepted.join(', ')}) — 한 문으로만 가야 한다`)
168
- continue
169
- }
170
- if (accepted[0] !== s.eventType) wrong.push(`${s.vocabulary}: ${s.eventType} 이어야 하는데 ${accepted[0]} 로 갔다`)
171
- }
172
- assert.deepEqual(wrong, [], `\n${wrong.join('\n')}`)
173
- })
174
-
175
- test('★ 한 배치에 모든 어휘가 섞여 와도 각자의 문으로 간다', () => {
176
- const r = ingestCanonicalRecords(SAMPLES.map(s => s.record) as any, 't', NOW)
177
- assert.deepEqual(r.rejected, [], `거부가 없어야 한다: ${JSON.stringify(r.rejected)}`)
178
- assert.deepEqual(
179
- (r.accepted as any[]).map(e => e.eventType).sort(),
180
- SAMPLES.map(s => s.eventType).sort()
181
- )
182
- })
183
-
184
- test('커널이 어휘를 늘리면 이 시험이 먼저 안다', () => {
185
- /*
186
- * 판별 함수의 수와 위 표본의 수가 어긋나면, 커널에 어휘가 늘었는데 여기 표본이 없다는 뜻이다.
187
- * (EPCIS 안의 갈림 둘(담김·변환)은 한 어휘로 센다 — 같은 문으로 간다.)
188
- */
189
- const gates = Object.keys(kernel).filter(n => /^is.*Record$/.test(n))
190
- const counted = gates.filter(n => !['isAggregationRecord', 'isTransformationRecord', 'isMasterDataRecord'].includes(n))
191
- assert.equal(
192
- counted.length,
193
- SAMPLES.length,
194
- `커널의 어휘는 ${counted.length}개인데 표본은 ${SAMPLES.length}개다:\n${counted.join(' ')}\n` +
195
- '늘어난 어휘의 표본을 SAMPLES 에 더하라 — 그래야 그 어휘도 한 문으로 가는지 검사된다.'
196
- )
197
- })
@@ -1,110 +0,0 @@
1
- /*
2
- * ★ 인스턴스별 캐시는 **트윈과 함께 사라진다.**
3
- *
4
- * ── 왜 이 검사가 필요한가 ─────────────────────────────────────────────────────
5
- * 엔진은 트윈마다 메모리에 몇 가지를 들고 있다(실측 추정기·구조 리비전·복구 표식). 지움은 저널과
6
- * 등록부까지 갔는데 **캐시는 남았다** — 삭제된 트윈의 항목이 서버 재기동까지 살아 있었다. 항목 하나가
7
- * 하루치 KPI 그룹을 물고 있으므로, 트윈을 만들고 지우는 일이 반복되는 현장에서는 그것이 곧 누수다.
8
- *
9
- * TTL 은 이것을 막지 못한다: TTL 은 **값이 낡는 것**을 막을 뿐 **없어진 주인**을 지우지 않는다.
10
- *
11
- * 그래서 규율은 둘이다.
12
- * ① 트윈이 사라지면 그 트윈에 대한 메모리를 **전부** 잊는다(정확한 쪽).
13
- * ② 우리 API 를 지나지 않고 사라지는 길(도메인째 삭제·DB 직접 조작)에는 **상한**이 막는다(방어).
14
- *
15
- * 사설(private) 필드를 들여다보는 검사인 것을 안다. 그런데 여기서 지켜야 하는 것은 겉으로 드러나는
16
- * 값이 아니라 **메모리가 자라지 않는다**는 사실이고, 그것은 안을 봐야 볼 수 있다.
17
- */
18
- import { test, before, after } from 'node:test'
19
- import assert from 'node:assert/strict'
20
- import { createRequire } from 'node:module'
21
- import type { DataSource } from 'typeorm'
22
-
23
- const req = createRequire(import.meta.url)
24
- const { NamingStrategy, addDataSource, entities: shellEntities, Domain } = req('@things-factory/shell')
25
- const { entities: authEntities } = req('@things-factory/auth-base')
26
- const { entities: twinEntities } = req('../dist-server/service/index.js')
27
- const { TwinEngine } = req('../dist-server/engine/index.js')
28
- const { DataSource: TypeOrmDataSource } = req('typeorm')
29
-
30
- let ds: DataSource
31
- let domainId: string
32
-
33
- const INSTANCE = 'cache-probe'
34
-
35
- const master = (): any => ({
36
- source: INSTANCE,
37
- system: 'wms',
38
- siteName: '캐시 창고',
39
- space: { spaceId: 'cache-site', width: 40, depth: 30, unit: 'm' },
40
- locations: [
41
- { id: 'dock', type: 'dock', role: 'location', name: '도크', capacity: 50 },
42
- { id: 'bin-1', type: 'storage', role: 'location', name: '빈1', capacity: 20 }
43
- ],
44
- equipment: [{ id: 'fk-1', kind: 'forklift', homeLocationId: 'dock' }]
45
- })
46
-
47
- /** 캐시 안을 본다 — 겉으로는 안 보이는 사실을 지키는 검사이므로. */
48
- const caches = () => ({
49
- measured: (TwinEngine as any).measuredCache as Map<string, unknown>,
50
- structureRev: (TwinEngine as any).structureRevCache as Record<string, number>,
51
- recovered: (TwinEngine as any).recovered as Record<string, unknown>
52
- })
53
- const keyOf = (id: string) => `${domainId}:${id}`
54
-
55
- before(async () => {
56
- ds = new TypeOrmDataSource({
57
- type: 'sqlite',
58
- database: ':memory:',
59
- synchronize: true,
60
- dropSchema: true,
61
- namingStrategy: new NamingStrategy(),
62
- entities: [...shellEntities, ...authEntities, ...twinEntities],
63
- logging: false
64
- })
65
- await ds.initialize()
66
- addDataSource('default', ds)
67
- const d = await ds.getRepository(Domain).save({ name: 'cache-test', subdomain: 'cache-test' } as any)
68
- domainId = d.id
69
- })
70
-
71
- after(async () => {
72
- await TwinEngine.stop(domainId, INSTANCE).catch(() => {})
73
- await ds?.destroy()
74
- })
75
-
76
- test('지운 트윈의 캐시는 남지 않는다 — TTL 은 없어진 주인을 지우지 않는다', async () => {
77
- await TwinEngine.ingestMaster(domainId, master(), 'reset')
78
- /* 캐시를 실제로 채운다 — 손으로 넣으면 "채우는 경로" 가 바뀌어도 검사가 통과한다. */
79
- await TwinEngine.structureRevOf(domainId, INSTANCE)
80
- const { measured, structureRev } = caches()
81
- assert.ok(keyOf(INSTANCE) in structureRev, '구조 리비전이 캐시에 올라와야 이 검사가 뜻이 있다')
82
-
83
- await TwinEngine.remove(domainId, INSTANCE)
84
-
85
- const after = caches()
86
- assert.equal(keyOf(INSTANCE) in after.structureRev, false, '지운 트윈의 구조 리비전이 남았다')
87
- assert.equal(after.measured.has(keyOf(INSTANCE)), false, '지운 트윈의 실측 캐시가 남았다')
88
- assert.equal(keyOf(INSTANCE) in after.recovered, false, '지운 트윈의 복구 표식이 남았다')
89
- assert.equal(measured, after.measured, '캐시 객체를 갈아치우는 것이 아니라 항목을 지운다')
90
- })
91
-
92
- test('상한을 넘으면 가장 오래 손대지 않은 것부터 버린다 — 주인 없이 사라진 트윈까지 막는다', async () => {
93
- const { measured } = caches()
94
- measured.clear()
95
- const MAX = (TwinEngine as any).MEASURED_MAX as number
96
- assert.ok(MAX > 0, '상한이 선언되어 있어야 방어가 성립한다')
97
-
98
- /*
99
- * 상한 + 2 개를 넣고, 넣는 경로(`measuredEstimator`)를 그대로 쓴다. 트윈이 등록되어 있지 않으면
100
- * KPI 조회가 빈 값을 내고 캐시에는 `undefined` 가 들어간다 — **그 자체도 캐시할 값이다**(없다는
101
- * 사실을 알고 있는 것과 매번 다시 묻는 것은 다르다).
102
- */
103
- const call = (TwinEngine as any).measuredEstimator.bind(TwinEngine)
104
- for (let i = 0; i < MAX + 2; i++) await call(domainId, `ghost-${i}`)
105
-
106
- assert.ok(measured.size <= MAX, `상한을 넘어 자랐다(${measured.size} > ${MAX})`)
107
- assert.equal(measured.has(`${domainId}:ghost-0`), false, '가장 오래된 항목이 남아 있다 — 버릴 순서가 어긋났다')
108
- assert.ok(measured.has(`${domainId}:ghost-${MAX + 1}`), '가장 최근 항목은 남아야 한다')
109
- measured.clear()
110
- })