@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,193 +0,0 @@
1
- /*
2
- * ★ 저널 검색 키 승격 검증 — payload(JSON) 안의 값을 인덱스 가능한 실컬럼으로 꺼내는 규칙.
3
- *
4
- * 이 규칙이 틀리면 "저널에는 있는데 검색으로는 안 나오는 이벤트" 가 생긴다. 화면에서는 그냥
5
- * **없는 것으로 보인다** — 저널에서 가장 나쁜 결함이라 규칙을 테스트로 고정한다.
6
- */
7
- import { test } from 'node:test'
8
- import assert from 'node:assert/strict'
9
-
10
- /*
11
- * **빌드 산출물을 부른다** — 이 모듈은 로그 문(`engine/log.js`)을 값으로 참조하고, 타입만 지우고 소스를
12
- * 실행하는 방식은 그 `.js` 경로를 `.ts` 로 바꿔 주지 않는다. 소스를 부르면 「모듈을 찾을 수 없다」로 선다.
13
- * **소스를 고친 뒤에는 `npm run build:server` 를 먼저 돌린다.**
14
- */
15
- import { createRequire } from 'node:module'
16
-
17
- const req = createRequire(import.meta.url)
18
- const { bizStepOf, epcOf, orderOf, bizTransactionOf, locationOf, equipmentIdOf, twinEventKeys } = req('../dist-server/service/twin-event/twin-event-keys.js')
19
-
20
- /** EPCIS ObjectEvent 한 건(입고) — 실제 인제스트가 싣는 모양. */
21
- const EPCIS_OBJECT = {
22
- eventType: 'epcis.ObjectEvent',
23
- eventTime: '2026-07-31T02:10:00.000Z',
24
- data: {
25
- bizStep: 'urn:epcglobal:cbv:bizstep:receiving',
26
- disposition: 'urn:epcglobal:cbv:disp:in_progress',
27
- epcList: ['urn:epc:id:sgtin:0614141.107346.2018'],
28
- readPoint: { id: 'urn:epc:id:sgln:0614141.00777.DOCK-3' },
29
- bizLocation: { id: 'urn:epc:id:sgln:0614141.00888.0' },
30
- bizTransactionList: [{ type: 'urn:epcglobal:cbv:btt:po', bizTransaction: 'urn:epc:id:gdti:0614141.402.2' }]
31
- }
32
- }
33
-
34
- test('EPCIS 이벤트에서 축이 모두 뽑히고, 거래는 거래 칸에 든다', () => {
35
- const k = twinEventKeys(EPCIS_OBJECT)
36
- assert.equal(k.bizStep, 'receiving')
37
- assert.equal(k.epc, 'urn:epc:id:sgtin:0614141.107346.2018')
38
- assert.equal(k.locationId, 'urn:epc:id:sgln:0614141.00777.DOCK-3')
39
- /*
40
- * ── 이 기대가 옮겨졌다 (2026-09-05 사용자 결정) ────────────────────────────
41
- * 전에는 이 GDTI 가 `orderId` 로 뽑혔다. 그래서 한 오더의 이력이 색인 안에서 두 쪽으로
42
- * 갈라졌다 — 운영 델타는 `order-1`, EPCIS 는 GDTI. 이제 칸이 둘이다.
43
- */
44
- assert.equal(k.bizTransaction, 'urn:epc:id:gdti:0614141.402.2')
45
- assert.equal(k.orderId, undefined, '거래 식별자가 오더 칸에 앉았다')
46
- })
47
-
48
- test('식별자는 끝마디가 아니라 전체를 저장한다 — 부분일치 검색이 양방향으로 성립해야 한다', () => {
49
- const k = twinEventKeys(EPCIS_OBJECT)
50
- /* 화면은 '2018' 로 축약해 보여주지만 색인은 원본을 갖는다. contains 검색이라
51
- * 끝마디로도 URN 전체로도 찾힌다 — 끝마디만 저장하면 URN 경로가 사라진다. */
52
- assert.ok(k.epc!.includes('2018'), '끝마디로 찾을 수 있어야 한다')
53
- assert.ok(k.epc!.startsWith('urn:epc:id:sgtin'), 'URN 전체로도 찾을 수 있어야 한다')
54
- })
55
-
56
- test('readPoint 가 없으면 bizLocation 으로 내려간다', () => {
57
- const ev = { ...EPCIS_OBJECT, data: { ...EPCIS_OBJECT.data, readPoint: undefined } }
58
- assert.equal(locationOf(ev), 'urn:epc:id:sgln:0614141.00888.0')
59
- })
60
-
61
- test('bizStep 이 없으면 이벤트 타입에서 유추한다 — 운영 델타도 단계를 말할 수 있어야 한다', () => {
62
- assert.equal(bizStepOf({ eventType: 'task.status', data: { task: 't1' } }), 'task.status')
63
- assert.equal(bizStepOf({ eventType: 'epcis.AggregationEvent', data: {} }), 'AggregationEvent')
64
- })
65
-
66
- test('a private business step is indexed by its short name, like a CBV one', () => {
67
- /* `split(':')` on `https://hatiolab.com/voc/bizstep/consuming` kept `//hatiolab.com/voc/bizstep/consuming` — a journal
68
- search for `consuming` found nothing. The rule is the contract's bizStepName. */
69
- assert.equal(bizStepOf({ data: { bizStep: 'https://hatiolab.com/voc/bizstep/consuming' } }), 'consuming')
70
- assert.equal(bizStepOf({ data: { bizStep: 'urn:epcglobal:cbv:bizstep:shipping' } }), 'shipping')
71
- })
72
-
73
- test('집합 이벤트는 parentID 를, 수량 이벤트는 epcClass 를 품목으로 쓴다', () => {
74
- assert.equal(epcOf({ data: { parentID: 'urn:epc:id:sscc:0614141.1234567890' } }), 'urn:epc:id:sscc:0614141.1234567890')
75
- assert.equal(epcOf({ data: { quantityList: [{ epcClass: 'urn:epc:idpat:sgtin:0614141.107346.*', quantity: 40 }] } }), 'urn:epc:idpat:sgtin:0614141.107346.*')
76
- })
77
-
78
- test('★ 운영 델타의 오더는 `orderId` 다 — 이 시험이 결함을 고정하고 있었다', () => {
79
- /*
80
- * ── 무엇이 잘못돼 있었나 (2026-08-24 실측) ────────────────────────────────
81
- * 이 시험은 `data: { order: 'SO-10021' }` 를 단정했다. **커널은 그런 모양을 낸 적이 없다** —
82
- * 오더는 `orderId` 다(`OrderStatusDelta.orderId` · `TaskStatusDelta.orderId`). 픽스처가 실제 델타
83
- * 대신 **스스로 지어낸 모양**을 썼고, 추출기도 같은 이름을 찾고 있었으니 둘이 나란히 초록이었다.
84
- *
85
- * 그동안 실 저널에서:
86
- * order.status 29,403,565 행 — order_id 100% 비어 있음
87
- * task.status 191,175 행 — 100% 비어 있음
88
- *
89
- * 색인 `ix_twin_event_4`(「이 오더가 어디까지 갔나」)가 자기 용도로 못 쓰였고, 화면은 오더를 눌러도
90
- * 「연결된 이벤트가 없습니다」를 냈다.
91
- *
92
- * **교훈**: 승격 키의 픽스처는 **커널이 실제로 내는 델타**여야 한다. 지어낸 모양으로 검사하면
93
- * 추출기와 시험이 함께 틀린 채로 영원히 초록이다.
94
- */
95
- assert.equal(orderOf({ eventType: 'order.status', data: { orderId: 'WO-260410-0133', status: 'in-progress' } }), 'WO-260410-0133')
96
- assert.equal(orderOf({ eventType: 'task.status', data: { taskId: 'TK-1', orderId: 'WO-1' } }), 'WO-1')
97
- /* 오더를 스스로 말하면 그 말이 이긴다 — 거래(PO/SO)와 오더는 같은 것이 아닐 수 있다. */
98
- assert.equal(
99
- orderOf({ data: { orderId: 'WO-1', bizTransactionList: [{ bizTransaction: 'urn:epc:id:gdti:0614141.402.2' }] } }),
100
- 'WO-1'
101
- )
102
- /*
103
- * ── 이 줄이 뒤집혔다 (2026-09-05 사용자 결정) ──────────────────────────────
104
- * 전에는 오더를 말하지 않는 EPCIS 가 **거래로 내려갔다.** 그래서 한 칸에 두 낱말이 들었고,
105
- * 한 오더의 이력이 색인 안에서 두 쪽으로 갈라졌다(실측: 어휘가 섞인 행 10,004개).
106
- *
107
- * 바로 위 줄이 그 위험을 이미 알고 있었다 — 「거래와 오더는 같은 것이 아닐 수 있다」. 알면서
108
- * 같은 칸에 넣고 있었다. 이제 갈라 든다.
109
- */
110
- assert.equal(orderOf({ data: { bizTransactionList: [{ bizTransaction: 'PO-9' }] } }), undefined)
111
- assert.equal(bizTransactionOf({ data: { bizTransactionList: [{ bizTransaction: 'PO-9' }] } }), 'PO-9')
112
- })
113
-
114
- test('★ 승격 키는 **커널이 실제로 내는 델타 모양**으로 검사한다', () => {
115
- /*
116
- * 위 결함의 부류는 「추출기가 찾는 이름을 발신자가 쓰지 않는다」이고, 지어낸 픽스처로는 절대 잡히지
117
- * 않는다. 그래서 실 저널에서 뜬 payload 모양을 그대로 놓고 단정한다 — 세 축이 실제로 채워지는지.
118
- */
119
- const orderDelta = { eventType: 'order.status', data: { orderId: 'order-1', kind: 'workorder', status: 'in-progress' } }
120
- const taskDelta = {
121
- eventType: 'task.status',
122
- data: { taskId: 'task-1', orderId: 'order-1', kind: 'cut', status: 'in-progress', resourceRef: 'cutter-1', fromNode: 'st-a', toNode: 'st-b' }
123
- }
124
- const energyEq = { eventType: 'energy.equipment', data: { equipmentId: 'pv-roof', at: '2026-08-17T10:45:20.664Z', generatedKW: 426 } }
125
-
126
- assert.equal(twinEventKeys(orderDelta).orderId, 'order-1', '오더 사건이 오더 축을 채운다')
127
- assert.equal(twinEventKeys(taskDelta).orderId, 'order-1', '작업도 자기 오더를 채운다 — 오더의 이력에 작업이 실린다')
128
- assert.equal(twinEventKeys(taskDelta).moverId, 'cutter-1', '작업이 쓴 자원이 설비 축에 실린다(`resourceRef`)')
129
- assert.equal(twinEventKeys(energyEq).moverId, 'pv-roof', '에너지 사건의 설비가 설비 축에 실린다(`equipmentId`)')
130
- })
131
-
132
- test('없는 값은 빈 문자열이 아니라 undefined — 결측과 빈값을 섞지 않는다', () => {
133
- const k = twinEventKeys({ eventType: 'equipment.status', data: { equipment: 'fork-1', status: 'idle' } })
134
- assert.equal(k.epc, undefined)
135
- assert.equal(k.orderId, undefined)
136
- assert.equal(k.locationId, undefined)
137
- assert.equal(k.moverId, undefined)
138
- /* bizStep 은 이벤트 타입에서 유추되므로 남는다 — 이건 결측이 아니다. */
139
- assert.equal(k.bizStep, 'equipment.status')
140
- })
141
-
142
- test('설비·무버 축 — 운영 델타의 moverId 를 뽑는다', () => {
143
- const ev = { eventType: 'equipment.status', data: { moverId: 'fork-3', status: 'down', location: 'rack-1' } }
144
- assert.equal(equipmentIdOf(ev), 'fork-3')
145
- const k = twinEventKeys(ev)
146
- assert.equal(k.moverId, 'fork-3')
147
- /* 개명 세대가 섞인다 — 읽는 쪽이 흡수한다(`moverId` 옛 채널 · `resourceRef` 작업 · `equipmentId` 에너지). */
148
- assert.equal(equipmentIdOf({ data: { resourceRef: 'cutter-1' } }), 'cutter-1')
149
- assert.equal(equipmentIdOf({ data: { equipmentId: 'pv-roof' } }), 'pv-roof')
150
- assert.equal(equipmentIdOf({ data: { moverId: 'fork-1', resourceRef: 'x' } }), 'fork-1', '앞의 이름이 이긴다')
151
- /* 운영 델타는 readPoint/bizLocation 이 없다 — 평범한 location 을 위치로 받는다.
152
- * 빠뜨리면 "이 설비가 어디서 무엇을 했나" 가 위치 축에서 통째로 사라진다. */
153
- assert.equal(k.locationId, 'rack-1')
154
- })
155
-
156
- test('EPCIS 의 readPoint 는 운영 델타의 location 보다 우선한다', () => {
157
- assert.equal(locationOf({ data: { readPoint: { id: 'DOCK-1' }, location: 'rack-9' } }), 'DOCK-1')
158
- })
159
-
160
- test('payload 가 data 로 감싸이지 않은 모양도 받는다', () => {
161
- assert.equal(epcOf({ epcList: ['urn:epc:id:sgtin:1.2.3'] }), 'urn:epc:id:sgtin:1.2.3')
162
- })
163
-
164
- test('상한을 넘는 값은 오류 없이 사라지지 않는다 — 잘리되 경고가 남는다', () => {
165
- const long = 'urn:epc:id:sgtin:' + 'x'.repeat(400)
166
- const warned: string[] = []
167
- const orig = console.warn
168
- console.warn = (...a: unknown[]) => void warned.push(String(a[0]))
169
- try {
170
- const k = twinEventKeys({ data: { epcList: [long] } })
171
- assert.equal(k.epc!.length, 255)
172
- assert.equal(warned.length, 1, '잘렸다는 사실이 어딘가에는 남아야 한다')
173
- assert.ok(warned[0].includes('epc'))
174
- } finally {
175
- console.warn = orig
176
- }
177
- })
178
-
179
- test('빈 봉투에도 터지지 않는다', () => {
180
- /* `provenance` 도 이 목록에 있어야 한다 — 봉투가 비어도 「선언된 것인지」는 낼 칸이 있다. */
181
- const empty = {
182
- action: undefined,
183
- bizStep: undefined,
184
- epc: undefined,
185
- orderId: undefined,
186
- bizTransaction: undefined,
187
- locationId: undefined,
188
- moverId: undefined,
189
- provenance: undefined
190
- }
191
- assert.deepEqual(twinEventKeys(undefined), empty)
192
- assert.deepEqual(twinEventKeys({}), empty)
193
- })
@@ -1,319 +0,0 @@
1
- /*
2
- * ★ 개념 안의 목록과 항목 하나 — **막다른 길을 만들지 않는다.**
3
- *
4
- * 개념 지도가 숫자만 내면 그 숫자가 막다른 길이다. 인스펙션의 원칙은 "화면에 보이는 모든 식별자는
5
- * 그 자신의 상세로 가는 문" 이므로, 셈 다음에 **목록**과 **항목**이 있어야 그 원칙이 성립한다.
6
- *
7
- * 여기서 지키는 것:
8
- * · 어떻게 셌는지 밝힌다 — 행이면 DB 가 페이징, 문서면 서버가 통째로 읽어 잘랐다(`basis`)
9
- * · 알리지 않고 자르지 않는다 — 총 건수가 항상 함께 오고, 훑기가 상한에 닿으면 그렇다고 말한다
10
- * · 모르는 축은 **거절한다** — 빈 목록으로 답하면 오타 하나가 "우리 트윈엔 그게 없다" 로 굳는다
11
- * · 투영이 낡아도 항목은 열린다 — 행에 없으면 문서에서 찾는다
12
- * · 이어진 것은 **양방향**이고, 선언된 관계만 따른다(선언에 없는 길은 그리지 않는다)
13
- * · 관측이 없는 것과 견주지 못한 것을 구별한다(`observed: null`)
14
- */
15
- import { test, before, after } from 'node:test'
16
- import assert from 'node:assert/strict'
17
- import { createRequire } from 'node:module'
18
- import type { DataSource } from 'typeorm'
19
-
20
- const req = createRequire(import.meta.url)
21
- const { NamingStrategy, addDataSource, entities: shellEntities, Domain } = req('@things-factory/shell')
22
- const { entities: authEntities } = req('@things-factory/auth-base')
23
- const { entities: twinEntities } = req('../dist-server/service/index.js')
24
- const { TwinEngine } = req('../dist-server/engine/index.js')
25
- const { TwinModelItemQuery } = req('../dist-server/service/twin-model/twin-model-item-query.js')
26
- const { TwinModelQuery } = req('../dist-server/service/twin-model/twin-model-query.js')
27
- const { TwinSpace } = req('../dist-server/service/twin-space/twin-space.js')
28
- const { TwinArea } = req('../dist-server/service/twin-space/twin-area.js')
29
- const { DataSource: TypeOrmDataSource } = req('typeorm')
30
-
31
- let ds: DataSource
32
- let domainId: string
33
- let q: any
34
- let ctx: any
35
-
36
- const INSTANCE = 'item-probe'
37
-
38
- /** MES 마스터 — 자리·설비·공정에 더해 **문서에만 사는 축**(레시피·라우트)까지 있는 모양. */
39
- const master = (): any => ({
40
- source: INSTANCE,
41
- system: 'mes',
42
- siteName: '항목 공장',
43
- space: { width: 80, depth: 40, unit: 'm' },
44
- locations: [
45
- { id: 'a-floor', type: 'production-line', role: 'area', name: '생산 플로어' },
46
- { id: 'cut-station', type: 'cut-station', role: 'location', name: '절단', parentId: 'a-floor', capacity: 20 },
47
- { id: 'weld-station', type: 'weld-station', role: 'location', name: '용접', parentId: 'a-floor', capacity: 20 }
48
- ],
49
- equipment: [
50
- { id: 'cutter-1', kind: 'cutter', homeLocationId: 'cut-station', mtbfMs: 3600000 },
51
- { id: 'welder-1', kind: 'welder', homeLocationId: 'weld-station' },
52
- { id: 'welder-2', kind: 'welder', homeLocationId: 'weld-station' }
53
- ],
54
- operations: [
55
- { key: 'cut', label: '절단', intent: 'process', locationType: 'cut-station', resourceType: 'cutter', duration: 'PT10M' },
56
- { key: 'weld', label: '용접', intent: 'process', locationType: 'weld-station', resourceType: 'welder', duration: 'PT20M' }
57
- ],
58
- productionSpec: {
59
- definition: {
60
- materials: [{ id: 'steel' }, { id: 'frame' }],
61
- routes: [{ key: 'frame-route', steps: ['cut', 'weld'] }],
62
- recipes: [{ key: 'frame-recipe', route: 'frame-route', inputs: [{ material: 'steel' }], outputs: [{ material: 'frame' }] }],
63
- operations: [
64
- { key: 'cut', label: '절단', intent: 'process', locationType: 'cut-station', resourceType: 'cutter', duration: 'PT10M' },
65
- { key: 'weld', label: '용접', intent: 'process', locationType: 'weld-station', resourceType: 'welder', duration: 'PT20M' }
66
- ]
67
- }
68
- }
69
- })
70
-
71
- before(async () => {
72
- ds = new TypeOrmDataSource({
73
- type: 'sqlite',
74
- database: ':memory:',
75
- synchronize: true,
76
- dropSchema: true,
77
- namingStrategy: new NamingStrategy(),
78
- entities: [...shellEntities, ...authEntities, ...twinEntities],
79
- logging: false
80
- })
81
- await ds.initialize()
82
- addDataSource('default', ds)
83
- const d = await ds.getRepository(Domain).save({ name: 'item-test', subdomain: 'item-test' } as any)
84
- domainId = d.id
85
- q = new TwinModelItemQuery()
86
- ctx = { state: { domain: { id: domainId } } }
87
-
88
- await TwinEngine.ingestMaster(domainId, master(), 'reset')
89
- })
90
-
91
- after(async () => {
92
- await TwinEngine.stop(domainId, INSTANCE).catch(() => {})
93
- await ds?.destroy()
94
- })
95
-
96
- test('행으로 옮긴 축은 DB 가 페이징하고 그 사실을 밝힌다', async () => {
97
- const page1 = await q.twinModelEntities(INSTANCE, 'equipment', ctx, undefined, 0, 2)
98
- assert.equal(page1.basis, 'rows', 'DB 가 셌다는 사실이 응답에 있어야 한다')
99
- assert.equal(page1.total, 3, '총 건수는 페이지 크기와 무관하게 사실이다')
100
- assert.equal(page1.items.length, 2)
101
-
102
- const page2 = await q.twinModelEntities(INSTANCE, 'equipment', ctx, undefined, 2, 2)
103
- assert.equal(page2.items.length, 1, '이어 읽을 수 있다')
104
- const seen = [...page1.items, ...page2.items].map((i: any) => i.id).sort()
105
- assert.deepEqual(seen, ['cutter-1', 'welder-1', 'welder-2'], '두 페이지가 전건을 덮는다')
106
- })
107
-
108
- test('아직 문서에 사는 축도 열린다 — 이주 전이라고 안 보이면 안 된다', async () => {
109
- const r = await q.twinModelEntities(INSTANCE, 'recipes', ctx)
110
- assert.equal(r.basis, 'document', '문서를 읽어 잘랐다는 사실을 밝힌다(규모 한계가 드러나야 한다)')
111
- assert.equal(r.total, 1)
112
- assert.deepEqual(r.items.map((i: any) => i.id), ['frame-recipe'])
113
- })
114
-
115
- test('검색이 전수 조회라는 사실을 드러낸다 — 감추면 한계를 아무도 모른다', async () => {
116
- const r = await q.twinModelEntities(INSTANCE, 'equipment', ctx, 'weld')
117
- assert.equal(r.total, 2)
118
- /* 훑어 걸렀다는 사실은 **이 두 칸이** 말한다(근거가 아니라 셈의 한계다). */
119
- assert.equal(typeof r.scanned, 'number', '몇 줄을 읽었는지 말하지 않는다')
120
- assert.equal(r.truncated, false, '상한에 닿지 않았으면 잘리지 않았다고 말한다')
121
- assert.deepEqual(r.items.map((i: any) => i.id).sort(), ['welder-1', 'welder-2'])
122
- })
123
-
124
- test('★ 근거는 계약이 닫아 둔 다섯 안에서만 답한다', async () => {
125
- /*
126
- * 2026-09-18 판정(ADR-0075 결정 3 을 코드에 대어 본 결과): 검색 갈래가 `'rows-scanned'` 를 냈다.
127
- * 그것은 출처가 아니라 우리가 어떻게 셌나이고, 목록 소비자는 계약에 없는 값을 만난다. 출처는
128
- * 훑었든 DB 가 골랐든 같은 행이므로 `rows` 다.
129
- */
130
- const { READ_BASIS } = req('@operato/ops-contract')
131
- const answers = [
132
- await q.twinModelEntities(INSTANCE, 'equipment', ctx, 'weld'),
133
- await q.twinModelEntities(INSTANCE, 'equipment', ctx),
134
- await q.twinModelEntities(INSTANCE, 'recipes', ctx)
135
- ]
136
- for (const a of answers) assert.ok(READ_BASIS.includes(a.basis), `계약 밖의 근거 '${a.basis}'`)
137
- assert.equal(answers[0].basis, 'rows', '훑어 세도 값이 온 곳은 행이다')
138
- })
139
-
140
- test('모르는 축은 거절한다 — 빈 목록은 "없다" 로 읽힌다', async () => {
141
- await assert.rejects(() => q.twinModelEntities(INSTANCE, 'nosuch', ctx), /unknown concept axis/)
142
- await assert.rejects(() => q.twinModelItem(INSTANCE, 'nosuch', 'x', ctx), /unknown concept axis/)
143
- })
144
-
145
- test('항목 하나 — 정체는 카탈로그에서, 선언은 원본에서, 출처가 함께 온다', async () => {
146
- const it = await q.twinModelItem(INSTANCE, 'equipment', 'cutter-1', ctx)
147
- assert.ok(it, '있는 항목은 열려야 한다')
148
- assert.equal(it.identity.typeRole, 'equipment', '표준 역할은 커널 카탈로그가 말한다')
149
- assert.equal(it.declared.kind, 'cutter')
150
- assert.equal(it.declared.mtbfMs, 3600000)
151
- assert.equal(it.provenance.basis, 'rows')
152
- assert.equal(it.provenance.sourceRef, INSTANCE, '어느 원본에서 왔는지가 항목에 붙어 있다')
153
- })
154
-
155
- test('비교하지 못했으면 관측은 null 이고, 답했으면 **근거를 알린다**', async () => {
156
- const it = await q.twinModelItem(INSTANCE, 'equipment', 'cutter-1', ctx)
157
- /*
158
- * 이 픽스처에는 저널이 없다(행만 있다) — 되짚을 것이 없으므로 관측은 없다. **0 이나 빈 객체로
159
- * 메우면 "관측했는데 아무것도 없었다" 로 읽힌다.**
160
- *
161
- * 예전 이 검사는 "트윈이 안 돌면 관측은 null" 이었다. 지금은 멈춘 트윈도 저널을 계산해 답할 수 있고,
162
- * 그 답이 **자기 근거를 달고 온다**(`observedBasis`). 그래서 규율을 그 자리에 맞춰 다시 적는다:
163
- * 답이 없으면 null, 답이 있으면 그것이 라이브인지 되짚은 것인지 말한다. 근거 없는 답은 없다.
164
- */
165
- assert.equal(it.observed, null, '되짚을 저널이 없으면 관측은 없다')
166
- assert.equal(it.observedBasis, undefined, '답이 없으면 근거도 말하지 않는다(빈 답에 근거를 붙이면 견준 것처럼 보인다)')
167
- })
168
-
169
- test('이어진 것은 양방향이고 선언된 관계만 따른다', async () => {
170
- const loc = await q.twinModelItem(INSTANCE, 'locations', 'weld-station', ctx)
171
-
172
- /* 들어오는 쪽 — 이 자리를 기준으로 삼는 설비 둘. 선언(`equipment.homeLocation`)이 알려 준다. */
173
- const home = loc.links.incoming.find((l: any) => l.via === 'ops.rel.home' && l.from === 'equipment')
174
- assert.ok(home, '나를 가리키는 관계가 보여야 한 걸음씩 걸을 수 있다')
175
- assert.deepEqual(home.ids.sort(), ['welder-1', 'welder-2'])
176
- assert.equal(home.total, 2)
177
-
178
- /* 나가는 쪽 — 자리는 구역을 가리킨다. 대상이 **축 밖**(공간의 구역)이라는 사실을 그대로 낸다. */
179
- const area = loc.links.out.find((l: any) => l.via === 'ops.rel.area')
180
- assert.ok(area, '커널이 "밖" 이라 부른 참조도 이어진 것으로 낸다')
181
- assert.equal(area.target.kind, 'external', '갈 곳이 다르므로 화면이 링크를 만들지 말지 알 수 있어야 한다')
182
- })
183
-
184
- test('문서에만 사는 항목의 관계도 선언대로 이어진다', async () => {
185
- const recipe = await q.twinModelItem(INSTANCE, 'recipes', 'frame-recipe', ctx)
186
- assert.equal(recipe.provenance.basis, 'document')
187
-
188
- const route = recipe.links.out.find((l: any) => l.via === 'ops.rel.route')
189
- assert.deepEqual(route.ids, ['frame-route'])
190
-
191
- /* `inputs[].material` — 배열을 지나는 경로가 선언의 문법이고, 그것을 따르는 것이 선언을 존중하는 것이다. */
192
- const input = recipe.links.out.find((l: any) => l.via === 'ops.rel.input')
193
- assert.deepEqual(input.ids, ['steel'])
194
- const output = recipe.links.out.find((l: any) => l.via === 'ops.rel.output')
195
- assert.deepEqual(output.ids, ['frame'])
196
- })
197
-
198
- test('없는 항목은 null — 빈 껍데기를 내주지 않는다', async () => {
199
- assert.equal(await q.twinModelItem(INSTANCE, 'equipment', 'no-such-machine', ctx), null)
200
- })
201
-
202
- test('내부 배관은 새어 나가지 않는다 — 사용자가 볼 것은 현장의 사실이지 우리 스키마가 아니다', async () => {
203
- /*
204
- * 실제로 새었다: `domainId`·`instanceRowId` 같은 내부 UUID 가 속성 패널까지 갔다.
205
- * 손으로 제외 목록을 두면 컬럼이 늘 때마다 잊는다 — 관계와 조인 컬럼은 엔티티 메타데이터가 안다.
206
- */
207
- const INTERNAL = /^(id|domainId?|instanceRowId|areaRowId|homeLocationRowId|createdAt|updatedAt|creator|updater|creatorId|updaterId)$/
208
-
209
- const list = await q.twinModelEntities(INSTANCE, 'locations', ctx)
210
- for (const it of list.items)
211
- for (const k of Object.keys(it.fields))
212
- assert.ok(!INTERNAL.test(k), `목록에 내부 컬럼이 새었다: ${k}`)
213
-
214
- const item = await q.twinModelItem(INSTANCE, 'locations', 'weld-station', ctx)
215
- for (const k of Object.keys(item.declared))
216
- assert.ok(!INTERNAL.test(k), `속성 패널에 내부 컬럼이 새었다: ${k}`)
217
-
218
- /* 식별자도 두 번 보이지 않는다 — 이미 itemId 로 나간다. */
219
- assert.ok(!('locationId' in item.declared), '항목 자신의 id 를 속성으로 또 내지 않는다')
220
- /* 출처는 속성이 아니라 근거다. */
221
- assert.ok(!('sourceRef' in item.declared) && !('ingestedAt' in item.declared))
222
- assert.equal(item.provenance.sourceRef, INSTANCE)
223
- })
224
-
225
- test('지도의 선이 진단이 된다 — 이어진 것뿐 아니라 **끊긴 것**을 센다', async () => {
226
- /*
227
- * 선이 "선언되었고 양끝이 존재한다" 만 말하면 지도는 그림일 뿐이다. 관계에서 가장 중요한 정보는
228
- * 대개 부재다 — 기준 자리가 비어 있는 설비, 없는 자리를 가리키는 설비.
229
- */
230
- const bad = master()
231
- bad.equipment.push({ id: 'ghost-1', kind: 'welder', homeLocationId: 'no-such-station' }) // 끊어진 참조
232
- bad.equipment.push({ id: 'floater-1', kind: 'welder' }) // 기준 자리 없음
233
- await TwinEngine.ingestMaster(domainId, bad, 'reset')
234
-
235
- const sum = await new TwinModelQuery().twinModelSummary(INSTANCE, ctx)
236
- const home = sum.edges.find((e: any) => e.from === 'equipment' && e.to === 'locations' && e.via === 'ops.rel.home')
237
- assert.ok(home, '설비→자리 선이 있어야 한다')
238
- assert.equal(home.linked, 3, '제대로 이어진 설비 셋')
239
- assert.equal(home.dangling, 1, '없는 자리를 가리키는 설비 하나 — 가장 나쁜 부류이므로 따로 센다')
240
- assert.equal(home.missing, 1, '기준 자리를 말하지 않은 설비 하나')
241
-
242
- /* 선택 관계인지도 함께 온다 — `missing` 이 결손인지 정상인지는 그것으로 갈린다. */
243
- assert.equal(home.optional, true)
244
- })
245
-
246
- /*
247
- * ★ 관측 열이 **자기 근거를 말한다** — 라이브인지 되짚은 것인지.
248
- *
249
- * 둘은 같은 모양의 값이라, 근거가 없으면 되짚은 값을 "지금 이렇다" 로 읽는다. 그래서 근거를 실을
250
- * 자리가 없던 동안에는 멈춘 트윈의 저널을 아예 계산하지 않았다(관측 열이 통째로 `—`). 자리를 만든 뒤의
251
- * 규율은 하나다: **답하면 근거를 말한다.**
252
- */
253
- test('멈춘 트윈도 저널을 계산해 답하고, 그 답은 다시 계산한 값이라고 알린다', async () => {
254
- const { WmsKernel, EventJournal } = req('@operato/twin-kernel')
255
- const model = {
256
- spaceId: 'journal-space',
257
- utcOffsetMinutes: 0,
258
- /* 커널은 선언 없이 팔레트·문서를 만들지 않는다 — 픽스처 자기 이름공간을 준다. */
259
- identity: { namespaces: ['https://twin.test/twin-model-item/journal'] },
260
- locations: [
261
- { id: 'dock-recv', type: 'dock', capacity: 100 },
262
- { id: 'bin-1', type: 'storage', capacity: 20 }
263
- ],
264
- equipment: [{ id: 'fk-1', kind: 'forklift', homeLocation: 'dock-recv' }]
265
- }
266
- /* 커널을 실제로 굴려 봉투를 얻는다 — 손으로 지어낸 모양은 검증이 아니다. */
267
- const journal = new EventJournal()
268
- const k = new WmsKernel('journal-probe')
269
- k.onEvent((e: any) => journal.append(e))
270
- k.loadTwinModel(model)
271
- k.scenario.load({
272
- seed: 7,
273
- generators: [
274
- {
275
- kind: 'inbound-arrival',
276
- rate: { distribution: 'constant', meanPerHour: 240 },
277
- content: { skuMix: [{ gtin: 'urn:epc:idpat:sgtin:0614141.012345.*', weight: 1 }], qtyPerLine: { min: 1, max: 1 } }
278
- }
279
- ]
280
- })
281
- k.scenario.start()
282
- for (let i = 0; i < 200; i++) k.tick(1000)
283
-
284
- const INST = 'journal-probe'
285
- await TwinEngine.provision(domainId, INST, 'wms', model, 'reset')
286
- await TwinEngine.persistBatch(domainId, INST, journal.all(), 0)
287
- await TwinEngine.stop(domainId, INST).catch(() => {})
288
- delete (TwinEngine as any).recovered[`${domainId}:${INST}`]
289
-
290
- const it = await q.twinModelItem(INST, 'equipment', 'fk-1', ctx)
291
- assert.ok(it?.observed, '저널이 있으면 멈춘 트윈도 마지막으로 알던 사실을 답할 수 있다')
292
- assert.equal(it.observedBasis, 'journal', '라이브가 아니라 되짚은 것이라고 말해야 "지금 이렇다" 로 읽히지 않는다')
293
- assert.ok(it.observedRevision > 0, '몇 번째 리비전까지 계산했는지 함께 말한다 — 규모의 한계도 그 수가 말한다')
294
- })
295
-
296
- test('★ 멈춘 트윈을 되세우지 못한 답도 출처가 제 근거와 같다 — 저널을 보러 간 답이 「지금 상태」라고 말하지 않는다', async () => {
297
- /*
298
- * ADR-0075 결정 3 · 결함 넘김 2026-09-24: 이 갈래만 `provenance.basis` 를 `state` 로 박아 두어, 같은 답이 `basis` 는
299
- * `journal` 인데 출처는 `state` 였다. 커널이 멈춰 있고(`isRunning` false) 되세우기도 실패하는 때를 대역으로 세운다.
300
- */
301
- const { READ_BASIS } = req('@operato/ops-contract')
302
- const isRunning = TwinEngine.isRunning
303
- const recover = TwinEngine.recover
304
- TwinEngine.isRunning = () => false
305
- TwinEngine.recover = async () => {
306
- throw new Error('nothing to rebuild')
307
- }
308
- try {
309
- /* 상태에서 읽는 축이라야 이 갈래를 지난다(`orders` — 계약이 `source: 'state'` 로 선언). */
310
- const it = await q.twinModelItem(INSTANCE, 'orders', 'order-1', ctx)
311
- assert.equal(it.observedAbsence, 'not-running', '전제: 못 읽은 갈래다')
312
- assert.equal(it.provenance.basis, it.basis, '출처와 근거가 같은 말을 한다')
313
- assert.equal(it.provenance.basis, 'journal', '멈춘 트윈은 저널을 보러 갔다')
314
- assert.ok(READ_BASIS.includes(it.provenance.basis))
315
- } finally {
316
- TwinEngine.isRunning = isRunning
317
- TwinEngine.recover = recover
318
- }
319
- })
@@ -1,125 +0,0 @@
1
- /*
2
- * A location's parent is another location or an area — the item panel splits them by lookup.
3
- *
4
- * Contract 0.9.24 (ops-contract `00a346f`) declares `locations.parentId` as `axis-or-external`: the parent is
5
- * another location (line · cell · zone) or, when no location has that id, an area of the space. Before this, the
6
- * declaration said "area" only, so a bin under a zone could not walk to its zone, and a zone could not see the
7
- * bins under it.
8
- *
9
- * What is held here:
10
- * - a parent that is a location becomes a link to that location, and nothing of it is sent to the area resolver;
11
- * - a parent that is not a location is resolved as an area — only those ids reach the resolver;
12
- * - a parent id found nowhere comes back as the resolver answers it (missing), not as an empty relation;
13
- * - a zone sees the locations under it as incoming, counted from the document (rows carry no parent location).
14
- */
15
- import { test, before, after } from 'node:test'
16
- import assert from 'node:assert/strict'
17
- import { createRequire } from 'node:module'
18
- import type { DataSource } from 'typeorm'
19
-
20
- const req = createRequire(import.meta.url)
21
- const { NamingStrategy, addDataSource, entities: shellEntities, Domain } = req('@things-factory/shell')
22
- const { entities: authEntities } = req('@things-factory/auth-base')
23
- const { entities: twinEntities } = req('../dist-server/service/index.js')
24
- const { TwinEngine } = req('../dist-server/engine/index.js')
25
- const { TwinModelItemQuery } = req('../dist-server/service/twin-model/twin-model-item-query.js')
26
- const { registerExternalResolver, clearExternalResolvers } = req('../dist-server/service/twin-model/external-resolver.js')
27
- const { DataSource: TypeOrmDataSource } = req('typeorm')
28
-
29
- let ds: DataSource
30
- let domainId: string
31
- let q: any
32
- let ctx: any
33
- const asked: string[][] = []
34
-
35
- const INSTANCE = 'parent-probe'
36
-
37
- const master = (): any => ({
38
- source: INSTANCE,
39
- system: 'wms',
40
- siteName: 'parent site',
41
- space: { width: 80, depth: 40, unit: 'm' },
42
- locations: [
43
- { id: 'hall-a', type: 'storage', role: 'area', name: 'Hall A' },
44
- { id: 'zone-1', type: 'storage', role: 'location', name: 'Zone 1', parentId: 'hall-a' },
45
- { id: 'bin-1', type: 'storage', role: 'location', name: 'Bin 1', parentId: 'zone-1', capacity: 10 },
46
- { id: 'bin-2', type: 'storage', role: 'location', name: 'Bin 2', parentId: 'zone-1', capacity: 10 },
47
- { id: 'bin-x', type: 'storage', role: 'location', name: 'Bin X', parentId: 'nowhere', capacity: 10 }
48
- ],
49
- equipment: [{ id: 'fk-1', kind: 'forklift', homeLocationId: 'zone-1' }]
50
- })
51
-
52
- before(async () => {
53
- ds = new TypeOrmDataSource({
54
- type: 'sqlite',
55
- database: ':memory:',
56
- synchronize: true,
57
- dropSchema: true,
58
- namingStrategy: new NamingStrategy(),
59
- entities: [...shellEntities, ...authEntities, ...twinEntities],
60
- logging: false
61
- })
62
- await ds.initialize()
63
- addDataSource('default', ds)
64
- const d = await ds.getRepository(Domain).save({ name: 'parent-test', subdomain: 'parent-test' } as any)
65
- domainId = d.id
66
- q = new TwinModelItemQuery()
67
- ctx = { state: { domain: { id: domainId } } }
68
-
69
- /* A stand-in for the host's area resolver: it records what it was asked and knows one area. */
70
- registerExternalResolver({
71
- entity: 'space.area',
72
- resolve: async (_domainId: string, ids: string[]) => {
73
- asked.push([...ids])
74
- return ids.map(id => (id === 'hall-a' ? { id, name: 'Hall A' } : { id, missing: true }))
75
- }
76
- })
77
-
78
- await TwinEngine.ingestMaster(domainId, master(), 'reset')
79
- })
80
-
81
- after(async () => {
82
- clearExternalResolvers()
83
- await TwinEngine.stop(domainId, INSTANCE).catch(() => {})
84
- await ds?.destroy()
85
- })
86
-
87
- const parentLinks = (item: any) => item.links.out.filter((l: any) => l.field === 'parentId')
88
-
89
- test('a parent that is a location is a link to that location — none of it goes to the area resolver', async () => {
90
- asked.length = 0
91
- const bin = await q.twinModelItem(INSTANCE, 'locations', 'bin-1', ctx)
92
- const links = parentLinks(bin)
93
- assert.equal(links.length, 1, `expected one parent line, got ${JSON.stringify(links)}`)
94
- assert.deepEqual(links[0].target, { kind: 'axis', axis: 'locations' })
95
- assert.equal(links[0].declaredTarget.kind, 'axis-or-external')
96
- assert.deepEqual(links[0].ids, ['zone-1'])
97
- assert.deepEqual(asked, [], 'a location parent was sent to the area resolver')
98
- })
99
-
100
- test('a parent that is not a location is resolved as an area — only that id reaches the resolver', async () => {
101
- asked.length = 0
102
- const zone = await q.twinModelItem(INSTANCE, 'locations', 'zone-1', ctx)
103
- const links = parentLinks(zone)
104
- assert.equal(links.length, 1)
105
- assert.deepEqual(links[0].target, { kind: 'external', entity: 'space.area' })
106
- assert.deepEqual(links[0].refs, [{ id: 'hall-a', name: 'Hall A' }])
107
- assert.deepEqual(asked, [['hall-a']])
108
- })
109
-
110
- test('a parent found nowhere is said to be missing — not an empty relation', async () => {
111
- const bin = await q.twinModelItem(INSTANCE, 'locations', 'bin-x', ctx)
112
- const links = parentLinks(bin)
113
- assert.equal(links.length, 1)
114
- assert.equal(links[0].target.kind, 'external')
115
- assert.equal(links[0].total, 1)
116
- assert.deepEqual(links[0].refs, [{ id: 'nowhere', missing: true }])
117
- })
118
-
119
- test('a zone sees the locations under it as incoming — counted from the document', async () => {
120
- const zone = await q.twinModelItem(INSTANCE, 'locations', 'zone-1', ctx)
121
- const under = zone.links.incoming.find((l: any) => l.from === 'locations' && l.field === 'parentId')
122
- assert.ok(under, `no incoming parent relation on the zone: ${JSON.stringify(zone.links.incoming.map((l: any) => [l.from, l.field]))}`)
123
- assert.deepEqual([...under.ids].sort(), ['bin-1', 'bin-2'])
124
- assert.equal(under.total, 2)
125
- })