@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,451 +0,0 @@
1
- /*
2
- * 정규 인제스트 — **어휘가 둘이다**(물류 EPCIS · 에너지 계측).
3
- *
4
- * ── 왜 있나 (2026-08-14, EMS 5단계 준비) ────────────────────────────────────
5
- * 이 seam 은 무조건 `type: 'ObjectEvent'` 를 만들었다. 그래서 커넥터가 계측을 이 길로 보내면 둘 중
6
- * 하나가 됐다: `epc` 가 없어 거부되거나(그나마 나은 쪽), **엉뚱한 물품 관측**으로 읽혀 재고가 흔들린다.
7
- * 오류 없이 틀리는 쪽이 더 나쁘다.
8
- *
9
- * 이 시험이 지키는 것 둘:
10
- * ① 한 배치에 두 어휘가 섞여 와도 각자의 봉투가 된다(커넥터가 나눠 보낼 의무를 지지 않는다).
11
- * ② **거부분이 사라지지 않는다** — 예전에는 호출부가 `rejected` 를 받지도 않았다.
12
- */
13
- import { test } from 'node:test'
14
- import assert from 'node:assert/strict'
15
-
16
- import { ingestCanonicalRecords } from '../server/engine/canonical-ingest.ts'
17
-
18
- /*
19
- * 이 파일의 **시계**. 아래 픽스처들이 8월 말을 쓰는데 시계가 8월 14일이었다 — 자기 시계보다 뒤의
20
- * 사실을 표본으로 두고 있었다. 커널이 「아직 오지 않은 시각의 사실」을 거부하게 되면서 드러났다
21
- * (2026-08-30). 시계를 픽스처 뒤로 옮긴다.
22
- */
23
- const NOW = '2026-09-01T00:00:00.000Z'
24
-
25
- const epcisRecord = {
26
- epc: 'urn:epc:id:sgtin:0614141.107346.2017',
27
- action: 'OBSERVE',
28
- bizStep: 'urn:epcglobal:cbv:bizstep:storing',
29
- disposition: 'urn:epcglobal:cbv:disp:in_progress',
30
- readPoint: 'rack-1'
31
- }
32
- const energyRecord = { meterId: 'meter-incoming', kW: 1200, at: '2026-08-14T09:00:30.000Z' }
33
-
34
- test('한 배치에 두 어휘가 섞여도 각자의 봉투가 된다', () => {
35
- const { accepted, rejected } = ingestCanonicalRecords([epcisRecord, energyRecord] as any, 't', NOW)
36
- assert.equal(rejected.length, 0, `거부 없음이어야 한다: ${JSON.stringify(rejected)}`)
37
- const types = accepted.map(e => e.eventType).sort()
38
- assert.deepEqual(types, ['energy.measured', 'epcis.ObjectEvent'])
39
- })
40
-
41
- test('계측을 물품 관측으로 만들지 않는다 — 이것이 이 갈림의 이유다', () => {
42
- const { accepted } = ingestCanonicalRecords([energyRecord] as any, 't', NOW)
43
- assert.equal(accepted.length, 1)
44
- assert.equal(accepted[0].eventType, 'energy.measured')
45
- /* EPCIS 페이로드의 흔적이 없어야 한다 — 있으면 미러가 물품을 지어낸다. */
46
- assert.equal((accepted[0].data as any).epcList, undefined)
47
- assert.equal((accepted[0].data as any).type, undefined)
48
- })
49
-
50
- test('거부분이 사라지지 않는다 — 커넥터 매핑이 틀린 것을 알 수 있어야 한다', () => {
51
- const { accepted, rejected } = ingestCanonicalRecords(
52
- [
53
- energyRecord,
54
- { meterId: 'm-2', kW: 10, at: '어제' }, // 시각 형식 오류
55
- { epc: '', action: 'OBSERVE', bizStep: 'x' } // EPCIS 쪽 결손
56
- ] as any,
57
- 't',
58
- NOW
59
- )
60
- assert.equal(accepted.length, 1, '유효한 것은 통과한다')
61
- assert.equal(rejected.length, 2)
62
- for (const r of rejected) assert.ok(r.errors.length > 0, '이유 없는 거부가 없다')
63
- })
64
-
65
- test('빈 입력에서 모든 갈래가 들어온 것이 없다 — 없는 것을 만들지 않는다', () => {
66
- /*
67
- * 어휘가 다섯이다 — 사건 넷과 사건이 아닌 것 하나(마스터데이터). 어느 갈래도 값을 지어내지 않는다.
68
- *
69
- * `undated` 는 `masterData` 와 같은 규칙으로 언제나 있다(빈 것이면 빈 객체). 없을 때 칸을 빼면
70
- * 읽는 쪽이 「이 버전이 그것을 안 센다」와 「셌는데 0이다」를 구별하지 못한다.
71
- */
72
- const none = { accepted: [], rejected: [], masterData: [], undated: {} }
73
- assert.deepEqual(ingestCanonicalRecords([], 't', NOW), none)
74
- assert.deepEqual(ingestCanonicalRecords(null, 't', NOW), none)
75
- })
76
-
77
- test('시각이 없는 계측은 호출자의 기준 시각을 쓴다 — 도착 시각이 근거다', () => {
78
- const { accepted } = ingestCanonicalRecords([{ meterId: 'm-1', kW: 5 }] as any, 't', NOW)
79
- assert.equal(accepted[0].eventTime, NOW)
80
- })
81
-
82
- /*
83
- * ── 세 번째 어휘: 설비 에너지 상태 (2026-08-15) ─────────────────────────────
84
- * 능력 계약은 태양광·축전지·감축 부하·차단기의 상태 필드를 선언해 두었는데 받는 길이 없었다.
85
- * 계량과 갈라 두는 이유는 커널에 적혀 있다 — 계량은 구간에 누적되고, 이것들은 그 설비의 지금이다.
86
- */
87
- test('설비 에너지 상태는 EPCIS 도 계량도 아닌 자기 어휘로 들어온다', () => {
88
- const { accepted, rejected } = ingestCanonicalRecords(
89
- [
90
- { equipmentId: 'pv-1', at: '2026-08-15T09:00:00.000Z', generatedKW: 210 },
91
- { meterId: 'm-1', kW: 800, at: '2026-08-15T09:00:00.000Z' },
92
- { epc: 'urn:epc:id:sgtin:9521321.012345.3', action: 'OBSERVE', bizStep: 'urn:epcglobal:cbv:bizstep:storing' }
93
- ] as any,
94
- 'tenant-1',
95
- '2026-08-15T09:00:00.000Z'
96
- )
97
- assert.equal(rejected.length, 0, JSON.stringify(rejected))
98
- const types = accepted.map(a => a.eventType).sort()
99
- assert.deepEqual(types, ['energy.equipment', 'energy.measured', 'epcis.ObjectEvent'].sort(), '세 어휘가 각자 봉투로')
100
- })
101
-
102
- test('바꿀 상태가 없는 보고는 거부한다 — 이유와 함께', () => {
103
- const { accepted, rejected } = ingestCanonicalRecords(
104
- [{ equipmentId: 'pv-1', at: '2026-08-15T09:00:00.000Z' }] as any,
105
- 'tenant-1',
106
- '2026-08-15T09:00:00.000Z'
107
- )
108
- assert.equal(accepted.length, 0)
109
- assert.match(rejected[0].errors.join(' '), /바꿀 상태/)
110
- })
111
-
112
- test('충전율이 백분율 범위를 벗어나면 거부한다 — 단위를 잘못 맞춘 커넥터를 통과시키지 않는다', () => {
113
- const { rejected } = ingestCanonicalRecords(
114
- [{ equipmentId: 'ess-1', at: '2026-08-15T09:00:00.000Z', soc: 380 }] as any,
115
- 'tenant-1',
116
- '2026-08-15T09:00:00.000Z'
117
- )
118
- assert.equal(rejected.length, 1)
119
- assert.match(rejected[0].errors.join(' '), /soc/)
120
- })
121
-
122
- test('개폐 위치는 표준의 네 값만 받는다 — 과도·불량을 열림/닫힘으로 반올림하지 않는다', () => {
123
- const ok = ingestCanonicalRecords([{ equipmentId: 'cb-1', at: '2026-08-15T09:00:00.000Z', position: 'intermediate' }] as any, 't', '2026-08-15T09:00:00.000Z')
124
- assert.equal(ok.accepted.length, 1)
125
- const bad = ingestCanonicalRecords([{ equipmentId: 'cb-1', at: '2026-08-15T09:00:00.000Z', position: 'ON' }] as any, 't', '2026-08-15T09:00:00.000Z')
126
- assert.equal(bad.rejected.length, 1)
127
- assert.match(bad.rejected[0].errors.join(' '), /position/)
128
- })
129
-
130
- /*
131
- * ── 레코드가 말한 시각이 봉투의 시각이 된다 (2026-08-23) ────────────────────
132
- *
133
- * 이 경로는 `eventTimePath` 를 주지 않아 **언제나 폴링 시각**을 썼다. 그래서 커넥터가 이미 싣고 있던
134
- * `eventTime` 이 알리지 않고 무시됐다 — 어디에도 오류가 나지 않고, 커넥터를 붙인 쪽은 그것이 먹는다고
135
- * 믿고 있었다.
136
- *
137
- * 무엇이 걸렸나: **계보의 시각**이다. 4월에 만든 로트가 8월에 만들어진 것으로 저널에 남았다. 그리고
138
- * 실측 소요를 재는 폴드가 봉투 시각을 쓰므로(`kpi-fold`: `workMs = 완료 − 첫 착수`), 폴링 간격을
139
- * 작업시간으로 배울 수 있었다 — 못 배우는 것보다 나쁘다.
140
- */
141
- test('레코드가 시각을 말하면 그것이 봉투의 시각이다 — 폴링 시각으로 덮지 않는다', () => {
142
- const POLLED = '2026-08-23T00:00:00.000Z'
143
- const SAID = '2026-04-15T07:35:53.000Z'
144
- const { accepted, rejected } = ingestCanonicalRecords(
145
- [{ ...epcisRecord, eventTime: SAID }] as any,
146
- 't',
147
- POLLED
148
- )
149
- assert.deepEqual(rejected, [])
150
- assert.equal(accepted[0].eventTime, SAID, '원본이 말한 시각이어야 한다')
151
- assert.notEqual(accepted[0].eventTime, POLLED, '폴링 시각이 아니어야 한다')
152
- })
153
-
154
- test('레코드가 시각을 말하지 않으면 폴링 시각으로 떨어진다 — 이 한 줄이 기존 경로를 막지 않는다', () => {
155
- /*
156
- * 커널의 경로 해석은 없는 값을 **오류로 만들지 않는다**(§`resolve`). 그래서 시각을 말하지 않는
157
- * 레코드는 예전처럼 기본값을 쓴다. 이 단정이 없으면 위 한 줄이 알리지 않고 대량 거부를 낼 수 있다.
158
- */
159
- const POLLED = '2026-08-23T00:00:00.000Z'
160
- const { accepted, rejected } = ingestCanonicalRecords([epcisRecord] as any, 't', POLLED)
161
- assert.deepEqual(rejected, [])
162
- assert.equal(accepted[0].eventTime, POLLED)
163
- })
164
-
165
- /*
166
- * ── 다섯 번째 어휘 — 발전 적산 (2026-08-28, 커널 0.7.69) ──────────────────────
167
- *
168
- * 커널이 `energy.generated` 를 오래 선언만 하고 있었고, 그 문이 0.7.69 에 열렸다. 그런데 문이 열린
169
- * 것과 길이 난 것은 다르다 — 이 seam 이 발전 적산을 **설비 상태 문으로 보내고 있었다.**
170
- *
171
- * 두 판정이 겹치기 때문이다. `isEnergyEquipmentRecord` 는 `equipmentId` 만 보므로 발전 적산에도
172
- * 참이다. 그래서 순서를 정하지 않으면 적산이 설비 상태 문에 닿고, 그 문은 적산을 값으로 세지 않아
173
- * 「바꿀 상태가 하나도 없다」로 돌려보낸다.
174
- *
175
- * 이 저장소에서 가장 자주 나는 결함 부류다 — 자리는 선언되어 있고 거기까지 가는 길이 없다.
176
- */
177
- const generationRecord = {
178
- equipmentId: 'inv-001',
179
- kWh: 574.8,
180
- kWhSince: '2026-08-13T15:00:00.000Z',
181
- at: '2026-08-14T09:00:30.000Z'
182
- }
183
-
184
- test('발전 적산은 설비 상태가 아니라 자기 문으로 들어온다', () => {
185
- const { accepted, rejected } = ingestCanonicalRecords([generationRecord] as any, 't', NOW)
186
- assert.deepEqual(rejected, [], `거부 없음이어야 한다: ${JSON.stringify(rejected)}`)
187
- assert.equal(accepted.length, 1)
188
- assert.equal(accepted[0].eventType, 'energy.generated', '설비 상태 문으로 가면 여기서 거부됐을 것이다')
189
- })
190
-
191
- test('적산이 쌓이기 시작한 시각이 봉투까지 간다 — 이것이 없으면 자정이 계기 교체로 남는다', () => {
192
- const { accepted } = ingestCanonicalRecords([generationRecord] as any, 't', NOW)
193
- assert.equal((accepted[0].data as any).since, '2026-08-13T15:00:00.000Z')
194
- assert.equal((accepted[0].data as any).kWh, 574.8)
195
- })
196
-
197
- test('기준점을 말하지 않는 원본도 그대로 통과한다 — 없는 칸을 만들지 않는다', () => {
198
- const { accepted, rejected } = ingestCanonicalRecords(
199
- [{ equipmentId: 'inv-002', kWh: 120.5, at: '2026-08-14T09:00:30.000Z' }] as any,
200
- 't',
201
- NOW
202
- )
203
- assert.deepEqual(rejected, [])
204
- assert.equal(accepted[0].eventType, 'energy.generated')
205
- assert.equal((accepted[0].data as any).since, undefined, '말하지 않은 것을 지어내지 않는다')
206
- })
207
-
208
- test('한 배치에 설비 상태와 발전 적산이 섞여도 각자의 문으로 간다', () => {
209
- const { accepted, rejected } = ingestCanonicalRecords(
210
- [{ equipmentId: 'inv-001', generatedKW: 8.2, at: '2026-08-14T09:00:30.000Z' }, generationRecord] as any,
211
- 't',
212
- NOW
213
- )
214
- assert.deepEqual(rejected, [], JSON.stringify(rejected))
215
- assert.deepEqual(accepted.map(e => e.eventType).sort(), ['energy.equipment', 'energy.generated'])
216
- })
217
-
218
- test('★ 상태까지 걷는다 — 자정에 되돌아간 적산이 계기 교체로 남지 않는다', async () => {
219
- /*
220
- * 문이 열린 것과 길이 난 것은 다르다. 그래서 봉투에서 멈추지 않고 **상태까지** 걷는다.
221
- *
222
- * PPMS 인버터의 `acc` 는 하루 누적이다(수집 코드가 전날까지 총량을 빼고, 그 값을 하루 만에
223
- * 만료되는 자리에 둔다). 그래서 자정마다 574.8 → 165.2 로 되돌아간다. 기준점을 말하지 않으면
224
- * 커널이 그것을 계기 교체로 읽고, 「계기 교체가 하루에 한 번 일어난다」가 지난 기록에 남는다.
225
- */
226
- const { EmsKernel } = await import('@operato/twin-kernel')
227
- const k = new EmsKernel('t')
228
- k.loadTwinModel({
229
- locations: [{ id: 'incoming', type: 'incoming', capacity: 0 }],
230
- equipment: [{ id: 'inv-001', kind: 'pv-array', locationId: 'incoming' }]
231
- } as any)
232
-
233
- const send = (kWh: number, since: string | undefined, at: string) => {
234
- const { accepted, rejected } = ingestCanonicalRecords(
235
- [{ equipmentId: 'inv-001', kWh, ...(since ? { kWhSince: since } : {}), at }] as any,
236
- 't',
237
- at
238
- )
239
- assert.deepEqual(rejected, [], JSON.stringify(rejected))
240
- for (const e of accepted) k.apply(e as any)
241
- }
242
- const inverter = () => (k.getSnapshot() as any).equipment.find((e: any) => e.id === 'inv-001')
243
-
244
- /* 첫날 저녁 — 그날 자정부터 574.8kWh */
245
- send(574.8, '2026-08-26T15:00:00.000Z', '2026-08-27T14:37:00.000Z')
246
- assert.equal(inverter().generatedKWh, 574.8, '적산이 상태에 선다')
247
-
248
- /* 다음 날 아침 — 값이 줄었지만 기준점이 나아갔다 */
249
- send(165.2, '2026-08-27T15:00:00.000Z', '2026-08-28T01:12:00.000Z')
250
- const after = inverter()
251
- assert.equal(after.generatedKWh, 165.2)
252
- assert.equal(after.generatedKWhSince, '2026-08-27T15:00:00.000Z', '어느 구간의 적산인지 남는다')
253
- assert.equal(after.generatedKWhResetAt, undefined, '구간이 새로 시작한 것은 계기의 이상이 아니다')
254
- })
255
-
256
- test('기준점 없이 값이 줄면 모른다고 표시한다 — 짐작을 사실로 적지 않는다', async () => {
257
- const { EmsKernel } = await import('@operato/twin-kernel')
258
- const k = new EmsKernel('t')
259
- k.loadTwinModel({
260
- locations: [{ id: 'incoming', type: 'incoming', capacity: 0 }],
261
- equipment: [{ id: 'inv-002', kind: 'pv-array', locationId: 'incoming' }]
262
- } as any)
263
- const send = (kWh: number, at: string) => {
264
- const { accepted } = ingestCanonicalRecords([{ equipmentId: 'inv-002', kWh, at }] as any, 't', at)
265
- for (const e of accepted) k.apply(e as any)
266
- }
267
- send(574.8, '2026-08-27T14:37:00.000Z')
268
- send(165.2, '2026-08-28T01:12:00.000Z')
269
- const eq = (k.getSnapshot() as any).equipment.find((e: any) => e.id === 'inv-002')
270
- assert.ok(eq.generatedKWhResetAt, '되돌아간 사실은 남긴다')
271
- assert.equal(eq.generatedKWhBasis, 'inferred', '그 판정이 짐작이라는 것도 함께 남긴다')
272
- })
273
-
274
- /*
275
- * ── 여섯째·일곱째 어휘 — 사용 구간과 청구서 (2026-08-29, 커널 0.7.72) ──────────
276
- *
277
- * 커널이 문을 열었고, 이 seam 은 또 그 어휘를 몰랐다. 발전 적산 때와 같은 자리다.
278
- *
279
- * 이번 겹침이 더 나쁘다. `isEnergyRecord` 는 `meterId` 가 있으면 참이므로 사용 구간에도 참이다.
280
- * 순서를 정하지 않으면 시간별 사용량이 계량 표본으로 들어가는데, 그 문은 `kWh` 를 적산
281
- * 레지스터로 읽는다. 우리가 넣는 값은 이미 구간의 양이라 차분의 차분이 된다 — **거부되지 않고
282
- * 값만 틀린다.**
283
- */
284
- const usageRecord = {
285
- meterId: 'incoming',
286
- from: '2026-08-28T15:00:00.000Z',
287
- to: '2026-08-28T16:00:00.000Z',
288
- kWh: 474.48,
289
- maxKW: 478.08,
290
- unitPrice: 87.3,
291
- currency: 'KRW',
292
- basis: 'provider'
293
- }
294
- const billRecord = {
295
- from: '2026-06-30T15:00:00.000Z',
296
- to: '2026-07-31T15:00:00.000Z',
297
- demandCharge: 13728000,
298
- currency: 'KRW',
299
- billingDemandKW: 1650
300
- }
301
-
302
- test('★ 사용 구간은 계량 표본이 아니라 자기 문으로 들어온다', () => {
303
- const { accepted, rejected } = ingestCanonicalRecords([usageRecord] as any, 't', NOW)
304
- assert.deepEqual(rejected, [], JSON.stringify(rejected))
305
- assert.equal(accepted.length, 1)
306
- assert.notEqual(accepted[0].eventType, 'energy.measured', '계량 문으로 가면 kWh 가 적산으로 읽힌다')
307
- })
308
-
309
- test('청구서도 자기 문으로 들어온다', () => {
310
- const { accepted, rejected } = ingestCanonicalRecords([billRecord] as any, 't', NOW)
311
- assert.deepEqual(rejected, [], JSON.stringify(rejected))
312
- assert.equal(accepted.length, 1)
313
- assert.notEqual(accepted[0].eventType, 'epcis.ObjectEvent', '물품 관측으로 만들지 않는다')
314
- })
315
-
316
- test('계량 표본은 그대로 계량 문으로 간다 — 이 갈림이 기존 경로를 막지 않는다', () => {
317
- const { accepted, rejected } = ingestCanonicalRecords(
318
- [{ meterId: 'incoming', kW: 1200, at: '2026-08-14T09:00:30.000Z' }] as any,
319
- 't',
320
- NOW
321
- )
322
- assert.deepEqual(rejected, [])
323
- assert.equal(accepted[0].eventType, 'energy.measured')
324
- })
325
-
326
- test('한 배치에 넷이 섞여도 각자의 문으로 간다', () => {
327
- const { accepted, rejected } = ingestCanonicalRecords(
328
- [energyRecord, generationRecord, usageRecord, billRecord] as any,
329
- 't',
330
- NOW
331
- )
332
- assert.deepEqual(rejected, [], JSON.stringify(rejected))
333
- assert.equal(accepted.length, 4, '넷 다 받아들인다')
334
- assert.equal(new Set(accepted.map(e => e.eventType)).size, 4, '넷이 서로 다른 사건이다')
335
- })
336
-
337
- /*
338
- * ── 여덟째 어휘 — 요금 기준 (2026-08-29, 커널 0.7.76) ─────────────────────────
339
- *
340
- * 문이 열렸는데 유입 갈림이 또 몰랐다. 오늘 세 번째다.
341
- */
342
- const tariffBasisRecord = {
343
- from: '2026-07-31T15:00:00.000Z',
344
- to: '2026-08-31T15:00:00.000Z',
345
- billingDemandKW: 1650,
346
- demandChargePerKW: 8320,
347
- currency: 'KRW'
348
- }
349
-
350
- test('★ 요금 기준이 자기 문으로 들어온다', () => {
351
- const { accepted, rejected } = ingestCanonicalRecords([tariffBasisRecord] as any, 't', NOW)
352
- assert.deepEqual(rejected, [], JSON.stringify(rejected))
353
- assert.equal(accepted.length, 1)
354
- assert.equal(accepted[0].eventType, 'energy.tariff.basis')
355
- })
356
-
357
- test('요금 기준의 사건 시각은 기간의 시작이다 — 진행 중인 주기도 미래에 적히지 않는다', () => {
358
- const { accepted } = ingestCanonicalRecords([tariffBasisRecord] as any, 't', NOW)
359
- assert.equal(accepted[0].eventTime, '2026-07-31T15:00:00.000Z', '청구서와 달리 to 가 아니다')
360
- })
361
-
362
- test('요금 기준과 청구서를 섞어도 각자의 문으로 간다', () => {
363
- const { accepted, rejected } = ingestCanonicalRecords([tariffBasisRecord, billRecord] as any, 't', NOW)
364
- assert.deepEqual(rejected, [], JSON.stringify(rejected))
365
- assert.deepEqual(accepted.map(e => e.eventType).sort(), ['energy.bill', 'energy.tariff.basis'])
366
- })
367
-
368
- test('설비의 전기 계측값은 설비 상태 문으로 간다 — 발전 출력이 없어도 받는다', () => {
369
- const { accepted, rejected } = ingestCanonicalRecords(
370
- [{ equipmentId: '002', dcVoltage: 469.13, dcCurrent: 68.7, acVoltage: [377.8, 379.9, 377.7], acCurrent: [37, 37.2, 37] }] as any,
371
- 't',
372
- NOW
373
- )
374
- assert.deepEqual(rejected, [], JSON.stringify(rejected))
375
- assert.equal(accepted[0].eventType, 'energy.equipment')
376
- })
377
-
378
- /* ── 발전 단가가 지나갈 길 (2026-08-30) ────────────────────────────────────
379
- *
380
- * ★ 오늘 다섯 번째다. 커널에 문을 열고 이 갈림에 길을 내지 않으면, 레코드가 아무 문에도
381
- * 들어가지 못하고 조용히 사라진다 — 거부도 되지 않으므로 아무도 모른다.
382
- */
383
- test('발전 단가가 그 문으로 간다', () => {
384
- const r = ingestCanonicalRecords(
385
- [{ from: '2026-08-29T15:00:00.000Z', to: '2026-08-30T15:00:00.000Z', unitPrice: 148.61, currency: 'KRW' }] as any,
386
- 't',
387
- NOW
388
- )
389
- assert.equal(r.rejected.length, 0, `거부되면 안 된다: ${JSON.stringify(r.rejected)}`)
390
- assert.equal(r.accepted.length, 1)
391
- assert.equal((r.accepted[0] as any).eventType, 'energy.generation.price')
392
- assert.equal((r.accepted[0] as any).eventTime, '2026-08-29T15:00:00.000Z', '사건 시각은 기간의 시작이다')
393
- })
394
-
395
- test('★ 단가·사용 구간·요금 기준·청구서가 한 배치에 섞여 와도 각자의 문으로 간다', () => {
396
- const r = ingestCanonicalRecords(
397
- [
398
- { from: '2026-08-29T15:00:00.000Z', to: '2026-08-30T15:00:00.000Z', unitPrice: 148.61, currency: 'KRW' },
399
- { meterId: 'incoming', from: '2026-08-29T15:00:00.000Z', to: '2026-08-29T16:00:00.000Z', kWh: 474.48 },
400
- { from: '2026-07-31T15:00:00.000Z', to: '2026-08-31T15:00:00.000Z', billingDemandKW: 1650, demandChargePerKW: 8320, currency: 'KRW' },
401
- { from: '2026-06-30T15:00:00.000Z', to: '2026-07-31T15:00:00.000Z', demandCharge: 13_728_000, currency: 'KRW' }
402
- ] as any,
403
- 't',
404
- NOW
405
- )
406
- assert.equal(r.rejected.length, 0, JSON.stringify(r.rejected))
407
- const types = (r.accepted as any[]).map(e => e.eventType).sort()
408
- assert.deepEqual(types, ['energy.bill', 'energy.generation.price', 'energy.tariff.basis', 'energy.usage.period'])
409
- })
410
-
411
- /* ── fact type 마다 시각 칸 이름이 다르다 ──────────────────────────────────── */
412
-
413
- test('★ nonconformance 는 decidedAt 을 자기 시각으로 쓴다 — 세 번째로 밟은 자리다', () => {
414
- /*
415
- * [측정함 2026-09-06] backfill 뒤 mes-line-a 의 nonconformance 4건이 event_time == created_at
416
- * 이었다. payload 의 `data.decidedAt` 은 2026-09-01 인데 저장된 시각은 2026-09-05 였다 — 5일 차이.
417
- *
418
- * push 경로에서는 안 보인다. 사실이 나자마자 보내니 몇 초 차이다. backfill 이 그 간격을 벌려서
419
- * 드러냈다.
420
- */
421
- const got = ingestCanonicalRecords(
422
- [{ subjectId: 'LOT-A', decision: 'scrap', decidedAt: '2026-09-01T02:50:51.832Z' }] as any,
423
- 't',
424
- NOW
425
- )
426
- assert.equal(got.accepted[0]?.eventTime, '2026-09-01T02:50:51.832Z', 'ingest 시각으로 떨어졌다')
427
- assert.deepEqual(got.undated, {}, '시각을 읽었으면 세지 않는다')
428
- })
429
-
430
- test('★ 시각을 못 읽으면 그 사실을 센다 — 조용히 지금 시각으로 떨어지지 않는다', () => {
431
- /*
432
- * 오류가 아니다. 절대값 snapshot 은 polling 순간이 맞는 시각이라 여기 세어지는 것이 정상이다.
433
- * 다만 그 수가 어디에도 안 남으면 `event_time == created_at` 이 유일한 단서이고, 그것은 우연히
434
- * 같은 것과 구별되지 않는다.
435
- */
436
- const got = ingestCanonicalRecords(
437
- [{ subjectId: 'LOT-B', decision: 'scrap' }] as any,
438
- 't',
439
- NOW
440
- )
441
- assert.deepEqual(got.undated, { disposition: 1 })
442
- })
443
-
444
- test('공통 이름이 있으면 그것이 이긴다 — 봉투 층의 판단이 가장 바깥이다', () => {
445
- const got = ingestCanonicalRecords(
446
- [{ subjectId: 'L', decision: 'scrap', at: '2026-09-03T00:00:00.000Z', decidedAt: '2026-09-01T00:00:00.000Z' }] as any,
447
- 't',
448
- NOW
449
- )
450
- assert.equal(got.accepted[0]?.eventTime, '2026-09-03T00:00:00.000Z')
451
- })
@@ -1,61 +0,0 @@
1
- /*
2
- * ★ 비직렬 수량이 들어오는 문 — **오류 없이 사라지지 않는다.**
3
- *
4
- * `CanonicalRecord` 에 `quantityList` 자리를 냈다(담김의 `childQuantityList` 가 하루 먼저 같은 이유로
5
- * 받은 자리다). 원본이 「이 자리에 이 품목이 얼마 남았다」를 말할 길이 없어서, 그것이 주된 경로인
6
- * 시스템(식품 제조 MES)은 라이브를 낼 수 없었다.
7
- *
8
- * ── 배포 뒤 (2026-08-21) ────────────────────────────────────────────────────
9
- * 커널 0.7.40 에 `ObjectEventMapping.quantityList` 가 들어와 **수량만 오는 레코드가 통과한다.**
10
- * 그 전까지는 `epcList` 와 `quantityList` 가 둘 다 비어 검증이 거부했고, 이 시험은 그 거부가 **아무 말도 없지
11
- * 않다**(이유와 함께 계수된다)는 것을 지켰다.
12
- *
13
- * 이제 통과 쪽으로 고정한다 — 통과와 거부를 둘 다 받아들이면 다시 막혔을 때 초록으로 남는다.
14
- */
15
- import { test } from 'node:test'
16
- import assert from 'node:assert/strict'
17
-
18
- import { ingestCanonicalRecords } from '../server/engine/canonical-ingest.ts'
19
-
20
- const T0 = '2026-08-20T09:00:00.000Z'
21
- const CLASS = 'https://chef.example.com/class/product-7f3a'
22
-
23
- const qtyRecord = {
24
- action: 'OBSERVE',
25
- bizStep: 'urn:epcglobal:cbv:bizstep:storing',
26
- disposition: 'urn:epcglobal:cbv:disp:sellable_accessible',
27
- quantityList: [{ epcClass: CLASS, quantity: 3.5, uom: 'KGM' }],
28
- readPoint: 'chef-wh:w1',
29
- bizLocation: 'chef-wh:w1'
30
- }
31
-
32
- test('수량만 오는 레코드가 통과하고 수량이 봉투까지 실린다', () => {
33
- const { accepted, rejected } = ingestCanonicalRecords(qtyRecord as any, 'plantA', T0)
34
- assert.deepEqual(rejected, [], `거부됐다 — 커널에 quantityList 자리가 있는지 확인: ${JSON.stringify(rejected)}`)
35
- assert.equal(accepted.length, 1)
36
- /* 자리만 통과하고 값이 빠지면 더 나쁘다 — 실린 줄 알고 잃는다. */
37
- const ev: any = (accepted[0] as any).data ?? (accepted[0] as any).event ?? accepted[0]
38
- assert.deepEqual(ev.quantityList, [{ epcClass: CLASS, quantity: 3.5, uom: 'KGM' }])
39
- assert.deepEqual(ev.epcList, [], '개체가 없으므로 빈 배열이다 — 지어내지 않는다')
40
- })
41
-
42
- test('개체 관측은 그대로 통과한다 — 문을 내면서 기존 길을 막지 않는다', () => {
43
- const { accepted, rejected } = ingestCanonicalRecords(
44
- { epc: 'urn:epc:id:sgtin:9521321.012345.1', action: 'OBSERVE', bizStep: 'urn:epcglobal:cbv:bizstep:storing', readPoint: 'chef-wh:w1' } as any,
45
- 'plantA',
46
- T0
47
- )
48
- assert.equal(rejected.length, 0, `개체 관측이 거부되면 안 된다: ${JSON.stringify(rejected)}`)
49
- assert.equal(accepted.length, 1)
50
- })
51
-
52
- test('개체도 수량도 없으면 거부된다 — 무엇을 관측했는지 말하지 않았다', () => {
53
- const { accepted, rejected } = ingestCanonicalRecords(
54
- { action: 'OBSERVE', bizStep: 'urn:epcglobal:cbv:bizstep:storing', readPoint: 'chef-wh:w1' } as any,
55
- 'plantA',
56
- T0
57
- )
58
- assert.equal(accepted.length, 0)
59
- assert.equal(rejected.length, 1)
60
- assert.ok(rejected[0].errors?.length, '이유 없이 버리지 않는다')
61
- })
@@ -1,89 +0,0 @@
1
- /*
2
- * 커널↔보드 capability 매핑 무결성 — 스트림라인의 척추 검증.
3
- * 커널이 타입별 capability 를 선언(SSOT)하고, 그 능력의 관측 상태필드가 data(tag) payload 로 흘러
4
- * 보드 컴포넌트에 도달한다. 이 브릿지가 끊기면 모니터링이 성립 안 한다.
5
- *
6
- * 여기서 검증하는 절반 = 커널→payload(Node 로 완결). 나머지 절반(payload→컴포넌트 렌더)은 클라 하네스.
7
- */
8
- import { test } from 'node:test'
9
- import assert from 'node:assert/strict'
10
-
11
- import { DOMAIN_CATALOG, CAPABILITIES, CAPABILITY_KEYS, capabilitiesForType, stateFieldsOf } from '@operato/ops-contract'
12
- import { buildEntityDeltas } from '../shared/entity-delta.ts'
13
-
14
- const SYSTEMS = ['wms', 'yms', 'mes'] as const
15
-
16
- test('카탈로그 무결성: 모든 타입의 capability 가 정의된 능력집합에 속함 (dangling/오타 0)', () => {
17
- for (const sys of SYSTEMS) {
18
- for (const t of DOMAIN_CATALOG[sys].types) {
19
- assert.ok(Array.isArray(t.capabilities), `${sys}/${t.key} capabilities 배열`)
20
- for (const c of t.capabilities) {
21
- assert.ok(CAPABILITY_KEYS.includes(c), `${sys}/${t.key}: '${c}' 는 정의된 능력`)
22
- }
23
- }
24
- }
25
- })
26
-
27
- test('capabilitiesForType: 타입→능력 해소(SSOT)', () => {
28
- assert.deepEqual(capabilitiesForType('wms', 'storage'), ['storable'], 'storage=storable')
29
- assert.ok(capabilitiesForType('wms', 'forklift').includes('mobile'), 'forklift 는 mobile')
30
- assert.ok(capabilitiesForType('wms', 'forklift').includes('operable'), 'forklift 는 operable')
31
- assert.deepEqual(capabilitiesForType('wms', '__nope__'), [], '미지 타입 → []')
32
- })
33
-
34
- test('능력 정의 완전성 + 직교(어느 상태필드도 두 능력에 중복 없음)', () => {
35
- const seen = new Map<string, string>()
36
- for (const k of CAPABILITY_KEYS) {
37
- assert.ok(CAPABILITIES[k], `${k} 정의 존재`)
38
- assert.ok(CAPABILITIES[k].stateFields.length > 0, `${k} stateFields ≥1`)
39
- for (const f of CAPABILITIES[k].stateFields) {
40
- assert.ok(!seen.has(f), `상태필드 '${f}' 직교 위반: ${seen.get(f)} & ${k}`)
41
- seen.set(f, k)
42
- }
43
- }
44
- })
45
-
46
- test('능력 소싱 구조: 4 자원/위치 능력은 카탈로그 타입에서, trackable 은 런타임 오더에서', () => {
47
- // 매핑 구조: 노드/무버 타입은 카탈로그가 capability 를 선언(정적 소싱).
48
- // trackable(오더/아이템 생애)은 런타임 생성 엔티티라 타입 카탈로그에 없고,
49
- // board-placement-twin-provider 가 __orders__ 집약에 직접 부여(런타임 소싱). 이 분리가 매핑의 실제 구조.
50
- const usedByType = new Set<string>()
51
- for (const sys of SYSTEMS) for (const t of DOMAIN_CATALOG[sys].types) for (const c of t.capabilities) usedByType.add(c)
52
-
53
- // 카탈로그가 쓰는 능력은 모두 정의됨(dangling 0)
54
- for (const c of usedByType) assert.ok(CAPABILITY_KEYS.includes(c as any), `카탈로그 사용 능력 '${c}' 정의됨`)
55
-
56
- // 4 자원/위치 능력은 각기 최소 1 타입에서 사용(죽은 정의 감지)
57
- for (const k of ['operable', 'storable', 'mobile', 'processable'] as const) {
58
- assert.ok(usedByType.has(k), `'${k}' 는 최소 1 카탈로그 타입에서 사용`)
59
- }
60
- // trackable 은 타입 카탈로그에 없음 = 런타임(오더) 스코프임을 명시 (고아가 아니라 다른 소싱 경로)
61
- assert.ok(!usedByType.has('trackable'), 'trackable 은 타입 카탈로그가 아니라 런타임 오더(__orders__)에서 소싱')
62
- })
63
-
64
- test('★ 스트림라인 브릿지: 능력의 상태필드가 라이브 payload 에 실림 (커널→보드 도달)', () => {
65
- // storable 노드 → occupancy/capacity (+ operable status)
66
- const nodeD: any = buildEntityDeltas({ locations: [{ id: 'n', type: 'storage', occupancy: 2, capacity: 9, status: 'idle' }] }, 't1')[0].data
67
- for (const f of stateFieldsOf(['storable'])) assert.ok(f in nodeD, `storable payload.${f}`)
68
- assert.ok('status' in nodeD, 'operable(노드 status) payload')
69
-
70
- // mobile+operable 무버 → location/motion/status
71
- const equipmentD: any = buildEntityDeltas({ equipment: [{ id: 'm', kind: 'forklift', location: 'n', status: 'busy', motion: { toNode: 'n2', progress: 0.3 } }] }, 't1').find(x => x.tag === 'm')!.data
72
- for (const f of stateFieldsOf(['mobile'])) assert.ok(f in equipmentD, `mobile payload.${f}`)
73
- for (const f of stateFieldsOf(['operable'])) assert.ok(f in equipmentD, `operable payload.${f}`)
74
-
75
- // trackable 오더 → progress/held (lifecycle 은 payload 에서 'status' 로 표면화 — 이름-매핑 시임)
76
- const orderD: any = buildEntityDeltas({ orders: [{ id: 'o', status: 'picking', progress: 0.5, held: false }] }, 't1').find(x => x.tag === 'o')!.data
77
- assert.ok('progress' in orderD && 'held' in orderD, 'trackable progress/held payload')
78
- assert.ok('status' in orderD, 'trackable lifecycle → payload.status (이름-매핑)')
79
- })
80
-
81
- test('시임 문서화 · processable output(양품/불량)은 payload oee.good/scrap 으로 표면화', () => {
82
- // 계약 stateField = 'output' 이나, 라이브 payload 는 이를 oee(정수%+good/scrap)로 집약해 표면화.
83
- const d: any = buildEntityDeltas({
84
- equipment: [{ id: 'c', kind: 'cutter', status: 'busy', oee: { overall: 0.8, availability: 0.9, performance: 0.9, quality: 0.98, goodCount: 10, nonconformingCount: 1 } }]
85
- }, 't1').find(x => x.tag === 'c')!.data
86
- assert.ok(d.oee, 'processable → payload.oee 존재')
87
- assert.equal(d.oee.good, 10, 'output.good = oee.good')
88
- assert.equal(d.oee.scrap, 1, 'output.scrap = oee.scrap')
89
- })