@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,226 +0,0 @@
1
- /*
2
- * 구조 투영 — `TwinModelDef`(커널 입력 문서) → **표준 엔티티 행**(ADR-0032).
3
- *
4
- * ── 왜 DB 검사인가 ─────────────────────────────────────────────────────────
5
- * 이 코드의 값어치는 **DB 가 대신 지켜 주는 것**에 있다 — 끊어진 참조를 FK 가 막고, 원본 없는 행을
6
- * NOT NULL 이 막는다. 순수 함수 검사로는 그게 하나도 확인되지 않는다. 그래서 실제 DataSource 를
7
- * 세운다(멀티DB 규약상 sqlite 로 도는 것이 5개 드라이버 공통의 최소선이기도 하다).
8
- *
9
- * ── 이 검사가 지키는 것 ────────────────────────────────────────────────────
10
- * · 문서의 세 축이 행으로 선다
11
- * · 설비→자리가 **진짜 FK** 로 이어진다(문자열 대조가 아니라)
12
- * · 끊어진 참조는 **이름을 대고 보고**되고, 행 자체는 남는다(막지 않되 침묵하지 않는다)
13
- * · **전량 교체** — 두 번 돌려도 늘지 않고, 원본에서 사라진 것은 행에서도 사라진다
14
- * · 원본 표식(`sourceRef`·`ingestedAt`) 없는 행은 만들 수 없다(캐시라는 사실이 구조로 지켜진다)
15
- * · 소요시간은 ISO 8601 **문자열 그대로** 남는다(분으로 줄이면 초가 오류 없이 사라진다)
16
- */
17
- import { test, before, after, beforeEach } from 'node:test'
18
- import assert from 'node:assert/strict'
19
- import { createRequire } from 'node:module'
20
- import type { DataSource } from 'typeorm'
21
-
22
- const req = createRequire(import.meta.url)
23
- const { NamingStrategy, addDataSource, entities: shellEntities, Domain } = req('@things-factory/shell')
24
- const { entities: authEntities } = req('@things-factory/auth-base')
25
- const { entities: twinEntities } = req('../dist-server/service/index.js')
26
- const { projectStructure } = req('../dist-server/service/twin-model/project-structure.js')
27
- const { TwinInstance } = req('../dist-server/service/twin-instance/twin-instance.js')
28
- const { TwinSpace } = req('../dist-server/service/twin-space/twin-space.js')
29
- const { TwinArea } = req('../dist-server/service/twin-space/twin-area.js')
30
- const { TwinLocation } = req('../dist-server/service/twin-model/twin-location.js')
31
- const { TwinEquipment } = req('../dist-server/service/twin-model/twin-equipment.js')
32
- const { TwinOperation } = req('../dist-server/service/twin-model/twin-operation.js')
33
- const { DataSource: TypeOrmDataSource } = req('typeorm')
34
-
35
- let ds: DataSource
36
- let domainId: string
37
-
38
- const INSTANCE = 'projection-probe'
39
- const SOURCE = 'projection-probe'
40
-
41
- /** 실제 트레일러 트윈과 같은 모양의 문서(축소판). */
42
- const model = () => ({
43
- locations: [
44
- { id: 'cut-station', type: 'cut-station', name: '프레임 절단', capacity: 20, parentId: 'a-floor' },
45
- { id: 'weld-station', type: 'weld-station', capacity: 20, parentId: 'a-floor' },
46
- { id: 'orphan-bin', type: 'storage', capacity: 5, parentId: 'no-such-area' }
47
- ],
48
- equipment: [
49
- { id: 'cutter-1', kind: 'cutter', name: '절단기 1호', homeLocation: 'cut-station', mtbfMs: 3600000,
50
- properties: [{ id: 'speed', value: '1.2', dataType: 'xs:double', uom: 'MTS' }] },
51
- { id: 'welder-1', kind: 'welder', homeLocation: 'weld-station' },
52
- { id: 'ghost-1', kind: 'welder', homeLocation: 'no-such-location' }
53
- ],
54
- operations: [
55
- { key: 'cut', label: 'twin.tpl.x.cut', intent: 'process', locationType: 'cut-station', resourceType: 'cutter',
56
- duration: 'PT1H10M30S', variability: { distribution: 'triangular', min: 'PT1H', max: 'PT1H30M' },
57
- parameters: [{ id: 'yield', value: '0.995' }],
58
- /* 네 자원 명세 — 설비는 `resourceType`, 나머지 셋은 아래. */
59
- personnelSpecification: [{ personnelClass: 'cutter-op', quantity: 1 }],
60
- physicalAssetSpecification: [{ assetClass: 'jig', quantity: 1 }],
61
- materialSpecification: [{ materialDefinition: 'steel', use: 'consumed', quantity: 2 }] }
62
- ]
63
- })
64
-
65
- before(async () => {
66
- ds = new TypeOrmDataSource({
67
- type: 'sqlite',
68
- database: ':memory:',
69
- synchronize: true,
70
- dropSchema: true,
71
- namingStrategy: new NamingStrategy(),
72
- entities: [...shellEntities, ...authEntities, ...twinEntities],
73
- logging: false
74
- })
75
- await ds.initialize()
76
- addDataSource('default', ds)
77
- const d = await ds.getRepository(Domain).save({ name: 'projection-test', subdomain: 'projection-test' } as any)
78
- domainId = d.id
79
-
80
- await ds.getRepository(TwinInstance).save({
81
- domain: { id: domainId },
82
- instanceId: INSTANCE,
83
- kind: 'mes',
84
- restartPolicy: 'reset',
85
- purpose: 'operational',
86
- status: 'stopped',
87
- model: {}
88
- } as any)
89
-
90
- /* 구역은 model 밖(호스트 개념) — 자리가 FK 로 이걸 가리킨다. */
91
- const space = await ds.getRepository(TwinSpace).save({ domain: { id: domainId }, spaceId: 'sp-1', name: '공장' } as any)
92
- await ds.getRepository(TwinArea).save({ domain: { id: domainId }, space: { id: space.id }, areaId: 'a-floor', name: '생산 플로어' } as any)
93
- })
94
-
95
- after(async () => {
96
- await ds?.destroy()
97
- })
98
-
99
- beforeEach(async () => {
100
- await projectStructure(domainId, INSTANCE, model(), SOURCE)
101
- })
102
-
103
- test('문서의 세 축이 행으로 선다', async () => {
104
- assert.equal(await ds.getRepository(TwinLocation).count(), 3)
105
- assert.equal(await ds.getRepository(TwinEquipment).count(), 3)
106
- assert.equal(await ds.getRepository(TwinOperation).count(), 1)
107
- })
108
-
109
- test('설비→자리가 진짜 FK 로 이어진다 — 문자열 대조가 아니다', async () => {
110
- const eq = await ds.getRepository(TwinEquipment).findOne({ where: { equipmentId: 'cutter-1' }, relations: ['homeLocation'] })
111
- assert.equal(eq?.homeLocation?.locationId, 'cut-station', 'FK 로 자리를 따라갈 수 있어야 한다')
112
- /* 자리 쪽에서도 같은 행이다 — 문자열이었으면 같은 값이지만 같은 행은 아니다. */
113
- const loc = await ds.getRepository(TwinLocation).findOne({ where: { locationId: 'cut-station' } })
114
- assert.equal(eq?.homeLocation?.id, loc?.id)
115
- })
116
-
117
- test('자리→구역이 FK 로 이어진다 — 커널이 "밖" 이라 부른 참조가 호스트에서는 평범한 FK 다', async () => {
118
- const loc = await ds.getRepository(TwinLocation).findOne({ where: { locationId: 'cut-station' }, relations: ['area'] })
119
- assert.equal(loc?.area?.areaId, 'a-floor')
120
- })
121
-
122
- test('끊어진 참조는 이름을 대고 보고된다 — 막지 않되 침묵하지 않는다', async () => {
123
- const report = await projectStructure(domainId, INSTANCE, model(), SOURCE)
124
- assert.deepEqual(report.unresolvedHome, ['ghost-1→no-such-location'])
125
- assert.deepEqual(report.unresolvedArea, ['orphan-bin→no-such-area'])
126
-
127
- /* 행 자체는 남는다 — 참조 하나 때문에 설비가 통째로 사라지면 그게 더 나쁜 거짓말이다. */
128
- const ghost = await ds.getRepository(TwinEquipment).findOne({ where: { equipmentId: 'ghost-1' }, relations: ['homeLocation'] })
129
- assert.ok(ghost, '끊어진 참조를 가진 설비도 행으로 남는다')
130
- assert.equal(ghost?.homeLocation, null, '이을 수 없는 참조는 비운다(엉뚱한 자리에 붙이지 않는다)')
131
- })
132
-
133
- test('전량 교체 — 두 번 돌려도 늘지 않는다', async () => {
134
- await projectStructure(domainId, INSTANCE, model(), SOURCE)
135
- await projectStructure(domainId, INSTANCE, model(), SOURCE)
136
- assert.equal(await ds.getRepository(TwinLocation).count(), 3)
137
- assert.equal(await ds.getRepository(TwinEquipment).count(), 3)
138
- })
139
-
140
- test('원본에서 사라진 것은 행에서도 사라진다 — 캐시는 원본을 따라간다', async () => {
141
- const shrunk = model()
142
- shrunk.locations = shrunk.locations.filter(l => l.id !== 'weld-station')
143
- shrunk.equipment = shrunk.equipment.filter(m => m.id !== 'welder-1')
144
- await projectStructure(domainId, INSTANCE, shrunk, SOURCE)
145
- assert.equal(await ds.getRepository(TwinLocation).count(), 2)
146
- assert.equal(await ds.getRepository(TwinEquipment).count(), 2)
147
- assert.equal(await ds.getRepository(TwinLocation).countBy({ locationId: 'weld-station' } as any), 0)
148
- })
149
-
150
- test('원본 표식 없는 행은 만들 수 없다 — 캐시라는 사실이 구조로 지켜진다', async () => {
151
- await assert.rejects(
152
- () =>
153
- ds.getRepository(TwinLocation).save({
154
- domain: { id: domainId },
155
- locationId: 'no-origin',
156
- type: 'storage'
157
- /* sourceRef · ingestedAt 없음 */
158
- } as any),
159
- /NOT NULL|constraint/i,
160
- '출처 없는 행이 들어가면 "원본에서 온 캐시" 라는 규율이 구조로는 안 지켜지는 것이다'
161
- )
162
- })
163
-
164
- test('소요시간은 ISO 8601 문자열 그대로 — 분으로 줄이면 초가 오류 없이 사라진다', async () => {
165
- const op = await ds.getRepository(TwinOperation).findOne({ where: { operationKey: 'cut' } })
166
- assert.equal(op?.duration, 'PT1H10M30S')
167
- /* 변동성·파라미터는 도메인마다 형이 달라 원형 그대로 싣는다. */
168
- assert.equal(op?.variability?.distribution, 'triangular')
169
- assert.deepEqual(op?.parameters, [{ id: 'yield', value: '0.995' }])
170
- })
171
-
172
- test('등록되지 않은 트윈에는 투영하지 않는다 — 주인 없는 행을 만들지 않는다', async () => {
173
- await assert.rejects(() => projectStructure(domainId, 'not-registered', model(), SOURCE), /not registered/)
174
- })
175
-
176
- test('네 자원 명세가 함께 옮겨진다 — 선언한 것만 제약이 되므로 빠지면 화면이 거짓이 된다', async () => {
177
- /*
178
- * ISA-95 는 공정이 무엇을 필요로 하는지를 넷으로 말한다: 설비·인원·자산·자재. 셋이 투영에서
179
- * 떨어져 있어서, 조회 화면이 "원본이 말한 값" 이라 적고도 넷 중 하나만 보였다 — 사람이 필요한
180
- * 공정을 보고 **사람이 필요 없다고 결론 내게** 되어 있었다.
181
- */
182
- const op = await ds.getRepository(TwinOperation).findOne({ where: { operationKey: 'cut' } })
183
- assert.deepEqual(op?.personnelSpecification, [{ personnelClass: 'cutter-op', quantity: 1 }], '인원 명세가 행에 남아야 한다')
184
- assert.deepEqual(op?.physicalAssetSpecification, [{ assetClass: 'jig', quantity: 1 }], '자산 명세도 남아야 한다')
185
- assert.deepEqual(op?.materialSpecification, [{ materialDefinition: 'steel', use: 'consumed', quantity: 2 }], '자재 명세도 남아야 한다')
186
- })
187
-
188
- test('이름이 행까지 온다 — 이름이 없으면 화면에 id 만 남는다', async () => {
189
- /*
190
- * 투영이 마스터의 `name` 을 버리고 있었다. 행에 이름이 없으면 어떤 화면도 이름을 만들 수 없어서
191
- * 목록·표·관계 그림이 모두 `cut-station` 을 찍었다 — 표면마다 따로 보이지만 결함은 여기 하나다.
192
- */
193
- const loc = await ds.getRepository(TwinLocation).findOne({ where: { domain: { id: domainId } as any, locationId: 'cut-station' } as any })
194
- assert.equal(loc!.name, '프레임 절단', '자리의 이름이 행에 실려야 한다')
195
-
196
- const eq = await ds.getRepository(TwinEquipment).findOne({ where: { domain: { id: domainId } as any, equipmentId: 'cutter-1' } as any })
197
- assert.equal(eq!.name, '절단기 1호', '설비의 이름이 행에 실려야 한다')
198
-
199
- /* 공정은 마스터가 `label` 로 말한다 — 행에서는 규약의 이름으로 둔다(어휘를 하나로). */
200
- const op = await ds.getRepository(TwinOperation).findOne({ where: { domain: { id: domainId } as any, operationKey: 'cut' } as any })
201
- assert.equal(op!.name, 'twin.tpl.x.cut', '공정의 이름이 행에 실려야 한다')
202
-
203
- /* **이름 없는 원본은 이름 없이 남는다** — id 를 이름으로 베끼면 "이름이 있다" 는 거짓이 되고,
204
- 화면은 이름 없음을 알아볼 수 없게 된다. */
205
- const noname = await ds.getRepository(TwinLocation).findOne({ where: { domain: { id: domainId } as any, locationId: 'weld-station' } as any })
206
- assert.equal(noname!.name ?? null, null, '원본이 이름을 말하지 않았으면 비어 있어야 한다')
207
- })
208
-
209
- test('자원 속성이 행까지 온다 — 소비처가 실제로 읽는 사실이다(주행 속도)', async () => {
210
- /*
211
- * 모델에는 있는데 행에 자리가 없어 투영이 흘리고 있었다. 그러면 조회 화면은 "원본이 말한 값" 이라
212
- * 적고도 속성을 못 보인다 — 이름이 같은 식으로 사라졌던 것과 같은 부류다.
213
- *
214
- * 단위를 값과 함께 담는지도 본다: 단위 없는 "1.2" 는 초속인지 시속인지 말하지 않는다.
215
- */
216
- const eq = await ds.getRepository(TwinEquipment).findOne({ where: { domain: { id: domainId } as any, equipmentId: 'cutter-1' } as any })
217
- const props = (eq!.properties ?? []) as any[]
218
- assert.equal(props.length, 1, '선언한 속성이 행에 실려야 한다')
219
- assert.equal(props[0].id, 'speed')
220
- assert.equal(props[0].value, '1.2')
221
- assert.equal(props[0].uom, 'MTS', '단위가 값과 함께 남아야 한다')
222
-
223
- /* 선언하지 않은 자원은 **비어 있다** — 빈 배열로 "선언했다" 고 말하지 않는다. */
224
- const noneProps = await ds.getRepository(TwinEquipment).findOne({ where: { domain: { id: domainId } as any, equipmentId: 'welder-1' } as any })
225
- assert.equal(noneProps!.properties ?? null, null)
226
- })
@@ -1,277 +0,0 @@
1
- /*
2
- * 선언 적합성(투영 편) — **모델이 말한 사실은 행에 남고, 행에 남은 것은 화면까지 간다.**
3
- *
4
- * ── 왜 필요한가 ─────────────────────────────────────────────────────────────
5
- * 같은 이름의 하네스가 두 벌 있다. 커널 편은 *선언 ⊆ 상태* 를 지키고(kernel/declaration-in-state),
6
- * 경계 편은 *원본 → 모델* 을 지킨다(declaration-reaches-model). 그런데 사실이 새던 구간은 **셋**이었고,
7
- * 남은 하나가 이것이다: **모델 → DB 행 → 조회 응답.**
8
- *
9
- * 여기서 잃은 것들: 자리·설비의 이름(화면이 `cut-station` 을 찍었다) · GS1 참조 · 자원 속성 ·
10
- * 시험 명세 참조 · 시험 결과. 전부 **투영 함수의 한 줄이 빠진** 것이었고, 그때는 사람이 하나씩 찾았다.
11
- *
12
- * 타입 검사는 못 잡는다: 컬럼이 거의 다 `nullable` 이라 **안 채우는 것이 합법**이다.
13
- *
14
- * ── 무엇이 기준인가 ─────────────────────────────────────────────────────────
15
- * **엔티티의 컬럼**이다(TypeORM 메타데이터에서 실행 중에 읽는다 — 손으로 적지 않는다). 컬럼이 있다는
16
- * 것은 "이 사실이 여기 앉는다" 는 선언이고, 앉을 자리를 만들어 두고 안 채우면 그 컬럼은 영원히 빈다.
17
- *
18
- * 그래서 컬럼마다 셋을 요구한다:
19
- * ① 픽스처가 모델에 그 값을 싣는다(값을 줄 방법을 모르면 **검사가 실패한다** — 알리지 않고 건너뛰면
20
- * 그 컬럼은 아무도 안 보는 컬럼이 된다)
21
- * ② 투영을 지나 행에 남는다
22
- * ③ 조회 응답에 나온다(화면이 읽는 자리)
23
- *
24
- * 기반 컬럼(id·관계·감사·출처)은 모델이 말하는 사실이 아니므로 이유와 함께 뺀다.
25
- */
26
- import { test, before, after } from 'node:test'
27
- import assert from 'node:assert/strict'
28
- import { createRequire } from 'node:module'
29
- import type { DataSource } from 'typeorm'
30
-
31
- const req = createRequire(import.meta.url)
32
- const { NamingStrategy, addDataSource, entities: shellEntities, Domain, getRepository } = req('@things-factory/shell')
33
- const { entities: authEntities } = req('@things-factory/auth-base')
34
- const { entities: twinEntities } = req('../dist-server/service/index.js')
35
- const { TwinEngine } = req('../dist-server/engine/index.js')
36
- const { TwinModelItemQuery } = req('../dist-server/service/twin-model/twin-model-item-query.js')
37
- const { TwinLocation } = req('../dist-server/service/twin-model/twin-location.js')
38
- const { TwinEquipment } = req('../dist-server/service/twin-model/twin-equipment.js')
39
- const { TwinOperation } = req('../dist-server/service/twin-model/twin-operation.js')
40
- const { DataSource: TypeOrmDataSource } = req('typeorm')
41
-
42
- let ds: DataSource
43
- let domainId: string
44
- let q: any
45
- let ctx: any
46
-
47
- const INSTANCE = 'projection-probe'
48
-
49
- /**
50
- * 모델이 말하는 사실이 **아닌** 컬럼 — 이유와 함께.
51
- *
52
- * 비어 있으면 안 된다: 여기 적지 않으면 검사가 그 컬럼에 값을 요구하고, 그것은 틀린 요구다.
53
- * 반대로 여기에 슬쩍 올리면 감시가 사라지므로 **이유를 함께 적는다**(리뷰가 볼 자리다).
54
- */
55
- const NOT_FROM_MODEL: Record<string, string> = {
56
- id: '행의 열쇠 — 모델이 정하지 않는다(DB 가 발급한다)',
57
- locationId: '개체 식별자 — 대조의 열쇠라 값 비교에서 뺀다(존재는 조회로 이미 확인한다)',
58
- equipmentId: '같음',
59
- operationKey: '같음',
60
- sourceRef: '어디서 왔나 — 투영이 남기는 근거다(모델의 사실이 아니라 옮긴 행위의 기록)',
61
- ingestedAt: '언제 옮겼나 — 같은 이유',
62
- seq: '문서의 차례 — 투영이 넣는 내부 컬럼이다(원본이 말한 값이 아니다)'
63
- }
64
-
65
- /** 컬럼별 값 — 이름으로 준다. 여기 없는 컬럼이 검사 대상에 들면 하네스가 실패한다. */
66
- const VALUE: Record<string, unknown> = {
67
- name: '절단 스테이션',
68
- description: '강판을 자르는 자리',
69
- type: 'cut-station',
70
- kind: 'cutter',
71
- capacity: 40,
72
- parallelism: 2,
73
- level: 'WorkCenter',
74
- gs1Id: 'urn:epc:id:sgln:0614141.00001.0',
75
- /*
76
- * 설비의 정체성 — **GS1 키가 아닌 것이 정상이다.** 실측한 값은 인버터의 하드웨어 식별자다
77
- * (`ES100000007d8d061d-1`). 자리의 `gs1Id`(SGLN)와 다른 축이라 이름도 다르다.
78
- */
79
- identity: 'ES100000007d8d061d-1',
80
- homeLocation: 'cut-station',
81
- mtbfMs: 600000,
82
- mttrMs: 60000,
83
- properties: [{ id: 'speed', value: '1.2', dataType: 'xs:double', uom: 'MTS' }],
84
- testSpecificationIds: ['cut-cert'],
85
- testResults: [{ specId: 'cut-cert', result: 'pass', expiresAt: '2099-01-01T00:00:00.000Z' }],
86
- intent: 'process',
87
- locationType: 'cut-station',
88
- resourceType: 'cutter',
89
- duration: 'PT25M',
90
- variability: { distribution: 'triangular', min: 'PT20M', max: 'PT35M', mode: 'PT24M' },
91
- parameters: [{ id: 'yield', value: '0.98' }],
92
- personnelSpecification: [{ personnelClass: 'cutter-op', quantity: 1 }],
93
- equipmentSpecification: [{ equipmentClass: 'cutter', quantity: 1 }],
94
- physicalAssetSpecification: [{ assetClass: 'euro-pallet', quantity: 1 }],
95
- materialSpecification: [{ material: 'steel', quantity: 1 }],
96
- label: '프레임 절단'
97
- }
98
-
99
- interface Case {
100
- axis: 'locations' | 'equipment' | 'operations'
101
- entity: any
102
- /** 행에서 그 개체를 찾는 컬럼 — 조회가 쓰는 것과 같은 이름이어야 한다(§ROW_BACKED). */
103
- idColumn: string
104
- id: string
105
- }
106
-
107
- const CASES: Case[] = [
108
- { axis: 'locations', entity: TwinLocation, idColumn: 'locationId', id: 'cut-station' },
109
- { axis: 'equipment', entity: TwinEquipment, idColumn: 'equipmentId', id: 'cutter-1' },
110
- { axis: 'operations', entity: TwinOperation, idColumn: 'operationKey', id: 'cut' }
111
- ]
112
-
113
- /**
114
- * 그 엔티티에서 **모델이 채워야 하는 컬럼** — TypeORM 메타데이터에서 읽는다(손으로 적지 않는다).
115
- * 관계·관계 id·감사 컬럼은 기반이므로 뺀다(그 판정은 조회가 쓰는 규칙과 같은 근거를 쓴다).
116
- */
117
- function watchedColumns(entity: any): string[] {
118
- const meta = getRepository(entity).metadata
119
- const infra = new Set<string>(['createdAt', 'updatedAt', 'creator', 'updater', 'creatorId', 'updaterId'])
120
- for (const rel of meta.relations) {
121
- infra.add(rel.propertyName)
122
- for (const jc of rel.joinColumns) infra.add(jc.propertyName)
123
- }
124
- for (const rid of meta.relationIds) infra.add(rid.propertyName)
125
- return meta.columns
126
- .map((c: any) => c.propertyName as string)
127
- .filter((n: string) => !infra.has(n) && !(n in NOT_FROM_MODEL))
128
- .sort()
129
- }
130
-
131
- /** 모든 감시 컬럼에 값을 실은 마스터. */
132
- function master(): any {
133
- const fill = (c: Case): Record<string, unknown> => {
134
- const o: Record<string, unknown> = {}
135
- for (const col of watchedColumns(c.entity)) {
136
- assert.ok(
137
- col in VALUE,
138
- `픽스처가 "${c.axis}.${col}" 에 실을 값을 모른다 — VALUE 에 하나 적어라(모델의 사실이 아니면 NOT_FROM_MODEL 에 이유와 함께).\n` +
139
- '알리지 않고 건너뛰면 그 컬럼은 아무도 안 보는 컬럼이 되고, 그것이 이 하네스가 막으려는 실패다.'
140
- )
141
- o[col] = VALUE[col]
142
- }
143
- return o
144
- }
145
- const loc = fill(CASES[0])
146
- const eq = fill(CASES[1])
147
- const op = fill(CASES[2])
148
- return {
149
- source: INSTANCE,
150
- system: 'mes',
151
- siteName: '투영 공장',
152
- space: { spaceId: 'projection-site', width: 60, depth: 40, unit: 'm' },
153
- locations: [
154
- { id: CASES[0].id, role: 'location', ...loc },
155
- { id: 'fg-store', type: 'fg-store', role: 'location', name: '완제품', capacity: 100 }
156
- ],
157
- /* 경계에서 이름이 바뀌는 것은 하나다(`homeLocationId → homeLocation`) — 경계 편 하네스가 지킨다. */
158
- equipment: [{ id: CASES[1].id, ...eq, homeLocationId: CASES[0].id }],
159
- testSpecifications: [{ id: 'cut-cert', name: '절단 자격' }],
160
- personnelClasses: [{ id: 'cutter-op', description: 'twin.tpl.test.class.cutter-op' }],
161
- assetClasses: [{ id: 'euro-pallet' }],
162
- operations: [{ key: CASES[2].id, ...op }],
163
- productionSpec: {
164
- companyPrefix: '0614141',
165
- binding: { steel: '077101' },
166
- definition: {
167
- materials: [{ id: 'steel' }],
168
- routes: [{ key: 'r', steps: [CASES[2].id] }],
169
- recipes: [{ key: 'rc', label: '프레임', route: 'r', inputs: [{ material: 'steel', qty: 1 }], outputs: [{ material: 'steel', qty: 1 }] }]
170
- }
171
- }
172
- }
173
- }
174
-
175
- before(async () => {
176
- ds = new TypeOrmDataSource({
177
- type: 'sqlite',
178
- database: ':memory:',
179
- synchronize: true,
180
- dropSchema: true,
181
- namingStrategy: new NamingStrategy(),
182
- entities: [...shellEntities, ...authEntities, ...twinEntities],
183
- logging: false
184
- })
185
- await ds.initialize()
186
- addDataSource('default', ds)
187
- const d = await ds.getRepository(Domain).save({ name: 'projection-test', subdomain: 'projection-test' } as any)
188
- domainId = d.id
189
- q = new TwinModelItemQuery()
190
- ctx = { state: { domain: { id: domainId } } }
191
-
192
- await TwinEngine.ingestMaster(domainId, master(), 'reset')
193
- })
194
-
195
- after(async () => {
196
- await TwinEngine.stop(domainId, INSTANCE).catch(() => {})
197
- await ds?.destroy()
198
- })
199
-
200
- test('감시할 컬럼이 비어 있지 않다 — 비면 이 하네스는 아무것도 지키지 않는다', () => {
201
- for (const c of CASES) {
202
- const cols = watchedColumns(c.entity)
203
- assert.ok(cols.length > 2, `${c.axis}: 감시 컬럼을 못 읽었다(${cols.length}개) — 메타데이터 읽기가 낡았다`)
204
- }
205
- })
206
-
207
- for (const c of CASES) {
208
- test(`${c.axis}: 모델이 말한 사실이 행에 남는다 — 투영이 버리지 않는다`, async () => {
209
- const row: any = await getRepository(c.entity).findOne({
210
- where: { domain: { id: domainId } as any, [c.idColumn]: c.id } as any
211
- })
212
- assert.ok(row, `${c.axis} "${c.id}" 행이 없다 — 사실 하나가 아니라 개체가 사라졌다`)
213
-
214
- const lost = watchedColumns(c.entity).filter(col => row[col] === null || row[col] === undefined)
215
- assert.deepEqual(
216
- lost,
217
- [],
218
- `${c.axis}: 모델은 말했는데 행에 없는 사실 [${lost}] — 투영이 버렸다.\n` +
219
- '컬럼이 있다는 것은 "이 사실이 여기 앉는다" 는 선언이다 — 앉을 자리를 두고 안 채우면 영원히 빈다.'
220
- )
221
- })
222
-
223
- test(`${c.axis}: 행에 남은 사실이 화면까지 간다 — 조회가 감추지 않는다`, async () => {
224
- const it = await q.twinModelItem(INSTANCE, c.axis, c.id, ctx)
225
- assert.ok(it?.declared, `${c.axis} "${c.id}" 항목이 열리지 않았다`)
226
- assert.equal(it.provenance?.basis, 'rows', '행에서 답해야 이 검사가 그 구간을 지킨다')
227
-
228
- const hidden = watchedColumns(c.entity).filter(col => it.declared[col] === undefined)
229
- assert.deepEqual(
230
- hidden,
231
- [],
232
- `${c.axis}: 행에는 있는데 조회 응답에 없는 사실 [${hidden}] — 화면은 그것을 물을 방법이 없다.`
233
- )
234
- })
235
- }
236
-
237
- /*
238
- * ★ 어떤 속성이 **효과가 있나** — 열린 것과 닫힌 것을 화면이 구별할 수 있게.
239
- *
240
- * 속성은 열려 있다(아무 사실이나 실어 보낼 수 있다). 그런데 값이 계산을 바꾸려면 그 규칙을 코드가
241
- * 알아야 하고, 그것은 닫혀 있다. 그 구분이 화면에 없으면 사용자는 속성을 넣고 나서 **아무 일도 안
242
- * 일어나는 이유**를 알 수 없다. 그래서 서버가 효과 등록부를 함께 낸다.
243
- *
244
- * 이 검사가 지키는 규율: **읽는 코드가 있는 것만 등록한다.** 지어낸 효과를 올리면 화면이 거짓을 말한다.
245
- */
246
- test('설비 항목이 효과 등록부를 함께 낸다 — 속도는 효과가 있고 나머지는 표시뿐이다', async () => {
247
- const it = await q.twinModelItem(INSTANCE, 'equipment', 'cutter-1', ctx)
248
- assert.ok(it?.propertyEffects, '등록부가 없으면 화면은 효과 있는 속성을 구별할 수 없다')
249
- assert.equal(it.propertyEffects.speed, 'twin.propeffect.speed', '속도는 주행 시간 계산이 읽는다')
250
- assert.equal('maxLoadKg' in it.propertyEffects, false, '읽는 코드가 없는 속성을 등록하면 화면이 거짓을 말한다')
251
- })
252
-
253
- test('등록부의 모든 항목이 읽는 자리를 밝힌다 — 지어낸 효과를 막는다', () => {
254
- const { PROPERTY_EFFECTS } = req('../dist-server/engine/property-effects.js')
255
- assert.ok(PROPERTY_EFFECTS.length > 0, '등록부가 비면 아무것도 지키지 않는다')
256
- for (const e of PROPERTY_EFFECTS) {
257
- assert.ok(e.id && e.axes?.length, `${e.id}: 어느 축의 속성인지 밝혀야 한다`)
258
- assert.match(e.effect, /^twin\.propeffect\./, `${e.id}: 효과 문구는 i18n 키다(서버는 사람 말을 만들지 않는다)`)
259
- assert.ok(e.readBy && e.readBy.length > 10, `${e.id}: 실제로 읽는 자리를 적어야 한다 — 없으면 지어낸 효과다`)
260
- }
261
- })
262
-
263
- test('등록되지 않은 속성은 등록부에 없다 — 화면이 "표시만 됩니다" 를 말할 근거가 된다', () => {
264
- const { propertyEffectsOf } = req('../dist-server/engine/property-effects.js')
265
- const eq = propertyEffectsOf('equipment')
266
- /*
267
- * 지금 트레일러 템플릿에는 효과 없는 속성이 선언돼 있지 않다(속도 하나뿐이다). 그래서 화면에서
268
- * "표시만 됩니다" 를 눈으로 볼 수 없다 — 그 갈래를 여기서 지킨다: 등록부에 없으면 화면이 그렇게 말한다.
269
- */
270
- assert.equal(eq.speed, 'twin.propeffect.speed')
271
- for (const unknown of ['maxLoadKg', 'skill', 'nominalSpeed']) {
272
- assert.equal(unknown in eq, false, `읽는 코드가 없는 "${unknown}" 이 등록되면 화면이 거짓을 말한다`)
273
- }
274
- /* 축이 다르면 효과도 다르다 — 품목 정의의 환산 계수를 설비에 말하지 않는다. */
275
- assert.equal('perBaseUnit' in eq, false)
276
- assert.equal(propertyEffectsOf('materialDefinitions').perBaseUnit, 'twin.propeffect.perBaseUnit')
277
- })
@@ -1,109 +0,0 @@
1
- /*
2
- * **투영이 읽는 이름이 선언에 실재하는가.**
3
- *
4
- * ── 무엇이 있었나 (2026-08-30) ────────────────────────────────────────────
5
- * 설비 투영이 `m.gs1Id` 를 읽고 있었는데 **선언에 그런 필드가 없었다.** 그래서 그 칸은 일곱 대 모두
6
- * 영원히 비어 있었다. 오류는 나지 않았다 — `?? null` 이 늘 `null` 을 냈을 뿐이다.
7
- *
8
- * 값은 한 칸 옆에 있었다. 커넥터가 인버터의 하드웨어 식별자를 이미 보내고 있었고, 정체성 칸도
9
- * 있었는데 그 사이에 길이 없었다. 인티그레이션 레인이 「값이 한 칸 옆에 있다」고 알려 와서 찾았다.
10
- *
11
- * ── 왜 다른 시험이 못 잡았나 ─────────────────────────────────────────────
12
- * `projection-reaches-screen` 은 **마스터 → 행 → 화면**을 걷는다. 그 길은 멀쩡했다 — 참조 계층이
13
- * `gs1Id` 를 실어 보내고 있었기 때문이다. 끊긴 것은 **선언 → 행** 쪽이었고, 아무도 그 길을 걷지
14
- * 않았다.
15
- *
16
- * 이 시험은 이름만 본다. 값이 흐르는지는 저 시험이 보고, 여기서는 **읽는 이름이 실재하는지**만 본다.
17
- * 둘이 함께 있어야 「자리는 있고 길이 없다」가 막힌다.
18
- */
19
- import { test } from 'node:test'
20
- import assert from 'node:assert/strict'
21
- import { readFileSync } from 'node:fs'
22
- import { createRequire } from 'node:module'
23
- import { fileURLToPath } from 'node:url'
24
- import { dirname, join } from 'node:path'
25
-
26
- const here = dirname(fileURLToPath(import.meta.url))
27
- const req = createRequire(import.meta.url)
28
-
29
- const projection = readFileSync(join(here, '..', 'server', 'service', 'twin-model', 'project-structure.ts'), 'utf-8')
30
-
31
- /** 계약이 배포한 선언 타입 원문 — 이름이 실재하는지 여기서 확인한다. */
32
- const contractTypes = readFileSync(join(dirname(req.resolve('@operato/ops-contract')), '..', 'dist', 'contract.d.ts'), 'utf-8')
33
- const domainTypes = readFileSync(
34
- join(dirname(req.resolve('@operato/ops-contract')), '..', 'dist', 'domain-definition.d.ts'),
35
- 'utf-8'
36
- )
37
- const declared = contractTypes + '\n' + domainTypes
38
-
39
- /**
40
- * 투영 안의 변수 이름 → 그 변수가 무엇의 선언인가.
41
- *
42
- * 이름을 손으로 적는다. 투영이 변수를 바꾸면 이 목록이 낡는데, 그때 아래 「대상이 실재한다」 검사가
43
- * 먼저 빨갛게 난다 — 낡은 채로 초록이 되지 않는다.
44
- */
45
- const SUBJECTS: { varName: string; what: string }[] = [
46
- { varName: 'l', what: '자리' },
47
- { varName: 'm', what: '설비' },
48
- { varName: 'o', what: '공정' }
49
- ]
50
-
51
- /** 선언에서 오지 않는 이름 — 투영이 스스로 만드는 값이다. 이유를 함께 적는다. */
52
- const NOT_FROM_DECLARATION: Record<string, string> = {
53
- sourceRef: '투영이 붙인다 — 어느 참조에서 왔나',
54
- ingestedAt: '투영이 붙인다 — 언제 채웠나',
55
- domain: '테넌트 — 호출부가 준다',
56
- instanceId: '어느 트윈인가 — 호출부가 준다'
57
- }
58
-
59
- /**
60
- * 그 변수에서 읽는 필드들.
61
- *
62
- * **형 단언을 지나서 본다** — `(m as any).x` 도 읽는 것이다. 처음에는 `m.x` 만 봤고, 그래서
63
- * 유령 이름을 넣어도 잡지 못했다(2026-08-30). 실제 코드가 그 모양을 쓰고 있었으므로 그 자리를
64
- * 통째로 놓치고 있었다.
65
- *
66
- * 단언을 쓰는 자리가 특히 위험하다 — 타입 검사가 이미 꺼져 있어서 컴파일러도 안 잡는다.
67
- */
68
- function readsOf(varName: string): { field: string; line: number }[] {
69
- const out: { field: string; line: number }[] = []
70
- const plain = new RegExp(`(?<![A-Za-z0-9_.)])${varName}\\.([a-zA-Z][A-Za-z0-9]*)`, 'g')
71
- const cast = new RegExp(`\\(\\s*${varName}\\s+as\\s+[^)]*\\)\\.([a-zA-Z][A-Za-z0-9]*)`, 'g')
72
- projection.split('\n').forEach((text, i) => {
73
- for (const re of [plain, cast]) for (const m of text.matchAll(re)) out.push({ field: m[1], line: i + 1 })
74
- })
75
- return out
76
- }
77
-
78
- test('★ 검사할 대상이 실재한다 — 없으면 이 시험은 아무것도 지키지 않는다', () => {
79
- assert.ok(declared.length > 10_000, '계약 선언 원문을 못 읽었다')
80
- for (const s of SUBJECTS) {
81
- assert.ok(readsOf(s.varName).length > 0, `${s.what}(${s.varName}) 를 읽는 자리가 없다 — 투영이 바뀌었다`)
82
- }
83
- })
84
-
85
- test('★ 투영이 읽는 이름이 선언에 실재한다 — 없는 이름을 읽으면 그 칸은 영원히 빈다', () => {
86
- const ghosts: string[] = []
87
- for (const s of SUBJECTS) {
88
- for (const { field, line } of readsOf(s.varName)) {
89
- if (field in NOT_FROM_DECLARATION) continue
90
- /* 선언 어딘가에 그 이름이 필드로 있는가 — 타입을 가리지 않고 이름만 본다. */
91
- if (!new RegExp(`\\b${field}\\??:`).test(declared)) {
92
- ghosts.push(`project-structure.ts:${line} ${s.what}.${field}`)
93
- }
94
- }
95
- }
96
- assert.deepEqual(
97
- [...new Set(ghosts)],
98
- [],
99
- `선언에 없는 이름을 읽는다:\n${[...new Set(ghosts)].join('\n')}\n\n` +
100
- '그 칸은 늘 null 이 되고 오류는 나지 않는다. 선언에 그 필드를 열거나, 투영이 읽는 이름을 고쳐라.\n' +
101
- '선언에서 오는 값이 아니면 NOT_FROM_DECLARATION 에 이유와 함께 올려라.'
102
- )
103
- })
104
-
105
- test('선언에서 오지 않는 이름에 이유가 적혀 있다', () => {
106
- for (const [name, why] of Object.entries(NOT_FROM_DECLARATION)) {
107
- assert.ok(why.trim().length > 5, `${name} 에 이유가 없다 — 이유 없이 올리면 이 시험이 아무것도 지키지 않는다`)
108
- }
109
- })