@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,411 +0,0 @@
1
- /*
2
- * **승인의 문은 한 벌이다** — 결재선에 올라간 조치는 여기서 결정되지 않는다.
3
- *
4
- * ── 무엇이 있었나 (2026-08-31) ───────────────────────────────────────────
5
- * 게이트를 세우고 승인 화면을 계획하다가 물었다 — 「무엇을 승인하는 화면인가」. 커맨드 행을 **적는
6
- * 코드가 하나도 없었다.** 대기 줄은 구조적으로 비어 있었다. 자리는 있고 길이 없는 그 부류다.
7
- *
8
- * 그것을 채우면서 문이 둘이 되었다: 이 패키지의 직접 결정과, 업무 목록(worklist)의 결재선. 문이 둘이면
9
- * 결재선에는 대기로 남아 있는데 조치는 이미 나간 상태가 만들어지고, 사고 뒤에 **어느 기록이 진짜인지**
10
- * 말할 수 없다.
11
- *
12
- * 그래서 규칙 하나: **결재선 자리가 적힌 커맨드는 결재선에서만 결정한다.** 이 시험이 그 규칙을 지킨다.
13
- */
14
- import { test } from 'node:test'
15
- import assert from 'node:assert/strict'
16
-
17
- import { CMD, MES_COMMANDS, type CommandTypeSpec } from '@operato/ops-contract'
18
-
19
- import {
20
- approve,
21
- dispatch,
22
- linkApproval,
23
- propose,
24
- reject,
25
- settleByApproval,
26
- type CommandStore,
27
- type StoredCommand
28
- } from '../server/service/actuation/command-dispatcher.js'
29
-
30
- const DOMAIN = 'd-1'
31
- const AT = '2026-08-31T02:00:00.000Z'
32
- const REF = 'activity-instance-1'
33
-
34
- /* MES 프로필의 선언을 그대로 쓴다 — 시험용 종류를 지어내면 선언과 어긋난 것을 시험이 통과시킨다. */
35
- const SPEC: readonly CommandTypeSpec[] = MES_COMMANDS
36
- const ORDER = MES_COMMANDS[0]!
37
- const PAYLOAD = { materialDefinitionId: 'urn:epc:idpat:sgtin:9521234.00001.*', quantity: 12, uom: 'EA' }
38
-
39
- const PROPOSER = 'line-lead@plant.example'
40
- const APPROVER = 'plant-manager@plant.example'
41
-
42
- const seed = (over: Partial<Parameters<typeof propose>[3]> = {}) => ({
43
- id: 'cmd-1',
44
- instanceId: 'twin-a',
45
- type: ORDER.type,
46
- origin: 'operator' as const,
47
- proposedBy: PROPOSER,
48
- proposedAt: AT,
49
- payload: PAYLOAD,
50
- ...over
51
- })
52
-
53
- /** 저장본 하나 — 프로세스가 아니라 여기 산다. 그래서 다시 세워도 남는다. */
54
- function makeStore(initial?: StoredCommand): CommandStore & { rows: Map<string, StoredCommand> } {
55
- const rows = new Map<string, StoredCommand>(initial ? [[initial.id, initial]] : [])
56
- const put = (command: StoredCommand) => {
57
- const copy: StoredCommand = JSON.parse(JSON.stringify(command))
58
- rows.set(copy.id, copy)
59
- return copy
60
- }
61
- return {
62
- rows,
63
- load: async (domainId, id) => (domainId === DOMAIN ? (rows.get(id) ?? null) : null),
64
- save: async (domainId, command) => {
65
- assert.equal(domainId, DOMAIN)
66
- put(command)
67
- },
68
- create: async (domainId, command) => {
69
- assert.equal(domainId, DOMAIN)
70
- if (rows.has(command.id)) throw new Error(`이미 있는 커맨드다 (${command.id})`)
71
- return put(command)
72
- }
73
- }
74
- }
75
-
76
- const ok = async (): Promise<{ ok: boolean; ref?: string }> => ({ ok: true, ref: 'JOB-1' })
77
-
78
- /* ── 낸다 ─────────────────────────────────────────────────────────────────── */
79
-
80
- test('★ 낸 조치가 대기 줄에 남는다 — 이 길이 없어 대기 줄이 비어 있었다', async () => {
81
- const store = makeStore()
82
- const command = await propose(store, DOMAIN, SPEC, seed())
83
-
84
- assert.equal(command.state, 'proposed')
85
- assert.equal(store.rows.size, 1, '행이 적히지 않았다')
86
- assert.equal(store.rows.get('cmd-1')!.type, ORDER.type)
87
- assert.equal(store.rows.get('cmd-1')!.payload.quantity, 12, '무엇을 지시하는지가 남지 않으면 승인할 근거가 없다')
88
- })
89
-
90
- test('★ 선언되지 않은 종류는 낼 수 없다 — 되돌릴 수 있는지 모르는 채로 게이트를 지나게 하지 않는다', async () => {
91
- const store = makeStore()
92
- await assert.rejects(propose(store, DOMAIN, SPEC, seed({ type: 'line.shutdown' })), /선언되지 않은 조치 종류/)
93
- assert.equal(store.rows.size, 0, '거절하면서 행을 적었다')
94
- })
95
-
96
- test('★ 요구하는 칸이 없으면 낼 수 없다 — 빈 지시가 대기 줄에 쌓이지 않게', async () => {
97
- const store = makeStore()
98
- await assert.rejects(propose(store, DOMAIN, SPEC, seed({ payload: { quantity: 12 } })), /요구하는 칸이 없다/)
99
- assert.equal(store.rows.size, 0)
100
- })
101
-
102
- test('선언이 「되돌릴 수 없다」이면 그대로 적힌다 — 낸 쪽이 정하지 않는다', async () => {
103
- const store = makeStore()
104
- const command = await propose(store, DOMAIN, SPEC, seed())
105
- assert.equal(command.reversible, ORDER.reversible)
106
- assert.equal(command.reversible, false, 'MES 생산 지시는 되돌릴 수 없다 — 취소해도 만든 것은 남는다')
107
- })
108
-
109
- /* ── 문은 한 벌이다 ───────────────────────────────────────────────────────── */
110
-
111
- test('★ 결재선에 올라간 조치는 여기서 승인되지 않는다', async () => {
112
- const store = makeStore()
113
- await propose(store, DOMAIN, SPEC, seed())
114
- await linkApproval(store, DOMAIN, 'cmd-1', REF)
115
-
116
- await assert.rejects(approve(store, DOMAIN, 'cmd-1', { by: APPROVER, at: AT }), /결재선에 올라가 있다/)
117
- await assert.rejects(reject(store, DOMAIN, 'cmd-1', { by: APPROVER, at: AT }), /결재선에 올라가 있다/)
118
- assert.equal(store.rows.get('cmd-1')!.state, 'proposed', '막았다면서 상태가 움직였다')
119
- })
120
-
121
- test('★ 결재선을 쓰지 않는 배포에서는 직접 결정이 유일한 문이다', async () => {
122
- const store = makeStore()
123
- await propose(store, DOMAIN, SPEC, seed())
124
-
125
- const approved = await approve(store, DOMAIN, 'cmd-1', { by: APPROVER, at: AT })
126
- assert.equal(approved.state, 'approved')
127
- assert.equal((await dispatch(store, DOMAIN, 'cmd-1', ok)).state, 'acked')
128
- })
129
-
130
- test('★ 올라가지 않은 커맨드에 결재선 판정을 옮기지 않는다 — 어디서 온 판정인지 알 수 없다', async () => {
131
- const store = makeStore()
132
- await propose(store, DOMAIN, SPEC, seed())
133
-
134
- await assert.rejects(
135
- settleByApproval(store, DOMAIN, 'cmd-1', { approvalRef: REF, approved: true, by: APPROVER, at: AT }),
136
- /결재선에 올라가지 않은/
137
- )
138
- })
139
-
140
- test('★ 다른 결재 건의 판정은 받지 않는다 — 옆 건의 승인으로 게이트가 열리지 않게', async () => {
141
- const store = makeStore()
142
- await propose(store, DOMAIN, SPEC, seed())
143
- await linkApproval(store, DOMAIN, 'cmd-1', REF)
144
-
145
- await assert.rejects(
146
- settleByApproval(store, DOMAIN, 'cmd-1', { approvalRef: 'activity-instance-9', approved: true, by: APPROVER, at: AT }),
147
- /다른 결재 건의 판정/
148
- )
149
- assert.equal(store.rows.get('cmd-1')!.state, 'proposed')
150
- })
151
-
152
- /* ── 결재선의 판정이 옮겨진다 ────────────────────────────────────────────── */
153
-
154
- test('★ 결재선이 승인하면 나갈 수 있다 — 누가 승인했는지가 커맨드에도 남는다', async () => {
155
- const store = makeStore()
156
- await propose(store, DOMAIN, SPEC, seed())
157
- await linkApproval(store, DOMAIN, 'cmd-1', REF)
158
-
159
- const approved = await settleByApproval(store, DOMAIN, 'cmd-1', {
160
- approvalRef: REF,
161
- approved: true,
162
- by: APPROVER,
163
- at: AT,
164
- note: '야간 물량 반영'
165
- })
166
-
167
- assert.equal(approved.state, 'approved')
168
- /* 커맨드 목록이 결재선을 조회하지 않고도 「누가 언제」를 보여야 한다. */
169
- assert.equal(store.rows.get('cmd-1')!.approval?.by, APPROVER)
170
- assert.equal(store.rows.get('cmd-1')!.approval?.note, '야간 물량 반영')
171
- assert.equal((await dispatch(store, DOMAIN, 'cmd-1', ok)).state, 'acked')
172
- })
173
-
174
- test('★ 결재선이 거절하면 커맨드는 거기서 닫힌다 — 뒤늦은 승인이 게이트를 열지 못한다', async () => {
175
- /*
176
- * 업무 목록에서 「거절」은 고쳐 다시 올리라는 뜻이지만, 조치에는 고칠 것이 없다 — 지시 내용은 제안될
177
- * 때 정해진다. 그래서 커맨드 쪽은 끝으로 다룬다. 그 뒤에 결재선에서 승인이 와도 계약이 막는다.
178
- */
179
- const store = makeStore()
180
- await propose(store, DOMAIN, SPEC, seed())
181
- await linkApproval(store, DOMAIN, 'cmd-1', REF)
182
-
183
- const rejected = await settleByApproval(store, DOMAIN, 'cmd-1', {
184
- approvalRef: REF,
185
- approved: false,
186
- by: APPROVER,
187
- at: AT,
188
- note: '그 라인은 정지 중이다'
189
- })
190
- assert.equal(rejected.state, 'rejected')
191
-
192
- await assert.rejects(
193
- settleByApproval(store, DOMAIN, 'cmd-1', { approvalRef: REF, approved: true, by: 'someone-else@plant.example', at: AT }),
194
- /승인할 수 없다|승인되지 않은|rejected/
195
- )
196
- await assert.rejects(dispatch(store, DOMAIN, 'cmd-1', ok))
197
- })
198
-
199
- /* ── 자극과 조치는 다른 어휘다 ───────────────────────────────────────────── */
200
-
201
- test('★ 커널 자극을 조치로 낼 수 없다 — 모델 안의 자극이 현장 지시가 되지 않게', async () => {
202
- /*
203
- * 계약에 어휘가 두 벌이다.
204
- *
205
- * CMD 커널 안에서 도는 자극. `resource.repair` = 모델에서 수리된 것으로 둔다
206
- * MES_COMMANDS 현장에 나가는 지시. `production.order` = 실제로 만든다
207
- *
208
- * 주의 신호가 권하는 것(`Attention.suggestedAction.command`)은 **앞엣것**이다. 주의를 읽어 조치를
209
- * 내는 코드를 쓰다 보면 그 값을 그대로 넘기게 된다 — 실제로 그러려다 멈췄다.
210
- */
211
- const store = makeStore()
212
- await assert.rejects(
213
- propose(store, DOMAIN, SPEC, seed({ type: CMD.resourceRepair })),
214
- /커널 안에서 도는 자극이다/
215
- )
216
- assert.equal(store.rows.size, 0)
217
- })
218
-
219
- test('★ 두 어휘가 겹치지 않는다 — 겹치면 어느 쪽으로 읽어야 할지 알 수 없다', () => {
220
- /*
221
- * 이 시험이 지키는 것은 앞의 거절이 **뜻을 갖는다**는 사실이다. 같은 문자열이 양쪽에 있으면 거절도
222
- * 통과도 옳지 않게 되고, 그때 위 시험은 초록인데 규칙은 사라진다.
223
- */
224
- const stimuli = new Set(Object.values(CMD) as string[])
225
- const overlap = MES_COMMANDS.map(s => s.type).filter(t => stimuli.has(t))
226
-
227
- assert.deepEqual(
228
- overlap,
229
- [],
230
- `자극과 조치에 같은 이름이 있다 (${overlap.join(', ')}) — 한 이름이 모델 상태를 바꾸기도 하고 현장에 나가기도 한다`
231
- )
232
- })
233
-
234
- /* ── 낸 사람도 자기 것을 승인한다 ───────────────────────────────────────── */
235
-
236
- /*
237
- * 낸 사람은 자기 조치를 승인하지 못한다는 규칙은 2026-10-23 사용자가 거두었다: 「twin 액추에이션
238
- * 커맨드의 자기 승인 금지도 걷어내라」(워크리스트의 상신자 규칙 ADR-0052 ② 와 함께). 결재선이 비어
239
- * 아무도 승인하지 않은 채 끝나는 길은 올리는 자리(operato-twin `approvalLineGap`)가 막는다.
240
- */
241
-
242
- test('★ 낸 사람이 자기 조치를 직접 승인한다', async () => {
243
- const store = makeStore()
244
- await propose(store, DOMAIN, SPEC, seed())
245
-
246
- assert.equal((await approve(store, DOMAIN, 'cmd-1', { by: PROPOSER, at: AT })).state, 'approved')
247
- })
248
-
249
- test('★ 결재선을 지나온 판정도 낸 사람의 승인을 받는다', async () => {
250
- const store = makeStore()
251
- await propose(store, DOMAIN, SPEC, seed())
252
- await linkApproval(store, DOMAIN, 'cmd-1', REF)
253
-
254
- await settleByApproval(store, DOMAIN, 'cmd-1', { approvalRef: REF, approved: true, by: PROPOSER, at: AT })
255
- assert.equal(store.rows.get('cmd-1')!.state, 'approved')
256
- })
257
-
258
- test('★ 낸 사람은 자기 것을 물릴 수 있다 — 거절에는 걸지 않는다', async () => {
259
- const store = makeStore()
260
- await propose(store, DOMAIN, SPEC, seed())
261
- const rejected = await reject(store, DOMAIN, 'cmd-1', { by: PROPOSER, at: AT, note: '잘못 냈다' })
262
- assert.equal(rejected.state, 'rejected')
263
- })
264
-
265
- test('★ 사람이 내는데 낸 사람이 없으면 받지 않는다 — 누가 냈는지 남아야 한다', async () => {
266
- const store = makeStore()
267
- await assert.rejects(propose(store, DOMAIN, SPEC, seed({ proposedBy: undefined })), /낸 사람이 있어야 한다/)
268
- assert.equal(store.rows.size, 0)
269
- })
270
-
271
- test('규칙·AI 가 낸 것은 낸 사람이 없다 — 사람이 아니다', async () => {
272
- const store = makeStore()
273
- const command = await propose(store, DOMAIN, SPEC, seed({ origin: 'rule', proposedBy: undefined }))
274
- assert.equal(command.proposedBy, undefined)
275
- /* 사람이 없으니 누구든 승인할 수 있다 — 그것이 이 경로의 뜻이다. */
276
- assert.equal((await approve(store, DOMAIN, 'cmd-1', { by: APPROVER, at: AT })).state, 'approved')
277
- })
278
-
279
- test('★ 낸 사람이 재기동을 넘어 산다 — 사고 뒤에 누가 냈는지 물을 자리다', async () => {
280
- const first = makeStore()
281
- await propose(first, DOMAIN, SPEC, seed())
282
- const saved: StoredCommand = JSON.parse(JSON.stringify(first.rows.get('cmd-1')))
283
-
284
- const second = makeStore(saved)
285
- assert.equal(second.rows.get('cmd-1')!.proposedBy, PROPOSER, '재기동에 낸 사람이 사라졌다')
286
- })
287
-
288
- test('★ 넘긴 뒤에도 낸 사람이 남는다 — 사고 뒤에 누가 냈는지 물을 자리다', async () => {
289
- const store = makeStore()
290
- await propose(store, DOMAIN, SPEC, seed())
291
- await approve(store, DOMAIN, 'cmd-1', { by: APPROVER, at: AT })
292
- const settled = await dispatch(store, DOMAIN, 'cmd-1', ok)
293
-
294
- assert.equal(settled.proposedBy, PROPOSER)
295
- assert.equal(store.rows.get('cmd-1')!.proposedBy, PROPOSER, '넘기는 사이에 낸 사람이 지워졌다')
296
- })
297
-
298
- /* ── 재기동 ───────────────────────────────────────────────────────────────── */
299
-
300
- test('★ 결재선 자리가 재기동을 넘어 산다 — 다시 세운 뒤 직접 결정이 열리면 우회로가 된다', async () => {
301
- const first = makeStore()
302
- await propose(first, DOMAIN, SPEC, seed())
303
- await linkApproval(first, DOMAIN, 'cmd-1', REF)
304
-
305
- /* 프로세스가 새로 선 것으로 본다 — 앞의 저장소 객체는 버리고 저장본만 물려준다. */
306
- const saved: StoredCommand = JSON.parse(JSON.stringify(first.rows.get('cmd-1')))
307
- const second = makeStore(saved)
308
-
309
- assert.equal(second.rows.get('cmd-1')!.approvalRef, REF, '재기동에 결재선 자리가 사라졌다')
310
- await assert.rejects(approve(second, DOMAIN, 'cmd-1', { by: APPROVER, at: AT }), /결재선에 올라가 있다/)
311
-
312
- const approved = await settleByApproval(second, DOMAIN, 'cmd-1', {
313
- approvalRef: REF,
314
- approved: true,
315
- by: APPROVER,
316
- at: AT
317
- })
318
- assert.equal(approved.state, 'approved')
319
- })
320
-
321
- test('★ 넘긴 뒤에도 결재선 자리가 남는다 — 사고 뒤에 어느 결재로 나갔는지 물을 자리다', async () => {
322
- const store = makeStore()
323
- await propose(store, DOMAIN, SPEC, seed())
324
- await linkApproval(store, DOMAIN, 'cmd-1', REF)
325
- await settleByApproval(store, DOMAIN, 'cmd-1', { approvalRef: REF, approved: true, by: APPROVER, at: AT })
326
-
327
- const settled = await dispatch(store, DOMAIN, 'cmd-1', ok)
328
- assert.equal(settled.state, 'acked')
329
- assert.equal(settled.approvalRef, REF)
330
- assert.equal(store.rows.get('cmd-1')!.approvalRef, REF, '넘기는 사이에 결재선 자리가 지워졌다')
331
- })
332
-
333
- /* ── 받아들였으나 남은 것이 있다 ────────────────────────────────────────────── */
334
-
335
- test('★ 저쪽이 덧붙인 말은 실패가 아니다 — 두 답이 구별되어야 한다', async () => {
336
- /*
337
- * 실측(2026-09-02): MES 에 조치 둘을 넘겼더니 트윈 쪽 두 행이 완전히 같았다. 하나는 지시서가
338
- * 붙었고 하나는 안 붙었는데 `state`·`dispatch_ref`·`error` 가 셋 다 같았다. 화면은 둘 다
339
- * 「나갔다」로 읽는다.
340
- */
341
- const store = makeStore()
342
- await propose(store, DOMAIN, SPEC, seed())
343
- await approve(store, DOMAIN, 'cmd-1', { by: APPROVER, at: AT })
344
-
345
- const out = await dispatch(store, DOMAIN, 'cmd-1', async () => ({
346
- ok: true,
347
- ref: 'WO-005',
348
- note: '지시서가 붙지 않았습니다 — 사람이 MES 에서 골라야 합니다'
349
- }))
350
-
351
- assert.equal(out.state, 'acked', '덧붙인 말이 있는 것을 실패로 앉혔다')
352
- assert.equal(out.dispatchRef, 'WO-005')
353
- assert.match(out.dispatchNote!, /지시서가 붙지 않았습니다/)
354
- assert.equal(out.error, undefined, '덧붙인 말을 오류 칸에 적었다')
355
- })
356
-
357
- test('덧붙인 말이 없으면 그 칸은 비어 있다 — 빈 문장을 만들지 않는다', async () => {
358
- const store = makeStore()
359
- await propose(store, DOMAIN, SPEC, seed())
360
- await approve(store, DOMAIN, 'cmd-1', { by: APPROVER, at: AT })
361
-
362
- const out = await dispatch(store, DOMAIN, 'cmd-1', async () => ({ ok: true, ref: 'WO-004' }))
363
-
364
- assert.equal(out.state, 'acked')
365
- assert.equal(out.dispatchNote, undefined)
366
- })
367
-
368
- /* ── 다시 넘길 때 지난 시도의 자국을 지운다 ────────────────────────────────── */
369
-
370
- test('★ 다시 넘겨 성공하면 지난 실패의 오류가 남지 않는다 — 한 행이 두 가지를 말하면 안 된다', async () => {
371
- /*
372
- * 실측(2026-09-03): `failed → dispatch` 로 다시 넘겨 성공했는데 지난 실패의 `error` 가 그대로
373
- * 남아, 한 행이 「받았다(acked)」와 「저쪽이 안 받는다」를 동시에 말했다. 화면이 그 행을 그리면
374
- * 어느 쪽을 믿어야 하는지 알 수 없다.
375
- */
376
- const store = makeStore()
377
- await propose(store, DOMAIN, SPEC, seed())
378
- await approve(store, DOMAIN, 'cmd-1', { by: APPROVER, at: AT })
379
-
380
- const failed = await dispatch(store, DOMAIN, 'cmd-1', async () => ({ ok: false, error: '저쪽에 비밀값이 없습니다' }))
381
- assert.equal(failed.state, 'failed')
382
- assert.match(failed.error!, /비밀값/)
383
-
384
- const retried = await dispatch(store, DOMAIN, 'cmd-1', async () => ({ ok: true, ref: 'WO-001' }))
385
- assert.equal(retried.state, 'acked')
386
- assert.equal(retried.dispatchRef, 'WO-001')
387
- assert.equal(retried.error, undefined, '지난 실패의 오류가 성공한 행에 남았다')
388
- })
389
-
390
- test('★ 다시 넘겨 덧붙일 말이 없으면 옛 말이 남지 않는다 — 오류와 같은 부류다', async () => {
391
- const store = makeStore()
392
- await propose(store, DOMAIN, SPEC, seed())
393
- await approve(store, DOMAIN, 'cmd-1', { by: APPROVER, at: AT })
394
-
395
- /* 한 번 실패하면서 덧붙인 말이 남을 수 있는 자리를 만든다. */
396
- await dispatch(store, DOMAIN, 'cmd-1', async () => ({ ok: true, ref: 'WO-1', note: '지시서를 골라야 합니다' }))
397
-
398
- /* `acked` 는 종착이라 다시 넘길 수 없다 — 그 사실을 함께 못 박는다. */
399
- await assert.rejects(() => dispatch(store, DOMAIN, 'cmd-1', async () => ({ ok: true, ref: 'WO-2' })), /넘길 수 없다/)
400
- })
401
-
402
- test('★ 다시 넘기다 또 실패하면 이번 사유만 남는다', async () => {
403
- const store = makeStore()
404
- await propose(store, DOMAIN, SPEC, seed())
405
- await approve(store, DOMAIN, 'cmd-1', { by: APPROVER, at: AT })
406
-
407
- await dispatch(store, DOMAIN, 'cmd-1', async () => ({ ok: false, error: '첫 번째 사유' }))
408
- const again = await dispatch(store, DOMAIN, 'cmd-1', async () => ({ ok: false, error: '두 번째 사유' }))
409
-
410
- assert.equal(again.error, '두 번째 사유', '두 사유가 겹쳐 남았다')
411
- })
@@ -1,209 +0,0 @@
1
- /*
2
- * **승인을 지나지 않은 조치는 현장에 나가지 못한다** — 배선.
3
- *
4
- * ── 왜 배선을 따로 보나 (2026-08-31) ─────────────────────────────────────
5
- * 승인 판정 자체는 계약이 지킨다(`ops-contract/test/actuation-gate.test.ts`). 여기서 보는 것은
6
- * **그 판정이 실제 경로에 서 있는가**다 — 어댑터가 불렸는가, 상태가 적혔는가, 다시 세운 뒤에도 승인이
7
- * 남아 있는가.
8
- *
9
- * 이 저장소에서 가장 자주 나는 결함이 「자리는 있고 길이 없다」이고, 게이트가 그 부류로 나면 결과가
10
- * 현장의 작업지시다. 그래서 마지막 시험이 **저장본만 남기고 다시 세운다.**
11
- */
12
- import { test } from 'node:test'
13
- import assert from 'node:assert/strict'
14
-
15
- import type { TwinCommand } from '@operato/ops-contract'
16
-
17
- import {
18
- approve,
19
- dispatch,
20
- reject,
21
- type CommandAck,
22
- type CommandStore,
23
- type StoredCommand
24
- } from '../server/service/actuation/command-dispatcher.js'
25
-
26
- const DOMAIN = 'd-1'
27
- const AT = '2026-08-31T02:00:00.000Z'
28
- const APPROVAL = { by: 'line-lead', at: AT }
29
-
30
- const irreversible = (over: Partial<TwinCommand> = {}): TwinCommand => ({
31
- id: 'cmd-1',
32
- instanceId: 'twin-a',
33
- type: 'order.hold',
34
- origin: 'ai',
35
- proposedAt: AT,
36
- state: 'proposed',
37
- ...over
38
- })
39
-
40
- /** 저장본 하나 — 프로세스가 아니라 여기 산다. 그래서 다시 세워도 남는다. */
41
- function makeStore(initial: StoredCommand): CommandStore & { rows: Map<string, StoredCommand> } {
42
- const rows = new Map<string, StoredCommand>([[initial.id, initial]])
43
- return {
44
- rows,
45
- load: async (domainId, id) => (domainId === DOMAIN ? (rows.get(id) ?? null) : null),
46
- /* 저장소를 흉내 내는 것이라 복사해 넣는다 — 같은 객체면 안 적혀도 통과한다. */
47
- save: async (domainId, command) => {
48
- assert.equal(domainId, DOMAIN)
49
- rows.set(command.id, JSON.parse(JSON.stringify(command)))
50
- },
51
- create: async (domainId, command) => {
52
- assert.equal(domainId, DOMAIN)
53
- const copy = JSON.parse(JSON.stringify(command))
54
- rows.set(command.id, copy)
55
- return copy
56
- }
57
- }
58
- }
59
-
60
- const ok = (ref = 'JOB-1') => async (): Promise<CommandAck> => ({ ok: true, ref })
61
-
62
- /* ── 승인 없이는 나가지 못한다 ────────────────────────────────────────────── */
63
-
64
- test('★ 승인하지 않은 조치는 어댑터에 닿지 않는다', async () => {
65
- const store = makeStore(irreversible())
66
- let called = false
67
-
68
- await assert.rejects(
69
- dispatch(store, DOMAIN, 'cmd-1', async () => {
70
- called = true
71
- return { ok: true }
72
- }),
73
- /승인되지 않은/
74
- )
75
- assert.equal(called, false, '어댑터가 불렸다 — 게이트가 서지 않았다')
76
- assert.equal(store.rows.get('cmd-1')!.state, 'proposed', '상태가 움직였다')
77
- })
78
-
79
- test('★ 상태만 approved 로 적고 승인 기록이 없으면 막는다 — 저장본을 손으로 고쳐도 열리지 않는다', async () => {
80
- const store = makeStore(irreversible({ state: 'approved' }))
81
- let called = false
82
- await assert.rejects(
83
- dispatch(store, DOMAIN, 'cmd-1', async () => {
84
- called = true
85
- return { ok: true }
86
- }),
87
- /승인 기록이 없는/
88
- )
89
- assert.equal(called, false)
90
- })
91
-
92
- test('★ 승인하면 나간다 — 어댑터가 돌려준 것이 남는다', async () => {
93
- const store = makeStore(irreversible())
94
- await approve(store, DOMAIN, 'cmd-1', APPROVAL)
95
- const settled = await dispatch(store, DOMAIN, 'cmd-1', ok('JOB-77'))
96
-
97
- assert.equal(settled.state, 'acked')
98
- assert.equal(settled.dispatchRef, 'JOB-77', '되돌릴 때 무엇을 되돌릴지 말할 수 없게 된다')
99
- assert.equal(store.rows.get('cmd-1')!.approval?.by, 'line-lead')
100
- })
101
-
102
- test('★ 넘기기 전에 「넘기는 중」을 먼저 적는다 — 그 사이에 죽으면 현장이 두 번 움직인다', async () => {
103
- const store = makeStore(irreversible())
104
- await approve(store, DOMAIN, 'cmd-1', APPROVAL)
105
-
106
- let seenWhileDispatching: string | undefined
107
- await dispatch(store, DOMAIN, 'cmd-1', async () => {
108
- seenWhileDispatching = store.rows.get('cmd-1')!.state
109
- return { ok: true, ref: 'x' }
110
- })
111
- assert.equal(seenWhileDispatching, 'dispatched', '어댑터를 부르는 동안 저장본이 아직 approved 였다')
112
- })
113
-
114
- /* ── 되돌릴 수 있는 것의 다른 문 ─────────────────────────────────────────── */
115
-
116
- test('★ 되돌릴 수 있는 조치는 사람 없이 지난다 — 시뮬과 what-if 가 이 길이다', async () => {
117
- const store = makeStore(irreversible({ reversible: true }))
118
- const settled = await dispatch(store, DOMAIN, 'cmd-1', ok())
119
- assert.equal(settled.state, 'acked')
120
- })
121
-
122
- test('★ 되돌릴 수 있다고 적지 않은 것은 그 문으로 못 간다 — 모름을 통과로 읽지 않는다', async () => {
123
- const store = makeStore(irreversible({ reversible: false }))
124
- await assert.rejects(dispatch(store, DOMAIN, 'cmd-1', ok()))
125
- })
126
-
127
- /* ── 실패와 되풀이 ────────────────────────────────────────────────────────── */
128
-
129
- test('★ 어댑터가 던지면 실패로 남고 이유가 적힌다', async () => {
130
- const store = makeStore(irreversible())
131
- await approve(store, DOMAIN, 'cmd-1', APPROVAL)
132
- const settled = await dispatch(store, DOMAIN, 'cmd-1', async () => {
133
- throw new Error('MES 가 응답하지 않는다')
134
- })
135
-
136
- assert.equal(settled.state, 'failed')
137
- assert.match(String(settled.error), /응답하지 않는다/)
138
- })
139
-
140
- test('어댑터가 이유 없이 실패해도 빈 칸으로 두지 않는다', async () => {
141
- const store = makeStore(irreversible())
142
- await approve(store, DOMAIN, 'cmd-1', APPROVAL)
143
- const settled = await dispatch(store, DOMAIN, 'cmd-1', async () => ({ ok: false }))
144
- assert.ok(String(settled.error).length > 0)
145
- })
146
-
147
- test('★ 실패한 것은 다시 넘길 수 있다 — 승인을 다시 받지 않는다', async () => {
148
- const store = makeStore(irreversible())
149
- await approve(store, DOMAIN, 'cmd-1', APPROVAL)
150
- await dispatch(store, DOMAIN, 'cmd-1', async () => ({ ok: false, error: '잠시 끊겼다' }))
151
-
152
- const retried = await dispatch(store, DOMAIN, 'cmd-1', ok('JOB-9'))
153
- assert.equal(retried.state, 'acked')
154
- assert.equal(retried.dispatchRef, 'JOB-9')
155
- })
156
-
157
- test('★ 이미 답을 받은 것은 다시 나가지 않는다 — 두 번 나가면 현장이 두 번 움직인다', async () => {
158
- const store = makeStore(irreversible())
159
- await approve(store, DOMAIN, 'cmd-1', APPROVAL)
160
- await dispatch(store, DOMAIN, 'cmd-1', ok())
161
-
162
- await assert.rejects(dispatch(store, DOMAIN, 'cmd-1', ok()), /넘길 수 없다/)
163
- })
164
-
165
- /* ── 거절 ─────────────────────────────────────────────────────────────────── */
166
-
167
- test('★ 거절하면 끝이다 — 되살아나지 않는다', async () => {
168
- const store = makeStore(irreversible())
169
- await reject(store, DOMAIN, 'cmd-1', { by: 'line-lead', at: AT, note: '지금 그 라인은 정지 중' })
170
-
171
- assert.equal(store.rows.get('cmd-1')!.state, 'rejected')
172
- await assert.rejects(approve(store, DOMAIN, 'cmd-1', APPROVAL))
173
- await assert.rejects(dispatch(store, DOMAIN, 'cmd-1', ok()))
174
- })
175
-
176
- test('승인을 기다리는 중에도 거절할 수 있다', async () => {
177
- const store = makeStore(irreversible())
178
- await approve(store, DOMAIN, 'cmd-1', APPROVAL)
179
- await reject(store, DOMAIN, 'cmd-1', { by: 'plant-manager', at: AT })
180
- assert.equal(store.rows.get('cmd-1')!.state, 'rejected')
181
- })
182
-
183
- /* ── 재기동 ───────────────────────────────────────────────────────────────── */
184
-
185
- test('★ 승인이 재기동을 넘어 산다 — 사람이 승인한 것이 사라지면 안 된다', async () => {
186
- const first = makeStore(irreversible())
187
- await approve(first, DOMAIN, 'cmd-1', APPROVAL)
188
- const saved: TwinCommand = JSON.parse(JSON.stringify(first.rows.get('cmd-1')))
189
-
190
- /* 프로세스가 새로 선 것으로 본다 — 앞의 저장소 객체는 버리고 저장본만 물려준다. */
191
- const second = makeStore(saved)
192
- const settled = await dispatch(second, DOMAIN, 'cmd-1', ok('JOB-3'))
193
-
194
- assert.equal(settled.state, 'acked', '이어받지 못하면 승인이 사라져 던진다')
195
- assert.equal(settled.approval?.by, 'line-lead')
196
- })
197
-
198
- test('★ 재기동이 게이트를 열지 않는다 — 되세운 것도 같은 문을 지난다', async () => {
199
- /* JSON 에는 승인 표식이 없다. 되세울 때 표식을 그냥 붙이면 재기동이 곧 우회로가 된다. */
200
- const saved: TwinCommand = JSON.parse(JSON.stringify(irreversible()))
201
- const store = makeStore(saved)
202
- await assert.rejects(dispatch(store, DOMAIN, 'cmd-1', ok()), /승인되지 않은/)
203
- })
204
-
205
- test('모르는 커맨드는 조용히 넘어가지 않는다', async () => {
206
- const store = makeStore(irreversible())
207
- await assert.rejects(dispatch(store, DOMAIN, 'nope', ok()), /모르는 커맨드/)
208
- await assert.rejects(approve(store, DOMAIN, 'nope', APPROVAL), /모르는 커맨드/)
209
- })