@things-factory/headless-twin 10.1.277 → 10.1.279

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (614) hide show
  1. package/package.json +21 -7
  2. package/dist-server/engine/attention-digest.js.map +0 -1
  3. package/dist-server/engine/canonical-ingest.js.map +0 -1
  4. package/dist-server/engine/checkpoint-fold.js.map +0 -1
  5. package/dist-server/engine/command-routing.js.map +0 -1
  6. package/dist-server/engine/declared-stimulus.js.map +0 -1
  7. package/dist-server/engine/energy-topology.js.map +0 -1
  8. package/dist-server/engine/event-time.js.map +0 -1
  9. package/dist-server/engine/index.js.map +0 -1
  10. package/dist-server/engine/ingest-dedupe.js.map +0 -1
  11. package/dist-server/engine/ingest-health.js.map +0 -1
  12. package/dist-server/engine/integration-coverage.js.map +0 -1
  13. package/dist-server/engine/integration-probes.js.map +0 -1
  14. package/dist-server/engine/integration-runner.js.map +0 -1
  15. package/dist-server/engine/integration-target-profile.js.map +0 -1
  16. package/dist-server/engine/kpi-baseline.js.map +0 -1
  17. package/dist-server/engine/kpi-fold.js.map +0 -1
  18. package/dist-server/engine/kpi-query.js.map +0 -1
  19. package/dist-server/engine/kpi-target.js.map +0 -1
  20. package/dist-server/engine/live-attentions.js.map +0 -1
  21. package/dist-server/engine/live-feed-registry.js.map +0 -1
  22. package/dist-server/engine/load-meter.js.map +0 -1
  23. package/dist-server/engine/local-declarations.js.map +0 -1
  24. package/dist-server/engine/log.js.map +0 -1
  25. package/dist-server/engine/loop-lag.js.map +0 -1
  26. package/dist-server/engine/measured-estimator.js.map +0 -1
  27. package/dist-server/engine/measured-yield.js.map +0 -1
  28. package/dist-server/engine/model-basis.js.map +0 -1
  29. package/dist-server/engine/model-gap.js.map +0 -1
  30. package/dist-server/engine/model-refusal.js.map +0 -1
  31. package/dist-server/engine/model-vocabulary.js.map +0 -1
  32. package/dist-server/engine/oee-accumulator.js.map +0 -1
  33. package/dist-server/engine/operation-basis.js.map +0 -1
  34. package/dist-server/engine/producer-guard.js.map +0 -1
  35. package/dist-server/engine/property-effects.js.map +0 -1
  36. package/dist-server/engine/read-time.js.map +0 -1
  37. package/dist-server/engine/restart-policy.js.map +0 -1
  38. package/dist-server/engine/runtime-key.js.map +0 -1
  39. package/dist-server/engine/spec-coverage.js.map +0 -1
  40. package/dist-server/engine/stage-path.js.map +0 -1
  41. package/dist-server/engine/state-axes.js.map +0 -1
  42. package/dist-server/engine/structure-diff.js.map +0 -1
  43. package/dist-server/engine/travel-estimator.js.map +0 -1
  44. package/dist-server/engine/twin-engine.js.map +0 -1
  45. package/dist-server/engine/twin-state-channel.js.map +0 -1
  46. package/dist-server/engine/warm-start.js.map +0 -1
  47. package/dist-server/index.js.map +0 -1
  48. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js.map +0 -1
  49. package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js.map +0 -1
  50. package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js.map +0 -1
  51. package/dist-server/migrations/1786300000000-IndexEventTypeByTime.js.map +0 -1
  52. package/dist-server/migrations/1786400000000-IndexEventCreatedAt.js.map +0 -1
  53. package/dist-server/migrations/1786500000000-CreateTwinSubjectEvents.js.map +0 -1
  54. package/dist-server/migrations/1786600000000-RenameOperatoMesAdapterType.js.map +0 -1
  55. package/dist-server/migrations/1786700000000-AddDispatchRetryColumns.js.map +0 -1
  56. package/dist-server/migrations/1786800000000-CreateTwinReferenceReconciliations.js.map +0 -1
  57. package/dist-server/migrations/index.js.map +0 -1
  58. package/dist-server/routes.js.map +0 -1
  59. package/dist-server/service/actuation/actuation-advisor.js.map +0 -1
  60. package/dist-server/service/actuation/actuation-outcome.js.map +0 -1
  61. package/dist-server/service/actuation/actuation-rule-resolver.js.map +0 -1
  62. package/dist-server/service/actuation/actuation-rule.js.map +0 -1
  63. package/dist-server/service/actuation/approval-gateway.js.map +0 -1
  64. package/dist-server/service/actuation/catch-up-effects.js.map +0 -1
  65. package/dist-server/service/actuation/command-dispatcher.js.map +0 -1
  66. package/dist-server/service/actuation/command-store.js.map +0 -1
  67. package/dist-server/service/actuation/dispatch-after-approval.js.map +0 -1
  68. package/dist-server/service/actuation/effect-match.js.map +0 -1
  69. package/dist-server/service/actuation/index.js.map +0 -1
  70. package/dist-server/service/actuation/retry-plan.js.map +0 -1
  71. package/dist-server/service/actuation/rule-evaluate.js.map +0 -1
  72. package/dist-server/service/actuation/rule-loop.js.map +0 -1
  73. package/dist-server/service/actuation/rule-runner.js.map +0 -1
  74. package/dist-server/service/actuation/rule-wiring.js.map +0 -1
  75. package/dist-server/service/actuation/settle-effects.js.map +0 -1
  76. package/dist-server/service/actuation/sweep-dispatch.js.map +0 -1
  77. package/dist-server/service/actuation/twin-command-resolver.js.map +0 -1
  78. package/dist-server/service/actuation/twin-command.js.map +0 -1
  79. package/dist-server/service/actuation/twin-now.js.map +0 -1
  80. package/dist-server/service/index.js.map +0 -1
  81. package/dist-server/service/reference/actuation-routing.js.map +0 -1
  82. package/dist-server/service/reference/actuation-target.js.map +0 -1
  83. package/dist-server/service/reference/actuation-verification.js.map +0 -1
  84. package/dist-server/service/reference/attention-lane.js.map +0 -1
  85. package/dist-server/service/reference/connection-portability-resolver.js.map +0 -1
  86. package/dist-server/service/reference/connection-portability.js.map +0 -1
  87. package/dist-server/service/reference/control-routing.js.map +0 -1
  88. package/dist-server/service/reference/discovery-result.js.map +0 -1
  89. package/dist-server/service/reference/fill-cadence.js.map +0 -1
  90. package/dist-server/service/reference/fill-dedupe.js.map +0 -1
  91. package/dist-server/service/reference/fill-loop.js.map +0 -1
  92. package/dist-server/service/reference/fill-span.js.map +0 -1
  93. package/dist-server/service/reference/hook-contract.js.map +0 -1
  94. package/dist-server/service/reference/hook-rejected.js.map +0 -1
  95. package/dist-server/service/reference/hook-store.js.map +0 -1
  96. package/dist-server/service/reference/index.js.map +0 -1
  97. package/dist-server/service/reference/ingest-space.js.map +0 -1
  98. package/dist-server/service/reference/knob-defaults.js.map +0 -1
  99. package/dist-server/service/reference/live-cadence.js.map +0 -1
  100. package/dist-server/service/reference/live-feed-lease.js.map +0 -1
  101. package/dist-server/service/reference/live-ingest.js.map +0 -1
  102. package/dist-server/service/reference/reference-adapter.js.map +0 -1
  103. package/dist-server/service/reference/reference-assessment.js.map +0 -1
  104. package/dist-server/service/reference/reference-fill-run.js.map +0 -1
  105. package/dist-server/service/reference/reference-fill.js.map +0 -1
  106. package/dist-server/service/reference/reference-hook.js.map +0 -1
  107. package/dist-server/service/reference/reference-link-groups.js.map +0 -1
  108. package/dist-server/service/reference/reference-links.js.map +0 -1
  109. package/dist-server/service/reference/reference-live.js.map +0 -1
  110. package/dist-server/service/reference/reference-master.js.map +0 -1
  111. package/dist-server/service/reference/reference-probe.js.map +0 -1
  112. package/dist-server/service/reference/reference-progress-channel.js.map +0 -1
  113. package/dist-server/service/reference/reference-progress-subscription.js.map +0 -1
  114. package/dist-server/service/reference/reference-progress.js.map +0 -1
  115. package/dist-server/service/reference/reference-reconciliation-query.js.map +0 -1
  116. package/dist-server/service/reference/reference-reconciliation-writer.js.map +0 -1
  117. package/dist-server/service/reference/reference-reconciliation.js.map +0 -1
  118. package/dist-server/service/reference/reference-registry.js.map +0 -1
  119. package/dist-server/service/reference/reference-resolver.js.map +0 -1
  120. package/dist-server/service/reference/template-registry.js.map +0 -1
  121. package/dist-server/service/reference/twin-reference-reconciliation.js.map +0 -1
  122. package/dist-server/service/reference/twin-reference.js.map +0 -1
  123. package/dist-server/service/twin-attention/index.js.map +0 -1
  124. package/dist-server/service/twin-attention/twin-attention-query.js.map +0 -1
  125. package/dist-server/service/twin-audit/command-audit.js.map +0 -1
  126. package/dist-server/service/twin-audit/index.js.map +0 -1
  127. package/dist-server/service/twin-audit/twin-audit-event.js.map +0 -1
  128. package/dist-server/service/twin-audit/twin-audit-query.js.map +0 -1
  129. package/dist-server/service/twin-backfill/backfill-period-facts.js.map +0 -1
  130. package/dist-server/service/twin-backfill/backfill-shape.js.map +0 -1
  131. package/dist-server/service/twin-backfill/index.js.map +0 -1
  132. package/dist-server/service/twin-backfill/twin-backfill-resolver.js.map +0 -1
  133. package/dist-server/service/twin-control/index.js.map +0 -1
  134. package/dist-server/service/twin-control/twin-control-mutation.js.map +0 -1
  135. package/dist-server/service/twin-event/index.js.map +0 -1
  136. package/dist-server/service/twin-event/journal-count.js.map +0 -1
  137. package/dist-server/service/twin-event/twin-event-keys.js.map +0 -1
  138. package/dist-server/service/twin-event/twin-event-type.js.map +0 -1
  139. package/dist-server/service/twin-event/twin-event.js.map +0 -1
  140. package/dist-server/service/twin-forecast/forecast-metrics.js.map +0 -1
  141. package/dist-server/service/twin-forecast/forecast-tuning.js.map +0 -1
  142. package/dist-server/service/twin-forecast/gap-analytics.js.map +0 -1
  143. package/dist-server/service/twin-forecast/index.js.map +0 -1
  144. package/dist-server/service/twin-forecast/twin-forecast-query.js.map +0 -1
  145. package/dist-server/service/twin-ingest-window/index.js.map +0 -1
  146. package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js.map +0 -1
  147. package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js.map +0 -1
  148. package/dist-server/service/twin-ingest-window/twin-ingest-window.js.map +0 -1
  149. package/dist-server/service/twin-instance/index.js.map +0 -1
  150. package/dist-server/service/twin-instance/twin-instance.js.map +0 -1
  151. package/dist-server/service/twin-journal/event-type-split-shape.js.map +0 -1
  152. package/dist-server/service/twin-journal/event-type-split.js.map +0 -1
  153. package/dist-server/service/twin-journal/index.js.map +0 -1
  154. package/dist-server/service/twin-journal/journal-order.js.map +0 -1
  155. package/dist-server/service/twin-journal/twin-journal-query.js.map +0 -1
  156. package/dist-server/service/twin-lifecycle/domain-catalog.js.map +0 -1
  157. package/dist-server/service/twin-lifecycle/index.js.map +0 -1
  158. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +0 -1
  159. package/dist-server/service/twin-metrics/index.js.map +0 -1
  160. package/dist-server/service/twin-metrics/twin-metrics-query.js.map +0 -1
  161. package/dist-server/service/twin-model/axis-journal-evidence.js.map +0 -1
  162. package/dist-server/service/twin-model/choose-recipe.js.map +0 -1
  163. package/dist-server/service/twin-model/epcis-coverage.js.map +0 -1
  164. package/dist-server/service/twin-model/external-resolver.js.map +0 -1
  165. package/dist-server/service/twin-model/iec61850-coverage.js.map +0 -1
  166. package/dist-server/service/twin-model/index.js.map +0 -1
  167. package/dist-server/service/twin-model/isa95-coverage.js.map +0 -1
  168. package/dist-server/service/twin-model/item-ref.js.map +0 -1
  169. package/dist-server/service/twin-model/name-index.js.map +0 -1
  170. package/dist-server/service/twin-model/project-structure.js.map +0 -1
  171. package/dist-server/service/twin-model/standard-coverage.js.map +0 -1
  172. package/dist-server/service/twin-model/status-tally.js.map +0 -1
  173. package/dist-server/service/twin-model/twin-equipment.js.map +0 -1
  174. package/dist-server/service/twin-model/twin-lineage-query.js.map +0 -1
  175. package/dist-server/service/twin-model/twin-location.js.map +0 -1
  176. package/dist-server/service/twin-model/twin-model-item-query.js.map +0 -1
  177. package/dist-server/service/twin-model/twin-model-mutation.js.map +0 -1
  178. package/dist-server/service/twin-model/twin-model-query.js.map +0 -1
  179. package/dist-server/service/twin-model/twin-model-tree-query.js.map +0 -1
  180. package/dist-server/service/twin-model/twin-operation.js.map +0 -1
  181. package/dist-server/service/twin-readiness/index.js.map +0 -1
  182. package/dist-server/service/twin-readiness/twin-readiness-query.js.map +0 -1
  183. package/dist-server/service/twin-space/area-resolver.js.map +0 -1
  184. package/dist-server/service/twin-space/index.js.map +0 -1
  185. package/dist-server/service/twin-space/move-space.js.map +0 -1
  186. package/dist-server/service/twin-space/representation-role.js.map +0 -1
  187. package/dist-server/service/twin-space/space-integrity.js.map +0 -1
  188. package/dist-server/service/twin-space/twin-area.js.map +0 -1
  189. package/dist-server/service/twin-space/twin-space-area.js.map +0 -1
  190. package/dist-server/service/twin-space/twin-space-representation.js.map +0 -1
  191. package/dist-server/service/twin-space/twin-space-resolver.js.map +0 -1
  192. package/dist-server/service/twin-space/twin-space.js.map +0 -1
  193. package/dist-server/service/twin-state/index.js.map +0 -1
  194. package/dist-server/service/twin-state/twin-state-subscription.js.map +0 -1
  195. package/dist-server/service/twin-structure/index.js.map +0 -1
  196. package/dist-server/service/twin-structure/twin-structure.js.map +0 -1
  197. package/dist-server/service/twin-subject/event-subjects.js.map +0 -1
  198. package/dist-server/service/twin-subject/index.js.map +0 -1
  199. package/dist-server/service/twin-subject/item-resolver.js.map +0 -1
  200. package/dist-server/service/twin-subject/subject-query-shape.js.map +0 -1
  201. package/dist-server/service/twin-subject/twin-subject-backfill.js.map +0 -1
  202. package/dist-server/service/twin-subject/twin-subject-event.js.map +0 -1
  203. package/dist-server/service/twin-subject/twin-subject-fast-path.js.map +0 -1
  204. package/dist-server/service/twin-subject/twin-subject-query.js.map +0 -1
  205. package/dist-server/service/twin-subject/twin-subject-writer.js.map +0 -1
  206. package/dist-server/service/twin-target/index.js.map +0 -1
  207. package/dist-server/service/twin-target/twin-target-resolver.js.map +0 -1
  208. package/dist-server/service/twin-target/twin-target.js.map +0 -1
  209. package/dist-shared/axis-read.js.map +0 -1
  210. package/dist-shared/entity-delta.js.map +0 -1
  211. package/dist-shared/kpi-broadcast.js.map +0 -1
  212. package/dist-shared/touched-items.js.map +0 -1
  213. package/dist-shared/twin-level.js.map +0 -1
  214. package/server/engine/attention-digest.ts +0 -102
  215. package/server/engine/canonical-ingest.ts +0 -511
  216. package/server/engine/checkpoint-fold.ts +0 -12
  217. package/server/engine/command-routing.ts +0 -67
  218. package/server/engine/declared-stimulus.ts +0 -66
  219. package/server/engine/energy-topology.ts +0 -189
  220. package/server/engine/event-time.ts +0 -96
  221. package/server/engine/index.ts +0 -51
  222. package/server/engine/ingest-dedupe.ts +0 -24
  223. package/server/engine/ingest-health.ts +0 -24
  224. package/server/engine/integration-coverage.ts +0 -147
  225. package/server/engine/integration-probes.ts +0 -144
  226. package/server/engine/integration-runner.ts +0 -95
  227. package/server/engine/integration-target-profile.ts +0 -103
  228. package/server/engine/kpi-baseline.ts +0 -202
  229. package/server/engine/kpi-fold.ts +0 -1516
  230. package/server/engine/kpi-query.ts +0 -1210
  231. package/server/engine/kpi-target.ts +0 -248
  232. package/server/engine/live-attentions.ts +0 -30
  233. package/server/engine/live-feed-registry.ts +0 -59
  234. package/server/engine/load-meter.ts +0 -393
  235. package/server/engine/local-declarations.ts +0 -779
  236. package/server/engine/log.ts +0 -72
  237. package/server/engine/loop-lag.ts +0 -120
  238. package/server/engine/measured-estimator.ts +0 -91
  239. package/server/engine/measured-yield.ts +0 -89
  240. package/server/engine/model-basis.ts +0 -162
  241. package/server/engine/model-gap.ts +0 -168
  242. package/server/engine/model-refusal.ts +0 -31
  243. package/server/engine/model-vocabulary.ts +0 -82
  244. package/server/engine/oee-accumulator.ts +0 -195
  245. package/server/engine/operation-basis.ts +0 -131
  246. package/server/engine/producer-guard.ts +0 -64
  247. package/server/engine/property-effects.ts +0 -216
  248. package/server/engine/read-time.ts +0 -77
  249. package/server/engine/restart-policy.ts +0 -55
  250. package/server/engine/runtime-key.ts +0 -58
  251. package/server/engine/spec-coverage.ts +0 -105
  252. package/server/engine/stage-path.ts +0 -172
  253. package/server/engine/state-axes.ts +0 -60
  254. package/server/engine/structure-diff.ts +0 -88
  255. package/server/engine/travel-estimator.ts +0 -138
  256. package/server/engine/twin-engine.ts +0 -4979
  257. package/server/engine/twin-state-channel.ts +0 -39
  258. package/server/engine/warm-start.ts +0 -265
  259. package/server/index.ts +0 -90
  260. package/server/migrations/1786000000000-RenameTwinInstanceBoardToModel.ts +0 -43
  261. package/server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.ts +0 -54
  262. package/server/migrations/1786200000000-CarryLiveFeedCursor.ts +0 -53
  263. package/server/migrations/1786300000000-IndexEventTypeByTime.ts +0 -48
  264. package/server/migrations/1786400000000-IndexEventCreatedAt.ts +0 -38
  265. package/server/migrations/1786500000000-CreateTwinSubjectEvents.ts +0 -93
  266. package/server/migrations/1786600000000-RenameOperatoMesAdapterType.ts +0 -66
  267. package/server/migrations/1786700000000-AddDispatchRetryColumns.ts +0 -82
  268. package/server/migrations/1786800000000-CreateTwinReferenceReconciliations.ts +0 -39
  269. package/server/migrations/index.ts +0 -25
  270. package/server/routes.ts +0 -75
  271. package/server/service/actuation/actuation-advisor.ts +0 -131
  272. package/server/service/actuation/actuation-outcome.ts +0 -97
  273. package/server/service/actuation/actuation-rule-resolver.ts +0 -147
  274. package/server/service/actuation/actuation-rule.ts +0 -139
  275. package/server/service/actuation/approval-gateway.ts +0 -44
  276. package/server/service/actuation/catch-up-effects.ts +0 -152
  277. package/server/service/actuation/command-dispatcher.ts +0 -474
  278. package/server/service/actuation/command-store.ts +0 -236
  279. package/server/service/actuation/dispatch-after-approval.ts +0 -71
  280. package/server/service/actuation/effect-match.ts +0 -124
  281. package/server/service/actuation/index.ts +0 -27
  282. package/server/service/actuation/retry-plan.ts +0 -145
  283. package/server/service/actuation/rule-evaluate.ts +0 -352
  284. package/server/service/actuation/rule-loop.ts +0 -160
  285. package/server/service/actuation/rule-runner.ts +0 -216
  286. package/server/service/actuation/rule-wiring.ts +0 -84
  287. package/server/service/actuation/settle-effects.ts +0 -115
  288. package/server/service/actuation/sweep-dispatch.ts +0 -179
  289. package/server/service/actuation/twin-command-resolver.ts +0 -387
  290. package/server/service/actuation/twin-command.ts +0 -232
  291. package/server/service/actuation/twin-now.ts +0 -97
  292. package/server/service/index.ts +0 -100
  293. package/server/service/reference/actuation-routing.ts +0 -192
  294. package/server/service/reference/actuation-target.ts +0 -163
  295. package/server/service/reference/actuation-verification.ts +0 -85
  296. package/server/service/reference/attention-lane.ts +0 -21
  297. package/server/service/reference/connection-portability-resolver.ts +0 -171
  298. package/server/service/reference/connection-portability.ts +0 -329
  299. package/server/service/reference/control-routing.ts +0 -62
  300. package/server/service/reference/discovery-result.ts +0 -95
  301. package/server/service/reference/fill-cadence.ts +0 -29
  302. package/server/service/reference/fill-dedupe.ts +0 -66
  303. package/server/service/reference/fill-loop.ts +0 -153
  304. package/server/service/reference/fill-span.ts +0 -31
  305. package/server/service/reference/hook-contract.ts +0 -364
  306. package/server/service/reference/hook-rejected.ts +0 -53
  307. package/server/service/reference/hook-store.ts +0 -28
  308. package/server/service/reference/index.ts +0 -18
  309. package/server/service/reference/ingest-space.ts +0 -104
  310. package/server/service/reference/knob-defaults.ts +0 -59
  311. package/server/service/reference/live-cadence.ts +0 -129
  312. package/server/service/reference/live-feed-lease.ts +0 -56
  313. package/server/service/reference/live-ingest.ts +0 -94
  314. package/server/service/reference/reference-adapter.ts +0 -985
  315. package/server/service/reference/reference-assessment.ts +0 -250
  316. package/server/service/reference/reference-fill-run.ts +0 -179
  317. package/server/service/reference/reference-fill.ts +0 -223
  318. package/server/service/reference/reference-hook.ts +0 -479
  319. package/server/service/reference/reference-link-groups.ts +0 -21
  320. package/server/service/reference/reference-links.ts +0 -77
  321. package/server/service/reference/reference-live.ts +0 -420
  322. package/server/service/reference/reference-master.ts +0 -999
  323. package/server/service/reference/reference-probe.ts +0 -264
  324. package/server/service/reference/reference-progress-channel.ts +0 -26
  325. package/server/service/reference/reference-progress-subscription.ts +0 -78
  326. package/server/service/reference/reference-progress.ts +0 -95
  327. package/server/service/reference/reference-reconciliation-query.ts +0 -28
  328. package/server/service/reference/reference-reconciliation-writer.ts +0 -38
  329. package/server/service/reference/reference-reconciliation.ts +0 -55
  330. package/server/service/reference/reference-registry.ts +0 -17
  331. package/server/service/reference/reference-resolver.ts +0 -969
  332. package/server/service/reference/template-registry.ts +0 -85
  333. package/server/service/reference/twin-reference-reconciliation.ts +0 -27
  334. package/server/service/reference/twin-reference.ts +0 -190
  335. package/server/service/twin-attention/index.ts +0 -3
  336. package/server/service/twin-attention/twin-attention-query.ts +0 -70
  337. package/server/service/twin-audit/command-audit.ts +0 -114
  338. package/server/service/twin-audit/index.ts +0 -5
  339. package/server/service/twin-audit/twin-audit-event.ts +0 -158
  340. package/server/service/twin-audit/twin-audit-query.ts +0 -72
  341. package/server/service/twin-backfill/backfill-period-facts.ts +0 -168
  342. package/server/service/twin-backfill/backfill-shape.ts +0 -86
  343. package/server/service/twin-backfill/index.ts +0 -3
  344. package/server/service/twin-backfill/twin-backfill-resolver.ts +0 -35
  345. package/server/service/twin-control/index.ts +0 -3
  346. package/server/service/twin-control/twin-control-mutation.ts +0 -150
  347. package/server/service/twin-event/index.ts +0 -3
  348. package/server/service/twin-event/journal-count.ts +0 -53
  349. package/server/service/twin-event/twin-event-keys.ts +0 -215
  350. package/server/service/twin-event/twin-event-type.ts +0 -68
  351. package/server/service/twin-event/twin-event.ts +0 -250
  352. package/server/service/twin-forecast/forecast-metrics.ts +0 -106
  353. package/server/service/twin-forecast/forecast-tuning.ts +0 -40
  354. package/server/service/twin-forecast/gap-analytics.ts +0 -139
  355. package/server/service/twin-forecast/index.ts +0 -3
  356. package/server/service/twin-forecast/twin-forecast-query.ts +0 -486
  357. package/server/service/twin-ingest-window/index.ts +0 -7
  358. package/server/service/twin-ingest-window/twin-ingest-window-query.ts +0 -125
  359. package/server/service/twin-ingest-window/twin-ingest-window-writer.ts +0 -57
  360. package/server/service/twin-ingest-window/twin-ingest-window.ts +0 -113
  361. package/server/service/twin-instance/index.ts +0 -3
  362. package/server/service/twin-instance/twin-instance.ts +0 -199
  363. package/server/service/twin-journal/event-type-split-shape.ts +0 -112
  364. package/server/service/twin-journal/event-type-split.ts +0 -144
  365. package/server/service/twin-journal/index.ts +0 -3
  366. package/server/service/twin-journal/journal-order.ts +0 -20
  367. package/server/service/twin-journal/twin-journal-query.ts +0 -615
  368. package/server/service/twin-lifecycle/domain-catalog.ts +0 -51
  369. package/server/service/twin-lifecycle/index.ts +0 -3
  370. package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +0 -285
  371. package/server/service/twin-metrics/index.ts +0 -3
  372. package/server/service/twin-metrics/twin-metrics-query.ts +0 -172
  373. package/server/service/twin-model/axis-journal-evidence.ts +0 -57
  374. package/server/service/twin-model/choose-recipe.ts +0 -31
  375. package/server/service/twin-model/epcis-coverage.ts +0 -251
  376. package/server/service/twin-model/external-resolver.ts +0 -173
  377. package/server/service/twin-model/iec61850-coverage.ts +0 -111
  378. package/server/service/twin-model/index.ts +0 -25
  379. package/server/service/twin-model/isa95-coverage.ts +0 -320
  380. package/server/service/twin-model/item-ref.ts +0 -80
  381. package/server/service/twin-model/name-index.ts +0 -94
  382. package/server/service/twin-model/project-structure.ts +0 -213
  383. package/server/service/twin-model/standard-coverage.ts +0 -35
  384. package/server/service/twin-model/status-tally.ts +0 -37
  385. package/server/service/twin-model/twin-equipment.ts +0 -191
  386. package/server/service/twin-model/twin-lineage-query.ts +0 -327
  387. package/server/service/twin-model/twin-location.ts +0 -147
  388. package/server/service/twin-model/twin-model-item-query.ts +0 -1029
  389. package/server/service/twin-model/twin-model-mutation.ts +0 -503
  390. package/server/service/twin-model/twin-model-query.ts +0 -792
  391. package/server/service/twin-model/twin-model-tree-query.ts +0 -211
  392. package/server/service/twin-model/twin-operation.ts +0 -157
  393. package/server/service/twin-readiness/index.ts +0 -3
  394. package/server/service/twin-readiness/twin-readiness-query.ts +0 -96
  395. package/server/service/twin-space/area-resolver.ts +0 -75
  396. package/server/service/twin-space/index.ts +0 -8
  397. package/server/service/twin-space/move-space.ts +0 -262
  398. package/server/service/twin-space/representation-role.ts +0 -15
  399. package/server/service/twin-space/space-integrity.ts +0 -293
  400. package/server/service/twin-space/twin-area.ts +0 -63
  401. package/server/service/twin-space/twin-space-area.ts +0 -66
  402. package/server/service/twin-space/twin-space-representation.ts +0 -99
  403. package/server/service/twin-space/twin-space-resolver.ts +0 -582
  404. package/server/service/twin-space/twin-space.ts +0 -148
  405. package/server/service/twin-state/index.ts +0 -3
  406. package/server/service/twin-state/twin-state-subscription.ts +0 -62
  407. package/server/service/twin-structure/index.ts +0 -3
  408. package/server/service/twin-structure/twin-structure.ts +0 -96
  409. package/server/service/twin-subject/event-subjects.ts +0 -162
  410. package/server/service/twin-subject/index.ts +0 -10
  411. package/server/service/twin-subject/item-resolver.ts +0 -92
  412. package/server/service/twin-subject/subject-query-shape.ts +0 -84
  413. package/server/service/twin-subject/twin-subject-backfill.ts +0 -196
  414. package/server/service/twin-subject/twin-subject-event.ts +0 -101
  415. package/server/service/twin-subject/twin-subject-fast-path.ts +0 -346
  416. package/server/service/twin-subject/twin-subject-query.ts +0 -210
  417. package/server/service/twin-subject/twin-subject-writer.ts +0 -189
  418. package/server/service/twin-target/index.ts +0 -5
  419. package/server/service/twin-target/twin-target-resolver.ts +0 -142
  420. package/server/service/twin-target/twin-target.ts +0 -97
  421. package/server/types/global.d.ts +0 -22
  422. package/shared/axis-read.ts +0 -28
  423. package/shared/entity-delta.ts +0 -335
  424. package/shared/kpi-broadcast.ts +0 -13
  425. package/shared/touched-items.ts +0 -73
  426. package/shared/twin-level.ts +0 -48
  427. package/test/ack-shape-alignment.test.ts +0 -97
  428. package/test/actuation-advisor.test.ts +0 -55
  429. package/test/actuation-approval-door.test.ts +0 -411
  430. package/test/actuation-dispatch.test.ts +0 -209
  431. package/test/actuation-effect.test.ts +0 -162
  432. package/test/actuation-outcome.test.ts +0 -152
  433. package/test/actuation-rule-runner.test.ts +0 -281
  434. package/test/actuation-rule.test.ts +0 -266
  435. package/test/actuation-seam.test.ts +0 -255
  436. package/test/actuation-settle.test.ts +0 -164
  437. package/test/actuation-target.test.ts +0 -145
  438. package/test/actuation-verification-state.test.ts +0 -139
  439. package/test/adopt-structure-live.test.ts +0 -133
  440. package/test/aggregate-not-findone.test.ts +0 -112
  441. package/test/area-resolver-db.test.ts +0 -110
  442. package/test/attention-digest.test.ts +0 -161
  443. package/test/axis-declaration-passthrough-db.test.ts +0 -152
  444. package/test/axis-journal-evidence.test.ts +0 -71
  445. package/test/axis-read.test.ts +0 -188
  446. package/test/backfill-shape.test.ts +0 -89
  447. package/test/boot-resume.test.ts +0 -287
  448. package/test/broadcast-cost-baseline.test.ts +0 -201
  449. package/test/broadcast-period.test.ts +0 -58
  450. package/test/broadcast-queue-overflow.test.ts +0 -244
  451. package/test/canonical-ingest-vocabularies.test.ts +0 -451
  452. package/test/canonical-quantity-door.test.ts +0 -61
  453. package/test/capability-mapping.test.ts +0 -89
  454. package/test/checkpoint-refuses-empty.test.ts +0 -103
  455. package/test/choose-recipe.test.ts +0 -117
  456. package/test/column-type-portability.test.ts +0 -122
  457. package/test/command-routing.test.ts +0 -61
  458. package/test/command-store-writes-columns.test.ts +0 -126
  459. package/test/connection-portability-doors.test.ts +0 -87
  460. package/test/connector-capability-declaration.test.ts +0 -195
  461. package/test/contract-layer-guard.test.ts +0 -48
  462. package/test/control-capability.test.ts +0 -98
  463. package/test/cursor-stall-not-read-failure.test.ts +0 -126
  464. package/test/declaration-reaches-model.test.ts +0 -226
  465. package/test/declared-location-types.test.ts +0 -89
  466. package/test/declared-stimulus.test.ts +0 -88
  467. package/test/dedupe-transformation.test.ts +0 -112
  468. package/test/discovery-result.test.ts +0 -75
  469. package/test/dispatch-after-approval-source.test.ts +0 -81
  470. package/test/duration-estimators.test.ts +0 -144
  471. package/test/energy-topology.test.ts +0 -113
  472. package/test/entity-delta.test.ts +0 -352
  473. package/test/equipment-identity-reaches.test.ts +0 -57
  474. package/test/event-subjects.test.ts +0 -148
  475. package/test/event-time-column.test.ts +0 -67
  476. package/test/event-type-split.test.ts +0 -178
  477. package/test/external-resolver.test.ts +0 -177
  478. package/test/fact-scope-wiring.test.ts +0 -96
  479. package/test/fill-dedupe.test.ts +0 -59
  480. package/test/fill-loop.test.ts +0 -35
  481. package/test/first-envelope.test.ts +0 -153
  482. package/test/fold-gap-speaks.test.ts +0 -53
  483. package/test/fold-shift-dst.test.ts +0 -110
  484. package/test/forecast-metrics.test.ts +0 -157
  485. package/test/forecast-tuning.test.ts +0 -42
  486. package/test/gap-analytics.test.ts +0 -113
  487. package/test/generated-not-counted.test.ts +0 -99
  488. package/test/guard-roots.ts +0 -76
  489. package/test/home-in-area.test.ts +0 -90
  490. package/test/hook-address.test.ts +0 -28
  491. package/test/hook-rejected-shape.test.ts +0 -86
  492. package/test/hook-response-sum.test.ts +0 -193
  493. package/test/hook-sequence.test.ts +0 -333
  494. package/test/ingest-bench.test.ts +0 -70
  495. package/test/ingest-dedupe.test.ts +0 -56
  496. package/test/ingest-expected-quiet.test.ts +0 -111
  497. package/test/ingest-health-engine.test.ts +0 -248
  498. package/test/ingest-health-wiring.test.ts +0 -120
  499. package/test/ingest-health.test.ts +0 -306
  500. package/test/ingest-history.test.ts +0 -247
  501. package/test/ingest-idempotent.test.ts +0 -211
  502. package/test/ingest-reconcile-four-ways.test.ts +0 -97
  503. package/test/ingest-rules-header.test.ts +0 -100
  504. package/test/ingest-running-guard.test.ts +0 -136
  505. package/test/ingest-space.test.ts +0 -78
  506. package/test/ingest-window-rolls-unobserved.test.ts +0 -72
  507. package/test/ingest-wiring-guard.test.ts +0 -197
  508. package/test/instance-cache-lifecycle.test.ts +0 -110
  509. package/test/intake-mapping-parity.test.ts +0 -175
  510. package/test/integration-probes.test.ts +0 -103
  511. package/test/integration-runner.test.ts +0 -95
  512. package/test/item-ref.test.ts +0 -78
  513. package/test/journal-order-axis.test.ts +0 -80
  514. package/test/journal-read-discipline.test.ts +0 -186
  515. package/test/journal-retention.test.ts +0 -275
  516. package/test/journal-sort-axis.test.ts +0 -142
  517. package/test/journal-write-door.test.ts +0 -110
  518. package/test/journal-write-trend.test.ts +0 -115
  519. package/test/kernel-kind-guard.test.ts +0 -98
  520. package/test/knob-defaults.test.ts +0 -72
  521. package/test/kpi-baseline-db.test.ts +0 -216
  522. package/test/kpi-baseline.test.ts +0 -196
  523. package/test/kpi-fold.test.ts +0 -1456
  524. package/test/kpi-query-bench.test.ts +0 -130
  525. package/test/lens-own-places.test.ts +0 -50
  526. package/test/lineage-survives-restart.test.ts +0 -234
  527. package/test/live-cadence.test.ts +0 -170
  528. package/test/live-cursor-wiring.test.ts +0 -87
  529. package/test/live-feed-lease.test.ts +0 -63
  530. package/test/live-feed-registry.test.ts +0 -75
  531. package/test/live-kernel-facts.test.ts +0 -161
  532. package/test/live-mirror-parity.test.ts +0 -286
  533. package/test/load-meter.test.ts +0 -328
  534. package/test/local-declarations.test.ts +0 -662
  535. package/test/log-stamp.test.ts +0 -59
  536. package/test/loop-lag.test.ts +0 -82
  537. package/test/master-to-twin.test.ts +0 -279
  538. package/test/measured-yield.test.ts +0 -90
  539. package/test/merge-streams.test.ts +0 -70
  540. package/test/mirror-resumes-from-checkpoint.test.ts +0 -192
  541. package/test/model-basis.test.ts +0 -141
  542. package/test/model-gap.test.ts +0 -153
  543. package/test/model-refusal.test.ts +0 -75
  544. package/test/model-vocabulary.test.ts +0 -114
  545. package/test/move-space.test.ts +0 -149
  546. package/test/mutation-gate.test.ts +0 -122
  547. package/test/oee-accumulator.test.ts +0 -204
  548. package/test/oee-site-calendar.test.ts +0 -146
  549. package/test/open-doors.test.ts +0 -197
  550. package/test/operation-basis.test.ts +0 -127
  551. package/test/operational-vocabulary.test.ts +0 -108
  552. package/test/operations-capability-db.test.ts +0 -165
  553. package/test/order-and-transaction-split.test.ts +0 -107
  554. package/test/order-fold-host.test.ts +0 -112
  555. package/test/producer-guard.test.ts +0 -66
  556. package/test/project-structure-db.test.ts +0 -226
  557. package/test/projection-reaches-screen.test.ts +0 -277
  558. package/test/projection-reads-declared.test.ts +0 -109
  559. package/test/property-effects.test.ts +0 -128
  560. package/test/provenance-promotion.test.ts +0 -99
  561. package/test/read-failure-ledger.test.ts +0 -106
  562. package/test/read-failure-visible.test.ts +0 -145
  563. package/test/read-time.test.ts +0 -118
  564. package/test/reference-fill.test.ts +0 -235
  565. package/test/reference-grounding.test.ts +0 -70
  566. package/test/reference-hook.test.ts +0 -177
  567. package/test/reference-links.test.ts +0 -56
  568. package/test/reference-reconciliation.test.ts +0 -39
  569. package/test/registry-key-guard.test.ts +0 -80
  570. package/test/rejection-carries-event-id.test.ts +0 -101
  571. package/test/rename-twin.test.ts +0 -89
  572. package/test/resolve-ts-siblings.mjs +0 -52
  573. package/test/restart-policy.test.ts +0 -111
  574. package/test/resync-origin-site.test.ts +0 -83
  575. package/test/retry-plan.test.ts +0 -139
  576. package/test/revision-axis.test.ts +0 -110
  577. package/test/runtime-key.test.ts +0 -66
  578. package/test/save-intake-collision.test.ts +0 -91
  579. package/test/scale-twin-bench.test.ts +0 -103
  580. package/test/secrets-at-rest.test.ts +0 -135
  581. package/test/snapshot-freshness.test.ts +0 -60
  582. package/test/source-outcome-audit.test.ts +0 -104
  583. package/test/space-integrity.test.ts +0 -223
  584. package/test/space-representation.test.ts +0 -66
  585. package/test/space-scope-includes-stopped.test.ts +0 -55
  586. package/test/spec-coverage.test.ts +0 -113
  587. package/test/stage-path.test.ts +0 -95
  588. package/test/standard-coverage.test.ts +0 -148
  589. package/test/state-axes.test.ts +0 -74
  590. package/test/status-tally.test.ts +0 -55
  591. package/test/streamline-e2e.test.ts +0 -76
  592. package/test/structure-revision-db.test.ts +0 -315
  593. package/test/subject-fast-path.test.ts +0 -148
  594. package/test/subject-read-model.test.ts +0 -175
  595. package/test/sweep-dispatch.test.ts +0 -191
  596. package/test/tenant-registry-db.test.ts +0 -149
  597. package/test/time-range.test.ts +0 -152
  598. package/test/touched-items.test.ts +0 -61
  599. package/test/twin-audit.test.ts +0 -83
  600. package/test/twin-event-keys.test.ts +0 -193
  601. package/test/twin-model-item-db.test.ts +0 -319
  602. package/test/twin-model-parent-relation-db.test.ts +0 -125
  603. package/test/twin-model-tree-db.test.ts +0 -209
  604. package/test/twin-origin-resync.test.ts +0 -133
  605. package/test/twin-state-channel.test.ts +0 -111
  606. package/test/vocabulary-guard.test.ts +0 -43
  607. package/test/warm-start-seam.test.ts +0 -162
  608. package/test/warm-start.test.ts +0 -297
  609. package/test/withheld-door.test.ts +0 -95
  610. package/test/yield-loop.test.ts +0 -199
  611. package/tsconfig.json +0 -15
  612. package/tsconfig.shared.json +0 -23
  613. package/tsconfig.shared.tsbuildinfo +0 -1
  614. package/tsconfig.tsbuildinfo +0 -1
@@ -1,191 +0,0 @@
1
- /*
2
- * ★ **그물이 실제로 줍는가** — 배선.
3
- *
4
- * 판단은 순수 함수가 지킨다(`retry-plan.test.ts`). 여기서 보는 것은 **그 답이 실제 경로에 서
5
- * 있는가**다: 표를 읽었나, 어댑터를 불렀나, 시도 횟수와 다음 시각을 적었나, 한 조치가 터져도
6
- * 다음을 보나.
7
- *
8
- * 이 저장소에서 가장 자주 나는 결함이 「자리는 있고 길이 없다」이고, 오늘 하루 그 부류를 여러 번
9
- * 고쳤다. 그물이 그 부류로 나면 **승인된 조치가 조용히 안 나간다.**
10
- */
11
- import { test } from 'node:test'
12
- import assert from 'node:assert/strict'
13
-
14
- import { sweepPendingDispatch } from '../server/service/actuation/sweep-dispatch.js'
15
- import type { CommandStore, StoredCommand } from '../server/service/actuation/command-dispatcher.js'
16
-
17
- const DOMAIN = 'd-1'
18
- const AT = '2026-09-04T02:00:00.000Z'
19
-
20
- const cmd = (over: Partial<StoredCommand> = {}): StoredCommand =>
21
- ({
22
- id: 'cmd-1',
23
- instanceId: 'twin-a',
24
- kind: 'production.release',
25
- origin: 'rule',
26
- state: 'approved',
27
- reversible: false,
28
- /* 되돌릴 수 없는 조치는 **승인 기록**이 있어야 넘어간다(§`asApproved`) — 그 모양이 이것이다. */
29
- approval: { by: 'lead', at: AT },
30
- ...over
31
- }) as StoredCommand
32
-
33
- /**
34
- * 표 하나와 가짜 커넥터 — `save` 가 무엇을 적었는지 본다.
35
- *
36
- * 의존을 인자로 받는 서명이라 여기서 다 흉내낼 수 있다. 직접 부르는 서명이었을 때는 이 시험이
37
- * DB·모듈 부팅을 끌어와 아예 뜨지 않았다 — 그것이 이 파일을 그 모양으로 바꾼 이유다.
38
- */
39
- function bench(rows: StoredCommand[], over: Record<string, unknown> = {}) {
40
- const table = new Map(rows.map(r => [r.id, { ...r }]))
41
- const saves: StoredCommand[] = []
42
- const store: CommandStore = {
43
- load: async (_d, id) => (table.has(id) ? { ...table.get(id)! } : null),
44
- save: async (_d, c) => {
45
- saves.push({ ...c })
46
- table.set(c.id, { ...c })
47
- },
48
- pendingDispatch: async () => [...table.values()]
49
- } as any
50
-
51
- const calls: string[] = []
52
- const deps = {
53
- store,
54
- /* 어댑터가 늘 받아 준다 — 「집었나」를 보는 시험이라 저쪽 사정은 다른 파일이 지킨다. */
55
- actuate: async (c: any) => {
56
- calls.push(c.id)
57
- return { ok: true, ref: `WO-${c.id}` }
58
- },
59
- idempotent: async () => false,
60
- ...over
61
- } as any
62
- return { store, table, saves, deps, calls }
63
- }
64
-
65
- /* ── 첫 시도를 줍는다 ─────────────────────────────────────────────────────── */
66
-
67
- test('★ 승인만 되고 안 나간 것을 줍는다 — 승인 직후 발신이 놓친 그 창이다', async () => {
68
- const { table, deps, calls } = bench([cmd()])
69
-
70
- const report = await sweepPendingDispatch(DOMAIN, deps)
71
- /* 어댑터가 없으므로 `routeActuation` 이 거절한다 — 그래도 **집었다**는 것이 이 시험의 주제다. */
72
- assert.equal(report.seen, 1)
73
- assert.equal(table.get('cmd-1')!.state !== 'approved', true, '집지 않아 상태가 그대로다')
74
- })
75
-
76
- test('★ 시도 횟수와 다음 시각을 적는다 — 메모리에 두면 재기동에 사라진다', async () => {
77
- const { table, deps, calls } = bench([cmd()])
78
-
79
- await sweepPendingDispatch(DOMAIN, deps)
80
- const after = table.get('cmd-1')!
81
-
82
- assert.equal(after.attempts, 1, '첫 시도가 1로 적혀야 한다')
83
- assert.ok(after.nextAttemptAt, '다음 시각이 없으면 물러섬이 재기동에 사라진다')
84
- assert.ok(Date.parse(after.nextAttemptAt!) > Date.now(), '다음 시각이 과거다')
85
- })
86
-
87
- /* ── 집지 않는 것들 ───────────────────────────────────────────────────────── */
88
-
89
- test('★ 종착은 집지 않는다', async () => {
90
- const { saves, deps } = bench([cmd({ state: 'acked', attempts: 1 })])
91
-
92
- const report = await sweepPendingDispatch(DOMAIN, deps)
93
-
94
- assert.equal(report.dispatched, 0)
95
- assert.equal(report.skipped['not-dispatchable'], 1)
96
- assert.deepEqual(saves, [], '집지 않았는데 표를 고쳤다')
97
- })
98
-
99
- test('★ 어댑터가 다시 될 일인지 말하지 않았으면 집지 않는다 — 목록에 「모름」으로 남는다', async () => {
100
- const { deps, store } = bench([cmd({ state: 'failed', attempts: 1, error: '저쪽이 안 받았습니다' })])
101
-
102
- const report = await sweepPendingDispatch(DOMAIN, deps)
103
-
104
- assert.equal(report.skipped['outlook-unknown'], 1)
105
- assert.equal(report.dispatched, 0)
106
- })
107
-
108
- test('★ 멱등을 선언하지 않은 커넥터는 재시도하지 않는다', async () => {
109
- const { deps, store } = bench([cmd({ state: 'failed', attempts: 1, retry: 'again' })])
110
-
111
- const report = await sweepPendingDispatch(DOMAIN, deps)
112
-
113
- assert.equal(report.skipped['not-idempotent'], 1)
114
- })
115
-
116
- test('★ 영원히 안 될 것은 집지 않는다', async () => {
117
- const { deps, store } = bench([cmd({ state: 'failed', attempts: 1, retry: 'never' })])
118
-
119
- assert.equal((await sweepPendingDispatch(DOMAIN, deps)).skipped['never'], 1)
120
- })
121
-
122
- test('★ 물러섬이 안 끝났으면 기다린다', async () => {
123
- const later = new Date(Date.now() + 300_000).toISOString()
124
- const { saves, deps } = bench([cmd({ state: 'failed', attempts: 1, retry: 'again', nextAttemptAt: later })])
125
-
126
- const report = await sweepPendingDispatch(DOMAIN, deps)
127
-
128
- /* 멱등 선언이 없어 그쪽에서 먼저 걸린다 — 어느 이유든 **집지 않았고 표를 안 고쳤다**가 핵심이다. */
129
- assert.equal(report.dispatched, 0)
130
- assert.deepEqual(saves, [])
131
- })
132
-
133
- /* ── 저장소가 못 내면 아무것도 하지 않는다 ──────────────────────────────── */
134
-
135
- test('★ 대기 줄을 못 내는 저장소에서는 아무것도 하지 않는다 — 옛 거동이 깨지지 않게', async () => {
136
- const deps = { store: { load: async () => null, save: async () => {} }, actuate: async () => ({ ok: true }), idempotent: async () => false } as any
137
-
138
- const report = await sweepPendingDispatch(DOMAIN, deps)
139
-
140
- assert.deepEqual(report, { seen: 0, dispatched: 0, skipped: {} })
141
- })
142
-
143
- test('★ 표 읽기가 터져도 그물이 죽지 않는다', async () => {
144
- const deps = {
145
- store: {
146
- load: async () => null,
147
- save: async () => {},
148
- pendingDispatch: async () => {
149
- throw new Error('DB 가 없다')
150
- }
151
- },
152
- actuate: async () => ({ ok: true }),
153
- idempotent: async () => false
154
- } as any
155
-
156
- const report = await sweepPendingDispatch(DOMAIN, deps)
157
- assert.equal(report.seen, 0)
158
- })
159
-
160
- /* ── 한 조치가 터져도 다음을 본다 ───────────────────────────────────────── */
161
-
162
- test('★ 한 조치에서 터져도 다음 조치를 본다 — 그물이 한 건에 멈추면 뒤가 다 막힌다', async () => {
163
- const { deps, store } = bench([cmd({ id: 'a' }), cmd({ id: 'b' })])
164
- const original = store.save
165
- let first = true
166
- ;(store as any).save = async (d: string, c: StoredCommand) => {
167
- if (first) {
168
- first = false
169
- throw new Error('첫 저장이 터졌다')
170
- }
171
- return original!(d, c)
172
- }
173
-
174
- const report = await sweepPendingDispatch(DOMAIN, deps)
175
-
176
- assert.equal(report.seen, 2, '둘 다 읽었다')
177
- /* 하나가 터졌어도 바퀴가 끝났다 — 던지면 이 단정에 오지 못한다. */
178
- assert.ok(report.dispatched + Object.values(report.skipped).reduce((a, b) => a + b, 0) >= 1)
179
- })
180
-
181
- /* ── 한 바퀴 상한 ─────────────────────────────────────────────────────────── */
182
-
183
- test('★ 대기 줄이 커도 한 주기를 독차지하지 않는다', async () => {
184
- const many = Array.from({ length: 120 }, (_, i) => cmd({ id: `c-${i}`, state: 'acked', attempts: 1 }))
185
- const { deps, store } = bench(many)
186
-
187
- const report = await sweepPendingDispatch(DOMAIN, deps)
188
-
189
- assert.equal(report.seen, 120, '표는 다 읽는다')
190
- assert.equal(report.skipped['not-dispatchable'], 50, '한 바퀴에 보는 것은 상한까지다')
191
- })
@@ -1,149 +0,0 @@
1
- /*
2
- * ★ 두 테넌트가 **같은 인스턴스 id** 로 각자 돈다 — 실 DB로 경계를 넘어 본다.
3
- *
4
- * ── 계기 (2026-08-06 테넌트 격리 전수 확인) ──────────────────────────────────
5
- * 런타임 레지스트리가 `instanceId` 하나로 키를 잡고 있었다. 그런데 DB 유일성은 `[domain, instanceId]`
6
- * 이고 트윈의 정체성도 그쪽이다. **충돌은 이론이 아니다** — 레퍼런스 경로가 `instanceId` 로 레퍼런스
7
- * 소스 이름(`sap-ewm-1710`)을 쓰고, 벤더 시스템 이름은 테넌트가 공유하는 어휘다.
8
- *
9
- * 그때 무엇이 틀렸나: `start`/`startFromRegistry` 가 **남의 런타임을 돌려주고**, `ingestLive` 는 도메인을
10
- * 확인하지 않아 남의 커널에 이벤트를 적용할 수 있었고, 목록의 `running` 이 남의 런타임을 봤다.
11
- *
12
- * 이 결함은 **유닛으로는 안 잡힌다** — 두 테넌트가 실제로 등록되고 각자 기동해야 드러난다. 그래서
13
- * 실 엔티티 sqlite 스키마 + 빌드 산출물로 경계를 넘는다(`structure-revision-db.test.ts` 와 같은 하네스).
14
- * **소스를 고친 뒤에는 `npm run build:server` 를 먼저 돌려야 반영된다.**
15
- */
16
- import { test, before, after, afterEach } 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 { DataSource: TypeOrmDataSource } = req('typeorm')
27
-
28
- let ds: DataSource
29
- let alpha: string
30
- let beta: string
31
-
32
- /** 두 테넌트가 같은 벤더 시스템을 연결했을 때 실제로 생기는 id. */
33
- const SHARED_ID = 'sap-ewm-1710'
34
-
35
- const model = (): any => ({
36
- spaceId: 'shared-space',
37
- utcOffsetMinutes: 0,
38
- locations: [
39
- { id: 'dock-recv', type: 'dock', capacity: 100 },
40
- { id: 'bin-1', type: 'storage', capacity: 20 }
41
- ],
42
- equipment: [{ id: 'fk-1', kind: 'forklift', homeLocation: 'dock-recv' }]
43
- })
44
-
45
- before(async () => {
46
- ds = new TypeOrmDataSource({
47
- type: 'sqlite',
48
- database: ':memory:',
49
- synchronize: true,
50
- dropSchema: true,
51
- namingStrategy: new NamingStrategy(),
52
- entities: [...shellEntities, ...authEntities, ...twinEntities],
53
- logging: false
54
- })
55
- await ds.initialize()
56
- addDataSource('default', ds)
57
-
58
- const a = await ds.getRepository(Domain).save({ name: 'tenant-alpha', subdomain: 'tenant-alpha' } as any)
59
- const b = await ds.getRepository(Domain).save({ name: 'tenant-beta', subdomain: 'tenant-beta' } as any)
60
- alpha = a.id
61
- beta = b.id
62
-
63
- /* 두 테넌트가 **같은 id** 로 각자 프로비저닝한다 — DB 유일성이 `[domain, instanceId]` 라 허용된다. */
64
- await TwinEngine.provision(alpha, SHARED_ID, 'wms', model(), 'reset')
65
- await TwinEngine.provision(beta, SHARED_ID, 'wms', model(), 'reset')
66
- })
67
-
68
- /**
69
- * **스펙마다 반드시 멈춘다.** 남기면 두 가지가 따라온다: 틱 타이머 때문에 러너가 끝나지 않고, 틱이
70
- * 뒤늦게 오류를 내는 DB 쓰기가 teardown 이후에 도착해 `SQLITE_MISUSE` 로 스위트를 오염시킨다.
71
- */
72
- afterEach(async () => {
73
- await TwinEngine.stop(alpha, SHARED_ID).catch(() => {})
74
- await TwinEngine.stop(beta, SHARED_ID).catch(() => {})
75
- })
76
-
77
- after(async () => {
78
- /* 정지 직후에도 진행 중인 쓰기가 있을 수 있다 — 커넥션을 닫기 전에 가라앉힌다. */
79
- await new Promise(resolve => setTimeout(resolve, 120))
80
- await ds?.destroy()
81
- })
82
-
83
- test('두 테넌트가 같은 id 로 프로비저닝된다 — 서로를 막지 않는다', async () => {
84
- /* 예전에는 한쪽이 **떠 있으면** 다른 쪽 재프로비전이 "instance is running" 으로 막혔다(존재 노출). */
85
- const listA = await TwinEngine.list(alpha)
86
- const listB = await TwinEngine.list(beta)
87
-
88
- assert.equal(listA.filter((x: any) => x.instanceId === SHARED_ID).length, 1)
89
- assert.equal(listB.filter((x: any) => x.instanceId === SHARED_ID).length, 1)
90
- })
91
-
92
- test('한쪽만 기동하면 다른 쪽은 **정지한 것으로** 보인다 — 이 회귀가 핵심', async () => {
93
- await TwinEngine.startFromRegistry(alpha, SHARED_ID)
94
-
95
- assert.equal(TwinEngine.owns(alpha, SHARED_ID), true, 'alpha 는 자기 트윈을 갖는다')
96
- assert.equal(TwinEngine.owns(beta, SHARED_ID), false, 'beta 는 기동하지 않았다')
97
-
98
- /* 목록의 running 이 남의 런타임을 보면 안 된다 — 예전에는 beta 도 running: true 였다. */
99
- const rowA = (await TwinEngine.list(alpha)).find((x: any) => x.instanceId === SHARED_ID)
100
- const rowB = (await TwinEngine.list(beta)).find((x: any) => x.instanceId === SHARED_ID)
101
- assert.equal(rowA.running, true)
102
- assert.equal(rowB.running, false)
103
- })
104
-
105
- test('둘 다 기동하면 **서로 다른 런타임**이다 — 남의 것을 돌려받지 않는다', async () => {
106
- const rtA = await TwinEngine.startFromRegistry(alpha, SHARED_ID)
107
- const rtB = await TwinEngine.startFromRegistry(beta, SHARED_ID)
108
-
109
- /* 예전에는 두 번째 호출이 첫 번째의 런타임을 그대로 돌려줬다(조기 반환이 id 로만 찾았다). */
110
- assert.notEqual(rtA, rtB, '같은 객체를 돌려주면 두 테넌트가 한 커널을 공유한다')
111
- assert.notEqual(TwinEngine.kernel(alpha, SHARED_ID), TwinEngine.kernel(beta, SHARED_ID))
112
- assert.equal(rtA.domainId, alpha)
113
- assert.equal(rtB.domainId, beta)
114
- })
115
-
116
- test('접근자가 테넌트별로 답한다 — 커널·스냅샷·런타임', async () => {
117
- await TwinEngine.startFromRegistry(alpha, SHARED_ID)
118
- await TwinEngine.startFromRegistry(beta, SHARED_ID)
119
-
120
- for (const [who, other] of [
121
- [alpha, beta],
122
- [beta, alpha]
123
- ]) {
124
- assert.ok(TwinEngine.kernel(who, SHARED_ID), '자기 커널은 있다')
125
- assert.notEqual(TwinEngine.kernel(who, SHARED_ID), TwinEngine.kernel(other, SHARED_ID))
126
- assert.notEqual(TwinEngine.runtime(who, SHARED_ID), TwinEngine.runtime(other, SHARED_ID))
127
- }
128
- })
129
-
130
- test('한쪽을 정지해도 다른 쪽은 계속 동작한다 — 남의 런타임을 지우지 않는다', async () => {
131
- await TwinEngine.startFromRegistry(alpha, SHARED_ID)
132
- await TwinEngine.startFromRegistry(beta, SHARED_ID)
133
-
134
- await TwinEngine.stop(alpha, SHARED_ID)
135
-
136
- assert.equal(TwinEngine.owns(alpha, SHARED_ID), false, '정지한 쪽은 사라진다')
137
- assert.equal(TwinEngine.owns(beta, SHARED_ID), true, '남의 트윈은 그대로다')
138
- assert.ok(TwinEngine.kernel(beta, SHARED_ID), 'beta 커널이 살아 있다')
139
- })
140
-
141
- test('없는 테넌트로 물으면 아무것도 주지 않는다 — 추측한 id 로 새지 않는다', async () => {
142
- await TwinEngine.startFromRegistry(alpha, SHARED_ID)
143
- const stranger = '99999999-9999-9999-9999-999999999999'
144
-
145
- assert.equal(TwinEngine.owns(stranger, SHARED_ID), false)
146
- assert.equal(TwinEngine.kernel(stranger, SHARED_ID), undefined)
147
- assert.equal(TwinEngine.runtime(stranger, SHARED_ID), undefined)
148
- assert.equal(TwinEngine.metrics(stranger, SHARED_ID), null)
149
- })
@@ -1,152 +0,0 @@
1
- /*
2
- * ★ 시각축은 **두 수만 묻는다** — 저널을 다 읽어 오지 않는다.
3
- *
4
- * ── 무엇을 겪었나 (2026-08-20 실측) ─────────────────────────────────────────
5
- * `TwinEngine.timeRange` 는 공간의 인스턴스마다 `find()` 로 **행을 전부 엔티티로 하이드레이션**한 뒤
6
- * JS 에서 min/max 를 골랐다. 그런데 이 함수는 화면 상단의 컨텍스트 띠가 **4초마다** 부른다. 개발
7
- * 서버에서 `order-check` 한 트윈이 275,882행 · `payload` 131MB 였다 — 4초마다 그 JSON 을 전부 파싱했다.
8
- *
9
- * 결과: 프로세스 CPU 81~152%, 아무 일도 하지 않는 질의가 8~14초. JS 프로파일 상위가 TypeORM 의
10
- * `RelationIdLoader`·`RawSqlResultsToEntityTransformer`·`stringToSimpleJson` 이고 GC 가 16.7% 였다.
11
- * 트윈 틱(계기가 16%)도 저널 쓰기도 아니라 **이 읽기**였다.
12
- *
13
- * ── 이 시험이 지키는 것 ─────────────────────────────────────────────────────
14
- * ① 답이 맞다(공간의 모든 트윈에 걸친 min/max, 남의 공간은 안 섞인다)
15
- * ② 「없음」을 0 으로 떨어뜨리지 않는다(시각축이 1970년에서 시작하면 스크러버가 못 쓰게 된다)
16
- * ③ **행을 실어 오지 않는다** — 고친 방식이 되돌아가면(다시 `find()`) 답은 그대로 맞고 느려지기만
17
- * 하므로, 결과만 보는 시험으로는 회귀를 잡을 수 없다. 그래서 소스를 함께 본다.
18
- */
19
- import { test, before, after } from 'node:test'
20
- import assert from 'node:assert/strict'
21
- import { createRequire } from 'node:module'
22
- import { readFileSync } from 'node:fs'
23
- import type { DataSource } from 'typeorm'
24
-
25
- const req = createRequire(import.meta.url)
26
- const { NamingStrategy, addDataSource, entities: shellEntities, Domain } = req('@things-factory/shell')
27
- const { entities: authEntities } = req('@things-factory/auth-base')
28
- const { entities: twinEntities } = req('../dist-server/service/index.js')
29
- const { TwinEngine } = req('../dist-server/engine/index.js')
30
- const { TwinEvent } = req('../dist-server/service/twin-event/twin-event.js')
31
- const { TwinInstance } = req('../dist-server/service/twin-instance/twin-instance.js')
32
- const { DataSource: TypeOrmDataSource } = req('typeorm')
33
-
34
- let ds: DataSource
35
- let domainId: string
36
-
37
- const SPACE = 'space-yard'
38
- const OTHER_SPACE = 'space-elsewhere'
39
-
40
- /** 저널 행 하나 — 시각축이 보는 것은 `eventTime` 뿐이다. */
41
- async function event(instanceId: string, eventTime: string | null, revision: number): Promise<void> {
42
- await ds.getRepository(TwinEvent).save(
43
- ds.getRepository(TwinEvent).create({
44
- domain: { id: domainId } as any,
45
- instanceId,
46
- eventType: 'test.event',
47
- revision,
48
- eventTime: eventTime === null ? null : new Date(eventTime),
49
- payload: { note: 'x' }
50
- } as any)
51
- )
52
- }
53
-
54
- async function instance(instanceId: string, spaceId: string): Promise<void> {
55
- await ds.getRepository(TwinInstance).save(
56
- ds.getRepository(TwinInstance).create({
57
- domain: { id: domainId } as any,
58
- instanceId,
59
- spaceId,
60
- kind: 'yms',
61
- status: 'stopped',
62
- restartPolicy: 'reset',
63
- purpose: 'operational'
64
- } as any)
65
- )
66
- }
67
-
68
- before(async () => {
69
- ds = new TypeOrmDataSource({
70
- type: 'sqlite',
71
- database: ':memory:',
72
- synchronize: true,
73
- dropSchema: true,
74
- namingStrategy: new NamingStrategy(),
75
- entities: [...shellEntities, ...authEntities, ...twinEntities],
76
- logging: false
77
- })
78
- await ds.initialize()
79
- addDataSource('default', ds)
80
-
81
- const d = await ds.getRepository(Domain).save({ name: 'range-test', subdomain: 'range-test' } as any)
82
- domainId = d.id
83
- })
84
-
85
- after(async () => {
86
- await ds?.destroy()
87
- })
88
-
89
- test('공간의 여러 트윈에 걸쳐 가장 이른 것과 가장 늦은 것을 낸다', async () => {
90
- await instance('yard-a', SPACE)
91
- await instance('yard-b', SPACE)
92
-
93
- /* 가장 이른 것은 b 에, 가장 늦은 것은 a 에 있다 — 한 트윈만 보면 답이 틀린다. */
94
- await event('yard-a', '2026-03-01T00:00:00.000Z', 1)
95
- await event('yard-a', '2026-06-30T12:00:00.000Z', 2)
96
- await event('yard-b', '2026-01-15T09:00:00.000Z', 1)
97
-
98
- const r = await TwinEngine.timeRange(domainId, SPACE)
99
- assert.equal(r.minTime, '2026-01-15T09:00:00.000Z')
100
- assert.equal(r.maxTime, '2026-06-30T12:00:00.000Z')
101
- })
102
-
103
- test('다른 공간의 저널은 섞이지 않는다 — 시각축은 그 현장의 것이다', async () => {
104
- await instance('far-c', OTHER_SPACE)
105
- await event('far-c', '2020-01-01T00:00:00.000Z', 1)
106
- await event('far-c', '2030-01-01T00:00:00.000Z', 2)
107
-
108
- const r = await TwinEngine.timeRange(domainId, SPACE)
109
- assert.equal(r.minTime, '2026-01-15T09:00:00.000Z', '2020년이 새어 들어오지 않는다')
110
- assert.equal(r.maxTime, '2026-06-30T12:00:00.000Z', '2030년도 그렇다')
111
- })
112
-
113
- test('시각이 빈 행이 시각축을 1970년으로 끌어내리지 않는다', async () => {
114
- /* 옛 행에는 `eventTime` 이 없을 수 있다. 그것을 0 으로 읽으면 스크러버가 56년을 그린다. */
115
- await event('yard-a', null, 3)
116
-
117
- const r = await TwinEngine.timeRange(domainId, SPACE)
118
- assert.equal(r.minTime, '2026-01-15T09:00:00.000Z', '빈 시각은 「없음」이고 0 이 아니다')
119
- })
120
-
121
- test('이벤트가 없으면 「없음」이다 — 0 이나 지금이 아니다', async () => {
122
- await instance('empty-d', 'space-empty')
123
-
124
- const r = await TwinEngine.timeRange(domainId, 'space-empty')
125
- assert.equal(r.minTime, null)
126
- assert.equal(r.maxTime, null)
127
- })
128
-
129
- test('그 공간에 트윈이 없으면 「없음」이다', async () => {
130
- const r = await TwinEngine.timeRange(domainId, 'space-nobody')
131
- assert.equal(r.minTime, null)
132
- assert.equal(r.maxTime, null)
133
- })
134
-
135
- test('두 수를 구하려고 행을 실어 오지 않는다 — 되돌아가면 답은 맞고 느려지기만 한다', () => {
136
- /*
137
- * 결과만 보는 시험으로는 이 회귀를 잡을 수 없다(`find()` 로 돌려도 min/max 는 맞다). 그래서 함수의
138
- * 소스를 본다: 집계(MIN/MAX)를 쓰고, 저널을 `find()` 로 긁지 않는다.
139
- */
140
- const src = readFileSync(new URL('../server/engine/twin-engine.ts', import.meta.url).pathname, 'utf-8')
141
- const at = src.indexOf('static async timeRange(')
142
- assert.ok(at > 0, 'timeRange 를 찾지 못했다 — 이름이 바뀌면 이 검사도 함께 옮긴다')
143
-
144
- /* 함수 본문만 떼어 본다 — 다음 멤버 선언까지. */
145
- const body = src.slice(at, src.indexOf('\n /** 정지 훅', at) > 0 ? src.indexOf('\n /** 정지 훅', at) : at + 4000)
146
-
147
- assert.ok(body.includes("MIN(e.eventTime)") && body.includes("MAX(e.eventTime)"), '집계는 DB 가 한다')
148
- assert.ok(
149
- !/getRepository\(TwinEvent\)\s*\.?\s*\n?\s*\.find\(/.test(body),
150
- '저널을 행 단위로 실어 오면 안 된다 — 275,882행 · payload 131MB 를 4초마다 파싱했던 자리다'
151
- )
152
- })
@@ -1,61 +0,0 @@
1
- /*
2
- * 사건이 **어느 물품을 건드렸나** — 브로드캐스팅이 바뀐 것만 만들 수 있게 (2026-08-21).
3
- *
4
- * 이 판정이 틀리면 **화면이 낡는다.** 그래서 지키는 것을 값으로 못 박는다:
5
- * ① 개체를 말한 자리를 전부 읽는다 — 관측·집약(부모/자식)·변환(입력/출력).
6
- * ② 부류 수량만 말한 사건은 「모른다」다 — 그 부류의 어느 개체인지 말하지 않았다.
7
- * ③ 물품을 만지지 않는다고 **선언된** 사건은 빈 범위다(작업·설비·인원·자산·오더·품질·확인·에너지).
8
- * ④ 낯선 낱말은 「모른다」다 — 커널이 사건을 늘렸을 때 알리지 않고 빠뜨리지 않는다.
9
- *
10
- * 「모른다」(`null`)와 「하나도 없다」(빈 집합)는 **다른 사실**이다. 앞은 전부 다시 만들게 하고 뒤는
11
- * 물품을 건너뛰게 한다 — 둘을 같게 두면 둘 중 하나가 반드시 틀린다.
12
- */
13
- import { test } from 'node:test'
14
- import assert from 'node:assert/strict'
15
-
16
- import { touchedItemKeys } from '../shared/touched-items.ts'
17
-
18
- const epcis = (data: any) => ({ eventType: 'epcis.object', data })
19
-
20
- test('관측 사건은 말한 개체를 모두 낸다', () => {
21
- const got = touchedItemKeys(epcis({ epcList: ['urn:epc:id:sgtin:952.1.A', 'urn:epc:id:sgtin:952.1.B'] }))
22
- assert.deepEqual([...got!].sort(), ['urn:epc:id:sgtin:952.1.A', 'urn:epc:id:sgtin:952.1.B'])
23
- })
24
-
25
- test('집약은 부모와 자식을 함께 낸다 — 부모만 내면 팔레트에 담긴 것이 낡는다', () => {
26
- const got = touchedItemKeys({
27
- eventType: 'epcis.aggregation',
28
- data: { parentID: 'urn:epc:id:sscc:952.P1', childEPCs: ['urn:epc:id:sgtin:952.1.A'] }
29
- })
30
- assert.deepEqual([...got!].sort(), ['urn:epc:id:sgtin:952.1.A', 'urn:epc:id:sscc:952.P1'])
31
- })
32
-
33
- test('변환은 입력과 출력을 함께 낸다 — 소비된 것도 값이 바뀐다', () => {
34
- const got = touchedItemKeys({
35
- eventType: 'epcis.transformation',
36
- data: { inputEPCList: ['in-1', 'in-2'], outputEPCList: ['out-1'] }
37
- })
38
- assert.deepEqual([...got!].sort(), ['in-1', 'in-2', 'out-1'])
39
- })
40
-
41
- test('부류 수량만 말한 사건은 「모른다」다 — 그 부류의 어느 개체인지 말하지 않았다', () => {
42
- const got = touchedItemKeys(epcis({ quantityList: [{ epcClass: 'urn:epc:idpat:sgtin:952.1.*', quantity: 3 }] }))
43
- assert.equal(got, null, '개체를 특정하지 못하면 전부 다시 만들어야 한다')
44
- })
45
-
46
- test('물품을 만지지 않는다고 선언된 사건은 빈 범위다 — 전부 다시 만들 이유가 없다', () => {
47
- for (const eventType of ['task.status', 'equipment.status', 'person.status', 'asset.status', 'order.status', 'quality.output', 'attention.acked']) {
48
- const got = touchedItemKeys({ eventType, data: { taskId: 't1', moverId: 'fk-1' } })
49
- assert.ok(got, `${eventType} 은 「모른다」가 아니다`)
50
- assert.equal(got!.size, 0, `${eventType} 은 물품을 건드리지 않는다`)
51
- }
52
- const energy = touchedItemKeys({ eventType: 'energy.measured', data: { id: 'm-1', kW: 12 } })
53
- assert.equal(energy!.size, 0)
54
- })
55
-
56
- test('낯선 낱말은 「모른다」다 — 커널이 사건을 늘렸을 때 알리지 않고 빠뜨리지 않는다', () => {
57
- assert.equal(touchedItemKeys({ eventType: 'something.new', data: { epcList: ['x'] } }), null)
58
- assert.equal(touchedItemKeys({ data: { epcList: ['x'] } }), null, '낱말이 없으면 판정할 수 없다')
59
- assert.equal(touchedItemKeys(undefined), null)
60
- assert.equal(touchedItemKeys({ eventType: 'epcis.object' }), null, '내용이 없으면 판정할 수 없다')
61
- })
@@ -1,83 +0,0 @@
1
- /*
2
- * 커맨드 감사 기록 — 이 검사가 지키는 것은 **기록이 증명력을 갖는가** 다.
3
- *
4
- * 감사 기록의 가치는 "남아 있다" 가 아니라 "믿을 수 있다" 에 있다. 클라이언트가 보낸 신원을 그대로
5
- * 적으면 위조가 자유로워 아무것도 증명하지 못하고, 거절된 시도를 안 남기면 "무엇을 하려 했는가" 가
6
- * 사라진다. 그 둘이 이 파일의 핵심 검사다.
7
- */
8
- import { test } from 'node:test'
9
- import assert from 'node:assert/strict'
10
-
11
- import { buildCommandAudit, normalizeOrigin } from '../server/service/twin-audit/command-audit.ts'
12
-
13
- const AT = new Date('2026-08-06T12:00:00.000Z')
14
-
15
- test('명령 종류를 그대로 싣는다 — 무엇을 하려 했는지가 감사의 시작이다', () => {
16
- const row = buildCommandAudit({ command: { commandId: 'c1', type: 'order.hold' }, ack: { accepted: true }, at: AT })
17
- assert.equal(row.commandType, 'order.hold')
18
- assert.equal(row.commandId, 'c1')
19
- })
20
-
21
- test('신원은 서버가 준 것만 적는다 — 커맨드에 실려 온 신원 주장은 무시한다', () => {
22
- const row = buildCommandAudit({
23
- /* 위조 시도: 클라이언트가 자기를 관리자라고 주장한다. */
24
- command: { type: 'order.hold', actorId: 'admin', actorEmail: 'admin@corp', actorName: '관리자' },
25
- ack: { accepted: true },
26
- actor: { id: 'u-7', email: 'kim@corp', name: '김현장' },
27
- at: AT
28
- })
29
- assert.equal(row.actorId, 'u-7')
30
- assert.equal(row.actorEmail, 'kim@corp')
31
- assert.equal(row.actorName, '김현장')
32
- })
33
-
34
- test('세션에 사용자가 없으면 비운다 — 모르는 것을 지어내지 않는다', () => {
35
- const row = buildCommandAudit({ command: { type: 'order.hold' }, ack: { accepted: true }, at: AT })
36
- assert.equal(row.actorId, undefined)
37
- assert.equal(row.actorEmail, undefined)
38
- })
39
-
40
- test('커널이 거절한 시도도 남는다 — 무엇을 하려 했는지가 감사의 절반이다', () => {
41
- const row = buildCommandAudit({
42
- command: { type: 'equipment.repair', args: { id: 'cutter-1' } },
43
- ack: { accepted: false, errorCode: 'not-broken' },
44
- at: AT
45
- })
46
- assert.equal(row.accepted, false)
47
- assert.equal(row.errorCode, 'not-broken')
48
- assert.deepEqual(row.args, { id: 'cutter-1' })
49
- })
50
-
51
- test('출처는 아는 값만 — 모르면 unknown 이지 사람이 한 것으로 치지 않는다', () => {
52
- assert.equal(normalizeOrigin('ai'), 'ai')
53
- assert.equal(normalizeOrigin('user'), 'user')
54
- assert.equal(normalizeOrigin('automation'), 'automation')
55
- assert.equal(normalizeOrigin(undefined), 'unknown')
56
- assert.equal(normalizeOrigin('관리자승인'), 'unknown')
57
- })
58
-
59
- test('근거는 문자열일 때만 싣는다 — 객체를 그대로 넣어 화면이 [object Object] 를 띄우지 않게', () => {
60
- const ok = buildCommandAudit({ command: { type: 't', reason: '대기 15분 절감' }, ack: {}, at: AT })
61
- assert.equal(ok.reason, '대기 15분 절감')
62
- const bad = buildCommandAudit({ command: { type: 't', reason: { why: 'x' } }, ack: {}, at: AT })
63
- assert.equal(bad.reason, undefined)
64
- })
65
-
66
- test('args 가 지나치게 크면 자르되 잘랐다고 알린다 — 알리지 않고 버리지 않는다', () => {
67
- const huge = { blob: 'x'.repeat(9000) }
68
- const row = buildCommandAudit({ command: { type: 't', args: huge }, ack: {}, at: AT })
69
- assert.equal(row.argsTruncated, true)
70
- assert.equal(typeof row.args, 'string')
71
- assert.ok((row.args as string).length <= 4000)
72
- })
73
-
74
- test('작은 args 는 자르지 않고 원형 그대로 — 나중에 따질 수 있어야 한다', () => {
75
- const row = buildCommandAudit({ command: { type: 't', args: { id: 'a', qty: 3 } }, ack: {}, at: AT })
76
- assert.equal(row.argsTruncated, false)
77
- assert.deepEqual(row.args, { id: 'a', qty: 3 })
78
- })
79
-
80
- test('시각은 호출부가 준 서버 시각을 그대로 쓴다 — 클라이언트 시계를 믿지 않는다', () => {
81
- const row = buildCommandAudit({ command: { type: 't', eventTime: '1999-01-01T00:00:00.000Z' }, ack: {}, at: AT })
82
- assert.equal(row.eventTime.toISOString(), AT.toISOString())
83
- })