@things-factory/headless-twin 10.0.9 → 10.0.11

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 (354) hide show
  1. package/dist-server/engine/canonical-ingest.d.ts +2 -2
  2. package/dist-server/engine/canonical-ingest.js +24 -2
  3. package/dist-server/engine/canonical-ingest.js.map +1 -1
  4. package/dist-server/engine/command-routing.js +1 -1
  5. package/dist-server/engine/command-routing.js.map +1 -1
  6. package/dist-server/engine/energy-topology.d.ts +86 -0
  7. package/dist-server/engine/energy-topology.js +144 -0
  8. package/dist-server/engine/energy-topology.js.map +1 -0
  9. package/dist-server/engine/index.d.ts +8 -3
  10. package/dist-server/engine/index.js +10 -3
  11. package/dist-server/engine/index.js.map +1 -1
  12. package/dist-server/engine/kpi-baseline.d.ts +1 -1
  13. package/dist-server/engine/kpi-baseline.js.map +1 -1
  14. package/dist-server/engine/kpi-fold.d.ts +137 -1
  15. package/dist-server/engine/kpi-fold.js +225 -0
  16. package/dist-server/engine/kpi-fold.js.map +1 -1
  17. package/dist-server/engine/kpi-query.d.ts +1 -1
  18. package/dist-server/engine/kpi-query.js +212 -18
  19. package/dist-server/engine/kpi-query.js.map +1 -1
  20. package/dist-server/engine/kpi-target.d.ts +17 -0
  21. package/dist-server/engine/kpi-target.js +24 -2
  22. package/dist-server/engine/kpi-target.js.map +1 -1
  23. package/dist-server/engine/live-feed-registry.d.ts +25 -0
  24. package/dist-server/engine/live-feed-registry.js +51 -0
  25. package/dist-server/engine/live-feed-registry.js.map +1 -0
  26. package/dist-server/engine/load-meter.d.ts +181 -0
  27. package/dist-server/engine/load-meter.js +267 -0
  28. package/dist-server/engine/load-meter.js.map +1 -0
  29. package/dist-server/engine/local-declarations.d.ts +262 -0
  30. package/dist-server/engine/local-declarations.js +528 -0
  31. package/dist-server/engine/local-declarations.js.map +1 -0
  32. package/dist-server/engine/model-basis.d.ts +39 -6
  33. package/dist-server/engine/model-basis.js +69 -9
  34. package/dist-server/engine/model-basis.js.map +1 -1
  35. package/dist-server/engine/{board-vocabulary.d.ts → model-vocabulary.d.ts} +4 -4
  36. package/dist-server/engine/{board-vocabulary.js → model-vocabulary.js} +37 -19
  37. package/dist-server/engine/model-vocabulary.js.map +1 -0
  38. package/dist-server/engine/oee-accumulator.d.ts +28 -0
  39. package/dist-server/engine/oee-accumulator.js +26 -1
  40. package/dist-server/engine/oee-accumulator.js.map +1 -1
  41. package/dist-server/engine/operation-basis.d.ts +32 -0
  42. package/dist-server/engine/operation-basis.js +87 -0
  43. package/dist-server/engine/operation-basis.js.map +1 -0
  44. package/dist-server/engine/property-effects.d.ts +30 -0
  45. package/dist-server/engine/property-effects.js +192 -0
  46. package/dist-server/engine/property-effects.js.map +1 -0
  47. package/dist-server/engine/runtime-key.d.ts +1 -1
  48. package/dist-server/engine/runtime-key.js +1 -1
  49. package/dist-server/engine/runtime-key.js.map +1 -1
  50. package/dist-server/engine/spec-coverage.js +3 -3
  51. package/dist-server/engine/spec-coverage.js.map +1 -1
  52. package/dist-server/engine/state-axes.d.ts +7 -2
  53. package/dist-server/engine/state-axes.js +8 -3
  54. package/dist-server/engine/state-axes.js.map +1 -1
  55. package/dist-server/engine/structure-diff.js +1 -1
  56. package/dist-server/engine/structure-diff.js.map +1 -1
  57. package/dist-server/engine/travel-estimator.d.ts +9 -2
  58. package/dist-server/engine/travel-estimator.js +11 -6
  59. package/dist-server/engine/travel-estimator.js.map +1 -1
  60. package/dist-server/engine/twin-engine.d.ts +332 -47
  61. package/dist-server/engine/twin-engine.js +1314 -279
  62. package/dist-server/engine/twin-engine.js.map +1 -1
  63. package/dist-server/engine/warm-start.d.ts +38 -4
  64. package/dist-server/engine/warm-start.js +38 -9
  65. package/dist-server/engine/warm-start.js.map +1 -1
  66. package/dist-server/index.d.ts +1 -0
  67. package/dist-server/index.js +17 -11
  68. package/dist-server/index.js.map +1 -1
  69. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.d.ts +5 -0
  70. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js +48 -0
  71. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js.map +1 -0
  72. package/dist-server/migrations/index.d.ts +2 -0
  73. package/dist-server/migrations/index.js +10 -0
  74. package/dist-server/migrations/index.js.map +1 -0
  75. package/dist-server/service/index.d.ts +3 -2
  76. package/dist-server/service/index.js +25 -17
  77. package/dist-server/service/index.js.map +1 -1
  78. package/dist-server/service/reference/discovery-result.d.ts +1 -1
  79. package/dist-server/service/reference/discovery-result.js +2 -2
  80. package/dist-server/service/reference/discovery-result.js.map +1 -1
  81. package/dist-server/service/reference/ingest-space.d.ts +24 -1
  82. package/dist-server/service/reference/ingest-space.js +17 -1
  83. package/dist-server/service/reference/ingest-space.js.map +1 -1
  84. package/dist-server/service/reference/reference-live.d.ts +23 -0
  85. package/dist-server/service/reference/reference-live.js +121 -4
  86. package/dist-server/service/reference/reference-live.js.map +1 -1
  87. package/dist-server/service/reference/reference-master.d.ts +194 -13
  88. package/dist-server/service/reference/reference-master.js +159 -28
  89. package/dist-server/service/reference/reference-master.js.map +1 -1
  90. package/dist-server/service/reference/reference-resolver.d.ts +31 -1
  91. package/dist-server/service/reference/reference-resolver.js +223 -12
  92. package/dist-server/service/reference/reference-resolver.js.map +1 -1
  93. package/dist-server/service/reference/template-registry.d.ts +19 -3
  94. package/dist-server/service/reference/template-registry.js.map +1 -1
  95. package/dist-server/service/twin-audit/command-audit.d.ts +37 -0
  96. package/dist-server/service/twin-audit/command-audit.js +53 -0
  97. package/dist-server/service/twin-audit/command-audit.js.map +1 -0
  98. package/dist-server/service/twin-audit/index.d.ts +4 -0
  99. package/dist-server/service/twin-audit/index.js +8 -0
  100. package/dist-server/service/twin-audit/index.js.map +1 -0
  101. package/dist-server/service/twin-audit/twin-audit-event.d.ts +24 -0
  102. package/dist-server/service/twin-audit/twin-audit-event.js +141 -0
  103. package/dist-server/service/twin-audit/twin-audit-event.js.map +1 -0
  104. package/dist-server/service/twin-audit/twin-audit-query.d.ts +4 -0
  105. package/dist-server/service/twin-audit/twin-audit-query.js +76 -0
  106. package/dist-server/service/twin-audit/twin-audit-query.js.map +1 -0
  107. package/dist-server/service/twin-control/twin-control-mutation.js +21 -1
  108. package/dist-server/service/twin-control/twin-control-mutation.js.map +1 -1
  109. package/dist-server/service/twin-event/twin-event-keys.d.ts +1 -1
  110. package/dist-server/service/twin-event/twin-event-keys.js +1 -1
  111. package/dist-server/service/twin-event/twin-event-keys.js.map +1 -1
  112. package/dist-server/service/twin-event/twin-event.d.ts +14 -5
  113. package/dist-server/service/twin-event/twin-event.js +45 -13
  114. package/dist-server/service/twin-event/twin-event.js.map +1 -1
  115. package/dist-server/service/twin-forecast/forecast-metrics.d.ts +13 -0
  116. package/dist-server/service/twin-forecast/forecast-metrics.js +57 -0
  117. package/dist-server/service/twin-forecast/forecast-metrics.js.map +1 -0
  118. package/dist-server/service/twin-forecast/forecast-tuning.d.ts +12 -0
  119. package/dist-server/service/twin-forecast/forecast-tuning.js +44 -0
  120. package/dist-server/service/twin-forecast/forecast-tuning.js.map +1 -0
  121. package/dist-server/service/twin-forecast/gap-analytics.d.ts +28 -2
  122. package/dist-server/service/twin-forecast/gap-analytics.js +43 -17
  123. package/dist-server/service/twin-forecast/gap-analytics.js.map +1 -1
  124. package/dist-server/service/twin-forecast/twin-forecast-query.js +217 -38
  125. package/dist-server/service/twin-forecast/twin-forecast-query.js.map +1 -1
  126. package/dist-server/service/twin-instance/twin-instance.d.ts +38 -5
  127. package/dist-server/service/twin-instance/twin-instance.js +66 -20
  128. package/dist-server/service/twin-instance/twin-instance.js.map +1 -1
  129. package/dist-server/service/twin-journal/twin-journal-query.d.ts +5 -2
  130. package/dist-server/service/twin-journal/twin-journal-query.js +71 -9
  131. package/dist-server/service/twin-journal/twin-journal-query.js.map +1 -1
  132. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.d.ts +3 -5
  133. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js +24 -27
  134. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +1 -1
  135. package/dist-server/service/twin-metrics/twin-metrics-query.d.ts +1 -0
  136. package/dist-server/service/twin-metrics/twin-metrics-query.js +62 -0
  137. package/dist-server/service/twin-metrics/twin-metrics-query.js.map +1 -1
  138. package/dist-server/service/twin-model/epcis-coverage.d.ts +14 -0
  139. package/dist-server/service/twin-model/epcis-coverage.js +174 -0
  140. package/dist-server/service/twin-model/epcis-coverage.js.map +1 -0
  141. package/dist-server/service/twin-model/iec61850-coverage.d.ts +14 -0
  142. package/dist-server/service/twin-model/iec61850-coverage.js +98 -0
  143. package/dist-server/service/twin-model/iec61850-coverage.js.map +1 -0
  144. package/dist-server/service/twin-model/index.d.ts +13 -0
  145. package/dist-server/service/twin-model/index.js +29 -0
  146. package/dist-server/service/twin-model/index.js.map +1 -0
  147. package/dist-server/service/twin-model/isa95-coverage.d.ts +48 -0
  148. package/dist-server/service/twin-model/isa95-coverage.js +155 -0
  149. package/dist-server/service/twin-model/isa95-coverage.js.map +1 -0
  150. package/dist-server/service/twin-model/project-structure.d.ts +16 -0
  151. package/dist-server/service/twin-model/project-structure.js +173 -0
  152. package/dist-server/service/twin-model/project-structure.js.map +1 -0
  153. package/dist-server/service/twin-model/standard-coverage.d.ts +9 -0
  154. package/dist-server/service/twin-model/standard-coverage.js +37 -0
  155. package/dist-server/service/twin-model/standard-coverage.js.map +1 -0
  156. package/dist-server/service/twin-model/twin-equipment.d.ts +64 -0
  157. package/dist-server/service/twin-model/twin-equipment.js +134 -0
  158. package/dist-server/service/twin-model/twin-equipment.js.map +1 -0
  159. package/dist-server/service/twin-model/twin-lineage-query.d.ts +3 -0
  160. package/dist-server/service/twin-model/twin-lineage-query.js +206 -0
  161. package/dist-server/service/twin-model/twin-lineage-query.js.map +1 -0
  162. package/dist-server/service/twin-model/twin-location.d.ts +58 -0
  163. package/dist-server/service/twin-model/twin-location.js +130 -0
  164. package/dist-server/service/twin-model/twin-location.js.map +1 -0
  165. package/dist-server/service/twin-model/twin-model-item-query.d.ts +141 -0
  166. package/dist-server/service/twin-model/twin-model-item-query.js +852 -0
  167. package/dist-server/service/twin-model/twin-model-item-query.js.map +1 -0
  168. package/dist-server/service/twin-model/twin-model-mutation.d.ts +57 -0
  169. package/dist-server/service/twin-model/twin-model-mutation.js +490 -0
  170. package/dist-server/service/twin-model/twin-model-mutation.js.map +1 -0
  171. package/dist-server/service/twin-model/twin-model-query.d.ts +43 -0
  172. package/dist-server/service/twin-model/twin-model-query.js +551 -0
  173. package/dist-server/service/twin-model/twin-model-query.js.map +1 -0
  174. package/dist-server/service/twin-model/twin-model-tree-query.d.ts +3 -0
  175. package/dist-server/service/twin-model/twin-model-tree-query.js +158 -0
  176. package/dist-server/service/twin-model/twin-model-tree-query.js.map +1 -0
  177. package/dist-server/service/twin-model/twin-operation.d.ts +61 -0
  178. package/dist-server/service/twin-model/twin-operation.js +137 -0
  179. package/dist-server/service/twin-model/twin-operation.js.map +1 -0
  180. package/dist-server/service/twin-space/move-space.d.ts +65 -0
  181. package/dist-server/service/twin-space/move-space.js +166 -0
  182. package/dist-server/service/twin-space/move-space.js.map +1 -0
  183. package/dist-server/service/twin-space/space-integrity.d.ts +97 -0
  184. package/dist-server/service/twin-space/space-integrity.js +182 -0
  185. package/dist-server/service/twin-space/space-integrity.js.map +1 -0
  186. package/dist-server/service/twin-space/twin-space-area.js +4 -4
  187. package/dist-server/service/twin-space/twin-space-area.js.map +1 -1
  188. package/dist-server/service/twin-space/twin-space-representation.js +6 -6
  189. package/dist-server/service/twin-space/twin-space-representation.js.map +1 -1
  190. package/dist-server/service/twin-space/twin-space-resolver.d.ts +63 -1
  191. package/dist-server/service/twin-space/twin-space-resolver.js +356 -18
  192. package/dist-server/service/twin-space/twin-space-resolver.js.map +1 -1
  193. package/dist-server/service/twin-space/twin-space.d.ts +17 -1
  194. package/dist-server/service/twin-space/twin-space.js +15 -5
  195. package/dist-server/service/twin-space/twin-space.js.map +1 -1
  196. package/dist-server/service/twin-structure/twin-structure.d.ts +1 -1
  197. package/dist-server/service/twin-structure/twin-structure.js +8 -8
  198. package/dist-server/service/twin-structure/twin-structure.js.map +1 -1
  199. package/dist-shared/axis-read.d.ts +12 -0
  200. package/dist-shared/axis-read.js +32 -0
  201. package/dist-shared/axis-read.js.map +1 -0
  202. package/{dist-server/engine → dist-shared}/entity-delta.d.ts +3 -0
  203. package/{dist-server/engine → dist-shared}/entity-delta.js +102 -2
  204. package/dist-shared/entity-delta.js.map +1 -0
  205. package/dist-shared/kpi-broadcast.js.map +1 -0
  206. package/dist-shared/twin-level.js.map +1 -0
  207. package/package.json +14 -12
  208. package/server/engine/canonical-ingest.ts +36 -4
  209. package/server/engine/command-routing.ts +1 -1
  210. package/server/engine/energy-topology.ts +189 -0
  211. package/server/engine/index.ts +10 -3
  212. package/server/engine/kpi-baseline.ts +1 -1
  213. package/server/engine/kpi-fold.ts +389 -1
  214. package/server/engine/kpi-query.ts +214 -19
  215. package/server/engine/kpi-target.ts +24 -2
  216. package/server/engine/live-feed-registry.ts +58 -0
  217. package/server/engine/load-meter.ts +384 -0
  218. package/server/engine/local-declarations.ts +700 -0
  219. package/server/engine/model-basis.ts +78 -10
  220. package/server/engine/{board-vocabulary.ts → model-vocabulary.ts} +36 -15
  221. package/server/engine/oee-accumulator.ts +34 -1
  222. package/server/engine/operation-basis.ts +100 -0
  223. package/server/engine/property-effects.ts +199 -0
  224. package/server/engine/runtime-key.ts +1 -1
  225. package/server/engine/spec-coverage.ts +3 -3
  226. package/server/engine/state-axes.ts +8 -3
  227. package/server/engine/structure-diff.ts +1 -1
  228. package/server/engine/travel-estimator.ts +11 -6
  229. package/server/engine/twin-engine.ts +1414 -274
  230. package/server/engine/warm-start.ts +83 -12
  231. package/server/index.ts +13 -10
  232. package/server/migrations/1786000000000-RenameTwinInstanceBoardToModel.ts +43 -0
  233. package/server/migrations/index.ts +7 -0
  234. package/server/service/index.ts +9 -1
  235. package/server/service/reference/discovery-result.ts +2 -2
  236. package/server/service/reference/ingest-space.ts +35 -1
  237. package/server/service/reference/reference-live.ts +119 -4
  238. package/server/service/reference/reference-master.ts +276 -35
  239. package/server/service/reference/reference-resolver.ts +232 -12
  240. package/server/service/reference/template-registry.ts +20 -5
  241. package/server/service/twin-audit/command-audit.ts +81 -0
  242. package/server/service/twin-audit/index.ts +5 -0
  243. package/server/service/twin-audit/twin-audit-event.ts +138 -0
  244. package/server/service/twin-audit/twin-audit-query.ts +72 -0
  245. package/server/service/twin-control/twin-control-mutation.ts +22 -1
  246. package/server/service/twin-event/twin-event-keys.ts +1 -1
  247. package/server/service/twin-event/twin-event.ts +59 -14
  248. package/server/service/twin-forecast/forecast-metrics.ts +60 -0
  249. package/server/service/twin-forecast/forecast-tuning.ts +40 -0
  250. package/server/service/twin-forecast/gap-analytics.ts +48 -9
  251. package/server/service/twin-forecast/twin-forecast-query.ts +208 -36
  252. package/server/service/twin-instance/twin-instance.ts +126 -25
  253. package/server/service/twin-journal/twin-journal-query.ts +74 -10
  254. package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +23 -22
  255. package/server/service/twin-metrics/twin-metrics-query.ts +59 -2
  256. package/server/service/twin-model/epcis-coverage.ts +195 -0
  257. package/server/service/twin-model/iec61850-coverage.ts +117 -0
  258. package/server/service/twin-model/index.ts +25 -0
  259. package/server/service/twin-model/isa95-coverage.ts +190 -0
  260. package/server/service/twin-model/project-structure.ts +199 -0
  261. package/server/service/twin-model/standard-coverage.ts +35 -0
  262. package/server/service/twin-model/twin-equipment.ts +157 -0
  263. package/server/service/twin-model/twin-lineage-query.ts +193 -0
  264. package/server/service/twin-model/twin-location.ts +147 -0
  265. package/server/service/twin-model/twin-model-item-query.ts +848 -0
  266. package/server/service/twin-model/twin-model-mutation.ts +503 -0
  267. package/server/service/twin-model/twin-model-query.ts +537 -0
  268. package/server/service/twin-model/twin-model-tree-query.ts +180 -0
  269. package/server/service/twin-model/twin-operation.ts +157 -0
  270. package/server/service/twin-space/move-space.ts +262 -0
  271. package/server/service/twin-space/space-integrity.ts +293 -0
  272. package/server/service/twin-space/twin-space-area.ts +4 -4
  273. package/server/service/twin-space/twin-space-representation.ts +6 -6
  274. package/server/service/twin-space/twin-space-resolver.ts +355 -21
  275. package/server/service/twin-space/twin-space.ts +40 -6
  276. package/server/service/twin-structure/twin-structure.ts +10 -10
  277. package/shared/axis-read.ts +28 -0
  278. package/{server/engine → shared}/entity-delta.ts +96 -1
  279. package/test/adopt-structure-live.test.ts +133 -0
  280. package/test/attention-digest.test.ts +3 -3
  281. package/test/axis-read.test.ts +87 -0
  282. package/test/boot-resume.test.ts +205 -0
  283. package/test/canonical-ingest-vocabularies.test.ts +118 -0
  284. package/test/capability-mapping.test.ts +1 -1
  285. package/test/column-type-portability.test.ts +122 -0
  286. package/test/command-routing.test.ts +1 -1
  287. package/test/declaration-reaches-model.test.ts +178 -0
  288. package/test/discovery-result.test.ts +1 -1
  289. package/test/energy-topology.test.ts +113 -0
  290. package/test/entity-delta.test.ts +171 -1
  291. package/test/event-time-column.test.ts +67 -0
  292. package/test/forecast-metrics.test.ts +71 -0
  293. package/test/forecast-tuning.test.ts +42 -0
  294. package/test/gap-analytics.test.ts +34 -7
  295. package/test/ingest-bench.test.ts +6 -6
  296. package/test/ingest-running-guard.test.ts +136 -0
  297. package/test/ingest-space.test.ts +29 -1
  298. package/test/instance-cache-lifecycle.test.ts +110 -0
  299. package/test/kernel-kind-guard.test.ts +96 -0
  300. package/test/kpi-baseline-db.test.ts +3 -1
  301. package/test/kpi-baseline.test.ts +3 -3
  302. package/test/kpi-fold.test.ts +393 -2
  303. package/test/kpi-query-bench.test.ts +5 -3
  304. package/test/lineage-survives-restart.test.ts +203 -0
  305. package/test/live-feed-registry.test.ts +67 -0
  306. package/test/live-kernel-facts.test.ts +161 -0
  307. package/test/live-mirror-parity.test.ts +22 -15
  308. package/test/load-meter.test.ts +314 -0
  309. package/test/local-declarations.test.ts +554 -0
  310. package/test/master-to-twin.test.ts +121 -33
  311. package/test/model-basis.test.ts +56 -1
  312. package/test/{board-vocabulary.test.ts → model-vocabulary.test.ts} +25 -25
  313. package/test/move-space.test.ts +149 -0
  314. package/test/mutation-gate.test.ts +19 -5
  315. package/test/oee-accumulator.test.ts +26 -7
  316. package/test/operation-basis.test.ts +100 -0
  317. package/test/operations-capability-db.test.ts +165 -0
  318. package/test/project-structure-db.test.ts +226 -0
  319. package/test/projection-reaches-screen.test.ts +272 -0
  320. package/test/property-effects.test.ts +96 -0
  321. package/test/resync-origin-site.test.ts +77 -0
  322. package/test/scale-twin-bench.test.ts +5 -5
  323. package/test/snapshot-freshness.test.ts +60 -0
  324. package/test/space-integrity.test.ts +223 -0
  325. package/test/standard-coverage.test.ts +94 -0
  326. package/test/state-axes.test.ts +1 -1
  327. package/test/streamline-e2e.test.ts +14 -14
  328. package/test/structure-revision-db.test.ts +11 -11
  329. package/test/tenant-registry-db.test.ts +5 -5
  330. package/test/twin-audit.test.ts +83 -0
  331. package/test/twin-model-item-db.test.ts +275 -0
  332. package/test/twin-model-tree-db.test.ts +176 -0
  333. package/test/twin-origin-resync.test.ts +114 -0
  334. package/test/warm-start-seam.test.ts +6 -6
  335. package/test/warm-start.test.ts +88 -3
  336. package/tsconfig.json +6 -1
  337. package/tsconfig.shared.json +23 -0
  338. package/tsconfig.shared.tsbuildinfo +1 -0
  339. package/tsconfig.tsbuildinfo +1 -0
  340. package/dist-server/engine/board-vocabulary.js.map +0 -1
  341. package/dist-server/engine/entity-delta.js.map +0 -1
  342. package/dist-server/engine/kpi-broadcast.js.map +0 -1
  343. package/dist-server/engine/twin-level.js.map +0 -1
  344. package/dist-server/service/twin-event/backfill-keys.d.ts +0 -11
  345. package/dist-server/service/twin-event/backfill-keys.js +0 -63
  346. package/dist-server/service/twin-event/backfill-keys.js.map +0 -1
  347. package/dist-server/tsconfig.tsbuildinfo +0 -1
  348. package/server/service/twin-event/backfill-keys.ts +0 -72
  349. /package/{dist-server/engine → dist-shared}/kpi-broadcast.d.ts +0 -0
  350. /package/{dist-server/engine → dist-shared}/kpi-broadcast.js +0 -0
  351. /package/{dist-server/engine → dist-shared}/twin-level.d.ts +0 -0
  352. /package/{dist-server/engine → dist-shared}/twin-level.js +0 -0
  353. /package/{server/engine → shared}/kpi-broadcast.ts +0 -0
  354. /package/{server/engine → shared}/twin-level.ts +0 -0
@@ -0,0 +1,490 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TwinModelMutation = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const type_graphql_1 = require("type-graphql");
6
+ const shell_1 = require("@things-factory/shell");
7
+ const twin_instance_js_1 = require("../twin-instance/twin-instance.js");
8
+ const twin_space_js_1 = require("../twin-space/twin-space.js");
9
+ const twin_engine_js_1 = require("../../engine/twin-engine.js");
10
+ const local_declarations_js_1 = require("../../engine/local-declarations.js");
11
+ const operation_basis_js_1 = require("../../engine/operation-basis.js");
12
+ const project_structure_js_1 = require("./project-structure.js");
13
+ /*
14
+ * 구조 테이블 **재생성** — 저장된 모델 문서로 캐시를 다시 그린다.
15
+ *
16
+ * ── 이것은 원본에서 다시 읽는 것과 다르다 ──────────────────────────────────────
17
+ * `resyncTwin` 은 **원본**에 가서 현장이 지금 어떻게 생겼는지 다시 읽는다(모델이 바뀔 수 있다).
18
+ * 여기는 **아무것도 다시 읽지 않는다** — 이미 갖고 있는 모델 문서를 테이블로 다시 푼다.
19
+ * 그래서 모델은 한 글자도 바뀌지 않고, 테이블만 문서와 같아진다.
20
+ *
21
+ * ── 왜 필요한가 ────────────────────────────────────────────────────────────────
22
+ * 이 앱에는 **투영이 생기기 전에 만들어진 트윈**이 있다. 문서에는 자리 6개·설비 32대가 있는데
23
+ * 테이블은 0행이고, 그중 일부는 원천도 기억하지 않아 다시 읽을 수조차 없다 — 조회 화면이
24
+ * 영구히 "테이블이 뒤에 있습니다" 만 말하는 막다른 상태다.
25
+ *
26
+ * ── 쓰기 경로가 둘이 되는 것 아닌가 ────────────────────────────────────────────
27
+ * 아니다. 그 규율(ADR-0032-D)이 막는 것은 **다른 진실이 행을 쓰는 것**이다(예: 틱 루프가 관측을
28
+ * 밀어 넣기). 여기서 쓰는 것은 인제스트가 쓰는 것과 **같은 문서·같은 투영**이고, 그 규율이 함께
29
+ * 요구한 "재생성 가능성을 구조로" 가 바로 이것이다. 캐시는 언제든 다시 그릴 수 있어야 한다.
30
+ */
31
+ /**
32
+ * 현장 겹을 **그 현장의 트윈 전부**에 얹는다 — 그러지 않으면 「현장 전체가 읽는다」가 거짓이 된다.
33
+ *
34
+ * ── 왜 필요한가 (2026-08-18) ────────────────────────────────────────────────
35
+ * 처음에는 호출한 트윈에만 얹었다. 그러면 같은 현장의 다른 EMS 트윈은 **다음에 자기가 다시 그려질 때
36
+ * 까지** 옛 값으로 돌아간다 — 화면은 「현장 전체」라고 말하는데 실제로는 한 트윈만 바뀐 상태다.
37
+ *
38
+ * 트윈마다 자기 겹을 그대로 얹는다(좁은 것이 이긴다). 돌고 있는 미러는 지금 받고, 시뮬레이션·정지
39
+ * 트윈은 문서에 반영한다(재기동 때 받는다) — 그 차이를 결과에 적어 돌려준다.
40
+ *
41
+ * 얹을 자리가 없는 트윈은 **정상**이다(창고 트윈에 요금 자리가 없다). 그 사실도 세어 돌려준다 —
42
+ * 「현장에 넣었는데 아무 트윈도 안 받았다」는 사용자가 알아야 할 사실이다.
43
+ */
44
+ async function spreadSpaceLayer(domainId, spaceId, spaceLayer, comment) {
45
+ const repo = (0, shell_1.getRepository)(twin_instance_js_1.TwinInstance);
46
+ const twins = await repo.find({ where: { domain: { id: domainId }, spaceId } });
47
+ const report = [];
48
+ let latest = spaceLayer;
49
+ for (const t of twins) {
50
+ if (!t.model)
51
+ continue;
52
+ const out = (0, local_declarations_js_1.applyDeclarationLayers)(t.model, latest, (t.localDeclarations ?? []));
53
+ /* 기억(`replaced`)은 **얹힌 트윈에서만** 채워진다 — 자리가 없는 트윈을 지나며 지워지지 않게 이어 든다. */
54
+ latest = out.spaceLayerApplied;
55
+ const landed = !out.missingTargets.some(m => m.scope === 'space' && spaceLayer.some(d => d.id === m.id && d.target === m.target));
56
+ t.localDeclarations = out.instanceLayerApplied;
57
+ const running = twin_engine_js_1.TwinEngine.modeOf(domainId, t.instanceId);
58
+ /*
59
+ * **트윈 하나가 실패해도 나머지는 받는다** — 다만 조용히 넘기지 않는다(2026-08-18 실측).
60
+ *
61
+ * 현장 선언을 처음 퍼뜨렸을 때 그 현장의 어떤 트윈에서 구조 투영이 터졌고(그 트윈 모델에 설비 id가
62
+ * 겹쳐 있었다 — 선재 결함), 그 예외가 올라와 **한 트윈 때문에 현장 전체 선언이 실패**했다. 사용자는
63
+ * 값을 넣었는데 아무 일도 일어나지 않은 것으로 본다.
64
+ *
65
+ * 그렇다고 삼키면 더 나쁘다: 「현장 전체가 읽는다」고 말한 뒤 몇 트윈이 못 읽는 상태가 된다. 그래서
66
+ * 트윈별로 이유를 적어 돌려준다.
67
+ */
68
+ try {
69
+ if (running === 'live') {
70
+ await repo.save(t);
71
+ await twin_engine_js_1.TwinEngine.adoptStructure(domainId, t.instanceId, out.model, comment);
72
+ report.push({ instanceId: t.instanceId, applied: 'running', landed });
73
+ continue;
74
+ }
75
+ t.model = out.model;
76
+ await repo.save(t);
77
+ await (0, project_structure_js_1.projectStructure)(domainId, t.instanceId, out.model, t.instanceId);
78
+ report.push({ instanceId: t.instanceId, applied: running ? 'on-restart' : 'stored', landed });
79
+ }
80
+ catch (e) {
81
+ report.push({ instanceId: t.instanceId, applied: 'failed', landed, error: e?.message ?? 'failed' });
82
+ }
83
+ }
84
+ return { spaceLayerApplied: latest, twins: report };
85
+ }
86
+ let TwinModelMutation = class TwinModelMutation {
87
+ async reprojectTwinModel(instanceId, context) {
88
+ const domainId = context.state.domain.id;
89
+ const inst = await (0, shell_1.getRepository)(twin_instance_js_1.TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } });
90
+ if (!inst)
91
+ return { ok: false, error: `unknown twin: ${instanceId}` };
92
+ if (!inst.model)
93
+ return { ok: false, error: `twin "${instanceId}" has no model document — there is nothing to draw from` };
94
+ try {
95
+ /*
96
+ * 출처 표식은 **이 트윈 자신**이다. 인제스트도 같은 값을 넣는다(`master.source` = instanceId) —
97
+ * 여기서 다른 값을 넣으면 같은 행이 어디서 왔는지가 경로마다 달라진다.
98
+ */
99
+ const report = await (0, project_structure_js_1.projectStructure)(domainId, instanceId, inst.model, instanceId);
100
+ return { ok: true, ...report };
101
+ }
102
+ catch (e) {
103
+ return { ok: false, error: e?.message || 'reprojection failed' };
104
+ }
105
+ }
106
+ /**
107
+ * 현장이 정하는 수를 트윈에 얹는다 — **구조는 원천이, 수는 현장이.**
108
+ *
109
+ * ── 왜 이 문이 필요했나 (2026-08-18) ──────────────────────────────────────
110
+ * 커넥터로 만든 트윈은 계통도·계량 지점을 원 시스템에서 읽어 온다. 그런데 요금 단가·계약 정보·
111
+ * 축전지 충전율은 원 시스템이 모른다(SCADA 게이트웨이는 우리 전기 계약을 알지 못한다). 그래서
112
+ * 계량이 흐르는 트윈에서도 **금액이 영원히 나오지 않았다** — 넣을 문이 없었기 때문이다.
113
+ *
114
+ * 값은 `model` 에 직접 쓰지 않고 **겹**으로 보관한다: 모델은 원천의 사본이므로 다시 읽기가 그것을
115
+ * 새로 그리면 직접 쓴 값은 조용히 사라진다. 겹은 모델을 그릴 때마다 다시 얹힌다.
116
+ *
117
+ * ── 돌고 있는 트윈에 어떻게 반영하나 ────────────────────────────────────────
118
+ * 미러는 **동작 중에** 새 구조를 받는다(현실은 멈추지 않는다). 시뮬레이션은 받지 않는다 — 조건이
119
+ * 바뀐 실험은 다른 실험이고, 커널이 그렇게 거절한다. 그때는 저장만 하고 **그 사실을 말한다**:
120
+ * 조용히 성공으로 답하면 사용자는 지금 화면의 수가 새 선언으로 계산된 줄로 읽는다.
121
+ */
122
+ async declareTwinProperties(instanceId, declarations, context) {
123
+ const domainId = context.state.domain.id;
124
+ const repo = (0, shell_1.getRepository)(twin_instance_js_1.TwinInstance);
125
+ const inst = await repo.findOne({ where: { domain: { id: domainId }, instanceId } });
126
+ if (!inst)
127
+ return { ok: false, error: `unknown twin: ${instanceId}` };
128
+ if (!inst.model)
129
+ return { ok: false, error: `twin "${instanceId}" has no model document — provision it before declaring values on it` };
130
+ /*
131
+ * **선언이 하나도 도착하지 않은 것**과 **받았지만 다 거절된 것**은 다른 일이다.
132
+ *
133
+ * 둘을 같은 문장으로 답했더니, 입력이 통째로 사라진 호출이 「받아준 선언이 없다 · 거절 목록 비어 있음」
134
+ * 이라는 답을 받았다 — 사용자는 자기 값이 서버까지 오지 못한 것을 알 수 없다(실제로 겪었다: GraphQL
135
+ * `Object` 스칼라에 인라인 리터럴로 주면 빈 배열이 되고, 변수로 주면 온다).
136
+ */
137
+ if (!declarations?.length)
138
+ return { ok: false, error: 'no declaration arrived — the declarations argument was empty' };
139
+ /*
140
+ * 검사부터 — 받지 않은 것을 조용히 버리지 않는다(사용자는 값을 넣었다고 믿는다).
141
+ *
142
+ * 공정 이름은 **대조로만** 걸러진다(모델에 행이 없어도 성립하는 선언이라 다른 안전망이 없다). 아직
143
+ * 돌지도 않고 명세 행도 없는 트윈이면 목록이 `undefined` 이고, 그때는 받아 주되 답에 그 사실을 싣는다.
144
+ */
145
+ const knownOperations = (0, operation_basis_js_1.knownOperationKinds)(inst.model, twin_engine_js_1.TwinEngine.kernel(domainId, instanceId), await twin_engine_js_1.TwinEngine.measuredOperationKinds(domainId, instanceId));
146
+ const { accepted, rejected } = (0, local_declarations_js_1.validateLocalDeclarations)(inst.kind, declarations, { knownOperations });
147
+ if (!accepted.length)
148
+ return { ok: false, error: 'no declaration was accepted', rejected };
149
+ const unverifiedOperations = knownOperations
150
+ ? []
151
+ : accepted.filter(d => d.target === 'operation').map(d => d.id);
152
+ /*
153
+ * 현장 범위면 **공간에 적는다** — 그 현장의 트윈 전부가 읽는 자리다. 공간을 모르면 거절한다(트윈에
154
+ * 몰래 적으면 사용자는 현장에 넣었다고 믿는다).
155
+ */
156
+ /* 현장 겹은 **읽기만** 한다 — 이 문은 트윈의 값만 넣는다(현장 값은 전용 문이 있다). 순서를 지키려면
157
+ 현장 겹을 함께 얹어야 한다: 현장 먼저, 트윈이 나중. */
158
+ const spaceRepo = (0, shell_1.getRepository)(twin_space_js_1.TwinSpace);
159
+ const space = inst.spaceId ? await spaceRepo.findOne({ where: { domain: { id: domainId }, spaceId: inst.spaceId } }) : null;
160
+ const nextSpace = (space?.localDeclarations ?? []);
161
+ const nextInst = (0, local_declarations_js_1.mergeLocalDeclarations)((inst.localDeclarations ?? []), accepted);
162
+ /* 얹으면서 **무엇을 덮었는지** 적어 온 겹을 저장한다 — 철회는 그 기억이 있어야 성립한다.
163
+ 순서가 규율이다: 현장 먼저, 트윈이 나중(좁은 것이 이긴다). */
164
+ const applied = (0, local_declarations_js_1.applyDeclarationLayers)(inst.model, nextSpace, nextInst);
165
+ const model = applied.model;
166
+ /* 현장 겹이 이 트윈에 얹을 자리가 없는 것은 정상이다(창고 트윈에 요금 자리가 없다) — 경고로 올리지 않는다. */
167
+ const missingTargets = applied.missingTargets.filter(t => t.scope === 'instance').map(({ target, id }) => ({ target, id }));
168
+ /* 읽을 수 있는 값으로 바꾸지 못한 선언 — 겹에는 남지만 계산에는 들어가지 않는다(그 사실을 말한다). */
169
+ const unreadable = applied.unreadable.map(({ target, id, propertyId }) => ({ target, id, propertyId }));
170
+ /* 겹은 언제나 남긴다 — 대상이 지금 없어도(구조가 바뀌었다) 사용자의 선언을 버리지 않는다. */
171
+ inst.localDeclarations = applied.instanceLayerApplied;
172
+ await repo.save(inst);
173
+ if (space) {
174
+ space.localDeclarations = applied.spaceLayerApplied;
175
+ await spaceRepo.save(space);
176
+ }
177
+ const running = twin_engine_js_1.TwinEngine.modeOf(domainId, instanceId);
178
+ if (running === 'live') {
179
+ /* 미러는 지금 받는다 — 저장·구조 행·커널이 함께 움직인다(adoptStructure 가 셋을 묶는다). */
180
+ const shift = await twin_engine_js_1.TwinEngine.adoptStructure(domainId, instanceId, model, 'local declarations (twin)');
181
+ return {
182
+ ok: true,
183
+ applied: 'running',
184
+ scope: 'instance',
185
+ accepted,
186
+ ...(rejected.length ? { rejected } : {}),
187
+ ...(missingTargets.length ? { missingTargets } : {}),
188
+ ...(unreadable.length ? { unreadable } : {}),
189
+ ...(unverifiedOperations.length
190
+ ? {
191
+ unverifiedOperations,
192
+ note: 'this twin has run no operations and declares no operation specification, so the operation name could not be checked — if it is misspelled the value will simply never be read'
193
+ }
194
+ : {}),
195
+ revision: shift.rev
196
+ };
197
+ }
198
+ /* 시뮬레이션·정지 트윈 — 문서와 구조 행에는 반영하고, 돌고 있는 커널에는 반영하지 않는다. */
199
+ inst.model = model;
200
+ await repo.save(inst);
201
+ const report = await (0, project_structure_js_1.projectStructure)(domainId, instanceId, model, instanceId);
202
+ return {
203
+ ok: true,
204
+ applied: running ? 'on-restart' : 'stored',
205
+ scope: 'instance',
206
+ ...(running ? { note: 'a running simulation keeps its current declarations — restart it to run on the new numbers' } : {}),
207
+ accepted,
208
+ ...(rejected.length ? { rejected } : {}),
209
+ ...(missingTargets.length ? { missingTargets } : {}),
210
+ ...(unreadable.length ? { unreadable } : {}),
211
+ ...(unverifiedOperations.length
212
+ ? {
213
+ unverifiedOperations,
214
+ note: 'this twin has run no operations and declares no operation specification, so the operation name could not be checked — if it is misspelled the value will simply never be read'
215
+ }
216
+ : {}),
217
+ ...report
218
+ };
219
+ }
220
+ /**
221
+ * 선언을 **철회한다** — 잘못 넣은 값을 원천으로 되돌리는 문.
222
+ *
223
+ * ── 왜 따로 문이 필요한가 (2026-08-18) ──────────────────────────────────────
224
+ * 선언은 겹에 보관되지만 **저장된 모델에 구워진다.** 그래서 겹에서 줄만 지워도 원래 값이 돌아오지
225
+ * 않는다 — 되돌릴 방법이 아예 없어서, 오타를 「원래 값을 다시 선언하는」 우회로만 고칠 수 있었다
226
+ * (사용자가 원래 값을 알고 있어야 한다는 뜻이고, 모르면 그 값은 영구히 이긴다).
227
+ *
228
+ * 그래서 겹이 **무엇을 덮었는지** 함께 기억하게 했고(`replaced`), 철회는 그 기억으로 되돌린다.
229
+ * 기억이 없는 옛 선언은 **손대지 않고 그렇게 말한다**(`unknownSource`) — 원래 값을 지어내는 것은
230
+ * 잘못 넣은 값을 그대로 두는 것보다 나쁘다. 그 자리는 다음 원천 재읽기가 바로잡는다.
231
+ *
232
+ * 반영 방식은 선언과 같다: 미러는 지금 받고(`adoptStructure`), 시뮬레이션은 재기동 때 받는다.
233
+ */
234
+ async revokeTwinDeclarations(instanceId, revocations, context) {
235
+ const domainId = context.state.domain.id;
236
+ const repo = (0, shell_1.getRepository)(twin_instance_js_1.TwinInstance);
237
+ const inst = await repo.findOne({ where: { domain: { id: domainId }, instanceId } });
238
+ if (!inst)
239
+ return { ok: false, error: `unknown twin: ${instanceId}` };
240
+ if (!inst.model)
241
+ return { ok: false, error: `twin "${instanceId}" has no model document` };
242
+ /* 도착 0건과 「겹에 없다」는 다른 일이다 — 선언 쪽에서 겪은 침묵을 여기서 되풀지 않는다. */
243
+ if (!revocations?.length)
244
+ return { ok: false, error: 'no revocation arrived — the revocations argument was empty' };
245
+ const spaceRepo = (0, shell_1.getRepository)(twin_space_js_1.TwinSpace);
246
+ const space = inst.spaceId ? await spaceRepo.findOne({ where: { domain: { id: domainId }, spaceId: inst.spaceId } }) : null;
247
+ const { layer, revoked, notFound } = (0, local_declarations_js_1.revokeLocalDeclarations)(inst.localDeclarations, revocations);
248
+ /* 이 문은 트윈 겹만 본다 — 현장 값을 여기서 빼려 하면 「겹에 없다」다(전용 문으로 가야 한다). */
249
+ if (!revoked.length)
250
+ return { ok: false, error: 'no declaration matched at this twin — a facility value is revoked at its facility', scope: 'instance', notFound };
251
+ /*
252
+ * 모델을 되돌리는 순서 — **뺀 뒤 남은 두 겹을 다시 얹는다.**
253
+ *
254
+ * 값을 「기억한 원천 값」으로 곧장 되돌리면, 트윈 겹을 뺐을 때 그 아래 있던 **현장 값이 되살아나지
255
+ * 않는다**(원천 값이 그 자리를 차지한다). 겹이 둘이 된 뒤에는 「빼고 다시 얹기」가 유일하게 옳은
256
+ * 되돌림이다 — 그러면 트윈 값을 빼면 현장 값이, 현장 값을 빼면 원천 값이 드러난다.
257
+ */
258
+ const restore = (0, local_declarations_js_1.restoreRevoked)(inst.model, revoked);
259
+ const nextSpace = (space?.localDeclarations ?? []);
260
+ const nextInst = layer;
261
+ const relaid = (0, local_declarations_js_1.applyDeclarationLayers)(restore.model, nextSpace, nextInst);
262
+ inst.localDeclarations = relaid.instanceLayerApplied;
263
+ await repo.save(inst);
264
+ if (space) {
265
+ space.localDeclarations = relaid.spaceLayerApplied;
266
+ await spaceRepo.save(space);
267
+ }
268
+ /*
269
+ * **겹에서 뺀 것**과 **값을 되돌린 것**은 다른 일이다 — 갈라서 말한다.
270
+ *
271
+ * 처음에는 되돌린 것만 `revoked` 로 냈다. 그래서 기억 없는 옛 선언을 철회하면 「revoked: [] 」이
272
+ * 돌아왔다 — 겹에서는 분명히 뺐는데(다시 얹히지 않는다) 아무 일도 없었던 것처럼 읽힌다.
273
+ */
274
+ const report = {
275
+ scope: 'instance',
276
+ withdrawn: revoked.map(r => ({ target: r.target, id: r.id, propertyId: r.propertyId })),
277
+ restored: restore.restored,
278
+ ...(notFound.length ? { notFound } : {}),
279
+ ...(restore.unknownSource.length
280
+ ? {
281
+ unknownSource: restore.unknownSource,
282
+ note: 'these declarations were made before the overridden value was remembered — the property keeps its current value until the next resync from the source'
283
+ }
284
+ : {}),
285
+ ...(restore.missingTargets.length ? { missingTargets: restore.missingTargets } : {})
286
+ };
287
+ const running = twin_engine_js_1.TwinEngine.modeOf(domainId, instanceId);
288
+ if (running === 'live') {
289
+ const shift = await twin_engine_js_1.TwinEngine.adoptStructure(domainId, instanceId, relaid.model, 'revoked local declarations (twin)');
290
+ return { ok: true, applied: 'running', ...report, revision: shift.rev };
291
+ }
292
+ inst.model = relaid.model;
293
+ await repo.save(inst);
294
+ await (0, project_structure_js_1.projectStructure)(domainId, instanceId, relaid.model, instanceId);
295
+ return {
296
+ ok: true,
297
+ applied: running ? 'on-restart' : 'stored',
298
+ ...(running ? { note: 'a running simulation keeps its current declarations — restart it to run without them' } : {}),
299
+ ...report
300
+ };
301
+ }
302
+ /**
303
+ * **현장의 값을 선언한다** — 트윈이 아니라 현장이 주어다.
304
+ *
305
+ * ── 왜 트윈 문과 갈랐나 (2026-08-18) ───────────────────────────────────────
306
+ * 처음에는 트윈 문에 범위 인자를 두었다. 그러면 **현장 값을 넣으려고 트윈을 골라야 한다** — 트윈은 그
307
+ * 값을 읽는 쪽이므로 개념이 거꾸로다(사용자가 그 어긋남을 지적했다). 주어가 다르면 문도 다르다.
308
+ *
309
+ * 어휘는 **그 현장 트윈들의 합집합**으로 검사한다: 한 현장에 여러 종류가 살고, 요금은 에너지 트윈만
310
+ * 읽는다. 어느 종류도 읽지 않는 속성은 거절한다(모르는 값을 받아 두면 사용자는 넣었다고 믿는다).
311
+ *
312
+ * 넣은 값은 그 현장의 **트윈 전부**에 얹힌다 — 한 트윈만 바꿔 두면 「현장 전체가 읽는다」가 거짓이 된다.
313
+ * 얹을 자리가 없는 트윈은 정상이고(창고 트윈에 요금 자리가 없다), 아무 트윈도 받지 않았다면 그 사실을
314
+ * 말한다.
315
+ */
316
+ async declareSpaceProperties(spaceId, declarations, context) {
317
+ const domainId = context.state.domain.id;
318
+ const spaceRepo = (0, shell_1.getRepository)(twin_space_js_1.TwinSpace);
319
+ const space = await spaceRepo.findOne({ where: { domain: { id: domainId }, spaceId } });
320
+ if (!space)
321
+ return { ok: false, error: `unknown facility: ${spaceId}` };
322
+ if (!declarations?.length)
323
+ return { ok: false, error: 'no declaration arrived — the declarations argument was empty' };
324
+ const twins = await (0, shell_1.getRepository)(twin_instance_js_1.TwinInstance).find({ where: { domain: { id: domainId }, spaceId } });
325
+ if (!twins.length)
326
+ return { ok: false, error: `facility "${spaceId}" has no twin — nothing would read the value` };
327
+ /*
328
+ * 검사는 **어느 종류든 읽으면 통과**다 — 현장에 에너지·창고가 함께 있으면 요금은 에너지 쪽 어휘로
329
+ * 받는다. 거절 이유는 종류별로 다를 수 있으니, 통과한 종류가 하나도 없을 때의 이유를 돌려준다.
330
+ */
331
+ /*
332
+ * 공정 이름도 **현장 합집합**으로 대조한다 — 창고가 돌리는 `putaway` 와 야드가 돌리는 `spot` 이 한
333
+ * 현장에 함께 있고, 현장 값은 그 전부에 얹힌다. 하나도 확인할 수 없으면 목록을 주지 않는다(모른다).
334
+ */
335
+ const knownSet = new Set();
336
+ for (const t of twins)
337
+ for (const k of (0, operation_basis_js_1.knownOperationKinds)(t.model, twin_engine_js_1.TwinEngine.kernel(domainId, t.instanceId), await twin_engine_js_1.TwinEngine.measuredOperationKinds(domainId, t.instanceId)) ?? [])
338
+ knownSet.add(k);
339
+ const knownOperations = knownSet.size ? [...knownSet] : undefined;
340
+ let accepted = [];
341
+ let rejected = [];
342
+ for (const kind of [...new Set(twins.map(t => t.kind))]) {
343
+ const r = (0, local_declarations_js_1.validateLocalDeclarations)(kind, declarations, { knownOperations });
344
+ if (r.accepted.length > accepted.length)
345
+ accepted = r.accepted;
346
+ if (!rejected.length)
347
+ rejected = r.rejected;
348
+ }
349
+ if (!accepted.length)
350
+ return { ok: false, error: 'no declaration was accepted by any twin kind at this facility', rejected };
351
+ const next = (0, local_declarations_js_1.mergeLocalDeclarations)(space.localDeclarations, accepted);
352
+ const spread = await spreadSpaceLayer(domainId, spaceId, next, 'local declarations (facility)');
353
+ space.localDeclarations = spread.spaceLayerApplied;
354
+ await spaceRepo.save(space);
355
+ const landed = spread.twins.filter(t => t.landed && t.applied !== 'failed');
356
+ return {
357
+ ok: true,
358
+ scope: 'space',
359
+ applied: landed.some(t => t.applied === 'running') ? 'running' : landed.length ? 'stored' : 'nowhere',
360
+ accepted,
361
+ ...(rejected.length ? { rejected } : {}),
362
+ twins: spread.twins,
363
+ ...(landed.length
364
+ ? {}
365
+ : { note: 'no twin at this facility has that target — the value is kept, but nothing reads it yet' })
366
+ };
367
+ }
368
+ /**
369
+ * 현장의 선언을 철회한다 — 그 현장의 **모든 트윈에서** 사라진다.
370
+ *
371
+ * 트윈이 같은 속성을 자기 겹에 갖고 있으면 그 값은 남는다(좁은 것이 이긴다) — 현장 값을 뺐는데 그
372
+ * 트윈만 그대로인 것이 옳다. 트윈마다 「원천으로 되돌리고 남은 두 겹을 다시 얹기」를 한다.
373
+ */
374
+ async revokeSpaceDeclarations(spaceId, revocations, context) {
375
+ const domainId = context.state.domain.id;
376
+ const spaceRepo = (0, shell_1.getRepository)(twin_space_js_1.TwinSpace);
377
+ const space = await spaceRepo.findOne({ where: { domain: { id: domainId }, spaceId } });
378
+ if (!space)
379
+ return { ok: false, error: `unknown facility: ${spaceId}` };
380
+ if (!revocations?.length)
381
+ return { ok: false, error: 'no revocation arrived — the revocations argument was empty' };
382
+ const { layer, revoked, notFound } = (0, local_declarations_js_1.revokeLocalDeclarations)(space.localDeclarations, revocations);
383
+ if (!revoked.length)
384
+ return { ok: false, error: 'no facility declaration matched', scope: 'space', notFound };
385
+ const repoAll = (0, shell_1.getRepository)(twin_instance_js_1.TwinInstance);
386
+ const twins = await repoAll.find({ where: { domain: { id: domainId }, spaceId } });
387
+ const per = [];
388
+ let spaceApplied = layer;
389
+ for (const t of twins) {
390
+ if (!t.model)
391
+ continue;
392
+ const back = (0, local_declarations_js_1.restoreRevoked)(t.model, revoked);
393
+ const out = (0, local_declarations_js_1.applyDeclarationLayers)(back.model, spaceApplied, (t.localDeclarations ?? []));
394
+ spaceApplied = out.spaceLayerApplied;
395
+ t.localDeclarations = out.instanceLayerApplied;
396
+ const running = twin_engine_js_1.TwinEngine.modeOf(domainId, t.instanceId);
397
+ /* 하나가 실패해도 나머지는 되돌린다 — 이유는 트윈별로 적어 돌려준다. */
398
+ try {
399
+ if (running === 'live') {
400
+ await repoAll.save(t);
401
+ await twin_engine_js_1.TwinEngine.adoptStructure(domainId, t.instanceId, out.model, 'revoked local declarations (facility)');
402
+ per.push({ instanceId: t.instanceId, applied: 'running' });
403
+ continue;
404
+ }
405
+ t.model = out.model;
406
+ await repoAll.save(t);
407
+ await (0, project_structure_js_1.projectStructure)(domainId, t.instanceId, out.model, t.instanceId);
408
+ per.push({ instanceId: t.instanceId, applied: running ? 'on-restart' : 'stored' });
409
+ }
410
+ catch (e) {
411
+ per.push({ instanceId: t.instanceId, applied: 'failed', error: e?.message ?? 'failed' });
412
+ }
413
+ }
414
+ space.localDeclarations = spaceApplied;
415
+ await spaceRepo.save(space);
416
+ return {
417
+ ok: true,
418
+ scope: 'space',
419
+ applied: per.some(x => x.applied === 'running') ? 'running' : 'stored',
420
+ withdrawn: revoked.map(r => ({ target: r.target, id: r.id, propertyId: r.propertyId })),
421
+ restored: revoked.filter(r => 'replaced' in r),
422
+ ...(notFound.length ? { notFound } : {}),
423
+ twins: per
424
+ };
425
+ }
426
+ };
427
+ exports.TwinModelMutation = TwinModelMutation;
428
+ tslib_1.__decorate([
429
+ (0, type_graphql_1.Directive)('@privilege(category: "twin", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)'),
430
+ (0, type_graphql_1.Mutation)(returns => shell_1.ScalarObject, {
431
+ description: "Rebuild this twin's structure tables from the model document it already holds. Reads nothing from the source: the model is unchanged and only the cache is redrawn. Use resyncTwin instead when the source itself may have changed."
432
+ }),
433
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('instanceId')),
434
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
435
+ tslib_1.__metadata("design:type", Function),
436
+ tslib_1.__metadata("design:paramtypes", [String, Object]),
437
+ tslib_1.__metadata("design:returntype", Promise)
438
+ ], TwinModelMutation.prototype, "reprojectTwinModel", null);
439
+ tslib_1.__decorate([
440
+ (0, type_graphql_1.Directive)('@privilege(category: "twin", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)'),
441
+ (0, type_graphql_1.Mutation)(returns => shell_1.ScalarObject, {
442
+ description: "Declare locally-owned numbers on a twin (tariff, contract, state of charge) as a layer on top of the reference-derived model, so a resync cannot drop them. Values carry source: local, telling every consumer that the authority for them sits here rather than in the source system. Values are validated against the kernel's property specification (unit and range). Mirrors adopt them while running; simulations keep their current declarations until restart, and the result says so."
443
+ }),
444
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('instanceId')),
445
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('declarations', type => [shell_1.ScalarObject])),
446
+ tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
447
+ tslib_1.__metadata("design:type", Function),
448
+ tslib_1.__metadata("design:paramtypes", [String, Array, Object]),
449
+ tslib_1.__metadata("design:returntype", Promise)
450
+ ], TwinModelMutation.prototype, "declareTwinProperties", null);
451
+ tslib_1.__decorate([
452
+ (0, type_graphql_1.Directive)('@privilege(category: "twin", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)'),
453
+ (0, type_graphql_1.Mutation)(returns => shell_1.ScalarObject, {
454
+ description: 'Revoke locally-declared values on a twin, restoring the value the reference system had when the declaration was applied (or removing the property if the source never had it). Declarations made before the overridden value was remembered are left untouched and reported, rather than guessed.'
455
+ }),
456
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('instanceId')),
457
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('revocations', type => [shell_1.ScalarObject])),
458
+ tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
459
+ tslib_1.__metadata("design:type", Function),
460
+ tslib_1.__metadata("design:paramtypes", [String, Array, Object]),
461
+ tslib_1.__metadata("design:returntype", Promise)
462
+ ], TwinModelMutation.prototype, "revokeTwinDeclarations", null);
463
+ tslib_1.__decorate([
464
+ (0, type_graphql_1.Directive)('@privilege(category: "twin", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)'),
465
+ (0, type_graphql_1.Mutation)(returns => shell_1.ScalarObject, {
466
+ description: 'Declare values that belong to a whole facility (space) rather than to one twin — tariff, currency, contracted power. They are applied to every twin in the facility (a twin-scope declaration of the same property still wins), and survive a resync from the source.'
467
+ }),
468
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('spaceId')),
469
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('declarations', type => [shell_1.ScalarObject])),
470
+ tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
471
+ tslib_1.__metadata("design:type", Function),
472
+ tslib_1.__metadata("design:paramtypes", [String, Array, Object]),
473
+ tslib_1.__metadata("design:returntype", Promise)
474
+ ], TwinModelMutation.prototype, "declareSpaceProperties", null);
475
+ tslib_1.__decorate([
476
+ (0, type_graphql_1.Directive)('@privilege(category: "twin", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)'),
477
+ (0, type_graphql_1.Mutation)(returns => shell_1.ScalarObject, {
478
+ description: 'Revoke facility-scope declarations, restoring on every twin in the facility the value that sat underneath (a twin-scope declaration of the same property stays, and the source value reappears where nothing else covers it).'
479
+ }),
480
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('spaceId')),
481
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('revocations', type => [shell_1.ScalarObject])),
482
+ tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
483
+ tslib_1.__metadata("design:type", Function),
484
+ tslib_1.__metadata("design:paramtypes", [String, Array, Object]),
485
+ tslib_1.__metadata("design:returntype", Promise)
486
+ ], TwinModelMutation.prototype, "revokeSpaceDeclarations", null);
487
+ exports.TwinModelMutation = TwinModelMutation = tslib_1.__decorate([
488
+ (0, type_graphql_1.Resolver)()
489
+ ], TwinModelMutation);
490
+ //# sourceMappingURL=twin-model-mutation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"twin-model-mutation.js","sourceRoot":"","sources":["../../../server/service/twin-model/twin-model-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'\n\nimport { ScalarObject, getRepository } from '@things-factory/shell'\n\nimport { TwinInstance } from '../twin-instance/twin-instance.js'\nimport { TwinSpace } from '../twin-space/twin-space.js'\nimport { TwinEngine } from '../../engine/twin-engine.js'\nimport {\n applyDeclarationLayers,\n applyLocalDeclarations,\n mergeLocalDeclarations,\n restoreRevoked,\n revokeLocalDeclarations,\n validateLocalDeclarations,\n type DeclarationRevocation,\n type LocalDeclaration\n} from '../../engine/local-declarations.js'\nimport { knownOperationKinds } from '../../engine/operation-basis.js'\nimport { projectStructure } from './project-structure.js'\n\n/*\n * 구조 테이블 **재생성** — 저장된 모델 문서로 캐시를 다시 그린다.\n *\n * ── 이것은 원본에서 다시 읽는 것과 다르다 ──────────────────────────────────────\n * `resyncTwin` 은 **원본**에 가서 현장이 지금 어떻게 생겼는지 다시 읽는다(모델이 바뀔 수 있다).\n * 여기는 **아무것도 다시 읽지 않는다** — 이미 갖고 있는 모델 문서를 테이블로 다시 푼다.\n * 그래서 모델은 한 글자도 바뀌지 않고, 테이블만 문서와 같아진다.\n *\n * ── 왜 필요한가 ────────────────────────────────────────────────────────────────\n * 이 앱에는 **투영이 생기기 전에 만들어진 트윈**이 있다. 문서에는 자리 6개·설비 32대가 있는데\n * 테이블은 0행이고, 그중 일부는 원천도 기억하지 않아 다시 읽을 수조차 없다 — 조회 화면이\n * 영구히 \"테이블이 뒤에 있습니다\" 만 말하는 막다른 상태다.\n *\n * ── 쓰기 경로가 둘이 되는 것 아닌가 ────────────────────────────────────────────\n * 아니다. 그 규율(ADR-0032-D)이 막는 것은 **다른 진실이 행을 쓰는 것**이다(예: 틱 루프가 관측을\n * 밀어 넣기). 여기서 쓰는 것은 인제스트가 쓰는 것과 **같은 문서·같은 투영**이고, 그 규율이 함께\n * 요구한 \"재생성 가능성을 구조로\" 가 바로 이것이다. 캐시는 언제든 다시 그릴 수 있어야 한다.\n */\n/**\n * 현장 겹을 **그 현장의 트윈 전부**에 얹는다 — 그러지 않으면 「현장 전체가 읽는다」가 거짓이 된다.\n *\n * ── 왜 필요한가 (2026-08-18) ────────────────────────────────────────────────\n * 처음에는 호출한 트윈에만 얹었다. 그러면 같은 현장의 다른 EMS 트윈은 **다음에 자기가 다시 그려질 때\n * 까지** 옛 값으로 돌아간다 — 화면은 「현장 전체」라고 말하는데 실제로는 한 트윈만 바뀐 상태다.\n *\n * 트윈마다 자기 겹을 그대로 얹는다(좁은 것이 이긴다). 돌고 있는 미러는 지금 받고, 시뮬레이션·정지\n * 트윈은 문서에 반영한다(재기동 때 받는다) — 그 차이를 결과에 적어 돌려준다.\n *\n * 얹을 자리가 없는 트윈은 **정상**이다(창고 트윈에 요금 자리가 없다). 그 사실도 세어 돌려준다 —\n * 「현장에 넣었는데 아무 트윈도 안 받았다」는 사용자가 알아야 할 사실이다.\n */\nasync function spreadSpaceLayer(\n domainId: string,\n spaceId: string,\n spaceLayer: LocalDeclaration[],\n comment: string\n): Promise<{\n spaceLayerApplied: LocalDeclaration[]\n twins: { instanceId: string; applied: string; landed: boolean; error?: string }[]\n}> {\n const repo = getRepository(TwinInstance)\n const twins = await repo.find({ where: { domain: { id: domainId }, spaceId } })\n const report: { instanceId: string; applied: string; landed: boolean; error?: string }[] = []\n let latest = spaceLayer\n for (const t of twins) {\n if (!t.model) continue\n const out = applyDeclarationLayers(t.model, latest, (t.localDeclarations ?? []) as LocalDeclaration[])\n /* 기억(`replaced`)은 **얹힌 트윈에서만** 채워진다 — 자리가 없는 트윈을 지나며 지워지지 않게 이어 든다. */\n latest = out.spaceLayerApplied\n const landed = !out.missingTargets.some(m => m.scope === 'space' && spaceLayer.some(d => d.id === m.id && d.target === m.target))\n t.localDeclarations = out.instanceLayerApplied as any\n const running = TwinEngine.modeOf(domainId, t.instanceId)\n /*\n * **트윈 하나가 실패해도 나머지는 받는다** — 다만 조용히 넘기지 않는다(2026-08-18 실측).\n *\n * 현장 선언을 처음 퍼뜨렸을 때 그 현장의 어떤 트윈에서 구조 투영이 터졌고(그 트윈 모델에 설비 id가\n * 겹쳐 있었다 — 선재 결함), 그 예외가 올라와 **한 트윈 때문에 현장 전체 선언이 실패**했다. 사용자는\n * 값을 넣었는데 아무 일도 일어나지 않은 것으로 본다.\n *\n * 그렇다고 삼키면 더 나쁘다: 「현장 전체가 읽는다」고 말한 뒤 몇 트윈이 못 읽는 상태가 된다. 그래서\n * 트윈별로 이유를 적어 돌려준다.\n */\n try {\n if (running === 'live') {\n await repo.save(t)\n await TwinEngine.adoptStructure(domainId, t.instanceId, out.model, comment)\n report.push({ instanceId: t.instanceId, applied: 'running', landed })\n continue\n }\n t.model = out.model\n await repo.save(t)\n await projectStructure(domainId, t.instanceId, out.model, t.instanceId)\n report.push({ instanceId: t.instanceId, applied: running ? 'on-restart' : 'stored', landed })\n } catch (e: any) {\n report.push({ instanceId: t.instanceId, applied: 'failed', landed, error: e?.message ?? 'failed' })\n }\n }\n return { spaceLayerApplied: latest, twins: report }\n}\n\n@Resolver()\nexport class TwinModelMutation {\n @Directive('@privilege(category: \"twin\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => ScalarObject, {\n description:\n \"Rebuild this twin's structure tables from the model document it already holds. Reads nothing from the source: the model is unchanged and only the cache is redrawn. Use resyncTwin instead when the source itself may have changed.\"\n })\n async reprojectTwinModel(@Arg('instanceId') instanceId: string, @Ctx() context: ResolverContext): Promise<any> {\n const domainId = context.state.domain.id\n const inst = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!inst) return { ok: false, error: `unknown twin: ${instanceId}` }\n if (!inst.model) return { ok: false, error: `twin \"${instanceId}\" has no model document — there is nothing to draw from` }\n\n try {\n /*\n * 출처 표식은 **이 트윈 자신**이다. 인제스트도 같은 값을 넣는다(`master.source` = instanceId) —\n * 여기서 다른 값을 넣으면 같은 행이 어디서 왔는지가 경로마다 달라진다.\n */\n const report = await projectStructure(domainId, instanceId, inst.model, instanceId)\n return { ok: true, ...report }\n } catch (e: any) {\n return { ok: false, error: e?.message || 'reprojection failed' }\n }\n }\n\n /**\n * 현장이 정하는 수를 트윈에 얹는다 — **구조는 원천이, 수는 현장이.**\n *\n * ── 왜 이 문이 필요했나 (2026-08-18) ──────────────────────────────────────\n * 커넥터로 만든 트윈은 계통도·계량 지점을 원 시스템에서 읽어 온다. 그런데 요금 단가·계약 정보·\n * 축전지 충전율은 원 시스템이 모른다(SCADA 게이트웨이는 우리 전기 계약을 알지 못한다). 그래서\n * 계량이 흐르는 트윈에서도 **금액이 영원히 나오지 않았다** — 넣을 문이 없었기 때문이다.\n *\n * 값은 `model` 에 직접 쓰지 않고 **겹**으로 보관한다: 모델은 원천의 사본이므로 다시 읽기가 그것을\n * 새로 그리면 직접 쓴 값은 조용히 사라진다. 겹은 모델을 그릴 때마다 다시 얹힌다.\n *\n * ── 돌고 있는 트윈에 어떻게 반영하나 ────────────────────────────────────────\n * 미러는 **동작 중에** 새 구조를 받는다(현실은 멈추지 않는다). 시뮬레이션은 받지 않는다 — 조건이\n * 바뀐 실험은 다른 실험이고, 커널이 그렇게 거절한다. 그때는 저장만 하고 **그 사실을 말한다**:\n * 조용히 성공으로 답하면 사용자는 지금 화면의 수가 새 선언으로 계산된 줄로 읽는다.\n */\n @Directive('@privilege(category: \"twin\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => ScalarObject, {\n description:\n \"Declare locally-owned numbers on a twin (tariff, contract, state of charge) as a layer on top of the reference-derived model, so a resync cannot drop them. Values carry source: local, telling every consumer that the authority for them sits here rather than in the source system. Values are validated against the kernel's property specification (unit and range). Mirrors adopt them while running; simulations keep their current declarations until restart, and the result says so.\"\n })\n async declareTwinProperties(\n @Arg('instanceId') instanceId: string,\n @Arg('declarations', type => [ScalarObject]) declarations: any[],\n @Ctx() context: ResolverContext\n ): Promise<any> {\n const domainId = context.state.domain.id\n const repo = getRepository(TwinInstance)\n const inst = await repo.findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!inst) return { ok: false, error: `unknown twin: ${instanceId}` }\n if (!inst.model) return { ok: false, error: `twin \"${instanceId}\" has no model document — provision it before declaring values on it` }\n\n /*\n * **선언이 하나도 도착하지 않은 것**과 **받았지만 다 거절된 것**은 다른 일이다.\n *\n * 둘을 같은 문장으로 답했더니, 입력이 통째로 사라진 호출이 「받아준 선언이 없다 · 거절 목록 비어 있음」\n * 이라는 답을 받았다 — 사용자는 자기 값이 서버까지 오지 못한 것을 알 수 없다(실제로 겪었다: GraphQL\n * `Object` 스칼라에 인라인 리터럴로 주면 빈 배열이 되고, 변수로 주면 온다).\n */\n if (!declarations?.length) return { ok: false, error: 'no declaration arrived — the declarations argument was empty' }\n\n /*\n * 검사부터 — 받지 않은 것을 조용히 버리지 않는다(사용자는 값을 넣었다고 믿는다).\n *\n * 공정 이름은 **대조로만** 걸러진다(모델에 행이 없어도 성립하는 선언이라 다른 안전망이 없다). 아직\n * 돌지도 않고 명세 행도 없는 트윈이면 목록이 `undefined` 이고, 그때는 받아 주되 답에 그 사실을 싣는다.\n */\n const knownOperations = knownOperationKinds(\n inst.model,\n TwinEngine.kernel(domainId, instanceId),\n await TwinEngine.measuredOperationKinds(domainId, instanceId)\n )\n const { accepted, rejected } = validateLocalDeclarations(inst.kind, declarations as LocalDeclaration[], { knownOperations })\n if (!accepted.length) return { ok: false, error: 'no declaration was accepted', rejected }\n const unverifiedOperations = knownOperations\n ? []\n : accepted.filter(d => d.target === 'operation').map(d => d.id)\n\n /*\n * 현장 범위면 **공간에 적는다** — 그 현장의 트윈 전부가 읽는 자리다. 공간을 모르면 거절한다(트윈에\n * 몰래 적으면 사용자는 현장에 넣었다고 믿는다).\n */\n /* 현장 겹은 **읽기만** 한다 — 이 문은 트윈의 값만 넣는다(현장 값은 전용 문이 있다). 순서를 지키려면\n 현장 겹을 함께 얹어야 한다: 현장 먼저, 트윈이 나중. */\n const spaceRepo = getRepository(TwinSpace)\n const space =\n inst.spaceId ? await spaceRepo.findOne({ where: { domain: { id: domainId }, spaceId: inst.spaceId } }) : null\n const nextSpace = (space?.localDeclarations ?? []) as LocalDeclaration[]\n const nextInst = mergeLocalDeclarations((inst.localDeclarations ?? []) as LocalDeclaration[], accepted)\n\n /* 얹으면서 **무엇을 덮었는지** 적어 온 겹을 저장한다 — 철회는 그 기억이 있어야 성립한다.\n 순서가 규율이다: 현장 먼저, 트윈이 나중(좁은 것이 이긴다). */\n const applied = applyDeclarationLayers(inst.model, nextSpace, nextInst)\n const model = applied.model\n /* 현장 겹이 이 트윈에 얹을 자리가 없는 것은 정상이다(창고 트윈에 요금 자리가 없다) — 경고로 올리지 않는다. */\n const missingTargets = applied.missingTargets.filter(t => t.scope === 'instance').map(({ target, id }) => ({ target, id }))\n /* 읽을 수 있는 값으로 바꾸지 못한 선언 — 겹에는 남지만 계산에는 들어가지 않는다(그 사실을 말한다). */\n const unreadable = applied.unreadable.map(({ target, id, propertyId }) => ({ target, id, propertyId }))\n\n /* 겹은 언제나 남긴다 — 대상이 지금 없어도(구조가 바뀌었다) 사용자의 선언을 버리지 않는다. */\n inst.localDeclarations = applied.instanceLayerApplied\n await repo.save(inst)\n if (space) {\n space.localDeclarations = applied.spaceLayerApplied\n await spaceRepo.save(space)\n }\n\n const running = TwinEngine.modeOf(domainId, instanceId)\n if (running === 'live') {\n /* 미러는 지금 받는다 — 저장·구조 행·커널이 함께 움직인다(adoptStructure 가 셋을 묶는다). */\n const shift = await TwinEngine.adoptStructure(domainId, instanceId, model, 'local declarations (twin)')\n return {\n ok: true,\n applied: 'running',\n scope: 'instance',\n accepted,\n ...(rejected.length ? { rejected } : {}),\n ...(missingTargets.length ? { missingTargets } : {}),\n ...(unreadable.length ? { unreadable } : {}),\n ...(unverifiedOperations.length\n ? {\n unverifiedOperations,\n note: 'this twin has run no operations and declares no operation specification, so the operation name could not be checked — if it is misspelled the value will simply never be read'\n }\n : {}),\n revision: shift.rev\n }\n }\n\n /* 시뮬레이션·정지 트윈 — 문서와 구조 행에는 반영하고, 돌고 있는 커널에는 반영하지 않는다. */\n inst.model = model\n await repo.save(inst)\n const report = await projectStructure(domainId, instanceId, model, instanceId)\n return {\n ok: true,\n applied: running ? 'on-restart' : 'stored',\n scope: 'instance',\n ...(running ? { note: 'a running simulation keeps its current declarations — restart it to run on the new numbers' } : {}),\n accepted,\n ...(rejected.length ? { rejected } : {}),\n ...(missingTargets.length ? { missingTargets } : {}),\n ...(unreadable.length ? { unreadable } : {}),\n ...(unverifiedOperations.length\n ? {\n unverifiedOperations,\n note: 'this twin has run no operations and declares no operation specification, so the operation name could not be checked — if it is misspelled the value will simply never be read'\n }\n : {}),\n ...report\n }\n }\n\n /**\n * 선언을 **철회한다** — 잘못 넣은 값을 원천으로 되돌리는 문.\n *\n * ── 왜 따로 문이 필요한가 (2026-08-18) ──────────────────────────────────────\n * 선언은 겹에 보관되지만 **저장된 모델에 구워진다.** 그래서 겹에서 줄만 지워도 원래 값이 돌아오지\n * 않는다 — 되돌릴 방법이 아예 없어서, 오타를 「원래 값을 다시 선언하는」 우회로만 고칠 수 있었다\n * (사용자가 원래 값을 알고 있어야 한다는 뜻이고, 모르면 그 값은 영구히 이긴다).\n *\n * 그래서 겹이 **무엇을 덮었는지** 함께 기억하게 했고(`replaced`), 철회는 그 기억으로 되돌린다.\n * 기억이 없는 옛 선언은 **손대지 않고 그렇게 말한다**(`unknownSource`) — 원래 값을 지어내는 것은\n * 잘못 넣은 값을 그대로 두는 것보다 나쁘다. 그 자리는 다음 원천 재읽기가 바로잡는다.\n *\n * 반영 방식은 선언과 같다: 미러는 지금 받고(`adoptStructure`), 시뮬레이션은 재기동 때 받는다.\n */\n @Directive('@privilege(category: \"twin\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => ScalarObject, {\n description:\n 'Revoke locally-declared values on a twin, restoring the value the reference system had when the declaration was applied (or removing the property if the source never had it). Declarations made before the overridden value was remembered are left untouched and reported, rather than guessed.'\n })\n async revokeTwinDeclarations(\n @Arg('instanceId') instanceId: string,\n @Arg('revocations', type => [ScalarObject]) revocations: any[],\n @Ctx() context: ResolverContext\n ): Promise<any> {\n const domainId = context.state.domain.id\n const repo = getRepository(TwinInstance)\n const inst = await repo.findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!inst) return { ok: false, error: `unknown twin: ${instanceId}` }\n if (!inst.model) return { ok: false, error: `twin \"${instanceId}\" has no model document` }\n /* 도착 0건과 「겹에 없다」는 다른 일이다 — 선언 쪽에서 겪은 침묵을 여기서 되풀지 않는다. */\n if (!revocations?.length) return { ok: false, error: 'no revocation arrived — the revocations argument was empty' }\n\n const spaceRepo = getRepository(TwinSpace)\n const space =\n inst.spaceId ? await spaceRepo.findOne({ where: { domain: { id: domainId }, spaceId: inst.spaceId } }) : null\n const { layer, revoked, notFound } = revokeLocalDeclarations(\n inst.localDeclarations as LocalDeclaration[] | undefined,\n revocations as DeclarationRevocation[]\n )\n /* 이 문은 트윈 겹만 본다 — 현장 값을 여기서 빼려 하면 「겹에 없다」다(전용 문으로 가야 한다). */\n if (!revoked.length) return { ok: false, error: 'no declaration matched at this twin — a facility value is revoked at its facility', scope: 'instance', notFound }\n\n /*\n * 모델을 되돌리는 순서 — **뺀 뒤 남은 두 겹을 다시 얹는다.**\n *\n * 값을 「기억한 원천 값」으로 곧장 되돌리면, 트윈 겹을 뺐을 때 그 아래 있던 **현장 값이 되살아나지\n * 않는다**(원천 값이 그 자리를 차지한다). 겹이 둘이 된 뒤에는 「빼고 다시 얹기」가 유일하게 옳은\n * 되돌림이다 — 그러면 트윈 값을 빼면 현장 값이, 현장 값을 빼면 원천 값이 드러난다.\n */\n const restore = restoreRevoked(inst.model, revoked)\n const nextSpace = (space?.localDeclarations ?? []) as LocalDeclaration[]\n const nextInst = layer\n\n const relaid = applyDeclarationLayers(restore.model, nextSpace, nextInst)\n\n inst.localDeclarations = relaid.instanceLayerApplied\n await repo.save(inst)\n if (space) {\n space.localDeclarations = relaid.spaceLayerApplied\n await spaceRepo.save(space)\n }\n\n /*\n * **겹에서 뺀 것**과 **값을 되돌린 것**은 다른 일이다 — 갈라서 말한다.\n *\n * 처음에는 되돌린 것만 `revoked` 로 냈다. 그래서 기억 없는 옛 선언을 철회하면 「revoked: [] 」이\n * 돌아왔다 — 겹에서는 분명히 뺐는데(다시 얹히지 않는다) 아무 일도 없었던 것처럼 읽힌다.\n */\n const report = {\n scope: 'instance',\n withdrawn: revoked.map(r => ({ target: r.target, id: r.id, propertyId: r.propertyId })),\n restored: restore.restored,\n ...(notFound.length ? { notFound } : {}),\n ...(restore.unknownSource.length\n ? {\n unknownSource: restore.unknownSource,\n note: 'these declarations were made before the overridden value was remembered — the property keeps its current value until the next resync from the source'\n }\n : {}),\n ...(restore.missingTargets.length ? { missingTargets: restore.missingTargets } : {})\n }\n\n const running = TwinEngine.modeOf(domainId, instanceId)\n if (running === 'live') {\n const shift = await TwinEngine.adoptStructure(domainId, instanceId, relaid.model, 'revoked local declarations (twin)')\n return { ok: true, applied: 'running', ...report, revision: shift.rev }\n }\n\n inst.model = relaid.model\n await repo.save(inst)\n await projectStructure(domainId, instanceId, relaid.model, instanceId)\n return {\n ok: true,\n applied: running ? 'on-restart' : 'stored',\n ...(running ? { note: 'a running simulation keeps its current declarations — restart it to run without them' } : {}),\n ...report\n }\n }\n /**\n * **현장의 값을 선언한다** — 트윈이 아니라 현장이 주어다.\n *\n * ── 왜 트윈 문과 갈랐나 (2026-08-18) ───────────────────────────────────────\n * 처음에는 트윈 문에 범위 인자를 두었다. 그러면 **현장 값을 넣으려고 트윈을 골라야 한다** — 트윈은 그\n * 값을 읽는 쪽이므로 개념이 거꾸로다(사용자가 그 어긋남을 지적했다). 주어가 다르면 문도 다르다.\n *\n * 어휘는 **그 현장 트윈들의 합집합**으로 검사한다: 한 현장에 여러 종류가 살고, 요금은 에너지 트윈만\n * 읽는다. 어느 종류도 읽지 않는 속성은 거절한다(모르는 값을 받아 두면 사용자는 넣었다고 믿는다).\n *\n * 넣은 값은 그 현장의 **트윈 전부**에 얹힌다 — 한 트윈만 바꿔 두면 「현장 전체가 읽는다」가 거짓이 된다.\n * 얹을 자리가 없는 트윈은 정상이고(창고 트윈에 요금 자리가 없다), 아무 트윈도 받지 않았다면 그 사실을\n * 말한다.\n */\n @Directive('@privilege(category: \"twin\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => ScalarObject, {\n description:\n 'Declare values that belong to a whole facility (space) rather than to one twin — tariff, currency, contracted power. They are applied to every twin in the facility (a twin-scope declaration of the same property still wins), and survive a resync from the source.'\n })\n async declareSpaceProperties(\n @Arg('spaceId') spaceId: string,\n @Arg('declarations', type => [ScalarObject]) declarations: any[],\n @Ctx() context: ResolverContext\n ): Promise<any> {\n const domainId = context.state.domain.id\n const spaceRepo = getRepository(TwinSpace)\n const space = await spaceRepo.findOne({ where: { domain: { id: domainId }, spaceId } })\n if (!space) return { ok: false, error: `unknown facility: ${spaceId}` }\n if (!declarations?.length) return { ok: false, error: 'no declaration arrived — the declarations argument was empty' }\n\n const twins = await getRepository(TwinInstance).find({ where: { domain: { id: domainId }, spaceId } })\n if (!twins.length) return { ok: false, error: `facility \"${spaceId}\" has no twin — nothing would read the value` }\n\n /*\n * 검사는 **어느 종류든 읽으면 통과**다 — 현장에 에너지·창고가 함께 있으면 요금은 에너지 쪽 어휘로\n * 받는다. 거절 이유는 종류별로 다를 수 있으니, 통과한 종류가 하나도 없을 때의 이유를 돌려준다.\n */\n /*\n * 공정 이름도 **현장 합집합**으로 대조한다 — 창고가 돌리는 `putaway` 와 야드가 돌리는 `spot` 이 한\n * 현장에 함께 있고, 현장 값은 그 전부에 얹힌다. 하나도 확인할 수 없으면 목록을 주지 않는다(모른다).\n */\n const knownSet = new Set<string>()\n for (const t of twins)\n for (const k of knownOperationKinds(\n t.model,\n TwinEngine.kernel(domainId, t.instanceId),\n await TwinEngine.measuredOperationKinds(domainId, t.instanceId)\n ) ?? [])\n knownSet.add(k)\n const knownOperations = knownSet.size ? [...knownSet] : undefined\n\n let accepted: LocalDeclaration[] = []\n let rejected: any[] = []\n for (const kind of [...new Set(twins.map(t => t.kind))]) {\n const r = validateLocalDeclarations(kind, declarations as LocalDeclaration[], { knownOperations })\n if (r.accepted.length > accepted.length) accepted = r.accepted\n if (!rejected.length) rejected = r.rejected\n }\n if (!accepted.length) return { ok: false, error: 'no declaration was accepted by any twin kind at this facility', rejected }\n\n const next = mergeLocalDeclarations(space.localDeclarations as LocalDeclaration[] | undefined, accepted)\n const spread = await spreadSpaceLayer(domainId, spaceId, next, 'local declarations (facility)')\n space.localDeclarations = spread.spaceLayerApplied as any\n await spaceRepo.save(space)\n\n const landed = spread.twins.filter(t => t.landed && t.applied !== 'failed')\n return {\n ok: true,\n scope: 'space',\n applied: landed.some(t => t.applied === 'running') ? 'running' : landed.length ? 'stored' : 'nowhere',\n accepted,\n ...(rejected.length ? { rejected } : {}),\n twins: spread.twins,\n ...(landed.length\n ? {}\n : { note: 'no twin at this facility has that target — the value is kept, but nothing reads it yet' })\n }\n }\n\n /**\n * 현장의 선언을 철회한다 — 그 현장의 **모든 트윈에서** 사라진다.\n *\n * 트윈이 같은 속성을 자기 겹에 갖고 있으면 그 값은 남는다(좁은 것이 이긴다) — 현장 값을 뺐는데 그\n * 트윈만 그대로인 것이 옳다. 트윈마다 「원천으로 되돌리고 남은 두 겹을 다시 얹기」를 한다.\n */\n @Directive('@privilege(category: \"twin\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => ScalarObject, {\n description:\n 'Revoke facility-scope declarations, restoring on every twin in the facility the value that sat underneath (a twin-scope declaration of the same property stays, and the source value reappears where nothing else covers it).'\n })\n async revokeSpaceDeclarations(\n @Arg('spaceId') spaceId: string,\n @Arg('revocations', type => [ScalarObject]) revocations: any[],\n @Ctx() context: ResolverContext\n ): Promise<any> {\n const domainId = context.state.domain.id\n const spaceRepo = getRepository(TwinSpace)\n const space = await spaceRepo.findOne({ where: { domain: { id: domainId }, spaceId } })\n if (!space) return { ok: false, error: `unknown facility: ${spaceId}` }\n if (!revocations?.length) return { ok: false, error: 'no revocation arrived — the revocations argument was empty' }\n\n const { layer, revoked, notFound } = revokeLocalDeclarations(\n space.localDeclarations as LocalDeclaration[] | undefined,\n revocations as DeclarationRevocation[]\n )\n if (!revoked.length) return { ok: false, error: 'no facility declaration matched', scope: 'space', notFound }\n\n const repoAll = getRepository(TwinInstance)\n const twins = await repoAll.find({ where: { domain: { id: domainId }, spaceId } })\n const per: { instanceId: string; applied: string; error?: string }[] = []\n let spaceApplied = layer\n for (const t of twins) {\n if (!t.model) continue\n const back = restoreRevoked(t.model, revoked)\n const out = applyDeclarationLayers(back.model, spaceApplied, (t.localDeclarations ?? []) as LocalDeclaration[])\n spaceApplied = out.spaceLayerApplied\n t.localDeclarations = out.instanceLayerApplied as any\n const running = TwinEngine.modeOf(domainId, t.instanceId)\n /* 하나가 실패해도 나머지는 되돌린다 — 이유는 트윈별로 적어 돌려준다. */\n try {\n if (running === 'live') {\n await repoAll.save(t)\n await TwinEngine.adoptStructure(domainId, t.instanceId, out.model, 'revoked local declarations (facility)')\n per.push({ instanceId: t.instanceId, applied: 'running' })\n continue\n }\n t.model = out.model\n await repoAll.save(t)\n await projectStructure(domainId, t.instanceId, out.model, t.instanceId)\n per.push({ instanceId: t.instanceId, applied: running ? 'on-restart' : 'stored' })\n } catch (e: any) {\n per.push({ instanceId: t.instanceId, applied: 'failed', error: e?.message ?? 'failed' })\n }\n }\n space.localDeclarations = spaceApplied as any\n await spaceRepo.save(space)\n\n return {\n ok: true,\n scope: 'space',\n applied: per.some(x => x.applied === 'running') ? 'running' : 'stored',\n withdrawn: revoked.map(r => ({ target: r.target, id: r.id, propertyId: r.propertyId })),\n restored: revoked.filter(r => 'replaced' in r),\n ...(notFound.length ? { notFound } : {}),\n twins: per\n }\n }\n}\n"]}