@things-factory/headless-twin 10.1.277 → 10.1.279

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (614) hide show
  1. package/package.json +21 -7
  2. package/dist-server/engine/attention-digest.js.map +0 -1
  3. package/dist-server/engine/canonical-ingest.js.map +0 -1
  4. package/dist-server/engine/checkpoint-fold.js.map +0 -1
  5. package/dist-server/engine/command-routing.js.map +0 -1
  6. package/dist-server/engine/declared-stimulus.js.map +0 -1
  7. package/dist-server/engine/energy-topology.js.map +0 -1
  8. package/dist-server/engine/event-time.js.map +0 -1
  9. package/dist-server/engine/index.js.map +0 -1
  10. package/dist-server/engine/ingest-dedupe.js.map +0 -1
  11. package/dist-server/engine/ingest-health.js.map +0 -1
  12. package/dist-server/engine/integration-coverage.js.map +0 -1
  13. package/dist-server/engine/integration-probes.js.map +0 -1
  14. package/dist-server/engine/integration-runner.js.map +0 -1
  15. package/dist-server/engine/integration-target-profile.js.map +0 -1
  16. package/dist-server/engine/kpi-baseline.js.map +0 -1
  17. package/dist-server/engine/kpi-fold.js.map +0 -1
  18. package/dist-server/engine/kpi-query.js.map +0 -1
  19. package/dist-server/engine/kpi-target.js.map +0 -1
  20. package/dist-server/engine/live-attentions.js.map +0 -1
  21. package/dist-server/engine/live-feed-registry.js.map +0 -1
  22. package/dist-server/engine/load-meter.js.map +0 -1
  23. package/dist-server/engine/local-declarations.js.map +0 -1
  24. package/dist-server/engine/log.js.map +0 -1
  25. package/dist-server/engine/loop-lag.js.map +0 -1
  26. package/dist-server/engine/measured-estimator.js.map +0 -1
  27. package/dist-server/engine/measured-yield.js.map +0 -1
  28. package/dist-server/engine/model-basis.js.map +0 -1
  29. package/dist-server/engine/model-gap.js.map +0 -1
  30. package/dist-server/engine/model-refusal.js.map +0 -1
  31. package/dist-server/engine/model-vocabulary.js.map +0 -1
  32. package/dist-server/engine/oee-accumulator.js.map +0 -1
  33. package/dist-server/engine/operation-basis.js.map +0 -1
  34. package/dist-server/engine/producer-guard.js.map +0 -1
  35. package/dist-server/engine/property-effects.js.map +0 -1
  36. package/dist-server/engine/read-time.js.map +0 -1
  37. package/dist-server/engine/restart-policy.js.map +0 -1
  38. package/dist-server/engine/runtime-key.js.map +0 -1
  39. package/dist-server/engine/spec-coverage.js.map +0 -1
  40. package/dist-server/engine/stage-path.js.map +0 -1
  41. package/dist-server/engine/state-axes.js.map +0 -1
  42. package/dist-server/engine/structure-diff.js.map +0 -1
  43. package/dist-server/engine/travel-estimator.js.map +0 -1
  44. package/dist-server/engine/twin-engine.js.map +0 -1
  45. package/dist-server/engine/twin-state-channel.js.map +0 -1
  46. package/dist-server/engine/warm-start.js.map +0 -1
  47. package/dist-server/index.js.map +0 -1
  48. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js.map +0 -1
  49. package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js.map +0 -1
  50. package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js.map +0 -1
  51. package/dist-server/migrations/1786300000000-IndexEventTypeByTime.js.map +0 -1
  52. package/dist-server/migrations/1786400000000-IndexEventCreatedAt.js.map +0 -1
  53. package/dist-server/migrations/1786500000000-CreateTwinSubjectEvents.js.map +0 -1
  54. package/dist-server/migrations/1786600000000-RenameOperatoMesAdapterType.js.map +0 -1
  55. package/dist-server/migrations/1786700000000-AddDispatchRetryColumns.js.map +0 -1
  56. package/dist-server/migrations/1786800000000-CreateTwinReferenceReconciliations.js.map +0 -1
  57. package/dist-server/migrations/index.js.map +0 -1
  58. package/dist-server/routes.js.map +0 -1
  59. package/dist-server/service/actuation/actuation-advisor.js.map +0 -1
  60. package/dist-server/service/actuation/actuation-outcome.js.map +0 -1
  61. package/dist-server/service/actuation/actuation-rule-resolver.js.map +0 -1
  62. package/dist-server/service/actuation/actuation-rule.js.map +0 -1
  63. package/dist-server/service/actuation/approval-gateway.js.map +0 -1
  64. package/dist-server/service/actuation/catch-up-effects.js.map +0 -1
  65. package/dist-server/service/actuation/command-dispatcher.js.map +0 -1
  66. package/dist-server/service/actuation/command-store.js.map +0 -1
  67. package/dist-server/service/actuation/dispatch-after-approval.js.map +0 -1
  68. package/dist-server/service/actuation/effect-match.js.map +0 -1
  69. package/dist-server/service/actuation/index.js.map +0 -1
  70. package/dist-server/service/actuation/retry-plan.js.map +0 -1
  71. package/dist-server/service/actuation/rule-evaluate.js.map +0 -1
  72. package/dist-server/service/actuation/rule-loop.js.map +0 -1
  73. package/dist-server/service/actuation/rule-runner.js.map +0 -1
  74. package/dist-server/service/actuation/rule-wiring.js.map +0 -1
  75. package/dist-server/service/actuation/settle-effects.js.map +0 -1
  76. package/dist-server/service/actuation/sweep-dispatch.js.map +0 -1
  77. package/dist-server/service/actuation/twin-command-resolver.js.map +0 -1
  78. package/dist-server/service/actuation/twin-command.js.map +0 -1
  79. package/dist-server/service/actuation/twin-now.js.map +0 -1
  80. package/dist-server/service/index.js.map +0 -1
  81. package/dist-server/service/reference/actuation-routing.js.map +0 -1
  82. package/dist-server/service/reference/actuation-target.js.map +0 -1
  83. package/dist-server/service/reference/actuation-verification.js.map +0 -1
  84. package/dist-server/service/reference/attention-lane.js.map +0 -1
  85. package/dist-server/service/reference/connection-portability-resolver.js.map +0 -1
  86. package/dist-server/service/reference/connection-portability.js.map +0 -1
  87. package/dist-server/service/reference/control-routing.js.map +0 -1
  88. package/dist-server/service/reference/discovery-result.js.map +0 -1
  89. package/dist-server/service/reference/fill-cadence.js.map +0 -1
  90. package/dist-server/service/reference/fill-dedupe.js.map +0 -1
  91. package/dist-server/service/reference/fill-loop.js.map +0 -1
  92. package/dist-server/service/reference/fill-span.js.map +0 -1
  93. package/dist-server/service/reference/hook-contract.js.map +0 -1
  94. package/dist-server/service/reference/hook-rejected.js.map +0 -1
  95. package/dist-server/service/reference/hook-store.js.map +0 -1
  96. package/dist-server/service/reference/index.js.map +0 -1
  97. package/dist-server/service/reference/ingest-space.js.map +0 -1
  98. package/dist-server/service/reference/knob-defaults.js.map +0 -1
  99. package/dist-server/service/reference/live-cadence.js.map +0 -1
  100. package/dist-server/service/reference/live-feed-lease.js.map +0 -1
  101. package/dist-server/service/reference/live-ingest.js.map +0 -1
  102. package/dist-server/service/reference/reference-adapter.js.map +0 -1
  103. package/dist-server/service/reference/reference-assessment.js.map +0 -1
  104. package/dist-server/service/reference/reference-fill-run.js.map +0 -1
  105. package/dist-server/service/reference/reference-fill.js.map +0 -1
  106. package/dist-server/service/reference/reference-hook.js.map +0 -1
  107. package/dist-server/service/reference/reference-link-groups.js.map +0 -1
  108. package/dist-server/service/reference/reference-links.js.map +0 -1
  109. package/dist-server/service/reference/reference-live.js.map +0 -1
  110. package/dist-server/service/reference/reference-master.js.map +0 -1
  111. package/dist-server/service/reference/reference-probe.js.map +0 -1
  112. package/dist-server/service/reference/reference-progress-channel.js.map +0 -1
  113. package/dist-server/service/reference/reference-progress-subscription.js.map +0 -1
  114. package/dist-server/service/reference/reference-progress.js.map +0 -1
  115. package/dist-server/service/reference/reference-reconciliation-query.js.map +0 -1
  116. package/dist-server/service/reference/reference-reconciliation-writer.js.map +0 -1
  117. package/dist-server/service/reference/reference-reconciliation.js.map +0 -1
  118. package/dist-server/service/reference/reference-registry.js.map +0 -1
  119. package/dist-server/service/reference/reference-resolver.js.map +0 -1
  120. package/dist-server/service/reference/template-registry.js.map +0 -1
  121. package/dist-server/service/reference/twin-reference-reconciliation.js.map +0 -1
  122. package/dist-server/service/reference/twin-reference.js.map +0 -1
  123. package/dist-server/service/twin-attention/index.js.map +0 -1
  124. package/dist-server/service/twin-attention/twin-attention-query.js.map +0 -1
  125. package/dist-server/service/twin-audit/command-audit.js.map +0 -1
  126. package/dist-server/service/twin-audit/index.js.map +0 -1
  127. package/dist-server/service/twin-audit/twin-audit-event.js.map +0 -1
  128. package/dist-server/service/twin-audit/twin-audit-query.js.map +0 -1
  129. package/dist-server/service/twin-backfill/backfill-period-facts.js.map +0 -1
  130. package/dist-server/service/twin-backfill/backfill-shape.js.map +0 -1
  131. package/dist-server/service/twin-backfill/index.js.map +0 -1
  132. package/dist-server/service/twin-backfill/twin-backfill-resolver.js.map +0 -1
  133. package/dist-server/service/twin-control/index.js.map +0 -1
  134. package/dist-server/service/twin-control/twin-control-mutation.js.map +0 -1
  135. package/dist-server/service/twin-event/index.js.map +0 -1
  136. package/dist-server/service/twin-event/journal-count.js.map +0 -1
  137. package/dist-server/service/twin-event/twin-event-keys.js.map +0 -1
  138. package/dist-server/service/twin-event/twin-event-type.js.map +0 -1
  139. package/dist-server/service/twin-event/twin-event.js.map +0 -1
  140. package/dist-server/service/twin-forecast/forecast-metrics.js.map +0 -1
  141. package/dist-server/service/twin-forecast/forecast-tuning.js.map +0 -1
  142. package/dist-server/service/twin-forecast/gap-analytics.js.map +0 -1
  143. package/dist-server/service/twin-forecast/index.js.map +0 -1
  144. package/dist-server/service/twin-forecast/twin-forecast-query.js.map +0 -1
  145. package/dist-server/service/twin-ingest-window/index.js.map +0 -1
  146. package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js.map +0 -1
  147. package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js.map +0 -1
  148. package/dist-server/service/twin-ingest-window/twin-ingest-window.js.map +0 -1
  149. package/dist-server/service/twin-instance/index.js.map +0 -1
  150. package/dist-server/service/twin-instance/twin-instance.js.map +0 -1
  151. package/dist-server/service/twin-journal/event-type-split-shape.js.map +0 -1
  152. package/dist-server/service/twin-journal/event-type-split.js.map +0 -1
  153. package/dist-server/service/twin-journal/index.js.map +0 -1
  154. package/dist-server/service/twin-journal/journal-order.js.map +0 -1
  155. package/dist-server/service/twin-journal/twin-journal-query.js.map +0 -1
  156. package/dist-server/service/twin-lifecycle/domain-catalog.js.map +0 -1
  157. package/dist-server/service/twin-lifecycle/index.js.map +0 -1
  158. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +0 -1
  159. package/dist-server/service/twin-metrics/index.js.map +0 -1
  160. package/dist-server/service/twin-metrics/twin-metrics-query.js.map +0 -1
  161. package/dist-server/service/twin-model/axis-journal-evidence.js.map +0 -1
  162. package/dist-server/service/twin-model/choose-recipe.js.map +0 -1
  163. package/dist-server/service/twin-model/epcis-coverage.js.map +0 -1
  164. package/dist-server/service/twin-model/external-resolver.js.map +0 -1
  165. package/dist-server/service/twin-model/iec61850-coverage.js.map +0 -1
  166. package/dist-server/service/twin-model/index.js.map +0 -1
  167. package/dist-server/service/twin-model/isa95-coverage.js.map +0 -1
  168. package/dist-server/service/twin-model/item-ref.js.map +0 -1
  169. package/dist-server/service/twin-model/name-index.js.map +0 -1
  170. package/dist-server/service/twin-model/project-structure.js.map +0 -1
  171. package/dist-server/service/twin-model/standard-coverage.js.map +0 -1
  172. package/dist-server/service/twin-model/status-tally.js.map +0 -1
  173. package/dist-server/service/twin-model/twin-equipment.js.map +0 -1
  174. package/dist-server/service/twin-model/twin-lineage-query.js.map +0 -1
  175. package/dist-server/service/twin-model/twin-location.js.map +0 -1
  176. package/dist-server/service/twin-model/twin-model-item-query.js.map +0 -1
  177. package/dist-server/service/twin-model/twin-model-mutation.js.map +0 -1
  178. package/dist-server/service/twin-model/twin-model-query.js.map +0 -1
  179. package/dist-server/service/twin-model/twin-model-tree-query.js.map +0 -1
  180. package/dist-server/service/twin-model/twin-operation.js.map +0 -1
  181. package/dist-server/service/twin-readiness/index.js.map +0 -1
  182. package/dist-server/service/twin-readiness/twin-readiness-query.js.map +0 -1
  183. package/dist-server/service/twin-space/area-resolver.js.map +0 -1
  184. package/dist-server/service/twin-space/index.js.map +0 -1
  185. package/dist-server/service/twin-space/move-space.js.map +0 -1
  186. package/dist-server/service/twin-space/representation-role.js.map +0 -1
  187. package/dist-server/service/twin-space/space-integrity.js.map +0 -1
  188. package/dist-server/service/twin-space/twin-area.js.map +0 -1
  189. package/dist-server/service/twin-space/twin-space-area.js.map +0 -1
  190. package/dist-server/service/twin-space/twin-space-representation.js.map +0 -1
  191. package/dist-server/service/twin-space/twin-space-resolver.js.map +0 -1
  192. package/dist-server/service/twin-space/twin-space.js.map +0 -1
  193. package/dist-server/service/twin-state/index.js.map +0 -1
  194. package/dist-server/service/twin-state/twin-state-subscription.js.map +0 -1
  195. package/dist-server/service/twin-structure/index.js.map +0 -1
  196. package/dist-server/service/twin-structure/twin-structure.js.map +0 -1
  197. package/dist-server/service/twin-subject/event-subjects.js.map +0 -1
  198. package/dist-server/service/twin-subject/index.js.map +0 -1
  199. package/dist-server/service/twin-subject/item-resolver.js.map +0 -1
  200. package/dist-server/service/twin-subject/subject-query-shape.js.map +0 -1
  201. package/dist-server/service/twin-subject/twin-subject-backfill.js.map +0 -1
  202. package/dist-server/service/twin-subject/twin-subject-event.js.map +0 -1
  203. package/dist-server/service/twin-subject/twin-subject-fast-path.js.map +0 -1
  204. package/dist-server/service/twin-subject/twin-subject-query.js.map +0 -1
  205. package/dist-server/service/twin-subject/twin-subject-writer.js.map +0 -1
  206. package/dist-server/service/twin-target/index.js.map +0 -1
  207. package/dist-server/service/twin-target/twin-target-resolver.js.map +0 -1
  208. package/dist-server/service/twin-target/twin-target.js.map +0 -1
  209. package/dist-shared/axis-read.js.map +0 -1
  210. package/dist-shared/entity-delta.js.map +0 -1
  211. package/dist-shared/kpi-broadcast.js.map +0 -1
  212. package/dist-shared/touched-items.js.map +0 -1
  213. package/dist-shared/twin-level.js.map +0 -1
  214. package/server/engine/attention-digest.ts +0 -102
  215. package/server/engine/canonical-ingest.ts +0 -511
  216. package/server/engine/checkpoint-fold.ts +0 -12
  217. package/server/engine/command-routing.ts +0 -67
  218. package/server/engine/declared-stimulus.ts +0 -66
  219. package/server/engine/energy-topology.ts +0 -189
  220. package/server/engine/event-time.ts +0 -96
  221. package/server/engine/index.ts +0 -51
  222. package/server/engine/ingest-dedupe.ts +0 -24
  223. package/server/engine/ingest-health.ts +0 -24
  224. package/server/engine/integration-coverage.ts +0 -147
  225. package/server/engine/integration-probes.ts +0 -144
  226. package/server/engine/integration-runner.ts +0 -95
  227. package/server/engine/integration-target-profile.ts +0 -103
  228. package/server/engine/kpi-baseline.ts +0 -202
  229. package/server/engine/kpi-fold.ts +0 -1516
  230. package/server/engine/kpi-query.ts +0 -1210
  231. package/server/engine/kpi-target.ts +0 -248
  232. package/server/engine/live-attentions.ts +0 -30
  233. package/server/engine/live-feed-registry.ts +0 -59
  234. package/server/engine/load-meter.ts +0 -393
  235. package/server/engine/local-declarations.ts +0 -779
  236. package/server/engine/log.ts +0 -72
  237. package/server/engine/loop-lag.ts +0 -120
  238. package/server/engine/measured-estimator.ts +0 -91
  239. package/server/engine/measured-yield.ts +0 -89
  240. package/server/engine/model-basis.ts +0 -162
  241. package/server/engine/model-gap.ts +0 -168
  242. package/server/engine/model-refusal.ts +0 -31
  243. package/server/engine/model-vocabulary.ts +0 -82
  244. package/server/engine/oee-accumulator.ts +0 -195
  245. package/server/engine/operation-basis.ts +0 -131
  246. package/server/engine/producer-guard.ts +0 -64
  247. package/server/engine/property-effects.ts +0 -216
  248. package/server/engine/read-time.ts +0 -77
  249. package/server/engine/restart-policy.ts +0 -55
  250. package/server/engine/runtime-key.ts +0 -58
  251. package/server/engine/spec-coverage.ts +0 -105
  252. package/server/engine/stage-path.ts +0 -172
  253. package/server/engine/state-axes.ts +0 -60
  254. package/server/engine/structure-diff.ts +0 -88
  255. package/server/engine/travel-estimator.ts +0 -138
  256. package/server/engine/twin-engine.ts +0 -4979
  257. package/server/engine/twin-state-channel.ts +0 -39
  258. package/server/engine/warm-start.ts +0 -265
  259. package/server/index.ts +0 -90
  260. package/server/migrations/1786000000000-RenameTwinInstanceBoardToModel.ts +0 -43
  261. package/server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.ts +0 -54
  262. package/server/migrations/1786200000000-CarryLiveFeedCursor.ts +0 -53
  263. package/server/migrations/1786300000000-IndexEventTypeByTime.ts +0 -48
  264. package/server/migrations/1786400000000-IndexEventCreatedAt.ts +0 -38
  265. package/server/migrations/1786500000000-CreateTwinSubjectEvents.ts +0 -93
  266. package/server/migrations/1786600000000-RenameOperatoMesAdapterType.ts +0 -66
  267. package/server/migrations/1786700000000-AddDispatchRetryColumns.ts +0 -82
  268. package/server/migrations/1786800000000-CreateTwinReferenceReconciliations.ts +0 -39
  269. package/server/migrations/index.ts +0 -25
  270. package/server/routes.ts +0 -75
  271. package/server/service/actuation/actuation-advisor.ts +0 -131
  272. package/server/service/actuation/actuation-outcome.ts +0 -97
  273. package/server/service/actuation/actuation-rule-resolver.ts +0 -147
  274. package/server/service/actuation/actuation-rule.ts +0 -139
  275. package/server/service/actuation/approval-gateway.ts +0 -44
  276. package/server/service/actuation/catch-up-effects.ts +0 -152
  277. package/server/service/actuation/command-dispatcher.ts +0 -474
  278. package/server/service/actuation/command-store.ts +0 -236
  279. package/server/service/actuation/dispatch-after-approval.ts +0 -71
  280. package/server/service/actuation/effect-match.ts +0 -124
  281. package/server/service/actuation/index.ts +0 -27
  282. package/server/service/actuation/retry-plan.ts +0 -145
  283. package/server/service/actuation/rule-evaluate.ts +0 -352
  284. package/server/service/actuation/rule-loop.ts +0 -160
  285. package/server/service/actuation/rule-runner.ts +0 -216
  286. package/server/service/actuation/rule-wiring.ts +0 -84
  287. package/server/service/actuation/settle-effects.ts +0 -115
  288. package/server/service/actuation/sweep-dispatch.ts +0 -179
  289. package/server/service/actuation/twin-command-resolver.ts +0 -387
  290. package/server/service/actuation/twin-command.ts +0 -232
  291. package/server/service/actuation/twin-now.ts +0 -97
  292. package/server/service/index.ts +0 -100
  293. package/server/service/reference/actuation-routing.ts +0 -192
  294. package/server/service/reference/actuation-target.ts +0 -163
  295. package/server/service/reference/actuation-verification.ts +0 -85
  296. package/server/service/reference/attention-lane.ts +0 -21
  297. package/server/service/reference/connection-portability-resolver.ts +0 -171
  298. package/server/service/reference/connection-portability.ts +0 -329
  299. package/server/service/reference/control-routing.ts +0 -62
  300. package/server/service/reference/discovery-result.ts +0 -95
  301. package/server/service/reference/fill-cadence.ts +0 -29
  302. package/server/service/reference/fill-dedupe.ts +0 -66
  303. package/server/service/reference/fill-loop.ts +0 -153
  304. package/server/service/reference/fill-span.ts +0 -31
  305. package/server/service/reference/hook-contract.ts +0 -364
  306. package/server/service/reference/hook-rejected.ts +0 -53
  307. package/server/service/reference/hook-store.ts +0 -28
  308. package/server/service/reference/index.ts +0 -18
  309. package/server/service/reference/ingest-space.ts +0 -104
  310. package/server/service/reference/knob-defaults.ts +0 -59
  311. package/server/service/reference/live-cadence.ts +0 -129
  312. package/server/service/reference/live-feed-lease.ts +0 -56
  313. package/server/service/reference/live-ingest.ts +0 -94
  314. package/server/service/reference/reference-adapter.ts +0 -985
  315. package/server/service/reference/reference-assessment.ts +0 -250
  316. package/server/service/reference/reference-fill-run.ts +0 -179
  317. package/server/service/reference/reference-fill.ts +0 -223
  318. package/server/service/reference/reference-hook.ts +0 -479
  319. package/server/service/reference/reference-link-groups.ts +0 -21
  320. package/server/service/reference/reference-links.ts +0 -77
  321. package/server/service/reference/reference-live.ts +0 -420
  322. package/server/service/reference/reference-master.ts +0 -999
  323. package/server/service/reference/reference-probe.ts +0 -264
  324. package/server/service/reference/reference-progress-channel.ts +0 -26
  325. package/server/service/reference/reference-progress-subscription.ts +0 -78
  326. package/server/service/reference/reference-progress.ts +0 -95
  327. package/server/service/reference/reference-reconciliation-query.ts +0 -28
  328. package/server/service/reference/reference-reconciliation-writer.ts +0 -38
  329. package/server/service/reference/reference-reconciliation.ts +0 -55
  330. package/server/service/reference/reference-registry.ts +0 -17
  331. package/server/service/reference/reference-resolver.ts +0 -969
  332. package/server/service/reference/template-registry.ts +0 -85
  333. package/server/service/reference/twin-reference-reconciliation.ts +0 -27
  334. package/server/service/reference/twin-reference.ts +0 -190
  335. package/server/service/twin-attention/index.ts +0 -3
  336. package/server/service/twin-attention/twin-attention-query.ts +0 -70
  337. package/server/service/twin-audit/command-audit.ts +0 -114
  338. package/server/service/twin-audit/index.ts +0 -5
  339. package/server/service/twin-audit/twin-audit-event.ts +0 -158
  340. package/server/service/twin-audit/twin-audit-query.ts +0 -72
  341. package/server/service/twin-backfill/backfill-period-facts.ts +0 -168
  342. package/server/service/twin-backfill/backfill-shape.ts +0 -86
  343. package/server/service/twin-backfill/index.ts +0 -3
  344. package/server/service/twin-backfill/twin-backfill-resolver.ts +0 -35
  345. package/server/service/twin-control/index.ts +0 -3
  346. package/server/service/twin-control/twin-control-mutation.ts +0 -150
  347. package/server/service/twin-event/index.ts +0 -3
  348. package/server/service/twin-event/journal-count.ts +0 -53
  349. package/server/service/twin-event/twin-event-keys.ts +0 -215
  350. package/server/service/twin-event/twin-event-type.ts +0 -68
  351. package/server/service/twin-event/twin-event.ts +0 -250
  352. package/server/service/twin-forecast/forecast-metrics.ts +0 -106
  353. package/server/service/twin-forecast/forecast-tuning.ts +0 -40
  354. package/server/service/twin-forecast/gap-analytics.ts +0 -139
  355. package/server/service/twin-forecast/index.ts +0 -3
  356. package/server/service/twin-forecast/twin-forecast-query.ts +0 -486
  357. package/server/service/twin-ingest-window/index.ts +0 -7
  358. package/server/service/twin-ingest-window/twin-ingest-window-query.ts +0 -125
  359. package/server/service/twin-ingest-window/twin-ingest-window-writer.ts +0 -57
  360. package/server/service/twin-ingest-window/twin-ingest-window.ts +0 -113
  361. package/server/service/twin-instance/index.ts +0 -3
  362. package/server/service/twin-instance/twin-instance.ts +0 -199
  363. package/server/service/twin-journal/event-type-split-shape.ts +0 -112
  364. package/server/service/twin-journal/event-type-split.ts +0 -144
  365. package/server/service/twin-journal/index.ts +0 -3
  366. package/server/service/twin-journal/journal-order.ts +0 -20
  367. package/server/service/twin-journal/twin-journal-query.ts +0 -615
  368. package/server/service/twin-lifecycle/domain-catalog.ts +0 -51
  369. package/server/service/twin-lifecycle/index.ts +0 -3
  370. package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +0 -285
  371. package/server/service/twin-metrics/index.ts +0 -3
  372. package/server/service/twin-metrics/twin-metrics-query.ts +0 -172
  373. package/server/service/twin-model/axis-journal-evidence.ts +0 -57
  374. package/server/service/twin-model/choose-recipe.ts +0 -31
  375. package/server/service/twin-model/epcis-coverage.ts +0 -251
  376. package/server/service/twin-model/external-resolver.ts +0 -173
  377. package/server/service/twin-model/iec61850-coverage.ts +0 -111
  378. package/server/service/twin-model/index.ts +0 -25
  379. package/server/service/twin-model/isa95-coverage.ts +0 -320
  380. package/server/service/twin-model/item-ref.ts +0 -80
  381. package/server/service/twin-model/name-index.ts +0 -94
  382. package/server/service/twin-model/project-structure.ts +0 -213
  383. package/server/service/twin-model/standard-coverage.ts +0 -35
  384. package/server/service/twin-model/status-tally.ts +0 -37
  385. package/server/service/twin-model/twin-equipment.ts +0 -191
  386. package/server/service/twin-model/twin-lineage-query.ts +0 -327
  387. package/server/service/twin-model/twin-location.ts +0 -147
  388. package/server/service/twin-model/twin-model-item-query.ts +0 -1029
  389. package/server/service/twin-model/twin-model-mutation.ts +0 -503
  390. package/server/service/twin-model/twin-model-query.ts +0 -792
  391. package/server/service/twin-model/twin-model-tree-query.ts +0 -211
  392. package/server/service/twin-model/twin-operation.ts +0 -157
  393. package/server/service/twin-readiness/index.ts +0 -3
  394. package/server/service/twin-readiness/twin-readiness-query.ts +0 -96
  395. package/server/service/twin-space/area-resolver.ts +0 -75
  396. package/server/service/twin-space/index.ts +0 -8
  397. package/server/service/twin-space/move-space.ts +0 -262
  398. package/server/service/twin-space/representation-role.ts +0 -15
  399. package/server/service/twin-space/space-integrity.ts +0 -293
  400. package/server/service/twin-space/twin-area.ts +0 -63
  401. package/server/service/twin-space/twin-space-area.ts +0 -66
  402. package/server/service/twin-space/twin-space-representation.ts +0 -99
  403. package/server/service/twin-space/twin-space-resolver.ts +0 -582
  404. package/server/service/twin-space/twin-space.ts +0 -148
  405. package/server/service/twin-state/index.ts +0 -3
  406. package/server/service/twin-state/twin-state-subscription.ts +0 -62
  407. package/server/service/twin-structure/index.ts +0 -3
  408. package/server/service/twin-structure/twin-structure.ts +0 -96
  409. package/server/service/twin-subject/event-subjects.ts +0 -162
  410. package/server/service/twin-subject/index.ts +0 -10
  411. package/server/service/twin-subject/item-resolver.ts +0 -92
  412. package/server/service/twin-subject/subject-query-shape.ts +0 -84
  413. package/server/service/twin-subject/twin-subject-backfill.ts +0 -196
  414. package/server/service/twin-subject/twin-subject-event.ts +0 -101
  415. package/server/service/twin-subject/twin-subject-fast-path.ts +0 -346
  416. package/server/service/twin-subject/twin-subject-query.ts +0 -210
  417. package/server/service/twin-subject/twin-subject-writer.ts +0 -189
  418. package/server/service/twin-target/index.ts +0 -5
  419. package/server/service/twin-target/twin-target-resolver.ts +0 -142
  420. package/server/service/twin-target/twin-target.ts +0 -97
  421. package/server/types/global.d.ts +0 -22
  422. package/shared/axis-read.ts +0 -28
  423. package/shared/entity-delta.ts +0 -335
  424. package/shared/kpi-broadcast.ts +0 -13
  425. package/shared/touched-items.ts +0 -73
  426. package/shared/twin-level.ts +0 -48
  427. package/test/ack-shape-alignment.test.ts +0 -97
  428. package/test/actuation-advisor.test.ts +0 -55
  429. package/test/actuation-approval-door.test.ts +0 -411
  430. package/test/actuation-dispatch.test.ts +0 -209
  431. package/test/actuation-effect.test.ts +0 -162
  432. package/test/actuation-outcome.test.ts +0 -152
  433. package/test/actuation-rule-runner.test.ts +0 -281
  434. package/test/actuation-rule.test.ts +0 -266
  435. package/test/actuation-seam.test.ts +0 -255
  436. package/test/actuation-settle.test.ts +0 -164
  437. package/test/actuation-target.test.ts +0 -145
  438. package/test/actuation-verification-state.test.ts +0 -139
  439. package/test/adopt-structure-live.test.ts +0 -133
  440. package/test/aggregate-not-findone.test.ts +0 -112
  441. package/test/area-resolver-db.test.ts +0 -110
  442. package/test/attention-digest.test.ts +0 -161
  443. package/test/axis-declaration-passthrough-db.test.ts +0 -152
  444. package/test/axis-journal-evidence.test.ts +0 -71
  445. package/test/axis-read.test.ts +0 -188
  446. package/test/backfill-shape.test.ts +0 -89
  447. package/test/boot-resume.test.ts +0 -287
  448. package/test/broadcast-cost-baseline.test.ts +0 -201
  449. package/test/broadcast-period.test.ts +0 -58
  450. package/test/broadcast-queue-overflow.test.ts +0 -244
  451. package/test/canonical-ingest-vocabularies.test.ts +0 -451
  452. package/test/canonical-quantity-door.test.ts +0 -61
  453. package/test/capability-mapping.test.ts +0 -89
  454. package/test/checkpoint-refuses-empty.test.ts +0 -103
  455. package/test/choose-recipe.test.ts +0 -117
  456. package/test/column-type-portability.test.ts +0 -122
  457. package/test/command-routing.test.ts +0 -61
  458. package/test/command-store-writes-columns.test.ts +0 -126
  459. package/test/connection-portability-doors.test.ts +0 -87
  460. package/test/connector-capability-declaration.test.ts +0 -195
  461. package/test/contract-layer-guard.test.ts +0 -48
  462. package/test/control-capability.test.ts +0 -98
  463. package/test/cursor-stall-not-read-failure.test.ts +0 -126
  464. package/test/declaration-reaches-model.test.ts +0 -226
  465. package/test/declared-location-types.test.ts +0 -89
  466. package/test/declared-stimulus.test.ts +0 -88
  467. package/test/dedupe-transformation.test.ts +0 -112
  468. package/test/discovery-result.test.ts +0 -75
  469. package/test/dispatch-after-approval-source.test.ts +0 -81
  470. package/test/duration-estimators.test.ts +0 -144
  471. package/test/energy-topology.test.ts +0 -113
  472. package/test/entity-delta.test.ts +0 -352
  473. package/test/equipment-identity-reaches.test.ts +0 -57
  474. package/test/event-subjects.test.ts +0 -148
  475. package/test/event-time-column.test.ts +0 -67
  476. package/test/event-type-split.test.ts +0 -178
  477. package/test/external-resolver.test.ts +0 -177
  478. package/test/fact-scope-wiring.test.ts +0 -96
  479. package/test/fill-dedupe.test.ts +0 -59
  480. package/test/fill-loop.test.ts +0 -35
  481. package/test/first-envelope.test.ts +0 -153
  482. package/test/fold-gap-speaks.test.ts +0 -53
  483. package/test/fold-shift-dst.test.ts +0 -110
  484. package/test/forecast-metrics.test.ts +0 -157
  485. package/test/forecast-tuning.test.ts +0 -42
  486. package/test/gap-analytics.test.ts +0 -113
  487. package/test/generated-not-counted.test.ts +0 -99
  488. package/test/guard-roots.ts +0 -76
  489. package/test/home-in-area.test.ts +0 -90
  490. package/test/hook-address.test.ts +0 -28
  491. package/test/hook-rejected-shape.test.ts +0 -86
  492. package/test/hook-response-sum.test.ts +0 -193
  493. package/test/hook-sequence.test.ts +0 -333
  494. package/test/ingest-bench.test.ts +0 -70
  495. package/test/ingest-dedupe.test.ts +0 -56
  496. package/test/ingest-expected-quiet.test.ts +0 -111
  497. package/test/ingest-health-engine.test.ts +0 -248
  498. package/test/ingest-health-wiring.test.ts +0 -120
  499. package/test/ingest-health.test.ts +0 -306
  500. package/test/ingest-history.test.ts +0 -247
  501. package/test/ingest-idempotent.test.ts +0 -211
  502. package/test/ingest-reconcile-four-ways.test.ts +0 -97
  503. package/test/ingest-rules-header.test.ts +0 -100
  504. package/test/ingest-running-guard.test.ts +0 -136
  505. package/test/ingest-space.test.ts +0 -78
  506. package/test/ingest-window-rolls-unobserved.test.ts +0 -72
  507. package/test/ingest-wiring-guard.test.ts +0 -197
  508. package/test/instance-cache-lifecycle.test.ts +0 -110
  509. package/test/intake-mapping-parity.test.ts +0 -175
  510. package/test/integration-probes.test.ts +0 -103
  511. package/test/integration-runner.test.ts +0 -95
  512. package/test/item-ref.test.ts +0 -78
  513. package/test/journal-order-axis.test.ts +0 -80
  514. package/test/journal-read-discipline.test.ts +0 -186
  515. package/test/journal-retention.test.ts +0 -275
  516. package/test/journal-sort-axis.test.ts +0 -142
  517. package/test/journal-write-door.test.ts +0 -110
  518. package/test/journal-write-trend.test.ts +0 -115
  519. package/test/kernel-kind-guard.test.ts +0 -98
  520. package/test/knob-defaults.test.ts +0 -72
  521. package/test/kpi-baseline-db.test.ts +0 -216
  522. package/test/kpi-baseline.test.ts +0 -196
  523. package/test/kpi-fold.test.ts +0 -1456
  524. package/test/kpi-query-bench.test.ts +0 -130
  525. package/test/lens-own-places.test.ts +0 -50
  526. package/test/lineage-survives-restart.test.ts +0 -234
  527. package/test/live-cadence.test.ts +0 -170
  528. package/test/live-cursor-wiring.test.ts +0 -87
  529. package/test/live-feed-lease.test.ts +0 -63
  530. package/test/live-feed-registry.test.ts +0 -75
  531. package/test/live-kernel-facts.test.ts +0 -161
  532. package/test/live-mirror-parity.test.ts +0 -286
  533. package/test/load-meter.test.ts +0 -328
  534. package/test/local-declarations.test.ts +0 -662
  535. package/test/log-stamp.test.ts +0 -59
  536. package/test/loop-lag.test.ts +0 -82
  537. package/test/master-to-twin.test.ts +0 -279
  538. package/test/measured-yield.test.ts +0 -90
  539. package/test/merge-streams.test.ts +0 -70
  540. package/test/mirror-resumes-from-checkpoint.test.ts +0 -192
  541. package/test/model-basis.test.ts +0 -141
  542. package/test/model-gap.test.ts +0 -153
  543. package/test/model-refusal.test.ts +0 -75
  544. package/test/model-vocabulary.test.ts +0 -114
  545. package/test/move-space.test.ts +0 -149
  546. package/test/mutation-gate.test.ts +0 -122
  547. package/test/oee-accumulator.test.ts +0 -204
  548. package/test/oee-site-calendar.test.ts +0 -146
  549. package/test/open-doors.test.ts +0 -197
  550. package/test/operation-basis.test.ts +0 -127
  551. package/test/operational-vocabulary.test.ts +0 -108
  552. package/test/operations-capability-db.test.ts +0 -165
  553. package/test/order-and-transaction-split.test.ts +0 -107
  554. package/test/order-fold-host.test.ts +0 -112
  555. package/test/producer-guard.test.ts +0 -66
  556. package/test/project-structure-db.test.ts +0 -226
  557. package/test/projection-reaches-screen.test.ts +0 -277
  558. package/test/projection-reads-declared.test.ts +0 -109
  559. package/test/property-effects.test.ts +0 -128
  560. package/test/provenance-promotion.test.ts +0 -99
  561. package/test/read-failure-ledger.test.ts +0 -106
  562. package/test/read-failure-visible.test.ts +0 -145
  563. package/test/read-time.test.ts +0 -118
  564. package/test/reference-fill.test.ts +0 -235
  565. package/test/reference-grounding.test.ts +0 -70
  566. package/test/reference-hook.test.ts +0 -177
  567. package/test/reference-links.test.ts +0 -56
  568. package/test/reference-reconciliation.test.ts +0 -39
  569. package/test/registry-key-guard.test.ts +0 -80
  570. package/test/rejection-carries-event-id.test.ts +0 -101
  571. package/test/rename-twin.test.ts +0 -89
  572. package/test/resolve-ts-siblings.mjs +0 -52
  573. package/test/restart-policy.test.ts +0 -111
  574. package/test/resync-origin-site.test.ts +0 -83
  575. package/test/retry-plan.test.ts +0 -139
  576. package/test/revision-axis.test.ts +0 -110
  577. package/test/runtime-key.test.ts +0 -66
  578. package/test/save-intake-collision.test.ts +0 -91
  579. package/test/scale-twin-bench.test.ts +0 -103
  580. package/test/secrets-at-rest.test.ts +0 -135
  581. package/test/snapshot-freshness.test.ts +0 -60
  582. package/test/source-outcome-audit.test.ts +0 -104
  583. package/test/space-integrity.test.ts +0 -223
  584. package/test/space-representation.test.ts +0 -66
  585. package/test/space-scope-includes-stopped.test.ts +0 -55
  586. package/test/spec-coverage.test.ts +0 -113
  587. package/test/stage-path.test.ts +0 -95
  588. package/test/standard-coverage.test.ts +0 -148
  589. package/test/state-axes.test.ts +0 -74
  590. package/test/status-tally.test.ts +0 -55
  591. package/test/streamline-e2e.test.ts +0 -76
  592. package/test/structure-revision-db.test.ts +0 -315
  593. package/test/subject-fast-path.test.ts +0 -148
  594. package/test/subject-read-model.test.ts +0 -175
  595. package/test/sweep-dispatch.test.ts +0 -191
  596. package/test/tenant-registry-db.test.ts +0 -149
  597. package/test/time-range.test.ts +0 -152
  598. package/test/touched-items.test.ts +0 -61
  599. package/test/twin-audit.test.ts +0 -83
  600. package/test/twin-event-keys.test.ts +0 -193
  601. package/test/twin-model-item-db.test.ts +0 -319
  602. package/test/twin-model-parent-relation-db.test.ts +0 -125
  603. package/test/twin-model-tree-db.test.ts +0 -209
  604. package/test/twin-origin-resync.test.ts +0 -133
  605. package/test/twin-state-channel.test.ts +0 -111
  606. package/test/vocabulary-guard.test.ts +0 -43
  607. package/test/warm-start-seam.test.ts +0 -162
  608. package/test/warm-start.test.ts +0 -297
  609. package/test/withheld-door.test.ts +0 -95
  610. package/test/yield-loop.test.ts +0 -199
  611. package/tsconfig.json +0 -15
  612. package/tsconfig.shared.json +0 -23
  613. package/tsconfig.shared.tsbuildinfo +0 -1
  614. package/tsconfig.tsbuildinfo +0 -1
@@ -1,112 +0,0 @@
1
- /*
2
- * ★ 수 하나가 필요하면 **집계로 묻는다** — `findOne(order: …)` 으로 흉내내지 않는다.
3
- *
4
- * ── 왜 이 검사가 필요한가 (2026-08-28 전수 조사) ────────────────────────────
5
- * 「가장 늦은 사건」·「저널 머리」·「첫 사건」처럼 **한 줄만** 필요한 자리에서 이런 모양을 썼다.
6
- *
7
- * findOne({ where: { domain: { id }, … }, order: { revision: 'DESC' } })
8
- *
9
- * 관계를 가진 엔티티에서 `find`·`findOne` 은 두 단계 질의가 되고 **안쪽에 상한이 없다** — 조건에 맞는
10
- * 행을 전부 만든 뒤 밖에서 한 줄을 고른다. 이 파일이 지키는 저장소에서 실측한 값이다.
11
- *
12
- * twinEvents 의 같은 모양 0.024초 대 12초 (저널 375만 행)
13
- * 현장 성과(`latestEventTime`) 7.2초 — 업무 사실 97만 행을 payload 까지 만든 뒤 한 줄
14
- * 백테스트 구간(`gapWindow`) 같은 모양을 두 번(첫 사건·마지막 사건)
15
- *
16
- * **답은 맞고 비용만 틀리다.** 그래서 사람 리뷰가 잡지 못한다 — 기계에 맡긴다.
17
- * (같은 이유로 만든 검사가 하나 더 있다: `journal-read-discipline`. 그것은 「통째로 읽는 자리」를 보고,
18
- * 이 검사는 「한 줄만 필요한데 통째로 읽는 자리」를 본다.)
19
- *
20
- * ── 규율 ────────────────────────────────────────────────────────────────────
21
- * 큰 표에서 한 줄·한 수가 필요하면 질의 빌더로 `MIN`·`MAX`·`COUNT` 를 묻는다. 색인의 끝을 집으므로
22
- * 행을 만들지 않는다.
23
- */
24
- import { test } from 'node:test'
25
- import assert from 'node:assert/strict'
26
- import { readFileSync, readdirSync, statSync } from 'node:fs'
27
- import { join } from 'node:path'
28
-
29
- const ROOT = join(import.meta.dirname, '..', 'server')
30
-
31
- /** 이 검사가 보는 큰 표 — 행이 수백만이 될 수 있는 것들. */
32
- const BIG_TABLES = ['TwinEvent', 'TwinSubjectEvent']
33
-
34
- /**
35
- * 예외 — **이유와 함께** 적는다. 이유가 없으면 예외가 아니다.
36
- *
37
- * 지금은 비어 있다. 예외를 더할 때는 왜 한 줄이 아니라 여러 행이 필요한지, 그리고 없어질 조건을 함께 적는다.
38
- */
39
- const ALLOWED: { file: string; why: string }[] = []
40
-
41
- function sites(): { file: string; line: number; snippet: string }[] {
42
- const out: { file: string; line: number; snippet: string }[] = []
43
- const walk = (dir: string) => {
44
- for (const name of readdirSync(dir)) {
45
- const p = join(dir, name)
46
- if (statSync(p).isDirectory()) { walk(p); continue }
47
- if (!name.endsWith('.ts')) continue
48
- const src = readFileSync(p, 'utf8')
49
- /*
50
- * 큰 표의 저장소에서 `findOne` 을 부르면서 `order:` 를 주는 모양을 찾는다. 정렬을 준다는 것은
51
- * 「끝에서 한 줄」을 원한다는 뜻이고, 그것이 곧 집계다.
52
- *
53
- * 변수에 담아 부르는 형태도 본다 — 그러지 않으면 이름만 바꿔 이 검사를 지나칠 수 있다.
54
- */
55
- for (const table of BIG_TABLES) {
56
- const vars = new Set<string>()
57
- for (const m of src.matchAll(new RegExp(`const\\s+(\\w+)\\s*=\\s*getRe(?:ad)?Repository\\(${table}\\)`, 'g'))) {
58
- vars.add(m[1])
59
- }
60
- const receivers = [`getRepository(${table})`, `getReadRepository(${table})`, ...[...vars]]
61
- for (const recv of receivers) {
62
- let at = src.indexOf(recv)
63
- while (at >= 0) {
64
- const after = src.slice(at + recv.length, at + recv.length + 400)
65
- const call = /^\s*\n?\s*\.findOne\(\s*\{([\s\S]{0,320})/.exec(after)
66
- if (call && /order\s*:/.test(call[1])) {
67
- out.push({
68
- file: p.slice(ROOT.length + 1),
69
- line: src.slice(0, at).split('\n').length,
70
- snippet: call[1].replace(/\s+/g, ' ').slice(0, 90)
71
- })
72
- }
73
- at = src.indexOf(recv, at + 1)
74
- }
75
- }
76
- }
77
- }
78
- }
79
- walk(ROOT)
80
- return out
81
- }
82
-
83
- test('★ 큰 표에서 한 줄을 원하면 집계로 묻는다 — findOne(order) 으로 흉내내지 않는다', () => {
84
- const found = sites().filter(s => !ALLOWED.some(a => a.file === s.file))
85
- assert.deepEqual(
86
- found.map(s => `${s.file}:${s.line} — ${s.snippet}`),
87
- [],
88
- '이 모양은 조건에 맞는 행을 전부 만든 뒤 한 줄을 고른다. 질의 빌더로 MIN·MAX·COUNT 를 묻는다.\n' +
89
- '정말 여러 행이 필요하면 ALLOWED 에 이유와 없어질 조건을 함께 적는다.'
90
- )
91
- })
92
-
93
- test('예외 목록에는 반드시 이유가 붙는다 — 이름만 적어 지나가지 않게', () => {
94
- for (const a of ALLOWED) assert.ok(a.why.trim().length > 20, `${a.file} 의 예외에 이유가 없다`)
95
- })
96
-
97
- test('★ 고친 자리들이 실제로 집계를 쓴다 — 되돌아가지 않게 이름으로 못박는다', () => {
98
- /*
99
- * 이름으로 못박는 이유: 되돌아가도 **답은 맞기 때문에** 결과를 보는 시험으로는 잡히지 않는다.
100
- */
101
- const kpi = readFileSync(join(ROOT, 'engine', 'kpi-query.ts'), 'utf8')
102
- assert.match(kpi, /select\('MAX\(e\.eventTime\)', 'at'\)/, '마지막 업무 기록 시각은 집계로 묻는다')
103
-
104
- const engine = readFileSync(join(ROOT, 'engine', 'twin-engine.ts'), 'utf8')
105
- assert.match(engine, /select\('MAX\(e\.revision\)', 'max'\)/, '저널 머리는 집계로 묻는다')
106
-
107
- const forecast = readFileSync(join(ROOT, 'service', 'twin-forecast', 'twin-forecast-query.ts'), 'utf8')
108
- assert.match(forecast, /\$\{agg\}\(e\.eventTime\)/, '백테스트 구간의 양 끝은 집계로 묻는다')
109
-
110
- const model = readFileSync(join(ROOT, 'service', 'twin-model', 'twin-model-query.ts'), 'utf8')
111
- assert.match(model, /select\('MAX\(e\.revision\)', 'max'\)/, '모델 요약의 저널 끝도 집계로 묻는다')
112
- })
@@ -1,110 +0,0 @@
1
- /*
2
- * What an area id is, and whose area it is.
3
- *
4
- * The item panel shows a location's parent. When the parent is an area, the host answers what that id is
5
- * (`external: 'space.area'`). Nothing registered that answer until 2026-09-18, so every location's parent read
6
- * "no component can resolve this relation" on the running twin.
7
- *
8
- * The lookup is (domain, space, areaId) — the area table's own unique key. An `areaId` is unique inside a space,
9
- * so the same id can exist in two spaces of one tenant; the space comes from the twin the relation belongs to.
10
- * Held here: the name of this twin's area, "missing" for an id that is in no area of this space, and another
11
- * space's area of the same id never answering.
12
- */
13
- import { test, before, after } from 'node:test'
14
- import assert from 'node:assert/strict'
15
- import { createRequire } from 'node:module'
16
- import type { DataSource } from 'typeorm'
17
-
18
- const req = createRequire(import.meta.url)
19
- const { NamingStrategy, addDataSource, entities: shellEntities, Domain } = req('@things-factory/shell')
20
- const { entities: authEntities } = req('@things-factory/auth-base')
21
- const { entities: twinEntities } = req('../dist-server/service/index.js')
22
- const { resolveAreas, installAreaResolver, SPACE_AREA_ENTITY } = req('../dist-server/service/twin-space/area-resolver.js')
23
- const { externalResolverEntities, clearExternalResolvers, resolveExternal } = req('../dist-server/service/twin-model/external-resolver.js')
24
- const { TwinSpace } = req('../dist-server/service/twin-space/twin-space.js')
25
- const { TwinArea } = req('../dist-server/service/twin-space/twin-area.js')
26
- const { TwinInstance } = req('../dist-server/service/twin-instance/twin-instance.js')
27
- const { DataSource: TypeOrmDataSource } = req('typeorm')
28
-
29
- let ds: DataSource
30
- let domainId: string
31
- let otherDomainId: string
32
-
33
- before(async () => {
34
- ds = new TypeOrmDataSource({
35
- type: 'sqlite',
36
- database: ':memory:',
37
- synchronize: true,
38
- dropSchema: true,
39
- namingStrategy: new NamingStrategy(),
40
- entities: [...shellEntities, ...authEntities, ...twinEntities],
41
- logging: false
42
- })
43
- await ds.initialize()
44
- addDataSource('default', ds)
45
- const d = await ds.getRepository(Domain).save({ name: 'area-test', subdomain: 'area-test' } as any)
46
- const other = await ds.getRepository(Domain).save({ name: 'area-other', subdomain: 'area-other' } as any)
47
- domainId = d.id
48
- otherDomainId = other.id
49
-
50
- const spaces = ds.getRepository(TwinSpace)
51
- const north = await spaces.save({ domain: { id: domainId }, spaceId: 'north', name: 'North site' } as any)
52
- const south = await spaces.save({ domain: { id: domainId }, spaceId: 'south', name: 'South site' } as any)
53
- const far = await spaces.save({ domain: { id: otherDomainId }, spaceId: 'far', name: 'Far site' } as any)
54
-
55
- const areas = ds.getRepository(TwinArea)
56
- /* The same areaId in two spaces of one tenant — that is what the space scope is for. */
57
- await areas.save({ domain: { id: domainId }, space: { id: north.id }, areaId: 'hall-a', name: 'North Hall A' } as any)
58
- await areas.save({ domain: { id: domainId }, space: { id: south.id }, areaId: 'hall-a', name: 'South Hall A' } as any)
59
- await areas.save({ domain: { id: otherDomainId }, space: { id: far.id }, areaId: 'hall-a', name: 'Far Hall A' } as any)
60
- /* An area with no name — the answer then carries the id alone, and does not invent one. */
61
- await areas.save({ domain: { id: domainId }, space: { id: north.id }, areaId: 'annex' } as any)
62
-
63
- const instances = ds.getRepository(TwinInstance)
64
- await instances.save({ domain: { id: domainId }, instanceId: 'north-twin', kind: 'wms', restartPolicy: 'resume', purpose: 'operational', spaceId: 'north', status: 'stopped' } as any)
65
- await instances.save({ domain: { id: domainId }, instanceId: 'south-twin', kind: 'wms', restartPolicy: 'resume', purpose: 'operational', spaceId: 'south', status: 'stopped' } as any)
66
- await instances.save({ domain: { id: domainId }, instanceId: 'homeless-twin', kind: 'wms', restartPolicy: 'resume', purpose: 'operational', status: 'stopped' } as any)
67
- })
68
-
69
- after(async () => {
70
- clearExternalResolvers()
71
- await ds?.destroy()
72
- })
73
-
74
- test('an area of this twin comes back with its name', async () => {
75
- const refs = await resolveAreas(domainId, ['hall-a'], { instanceId: 'north-twin' })
76
- assert.deepEqual(refs, [{ id: 'hall-a', name: 'North Hall A' }])
77
- })
78
-
79
- test('the same areaId in another space of the same tenant never answers', async () => {
80
- const south = await resolveAreas(domainId, ['hall-a'], { instanceId: 'south-twin' })
81
- assert.deepEqual(south, [{ id: 'hall-a', name: 'South Hall A' }], 'each twin sees its own space')
82
- const other = await resolveAreas(otherDomainId, ['hall-a'], { instanceId: 'north-twin' })
83
- assert.deepEqual(other, [{ id: 'hall-a', missing: true }], 'a twin of another tenant is not this tenant’s twin')
84
- })
85
-
86
- test('an id that is in no area of this space is missing — it is not dropped', async () => {
87
- const refs = await resolveAreas(domainId, ['hall-a', 'nowhere'], { instanceId: 'north-twin' })
88
- assert.deepEqual(refs, [{ id: 'hall-a', name: 'North Hall A' }, { id: 'nowhere', missing: true }])
89
- })
90
-
91
- test('an area with no name answers with the id alone — no name is invented', async () => {
92
- const refs = await resolveAreas(domainId, ['annex'], { instanceId: 'north-twin' })
93
- assert.deepEqual(refs, [{ id: 'annex' }])
94
- })
95
-
96
- test('a twin with no space cannot have area parents, and says so', async () => {
97
- const warned: string[] = []
98
- const refs = await resolveAreas(domainId, ['hall-a'], { instanceId: 'homeless-twin' }, m => warned.push(m))
99
- assert.deepEqual(refs, [{ id: 'hall-a', missing: true }])
100
- assert.equal(warned.length, 1, 'the reason is said once, not swallowed')
101
- })
102
-
103
- test('the resolver is registered under the word the contract uses, and answers through the seam', async () => {
104
- clearExternalResolvers()
105
- installAreaResolver()
106
- assert.ok(externalResolverEntities().includes(SPACE_AREA_ENTITY))
107
- assert.equal(SPACE_AREA_ENTITY, 'space.area')
108
- const got = await resolveExternal(SPACE_AREA_ENTITY, domainId, ['hall-a'], { instanceId: 'north-twin' })
109
- assert.deepEqual(got, { refs: [{ id: 'hall-a', name: 'North Hall A' }] })
110
- })
@@ -1,161 +0,0 @@
1
- /*
2
- * ★ 주의 신호 요약 — 신호가 많은 트윈의 전송량.
3
- *
4
- * ── 계기 ────────────────────────────────────────────────────────────────────
5
- * 축 선택으로 리프레시를 80KB → 2KB 로 줄였는데 **신호가 많은 트윈은 거기서 막혔다**:
6
- * `hatio-yard` 는 신호 397건이 108KB 라 5배 감소에 그쳤다. 그런데 화면이 그 397건으로 하는 일은
7
- * 둘뿐이다 — 레일에 20건만 그리고, 자리 7곳의 색을 뽑는다.
8
- *
9
- * ── 이 테스트가 지키는 것 ───────────────────────────────────────────────────
10
- * ① **자리 색은 전량을 근거로** 계산된다. 상위 N 으로 줄이면 20위 밖의 신호를 가진 자리가 색을 잃는다.
11
- * ② **알리지 않고 자르지 않는다.** 전체 개수를 함께 보내야 레일이 "N건 더" 를 말할 수 있다.
12
- * ③ **순서가 화면과 같다.** 서버가 고른 20건이 화면이 고를 20건과 달라지면 아무 데서도 안 드러난다.
13
- */
14
- import { test } from 'node:test'
15
- import assert from 'node:assert/strict'
16
- import { readFile } from 'node:fs/promises'
17
-
18
- import { digestAttentions, compareAttentions, mergeLensAttentions } from '../server/engine/attention-digest.ts'
19
-
20
- const attn = (id: string, severity: string, locationId?: string, state?: string) => ({ id, severity, state, anchor: locationId ? { locationId } : undefined })
21
-
22
- test('상위 N 만 남기고 전체 개수를 함께 낸다 — 알리지 않고 자르지 않는다', () => {
23
- const all = Array.from({ length: 50 }, (_, i) => attn(`a${i}`, 'low', `loc-${i % 3}`))
24
- const d = digestAttentions(all, 20)
25
- assert.equal(d.attentions.length, 20)
26
- assert.equal(d.attentionTotal, 50, '전체 개수가 없으면 화면이 "괜찮아졌다" 로 읽는다')
27
- })
28
-
29
- test('자리 색은 전량을 근거로 처리한다 — 상위 N 밖의 자리도 색을 갖는다', () => {
30
- /* 앞 20건은 loc-hot 에, 21번째 한 건만 loc-cold 에 — 잘린 뒤에 계산하면 loc-cold 가 색을 잃는다. */
31
- const all = [...Array.from({ length: 20 }, (_, i) => attn(`hot${i}`, 'high', 'loc-hot')), attn('cold', 'critical', 'loc-cold')]
32
- const d = digestAttentions(all, 20)
33
- assert.equal(d.attentions.length, 20)
34
- assert.equal(d.severityByLocation['loc-cold'], 'critical', '상위 N 밖의 신호도 자리 색에는 반영돼야 한다')
35
- assert.equal(d.severityByLocation['loc-hot'], 'high')
36
- })
37
-
38
- test('자리마다 가장 급한 심각도가 남는다', () => {
39
- const d = digestAttentions([attn('a', 'low', 'n1'), attn('b', 'critical', 'n1'), attn('c', 'medium', 'n1')])
40
- assert.equal(d.severityByLocation['n1'], 'critical')
41
- })
42
-
43
- test('순서는 화면과 같다 — 확인된 것은 아래로, 그다음 심각도순', () => {
44
- const all = [attn('acked-crit', 'critical', 'n1', 'acknowledged'), attn('low', 'low', 'n2'), attn('high', 'high', 'n3')]
45
- const d = digestAttentions(all, 2)
46
- assert.deepEqual(d.attentions.map(a => a.id), ['high', 'low'], '확인된 critical 보다 확인 안 된 것이 먼저다')
47
- assert.equal(d.attentionTotal, 3)
48
- })
49
-
50
- test('한도를 지정하지 않으면 자르지 않는다 — 이 값을 모르는 소비처가 일부만 받으면 안 된다', () => {
51
- const all = Array.from({ length: 30 }, (_, i) => attn(`a${i}`, 'low'))
52
- assert.equal(digestAttentions(all).attentions.length, 30)
53
- assert.equal(digestAttentions(all, 0).attentions.length, 30)
54
- assert.equal(digestAttentions(all, -5).attentions.length, 30)
55
- })
56
-
57
- test('자리에 붙지 않은 신호는 색 요약에 들어가지 않는다 — 없는 자리를 만들지 않는다', () => {
58
- const d = digestAttentions([attn('orphan', 'critical'), attn('anchored', 'low', 'n1')])
59
- assert.deepEqual(Object.keys(d.severityByLocation), ['n1'])
60
- assert.equal(d.attentionTotal, 2, '색에 안 들어가도 개수에는 든다')
61
- })
62
-
63
- test('신호가 없으면 빈 요약 — 없는 것을 만들지 않는다', () => {
64
- for (const v of [undefined, null, []]) {
65
- const d = digestAttentions(v as any, 20)
66
- assert.deepEqual(d.attentions, [])
67
- assert.equal(d.attentionTotal, 0)
68
- assert.deepEqual(d.severityByLocation, {})
69
- }
70
- })
71
-
72
- test('정렬 함수는 원본을 바꾸지 않는다 — 스냅샷을 제자리에서 흔들면 다른 소비처가 영향받는다', () => {
73
- const all = [attn('low', 'low'), attn('crit', 'critical')]
74
- const before = all.map(a => a.id)
75
- digestAttentions(all, 1)
76
- assert.deepEqual(all.map(a => a.id), before)
77
- assert.equal(compareAttentions(all[1], all[0]) < 0, true, 'critical 이 앞이다')
78
- })
79
-
80
- /*
81
- * ── 여러 렌즈를 한 현장으로 모으기 (2026-08-05) ────────────────────────────
82
- * 한 공장에 WMS·MES·YMS 가 함께 있으므로 "이 현장에서 봐야 할 것" 은 렌즈 하나로 답할 수 없다.
83
- * 예전에는 화면이 인스턴스마다 물어 손으로 합쳤고, 그러면 정렬 규칙이 화면마다 갈린다.
84
- *
85
- * 모으면서 알리지 않고 틀릴 수 있는 자리 셋을 여기서 못 박는다.
86
- */
87
- test('★ 어느 트윈에서 온 신호인지 붙는다 — 조치는 결국 그 트윈에 보내야 한다', () => {
88
- const d = mergeLensAttentions([
89
- { instanceId: 'wms', attentions: [attn('a', 'high', 'dock-1')] },
90
- { instanceId: 'yms', attentions: [attn('b', 'low', 'gate-1')] }
91
- ])
92
- assert.deepEqual(d.attentions.map(a => [a.id, (a as any).instanceId]), [['a', 'wms'], ['b', 'yms']])
93
- })
94
-
95
- test('★ 순서는 렌즈 순서가 아니라 급한 순서다 — 뒤 렌즈의 심각한 신호가 밀려나면 안 된다', () => {
96
- const d = mergeLensAttentions(
97
- [
98
- { instanceId: 'wms', attentions: [attn('low-1', 'low'), attn('low-2', 'low')] },
99
- { instanceId: 'mes', attentions: [attn('crit', 'critical')] }
100
- ],
101
- 1
102
- )
103
- assert.deepEqual(d.attentions.map(a => a.id), ['crit'], '상위 1건은 뒤 렌즈의 critical 이어야 한다')
104
- assert.equal(d.attentionTotal, 3)
105
- })
106
-
107
- test('★ 두 렌즈가 같은 대상을 지목하면 더 급한 쪽이 색을 정한다 — 하나의 현실이므로', () => {
108
- const d = mergeLensAttentions([
109
- { instanceId: 'wms', attentions: [attn('a', 'low', 'dock-1')] },
110
- { instanceId: 'yms', attentions: [attn('b', 'critical', 'dock-1')] }
111
- ])
112
- assert.equal(d.severityByLocation['dock-1'], 'critical')
113
- /* 렌즈 순서를 뒤집어도 같아야 한다 — 색이 순서에 따라 달라지면 화면이 새로고침마다 바뀐다. */
114
- const flipped = mergeLensAttentions([
115
- { instanceId: 'yms', attentions: [attn('b', 'critical', 'dock-1')] },
116
- { instanceId: 'wms', attentions: [attn('a', 'low', 'dock-1')] }
117
- ])
118
- assert.equal(flipped.severityByLocation['dock-1'], 'critical')
119
- })
120
-
121
- test('★ 신호가 없는 렌즈는 아무것도 보태지 않는다 — 빈 렌즈가 개수를 늘리지 않게', () => {
122
- const d = mergeLensAttentions([
123
- { instanceId: 'wms', attentions: [attn('a', 'low')] },
124
- { instanceId: 'mes', attentions: [] },
125
- { instanceId: 'yms', attentions: undefined }
126
- ])
127
- assert.equal(d.attentionTotal, 1)
128
- assert.deepEqual(d.attentions.map(a => a.id), ['a'])
129
- })
130
-
131
- test('★ 렌즈가 하나도 없으면 빈 요약 — 공간에 배치된 트윈이 없을 때', () => {
132
- const d = mergeLensAttentions([], 20)
133
- assert.deepEqual(d.attentions, [])
134
- assert.equal(d.attentionTotal, 0)
135
- assert.deepEqual(d.severityByLocation, {})
136
- })
137
-
138
- /*
139
- * ── 자를 수 있는 문만 자른다 (2026-09-19, 수석 아키텍트 판정) ────────────────
140
- *
141
- * 목록 문(`twinAttentions`)에 `limit` 이 있었다. 자르면서 **몇 건을 잘랐는지는 답에 실을 자리가
142
- * 없었다** — 답이 맨 목록이라서다. 그러면 스무 건을 받은 화면은 그것이 전부인지 이백 중 스물인지
143
- * 구별할 수 없고, 그 구별이 없으면 「괜찮아졌다」로 읽힌다(위 ②와 같은 자리).
144
- *
145
- * 그래서 자르는 일은 **자른 수를 말할 수 있는 문**에만 둔다. 이 검사는 그 규칙을 소스에서 센다 —
146
- * 인자를 되돌려 놓으면 빨강이 된다.
147
- */
148
- test('★ 목록 문은 자르지 않는다 — 자르는 인자는 전체 개수를 함께 내는 문에만 있다', async () => {
149
- const source = await readFile(new URL('../server/service/twin-attention/twin-attention-query.ts', import.meta.url), 'utf-8')
150
-
151
- const listAt = source.indexOf('async twinAttentions(')
152
- const digestAt = source.indexOf('async twinAttentionDigest(')
153
- assert.ok(listAt >= 0 && digestAt > listAt, '두 문을 못 찾았다 — 이 검사는 아무것도 지키지 않는다')
154
-
155
- const list = source.slice(listAt, digestAt)
156
- const digest = source.slice(digestAt)
157
-
158
- assert.ok(!/@Arg\(\s*'limit'/.test(list), '목록 문에 자르는 인자가 있다 — 자른 수를 답에 실을 자리가 없다')
159
- assert.ok(/@Arg\(\s*'limit'/.test(digest), '자르는 문이 없어졌다 — 화면이 상위 N 을 받을 길이 없다')
160
- assert.ok(/digestAttentions\(/.test(digest), '자르는 문은 전체 개수를 함께 내는 함수를 지나야 한다')
161
- })
@@ -1,152 +0,0 @@
1
- /*
2
- * 축의 선언이 읽기 문을 그대로 지나간다 — `journalAxis` · `describedBy` (ADR-0074).
3
- *
4
- * 둘은 앱의 화면 상수에 있던 것이다. 그 자리에 있는 동안 축 이름이 한 세대 바뀌자 표가 따라오지
5
- * 못했고, 로케이션 · 오더 · 품목의 360 은 저널을 **묻지도 않은 채** 「이 개념은 이력 축이 없다」를
6
- * 그렸다. 계약으로 올라온 지금, 화면이 다시 자기 표를 만들지 않으려면 읽기 문이 그 값을 날라야 한다.
7
- *
8
- * 여기서 지키는 것은 하나다: **계약이 말한 값이 그대로 도착한다.** 값을 이 파일에 다시 적지 않는다 —
9
- * 다시 적으면 계약이 바뀔 때 시험이 같이 썩고, 지나가는지를 못 본다.
10
- */
11
- import { test, before, after } from 'node:test'
12
- import assert from 'node:assert/strict'
13
- import { createRequire } from 'node:module'
14
- import type { DataSource } from 'typeorm'
15
-
16
- const req = createRequire(import.meta.url)
17
- const { NamingStrategy, addDataSource, entities: shellEntities, Domain } = req('@things-factory/shell')
18
- const { entities: authEntities } = req('@things-factory/auth-base')
19
- const { entities: twinEntities } = req('../dist-server/service/index.js')
20
- const { TwinEngine } = req('../dist-server/engine/index.js')
21
- const { TwinModelItemQuery } = req('../dist-server/service/twin-model/twin-model-item-query.js')
22
- const { axisInfo } = req('@operato/ops-contract')
23
- const { DataSource: TypeOrmDataSource } = req('typeorm')
24
-
25
- let ds: DataSource
26
- let q: any
27
- let ctx: any
28
- const INSTANCE = 'declaration-probe'
29
-
30
- before(async () => {
31
- ds = new TypeOrmDataSource({
32
- type: 'sqlite',
33
- database: ':memory:',
34
- synchronize: true,
35
- dropSchema: true,
36
- namingStrategy: new NamingStrategy(),
37
- entities: [...shellEntities, ...authEntities, ...twinEntities],
38
- logging: false
39
- })
40
- await ds.initialize()
41
- addDataSource('default', ds)
42
- const d = await ds.getRepository(Domain).save({ name: 'decl-test', subdomain: 'decl-test' } as any)
43
- q = new TwinModelItemQuery()
44
- ctx = { state: { domain: { id: d.id } } }
45
-
46
- /*
47
- * 축마다 **자기 모양대로** 한 항목씩 — 설명 칸이 축마다 다른 이름으로 온다는 것이 아래 시험의 요점이다.
48
- * (등급 넷과 검사 명세는 `name` 으로 들어오는데 형 선언은 `description` 을 말한다 — 실측, 2026-09-18.)
49
- */
50
- await TwinEngine.ingestMaster(d.id, {
51
- source: INSTANCE,
52
- system: 'wms',
53
- siteName: 'declaration site',
54
- space: { width: 40, depth: 20, unit: 'm' },
55
- locations: [{ id: 'bin-1', type: 'storage', role: 'location', name: 'Bin 1', capacity: 10 }],
56
- equipment: [{ id: 'fk-1', kind: 'forklift', homeLocationId: 'bin-1' }],
57
- equipmentClasses: [{ id: 'EC-FORKLIFT', name: '지게차' }],
58
- materialClasses: [{ id: 'MC-BOX', name: '상자류' }],
59
- materialDefinitions: [{ id: 'MD-BOX-01', name: '표준 상자', materialClassIds: ['MC-BOX'] }],
60
- testSpecifications: [{ id: 'TS-DROP', name: '낙하 시험', version: '1', criteria: [] }]
61
- }, 'reset')
62
- })
63
-
64
- after(async () => {
65
- await TwinEngine.stop(ctx.state.domain.id, INSTANCE).catch(() => {})
66
- await ds?.destroy()
67
- })
68
-
69
- test('★ 자리의 이력 축과 설명 필드가 계약이 말한 그대로 도착한다', async () => {
70
- const item = await q.twinModelItem(INSTANCE, 'locations', 'bin-1', ctx)
71
- const declared = axisInfo('locations')
72
- assert.ok(declared?.journalAxis, '계약이 자리의 저널 축을 말하지 않는다 — 시험의 기준이 비었다')
73
- assert.equal(item.identity.journalAxis, declared.journalAxis)
74
- assert.deepEqual(item.identity.describedBy, declared.describedBy)
75
- })
76
-
77
- test('★ 설비도 같은 자리에서 자기 선언을 받는다 — 축마다 다른 값이 온다', async () => {
78
- const item = await q.twinModelItem(INSTANCE, 'equipment', 'fk-1', ctx)
79
- const declared = axisInfo('equipment')
80
- assert.equal(item.identity.journalAxis, declared!.journalAxis)
81
- assert.deepEqual(item.identity.describedBy, declared!.describedBy)
82
- /* 두 축이 같은 값을 받으면 「지나간다」를 못 본 것이다. */
83
- assert.notEqual(declared!.journalAxis, axisInfo('locations')!.journalAxis)
84
- })
85
-
86
- test('★ 저널이 그 축으로 기록하지 않는 개념은 null 로 온다 — 없는 것을 이름으로 채우지 않는다', async () => {
87
- const declared = axisInfo('operations')
88
- assert.equal(declared?.journalAxis, undefined, '명세 축은 저널 축을 갖지 않는다')
89
- /* 이 트윈에는 공정 선언이 없다 — 선언이 없는 축도 문은 같은 모양으로 답한다. */
90
- const item = await q.twinModelItem(INSTANCE, 'operations', 'no-such-operation', ctx)
91
- if (item) assert.equal(item.identity.journalAxis, null, '없는 것은 null 이고 빈 문자열이 아니다')
92
- })
93
-
94
- /*
95
- * 상태 축에 없는 개체를 물으면 — **그런 개체가 없다**고 답한다.
96
- *
97
- * 2026-09-18, 도는 서버에서: 지어낸 작업 식별자(`tasks:T-1`)로 물었더니 패널이 하나 돌아왔고 화면은
98
- * 「트윈이 실제로 본 것입니다」라고 적었다. 있지도 않은 개체가 **값이 비어 있는 개체**처럼 보였다.
99
- * 갈래가 `!snap || !found` 하나여서 두 사실이 한 답으로 접혔기 때문이다.
100
- *
101
- * 상태를 읽었는데 없다 → 그런 개체가 없다(문서 축과 같은 `null`)
102
- * 상태를 못 읽었다 → 모른다. 이유를 코드로 말한다(`not-running`)
103
- */
104
- test('★ 상태를 읽었는데 그 개체가 없으면 없다고 답한다 — 빈 개체를 만들지 않는다', async () => {
105
- const gone = await q.twinModelItem(INSTANCE, 'tasks', 'NO-SUCH-TASK-ID', ctx)
106
- assert.equal(gone, null, '없는 개체에 패널을 돌려주면 화면이 그것을 그린다')
107
- })
108
-
109
- test('★ 같은 물음을 문서 축에 해도 같은 답이다 — 축마다 다른 말을 하지 않는다', async () => {
110
- const gone = await q.twinModelItem(INSTANCE, 'locations', 'NO-SUCH-LOCATION', ctx)
111
- assert.equal(gone, null)
112
- })
113
-
114
- test('★ 있는 개체는 그대로 답한다 — 위의 고침이 다 지워 버리지 않았는지', async () => {
115
- const item = await q.twinModelItem(INSTANCE, 'locations', 'bin-1', ctx)
116
- assert.ok(item, '있는 개체가 사라졌다')
117
- assert.equal(item.itemId, 'bin-1')
118
- })
119
-
120
- /*
121
- * **선언이 고른 칸이 실제 항목에 있는가** (2026-09-18).
122
- *
123
- * `describedBy` 를 형 선언에서 뽑아 적었더니 여섯 축이 빗나갔다 — 등급 넷 · 품목 정의 · 검사 명세는
124
- * 형이 `description` 을 말하는데 들어오는 자료는 `name` 을 든다. 화면은 오류 없이 **밑줄이 없는
125
- * 제목**만 그렸다(도는 트윈에서 실측). 계약과 자료가 갈린 것을 시험이 못 잡았던 이유는, 그 시험이
126
- * 「그 이름이 계약 어딘가에 선언돼 있나」까지만 봤기 때문이다.
127
- *
128
- * 그래서 여기서는 **들어온 항목**에 대고 잰다: 선언한 칸 중 적어도 하나가 그 항목에 값으로 있어야 한다.
129
- */
130
- test('★ 선언이 고른 칸 중 하나는 실제 항목이 들고 있다 — 계약과 자료가 갈리면 밑줄이 사라진다', async () => {
131
- const sample: Record<string, string> = {
132
- locations: 'bin-1',
133
- equipment: 'fk-1',
134
- equipmentClasses: 'EC-FORKLIFT',
135
- materialClasses: 'MC-BOX',
136
- materialDefinitions: 'MD-BOX-01',
137
- testSpecifications: 'TS-DROP'
138
- }
139
- const missing: string[] = []
140
- for (const [axis, itemId] of Object.entries(sample)) {
141
- const item = await q.twinModelItem(INSTANCE, axis, itemId, ctx)
142
- assert.ok(item, `${axis}: 픽스처가 안 들어갔다 — 이 시험이 아무것도 재지 못한다`)
143
- const keys: string[] = item.identity?.describedBy ?? []
144
- assert.ok(keys.length, `${axis}: 계약이 설명 칸을 말하지 않는다`)
145
- const has = keys.some(k => {
146
- const v = (item.observed ?? {})[k] ?? (item.declared ?? {})[k]
147
- return v != null && v !== ''
148
- })
149
- if (!has) missing.push(`${axis}: 선언은 [${keys.join(', ')}] 인데 항목이 든 것은 [${Object.keys(item.declared ?? {}).join(', ')}]`)
150
- }
151
- assert.deepEqual(missing, [], missing.join('\n'))
152
- })
@@ -1,71 +0,0 @@
1
- /*
2
- * 상태가 빈 축의 이유 — **「아직 없다」와 「왔는데 상태에 없다」를 가른다** (2026-08-22).
3
- *
4
- * ── 무엇이 있었나 ───────────────────────────────────────────────────────────
5
- * 카드가 「작업 — 아직 하나도 없습니다」라고 말했다. 그 트윈의 저널에는 `task.status` 5,786건이 있었고
6
- * **마지막 상태가 `in-progress`** 였다. 사용자가 「작업 지시 835건인데 작업이 0인 이유」를 물었고,
7
- * 원인은 관측 모드 커널이 관측기의 작업을 스냅샷으로 내보내지 않는 것이었다(커널 자리, 그 레인에 넘겼다).
8
- *
9
- * **화면 몫은 단정하지 않는 것이다.** 「아직 하나도 없습니다」는 「선언은 있고 사실이 아직 일어나지
10
- * 않았다」는 뜻인데 실제로는 「사실이 일어났는데 상태에 오지 못했다」였다. 그 차이를 화면이 말하지
11
- * 않아서 사용자가 직접 조사해야 했다.
12
- *
13
- * 이 시험이 지키는 것:
14
- * ① 저널에 그 축의 사건이 있으면 **그렇게 말한다**.
15
- * ② 없으면 예전 그대로 「아직 없다」다.
16
- * ③ 판단할 수 없는 축은 **아무 말도 만들지 않는다**(`null`) — 모르는 것을 새 사실로 바꾸지 않는다.
17
- * ④ 한 건만 묻는다 — 세는 것도 비용이다(저널 358만 행에서 전량 세기는 5.32초였다).
18
- */
19
- import { test } from 'node:test'
20
- import assert from 'node:assert/strict'
21
-
22
- import { axisSeenInJournal } from '../server/service/twin-model/axis-journal-evidence.ts'
23
-
24
- /** 저장소 흉내 — 어떤 조건으로 몇 번 물었는지 기록한다. */
25
- function repoWith(present: string[]) {
26
- const asked: any[] = []
27
- return {
28
- asked,
29
- async find(opts: any) {
30
- asked.push(opts)
31
- const t = opts?.where?.eventType
32
- const hit =
33
- typeof t === 'string'
34
- ? present.includes(t)
35
- : /* Like(…) 객체 — 접두사로 본다 */
36
- present.some(p => p.startsWith(String(t?._value ?? '').replace('%', '')))
37
- return hit ? [{ id: 'x' }] : []
38
- }
39
- } as any
40
- }
41
-
42
- const WHERE = { domain: { id: 'd' }, instanceId: 'twin-1' }
43
-
44
- test('저널에 그 축의 사건이 있으면 그렇게 말한다 — 작업', async () => {
45
- const repo = repoWith(['task.status'])
46
- assert.equal(await axisSeenInJournal(repo, WHERE, 'tasks'), true)
47
- })
48
-
49
- test('없으면 예전 그대로 — 아직 없다', async () => {
50
- const repo = repoWith(['order.status'])
51
- assert.equal(await axisSeenInJournal(repo, WHERE, 'tasks'), false)
52
- })
53
-
54
- test('물품은 사건 이름이 여럿이라 접두사로 본다 — 커널이 이름을 늘려도 낡지 않게', async () => {
55
- const repo = repoWith(['epcis.AggregationEvent'])
56
- assert.equal(await axisSeenInJournal(repo, WHERE, 'items'), true)
57
- })
58
-
59
- test('판단할 수 없는 축은 아무 말도 만들지 않는다', async () => {
60
- const repo = repoWith(['task.status'])
61
- assert.equal(await axisSeenInJournal(repo, WHERE, 'locations'), null, '표에 없는 축은 모른다')
62
- assert.equal(repo.asked.length, 0, '모르는 축을 두고 저널을 묻지 않는다')
63
- })
64
-
65
- test('한 건만 묻는다 — 세는 것도 비용이다', async () => {
66
- const repo = repoWith(['task.status'])
67
- await axisSeenInJournal(repo, WHERE, 'tasks')
68
- assert.equal(repo.asked.length, 1)
69
- assert.equal(repo.asked[0].take, 1, '한 건만 읽는다')
70
- assert.deepEqual(repo.asked[0].select, ['id'], '키 컬럼만 읽는다(행 본문을 만들지 않는다)')
71
- })