@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,103 +0,0 @@
1
- /*
2
- * ★ **아무것도 듣지 못한 것을 「비었다」로 적지 않는다** — 체크포인트가 좋은 스냅샷을 덮지 않게.
3
- *
4
- * ── 무엇이 손실을 영구화하고 있었나 (2026-08-24 실측) ────────────────────────
5
- * 미러가 재기동하면 관측 축(재고·오더·작업)을 들고 오지 않는다(`startLive` 가 되찾은 상태를 버린다 —
6
- * 「다음 계측이 정정한다」는 전제). 그런데 원본이 **커서 증분**으로 말하는 현장에서는 그 정정이 오지
7
- * 않는다: 커서가 따라잡힌 뒤 원본이 변하지 않으면 미러는 영구히 빈 채다.
8
- *
9
- * 실측(포천, `operato-chef-v1-pocheon`):
10
- *
11
- * 저널을 계산하면 items 741 · orders 2,856 · tasks 9,250 · nowTime 2026-04-15
12
- * 라이브 미러 items 0 · orders 0 · tasks 0 · nowTime 2026-01-01
13
- * 저장된 스냅샷 rev 221,884 · items 741 · orders 2,780 · tasks 6,353 (어제 것)
14
- * 그런데 이 버전이 같은 키에 **빈 상태**를 쓰고 있었다
15
- *
16
- * 그러면 되살릴 캐시가 사라진다. 재기동이 상태를 버리는 것은 저널에서 되살릴 수 있지만, **캐시를
17
- * 지우는 것은 그 복구 수단을 함께 지운다.**
18
- *
19
- * ── 왜 리비전으로는 막을 수 없나 ────────────────────────────────────────────
20
- * 저널 줄 번호는 **관측이 없어도 자란다**(다른 축·다른 트윈의 사건, 체크포인트 자체). 그래서
21
- * 「리비전이 더 크면 진전」이라는 규칙은 빈 상태를 통과시킨다.
22
- *
23
- * 막는 기준은 **「들은 것이 있나」**다. 유입이 한 건도 없었다면 그 빈 상태는 원본이 「비었다」고
24
- * 말한 것이 아니라 **우리가 아무것도 못 들은 것**이다 — 그 둘을 같은 값으로 적으면 「모름」이
25
- * 「없음」이 된다. 이 저장소가 여러 번 거절한 모양이다.
26
- *
27
- * 원본이 실제로 「다 비었다」고 말한 경우는 막지 않는다 — 그때는 유입이 있었으므로 이 문을 지난다.
28
- *
29
- * ── 엔진 본체는 부를 수 없다 ────────────────────────────────────────────────
30
- * DB 를 물고 있어 시험에서 부르지 못한다(§`snapshot-freshness` 와 같은 사정). 그래서 판정식만 떼어
31
- * 시험하고, **그 식이 엔진에 실제로 있는지**를 소스로 함께 확인한다 — 식만 시험하면 엔진이 그것을
32
- * 쓰지 않아도 초록이다.
33
- */
34
- import { test } from 'node:test'
35
- import assert from 'node:assert/strict'
36
- import { readFileSync } from 'node:fs'
37
- import { join } from 'node:path'
38
-
39
- /** 엔진의 조건과 같은 식(`twin-engine.persistSnapshot`). */
40
- const observed = (s: any): number => (s?.items?.length ?? 0) + (s?.orders?.length ?? 0) + (s?.tasks?.length ?? 0)
41
-
42
- const refuses = (live: any, stored: any, ingestedTotal: number): boolean =>
43
- !(ingestedTotal > 0) && observed(live) === 0 && observed(stored) > 0
44
-
45
- const RICH = { items: [{ epc: 'a' }], orders: [{ id: 'o' }], tasks: [{ id: 't' }] }
46
- const EMPTY = { items: [], orders: [], tasks: [] }
47
-
48
- test('못 들었고 라이브가 비었는데 저장된 것에 사실이 있으면 — **거절한다**', () => {
49
- /* ★ 이 시험이 막는 것. 통과시키면 되살릴 유일한 사본이 사라진다. */
50
- assert.equal(refuses(EMPTY, RICH, 0), true)
51
- })
52
-
53
- test('들은 것이 있으면 통과한다 — 원본이 「다 비었다」고 말한 것은 사실이다', () => {
54
- /*
55
- * 창고가 실제로 비는 것은 정상이다. 그때는 유입이 있었으므로 그 빈 상태가 **관측**이고,
56
- * 여기서 막으면 스냅샷이 영구히 낡는다(고치려던 것의 반대 방향으로 틀린다).
57
- */
58
- assert.equal(refuses(EMPTY, RICH, 1), false)
59
- assert.equal(refuses(EMPTY, RICH, 24839), false)
60
- })
61
-
62
- test('라이브에 사실이 있으면 통과한다 — 못 들었어도 심어진 상태는 지킬 값이다', () => {
63
- assert.equal(refuses(RICH, RICH, 0), false)
64
- })
65
-
66
- test('저장된 것이 비어 있으면 막을 것이 없다 — 첫 체크포인트를 가로막지 않는다', () => {
67
- /* 처음 뜬 트윈은 저장된 것이 없다. 여기서 막으면 그 트윈은 영원히 스냅샷을 갖지 못한다. */
68
- assert.equal(refuses(EMPTY, EMPTY, 0), false)
69
- assert.equal(refuses(EMPTY, null, 0), false)
70
- assert.equal(refuses(EMPTY, undefined, 0), false)
71
- })
72
-
73
- test('축 하나만 남아도 사실이다 — 셋을 합쳐 센다', () => {
74
- /*
75
- * 오더만 남고 재고가 빈 상태는 흔하다(다 내보낸 창고). 축마다 따로 판정하면 그 상태가
76
- * 「비었다」로 읽힌다.
77
- */
78
- assert.equal(refuses(EMPTY, { items: [], orders: [{ id: 'o' }], tasks: [] }, 0), true)
79
- assert.equal(refuses(EMPTY, { items: [], orders: [], tasks: [{ id: 't' }] }, 0), true)
80
- })
81
-
82
- test('리비전은 판정에 쓰지 않는다 — 저널 번호는 관측이 없어도 자란다', () => {
83
- /*
84
- * ★ 이 단정이 **틀린 기준으로 돌아가는 것**을 막는다. 실측에서 저장된 스냅샷의 리비전은 221,884
85
- * 였고 라이브는 그보다 큰 번호를 들고 있었다 — 리비전을 기준으로 삼으면 빈 상태가 통과한다.
86
- */
87
- const live = { ...EMPTY, revision: 999999 }
88
- const stored = { ...RICH, revision: 1 }
89
- assert.equal(refuses(live, stored, 0), true, '번호가 커도 사실이 없으면 덮지 않는다')
90
- })
91
-
92
- test('엔진이 실제로 이 판정을 한다 — 식만 시험하면 엔진이 안 써도 초록이다', () => {
93
- const src = readFileSync(join(import.meta.dirname, '..', 'server', 'engine', 'twin-engine.ts'), 'utf8')
94
- /* 주석을 걷어낸 코드만 — 「덮지 않는다」를 적어 둔 근거가 가드를 뒤집지 않게. */
95
- const code = src.replace(/\/\*[\s\S]*?\*\//g, ' ').replace(/(^|[^:])\/\/.*$/gm, '$1')
96
- const at = code.indexOf('persistSnapshot')
97
- assert.ok(at > 0, 'persistSnapshot 이 있어야 한다')
98
- const body = code.slice(at, at + 2000)
99
- assert.match(body, /ingestedTotal/, '「들은 것이 있나」를 본다')
100
- assert.match(body, /items\?\.length[\s\S]{0,80}orders\?\.length[\s\S]{0,80}tasks\?\.length/, '관측 축 셋을 합쳐 센다')
101
- assert.match(body, /checkpoint refused/, '거절을 말한다 — 알리지 않고 거절하지 않는다')
102
- assert.doesNotMatch(body.slice(0, body.indexOf('checkpoint refused')), /revision >|revision </, '리비전 비교로 판정하지 않는다')
103
- })
@@ -1,117 +0,0 @@
1
- /*
2
- * ★ **어느 레시피로 만들었나 — 짐작하지 않는다.**
3
- *
4
- * ── 무엇이 있었나 (2026-09-05) ─────────────────────────────────────────────
5
- * 계보 진단이 자재로 되짚어 `recipes.find(...)` 로 **먼저 걸리는 하나**를 골랐다. 배열 순서가 답을
6
- * 정한다는 뜻이다. 그리고 한 자재에 레시피가 둘인 경우가 이미 있다 — plant 마스터 실측:
7
- *
8
- * BOLT-M8 → RCP-BOLT-STD 유효시작 2026-09-01 09:25:29.447
9
- * RCP-BOLT-FAST 유효시작 2026-09-01 09:25:29.510
10
- *
11
- * 빠른 방식으로 만든 볼트인데 표준 방식과 견주고 「설계와 다릅니다」가 나온다. 사람은 라인에
12
- * 문제가 있다고 믿고 확인하러 간다. **틀린 답이 확신에 찬 얼굴로 나오는 것**이 그 상태였다.
13
- *
14
- * ── 답은 적혀 있었다 ───────────────────────────────────────────────────────
15
- * 만들 때 정해지는 사실이고 커널이 오더에 싣는다(`FlowOrder.recipeKey`). 변환 사건은 그 오더를
16
- * 거래 식별자로 가리키고, 계보 함수는 그 값을 이미 꺼내 놓고도 쓰지 않았다.
17
- *
18
- * 세 자리가 다 있었고 **마지막 연결만 없었다.**
19
- *
20
- * ── 왜 순수 함수인가 ───────────────────────────────────────────────────────
21
- * 규칙만 따로 재려면 DB 도 트윈도 필요 없어야 한다. 여기서 값으로 못 박아 두면 다음에 「하나쯤
22
- * 골라 주는 게 친절하지 않나」가 올라올 때 그 줄이 빨개진다.
23
- */
24
- import { test } from 'node:test'
25
- import assert from 'node:assert/strict'
26
-
27
- import { chooseRecipe } from '../server/service/twin-model/choose-recipe.js'
28
-
29
- const STD = { key: 'RCP-BOLT-STD', outputs: [{ material: 'BOLT-M8' }] }
30
- const FAST = { key: 'RCP-BOLT-FAST', outputs: [{ material: 'BOLT-M8' }] }
31
- const OTHER = { key: 'RCP-CT-BLANK', outputs: [{ material: 'CT-BLANK' }] }
32
-
33
- const ALL = [STD, FAST, OTHER]
34
-
35
- /* ── 오더가 말하면 그것을 쓴다 ───────────────────────────────────────────── */
36
-
37
- test('★ 오더가 말한 레시피를 쓴다 — 버전이 둘이어도 고민하지 않는다', () => {
38
- const r = chooseRecipe(ALL, [STD, FAST], 'RCP-BOLT-FAST')
39
-
40
- assert.equal(r.recipe, FAST, '오더가 말했는데 다른 것을 골랐다')
41
- assert.equal(r.basis, 'order')
42
- })
43
-
44
- test('★ 배열 순서가 답을 바꾸지 않는다 — 옛 결함의 핵심이 이것이었다', () => {
45
- const forward = chooseRecipe([STD, FAST], [STD, FAST], 'RCP-BOLT-FAST')
46
- const reversed = chooseRecipe([FAST, STD], [FAST, STD], 'RCP-BOLT-FAST')
47
-
48
- assert.equal(forward.recipe, reversed.recipe, '순서를 뒤집으니 답이 달라졌다')
49
- assert.equal(forward.recipe?.key, 'RCP-BOLT-FAST')
50
- })
51
-
52
- /* ── 오더가 말 안 할 때 ─────────────────────────────────────────────────── */
53
-
54
- test('★ 후보가 하나면 쓴다 — 고를 것이 없으면 짐작이 아니다', () => {
55
- const r = chooseRecipe(ALL, [OTHER], undefined)
56
-
57
- assert.equal(r.recipe, OTHER)
58
- assert.equal(r.basis, 'only-candidate')
59
- })
60
-
61
- test('★ 후보가 둘 이상이면 답하지 않는다 — 여기가 옛 결함의 자리다', () => {
62
- /*
63
- * 옛 코드: `recipes.find(...)` — 이 자리에서 STD 를 돌려줬다. 그 답이 틀릴 확률이 절반이고,
64
- * 틀렸다는 사실은 아무 데도 안 남았다.
65
- */
66
- const r = chooseRecipe(ALL, [STD, FAST], undefined)
67
-
68
- assert.equal(r.recipe, undefined, '어느 것으로 만들었는지 모르는 채로 하나를 골랐다')
69
- assert.equal(r.basis, 'ambiguous')
70
- })
71
-
72
- /* ── 어긋남과 모름을 가른다 ─────────────────────────────────────────────── */
73
-
74
- test('★ 오더가 말한 레시피가 선언에 없으면 「모른다」가 아니라 「어긋났다」', () => {
75
- /*
76
- * 사람이 할 일이 다르다. 어긋남은 선언이나 원본을 고칠 일이고, 모호함은 그 개체의 기록이 없는
77
- * 일이다. 한 낱말로 합치면 화면이 둘 중 어느 쪽인지 말할 수 없다.
78
- */
79
- const r = chooseRecipe(ALL, [STD, FAST], 'RCP-사라진것')
80
-
81
- assert.equal(r.recipe, undefined)
82
- assert.equal(r.basis, 'said-but-undeclared')
83
- })
84
-
85
- test('★ 후보가 아예 없으면 none — 「이 자재를 내는 레시피가 없다」', () => {
86
- const r = chooseRecipe(ALL, [], undefined)
87
-
88
- assert.equal(r.recipe, undefined)
89
- assert.equal(r.basis, 'none')
90
- })
91
-
92
- /* ── 무너지지 않는다 ────────────────────────────────────────────────────── */
93
-
94
- test('빈 목록·빈 값에도 터지지 않는다', () => {
95
- assert.equal(chooseRecipe([], [], undefined).basis, 'none')
96
- assert.equal(chooseRecipe([], [], 'X').basis, 'said-but-undeclared')
97
- assert.equal(chooseRecipe(ALL, [STD], '').basis, 'only-candidate', '빈 문자열은 「말했다」가 아니다')
98
- })
99
-
100
- /* ── 검사가 실제로 무언가를 재나 ─────────────────────────────────────────── */
101
-
102
- test('★ 이 검사가 실제로 무언가를 잰다 — 견준 것이 0이면 빨강', () => {
103
- /* 네 판정이 다 나오는지. 하나라도 안 나오면 위 검사들이 같은 가지만 밟고 있는 것이다. */
104
- const bases = new Set([
105
- chooseRecipe(ALL, [STD, FAST], 'RCP-BOLT-FAST').basis,
106
- chooseRecipe(ALL, [OTHER], undefined).basis,
107
- chooseRecipe(ALL, [STD, FAST], undefined).basis,
108
- chooseRecipe(ALL, [STD], 'RCP-없음').basis,
109
- chooseRecipe(ALL, [], undefined).basis
110
- ])
111
-
112
- assert.deepEqual(
113
- [...bases].sort(),
114
- ['ambiguous', 'none', 'only-candidate', 'order', 'said-but-undeclared'],
115
- `판정이 다 나오지 않는다: ${[...bases].join(' · ')}`
116
- )
117
- })
@@ -1,122 +0,0 @@
1
- /*
2
- * 컬럼 타입은 **드라이버 방언을 적지 않는다.**
3
- *
4
- * ── 무엇이 났나 (2026-08-19) ────────────────────────────────────────────────
5
- * 릴리즈 부팅이 Postgres 에서 막혔다:
6
- *
7
- * DataTypeNotSupportedError: Data type "datetime" in "TwinEvent.eventTime" is not supported by "postgres"
8
- *
9
- * `datetime` 은 **MySQL·MSSQL 의 이름**이다(Postgres·Oracle 은 거절한다). 거꾸로 `timestamp` 는 MySQL
10
- * 이 받지만 예전 주석은 「sqlite 가 지원하지 않는다」고 적어 두었다 — sqlite 드라이버는 타입 목록이
11
- * 비어 있어 **아무 이름도 검증하지 않는다**(그래서 개발 중에는 무엇을 적어도 통과했다). 결국 다섯
12
- * 드라이버에 다 통하는 날짜 이름은 **없다.**
13
- *
14
- * 그래서 이름을 고르는 일을 TypeORM 에 맡긴다: `emitDecoratorMetadata` 가 켜져 있으므로 `Date` 속성에
15
- * `@Column()` 만 달면 드라이버별로 알맞게 바뀐다(Postgres `timestamp without time zone` · sqlite·MySQL
16
- * `datetime` · Oracle `timestamp`) — sqlite 거동은 그대로다.
17
- *
18
- * 이 시험은 그 규율을 **소스에서** 지킨다: 이 패키지의 엔티티가 명시한 타입 이름은 네 드라이버(검증을
19
- * 하는 쪽) 모두가 아는 것이어야 한다. 개발 DB 가 sqlite 라 아무것도 못 잡아 주기 때문에 필요하다.
20
- */
21
- import { test } from 'node:test'
22
- import assert from 'node:assert/strict'
23
- import { readdirSync, readFileSync, statSync } from 'node:fs'
24
- import { fileURLToPath } from 'node:url'
25
- import { createRequire } from 'node:module'
26
- import { join } from 'node:path'
27
-
28
- const req = createRequire(import.meta.url)
29
-
30
- /** 드라이버가 아는 타입 이름 — **TypeORM 소스에서 읽는다**(우리가 목록을 옮겨 적지 않는다). */
31
- function supportedTypes(driverPath: string): Set<string> {
32
- const src = readFileSync(req.resolve(driverPath), 'utf-8')
33
- const m = src.match(/supportedDataTypes = \[([\s\S]*?)\];/)
34
- assert.ok(m, `${driverPath}: supportedDataTypes 를 찾지 못했다(TypeORM 구조가 바뀌었다)`)
35
- return new Set((m![1].match(/"[^"]+"/g) ?? []).map(s => s.slice(1, -1)))
36
- }
37
-
38
- /*
39
- * sqlite 는 목록이 비어 있다 = **검증하지 않는다.** 그래서 여기 넣지 않는다 — 넣으면 모든 타입이
40
- * 「sqlite 가 모른다」로 걸려 이 시험이 소음이 된다. 개발 DB 가 아무것도 못 잡는다는 사실이 이 시험의 이유다.
41
- */
42
- const DRIVERS: Record<string, string> = {
43
- postgres: 'typeorm/driver/postgres/PostgresDriver.js',
44
- mysql: 'typeorm/driver/mysql/MysqlDriver.js',
45
- oracle: 'typeorm/driver/oracle/OracleDriver.js',
46
- mssql: 'typeorm/driver/sqlserver/SqlServerDriver.js'
47
- }
48
-
49
- function entitySources(): { file: string; src: string }[] {
50
- const root = fileURLToPath(new URL('../server', import.meta.url))
51
- const out: { file: string; src: string }[] = []
52
- const walk = (dir: string) => {
53
- for (const name of readdirSync(dir)) {
54
- const path = join(dir, name)
55
- if (statSync(path).isDirectory()) { walk(path); continue }
56
- if (!name.endsWith('.ts')) continue
57
- const src = readFileSync(path, 'utf-8')
58
- if (/@Entity\(/.test(src)) out.push({ file: path.slice(root.length + 1), src })
59
- }
60
- }
61
- walk(root)
62
- return out
63
- }
64
-
65
- test('엔티티가 있다 — 훑을 대상이 없으면 이 시험은 아무것도 지키지 않는다', () => {
66
- assert.ok(entitySources().length >= 5, '이 패키지의 엔티티를 찾아야 한다')
67
- })
68
-
69
- /*
70
- * **드라이버마다 이름이 다른 컬럼은 코드가 고른다.**
71
- *
72
- * 긴 글이 그렇다: `text` 를 Oracle 이 모르고(그쪽은 `clob`), MySQL 계열은 `longtext`, MSSQL 은
73
- * `nvarchar(MAX)` 를 쓴다. 이 레포의 정본 관행은 `DATABASE_TYPE` 으로 분기하는 것이다
74
- * (`board-service` 의 `Board.model`) — 그 분기는 이 시험의 리터럴 검사에 걸리지 않는다(정상이다).
75
- *
76
- * 그래서 면제 목록을 두지 않는다: 고정 리터럴은 전부 잡고, 갈라야 하는 컬럼은 관행대로 가른다.
77
- */
78
- const KNOWN_GAPS = new Set<string>()
79
-
80
- test('명시한 컬럼 타입은 네 드라이버가 모두 아는 이름이다 — 개발 DB(sqlite)는 아무것도 잡아 주지 않는다', () => {
81
- const supported = Object.fromEntries(Object.entries(DRIVERS).map(([n, p]) => [n, supportedTypes(p)]))
82
- const violations: string[] = []
83
- for (const { file, src } of entitySources()) {
84
- for (const m of src.matchAll(/type:\s*'([a-z][a-z0-9 _]*)'/g)) {
85
- const type = m[1]
86
- const missing = Object.entries(supported).filter(([, s]) => !s.has(type)).map(([n]) => n)
87
- if (!missing.length) continue
88
- const line = `${file}: type '${type}' — ${missing.join(', ')} 가 모른다`
89
- if (!KNOWN_GAPS.has(line)) violations.push(line)
90
- }
91
- }
92
- assert.deepEqual(violations, [], `드라이버 방언을 적은 컬럼:\n${violations.join('\n')}`)
93
- })
94
-
95
- test('면제를 남겨 두면 그것이 아직 사실인지 확인한다 — 유령 면제를 남기지 않는다', () => {
96
- const supported = Object.fromEntries(Object.entries(DRIVERS).map(([n, p]) => [n, supportedTypes(p)]))
97
- const present = new Set<string>()
98
- for (const { file, src } of entitySources()) {
99
- for (const m of src.matchAll(/type:\s*'([a-z][a-z0-9 _]*)'/g)) {
100
- const missing = Object.entries(supported).filter(([, s]) => !s.has(m[1])).map(([n]) => n)
101
- if (missing.length) present.add(`${file}: type '${m[1]}' — ${missing.join(', ')} 가 모른다`)
102
- }
103
- }
104
- for (const gap of KNOWN_GAPS) assert.ok(present.has(gap), `이 예외는 이제 사실이 아니다(목록에서 지워라): ${gap}`)
105
- })
106
-
107
- test('날짜 컬럼은 이름을 적지 않는다 — TypeORM 이 드라이버별로 고르게 둔다', () => {
108
- for (const { file, src } of entitySources()) {
109
- assert.equal(/type:\s*'(datetime|timestamp|timestamptz|datetime2|smalldatetime)'/.test(src), false, `${file}: 날짜 타입 이름을 적었다`)
110
- }
111
- })
112
-
113
- /*
114
- * 드라이버별로 갈라야 하는 컬럼은 **갈린 상태로** 있어야 한다 — 다시 고정 리터럴로 돌아가면 그 드라이버가
115
- * 부팅에서 거절한다(감사 사유는 사람이 쓰는 글이라 길이를 자르지 않는다).
116
- */
117
- test('긴 글 컬럼은 DATABASE_TYPE 으로 갈린다 — 관행을 되돌리지 않는다', () => {
118
- const src = readFileSync(fileURLToPath(new URL('../server/service/twin-audit/twin-audit-event.ts', import.meta.url)), 'utf-8')
119
- assert.match(src, /const DATABASE_TYPE = config\.get\('ormconfig', \{\}\)\.type/, '관행과 같은 자리에서 읽는다')
120
- for (const name of ['longtext', 'clob', 'nvarchar', 'text']) assert.ok(src.includes(`'${name}'`), `${name} 갈래가 있어야 한다`)
121
- assert.match(src, /length: DATABASE_TYPE == 'mssql' \? 'MAX' : undefined/, 'MSSQL 은 길이까지 말해야 잘리지 않는다')
122
- })
@@ -1,61 +0,0 @@
1
- /*
2
- * ★ 커맨드 라우팅 판정 — 권위(모드) × 성격(주석/액추에이션).
3
- *
4
- * ── 무엇이 문제였나 ─────────────────────────────────────────────────────────
5
- * 리졸버가 `inst.runtime.dispatch(...)` 를 곧바로 불렀다. 그런데 `runtime` 은 **시뮬 경로에서만**
6
- * 만들어진다. 실물을 비추는 트윈(mirror)에서는 그 한 줄이 `TypeError` 로 터져 조치 채널이 통째로
7
- * 닿지 않았다 — 사용자에게는 이유 있는 거절이 아니라 그냥 실패였다.
8
- *
9
- * ── 그냥 열면 안 되는 이유 ──────────────────────────────────────────────────
10
- * 미러에서 액추에이션을 허용하면 **새 거짓말이 생긴다**: 트윈은 "보류됨" 이라 말하고 실 시스템은
11
- * 모른다. 그래서 실 프로세스를 바꾸는 커맨드는 아웃바운드 어댑터가 붙기 전까지 이유를 밝혀 거절한다
12
- * (`design/plans/command-routing.md` P0). 확인(ack)은 트윈 쪽 주석이라 미러에서도 통과한다.
13
- */
14
- import { test } from 'node:test'
15
- import assert from 'node:assert/strict'
16
-
17
- import { routeCommand, isActuation } from '../server/engine/command-routing.ts'
18
-
19
- const sim = { hasRuntime: true, hasKernelDispatch: true }
20
- const mirror = { mode: 'live', hasRuntime: false, hasKernelDispatch: true }
21
-
22
- test('시뮬 — 커맨드는 커널 런타임으로 간다(현행 경로 그대로)', () => {
23
- assert.deepEqual(routeCommand(sim, true, 'order.hold'), { target: 'runtime' })
24
- assert.deepEqual(routeCommand(sim, true, 'attention.ack'), { target: 'runtime' })
25
- })
26
-
27
- test('미러 — 확인(ack)은 관측 커널로 간다. 현실을 건드리지 않는 주석이다', () => {
28
- assert.deepEqual(routeCommand(mirror, true, 'attention.ack'), { target: 'kernel' })
29
- })
30
-
31
- test('미러 — 실 프로세스를 바꾸는 커맨드는 이유를 밝히고 거절한다', () => {
32
- for (const type of ['order.hold', 'order.resume', 'order.release', 'resource.down', 'resource.repair', 'resource.add']) {
33
- const r = routeCommand(mirror, true, type)
34
- assert.equal(r.target, 'reject', `${type} 은 미러에서 통과하면 안 된다`)
35
- if (r.target !== 'reject') return
36
- assert.equal(r.errorCode, 'actuation-not-wired')
37
- assert.equal(r.errorParams?.type, type, '어느 커맨드였는지 함께 알려야 한다')
38
- }
39
- })
40
-
41
- test('없는 인스턴스와 다른 도메인은 같은 사유로 거절한다 — 있음/없음이 구별되면 그것이 정보다', () => {
42
- assert.deepEqual(routeCommand(undefined, false, 'attention.ack'), { target: 'reject', errorCode: 'no-instance' })
43
- assert.deepEqual(routeCommand(sim, false, 'attention.ack'), { target: 'reject', errorCode: 'no-instance' })
44
- })
45
-
46
- test('런타임이 없는 시뮬 — 오류를 내지 않고 이유를 알린다', () => {
47
- assert.deepEqual(routeCommand({ hasRuntime: false, hasKernelDispatch: true }, true, 'order.hold'), { target: 'reject', errorCode: 'no-runtime' })
48
- })
49
-
50
- test('커널이 커맨드를 못 받는 미러 — 확인도 이유를 말하고 멈춘다', () => {
51
- assert.deepEqual(routeCommand({ mode: 'live', hasRuntime: false, hasKernelDispatch: false }, true, 'attention.ack'), { target: 'reject', errorCode: 'no-runtime' })
52
- })
53
-
54
- test('빈 커맨드 종류는 거절한다 — 무엇을 하라는지 모르는 것을 보내지 않는다', () => {
55
- assert.deepEqual(routeCommand(sim, true, ''), { target: 'reject', errorCode: 'unknown-command' })
56
- })
57
-
58
- test('성격 판정 — 확인만 주석이고 나머지는 액추에이션이다', () => {
59
- assert.equal(isActuation('attention.ack'), false)
60
- for (const t of ['order.hold', 'resource.add', 'order.release']) assert.equal(isActuation(t), true, t)
61
- })
@@ -1,126 +0,0 @@
1
- /*
2
- * ★ **칸이 있으면 쓰는 길도 있어야 한다** — `save` 가 손으로 든 목록이라 새 칸을 빠뜨린다.
3
- *
4
- * ── 무엇이 있었나 (2026-09-04) ──────────────────────────────────────────────
5
- * 일꾼에 네 칸을 더했다 — `dispatch_note_next` · `retry` · `attempts` · `next_attempt_at`.
6
- * 엔티티에 선언하고 마이그레이션까지 걸었는데 **`save` 가 그 칸을 안 썼다.** 그 함수는 쓸 칸을
7
- * 손으로 들고 있고, 새 칸이 그 목록에 없었다.
8
- *
9
- * 그래서 일꾼이 물러섬을 계산해 넘겼는데 표에는 아무것도 안 남았다. 재기동하면 물러서던 것이
10
- * 전부 즉시 재시도가 되고, 목록의 「몇 번 해 봤나」가 영원히 비어 있다. **오류는 나지 않는다.**
11
- *
12
- * 30분을 뒤진 끝에 찾았고, 이 저장소에서 하루 종일 「자리는 있고 길이 없다」로 부른 것과 같다 —
13
- * 이번에는 **칸과 쓰는 길** 사이였다.
14
- *
15
- * ── 무엇을 검사하나 ────────────────────────────────────────────────────────
16
- * 엔티티가 칸을 가진 필드는 `save` 가 쓰거나, 안 쓰는 이유가 아래 표에 있어야 한다. 목록을
17
- * 소스에서 읽는다 — 손으로 적으면 새 칸이 조용히 빠지고 그것이 바로 이 검사가 막으려는 실패다.
18
- */
19
- import { test } from 'node:test'
20
- import assert from 'node:assert/strict'
21
- import { readFileSync } from 'node:fs'
22
-
23
- const bare = (p: string): string =>
24
- readFileSync(new URL(p, import.meta.url), 'utf8')
25
- .replace(/\/\*[\s\S]*?\*\//g, '')
26
- .replace(/\/\/[^\n]*/g, '')
27
-
28
- const ENTITY = bare('../server/service/actuation/twin-command.ts')
29
- const STORE = bare('../server/service/actuation/command-store.ts')
30
-
31
- /**
32
- * `save` 가 일부러 안 쓰는 칸 — 이유와 함께.
33
- *
34
- * 비어 있는 것이 정상이 아니다: 이 표는 「고치는 경로가 다른 칸」을 든다. 채울 때 그 이유가
35
- * 「다른 함수가 쓴다」인지 「읽기 전용」인지 적어야 한다.
36
- */
37
- const NOT_BY_SAVE: { column: string; why: string }[] = [
38
- { column: 'domain', why: '열쇠 — 테넌트로 좁히는 조건이다' },
39
- { column: 'instanceId', why: '낼 때 정해지고 바뀌지 않는다(create)' },
40
- { column: 'type', why: '낼 때 정해지고 바뀌지 않는다(create)' },
41
- { column: 'payload', why: '낼 때 정해지고 바뀌지 않는다 — 지시 내용은 제안될 때 굳는다' },
42
- { column: 'origin', why: '낼 때 정해지고 바뀌지 않는다(create)' },
43
- { column: 'proposedBy', why: '낼 때 정해지고 바뀌지 않는다(create)' },
44
- { column: 'reversible', why: '명세에서 온다 — 낼 때 굳는다(create)' },
45
- { column: 'causeRef', why: '낼 때 정해진다 — 규칙이 낸 근거(create)' },
46
- { column: 'ruleRef', why: '낼 때 정해진다(create)' },
47
- { column: 'effectStatus', why: '유입 경로가 `recordEffects` 로만 적는다 — 관측이 조치의 수명에 손대지 않게' },
48
- { column: 'effectAt', why: '같음 — `recordEffects`' },
49
- { column: 'effectSeen', why: '같음 — `recordEffects`' },
50
- { column: 'createdAt', why: 'TypeORM 이 넣는다' },
51
- { column: 'updatedAt', why: 'TypeORM 이 넣는다' }
52
- ]
53
-
54
- /** 엔티티가 컬럼을 선언한 속성 이름들 — 데코레이터 다음 줄의 필드를 읽는다. */
55
- function entityColumns(): string[] {
56
- const out: string[] = []
57
- const lines = ENTITY.split('\n')
58
- for (let i = 0; i < lines.length; i++) {
59
- if (!/@(Column|CreateDateColumn|UpdateDateColumn|ManyToOne)\(/.test(lines[i])) continue
60
- /* 데코레이터가 여럿 붙는다(@Column + @Field) — 다음 필드 줄까지 내려간다. */
61
- for (let j = i + 1; j < Math.min(i + 6, lines.length); j++) {
62
- const m = lines[j].match(/^\s{2}([a-zA-Z][\w]*)\??:/)
63
- if (m) {
64
- out.push(m[1])
65
- break
66
- }
67
- }
68
- }
69
- return [...new Set(out)]
70
- }
71
-
72
- /** `save` 가 실제로 쓰는 속성 — 그 함수 본문에서만 읽는다. */
73
- function savedColumns(): string[] {
74
- const start = STORE.indexOf('save: async')
75
- assert.ok(start > 0, '`save` 를 못 찾았다 — 이 검사가 따라가야 한다')
76
- const body = STORE.slice(start, STORE.indexOf('create: async', start))
77
- return [...new Set([...body.matchAll(/^\s{10}([a-zA-Z][\w]*):/gm)].map(m => m[1]))]
78
- }
79
-
80
- test('★ 엔티티가 든 칸은 save 가 쓰거나 안 쓰는 이유가 적혀 있다', () => {
81
- const excused = new Set(NOT_BY_SAVE.map(e => e.column))
82
- const written = new Set(savedColumns())
83
-
84
- const orphans = entityColumns().filter(c => !written.has(c) && !excused.has(c))
85
-
86
- assert.deepEqual(
87
- orphans,
88
- [],
89
- '엔티티에 칸이 있는데 `save` 가 안 쓴다. 값이 계산되고 표에는 안 남는다 — 오류는 나지 않는다:\n ' +
90
- orphans.join('\n ') +
91
- '\n쓰게 하거나, 다른 경로로 쓴다면 NOT_BY_SAVE 에 이유를 적는다.'
92
- )
93
- })
94
-
95
- test('★ 이 검사가 실제로 무언가를 잰다 — 견준 것이 0이면 빨강', () => {
96
- /*
97
- * 정규식이 엔티티 모양을 못 따라가면 목록이 비고, 그러면 위 검사가 **초록인데 아무것도 안 재는
98
- * 상태**가 된다. 오늘 이 저장소의 다른 검사가 그렇게 났다.
99
- */
100
- const columns = entityColumns()
101
- const written = savedColumns()
102
-
103
- assert.ok(columns.length > 15, `엔티티 칸을 ${columns.length}개만 읽었다 — 정규식이 모양을 놓쳤다`)
104
- assert.ok(written.length > 5, `save 가 쓰는 칸을 ${written.length}개만 읽었다`)
105
-
106
- /* 예외 표가 낡지 않았나 — 지워진 칸이 남아 있으면 검사를 넓혀 주는 척만 한다. */
107
- const known = new Set(columns)
108
- const stale = NOT_BY_SAVE.map(e => e.column).filter(c => !known.has(c))
109
- assert.deepEqual(stale, [], `예외 표에 있는데 엔티티에 없다:\n ${stale.join('\n ')}`)
110
-
111
- /* 이유 없는 예외는 예외가 아니다. */
112
- const mute = NOT_BY_SAVE.filter(e => !e.why?.trim()).map(e => e.column)
113
- assert.deepEqual(mute, [], `이유 없이 예외로 올렸다:\n ${mute.join('\n ')}`)
114
- })
115
-
116
- test('★ 일꾼이 쓰는 네 칸이 실제로 save 를 지난다', () => {
117
- /*
118
- * 위 검사는 목록 대조라 예외 표에 올리면 통과한다. 이 넷은 **물러섬이 표에 남는 근거**여서
119
- * 예외가 될 수 없다 — 이름으로 못 박는다.
120
- */
121
- const written = new Set(savedColumns())
122
-
123
- for (const c of ['dispatchNoteNext', 'retry', 'attempts', 'nextAttemptAt']) {
124
- assert.ok(written.has(c), `save 가 ${c} 를 안 쓴다 — 물러섬이 재기동에 사라진다`)
125
- }
126
- })
@@ -1,87 +0,0 @@
1
- /*
2
- * ★ **연결 이관의 문 셋** — 몸통은 순수 함수이고, 이 검사는 **문이 그 규율을 지키는지** 본다.
3
- *
4
- * ── 무엇을 옮기나 (사용자와 맞춘 개념, 2026-09-05) ────────────────────────
5
- * 옮기는 것은 「붙는 법」이지 「붙은 결과」가 아니다. 마스터·사실·잰 값·비밀값은 안 옮긴다 —
6
- * 앞의 셋은 다시 얻을 수 있고, 비밀값은 그 환경의 것이지 셋업이 아니다.
7
- *
8
- * ── 이 검사가 지키는 것 ────────────────────────────────────────────────────
9
- * 문이 몸통의 판단을 **뒤집지 않는지**다. 몸통 시험 19개가 이미 「비밀값이 안 나간다」를 지키는데,
10
- * 문이 그것을 되살려 쓰면 그 19개가 아무것도 못 막는다.
11
- */
12
- import { test } from 'node:test'
13
- import assert from 'node:assert/strict'
14
-
15
- import { exportConnections, planImport, SECRET_KEYS } from '../server/service/reference/connection-portability.js'
16
-
17
- const row = (over: any = {}) => ({
18
- source: 'mes-miratek',
19
- system: 'operato-plant',
20
- siteName: '미라텍',
21
- adapterType: 'operato-plant',
22
- connectionConfig: { baseUrl: 'https://plant.example', siteId: 'mes-miratek', token: 'SECRET-VALUE', hookSecret: 'ALSO-SECRET' },
23
- ...over
24
- })
25
-
26
- test('★ 비밀값이 패키지에 안 나간다 — 이름만 나간다', () => {
27
- const b = exportConnections([row()], { at: '2026-09-05T00:00:00.000Z' })
28
- const text = JSON.stringify(b)
29
-
30
- assert.ok(!text.includes('SECRET-VALUE'), '토큰이 패키지에 실렸다')
31
- assert.ok(!text.includes('ALSO-SECRET'), '훅 비밀값이 패키지에 실렸다')
32
- assert.deepEqual(b.connections[0].secretsRequired.sort(), ['hookSecret', 'token'], '무엇을 채워야 하는지 말하지 않는다')
33
- })
34
-
35
- test('★ 선언은 나간다 — 그것이 옮기려는 것이다', () => {
36
- const b = exportConnections([row()], { at: '2026-09-05T00:00:00.000Z' })
37
- const c = b.connections[0]
38
-
39
- assert.equal(c.adapterType, 'operato-plant')
40
- assert.equal(c.config.baseUrl, 'https://plant.example')
41
- assert.equal(c.config.siteId, 'mes-miratek')
42
- })
43
-
44
- test('★ 새 비밀 칸도 기본으로 안 나간다 — 이름 규칙으로 거른다', () => {
45
- /*
46
- * 비밀 칸이 하나 늘 때 이 목록을 안 고치면 그 값이 파일로 나간다. 그래서 규칙이 이름이고,
47
- * 그 규칙이 지금 무엇을 아는지 값으로 못 박는다.
48
- */
49
- assert.ok(SECRET_KEYS.includes('token' as any))
50
- assert.ok(SECRET_KEYS.includes('hookSecret' as any))
51
- assert.ok(SECRET_KEYS.includes('intakeSecret' as any))
52
- assert.ok(SECRET_KEYS.length >= 4, `비밀 칸 이름을 ${SECRET_KEYS.length}개만 안다`)
53
- })
54
-
55
- test('★ 없는 비밀값을 지어내지 않는다 — 이름을 대고 사람에게 넘긴다', () => {
56
- const b = exportConnections([row()], { at: '2026-09-05T00:00:00.000Z' })
57
- /* 이 환경에는 그 비밀값이 없다. */
58
- const plan = planImport(b, [], () => false)
59
-
60
- const needs = plan.needsHuman.find(n => n.source === 'mes-miratek')
61
- assert.ok(needs, '사람이 채울 것을 말하지 않는다')
62
- assert.deepEqual(needs!.keys.sort(), ['hookSecret', 'token'])
63
- })
64
-
65
- test('★ 이미 있는 연결의 비밀값을 패키지가 안 지운다', () => {
66
- const b = exportConnections([row()], { at: '2026-09-05T00:00:00.000Z' })
67
- const existing = [{ source: 'mes-miratek', connectionConfig: { token: 'LIVE-TOKEN' } }]
68
- const plan = planImport(b, existing, () => false)
69
-
70
- const a = plan.actions.find(x => (x as any).connection?.source === 'mes-miratek') as any
71
- assert.equal(a?.action, 'update', `갱신이 아니라 ${a?.action} 이다`)
72
- assert.ok(a.keptSecrets?.includes('token'), '이미 있는 토큰을 지킨다고 말하지 않는다')
73
- })
74
-
75
- test('★ 패키지가 아닌 것을 받으면 아무것도 하지 않는다', () => {
76
- for (const bad of [null, {}, { kind: 'something-else' }, 'text']) {
77
- const plan = planImport(bad, [], () => false)
78
- assert.equal(plan.actions.length, 0, `${JSON.stringify(bad)} 로 무언가를 하려 했다`)
79
- assert.ok(plan.errors.length, '왜 안 되는지 말하지 않는다')
80
- }
81
- })
82
-
83
- test('★ 이 검사가 실제로 무언가를 잰다 — 견준 것이 0이면 빨강', () => {
84
- const b = exportConnections([row()], { at: '2026-09-05T00:00:00.000Z' })
85
- assert.equal(b.connections.length, 1, '패키지가 비었다 — 이 검사가 아무것도 안 잰다')
86
- assert.ok(planImport(b, [], () => true).actions.length > 0, '계획이 비었다')
87
- })