@things-factory/headless-twin 10.0.15 → 10.0.18

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 (513) hide show
  1. package/dist-server/engine/attention-digest.d.ts +4 -4
  2. package/dist-server/engine/attention-digest.js +7 -7
  3. package/dist-server/engine/attention-digest.js.map +1 -1
  4. package/dist-server/engine/canonical-ingest.d.ts +18 -82
  5. package/dist-server/engine/canonical-ingest.js +183 -18
  6. package/dist-server/engine/canonical-ingest.js.map +1 -1
  7. package/dist-server/engine/command-routing.js +1 -1
  8. package/dist-server/engine/command-routing.js.map +1 -1
  9. package/dist-server/engine/declared-stimulus.js +1 -1
  10. package/dist-server/engine/declared-stimulus.js.map +1 -1
  11. package/dist-server/engine/energy-topology.js +4 -4
  12. package/dist-server/engine/energy-topology.js.map +1 -1
  13. package/dist-server/engine/ingest-dedupe.d.ts +38 -0
  14. package/dist-server/engine/ingest-dedupe.js +145 -0
  15. package/dist-server/engine/ingest-dedupe.js.map +1 -0
  16. package/dist-server/engine/ingest-health.d.ts +90 -10
  17. package/dist-server/engine/ingest-health.js +125 -16
  18. package/dist-server/engine/ingest-health.js.map +1 -1
  19. package/dist-server/engine/integration-probes.d.ts +3 -3
  20. package/dist-server/engine/integration-probes.js +6 -6
  21. package/dist-server/engine/integration-probes.js.map +1 -1
  22. package/dist-server/engine/kpi-baseline.js +4 -4
  23. package/dist-server/engine/kpi-baseline.js.map +1 -1
  24. package/dist-server/engine/kpi-fold.d.ts +212 -14
  25. package/dist-server/engine/kpi-fold.js +374 -21
  26. package/dist-server/engine/kpi-fold.js.map +1 -1
  27. package/dist-server/engine/kpi-query.d.ts +11 -11
  28. package/dist-server/engine/kpi-query.js +281 -36
  29. package/dist-server/engine/kpi-query.js.map +1 -1
  30. package/dist-server/engine/live-feed-registry.d.ts +1 -1
  31. package/dist-server/engine/live-feed-registry.js +1 -1
  32. package/dist-server/engine/live-feed-registry.js.map +1 -1
  33. package/dist-server/engine/load-meter.d.ts +1 -1
  34. package/dist-server/engine/load-meter.js.map +1 -1
  35. package/dist-server/engine/local-declarations.d.ts +7 -7
  36. package/dist-server/engine/local-declarations.js +15 -14
  37. package/dist-server/engine/local-declarations.js.map +1 -1
  38. package/dist-server/engine/log.d.ts +1 -1
  39. package/dist-server/engine/log.js +1 -1
  40. package/dist-server/engine/log.js.map +1 -1
  41. package/dist-server/engine/measured-estimator.js +1 -1
  42. package/dist-server/engine/measured-estimator.js.map +1 -1
  43. package/dist-server/engine/measured-yield.js +1 -1
  44. package/dist-server/engine/measured-yield.js.map +1 -1
  45. package/dist-server/engine/model-basis.d.ts +1 -1
  46. package/dist-server/engine/model-basis.js +1 -1
  47. package/dist-server/engine/model-basis.js.map +1 -1
  48. package/dist-server/engine/model-gap.d.ts +3 -3
  49. package/dist-server/engine/model-gap.js +1 -1
  50. package/dist-server/engine/model-gap.js.map +1 -1
  51. package/dist-server/engine/model-vocabulary.js +3 -3
  52. package/dist-server/engine/model-vocabulary.js.map +1 -1
  53. package/dist-server/engine/oee-accumulator.d.ts +6 -5
  54. package/dist-server/engine/oee-accumulator.js +6 -5
  55. package/dist-server/engine/oee-accumulator.js.map +1 -1
  56. package/dist-server/engine/property-effects.js +2 -2
  57. package/dist-server/engine/property-effects.js.map +1 -1
  58. package/dist-server/engine/read-time.d.ts +22 -0
  59. package/dist-server/engine/read-time.js +81 -0
  60. package/dist-server/engine/read-time.js.map +1 -0
  61. package/dist-server/engine/restart-policy.js +1 -1
  62. package/dist-server/engine/restart-policy.js.map +1 -1
  63. package/dist-server/engine/runtime-key.js +1 -1
  64. package/dist-server/engine/runtime-key.js.map +1 -1
  65. package/dist-server/engine/spec-coverage.d.ts +2 -2
  66. package/dist-server/engine/spec-coverage.js +1 -1
  67. package/dist-server/engine/spec-coverage.js.map +1 -1
  68. package/dist-server/engine/stage-path.d.ts +4 -4
  69. package/dist-server/engine/stage-path.js +1 -1
  70. package/dist-server/engine/stage-path.js.map +1 -1
  71. package/dist-server/engine/state-axes.d.ts +1 -1
  72. package/dist-server/engine/state-axes.js +2 -2
  73. package/dist-server/engine/state-axes.js.map +1 -1
  74. package/dist-server/engine/travel-estimator.d.ts +2 -2
  75. package/dist-server/engine/travel-estimator.js +1 -1
  76. package/dist-server/engine/travel-estimator.js.map +1 -1
  77. package/dist-server/engine/twin-engine.d.ts +307 -54
  78. package/dist-server/engine/twin-engine.js +822 -196
  79. package/dist-server/engine/twin-engine.js.map +1 -1
  80. package/dist-server/engine/warm-start.d.ts +2 -2
  81. package/dist-server/engine/warm-start.js +5 -5
  82. package/dist-server/engine/warm-start.js.map +1 -1
  83. package/dist-server/index.js +1 -1
  84. package/dist-server/index.js.map +1 -1
  85. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js +1 -1
  86. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js.map +1 -1
  87. package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js +3 -3
  88. package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js.map +1 -1
  89. package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js +2 -2
  90. package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js.map +1 -1
  91. package/dist-server/migrations/1786300000000-IndexEventTypeByTime.d.ts +5 -0
  92. package/dist-server/migrations/1786300000000-IndexEventTypeByTime.js +54 -0
  93. package/dist-server/migrations/1786300000000-IndexEventTypeByTime.js.map +1 -0
  94. package/dist-server/migrations/1786400000000-IndexEventCreatedAt.d.ts +5 -0
  95. package/dist-server/migrations/1786400000000-IndexEventCreatedAt.js +44 -0
  96. package/dist-server/migrations/1786400000000-IndexEventCreatedAt.js.map +1 -0
  97. package/dist-server/migrations/1786500000000-CreateTwinSubjectEvents.d.ts +6 -0
  98. package/dist-server/migrations/1786500000000-CreateTwinSubjectEvents.js +84 -0
  99. package/dist-server/migrations/1786500000000-CreateTwinSubjectEvents.js.map +1 -0
  100. package/dist-server/migrations/index.js +7 -1
  101. package/dist-server/migrations/index.js.map +1 -1
  102. package/dist-server/routes.d.ts +1 -0
  103. package/dist-server/routes.js +69 -5
  104. package/dist-server/routes.js.map +1 -1
  105. package/dist-server/service/index.d.ts +2 -2
  106. package/dist-server/service/index.js +30 -24
  107. package/dist-server/service/index.js.map +1 -1
  108. package/dist-server/service/reference/control-routing.d.ts +1 -1
  109. package/dist-server/service/reference/control-routing.js +1 -1
  110. package/dist-server/service/reference/control-routing.js.map +1 -1
  111. package/dist-server/service/reference/discovery-result.d.ts +2 -2
  112. package/dist-server/service/reference/discovery-result.js +3 -3
  113. package/dist-server/service/reference/discovery-result.js.map +1 -1
  114. package/dist-server/service/reference/hook-contract.d.ts +43 -0
  115. package/dist-server/service/reference/hook-contract.js +59 -0
  116. package/dist-server/service/reference/hook-contract.js.map +1 -0
  117. package/dist-server/service/reference/ingest-space.d.ts +1 -1
  118. package/dist-server/service/reference/ingest-space.js +4 -4
  119. package/dist-server/service/reference/ingest-space.js.map +1 -1
  120. package/dist-server/service/reference/knob-defaults.d.ts +1 -1
  121. package/dist-server/service/reference/knob-defaults.js +4 -4
  122. package/dist-server/service/reference/knob-defaults.js.map +1 -1
  123. package/dist-server/service/reference/reference-adapter.d.ts +116 -9
  124. package/dist-server/service/reference/reference-adapter.js +27 -0
  125. package/dist-server/service/reference/reference-adapter.js.map +1 -1
  126. package/dist-server/service/reference/reference-hook.d.ts +20 -0
  127. package/dist-server/service/reference/reference-hook.js +133 -0
  128. package/dist-server/service/reference/reference-hook.js.map +1 -0
  129. package/dist-server/service/reference/reference-live.d.ts +2 -2
  130. package/dist-server/service/reference/reference-live.js +76 -13
  131. package/dist-server/service/reference/reference-live.js.map +1 -1
  132. package/dist-server/service/reference/reference-master.d.ts +25 -16
  133. package/dist-server/service/reference/reference-master.js +35 -13
  134. package/dist-server/service/reference/reference-master.js.map +1 -1
  135. package/dist-server/service/reference/reference-resolver.d.ts +1 -1
  136. package/dist-server/service/reference/reference-resolver.js +12 -12
  137. package/dist-server/service/reference/reference-resolver.js.map +1 -1
  138. package/dist-server/service/reference/template-registry.d.ts +1 -1
  139. package/dist-server/service/reference/template-registry.js.map +1 -1
  140. package/dist-server/service/reference/twin-reference.d.ts +3 -3
  141. package/dist-server/service/reference/twin-reference.js.map +1 -1
  142. package/dist-server/service/twin-attention/twin-attention-query.d.ts +1 -1
  143. package/dist-server/service/twin-attention/twin-attention-query.js +1 -1
  144. package/dist-server/service/twin-attention/twin-attention-query.js.map +1 -1
  145. package/dist-server/service/twin-audit/command-audit.d.ts +1 -1
  146. package/dist-server/service/twin-audit/command-audit.js.map +1 -1
  147. package/dist-server/service/twin-audit/twin-audit-event.d.ts +1 -1
  148. package/dist-server/service/twin-audit/twin-audit-event.js.map +1 -1
  149. package/dist-server/service/twin-audit/twin-audit-query.js +1 -1
  150. package/dist-server/service/twin-audit/twin-audit-query.js.map +1 -1
  151. package/dist-server/service/twin-backfill/backfill-period-facts.d.ts +24 -0
  152. package/dist-server/service/twin-backfill/backfill-period-facts.js +96 -0
  153. package/dist-server/service/twin-backfill/backfill-period-facts.js.map +1 -0
  154. package/dist-server/service/twin-backfill/backfill-shape.d.ts +34 -0
  155. package/dist-server/service/twin-backfill/backfill-shape.js +75 -0
  156. package/dist-server/service/twin-backfill/backfill-shape.js.map +1 -0
  157. package/dist-server/service/twin-backfill/index.d.ts +2 -0
  158. package/dist-server/service/twin-backfill/index.js +6 -0
  159. package/dist-server/service/twin-backfill/index.js.map +1 -0
  160. package/dist-server/service/twin-backfill/twin-backfill-resolver.d.ts +10 -0
  161. package/dist-server/service/twin-backfill/twin-backfill-resolver.js +44 -0
  162. package/dist-server/service/twin-backfill/twin-backfill-resolver.js.map +1 -0
  163. package/dist-server/service/twin-control/twin-control-mutation.js +3 -3
  164. package/dist-server/service/twin-control/twin-control-mutation.js.map +1 -1
  165. package/dist-server/service/twin-event/twin-event-keys.d.ts +1 -1
  166. package/dist-server/service/twin-event/twin-event-keys.js +2 -2
  167. package/dist-server/service/twin-event/twin-event-keys.js.map +1 -1
  168. package/dist-server/service/twin-event/twin-event-type.d.ts +1 -0
  169. package/dist-server/service/twin-event/twin-event-type.js +8 -1
  170. package/dist-server/service/twin-event/twin-event-type.js.map +1 -1
  171. package/dist-server/service/twin-event/twin-event.d.ts +2 -2
  172. package/dist-server/service/twin-event/twin-event.js +32 -4
  173. package/dist-server/service/twin-event/twin-event.js.map +1 -1
  174. package/dist-server/service/twin-forecast/forecast-metrics.js +1 -1
  175. package/dist-server/service/twin-forecast/forecast-metrics.js.map +1 -1
  176. package/dist-server/service/twin-forecast/gap-analytics.d.ts +1 -1
  177. package/dist-server/service/twin-forecast/gap-analytics.js.map +1 -1
  178. package/dist-server/service/twin-forecast/twin-forecast-query.js +29 -11
  179. package/dist-server/service/twin-forecast/twin-forecast-query.js.map +1 -1
  180. package/dist-server/service/twin-ingest-window/twin-ingest-window-query.d.ts +1 -1
  181. package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js +1 -1
  182. package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js.map +1 -1
  183. package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js +1 -1
  184. package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js.map +1 -1
  185. package/dist-server/service/twin-instance/twin-instance.js.map +1 -1
  186. package/dist-server/service/twin-journal/event-type-split-shape.d.ts +50 -0
  187. package/dist-server/service/twin-journal/event-type-split-shape.js +111 -0
  188. package/dist-server/service/twin-journal/event-type-split-shape.js.map +1 -0
  189. package/dist-server/service/twin-journal/event-type-split.d.ts +15 -0
  190. package/dist-server/service/twin-journal/event-type-split.js +102 -0
  191. package/dist-server/service/twin-journal/event-type-split.js.map +1 -0
  192. package/dist-server/service/twin-journal/journal-order.d.ts +15 -0
  193. package/dist-server/service/twin-journal/journal-order.js +17 -0
  194. package/dist-server/service/twin-journal/journal-order.js.map +1 -0
  195. package/dist-server/service/twin-journal/twin-journal-query.d.ts +5 -5
  196. package/dist-server/service/twin-journal/twin-journal-query.js +232 -21
  197. package/dist-server/service/twin-journal/twin-journal-query.js.map +1 -1
  198. package/dist-server/service/twin-lifecycle/domain-catalog.js +2 -1
  199. package/dist-server/service/twin-lifecycle/domain-catalog.js.map +1 -1
  200. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.d.ts +27 -1
  201. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js +59 -3
  202. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +1 -1
  203. package/dist-server/service/twin-metrics/twin-metrics-query.js +14 -1
  204. package/dist-server/service/twin-metrics/twin-metrics-query.js.map +1 -1
  205. package/dist-server/service/twin-model/axis-journal-evidence.js +1 -1
  206. package/dist-server/service/twin-model/axis-journal-evidence.js.map +1 -1
  207. package/dist-server/service/twin-model/epcis-coverage.js +34 -3
  208. package/dist-server/service/twin-model/epcis-coverage.js.map +1 -1
  209. package/dist-server/service/twin-model/iec61850-coverage.js +1 -1
  210. package/dist-server/service/twin-model/iec61850-coverage.js.map +1 -1
  211. package/dist-server/service/twin-model/isa95-coverage.d.ts +12 -9
  212. package/dist-server/service/twin-model/isa95-coverage.js +33 -9
  213. package/dist-server/service/twin-model/isa95-coverage.js.map +1 -1
  214. package/dist-server/service/twin-model/item-ref.js +2 -2
  215. package/dist-server/service/twin-model/item-ref.js.map +1 -1
  216. package/dist-server/service/twin-model/name-index.d.ts +1 -1
  217. package/dist-server/service/twin-model/name-index.js +2 -2
  218. package/dist-server/service/twin-model/name-index.js.map +1 -1
  219. package/dist-server/service/twin-model/project-structure.d.ts +1 -1
  220. package/dist-server/service/twin-model/project-structure.js +7 -6
  221. package/dist-server/service/twin-model/project-structure.js.map +1 -1
  222. package/dist-server/service/twin-model/twin-equipment.d.ts +2 -2
  223. package/dist-server/service/twin-model/twin-equipment.js +3 -3
  224. package/dist-server/service/twin-model/twin-equipment.js.map +1 -1
  225. package/dist-server/service/twin-model/twin-lineage-query.js +16 -5
  226. package/dist-server/service/twin-model/twin-lineage-query.js.map +1 -1
  227. package/dist-server/service/twin-model/twin-location.d.ts +1 -1
  228. package/dist-server/service/twin-model/twin-location.js.map +1 -1
  229. package/dist-server/service/twin-model/twin-model-item-query.d.ts +3 -3
  230. package/dist-server/service/twin-model/twin-model-item-query.js +15 -15
  231. package/dist-server/service/twin-model/twin-model-item-query.js.map +1 -1
  232. package/dist-server/service/twin-model/twin-model-mutation.d.ts +2 -2
  233. package/dist-server/service/twin-model/twin-model-mutation.js +4 -4
  234. package/dist-server/service/twin-model/twin-model-mutation.js.map +1 -1
  235. package/dist-server/service/twin-model/twin-model-query.js +51 -30
  236. package/dist-server/service/twin-model/twin-model-query.js.map +1 -1
  237. package/dist-server/service/twin-model/twin-model-tree-query.js +23 -1
  238. package/dist-server/service/twin-model/twin-model-tree-query.js.map +1 -1
  239. package/dist-server/service/twin-model/twin-operation.d.ts +1 -1
  240. package/dist-server/service/twin-model/twin-operation.js +1 -1
  241. package/dist-server/service/twin-model/twin-operation.js.map +1 -1
  242. package/dist-server/service/twin-space/move-space.js +2 -2
  243. package/dist-server/service/twin-space/move-space.js.map +1 -1
  244. package/dist-server/service/twin-space/representation-role.d.ts +2 -0
  245. package/dist-server/service/twin-space/representation-role.js +18 -0
  246. package/dist-server/service/twin-space/representation-role.js.map +1 -0
  247. package/dist-server/service/twin-space/space-integrity.d.ts +1 -1
  248. package/dist-server/service/twin-space/space-integrity.js.map +1 -1
  249. package/dist-server/service/twin-space/twin-space-representation.d.ts +2 -0
  250. package/dist-server/service/twin-space/twin-space-representation.js +16 -0
  251. package/dist-server/service/twin-space/twin-space-representation.js.map +1 -1
  252. package/dist-server/service/twin-space/twin-space-resolver.d.ts +2 -2
  253. package/dist-server/service/twin-space/twin-space-resolver.js +37 -8
  254. package/dist-server/service/twin-space/twin-space-resolver.js.map +1 -1
  255. package/dist-server/service/twin-structure/twin-structure.js +3 -3
  256. package/dist-server/service/twin-structure/twin-structure.js.map +1 -1
  257. package/dist-server/service/twin-subject/event-subjects.d.ts +43 -0
  258. package/dist-server/service/twin-subject/event-subjects.js +137 -0
  259. package/dist-server/service/twin-subject/event-subjects.js.map +1 -0
  260. package/dist-server/service/twin-subject/index.d.ts +9 -0
  261. package/dist-server/service/twin-subject/index.js +16 -0
  262. package/dist-server/service/twin-subject/index.js.map +1 -0
  263. package/dist-server/service/twin-subject/item-resolver.d.ts +10 -0
  264. package/dist-server/service/twin-subject/item-resolver.js +93 -0
  265. package/dist-server/service/twin-subject/item-resolver.js.map +1 -0
  266. package/dist-server/service/twin-subject/subject-query-shape.d.ts +22 -0
  267. package/dist-server/service/twin-subject/subject-query-shape.js +88 -0
  268. package/dist-server/service/twin-subject/subject-query-shape.js.map +1 -0
  269. package/dist-server/service/twin-subject/twin-subject-backfill.d.ts +23 -0
  270. package/dist-server/service/twin-subject/twin-subject-backfill.js +159 -0
  271. package/dist-server/service/twin-subject/twin-subject-backfill.js.map +1 -0
  272. package/dist-server/service/twin-subject/twin-subject-event.d.ts +14 -0
  273. package/dist-server/service/twin-subject/twin-subject-event.js +111 -0
  274. package/dist-server/service/twin-subject/twin-subject-event.js.map +1 -0
  275. package/dist-server/service/twin-subject/twin-subject-fast-path.d.ts +39 -0
  276. package/dist-server/service/twin-subject/twin-subject-fast-path.js +295 -0
  277. package/dist-server/service/twin-subject/twin-subject-fast-path.js.map +1 -0
  278. package/dist-server/service/twin-subject/twin-subject-query.d.ts +27 -0
  279. package/dist-server/service/twin-subject/twin-subject-query.js +232 -0
  280. package/dist-server/service/twin-subject/twin-subject-query.js.map +1 -0
  281. package/dist-server/service/twin-subject/twin-subject-writer.d.ts +27 -0
  282. package/dist-server/service/twin-subject/twin-subject-writer.js +166 -0
  283. package/dist-server/service/twin-subject/twin-subject-writer.js.map +1 -0
  284. package/dist-server/service/twin-target/twin-target-resolver.js +1 -1
  285. package/dist-server/service/twin-target/twin-target-resolver.js.map +1 -1
  286. package/dist-shared/entity-delta.d.ts +1 -1
  287. package/dist-shared/entity-delta.js +4 -4
  288. package/dist-shared/entity-delta.js.map +1 -1
  289. package/dist-shared/touched-items.js +2 -2
  290. package/dist-shared/touched-items.js.map +1 -1
  291. package/dist-shared/twin-level.js +1 -1
  292. package/dist-shared/twin-level.js.map +1 -1
  293. package/package.json +7 -6
  294. package/server/engine/attention-digest.ts +9 -9
  295. package/server/engine/canonical-ingest.ts +202 -87
  296. package/server/engine/command-routing.ts +1 -1
  297. package/server/engine/declared-stimulus.ts +1 -1
  298. package/server/engine/energy-topology.ts +2 -2
  299. package/server/engine/ingest-dedupe.ts +149 -0
  300. package/server/engine/ingest-health.ts +171 -22
  301. package/server/engine/integration-probes.ts +7 -7
  302. package/server/engine/kpi-baseline.ts +4 -4
  303. package/server/engine/kpi-fold.ts +592 -41
  304. package/server/engine/kpi-query.ts +307 -48
  305. package/server/engine/live-feed-registry.ts +1 -1
  306. package/server/engine/load-meter.ts +1 -1
  307. package/server/engine/local-declarations.ts +15 -14
  308. package/server/engine/log.ts +1 -1
  309. package/server/engine/measured-estimator.ts +1 -1
  310. package/server/engine/measured-yield.ts +1 -1
  311. package/server/engine/model-basis.ts +2 -2
  312. package/server/engine/model-gap.ts +3 -3
  313. package/server/engine/model-vocabulary.ts +2 -2
  314. package/server/engine/oee-accumulator.ts +8 -6
  315. package/server/engine/property-effects.ts +2 -2
  316. package/server/engine/read-time.ts +77 -0
  317. package/server/engine/restart-policy.ts +1 -1
  318. package/server/engine/runtime-key.ts +1 -1
  319. package/server/engine/spec-coverage.ts +3 -3
  320. package/server/engine/stage-path.ts +5 -5
  321. package/server/engine/state-axes.ts +2 -2
  322. package/server/engine/travel-estimator.ts +2 -2
  323. package/server/engine/twin-engine.ts +906 -205
  324. package/server/engine/warm-start.ts +6 -6
  325. package/server/index.ts +1 -1
  326. package/server/migrations/1786000000000-RenameTwinInstanceBoardToModel.ts +1 -1
  327. package/server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.ts +3 -3
  328. package/server/migrations/1786200000000-CarryLiveFeedCursor.ts +2 -2
  329. package/server/migrations/1786300000000-IndexEventTypeByTime.ts +48 -0
  330. package/server/migrations/1786400000000-IndexEventCreatedAt.ts +38 -0
  331. package/server/migrations/1786500000000-CreateTwinSubjectEvents.ts +93 -0
  332. package/server/migrations/index.ts +7 -1
  333. package/server/routes.ts +73 -5
  334. package/server/service/index.ts +7 -1
  335. package/server/service/reference/control-routing.ts +1 -1
  336. package/server/service/reference/discovery-result.ts +3 -3
  337. package/server/service/reference/hook-contract.ts +103 -0
  338. package/server/service/reference/ingest-space.ts +4 -4
  339. package/server/service/reference/knob-defaults.ts +4 -4
  340. package/server/service/reference/reference-adapter.ts +145 -10
  341. package/server/service/reference/reference-hook.ts +145 -0
  342. package/server/service/reference/reference-live.ts +87 -15
  343. package/server/service/reference/reference-master.ts +51 -20
  344. package/server/service/reference/reference-resolver.ts +11 -11
  345. package/server/service/reference/template-registry.ts +1 -1
  346. package/server/service/reference/twin-reference.ts +3 -3
  347. package/server/service/twin-attention/twin-attention-query.ts +1 -1
  348. package/server/service/twin-audit/command-audit.ts +1 -1
  349. package/server/service/twin-audit/twin-audit-event.ts +2 -2
  350. package/server/service/twin-audit/twin-audit-query.ts +1 -1
  351. package/server/service/twin-backfill/backfill-period-facts.ts +168 -0
  352. package/server/service/twin-backfill/backfill-shape.ts +86 -0
  353. package/server/service/twin-backfill/index.ts +3 -0
  354. package/server/service/twin-backfill/twin-backfill-resolver.ts +35 -0
  355. package/server/service/twin-control/twin-control-mutation.ts +2 -2
  356. package/server/service/twin-event/twin-event-keys.ts +2 -2
  357. package/server/service/twin-event/twin-event-type.ts +18 -1
  358. package/server/service/twin-event/twin-event.ts +32 -6
  359. package/server/service/twin-forecast/forecast-metrics.ts +1 -1
  360. package/server/service/twin-forecast/gap-analytics.ts +1 -1
  361. package/server/service/twin-forecast/twin-forecast-query.ts +30 -11
  362. package/server/service/twin-ingest-window/twin-ingest-window-query.ts +1 -1
  363. package/server/service/twin-ingest-window/twin-ingest-window-writer.ts +1 -1
  364. package/server/service/twin-instance/twin-instance.ts +4 -4
  365. package/server/service/twin-journal/event-type-split-shape.ts +112 -0
  366. package/server/service/twin-journal/event-type-split.ts +144 -0
  367. package/server/service/twin-journal/journal-order.ts +20 -0
  368. package/server/service/twin-journal/twin-journal-query.ts +224 -20
  369. package/server/service/twin-lifecycle/domain-catalog.ts +2 -1
  370. package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +58 -4
  371. package/server/service/twin-metrics/twin-metrics-query.ts +14 -1
  372. package/server/service/twin-model/axis-journal-evidence.ts +1 -1
  373. package/server/service/twin-model/epcis-coverage.ts +34 -3
  374. package/server/service/twin-model/iec61850-coverage.ts +1 -1
  375. package/server/service/twin-model/isa95-coverage.ts +43 -16
  376. package/server/service/twin-model/item-ref.ts +2 -2
  377. package/server/service/twin-model/name-index.ts +2 -2
  378. package/server/service/twin-model/project-structure.ts +7 -6
  379. package/server/service/twin-model/twin-equipment.ts +16 -4
  380. package/server/service/twin-model/twin-lineage-query.ts +16 -5
  381. package/server/service/twin-model/twin-location.ts +1 -1
  382. package/server/service/twin-model/twin-model-item-query.ts +15 -15
  383. package/server/service/twin-model/twin-model-mutation.ts +4 -4
  384. package/server/service/twin-model/twin-model-query.ts +49 -28
  385. package/server/service/twin-model/twin-model-tree-query.ts +26 -2
  386. package/server/service/twin-model/twin-operation.ts +2 -2
  387. package/server/service/twin-space/move-space.ts +3 -3
  388. package/server/service/twin-space/representation-role.ts +15 -0
  389. package/server/service/twin-space/space-integrity.ts +1 -1
  390. package/server/service/twin-space/twin-space-representation.ts +37 -0
  391. package/server/service/twin-space/twin-space-resolver.ts +40 -8
  392. package/server/service/twin-structure/twin-structure.ts +3 -3
  393. package/server/service/twin-subject/event-subjects.ts +155 -0
  394. package/server/service/twin-subject/index.ts +10 -0
  395. package/server/service/twin-subject/item-resolver.ts +92 -0
  396. package/server/service/twin-subject/subject-query-shape.ts +84 -0
  397. package/server/service/twin-subject/twin-subject-backfill.ts +196 -0
  398. package/server/service/twin-subject/twin-subject-event.ts +101 -0
  399. package/server/service/twin-subject/twin-subject-fast-path.ts +346 -0
  400. package/server/service/twin-subject/twin-subject-query.ts +210 -0
  401. package/server/service/twin-subject/twin-subject-writer.ts +189 -0
  402. package/server/service/twin-target/twin-target-resolver.ts +1 -1
  403. package/shared/entity-delta.ts +4 -4
  404. package/shared/touched-items.ts +2 -2
  405. package/shared/twin-level.ts +1 -1
  406. package/test/adopt-structure-live.test.ts +3 -3
  407. package/test/aggregate-not-findone.test.ts +112 -0
  408. package/test/attention-digest.test.ts +6 -6
  409. package/test/axis-read.test.ts +6 -5
  410. package/test/backfill-shape.test.ts +89 -0
  411. package/test/boot-resume.test.ts +20 -7
  412. package/test/broadcast-cost-baseline.test.ts +2 -1
  413. package/test/broadcast-period.test.ts +2 -2
  414. package/test/broadcast-queue-overflow.test.ts +244 -0
  415. package/test/canonical-ingest-vocabularies.test.ts +259 -8
  416. package/test/canonical-quantity-door.test.ts +2 -2
  417. package/test/capability-mapping.test.ts +1 -1
  418. package/test/checkpoint-refuses-empty.test.ts +2 -2
  419. package/test/connector-capability-declaration.test.ts +88 -0
  420. package/test/contract-layer-guard.test.ts +48 -0
  421. package/test/control-capability.test.ts +1 -1
  422. package/test/cursor-stall-not-read-failure.test.ts +2 -2
  423. package/test/declaration-reaches-model.test.ts +7 -5
  424. package/test/declared-stimulus.test.ts +4 -4
  425. package/test/discovery-result.test.ts +2 -2
  426. package/test/entity-delta.test.ts +4 -4
  427. package/test/equipment-identity-reaches.test.ts +57 -0
  428. package/test/event-subjects.test.ts +147 -0
  429. package/test/event-time-column.test.ts +3 -3
  430. package/test/event-type-split.test.ts +155 -0
  431. package/test/fact-scope-wiring.test.ts +96 -0
  432. package/test/fold-gap-speaks.test.ts +53 -0
  433. package/test/forecast-metrics.test.ts +1 -1
  434. package/test/forecast-tuning.test.ts +1 -1
  435. package/test/generated-not-counted.test.ts +99 -0
  436. package/test/ingest-bench.test.ts +2 -1
  437. package/test/ingest-health-engine.test.ts +2 -2
  438. package/test/ingest-health-wiring.test.ts +7 -5
  439. package/test/ingest-health.test.ts +6 -6
  440. package/test/ingest-history.test.ts +2 -2
  441. package/test/ingest-idempotent.test.ts +132 -0
  442. package/test/ingest-space.test.ts +3 -3
  443. package/test/ingest-wiring-guard.test.ts +197 -0
  444. package/test/integration-probes.test.ts +3 -3
  445. package/test/integration-runner.test.ts +1 -1
  446. package/test/item-ref.test.ts +1 -1
  447. package/test/journal-order-axis.test.ts +80 -0
  448. package/test/journal-read-discipline.test.ts +16 -6
  449. package/test/journal-retention.test.ts +171 -29
  450. package/test/journal-sort-axis.test.ts +1 -1
  451. package/test/journal-write-door.test.ts +3 -3
  452. package/test/journal-write-trend.test.ts +1 -1
  453. package/test/kernel-kind-guard.test.ts +3 -3
  454. package/test/knob-defaults.test.ts +1 -1
  455. package/test/kpi-baseline-db.test.ts +2 -2
  456. package/test/kpi-fold.test.ts +266 -14
  457. package/test/kpi-query-bench.test.ts +3 -3
  458. package/test/live-cursor-wiring.test.ts +6 -6
  459. package/test/live-kernel-facts.test.ts +11 -11
  460. package/test/live-mirror-parity.test.ts +9 -6
  461. package/test/load-meter.test.ts +1 -1
  462. package/test/local-declarations.test.ts +13 -12
  463. package/test/log-stamp.test.ts +1 -1
  464. package/test/master-to-twin.test.ts +2 -2
  465. package/test/measured-yield.test.ts +2 -2
  466. package/test/merge-streams.test.ts +70 -0
  467. package/test/mirror-resumes-from-checkpoint.test.ts +13 -13
  468. package/test/model-basis.test.ts +2 -2
  469. package/test/model-gap.test.ts +4 -4
  470. package/test/model-vocabulary.test.ts +2 -2
  471. package/test/move-space.test.ts +1 -1
  472. package/test/oee-accumulator.test.ts +20 -5
  473. package/test/operational-vocabulary.test.ts +2 -2
  474. package/test/project-structure-db.test.ts +2 -2
  475. package/test/projection-reaches-screen.test.ts +7 -2
  476. package/test/projection-reads-declared.test.ts +109 -0
  477. package/test/property-effects.test.ts +10 -6
  478. package/test/read-failure-ledger.test.ts +106 -0
  479. package/test/read-failure-visible.test.ts +7 -7
  480. package/test/read-time.test.ts +118 -0
  481. package/test/reference-grounding.test.ts +1 -1
  482. package/test/reference-hook.test.ts +86 -0
  483. package/test/registry-key-guard.test.ts +1 -1
  484. package/test/rename-twin.test.ts +81 -0
  485. package/test/restart-policy.test.ts +3 -3
  486. package/test/resync-origin-site.test.ts +3 -3
  487. package/test/revision-axis.test.ts +14 -8
  488. package/test/runtime-key.test.ts +3 -3
  489. package/test/scale-twin-bench.test.ts +2 -1
  490. package/test/snapshot-freshness.test.ts +4 -4
  491. package/test/source-outcome-audit.test.ts +1 -1
  492. package/test/space-integrity.test.ts +1 -1
  493. package/test/space-representation.test.ts +66 -0
  494. package/test/space-scope-includes-stopped.test.ts +55 -0
  495. package/test/spec-coverage.test.ts +1 -1
  496. package/test/standard-coverage.test.ts +19 -21
  497. package/test/status-tally.test.ts +1 -1
  498. package/test/structure-revision-db.test.ts +7 -7
  499. package/test/subject-fast-path.test.ts +148 -0
  500. package/test/subject-read-model.test.ts +175 -0
  501. package/test/touched-items.test.ts +2 -2
  502. package/test/twin-audit.test.ts +1 -1
  503. package/test/twin-event-keys.test.ts +1 -1
  504. package/test/twin-model-item-db.test.ts +5 -5
  505. package/test/twin-model-tree-db.test.ts +35 -2
  506. package/test/twin-origin-resync.test.ts +1 -1
  507. package/test/vocabulary-guard.test.ts +1 -1
  508. package/test/warm-start-seam.test.ts +1 -1
  509. package/test/warm-start.test.ts +6 -6
  510. package/test/withheld-door.test.ts +2 -2
  511. package/test/yield-loop.test.ts +4 -4
  512. package/tsconfig.shared.tsbuildinfo +1 -1
  513. package/tsconfig.tsbuildinfo +1 -1
@@ -1,4 +1,5 @@
1
1
  import type { ReducerCheckpoint } from '@operato/twin-kernel';
2
+ import type { VocabularyElement } from '@operato/ops-contract';
2
3
  import type { OeeCheckpoint } from './oee-accumulator.js';
3
4
  import { type ReferenceMaster } from '../service/reference/reference-master.js';
4
5
  import { type IngestWarning } from '../service/reference/reference-master.js';
@@ -8,7 +9,9 @@ import { type LoadMeter, type LoadPhase } from './load-meter.js';
8
9
  import { type StructureDiff } from './structure-diff.js';
9
10
  import { OeeAccumulator } from './oee-accumulator.js';
10
11
  import { type IngestHealthView, type IngestWindow } from './ingest-health.js';
11
- import type { TwinModelDef, StructureShift, TwinRuntime as TwinRuntimeType, CanonicalEnvelope } from '@operato/twin-kernel';
12
+ import { FactDeduper } from './ingest-dedupe.js';
13
+ import type { TwinRuntime as TwinRuntimeType } from '@operato/twin-kernel';
14
+ import type { TwinModelDef, StructureShift, CanonicalEnvelope } from '@operato/ops-contract';
12
15
  interface TwinMetrics {
13
16
  ingestedTotal: number;
14
17
  broadcastTotal: number;
@@ -48,12 +51,26 @@ interface InstanceRuntime {
48
51
  mode?: 'sim' | 'live';
49
52
  /** 이 트윈이 선 현장 — 같은 현장의 트윈끼리 서로의 설비 상태를 읽을 수 있게 하는 열쇠. */
50
53
  spaceId?: string;
54
+ /**
55
+ * 이 트윈의 모델 — **대상별 사건 목록에 품목 줄을 적을 때** 쓴다 (2026-08-27).
56
+ *
57
+ * 개체 식별자에서 선언된 품목을 찾는 판정이 그 트윈의 선언을 본다(§`item-resolver`). 사건마다
58
+ * 등록부를 읽으면 쓰기마다 DB 조회가 하나 늘어나므로, 세울 때 받은 모델을 들고 있는다.
59
+ */
60
+ model?: TwinModelDef;
51
61
  /**
52
62
  * live 의 상태 접근 어댑터 — 이제 **관측 모드 커널**을 가리킨다(`kernel` 과 같은 것).
53
63
  * 이름은 소비처 호환으로 남았고, P3 에서 커널 어휘로 정리하면 사라진다.
54
64
  */
55
65
  projector?: any;
56
66
  oee?: OeeAccumulator;
67
+ /**
68
+ * 같은 사실이 두 번 오는 것을 거르는 자리(§`FactDeduper`).
69
+ *
70
+ * 트윈마다 하나다 — 정체는 트윈 안에서만 뜻이 있고, 트윈 하나가 되풀이 받는 것을 거르는 것이 목적이다.
71
+ * 프로세스가 새로 뜨면 비어 있다(그 사실은 `FactDeduper` 주석에 적어 두었다).
72
+ */
73
+ deduper?: FactDeduper;
57
74
  unsub: () => void;
58
75
  /**
59
76
  * 방금 인입한 봉투들 — 커널이 그것을 재방출할 때 **저널에 두 번 적지 않기** 위한 표시.
@@ -72,6 +89,8 @@ interface InstanceRuntime {
72
89
  * 하나도 건드리지 않았다」이고, 그 둘은 다른 사실이다.
73
90
  */
74
91
  dirtyItems?: Set<string>;
92
+ /** 기동 이후 이 트윈이 발행한 건수 — 무엇이 대기열을 채우는지 값으로 말한다. */
93
+ publishedTotal?: number;
75
94
  /** 다음 브로드캐스팅에서 전부 만들어야 하나 — 주기마다 한 번은 그물로 전부 만든다. */
76
95
  fullBroadcastDue?: boolean;
77
96
  /** 전부 만들기까지 남은 창 수. */
@@ -106,7 +125,7 @@ export declare class TwinEngine {
106
125
  /**
107
126
  * 흩어진 첫 발화 뒤 주기 틱. **핸들은 항상 진짜 타이머**다 — 정지하는 쪽이 `clearInterval(inst.timer)`
108
127
  * 하나로 끝내야 하므로, 첫 발화 전에는 그 `setTimeout` 을, 이후에는 `setInterval` 을 같은 자리에 둔다
109
- * (감싼 객체를 주면 `clearInterval` 이 아무 일도 하지 않고 트윈이 멈추지 않는다 — 조용한 결함이 된다).
128
+ * (감싼 객체를 주면 `clearInterval` 이 아무 일도 하지 않고 트윈이 멈추지 않는다 — 들어온 것이 없는 결함이 된다).
110
129
  */
111
130
  private static startTickTimer;
112
131
  /** 굶김 문턱 — 틱 간격의 배수(1초 간격이면 5초). 이 시간만큼 호스트가 멈춘다. */
@@ -125,6 +144,13 @@ export declare class TwinEngine {
125
144
  static CHAIN_STRIDE: number;
126
145
  static CHAIN_KEEP: number;
127
146
  static SNAPSHOT_TTL_S: number;
147
+ /**
148
+ * 멈춘 트윈의 마지막 상태를 두는 기간 — 사실상 만료 없음 (2026-08-27).
149
+ *
150
+ * 캐시 계층에 「만료 없음」을 뜻하는 값이 없어서 큰 수를 쓴다(`ICacheService` 는 초 단위 TTL 하나만
151
+ * 받는다). 100년이면 이 시스템의 수명보다 길다.
152
+ */
153
+ static SNAPSHOT_KEEP_S: number;
128
154
  static CHECKPOINT_MS: number;
129
155
  /**
130
156
  * **저널 보존 — 지우는 것은 선언이 있을 때만 한다.**
@@ -137,16 +163,16 @@ export declare class TwinEngine {
137
163
  * ── 그런데 저널을 지우는 것은 사실을 잃는 일이다 ──────────────────────────
138
164
  * 그래서 세 규율을 지킨다.
139
165
  *
140
- * ① **선언이 없으면 아무것도 지우지 않는다.** 기본값은 없음이다 — 조용히 지우는 편이 조용히 쌓는
166
+ * ① **선언이 없으면 아무것도 지우지 않는다.** 기본값은 없음이다 — 알리지 않고 지우는 편이 알리지 않고 쌓는
141
167
  * 것보다 나쁘다. 지우는 것은 사람이 정한다.
142
168
  * ② **체크포인트가 대신할 수 있는 만큼만.** 스냅샷이 없거나 그 리비전을 넘는 자리는 건드리지 않는다.
143
169
  * 주석이 「만료 시 저널 replay 폴백」이라고 적어 둔 그대로 — 스냅샷이 사라지면 저널이 **유일한**
144
170
  * 복구 수단이므로, 둘을 함께 잃으면 그 트윈의 상태는 되돌릴 수 없다.
145
- * ③ **지운 것을 말한다.** 몇 건을 어느 시각까지 지웠는지 로그에 남긴다. 조용히 줄어든 저널은
171
+ * ③ **지운 것을 말한다.** 몇 건을 어느 시각까지 지웠는지 로그에 남긴다. 알리지 않고 줄어든 저널은
146
172
  * 「없었던 일」과 구별되지 않는다.
147
173
  *
148
174
  * 그리고 보존 기간은 **스냅샷 TTL(7일)보다 짧을 수 없다.** 더 짧으면 스냅샷이 살아 있는데 그것이
149
- * 가리키는 앞쪽 저널이 없는 구간이 생기고, 시간여행·계보 추적이 그 구간에서 조용히 빈다.
175
+ * 가리키는 앞쪽 저널이 없는 구간이 생기고, 시간여행·계보 추적이 그 구간에서 알리지 않고 빈다.
150
176
  */
151
177
  static JOURNAL_RETENTION_DAYS?: number;
152
178
  /**
@@ -166,34 +192,45 @@ export declare class TwinEngine {
166
192
  private static retentionTimer?;
167
193
  private static checkpointTimer?;
168
194
  /** 최신 스냅샷을 cache-service 에 체크포인트(도메인+instanceId 키). display-only·비차단·오류흡수. */
169
- static persistSnapshot(domainId: string, instanceId: string): Promise<void>;
195
+ static persistSnapshot(domainId: string, instanceId: string,
196
+ /**
197
+ * 만료를 두지 않는다 — **트윈을 멈출 때만** 참이다 (2026-08-27).
198
+ *
199
+ * 도는 트윈은 주기적으로 다시 쓰므로 7일 만료가 걸리지 않는다. 멈춘 트윈은 아무도 쓰지 않아서
200
+ * 7일 뒤 만료되고, 그러면 그 트윈의 마지막 상태를 아는 것이 아무것도 없다. 멈추는 순간이 그
201
+ * 상태가 메모리에 있는 마지막 순간이므로 그때 만료 없이 적는다.
202
+ *
203
+ * 만료된 뒤에도 그 트윈은 보관된 구간에서 다시 세워진다(보관 기간만큼이므로 유한하다). 다만 그
204
+ * 구간 앞의 상태는 알 수 없다. 멈추는 순간에 적어 두면 그 손실이 없다.
205
+ */
206
+ keepForever?: boolean): Promise<void>;
170
207
  /**
171
- * 접기의 **재개점** — 리듀서 내부 상태 전부 + 가동 누적기.
208
+ * 계산의 **재개점** — 리듀서 내부 상태 전부 + 가동 누적기.
172
209
  *
173
- * 스냅샷(`state`)은 소비처가 보는 값이라 이어 접기의 씨앗이 되지 못한다(보류된 담김·집합·반영 못 한
174
- * 사건 집계가 없다 — 그 상태로 뒤를 접으면 0부터 접은 결과와 조용히 달라진다). 그래서 씨앗은 따로 든다.
210
+ * 스냅샷(`state`)은 소비처가 보는 값이라 이어 계산의 씨앗이 되지 못한다(보류된 담김·집합·반영 못 한
211
+ * 사건 집계가 없다 — 그 상태로 뒤를 계산하면 0부터 계산한 결과와 오류 없이 달라진다). 그래서 씨앗은 따로 든다.
175
212
  */
176
213
  private static readonly FOLD_NOTE;
177
214
  /**
178
- * 재기동에 쓸 **웜스타트 씨앗**을 만든다 — 상태 + 이어 접을 재개점.
215
+ * 재기동에 쓸 **웜스타트 씨앗**을 만든다 — 상태 + 이어 계산할 재개점.
179
216
  *
180
217
  * ── 왜 이 자리가 생겼나 (2026-08-24) ──────────────────────────────────────
181
218
  * 두 호출부가 같은 일을 조금씩 다르게 하고 있었고(겹포장을 한쪽만 벗겼다), 둘 다 **재개점을 버리고**
182
219
  * 상태만 들고 갔다. 그래서 저장된 재개점을 읽는 쪽이 다 있는데도 재기동은 매번 저널을 처음부터
183
- * 접었다(실측: 저널 2,960만 줄).
220
+ * 계산했다(실측: 저널 2,960만 줄).
184
221
  *
185
222
  * 여기서 하는 일 셋:
186
223
  * ① 겹포장을 벗긴다 — 옛 형식으로 저장된 값이 한 번은 반드시 나온다
187
224
  * ② **그 공장이 아직 그 공장인지** 심판한다 — 아니면 씨앗을 버린다(아래)
188
- * ③ 씨앗이 저널 끝보다 앞서 있으면 **그 꼬리만 접어** 끝까지 밀어 둔다
225
+ * ③ 씨앗이 저널 끝보다 앞서 있으면 **그 꼬리만 계산해** 끝까지 밀어 둔다
189
226
  *
190
227
  * ②가 필요한 이유: 재개점은 그때의 보드 위에서 만들어진 것이다. 그 뒤 구조가 바뀌었다면(자리가
191
228
  * 빠졌다·설비가 옮겨졌다) 되세운 리듀서는 **지금 없는 자리와 설비를 든다** — 없는 냉장실이 화면에
192
229
  * 나오고 그 자리의 판정이 계속 돌아간다. 오류 없이 틀리므로 눈에 띄지 않는다.
193
230
  *
194
231
  * ③이 필요한 이유: 스냅샷은 체크포인트 주기로 쓰이므로 마지막 주기 이후의 사실은 저널에만 있다.
195
- * 그것을 빼고 되세우면 그만큼이 조용히 사라진다 — 「모름」을 「없음」으로 적는 것과 같은 부류다.
196
- * 접는 구간은 **그 틈뿐**이고(저널 전체가 아니다), `recover` 가 그 자리에서 새 재개점을 남겨 준다.
232
+ * 그것을 빼고 되세우면 그만큼이 오류 없이 사라진다 — 「모름」을 「없음」으로 적는 것과 같은 부류다.
233
+ * 계산하는 구간은 **그 틈뿐**이고(저널 전체가 아니다), `recover` 가 그 자리에서 새 재개점을 남겨 준다.
197
234
  */
198
235
  private static warmSeedFor;
199
236
  /** 체크포인트된 최신 스냅샷 로드(없으면 null). getFromCache 는 CacheStore 엔티티를 반환 → 페이로드는 .value. */
@@ -207,10 +244,10 @@ export declare class TwinEngine {
207
244
  };
208
245
  } | null>;
209
246
  /**
210
- * 접은 상태를 스냅샷으로 남긴다 — **라이브가 아니어도.**
247
+ * 계산한 상태를 스냅샷으로 남긴다 — **라이브가 아니어도.**
211
248
  *
212
249
  * `persistSnapshot` 은 기동 중인 인스턴스에서만 뜬다(메모리가 진실이므로 옳다). 그런데 **멈춘**
213
- * 트윈을 조회할 때마다 저널을 전량 다시 접고 있었다(23,731건짜리 트윈에서 4.6초). 그 폴드의 결과를
250
+ * 트윈을 조회할 때마다 저널을 전량 다시 계산하고 있었다(23,731건짜리 트윈에서 4.6초). 그 폴드의 결과를
214
251
  * 남겨 두면 **처음 한 번만 느리다.**
215
252
  *
216
253
  * `structureRev` 를 함께 적는다: 이벤트가 하나도 안 늘어도 구조를 갈아치우면(재프로비저닝) 그
@@ -228,11 +265,11 @@ export declare class TwinEngine {
228
265
  /** 사슬 색인 — 어떤 리비전 지점을 들고 있나(최신순 아님, 오름차순). */
229
266
  private static chainIndex;
230
267
  /**
231
- * 목표 이전의 **가장 가까운 지점**을 고른다 — 없으면 `null`(0부터 접는다).
268
+ * 목표 이전의 **가장 가까운 지점**을 고른다 — 없으면 `null`(0부터 계산한다).
232
269
  *
233
270
  * 시각으로 물었으면 그 지점의 마지막 사실 시각이 목표 이내여야 한다(리비전만 보면 목표보다 뒤의
234
271
  * 사실이 씨앗에 섞인다). 구조가 바뀐 트윈에서는 쓰지 않는다 — 마디를 건너뛴 씨앗은 그 경계의
235
- * 판정을 잃는다(그 경우는 0부터 접는 것이 옳다).
272
+ * 판정을 잃는다(그 경우는 0부터 계산하는 것이 옳다).
236
273
  */
237
274
  private static chainSeedFor;
238
275
  /** 눈금을 넘었으면 한 지점을 남긴다 — 오래된 것은 버린다(색인도 함께 줄인다). */
@@ -240,12 +277,13 @@ export declare class TwinEngine {
240
277
  /** 이 트윈 저널의 끝 리비전 · 최신 구조 리비전 — 스냅샷이 지금의 사실인지 가리는 두 값. */
241
278
  private static tipOf;
242
279
  /**
243
- * **저널을 보존 기간까지만 둔다** — 체크포인트가 대신할 수 있는 만큼만 지운다.
280
+ * **저널을 보존 기간까지만 둔다.**
244
281
  *
245
- * 한 인스턴스에서 지우는 조건은 **둘 다** 만족해야 한다.
282
+ * 지우는 조건은 하나다 — `createdAt` 이 보존 기간보다 오래됐다(**행이 쓰인 실제 시각**이 기준이다).
246
283
  *
247
- * · `createdAt` 이 보존 기간보다 오래됐다 — **행이 쓰인 실제 시각**이 기준이다
248
- * · `revision` 이 **체크포인트 리비전 이하**다 — 그 앞은 스냅샷이 대신한다
284
+ * **도는 트윈**에서만 조건이 하나 더 붙는다: `revision` 이 체크포인트 리비전 이하여야 한다. 도는
285
+ * 트윈은 메모리에서 이어 집계하므로, 체크포인트가 아직 반영하지 못한 사건을 지우면 그 구간이
286
+ * 어디에도 없어진다. 멈춘 트윈에는 이어 집계할 메모리가 없어서 이 조건이 없다.
249
287
  *
250
288
  * ── 왜 `eventTime` 이 아니라 `createdAt` 인가 (2026-08-22 실측으로 고침) ────
251
289
  * 처음에 `eventTime` 으로 적었다. 그것은 **트윈의 시계**다 — 시뮬레이션은 자기 시계로 사건을 찍고,
@@ -260,9 +298,17 @@ export declare class TwinEngine {
260
298
  * `createdAt` 은 그 행이 DB 에 쓰인 시각이고 1,599만 행 전부 채워져 있다(확인함). 도메인 시각을
261
299
  * 정책에 쓰지 않는다 — 그 둘을 섞으면 시뮬과 미러에서 같은 설정이 다르게 동작한다.
262
300
  *
263
- * 스냅샷이 없으면 **그 인스턴스는 건드리지 않는다.** 저널이 유일한 복구 수단인 상태이므로, 지우면
264
- * 그 트윈의 상태를 되돌릴 수 없다. 「지울 수 없었다」는 사실도 함께 센다 — 조용히 넘기면 「보존이
265
- * 도는데 왜 안 줄어드나」가 된다.
301
+ * ── 왜 체크포인트를 전제 조건으로 두지 않나 (2026-08-27) ───────────────────
302
+ * 예전에는 체크포인트가 없으면 그 트윈을 건드리지 않았다. 「저널이 유일한 복구 수단」이라는 전제
303
+ * 때문이었고, 그 전제가 틀렸다. 트윈이 자기 저널과 어떤 관계인지는 `restartPolicy` 가 선언한다 —
304
+ * `resync` 는 연결된 시스템에서 다시 읽고, `reset` 은 씨앗부터 돌리고, `resume` 은 보관된 구간에서
305
+ * 세운다. 셋 다 보관 기간 밖의 사건을 요구하지 않는다.
306
+ *
307
+ * 보존 기간을 7일로 선언한 것이 곧 「7일 전 상태로는 세우지 않는다」는 뜻이다. 그 전제를 지키느라
308
+ * 지우지 않으면, 멈춘 트윈의 저널이 영구히 남는다 — 실측으로 세 트윈에 2,900만 행이 그렇게 남았다.
309
+ *
310
+ * 「지울 수 없었다」는 사실은 그대로 센다(도는데 체크포인트가 아직 없는 경우) — 알리지 않고 넘기면
311
+ * 「보존이 도는데 왜 안 줄어드나」가 된다.
266
312
  *
267
313
  * `createdAt` 이 빈 옛 행은 **지우지 않는다**(시각을 모르는 것을 「오래됐다」로 읽지 않는다).
268
314
  *
@@ -271,8 +317,51 @@ export declare class TwinEngine {
271
317
  static pruneJournal(domainId: string): Promise<{
272
318
  deleted: number;
273
319
  instances: number;
274
- skipped: string[];
275
320
  }>;
321
+ /**
322
+ * 한 번의 지우기가 다루는 행 수 — 쓰기 잠금을 이 만큼만 잡는다.
323
+ *
324
+ * ── 20,000 이 왜 컸나 (2026-08-28 실측) ────────────────────────────────────
325
+ * 앞 판은 20,000 이었고 근거는 「한 문장으로 수백만 행을 지우면 74초였다」였다. 그것은 **더 나쁜
326
+ * 쪽과 견준 수**이고, 20,000 자체를 잰 것이 아니었다. 실제로 재 보니 이렇다(서버 기록):
327
+ *
328
+ * hatio-mx1 20,123줄 5.6초
329
+ * hatio-mx2 20,130줄 5.2초
330
+ * hatio-us 20,139줄 4.2초
331
+ * 한 창의 합계 약 15초
332
+ *
333
+ * sqlite 는 연결이 하나다. 그래서 그 4~5초 동안 **화면의 모든 질의가 줄을 선다** — 실측으로 첫
334
+ * 화면 조회가 12.2초였다(정상 상태에서는 40밀리초다).
335
+ *
336
+ * 그리고 예산(`JOURNAL_PRUNE_BUDGET_MS` = 2초)이 **문장이 끝난 뒤에** 검사되므로, 한 문장이 예산을
337
+ * 2~3배 넘긴다. 배치를 나눈 뜻이 그만큼 없어진다.
338
+ *
339
+ * ── 2,000 의 근거 ──────────────────────────────────────────────────────────
340
+ * 위 실측이 줄당 약 0.26밀리초다(5.2초 / 20,130줄). 2,000줄이면 **한 문장이 약 0.5초**다. 화면이
341
+ * 한 번 멈추는 길이가 5초에서 0.5초로 줄고, 예산 검사도 뜻을 갖는다(한 창에 문장 넷).
342
+ *
343
+ * 총량은 같고 나눠서 치른다 — 창마다 지우는 수가 줄지만 지우는 일은 급하지 않다(창이 10분마다 온다).
344
+ *
345
+ * 값을 바꾸려면 다시 재고 이 문장을 고칠 것.
346
+ */
347
+ static JOURNAL_PRUNE_BATCH: number;
348
+ /**
349
+ * 한 창에서 지우는 데 쓰는 시간 상한(ms) — 남은 것은 다음 창이 이어서 지운다.
350
+ *
351
+ * 밀린 몫이 며칠치면 한 창에서 다 지울 수 없다. 다 지우려 들면 그동안 호스트가 멈추고, 그것이 바로
352
+ * 고치려는 증상이다. 총량은 같고 나눠서 치른다.
353
+ *
354
+ * ── 2초에서 5초로 올린 이유 (2026-08-28) ───────────────────────────────────
355
+ * 배치를 20,000 → 2,000 으로 줄였다(§`JOURNAL_PRUNE_BATCH`). 예산을 그대로 두면 **창마다 지우는
356
+ * 양이 2.5배 줄어** 밀린 몫이 빠지지 않는다.
357
+ *
358
+ * 예산을 5초로 두면 한 창에 문장 열 개(각 0.5초)가 돌아 **지우는 양은 전과 같고**, 잠금은 열 번
359
+ * 나뉘어 그 사이에 화면 질의가 처리된다. 고치려던 것은 총 시간이 아니라 **한 번에 멈추는 길이**다.
360
+ *
361
+ * 전 한 문장 5.2초 · 그동안 모든 조회가 줄을 선다
362
+ * 후 문장 열 개 × 0.5초 · 사이마다 루프를 비워 준다
363
+ */
364
+ static JOURNAL_PRUNE_BUDGET_MS: number;
276
365
  /** 보존 정리 주기 기동(1회) — 선언이 없으면 아무것도 하지 않는다. */
277
366
  static startRetentionLoop(domainId: string): void;
278
367
  /** 체크포인트 루프 기동(1회) — 라이브 인스턴스들의 최신 스냅샷을 주기 영속. */
@@ -289,7 +378,7 @@ export declare class TwinEngine {
289
378
  * `bootstrap()` 은 상태만 되찾아 `recovered` 에 담았고, 커널을 세우는 것은 **명시 mutation 뿐**이었다
290
379
  * (이 파일 위쪽 주석이 「향후」라고 적어 둔 그 자리다). 그래서 서버를 한 번 재기동하면 등록부는
291
380
  * `running` 이라 말하는데 **아무 커널도 돌지 않았다** — 화면은 도는 트윈을, 실제로는 멈춘 트윈을.
292
- * 미러 트윈에서는 더 나쁘다: 계측이 조용히 끊기고, 사람은 「값이 안 변하네」로 알게 된다.
381
+ * 미러 트윈에서는 더 나쁘다: 계측이 알리지 않고 끊기고, 사람은 「값이 안 변하네」로 알게 된다.
293
382
  *
294
383
  * ── 모드를 지어내지 않는다 ──────────────────────────────────────────────────
295
384
  * 미러였던 트윈을 시뮬로 되살리면 **없던 움직임을 만들어 낸다**(관측 트윈이 스스로 물건을 옮긴다).
@@ -338,7 +427,7 @@ export declare class TwinEngine {
338
427
  * `model.operations`(마스터 인제스트가 통과시킨 ISA-95 OperationsSegment 명세)를 커널이 소비한다.
339
428
  * 없으면 커널 기본 상수로 굴러가고, 커널 `specCoverage()` 가 무엇을 기본값으로 썼는지 보고한다.
340
429
  *
341
- * 커널이 아직 이 API 를 갖지 않은 버전이면(발행 이전) **조용히 넘어가지 않고 경고한다** — 명세를
430
+ * 커널이 아직 이 API 를 갖지 않은 버전이면(발행 이전) **알리지 않고 넘어가지 않고 경고한다** — 명세를
342
431
  * 선언했는데 반영되지 않는 상태를 모르고 지나가면, 예측이 상수로 돌아간 것을 아무도 알 수 없다.
343
432
  */
344
433
  private static applyOperations;
@@ -352,11 +441,11 @@ export declare class TwinEngine {
352
441
  * 둘 다 못 만들면 주입하지 않는다 — 커널이 명세·상수로 굴러가고 `specCoverage()` 가 그 사실을 남긴다.
353
442
  *
354
443
  * 실측은 DB 조회라 비동기다. 그래서 이 함수는 **await 하지 않는 쪽에서도 안전**하도록 실패를 삼키되,
355
- * 무엇을 왜 못 넣었는지는 로그로 남긴다(조용한 무효화 금지).
444
+ * 무엇을 왜 못 넣었는지는 로그로 남긴다(들어온 것이 없는 무효화 금지).
356
445
  */
357
446
  static installEstimators(kernel: any, domainId: string, instanceId: string, model: any): Promise<void>;
358
447
  /**
359
- * 실측 추정기 — **예측 요청마다 저널을 다시 접지 않는다.**
448
+ * 실측 추정기 — **예측 요청마다 저널을 다시 계산하지 않는다.**
360
449
  *
361
450
  * 예측 커널은 요청마다 새로 세워지고(미러 예측·백테스트), 화면은 시각을 긁으면 계속 재예측한다.
362
451
  * 거기에 KPI 조회를 그대로 달면 요청당 저널 스캔이 하나씩 붙는다 — 실측은 분 단위로 바뀌지 않으므로
@@ -375,10 +464,10 @@ export declare class TwinEngine {
375
464
  * 다시 넣으므로). 버리는 것이 손해가 아닌 이유: 이 값은 캐시이고, 없으면 다시 계산한다.
376
465
  *
377
466
  * 수를 크게 잡는다 — 트윈 규모는 늘 크고, 항목 하나는 작업 종류별 소요 몇 줄이다. 상한이 작으면
378
- * 정상 규모에서 서로 밀어내며 캐시가 무의미해진다(그게 더 나쁘다: 조용히 느려진다).
467
+ * 정상 규모에서 서로 밀어내며 캐시가 무의미해진다(그게 더 나쁘다: 알리지 않고 느려진다).
379
468
  */
380
469
  private static readonly MEASURED_MAX;
381
- /** 이 트윈이 이력에서 배운 양품률 — 소요와 **같은 폴드·같은 캐시**에서 온다(저널을 두 번 접지 않는다). */
470
+ /** 이 트윈이 이력에서 배운 양품률 — 소요와 **같은 폴드·같은 캐시**에서 온다(저널을 두 번 계산하지 않는다). */
382
471
  private static measuredYield;
383
472
  private static measuredEstimator;
384
473
  /**
@@ -412,7 +501,7 @@ export declare class TwinEngine {
412
501
  * 보여야 하는 화면이 정작 그때 아무 말도 못 한다.
413
502
  *
414
503
  * 그 빈칸을 이력로 메운다: 저널에서 배운 종류는 **추정기가 이미 답할 수 있는 종류**이므로, 지어내는
415
- * 것이 아니라 있는 사실을 꺼내는 것이다. 같은 캐시(60초)를 쓰므로 조회마다 저널을 다시 접지 않는다.
504
+ * 것이 아니라 있는 사실을 꺼내는 것이다. 같은 캐시(60초)를 쓰므로 조회마다 저널을 다시 계산하지 않는다.
416
505
  */
417
506
  static measuredOperationKinds(domainId: string, instanceId: string): Promise<string[]>;
418
507
  /**
@@ -426,7 +515,7 @@ export declare class TwinEngine {
426
515
  *
427
516
  * 계산은 커널이 자기 상태에서 한다(`kernel.capacity`). 여기서 하는 일은 **기준 주를 정해 주는
428
517
  * 것**뿐이다: 공휴일이 없는 평상주여야 한다 — 공휴일은 연간 가용량을 따로 깎지, 이 공장의 평상시
429
- * 상한을 정하지 않는다. 커널이 임의로 고르게 두면 그 주에 공휴일이 끼었을 때 상한이 조용히 낮아진다.
518
+ * 상한을 정하지 않는다. 커널이 임의로 고르게 두면 그 주에 공휴일이 끼었을 때 상한이 알리지 않고 낮아진다.
430
519
  *
431
520
  * 트윈이 기동 중이 아니면 `undefined` 다 — 0 이 아니다. 기동하지 않은 트윈의 상한을 0 이라고 답하면 화면은
432
521
  * "이 공장은 아무것도 못 만든다" 고 말한다.
@@ -461,7 +550,7 @@ export declare class TwinEngine {
461
550
  reason?: 'not-running' | 'no-operations';
462
551
  }[]>;
463
552
  /**
464
- * 미러 기동의 연속성 씨앗 — 이어받은 것은 **말한다**(조용히 잇지 않는다).
553
+ * 미러 기동의 연속성 씨앗 — 이어받은 것은 **말한다**(알리지 않고 잇지 않는다).
465
554
  *
466
555
  * 커널이 그 문을 열어 두지 않았으면 그 사실도 말한다: 그 트윈은 재기동마다 열린 구간을 잃는다.
467
556
  */
@@ -474,7 +563,7 @@ export declare class TwinEngine {
474
563
  * 줄줄이 생겼다: 예측하려면 임시 커널을 세워야 했고(`buildForecastKernel`), 주목 신호를 호스트가
475
564
  * 덧붙여야 했고(`withLiveAttentions`), AI 예측 도구는 미러에서 "찾을 수 없다" 로 끝났다.
476
565
  *
477
- * 이제 라이브 인스턴스도 **커널이다.** 같은 규칙(`ObservedReducer`)으로 이벤트를 접고, 주목 신호를
566
+ * 이제 라이브 인스턴스도 **커널이다.** 같은 규칙(`ObservedReducer`)으로 이벤트를 계산하고, 주목 신호를
478
567
  * 스스로 내고, 그 자리에서 `fork` 해 예측한다. 구동만 다르다 — sim 은 `tick`, live 는 `apply`.
479
568
  *
480
569
  * 실 이벤트원 = reference 어댑터 openLiveFeed → face2-adapter.ingest → CanonicalEnvelope → ingestLive().
@@ -496,7 +585,7 @@ export declare class TwinEngine {
496
585
  * 이름이 그대로 굳은 것), 일반 기제에 한 시스템 이름이 붙어 있었기 때문에 창고 트윈이 이 자리를
497
586
  * 쓰지 못했다. 별명으로 남겨 두면 그 혼동이 계속되므로 하나로 통일했다.
498
587
  *
499
- * 옛 이름만 가진 모델이 있으면 **조용히 생산 선언을 잃는 대신 분명히 멈춘다** — 그 트윈은 공정이
588
+ * 옛 이름만 가진 모델이 있으면 **알리지 않고 생산 선언을 잃는 대신 분명히 멈춘다** — 그 트윈은 공정이
500
589
  * 없는 채로 돌게 되고(라인이 서 있는 창고), 원인을 찾기 어렵다.
501
590
  */
502
591
  private static productionSpecOf;
@@ -520,32 +609,84 @@ export declare class TwinEngine {
520
609
  *
521
610
  * ── 넣은 수를 **답한다** (2026-08-20) ────────────────────────────────────────
522
611
  * 트윈이 라이브로 돌지 않으면 여기서 봉투를 버린다. 그것 자체는 맞다(넣을 커널이 없다). 문제는
523
- * **조용히** 버린 것이었다: 트윈이 멈춘 뒤에도 피드는 남아 레코드를 나르고, 유입 장부는 그것을
612
+ * **알리지 않고** 버린 것이었다: 트윈이 멈춘 뒤에도 피드는 남아 레코드를 나르고, 유입 장부는 그것을
524
613
  * 「통과」로 셌다. 화면은 멈춘 트윈 옆에 「150 통과 · 100%」라고 적었다 — 사실이 사라지는 동안
525
614
  * 화면이 안심시킨 것이다.
526
615
  *
527
616
  * 그래서 **넣은 수를 돌려준다.** 부르는 쪽이 제시 수와 견주어 버려진 수를 장부에 적는다. 반환을
528
617
  * 무시하는 호출부는 그대로 동작한다(전과 같다).
529
618
  */
530
- static ingestLive(domainId: string, id: string, envelopes: CanonicalEnvelope[]): number;
619
+ /**
620
+ * 유입 결과를 수로 낸다 — 받은 수 · 중복으로 버린 수 · 보낸 수.
621
+ *
622
+ * `ingestLive` 는 받은 수만 돌려주는데, 웹훅으로 받을 때는 **몇 건이 중복이었는지도 답해야** 한다.
623
+ * 밀어 주는 쪽이 그 수를 보고 자기가 되풀이 보내고 있다는 것을 알 수 있어야 하고, 그것을 모르면
624
+ * 우리 응답이 「전부 새 것이었다」로 읽힌다.
625
+ */
626
+ static ingestLiveResult(domainId: string, id: string, envelopes: CanonicalEnvelope[], source?: string): {
627
+ offered: number;
628
+ applied: number;
629
+ duplicates: number;
630
+ };
631
+ /**
632
+ * **마스터데이터를 받는다** — 변하지 않는 속성을 상태에 세운다. 저널에 적지 않는다.
633
+ *
634
+ * ── 왜 저널에 적지 않나 ────────────────────────────────────────────────────
635
+ * 유통기한·로트번호 같은 값은 그 물건의 생애 동안 같다. 그래서 「그때는 얼마였나」라는 물음이
636
+ * 성립하지 않는다 — 시각축이 없는 값이므로 사건이 아니다. 되세울 근거는 중간 저장본이 든다
637
+ * (리듀서가 그 값을 저장본에 담는다).
638
+ *
639
+ * ── 이 문이 없어서 무엇이 났나 (2026-08-28 실측) ───────────────────────────
640
+ * 표준은 그 값을 `ObjectEvent(action=ADD)` 에만 실을 수 있게 한다. 그래서 전량을 읽는 원본이
641
+ * 재고를 다시 말할 때마다 **들어오지 않은 것을 「들어왔다」** 고 했고, 사건 단위 값이라 자리별로
642
+ * 묶을 수도 없어 낱개로 나갔다 — 재기동 한 번에 2,665건이 「읽은 시각」으로 쌓였다.
643
+ *
644
+ * 돌려주는 수는 **상태에 반영된 건수**다. 라이브로 돌지 않는 트윈은 0 을 낸다 — 그 차이를 부르는
645
+ * 쪽이 알아야 한다(버려진 것을 통과로 세면 멈춘 트윈이 정상으로 보인다).
646
+ *
647
+ * 설계: `operato-twin/design/plans/master-data.md`
648
+ */
649
+ static applyMasterData(domainId: string, id: string, elements: readonly VocabularyElement[]): number;
650
+ static ingestLive(domainId: string, id: string, envelopes: CanonicalEnvelope[], source?: string): number;
531
651
  /**
532
652
  * 구간 성과 브로드캐스팅은 **없앴다**(2026-08-06). 카드가 `twinKpi` 를 직접 묻는다.
533
653
  *
534
654
  * 왜: 카드를 여러 단계(공간·트윈·구역·자리·설비)에 붙이려면 브로드캐스팅으로는 태그가 트윈당 1,200개가 되고,
535
- * **모델에 카드를 하나도 안 놓아도** 30초마다 트윈마다 저널을 접었다. 질의로 바꾸니 보고 있는 카드
655
+ * **모델에 카드를 하나도 안 놓아도** 30초마다 트윈마다 저널을 계산했다. 질의로 바꾸니 보고 있는 카드
536
656
  * 수만큼만 들고, 같은 (대상·창·축) 은 클라이언트가 하나로 합친다.
537
657
  *
538
658
  * 덤으로 질의만 할 수 있는 것이 둘 생겼다 — **과거 시각**(`toTime`)과 **공간 단위 합산**(여러 트윈을
539
- * 한 번에 접기). 브로드캐스팅 루프는 트윈별이라 둘 다 못 했다.
659
+ * 한 번에 계산). 브로드캐스팅 루프는 트윈별이라 둘 다 못 했다.
540
660
  *
541
661
  * 축을 나눠도 폴드 비용이 같다는 실측이 근거다(`test/kpi-query-bench.test.ts`).
542
662
  */
543
663
  /**
544
664
  * 몇 창마다 한 번은 **전부** 만드나 — 사건 없이 값이 바뀌는 자리에 대한 그물.
545
665
  *
546
- * 25 창이면 기본 주기에서 5초다. 보장이 아니라 그물이다(위 `publishEntityData` 주석).
666
+ * 보장이 아니라 그물이다(위 `publishEntityData` 주석). **세는 단위는 창이지만 뜻은 시간**이므로,
667
+ * 기본 주기를 200밀리초에서 1초로 늘린 날 이 수도 함께 줄였다(25창 → 5창). 그러지 않으면 그물이
668
+ * 5초에서 25초로 벌어져, 시각만으로 바뀌는 값(유효 기간 만료 같은 것)이 그만큼 늦게 보인다.
547
669
  */
548
670
  static FULL_BROADCAST_EVERY: number;
671
+ /**
672
+ * **한 실행 차례에 발행할 수 있는 건수** — 이만큼 발행하면 루프를 비워 준다 (2026-08-27).
673
+ *
674
+ * ── 왜 상한이 필요한가 (실측으로 서버가 두 번 죽었다) ──────────────────────
675
+ * 구독의 대기열에는 버퍼가 없다(`pubsub.subscribe` 가 `new Repeater(fn)` 을 버퍼 없이 만든다).
676
+ * 발행하는 순간에 「다음 값을 달라」는 요청이 이미 걸려 있어야 바로 전달되고, 아니면 대기열에
677
+ * 쌓인다. 상한은 1024 이고 넘으면 예외가 난다(`@repeaterjs/repeater` 의 `MAX_QUEUE_LENGTH`).
678
+ *
679
+ * 값을 꺼내는 쪽은 비동기다. 그래서 **동기 반복문이 도는 중에는 한 건도 꺼내지 못한다.** 라이브러리로
680
+ * 직접 재 본 값이다 — 소비자를 붙여 두고 2,000건을 동기로 발행하면 소비자가 꺼낸 것은 1건이었고
681
+ * 나머지가 쌓여 예외가 났다.
682
+ *
683
+ * 그 예외는 `publish()` 호출자에게 오지 않는다. `EventTarget` 이 리스너 예외를 uncaughtException 으로
684
+ * 보내므로 try/catch 로는 잡을 수 없다(2026-08-14 에 그 가드를 붙였는데 그래서 무력했다). 막는 방법은
685
+ * **한 차례에 상한을 넘기지 않는 것** 하나다.
686
+ *
687
+ * 1024 보다 넉넉히 작게 둔다 — 소비자가 한 청크를 다 꺼내지 못해도 다음 청크까지 여유가 남는다.
688
+ */
689
+ static PUBLISH_CHUNK: number;
549
690
  /** 전부 만든 횟수 — 범위를 좁히지 못한 창이 얼마나 되는지 값으로 남는다. */
550
691
  static broadcastFullPasses: number;
551
692
  /**
@@ -584,7 +725,7 @@ export declare class TwinEngine {
584
725
  static BROADCAST_LOAD_RATIO: number;
585
726
  /** 지금 쓰고 있는 주기(ms) — 계기판이 이 값을 읽는다. 늘어난 채로 있으면 그것이 사실이다. */
586
727
  static broadcastPeriodMs: number;
587
- /** 주기를 늘린 횟수 — 조용히 늦추지 않는다. */
728
+ /** 주기를 늘린 횟수 — 알리지 않고 늦추지 않는다. */
588
729
  static broadcastBackoffs: number;
589
730
  private static broadcastTimer?;
590
731
  /** live 브로드캐스팅 coalescer — dirty 인 live 인스턴스만 주기적으로 1회 브로드캐스팅(entitySigs 로 변경 엔티티만). */
@@ -604,7 +745,20 @@ export declare class TwinEngine {
604
745
  * 한 tick 에서 수백 번 반복되며 이벤트 루프를 막았다(위 `start()` 주석의 35초 틱). 브로드캐스팅을 모으는
605
746
  * 규율은 모드의 성질이 아니라 **채널의 성질**이다 — 최신-상태 채널이면 중간 상태는 보낼 값이 없다.
606
747
  */
748
+ /**
749
+ * 브로드캐스팅 한 창 — **겹쳐 돌지 않는다** (2026-08-27).
750
+ *
751
+ * 발행이 청크로 나뉘어 사이에 루프를 비워 주므로 한 창이 주기를 넘길 수 있다. 그때 다음 타이머가
752
+ * 겹쳐 들어오면 같은 태그가 두 순서로 나가고 시그니처 표가 엉킨다. 그래서 앞 창이 끝날 때까지
753
+ * 다음 타이머는 그대로 돌아간다 — **창을 버리는 것이 아니다.** 다음 타이머가 이어서 한다.
754
+ *
755
+ * 겹친 횟수를 센다. 계속 겹치면 주기보다 한 창이 오래 걸리고 있다는 뜻이고, 그것은
756
+ * `adjustBroadcastPeriod` 가 주기를 올려 스스로 풀어야 하는 사실이다.
757
+ */
758
+ private static flushInFlight;
759
+ static flushOverruns: number;
607
760
  static flushLiveBroadcasts(): void;
761
+ private static flushBroadcastWindow;
608
762
  /**
609
763
  * 저널 행 한 줄 — **기록 경로가 둘이라(라이브 벌크·심 단건) 행 모양은 반드시 한 곳에서 만든다.**
610
764
  * 두 곳에 각자 적으면 승격 검색 키가 한쪽에만 채워지고, 반쯤 빈 색인은 "저널에는 있는데
@@ -628,12 +782,12 @@ export declare class TwinEngine {
628
782
  * 모아 둔 저널을 **한 번에** 쓴다 — 두 구동이 같은 문을 쓴다 (§7.1).
629
783
  *
630
784
  * ── 왜 한 함수인가 ─────────────────────────────────────────────────────────
631
- * 쓰는 자리가 둘이면(주기 flush · 정지) 한쪽만 고쳐지고, 그 어긋남은 **사실이 조용히 사라지는**
785
+ * 쓰는 자리가 둘이면(주기 flush · 정지) 한쪽만 고쳐지고, 그 어긋남은 **사실이 오류 없이 사라지는**
632
786
  * 모양으로 나타난다. 그래서 흘리는 규칙을 여기 한 곳에 둔다.
633
787
  *
634
788
  * ── 리비전을 누가 매기나 ───────────────────────────────────────────────────
635
789
  * · 라이브 — 원천은 리비전을 주지 않으므로 **호스트가** 이어 붙인다(저널 high-water 에서 시드).
636
- * · 시뮬 — **커널의 리비전**이 실려 온다(저널이 그것으로 접히고 시간여행이 그것을 딛는다).
790
+ * · 시뮬 — **커널의 리비전**이 실려 온다(저널이 그 번호로 정렬되고 시간여행이 그것을 딛는다).
637
791
  * 그래서 버퍼는 두 모양을 함께 든다: 봉투만 있으면 라이브, `{ event, revision }` 이면 시뮬이다.
638
792
  */
639
793
  private static flushJournal;
@@ -643,10 +797,42 @@ export declare class TwinEngine {
643
797
  * 예전에는 이 경로가 **델타마다 한 행씩** 저장했다(그리고 행마다 구조 리비전을 물었다). 규모에서 그것이
644
798
  * 호스트를 먹었다(§7.1 실측). 여기서 구조 리비전은 **한 번만** 묻는다.
645
799
  */
800
+ /**
801
+ * **마감된 구간 사실은 한 번만 적는다** — 같은 사실이 두 번 오면 한 사실이다 (2026-08-30).
802
+ *
803
+ * ── 왜 쓰는 자리에서 막나 ──────────────────────────────────────────────────
804
+ * 커널이 그 사실들의 정체성을 내용에서 만든다(종류·대상·시작·끝). 그런데 저널의 기본키는 새로
805
+ * 만드는 uuid 라, **id 가 글자 하나까지 같아도 행이 따로 쌓였다.**
806
+ *
807
+ * 실측(2026-08-30): 발전 단가가 행 7개·서로 다른 id 4개였다. 8월 27일 단가가 세 벌 있었고,
808
+ * 그 구간의 수익이 세 번 세어진다.
809
+ *
810
+ * 커넥터가 커서로 막는 것이 첫 방어선이고 그쪽도 고쳤다. 그런데 **커넥터가 한 번 실수하면 저널이
811
+ * 부풀고 그 위의 모든 합이 틀린다.** 정체성은 커널이 선언한 사실이므로, 어느 문으로 들어오든
812
+ * 지켜져야 한다 — 채우기 경로에만 있으면 그 보증은 「어느 문으로 왔느냐」에 걸린다.
813
+ *
814
+ * ── 값이 싼 이유 ───────────────────────────────────────────────────────────
815
+ * 마감된 구간 사실만 본다(시점의 관측은 그대로 지난다 — 반복이 뜻을 가진다). 그것들은 드물어서
816
+ * (한 시간에 한 줄) 한 묶음에 몇 개뿐이고, 그 구간의 그 종류만 색인으로 읽는다.
817
+ */
818
+ private static readonly PERIOD_FACT_TYPES;
819
+ static dropAlreadyWritten(domainId: string, instanceId: string, envelopes: any[]): Promise<any[]>;
646
820
  static persistCarried(domainId: string, instanceId: string, items: {
647
821
  event: any;
648
822
  revision: number;
649
823
  }[]): Promise<void>;
824
+ /**
825
+ * **대상별 사건 목록에 함께 적는다** — 조회용 파생 표 (2026-08-27).
826
+ *
827
+ * 저널을 쓰는 두 문(`persistBatch` · `persistCarried`) 뒤에서 부른다. 다른 자리에서 나중에 적으면
828
+ * 「저널에는 있고 그 표에는 없는 사건」이 생기고, 그것은 화면에서 오류 없이 빠진 사건이 된다.
829
+ *
830
+ * **저널이 먼저다.** 이 표에 적다가 실패해도 저널 쓰기를 되돌리지 않는다 — 사실의 원본은 저널이고
831
+ * 이 표는 다시 만들 수 있다. 실패는 세어 남긴다(§`subjectWriteFailures`).
832
+ *
833
+ * 설계: `operato-twin/design/plans/read-models.md`
834
+ */
835
+ private static writeSubjects;
650
836
  /**
651
837
  * 저널 행을 넣는다 — **넣기만 한다**(2026-08-20).
652
838
  *
@@ -669,6 +855,23 @@ export declare class TwinEngine {
669
855
  };
670
856
  }): Promise<void>;
671
857
  /**
858
+ * ── **트윈은 설비의 마스터가 아니다** (사용자 결정 2026-08-30) ─────────────
859
+ *
860
+ * 인원·설비·자산의 마스터는 `@things-factory/ops-master` 다. 트윈은 그것을 **당겨 와** 모델에
861
+ * 반영하고, 여기 남는 것은 그 결과의 캐시다.
862
+ *
863
+ * 그래서 이 함수가 하는 일에 선이 있다.
864
+ *
865
+ * 트윈 안에서 사람이 더한 설비 가정·시뮬레이션의 사실이다 — 트윈이 든다 (지금 이 함수)
866
+ * 현장에 실제로 있는 설비 마스터의 사실이다 — 트윈이 만들지 않는다
867
+ *
868
+ * 이 함수는 **트윈 제어 명령**(`resource.add`) 뒤에만 불린다. 관측에서 설비가 생기는 경로가 아니다.
869
+ * 관측으로 모르는 설비가 들어오면 그것은 **마스터에 없는 것**이고, 트윈이 조용히 만들어 주면 두
870
+ * 곳이 서로 다른 설비 목록을 갖게 된다. 그때는 만들지 말고 「모르는 설비가 왔다」로 세어야 한다.
871
+ *
872
+ * 당겨 오는 길이 붙으면 이 주석의 위쪽 절반만 남는다.
873
+ *
874
+ * ── 원래 설명 ─────────────────────────────────────────────────────────────
672
875
  * 라이브 구조 변이(resource.add 등)를 저장된 model 에 반영 — 런타임 커널의 무버를 registry model.equipment 에 동기.
673
876
  * 이게 없으면 런타임엔 추가돼도(상태·저널엔 반영) 저장 model 는 원본이라 프로비저닝 편집기·재기동(loadTwinModel)이
674
877
  * 추가분을 잃는다. 기존 model.equipment 항목은 보존(homeLocation 유지)하고 새 id 만 append(추가 시점 location=homeLocation).
@@ -684,7 +887,7 @@ export declare class TwinEngine {
684
887
  /**
685
888
  * 실행 중이면 구조를 교체하지 않는다 — **판정 문장을 한 곳에 둔다.**
686
889
  *
687
- * 인제스트는 전량 교체라, 이벤트를 접고 있는 커널 밑에서 바닥을 바꾸는 셈이 된다. 지금은 거절이
890
+ * 인제스트는 전량 교체라, 이벤트를 계산하고 있는 커널 밑에서 바닥을 바꾸는 셈이 된다. 지금은 거절이
688
891
  * 유일한 답이지만 최종형은 아니다(`adoptStructure` 배선). 두 곳에서 같은 문장으로 거절해야
689
892
  * 나중에 이 규칙을 걷어낼 때 걷어낼 것이 하나로 보인다.
690
893
  */
@@ -701,7 +904,7 @@ export declare class TwinEngine {
701
904
  * 세 가지가 **함께** 일어나야 한다. 하나라도 빠지면 층이 어긋난다:
702
905
  * ① 리비전 — 이 시점 이후의 이벤트가 새 번호를 달고 다닌다(재생이 마디를 나눌 수 있게)
703
906
  * ② 저장 model·구조 행 — 조회가 새 구조를 본다
704
- * ③ 커널 — 지금 접히는 이벤트가 새 구조 위에서 접힌다
907
+ * ③ 커널 — 지금 계산에 들어가는 이벤트가 새 구조 위에서 계산된다
705
908
  */
706
909
  static adoptStructure(domainId: string, instanceId: string, model: TwinModelDef, comment?: string, origin?: any): Promise<{
707
910
  rev: number;
@@ -711,7 +914,7 @@ export declare class TwinEngine {
711
914
  * **재기동 정책은 생성 시점의 선언이다**(ADR-0029 §2) — 트윈은 정책 없이 존재할 수 없다.
712
915
  *
713
916
  * 예전에는 이 자리가 없었고 `register` 가 기본값(`sim-experiment` = 저널 초기화)을 각인했다. 그래서
714
- * 선언을 빠뜨린 프로비저닝이 **재기동마다 이력을 지우는 트윈**을 조용히 만들었다. 이제 만드는 쪽이
917
+ * 선언을 빠뜨린 프로비저닝이 **재기동마다 이력을 지우는 트윈**을 알리지 않고 만들었다. 이제 만드는 쪽이
715
918
  * 말해야 한다: 이 트윈이 자기 과거를 어떻게 대하는지는 만드는 사람이 아는 사실이다.
716
919
  */
717
920
  restartPolicy: RestartPolicy, comment?: string, origin?: any,
@@ -864,8 +1067,21 @@ export declare class TwinEngine {
864
1067
  * 못 보낸 것은 **사실로 남긴다**(횟수를 세고 창마다 한 줄 남긴다). 삼키면 「보냈는데 화면이 낡았다」가
865
1068
  * 되고, 그건 가장 찾기 어려운 부류다.
866
1069
  */
1070
+ /**
1071
+ * 브로드캐스팅 한 건 — **이 가드가 대기열 넘침을 막지는 못한다** (2026-08-27 측정으로 바로잡음).
1072
+ *
1073
+ * 2026-08-14 에 이 함수를 「방송이 호스트를 죽이지 못하게」라는 이름으로 붙였다. 그것이 사실이 아니다.
1074
+ * 대기열이 넘칠 때 나는 예외는 `EventTarget` 이 부른 리스너 안에서 난다. 런타임은 리스너 예외를
1075
+ * 호출자에게 주지 않고 uncaughtException 으로 보낸다. 그래서 이 try/catch 에는 잡을 것이 없다.
1076
+ * 실제로 그 뒤 3주 동안 막힌 줄 알고 있었고, 2026-08-27 10:24 에 같은 예외로 다시 죽었다.
1077
+ *
1078
+ * 넘침을 막는 것은 **한 실행 차례에 발행하는 수를 상한 아래로 두는 것**이다(§`PUBLISH_CHUNK`).
1079
+ *
1080
+ * 그래도 이 가드를 남기는 이유는 둘이다. `publish` 가 직접 던지는 경우(직렬화 실패 등)를 잡고,
1081
+ * 못 보낸 태그의 시그니처를 되돌린다 — 남겨 두면 그 태그가 오류 없이 영원히 낡은 값을 보인다.
1082
+ */
867
1083
  private static publishGuarded;
868
- static publishEntityData(inst: InstanceRuntime): void;
1084
+ static publishEntityData(inst: InstanceRuntime): Promise<void>;
869
1085
  /**
870
1086
  * 재부팅 복구 / 시간여행 — DB 저널을 replay 해 상태 재구성.
871
1087
  * model 는 레지스트리(TwinInstance)에서, 이벤트는 TwinEvent(revision ASC)에서.
@@ -1040,6 +1256,37 @@ export declare class TwinEngine {
1040
1256
  * `offered` 는 **제시된 레코드 수**다(거부 여부 무관). 통과율을 서로 다른 두 계수기에서 나눠 계산하면
1041
1257
  * 분모와 분자가 다른 것을 세게 되므로, 한자리에서 본 수를 그대로 넘긴다.
1042
1258
  */
1259
+ /**
1260
+ * 이 트윈의 저널이 지금 몇 번까지 적혔나 — **접근자로 낸다.**
1261
+ *
1262
+ * 레지스트리를 밖에서 직접 색인하지 않게 하는 것이 이 저장소의 규율이다(§`engine-registry-access`).
1263
+ * 지난 기록을 채우는 길이 다음 번호를 알아야 해서 열었다.
1264
+ *
1265
+ * 트윈이 도는 중이 아니면 0 이다 — 그때는 저널만 있고 이어 붙일 번호를 커널이 들고 있지 않다.
1266
+ */
1267
+ /**
1268
+ * 마감된 구간 사실의 **이름을 지을 때 쓸 범위와 선언** — 유입 문에 넘긴다.
1269
+ *
1270
+ * ── 왜 호스트가 주나 (2026-08-30) ────────────────────────────────────────
1271
+ * 커널은 `new Kernel(domainId, …)` 으로 서므로 **자기가 어느 트윈인지 모른다.** 그런데 설비 번호는
1272
+ * 트윈 안에서만 통하는 이름표라, 한 도메인에 현장이 둘이면 서로 다른 설비의 같은 날이 한 사실이
1273
+ * 된다. 실측으로 그 일이 났다 — 두 발전소의 `002` 가 겹쳐, 여러 현장을 함께 계산하는 성과 화면에서
1274
+ * 한쪽 발전량이 사라진다.
1275
+ *
1276
+ * 선언된 정체성은 **커널이 답한다**(§`FlowEngine.equipmentIdentity`) — 판정을 두 곳에 두지 않는다.
1277
+ * 트윈이 돌고 있지 않으면 선언을 물을 곳이 없으므로 범위만 넘긴다(그때도 겹치지는 않는다).
1278
+ */
1279
+ static factScope(domainId: string, instanceId: string): {
1280
+ scopeId: string;
1281
+ identityOf?: (kind: 'equipment' | 'meter', localId: string) => string | undefined;
1282
+ };
1283
+ static journalHead(domainId: string, instanceId: string): number;
1284
+ /**
1285
+ * 저널에 그만큼 적었으니 번호를 밀어 준다.
1286
+ *
1287
+ * 밀어 주지 않으면 다음에 라이브가 **같은 번호를 다시 쓴다** — 같은 시각의 두 사실을 가릴 수 없게 된다.
1288
+ */
1289
+ static advanceJournalHead(domainId: string, instanceId: string, by: number): void;
1043
1290
  static recordIngestResult(domainId: string, instanceId: string, offered: number, rejected: {
1044
1291
  record?: unknown;
1045
1292
  errors?: string[];
@@ -1054,18 +1301,24 @@ export declare class TwinEngine {
1054
1301
  * **원본에 닿지 못했다**를 적는다 — 「받은 것이 없다」와 가른다(§`recordReadFailure`).
1055
1302
  *
1056
1303
  * 이 문이 없던 동안 실 원본이 끊겨도 트윈의 조회 가능한 상태에 그 사실이 없었다. 화면이 볼 수 있는
1057
- * 것은 「새 사실이 없다」뿐이었고 그것은 「원본이 조용하다」와 구별되지 않는다 — 실증 중에 원본이
1304
+ * 것은 「새 사실이 없다」뿐이었고 그것은 「연결된 시스템에서 들어온 것이 없다」와 구별되지 않는다 — 실증 중에 원본이
1058
1305
  * 끊기면 사용자가 원인을 찾을 수 없다.
1059
1306
  *
1060
1307
  * 로그로는 말하고 있었다(어댑터가 재시도를 경고한다). 그러나 **로그는 사람이 볼 때만 값이 있다** —
1061
1308
  * 화면이 말하려면 상태에 있어야 한다.
1062
1309
  */
1063
- static recordIngestReadFailure(domainId: string, instanceId: string, reason: string, nowMs?: number, stream?: string): void;
1310
+ static recordIngestReadFailure(domainId: string, instanceId: string, reason: string, nowMs?: number, stream?: string, nextRetryMs?: number): void;
1311
+ /**
1312
+ * **끊겼다가 돌아왔다** — 실패 기록을 지우고 그 사실을 남긴다 (2026-08-27).
1313
+ *
1314
+ * `clearIngestReadFailure` 와 나누어 둔다: 지우기만 하면 「끊긴 적이 있었다」가 화면에서 사라진다.
1315
+ */
1316
+ static recordIngestRecovered(domainId: string, instanceId: string, afterFailures: number, downMs: number, nowMs?: number): void;
1064
1317
  /**
1065
1318
  * 읽기가 성공했다 — 단절 기록을 지운다.
1066
1319
  *
1067
1320
  * **빈 읽기도 성공이다.** 원본이 「새 것이 없다」고 답한 것은 닿았다는 뜻이므로, 그때도 부른다.
1068
- * 그 둘을 같게 두면 조용한 원본이 끊긴 원본으로 보인다.
1321
+ * 그 둘을 같게 두면 들어온 것이 없는 연결이 끊긴 원본으로 보인다.
1069
1322
  */
1070
1323
  static clearIngestReadFailure(domainId: string, instanceId: string): void;
1071
1324
  /**
@@ -1082,7 +1335,7 @@ export declare class TwinEngine {
1082
1335
  * **원본에 있는데 세우지 않은 것을 적는다** — 이유와 수(§`IngestLedger.withheld`).
1083
1336
  *
1084
1337
  * 어댑터가 주기마다 불러도 된다: 장부가 이유로 묶어 **마지막 수로 덮는다**(누적하지 않는다).
1085
- * `count: 0` 은 「그 이유가 풀렸다」로 그 줄을 지운다 — 조용히 그치면 낡은 수가 남는다.
1338
+ * `count: 0` 은 「그 이유가 풀렸다」로 그 줄을 지운다 — 알리지 않고 그치면 낡은 수가 남는다.
1086
1339
  */
1087
1340
  static recordIngestWithheld(domainId: string, instanceId: string, reason: string, count: number, nowMs?: number): void;
1088
1341
  /** 창을 넘겼다 — 정체 기록을 지운다(풀린 정체가 화면에 남아 있으면 그것도 거짓이다). */
@@ -1147,7 +1400,7 @@ export declare class TwinEngine {
1147
1400
  /**
1148
1401
  * 도는 인스턴스 전체의 계측(모니터 대시보드용) — **시뮬과 미러를 함께**.
1149
1402
  *
1150
- * 예전에는 시뮬에 계기가 없어 이 목록에서 조용히 빠졌다(계기가 `null` 이라 걸러졌다). 도는 트윈
1403
+ * 예전에는 시뮬에 계기가 없어 이 목록에서 알리지 않고 빠졌다(계기가 `null` 이라 걸러졌다). 도는 트윈
1151
1404
  * 대부분이 시뮬인 서버에서 그 목록은 「부하가 거의 없다」로 보였다.
1152
1405
  */
1153
1406
  static allMetrics(domainId?: string): Promise<any[]>;