@things-factory/headless-twin 10.1.277 → 10.1.279

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (614) hide show
  1. package/package.json +21 -7
  2. package/dist-server/engine/attention-digest.js.map +0 -1
  3. package/dist-server/engine/canonical-ingest.js.map +0 -1
  4. package/dist-server/engine/checkpoint-fold.js.map +0 -1
  5. package/dist-server/engine/command-routing.js.map +0 -1
  6. package/dist-server/engine/declared-stimulus.js.map +0 -1
  7. package/dist-server/engine/energy-topology.js.map +0 -1
  8. package/dist-server/engine/event-time.js.map +0 -1
  9. package/dist-server/engine/index.js.map +0 -1
  10. package/dist-server/engine/ingest-dedupe.js.map +0 -1
  11. package/dist-server/engine/ingest-health.js.map +0 -1
  12. package/dist-server/engine/integration-coverage.js.map +0 -1
  13. package/dist-server/engine/integration-probes.js.map +0 -1
  14. package/dist-server/engine/integration-runner.js.map +0 -1
  15. package/dist-server/engine/integration-target-profile.js.map +0 -1
  16. package/dist-server/engine/kpi-baseline.js.map +0 -1
  17. package/dist-server/engine/kpi-fold.js.map +0 -1
  18. package/dist-server/engine/kpi-query.js.map +0 -1
  19. package/dist-server/engine/kpi-target.js.map +0 -1
  20. package/dist-server/engine/live-attentions.js.map +0 -1
  21. package/dist-server/engine/live-feed-registry.js.map +0 -1
  22. package/dist-server/engine/load-meter.js.map +0 -1
  23. package/dist-server/engine/local-declarations.js.map +0 -1
  24. package/dist-server/engine/log.js.map +0 -1
  25. package/dist-server/engine/loop-lag.js.map +0 -1
  26. package/dist-server/engine/measured-estimator.js.map +0 -1
  27. package/dist-server/engine/measured-yield.js.map +0 -1
  28. package/dist-server/engine/model-basis.js.map +0 -1
  29. package/dist-server/engine/model-gap.js.map +0 -1
  30. package/dist-server/engine/model-refusal.js.map +0 -1
  31. package/dist-server/engine/model-vocabulary.js.map +0 -1
  32. package/dist-server/engine/oee-accumulator.js.map +0 -1
  33. package/dist-server/engine/operation-basis.js.map +0 -1
  34. package/dist-server/engine/producer-guard.js.map +0 -1
  35. package/dist-server/engine/property-effects.js.map +0 -1
  36. package/dist-server/engine/read-time.js.map +0 -1
  37. package/dist-server/engine/restart-policy.js.map +0 -1
  38. package/dist-server/engine/runtime-key.js.map +0 -1
  39. package/dist-server/engine/spec-coverage.js.map +0 -1
  40. package/dist-server/engine/stage-path.js.map +0 -1
  41. package/dist-server/engine/state-axes.js.map +0 -1
  42. package/dist-server/engine/structure-diff.js.map +0 -1
  43. package/dist-server/engine/travel-estimator.js.map +0 -1
  44. package/dist-server/engine/twin-engine.js.map +0 -1
  45. package/dist-server/engine/twin-state-channel.js.map +0 -1
  46. package/dist-server/engine/warm-start.js.map +0 -1
  47. package/dist-server/index.js.map +0 -1
  48. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js.map +0 -1
  49. package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js.map +0 -1
  50. package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js.map +0 -1
  51. package/dist-server/migrations/1786300000000-IndexEventTypeByTime.js.map +0 -1
  52. package/dist-server/migrations/1786400000000-IndexEventCreatedAt.js.map +0 -1
  53. package/dist-server/migrations/1786500000000-CreateTwinSubjectEvents.js.map +0 -1
  54. package/dist-server/migrations/1786600000000-RenameOperatoMesAdapterType.js.map +0 -1
  55. package/dist-server/migrations/1786700000000-AddDispatchRetryColumns.js.map +0 -1
  56. package/dist-server/migrations/1786800000000-CreateTwinReferenceReconciliations.js.map +0 -1
  57. package/dist-server/migrations/index.js.map +0 -1
  58. package/dist-server/routes.js.map +0 -1
  59. package/dist-server/service/actuation/actuation-advisor.js.map +0 -1
  60. package/dist-server/service/actuation/actuation-outcome.js.map +0 -1
  61. package/dist-server/service/actuation/actuation-rule-resolver.js.map +0 -1
  62. package/dist-server/service/actuation/actuation-rule.js.map +0 -1
  63. package/dist-server/service/actuation/approval-gateway.js.map +0 -1
  64. package/dist-server/service/actuation/catch-up-effects.js.map +0 -1
  65. package/dist-server/service/actuation/command-dispatcher.js.map +0 -1
  66. package/dist-server/service/actuation/command-store.js.map +0 -1
  67. package/dist-server/service/actuation/dispatch-after-approval.js.map +0 -1
  68. package/dist-server/service/actuation/effect-match.js.map +0 -1
  69. package/dist-server/service/actuation/index.js.map +0 -1
  70. package/dist-server/service/actuation/retry-plan.js.map +0 -1
  71. package/dist-server/service/actuation/rule-evaluate.js.map +0 -1
  72. package/dist-server/service/actuation/rule-loop.js.map +0 -1
  73. package/dist-server/service/actuation/rule-runner.js.map +0 -1
  74. package/dist-server/service/actuation/rule-wiring.js.map +0 -1
  75. package/dist-server/service/actuation/settle-effects.js.map +0 -1
  76. package/dist-server/service/actuation/sweep-dispatch.js.map +0 -1
  77. package/dist-server/service/actuation/twin-command-resolver.js.map +0 -1
  78. package/dist-server/service/actuation/twin-command.js.map +0 -1
  79. package/dist-server/service/actuation/twin-now.js.map +0 -1
  80. package/dist-server/service/index.js.map +0 -1
  81. package/dist-server/service/reference/actuation-routing.js.map +0 -1
  82. package/dist-server/service/reference/actuation-target.js.map +0 -1
  83. package/dist-server/service/reference/actuation-verification.js.map +0 -1
  84. package/dist-server/service/reference/attention-lane.js.map +0 -1
  85. package/dist-server/service/reference/connection-portability-resolver.js.map +0 -1
  86. package/dist-server/service/reference/connection-portability.js.map +0 -1
  87. package/dist-server/service/reference/control-routing.js.map +0 -1
  88. package/dist-server/service/reference/discovery-result.js.map +0 -1
  89. package/dist-server/service/reference/fill-cadence.js.map +0 -1
  90. package/dist-server/service/reference/fill-dedupe.js.map +0 -1
  91. package/dist-server/service/reference/fill-loop.js.map +0 -1
  92. package/dist-server/service/reference/fill-span.js.map +0 -1
  93. package/dist-server/service/reference/hook-contract.js.map +0 -1
  94. package/dist-server/service/reference/hook-rejected.js.map +0 -1
  95. package/dist-server/service/reference/hook-store.js.map +0 -1
  96. package/dist-server/service/reference/index.js.map +0 -1
  97. package/dist-server/service/reference/ingest-space.js.map +0 -1
  98. package/dist-server/service/reference/knob-defaults.js.map +0 -1
  99. package/dist-server/service/reference/live-cadence.js.map +0 -1
  100. package/dist-server/service/reference/live-feed-lease.js.map +0 -1
  101. package/dist-server/service/reference/live-ingest.js.map +0 -1
  102. package/dist-server/service/reference/reference-adapter.js.map +0 -1
  103. package/dist-server/service/reference/reference-assessment.js.map +0 -1
  104. package/dist-server/service/reference/reference-fill-run.js.map +0 -1
  105. package/dist-server/service/reference/reference-fill.js.map +0 -1
  106. package/dist-server/service/reference/reference-hook.js.map +0 -1
  107. package/dist-server/service/reference/reference-link-groups.js.map +0 -1
  108. package/dist-server/service/reference/reference-links.js.map +0 -1
  109. package/dist-server/service/reference/reference-live.js.map +0 -1
  110. package/dist-server/service/reference/reference-master.js.map +0 -1
  111. package/dist-server/service/reference/reference-probe.js.map +0 -1
  112. package/dist-server/service/reference/reference-progress-channel.js.map +0 -1
  113. package/dist-server/service/reference/reference-progress-subscription.js.map +0 -1
  114. package/dist-server/service/reference/reference-progress.js.map +0 -1
  115. package/dist-server/service/reference/reference-reconciliation-query.js.map +0 -1
  116. package/dist-server/service/reference/reference-reconciliation-writer.js.map +0 -1
  117. package/dist-server/service/reference/reference-reconciliation.js.map +0 -1
  118. package/dist-server/service/reference/reference-registry.js.map +0 -1
  119. package/dist-server/service/reference/reference-resolver.js.map +0 -1
  120. package/dist-server/service/reference/template-registry.js.map +0 -1
  121. package/dist-server/service/reference/twin-reference-reconciliation.js.map +0 -1
  122. package/dist-server/service/reference/twin-reference.js.map +0 -1
  123. package/dist-server/service/twin-attention/index.js.map +0 -1
  124. package/dist-server/service/twin-attention/twin-attention-query.js.map +0 -1
  125. package/dist-server/service/twin-audit/command-audit.js.map +0 -1
  126. package/dist-server/service/twin-audit/index.js.map +0 -1
  127. package/dist-server/service/twin-audit/twin-audit-event.js.map +0 -1
  128. package/dist-server/service/twin-audit/twin-audit-query.js.map +0 -1
  129. package/dist-server/service/twin-backfill/backfill-period-facts.js.map +0 -1
  130. package/dist-server/service/twin-backfill/backfill-shape.js.map +0 -1
  131. package/dist-server/service/twin-backfill/index.js.map +0 -1
  132. package/dist-server/service/twin-backfill/twin-backfill-resolver.js.map +0 -1
  133. package/dist-server/service/twin-control/index.js.map +0 -1
  134. package/dist-server/service/twin-control/twin-control-mutation.js.map +0 -1
  135. package/dist-server/service/twin-event/index.js.map +0 -1
  136. package/dist-server/service/twin-event/journal-count.js.map +0 -1
  137. package/dist-server/service/twin-event/twin-event-keys.js.map +0 -1
  138. package/dist-server/service/twin-event/twin-event-type.js.map +0 -1
  139. package/dist-server/service/twin-event/twin-event.js.map +0 -1
  140. package/dist-server/service/twin-forecast/forecast-metrics.js.map +0 -1
  141. package/dist-server/service/twin-forecast/forecast-tuning.js.map +0 -1
  142. package/dist-server/service/twin-forecast/gap-analytics.js.map +0 -1
  143. package/dist-server/service/twin-forecast/index.js.map +0 -1
  144. package/dist-server/service/twin-forecast/twin-forecast-query.js.map +0 -1
  145. package/dist-server/service/twin-ingest-window/index.js.map +0 -1
  146. package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js.map +0 -1
  147. package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js.map +0 -1
  148. package/dist-server/service/twin-ingest-window/twin-ingest-window.js.map +0 -1
  149. package/dist-server/service/twin-instance/index.js.map +0 -1
  150. package/dist-server/service/twin-instance/twin-instance.js.map +0 -1
  151. package/dist-server/service/twin-journal/event-type-split-shape.js.map +0 -1
  152. package/dist-server/service/twin-journal/event-type-split.js.map +0 -1
  153. package/dist-server/service/twin-journal/index.js.map +0 -1
  154. package/dist-server/service/twin-journal/journal-order.js.map +0 -1
  155. package/dist-server/service/twin-journal/twin-journal-query.js.map +0 -1
  156. package/dist-server/service/twin-lifecycle/domain-catalog.js.map +0 -1
  157. package/dist-server/service/twin-lifecycle/index.js.map +0 -1
  158. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +0 -1
  159. package/dist-server/service/twin-metrics/index.js.map +0 -1
  160. package/dist-server/service/twin-metrics/twin-metrics-query.js.map +0 -1
  161. package/dist-server/service/twin-model/axis-journal-evidence.js.map +0 -1
  162. package/dist-server/service/twin-model/choose-recipe.js.map +0 -1
  163. package/dist-server/service/twin-model/epcis-coverage.js.map +0 -1
  164. package/dist-server/service/twin-model/external-resolver.js.map +0 -1
  165. package/dist-server/service/twin-model/iec61850-coverage.js.map +0 -1
  166. package/dist-server/service/twin-model/index.js.map +0 -1
  167. package/dist-server/service/twin-model/isa95-coverage.js.map +0 -1
  168. package/dist-server/service/twin-model/item-ref.js.map +0 -1
  169. package/dist-server/service/twin-model/name-index.js.map +0 -1
  170. package/dist-server/service/twin-model/project-structure.js.map +0 -1
  171. package/dist-server/service/twin-model/standard-coverage.js.map +0 -1
  172. package/dist-server/service/twin-model/status-tally.js.map +0 -1
  173. package/dist-server/service/twin-model/twin-equipment.js.map +0 -1
  174. package/dist-server/service/twin-model/twin-lineage-query.js.map +0 -1
  175. package/dist-server/service/twin-model/twin-location.js.map +0 -1
  176. package/dist-server/service/twin-model/twin-model-item-query.js.map +0 -1
  177. package/dist-server/service/twin-model/twin-model-mutation.js.map +0 -1
  178. package/dist-server/service/twin-model/twin-model-query.js.map +0 -1
  179. package/dist-server/service/twin-model/twin-model-tree-query.js.map +0 -1
  180. package/dist-server/service/twin-model/twin-operation.js.map +0 -1
  181. package/dist-server/service/twin-readiness/index.js.map +0 -1
  182. package/dist-server/service/twin-readiness/twin-readiness-query.js.map +0 -1
  183. package/dist-server/service/twin-space/area-resolver.js.map +0 -1
  184. package/dist-server/service/twin-space/index.js.map +0 -1
  185. package/dist-server/service/twin-space/move-space.js.map +0 -1
  186. package/dist-server/service/twin-space/representation-role.js.map +0 -1
  187. package/dist-server/service/twin-space/space-integrity.js.map +0 -1
  188. package/dist-server/service/twin-space/twin-area.js.map +0 -1
  189. package/dist-server/service/twin-space/twin-space-area.js.map +0 -1
  190. package/dist-server/service/twin-space/twin-space-representation.js.map +0 -1
  191. package/dist-server/service/twin-space/twin-space-resolver.js.map +0 -1
  192. package/dist-server/service/twin-space/twin-space.js.map +0 -1
  193. package/dist-server/service/twin-state/index.js.map +0 -1
  194. package/dist-server/service/twin-state/twin-state-subscription.js.map +0 -1
  195. package/dist-server/service/twin-structure/index.js.map +0 -1
  196. package/dist-server/service/twin-structure/twin-structure.js.map +0 -1
  197. package/dist-server/service/twin-subject/event-subjects.js.map +0 -1
  198. package/dist-server/service/twin-subject/index.js.map +0 -1
  199. package/dist-server/service/twin-subject/item-resolver.js.map +0 -1
  200. package/dist-server/service/twin-subject/subject-query-shape.js.map +0 -1
  201. package/dist-server/service/twin-subject/twin-subject-backfill.js.map +0 -1
  202. package/dist-server/service/twin-subject/twin-subject-event.js.map +0 -1
  203. package/dist-server/service/twin-subject/twin-subject-fast-path.js.map +0 -1
  204. package/dist-server/service/twin-subject/twin-subject-query.js.map +0 -1
  205. package/dist-server/service/twin-subject/twin-subject-writer.js.map +0 -1
  206. package/dist-server/service/twin-target/index.js.map +0 -1
  207. package/dist-server/service/twin-target/twin-target-resolver.js.map +0 -1
  208. package/dist-server/service/twin-target/twin-target.js.map +0 -1
  209. package/dist-shared/axis-read.js.map +0 -1
  210. package/dist-shared/entity-delta.js.map +0 -1
  211. package/dist-shared/kpi-broadcast.js.map +0 -1
  212. package/dist-shared/touched-items.js.map +0 -1
  213. package/dist-shared/twin-level.js.map +0 -1
  214. package/server/engine/attention-digest.ts +0 -102
  215. package/server/engine/canonical-ingest.ts +0 -511
  216. package/server/engine/checkpoint-fold.ts +0 -12
  217. package/server/engine/command-routing.ts +0 -67
  218. package/server/engine/declared-stimulus.ts +0 -66
  219. package/server/engine/energy-topology.ts +0 -189
  220. package/server/engine/event-time.ts +0 -96
  221. package/server/engine/index.ts +0 -51
  222. package/server/engine/ingest-dedupe.ts +0 -24
  223. package/server/engine/ingest-health.ts +0 -24
  224. package/server/engine/integration-coverage.ts +0 -147
  225. package/server/engine/integration-probes.ts +0 -144
  226. package/server/engine/integration-runner.ts +0 -95
  227. package/server/engine/integration-target-profile.ts +0 -103
  228. package/server/engine/kpi-baseline.ts +0 -202
  229. package/server/engine/kpi-fold.ts +0 -1516
  230. package/server/engine/kpi-query.ts +0 -1210
  231. package/server/engine/kpi-target.ts +0 -248
  232. package/server/engine/live-attentions.ts +0 -30
  233. package/server/engine/live-feed-registry.ts +0 -59
  234. package/server/engine/load-meter.ts +0 -393
  235. package/server/engine/local-declarations.ts +0 -779
  236. package/server/engine/log.ts +0 -72
  237. package/server/engine/loop-lag.ts +0 -120
  238. package/server/engine/measured-estimator.ts +0 -91
  239. package/server/engine/measured-yield.ts +0 -89
  240. package/server/engine/model-basis.ts +0 -162
  241. package/server/engine/model-gap.ts +0 -168
  242. package/server/engine/model-refusal.ts +0 -31
  243. package/server/engine/model-vocabulary.ts +0 -82
  244. package/server/engine/oee-accumulator.ts +0 -195
  245. package/server/engine/operation-basis.ts +0 -131
  246. package/server/engine/producer-guard.ts +0 -64
  247. package/server/engine/property-effects.ts +0 -216
  248. package/server/engine/read-time.ts +0 -77
  249. package/server/engine/restart-policy.ts +0 -55
  250. package/server/engine/runtime-key.ts +0 -58
  251. package/server/engine/spec-coverage.ts +0 -105
  252. package/server/engine/stage-path.ts +0 -172
  253. package/server/engine/state-axes.ts +0 -60
  254. package/server/engine/structure-diff.ts +0 -88
  255. package/server/engine/travel-estimator.ts +0 -138
  256. package/server/engine/twin-engine.ts +0 -4979
  257. package/server/engine/twin-state-channel.ts +0 -39
  258. package/server/engine/warm-start.ts +0 -265
  259. package/server/index.ts +0 -90
  260. package/server/migrations/1786000000000-RenameTwinInstanceBoardToModel.ts +0 -43
  261. package/server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.ts +0 -54
  262. package/server/migrations/1786200000000-CarryLiveFeedCursor.ts +0 -53
  263. package/server/migrations/1786300000000-IndexEventTypeByTime.ts +0 -48
  264. package/server/migrations/1786400000000-IndexEventCreatedAt.ts +0 -38
  265. package/server/migrations/1786500000000-CreateTwinSubjectEvents.ts +0 -93
  266. package/server/migrations/1786600000000-RenameOperatoMesAdapterType.ts +0 -66
  267. package/server/migrations/1786700000000-AddDispatchRetryColumns.ts +0 -82
  268. package/server/migrations/1786800000000-CreateTwinReferenceReconciliations.ts +0 -39
  269. package/server/migrations/index.ts +0 -25
  270. package/server/routes.ts +0 -75
  271. package/server/service/actuation/actuation-advisor.ts +0 -131
  272. package/server/service/actuation/actuation-outcome.ts +0 -97
  273. package/server/service/actuation/actuation-rule-resolver.ts +0 -147
  274. package/server/service/actuation/actuation-rule.ts +0 -139
  275. package/server/service/actuation/approval-gateway.ts +0 -44
  276. package/server/service/actuation/catch-up-effects.ts +0 -152
  277. package/server/service/actuation/command-dispatcher.ts +0 -474
  278. package/server/service/actuation/command-store.ts +0 -236
  279. package/server/service/actuation/dispatch-after-approval.ts +0 -71
  280. package/server/service/actuation/effect-match.ts +0 -124
  281. package/server/service/actuation/index.ts +0 -27
  282. package/server/service/actuation/retry-plan.ts +0 -145
  283. package/server/service/actuation/rule-evaluate.ts +0 -352
  284. package/server/service/actuation/rule-loop.ts +0 -160
  285. package/server/service/actuation/rule-runner.ts +0 -216
  286. package/server/service/actuation/rule-wiring.ts +0 -84
  287. package/server/service/actuation/settle-effects.ts +0 -115
  288. package/server/service/actuation/sweep-dispatch.ts +0 -179
  289. package/server/service/actuation/twin-command-resolver.ts +0 -387
  290. package/server/service/actuation/twin-command.ts +0 -232
  291. package/server/service/actuation/twin-now.ts +0 -97
  292. package/server/service/index.ts +0 -100
  293. package/server/service/reference/actuation-routing.ts +0 -192
  294. package/server/service/reference/actuation-target.ts +0 -163
  295. package/server/service/reference/actuation-verification.ts +0 -85
  296. package/server/service/reference/attention-lane.ts +0 -21
  297. package/server/service/reference/connection-portability-resolver.ts +0 -171
  298. package/server/service/reference/connection-portability.ts +0 -329
  299. package/server/service/reference/control-routing.ts +0 -62
  300. package/server/service/reference/discovery-result.ts +0 -95
  301. package/server/service/reference/fill-cadence.ts +0 -29
  302. package/server/service/reference/fill-dedupe.ts +0 -66
  303. package/server/service/reference/fill-loop.ts +0 -153
  304. package/server/service/reference/fill-span.ts +0 -31
  305. package/server/service/reference/hook-contract.ts +0 -364
  306. package/server/service/reference/hook-rejected.ts +0 -53
  307. package/server/service/reference/hook-store.ts +0 -28
  308. package/server/service/reference/index.ts +0 -18
  309. package/server/service/reference/ingest-space.ts +0 -104
  310. package/server/service/reference/knob-defaults.ts +0 -59
  311. package/server/service/reference/live-cadence.ts +0 -129
  312. package/server/service/reference/live-feed-lease.ts +0 -56
  313. package/server/service/reference/live-ingest.ts +0 -94
  314. package/server/service/reference/reference-adapter.ts +0 -985
  315. package/server/service/reference/reference-assessment.ts +0 -250
  316. package/server/service/reference/reference-fill-run.ts +0 -179
  317. package/server/service/reference/reference-fill.ts +0 -223
  318. package/server/service/reference/reference-hook.ts +0 -479
  319. package/server/service/reference/reference-link-groups.ts +0 -21
  320. package/server/service/reference/reference-links.ts +0 -77
  321. package/server/service/reference/reference-live.ts +0 -420
  322. package/server/service/reference/reference-master.ts +0 -999
  323. package/server/service/reference/reference-probe.ts +0 -264
  324. package/server/service/reference/reference-progress-channel.ts +0 -26
  325. package/server/service/reference/reference-progress-subscription.ts +0 -78
  326. package/server/service/reference/reference-progress.ts +0 -95
  327. package/server/service/reference/reference-reconciliation-query.ts +0 -28
  328. package/server/service/reference/reference-reconciliation-writer.ts +0 -38
  329. package/server/service/reference/reference-reconciliation.ts +0 -55
  330. package/server/service/reference/reference-registry.ts +0 -17
  331. package/server/service/reference/reference-resolver.ts +0 -969
  332. package/server/service/reference/template-registry.ts +0 -85
  333. package/server/service/reference/twin-reference-reconciliation.ts +0 -27
  334. package/server/service/reference/twin-reference.ts +0 -190
  335. package/server/service/twin-attention/index.ts +0 -3
  336. package/server/service/twin-attention/twin-attention-query.ts +0 -70
  337. package/server/service/twin-audit/command-audit.ts +0 -114
  338. package/server/service/twin-audit/index.ts +0 -5
  339. package/server/service/twin-audit/twin-audit-event.ts +0 -158
  340. package/server/service/twin-audit/twin-audit-query.ts +0 -72
  341. package/server/service/twin-backfill/backfill-period-facts.ts +0 -168
  342. package/server/service/twin-backfill/backfill-shape.ts +0 -86
  343. package/server/service/twin-backfill/index.ts +0 -3
  344. package/server/service/twin-backfill/twin-backfill-resolver.ts +0 -35
  345. package/server/service/twin-control/index.ts +0 -3
  346. package/server/service/twin-control/twin-control-mutation.ts +0 -150
  347. package/server/service/twin-event/index.ts +0 -3
  348. package/server/service/twin-event/journal-count.ts +0 -53
  349. package/server/service/twin-event/twin-event-keys.ts +0 -215
  350. package/server/service/twin-event/twin-event-type.ts +0 -68
  351. package/server/service/twin-event/twin-event.ts +0 -250
  352. package/server/service/twin-forecast/forecast-metrics.ts +0 -106
  353. package/server/service/twin-forecast/forecast-tuning.ts +0 -40
  354. package/server/service/twin-forecast/gap-analytics.ts +0 -139
  355. package/server/service/twin-forecast/index.ts +0 -3
  356. package/server/service/twin-forecast/twin-forecast-query.ts +0 -486
  357. package/server/service/twin-ingest-window/index.ts +0 -7
  358. package/server/service/twin-ingest-window/twin-ingest-window-query.ts +0 -125
  359. package/server/service/twin-ingest-window/twin-ingest-window-writer.ts +0 -57
  360. package/server/service/twin-ingest-window/twin-ingest-window.ts +0 -113
  361. package/server/service/twin-instance/index.ts +0 -3
  362. package/server/service/twin-instance/twin-instance.ts +0 -199
  363. package/server/service/twin-journal/event-type-split-shape.ts +0 -112
  364. package/server/service/twin-journal/event-type-split.ts +0 -144
  365. package/server/service/twin-journal/index.ts +0 -3
  366. package/server/service/twin-journal/journal-order.ts +0 -20
  367. package/server/service/twin-journal/twin-journal-query.ts +0 -615
  368. package/server/service/twin-lifecycle/domain-catalog.ts +0 -51
  369. package/server/service/twin-lifecycle/index.ts +0 -3
  370. package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +0 -285
  371. package/server/service/twin-metrics/index.ts +0 -3
  372. package/server/service/twin-metrics/twin-metrics-query.ts +0 -172
  373. package/server/service/twin-model/axis-journal-evidence.ts +0 -57
  374. package/server/service/twin-model/choose-recipe.ts +0 -31
  375. package/server/service/twin-model/epcis-coverage.ts +0 -251
  376. package/server/service/twin-model/external-resolver.ts +0 -173
  377. package/server/service/twin-model/iec61850-coverage.ts +0 -111
  378. package/server/service/twin-model/index.ts +0 -25
  379. package/server/service/twin-model/isa95-coverage.ts +0 -320
  380. package/server/service/twin-model/item-ref.ts +0 -80
  381. package/server/service/twin-model/name-index.ts +0 -94
  382. package/server/service/twin-model/project-structure.ts +0 -213
  383. package/server/service/twin-model/standard-coverage.ts +0 -35
  384. package/server/service/twin-model/status-tally.ts +0 -37
  385. package/server/service/twin-model/twin-equipment.ts +0 -191
  386. package/server/service/twin-model/twin-lineage-query.ts +0 -327
  387. package/server/service/twin-model/twin-location.ts +0 -147
  388. package/server/service/twin-model/twin-model-item-query.ts +0 -1029
  389. package/server/service/twin-model/twin-model-mutation.ts +0 -503
  390. package/server/service/twin-model/twin-model-query.ts +0 -792
  391. package/server/service/twin-model/twin-model-tree-query.ts +0 -211
  392. package/server/service/twin-model/twin-operation.ts +0 -157
  393. package/server/service/twin-readiness/index.ts +0 -3
  394. package/server/service/twin-readiness/twin-readiness-query.ts +0 -96
  395. package/server/service/twin-space/area-resolver.ts +0 -75
  396. package/server/service/twin-space/index.ts +0 -8
  397. package/server/service/twin-space/move-space.ts +0 -262
  398. package/server/service/twin-space/representation-role.ts +0 -15
  399. package/server/service/twin-space/space-integrity.ts +0 -293
  400. package/server/service/twin-space/twin-area.ts +0 -63
  401. package/server/service/twin-space/twin-space-area.ts +0 -66
  402. package/server/service/twin-space/twin-space-representation.ts +0 -99
  403. package/server/service/twin-space/twin-space-resolver.ts +0 -582
  404. package/server/service/twin-space/twin-space.ts +0 -148
  405. package/server/service/twin-state/index.ts +0 -3
  406. package/server/service/twin-state/twin-state-subscription.ts +0 -62
  407. package/server/service/twin-structure/index.ts +0 -3
  408. package/server/service/twin-structure/twin-structure.ts +0 -96
  409. package/server/service/twin-subject/event-subjects.ts +0 -162
  410. package/server/service/twin-subject/index.ts +0 -10
  411. package/server/service/twin-subject/item-resolver.ts +0 -92
  412. package/server/service/twin-subject/subject-query-shape.ts +0 -84
  413. package/server/service/twin-subject/twin-subject-backfill.ts +0 -196
  414. package/server/service/twin-subject/twin-subject-event.ts +0 -101
  415. package/server/service/twin-subject/twin-subject-fast-path.ts +0 -346
  416. package/server/service/twin-subject/twin-subject-query.ts +0 -210
  417. package/server/service/twin-subject/twin-subject-writer.ts +0 -189
  418. package/server/service/twin-target/index.ts +0 -5
  419. package/server/service/twin-target/twin-target-resolver.ts +0 -142
  420. package/server/service/twin-target/twin-target.ts +0 -97
  421. package/server/types/global.d.ts +0 -22
  422. package/shared/axis-read.ts +0 -28
  423. package/shared/entity-delta.ts +0 -335
  424. package/shared/kpi-broadcast.ts +0 -13
  425. package/shared/touched-items.ts +0 -73
  426. package/shared/twin-level.ts +0 -48
  427. package/test/ack-shape-alignment.test.ts +0 -97
  428. package/test/actuation-advisor.test.ts +0 -55
  429. package/test/actuation-approval-door.test.ts +0 -411
  430. package/test/actuation-dispatch.test.ts +0 -209
  431. package/test/actuation-effect.test.ts +0 -162
  432. package/test/actuation-outcome.test.ts +0 -152
  433. package/test/actuation-rule-runner.test.ts +0 -281
  434. package/test/actuation-rule.test.ts +0 -266
  435. package/test/actuation-seam.test.ts +0 -255
  436. package/test/actuation-settle.test.ts +0 -164
  437. package/test/actuation-target.test.ts +0 -145
  438. package/test/actuation-verification-state.test.ts +0 -139
  439. package/test/adopt-structure-live.test.ts +0 -133
  440. package/test/aggregate-not-findone.test.ts +0 -112
  441. package/test/area-resolver-db.test.ts +0 -110
  442. package/test/attention-digest.test.ts +0 -161
  443. package/test/axis-declaration-passthrough-db.test.ts +0 -152
  444. package/test/axis-journal-evidence.test.ts +0 -71
  445. package/test/axis-read.test.ts +0 -188
  446. package/test/backfill-shape.test.ts +0 -89
  447. package/test/boot-resume.test.ts +0 -287
  448. package/test/broadcast-cost-baseline.test.ts +0 -201
  449. package/test/broadcast-period.test.ts +0 -58
  450. package/test/broadcast-queue-overflow.test.ts +0 -244
  451. package/test/canonical-ingest-vocabularies.test.ts +0 -451
  452. package/test/canonical-quantity-door.test.ts +0 -61
  453. package/test/capability-mapping.test.ts +0 -89
  454. package/test/checkpoint-refuses-empty.test.ts +0 -103
  455. package/test/choose-recipe.test.ts +0 -117
  456. package/test/column-type-portability.test.ts +0 -122
  457. package/test/command-routing.test.ts +0 -61
  458. package/test/command-store-writes-columns.test.ts +0 -126
  459. package/test/connection-portability-doors.test.ts +0 -87
  460. package/test/connector-capability-declaration.test.ts +0 -195
  461. package/test/contract-layer-guard.test.ts +0 -48
  462. package/test/control-capability.test.ts +0 -98
  463. package/test/cursor-stall-not-read-failure.test.ts +0 -126
  464. package/test/declaration-reaches-model.test.ts +0 -226
  465. package/test/declared-location-types.test.ts +0 -89
  466. package/test/declared-stimulus.test.ts +0 -88
  467. package/test/dedupe-transformation.test.ts +0 -112
  468. package/test/discovery-result.test.ts +0 -75
  469. package/test/dispatch-after-approval-source.test.ts +0 -81
  470. package/test/duration-estimators.test.ts +0 -144
  471. package/test/energy-topology.test.ts +0 -113
  472. package/test/entity-delta.test.ts +0 -352
  473. package/test/equipment-identity-reaches.test.ts +0 -57
  474. package/test/event-subjects.test.ts +0 -148
  475. package/test/event-time-column.test.ts +0 -67
  476. package/test/event-type-split.test.ts +0 -178
  477. package/test/external-resolver.test.ts +0 -177
  478. package/test/fact-scope-wiring.test.ts +0 -96
  479. package/test/fill-dedupe.test.ts +0 -59
  480. package/test/fill-loop.test.ts +0 -35
  481. package/test/first-envelope.test.ts +0 -153
  482. package/test/fold-gap-speaks.test.ts +0 -53
  483. package/test/fold-shift-dst.test.ts +0 -110
  484. package/test/forecast-metrics.test.ts +0 -157
  485. package/test/forecast-tuning.test.ts +0 -42
  486. package/test/gap-analytics.test.ts +0 -113
  487. package/test/generated-not-counted.test.ts +0 -99
  488. package/test/guard-roots.ts +0 -76
  489. package/test/home-in-area.test.ts +0 -90
  490. package/test/hook-address.test.ts +0 -28
  491. package/test/hook-rejected-shape.test.ts +0 -86
  492. package/test/hook-response-sum.test.ts +0 -193
  493. package/test/hook-sequence.test.ts +0 -333
  494. package/test/ingest-bench.test.ts +0 -70
  495. package/test/ingest-dedupe.test.ts +0 -56
  496. package/test/ingest-expected-quiet.test.ts +0 -111
  497. package/test/ingest-health-engine.test.ts +0 -248
  498. package/test/ingest-health-wiring.test.ts +0 -120
  499. package/test/ingest-health.test.ts +0 -306
  500. package/test/ingest-history.test.ts +0 -247
  501. package/test/ingest-idempotent.test.ts +0 -211
  502. package/test/ingest-reconcile-four-ways.test.ts +0 -97
  503. package/test/ingest-rules-header.test.ts +0 -100
  504. package/test/ingest-running-guard.test.ts +0 -136
  505. package/test/ingest-space.test.ts +0 -78
  506. package/test/ingest-window-rolls-unobserved.test.ts +0 -72
  507. package/test/ingest-wiring-guard.test.ts +0 -197
  508. package/test/instance-cache-lifecycle.test.ts +0 -110
  509. package/test/intake-mapping-parity.test.ts +0 -175
  510. package/test/integration-probes.test.ts +0 -103
  511. package/test/integration-runner.test.ts +0 -95
  512. package/test/item-ref.test.ts +0 -78
  513. package/test/journal-order-axis.test.ts +0 -80
  514. package/test/journal-read-discipline.test.ts +0 -186
  515. package/test/journal-retention.test.ts +0 -275
  516. package/test/journal-sort-axis.test.ts +0 -142
  517. package/test/journal-write-door.test.ts +0 -110
  518. package/test/journal-write-trend.test.ts +0 -115
  519. package/test/kernel-kind-guard.test.ts +0 -98
  520. package/test/knob-defaults.test.ts +0 -72
  521. package/test/kpi-baseline-db.test.ts +0 -216
  522. package/test/kpi-baseline.test.ts +0 -196
  523. package/test/kpi-fold.test.ts +0 -1456
  524. package/test/kpi-query-bench.test.ts +0 -130
  525. package/test/lens-own-places.test.ts +0 -50
  526. package/test/lineage-survives-restart.test.ts +0 -234
  527. package/test/live-cadence.test.ts +0 -170
  528. package/test/live-cursor-wiring.test.ts +0 -87
  529. package/test/live-feed-lease.test.ts +0 -63
  530. package/test/live-feed-registry.test.ts +0 -75
  531. package/test/live-kernel-facts.test.ts +0 -161
  532. package/test/live-mirror-parity.test.ts +0 -286
  533. package/test/load-meter.test.ts +0 -328
  534. package/test/local-declarations.test.ts +0 -662
  535. package/test/log-stamp.test.ts +0 -59
  536. package/test/loop-lag.test.ts +0 -82
  537. package/test/master-to-twin.test.ts +0 -279
  538. package/test/measured-yield.test.ts +0 -90
  539. package/test/merge-streams.test.ts +0 -70
  540. package/test/mirror-resumes-from-checkpoint.test.ts +0 -192
  541. package/test/model-basis.test.ts +0 -141
  542. package/test/model-gap.test.ts +0 -153
  543. package/test/model-refusal.test.ts +0 -75
  544. package/test/model-vocabulary.test.ts +0 -114
  545. package/test/move-space.test.ts +0 -149
  546. package/test/mutation-gate.test.ts +0 -122
  547. package/test/oee-accumulator.test.ts +0 -204
  548. package/test/oee-site-calendar.test.ts +0 -146
  549. package/test/open-doors.test.ts +0 -197
  550. package/test/operation-basis.test.ts +0 -127
  551. package/test/operational-vocabulary.test.ts +0 -108
  552. package/test/operations-capability-db.test.ts +0 -165
  553. package/test/order-and-transaction-split.test.ts +0 -107
  554. package/test/order-fold-host.test.ts +0 -112
  555. package/test/producer-guard.test.ts +0 -66
  556. package/test/project-structure-db.test.ts +0 -226
  557. package/test/projection-reaches-screen.test.ts +0 -277
  558. package/test/projection-reads-declared.test.ts +0 -109
  559. package/test/property-effects.test.ts +0 -128
  560. package/test/provenance-promotion.test.ts +0 -99
  561. package/test/read-failure-ledger.test.ts +0 -106
  562. package/test/read-failure-visible.test.ts +0 -145
  563. package/test/read-time.test.ts +0 -118
  564. package/test/reference-fill.test.ts +0 -235
  565. package/test/reference-grounding.test.ts +0 -70
  566. package/test/reference-hook.test.ts +0 -177
  567. package/test/reference-links.test.ts +0 -56
  568. package/test/reference-reconciliation.test.ts +0 -39
  569. package/test/registry-key-guard.test.ts +0 -80
  570. package/test/rejection-carries-event-id.test.ts +0 -101
  571. package/test/rename-twin.test.ts +0 -89
  572. package/test/resolve-ts-siblings.mjs +0 -52
  573. package/test/restart-policy.test.ts +0 -111
  574. package/test/resync-origin-site.test.ts +0 -83
  575. package/test/retry-plan.test.ts +0 -139
  576. package/test/revision-axis.test.ts +0 -110
  577. package/test/runtime-key.test.ts +0 -66
  578. package/test/save-intake-collision.test.ts +0 -91
  579. package/test/scale-twin-bench.test.ts +0 -103
  580. package/test/secrets-at-rest.test.ts +0 -135
  581. package/test/snapshot-freshness.test.ts +0 -60
  582. package/test/source-outcome-audit.test.ts +0 -104
  583. package/test/space-integrity.test.ts +0 -223
  584. package/test/space-representation.test.ts +0 -66
  585. package/test/space-scope-includes-stopped.test.ts +0 -55
  586. package/test/spec-coverage.test.ts +0 -113
  587. package/test/stage-path.test.ts +0 -95
  588. package/test/standard-coverage.test.ts +0 -148
  589. package/test/state-axes.test.ts +0 -74
  590. package/test/status-tally.test.ts +0 -55
  591. package/test/streamline-e2e.test.ts +0 -76
  592. package/test/structure-revision-db.test.ts +0 -315
  593. package/test/subject-fast-path.test.ts +0 -148
  594. package/test/subject-read-model.test.ts +0 -175
  595. package/test/sweep-dispatch.test.ts +0 -191
  596. package/test/tenant-registry-db.test.ts +0 -149
  597. package/test/time-range.test.ts +0 -152
  598. package/test/touched-items.test.ts +0 -61
  599. package/test/twin-audit.test.ts +0 -83
  600. package/test/twin-event-keys.test.ts +0 -193
  601. package/test/twin-model-item-db.test.ts +0 -319
  602. package/test/twin-model-parent-relation-db.test.ts +0 -125
  603. package/test/twin-model-tree-db.test.ts +0 -209
  604. package/test/twin-origin-resync.test.ts +0 -133
  605. package/test/twin-state-channel.test.ts +0 -111
  606. package/test/vocabulary-guard.test.ts +0 -43
  607. package/test/warm-start-seam.test.ts +0 -162
  608. package/test/warm-start.test.ts +0 -297
  609. package/test/withheld-door.test.ts +0 -95
  610. package/test/yield-loop.test.ts +0 -199
  611. package/tsconfig.json +0 -15
  612. package/tsconfig.shared.json +0 -23
  613. package/tsconfig.shared.tsbuildinfo +0 -1
  614. package/tsconfig.tsbuildinfo +0 -1
@@ -1,57 +0,0 @@
1
- import { twinWarn } from '../../engine/log.js'
2
- import { getRepository } from '@things-factory/shell'
3
-
4
- import { TwinEngine } from '../../engine/index.js'
5
- import { TwinIngestWindow } from './twin-ingest-window.js'
6
-
7
- /*
8
- * 닫힌 창을 표로 옮긴다 — **영속이 붙는 유일한 자리.**
9
- *
10
- * 커널 층(`engine/ingest-health.ts`)은 저장 계층을 모른다. 창이 닫힐 때 부를 곳을 엔진이 문으로 열어
11
- * 두었고(`onIngestWindowClosed`), 이 파일이 부팅에서 한 번 등록한다. 그래서 기록 경로가 갈리지 않는다.
12
- *
13
- * ── 실패를 삼키지 않는다 ────────────────────────────────────────────────────
14
- * 쓰기가 터져도 메모리 장부는 계속 굴러간다(`rollIngestWindow` 가 훅을 감싼다). 다만 **알리지 않고 넘기지는
15
- * 않는다** — 실패를 로그로 남긴다. 그러지 않으면 추이 표에 구멍이 생긴 이유를 나중에 알 수 없다.
16
- *
17
- * ── 왜 await 하지 않나 ──────────────────────────────────────────────────────
18
- * 이 훅은 인제스트 경로에서 불린다(라이브 피드의 콜백 안). 여기서 DB 를 기다리면 **유입이 DB 속도에
19
- * 묶인다** — 이 기능이 막으려던 부하가 그 모양으로 돌아온다. 그래서 띄워 보내고 결과만 로그로 받는다.
20
- */
21
- export function installIngestWindowWriter(): void {
22
- TwinEngine.onIngestWindowClosed((at, closed) => {
23
- const repo = getRepository(TwinIngestWindow)
24
- const offered = closed.offered
25
- repo
26
- .save(
27
- repo.create({
28
- domain: { id: at.domainId } as any,
29
- instanceId: at.instanceId,
30
- openedAt: new Date(closed.startMs),
31
- closedAt: new Date(closed.endMs),
32
- offered,
33
- rejected: closed.rejected,
34
- undelivered: closed.undelivered,
35
- /* 적힌 것도 같은 행에 — 창이 유입 없이 닫혔어도(시뮬) 이 두 수는 사실이다. */
36
- journaledRows: closed.rows,
37
- journalFlushes: closed.flushes,
38
- /*
39
- * 제시가 0 이면 비워 둔다 — 1 로 채우면 「전부 통과」로 읽힌다.
40
- * 통과는 **트윈에 닿은** 것만이다: 버려진 것을 빼지 않으면 멈춘 트윈의 창이 100% 로 남는다.
41
- */
42
- ...(offered > 0
43
- ? { acceptedRatio: round4((offered - closed.rejected - closed.undelivered) / offered) }
44
- : {})
45
- })
46
- )
47
- .catch(err =>
48
- twinWarn(
49
- `[twin-ingest-window] "${at.instanceId}" window not persisted (trend will have a gap here):`,
50
- err?.message ?? err
51
- )
52
- )
53
- })
54
- }
55
-
56
- /** 0.999 가 1 로 반올림되면 「전부 통과」로 읽힌다 — 자릿수를 넉넉히 준다(메모리 장부와 같은 규칙). */
57
- const round4 = (v: number) => Math.round(v * 10000) / 10000
@@ -1,113 +0,0 @@
1
- import { CreateDateColumn, Entity, Index, Column, RelationId, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'
2
- import { ObjectType, Field, ID, Int, Float } from 'type-graphql'
3
-
4
- import { Domain } from '@things-factory/shell'
5
-
6
- /*
7
- * 인제스트 창 하나 — **동기화 추이를 재기동 뒤에도 이어 보기 위한 행.**
8
- *
9
- * ── 왜 창마다이고 건마다가 아닌가 ───────────────────────────────────────────
10
- * 거부마다 행을 쓰면 라이브 계측 규모에서 초당 1만 행이고, 그 부하가 이벤트 루프로 돌아온다. 창마다면
11
- * 트윈 1,000개에 하루 14.4만 행(약 14MB)이다. 그래서 **닫힌 창 하나가 영속의 단위**다.
12
- *
13
- * 건마다 남기는 자리는 이미 따로 있다: 시나리오 경로가 `PayloadLog` 로 dead-letter 를 남긴다(배치성
14
- * 유입이라 건수가 감당된다). 이 표는 그것을 대신하지 않고 **추이**를 답한다.
15
- *
16
- * ── 왜 사유·표본은 여기 없나 ────────────────────────────────────────────────
17
- * 사유 문구는 길고 표본에는 **고객의 레코드 원문**이 들어 있다. 그것을 창마다 영속하면 표가 커지고
18
- * 고객 데이터가 오래 남는다. 사유와 표본은 메모리 장부가 답하고(최근 6시간), 이 표는 숫자만 든다.
19
- *
20
- * ── 고치지 않는다 ───────────────────────────────────────────────────────────
21
- * 닫힌 창은 지나간 사실이다. 그래서 `updatedAt`·`deletedAt` 을 두지 않는다(저널과 같은 규율).
22
- */
23
- @Entity()
24
- @Index('ix_twin_ingest_window_0', (e: TwinIngestWindow) => [e.domain, e.instanceId, e.closedAt], { unique: false })
25
- @ObjectType({
26
- description:
27
- 'One closed ingest window for a twin: how many records were offered, accepted and rejected between two times. Written when a window closes (about every 10 minutes per twin) so the sync trend survives a restart and reaches further back than the in-memory ledger. Reasons and rejected-record samples are deliberately not stored here — they live in the in-memory ledger, which covers roughly the last 6 hours.'
28
- })
29
- export class TwinIngestWindow {
30
- @PrimaryGeneratedColumn('uuid')
31
- @Field(type => ID, { description: 'Unique identifier of the window record.' })
32
- readonly id: string
33
-
34
- @ManyToOne(type => Domain)
35
- @Field(type => Domain, { nullable: true, description: 'Owning tenant domain.' })
36
- domain?: Domain
37
-
38
- @RelationId((e: TwinIngestWindow) => e.domain)
39
- domainId?: string
40
-
41
- @Column()
42
- @Field({ description: 'Twin runtime instance this window belongs to.' })
43
- instanceId: string
44
-
45
- @Column()
46
- @Field({ description: 'When the window opened.' })
47
- openedAt: Date
48
-
49
- @Column()
50
- @Field({ description: 'When the window closed. Windows close on the next ingest after the window length elapses, so a feed that stops leaves its last window open and unwritten.' })
51
- closedAt: Date
52
-
53
- @Column({ type: 'int' })
54
- @Field(type => Int, { description: 'Records offered in this window, whether or not they were accepted.' })
55
- offered: number
56
-
57
- @Column({ type: 'int' })
58
- @Field(type => Int, { description: 'Records the kernel refused in this window because they did not map — the fix is in the mapping.' })
59
- rejected: number
60
-
61
- /*
62
- * 거부와 따로 센다 — **처방이 다르다.**
63
- *
64
- * 트윈이 라이브로 돌지 않으면 커널이 레코드를 버린다. 그것을 거부에 합치면 「매핑을 고쳐라」로 읽히고,
65
- * 통과에 합치면 멈춘 트윈이 100% 로 보인다(실제로 그렇게 떴다). 그래서 제3의 수로 남긴다.
66
- */
67
- @Column({ type: 'int', default: 0 })
68
- @Field(type => Int, {
69
- description:
70
- 'Records that mapped fine but never reached the twin, because the twin was not running live while the feed kept delivering. Distinct from rejected: the fix here is to start the twin or disconnect the feed, not to change the mapping. Offered minus rejected minus undelivered is what actually reached the twin.'
71
- })
72
- undelivered: number
73
-
74
- /*
75
- * 통과율을 **함께 적는다.** 읽는 쪽에서 나누게 하면 소비처마다 반올림이 갈리고(0.999 를 1 로 쓰는
76
- * 곳이 생긴다), 제시가 0 인 창에서 0으로 나누는 실수가 각자 생긴다. 제시가 0 이면 **비어 둔다** —
77
- * 1 로 채우면 「전부 통과」로 읽힌다.
78
- */
79
- @Column({ type: 'float', nullable: true })
80
- @Field(type => Float, {
81
- nullable: true,
82
- description:
83
- 'Share of offered records that reached the twin (0–1), rounded to four places. Null when nothing was offered in this window — an empty window is not a perfect one, and writing 1 there would read as "everything passed".'
84
- })
85
- acceptedRatio?: number
86
-
87
- /*
88
- * ── 적힌 것도 같은 창에 든다 ────────────────────────────────────────────────
89
- * 유입과 **다른 축**이다. 시뮬 트윈은 받는 것 없이 자기가 낸 사실을 적으므로 `offered` 가 0 이고
90
- * `journaledRows` 는 0 이 아니다. 이 칸이 없으면 도는 트윈 대부분이 시뮬인 서버의 활동이 어느 추이에도
91
- * 남지 않는다(계기는 지금만 답하고 재기동에 0 으로 돌아간다).
92
- *
93
- * 두 수를 따로 세는 이유: 2026-08-20 에 고친 것이 **행당 왕복**이다(델타마다 한 번 → 창당 한 번).
94
- * 행만 세면 그 개선도, 되돌아가는 것도 보이지 않는다.
95
- */
96
- @Column({ type: 'int', default: 0 })
97
- @Field(type => Int, {
98
- description:
99
- 'Journal rows written for this twin during this window. This is a different axis from ingest: a twin driven by a simulator source receives nothing (offered = 0) yet writes what it produces, so without this column its activity appears in no trend at all.'
100
- })
101
- journaledRows: number
102
-
103
- @Column({ type: 'int', default: 0 })
104
- @Field(type => Int, {
105
- description:
106
- 'Number of journal write round-trips (flushes) behind those rows. Counted separately from the rows themselves so that a regression back to per-delta writes — the defect fixed on 2026-08-20, where each kernel delta cost one insert — is visible as rows-per-flush falling back towards 1.'
107
- })
108
- journalFlushes: number
109
-
110
- @CreateDateColumn()
111
- @Field({ nullable: true, description: 'When this record was written.' })
112
- createdAt?: Date
113
- }
@@ -1,3 +0,0 @@
1
- import { TwinInstance } from './twin-instance.js'
2
-
3
- export const entities = [TwinInstance]
@@ -1,199 +0,0 @@
1
- import { CreateDateColumn, Entity, Index, Column, RelationId, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'
2
- import { ObjectType, Field, ID } from 'type-graphql'
3
-
4
- import { Domain, ScalarObject } from '@things-factory/shell'
5
- import { User } from '@things-factory/auth-base'
6
- import { modelColumnTransformer } from '../../engine/model-vocabulary.js'
7
-
8
- /*
9
- * TwinInstance — 트윈 인스턴스 레지스트리(재부팅 복구의 앵커).
10
- * 복구(DB→replay)는 model(마스터 청사진)가 있어야 이벤트를 상태로 다시 계산할 수 있다 → model·kind 를 영속.
11
- * 이벤트(TwinEvent)와 달리 가변(status 갱신) — 인스턴스의 "현재 등록 상태".
12
- * model 는 simple-json(멀티DB 이식 — postgres/mysql/sqlite/mssql/oracle 공통).
13
- * (CLAUDE.md: 모든 @ObjectType/@Field 는 영문 description 필수.)
14
- */
15
- @Entity()
16
- @Index('ix_twin_instance_0', (e: TwinInstance) => [e.domain, e.instanceId], { unique: true })
17
- @Index('ix_twin_instance_1', (e: TwinInstance) => [e.domain, e.spaceId]) // 공간→인스턴스 1급 질의(공간 중심 존재론)
18
- @ObjectType({ description: 'Registry of a hosted twin runtime instance — anchors reboot recovery (model + kind).' })
19
- export class TwinInstance {
20
- @PrimaryGeneratedColumn('uuid')
21
- @Field(type => ID, { description: 'Unique identifier of the registry record.' })
22
- readonly id: string
23
-
24
- @ManyToOne(type => Domain)
25
- @Field(type => Domain, { nullable: true, description: 'Owning tenant domain.' })
26
- domain?: Domain
27
-
28
- @RelationId((e: TwinInstance) => e.domain)
29
- domainId?: string
30
-
31
- @Column()
32
- @Field({ description: 'Twin runtime instance id (unique within a domain).' })
33
- instanceId: string
34
-
35
- /**
36
- * **사람이 부르는 이름** — 업무키(`instanceId`)와 나란히 두는 표시명(프레임워크 엔티티 규약).
37
- *
38
- * ── 왜 업무키와 이름을 나눠 두나 ─────────────────────────────────────────────
39
- * `instanceId` 는 URL·저널·구독이 전부 쓰는 **계약**이라 바꿀 수 없다. 반대로 이름은 바뀌고,
40
- * 중복되고(사이트 둘에 "도장" 이 있는 것이 정상), 언어마다 다르다. 둘을 한 컬럼에 담으면 개명이
41
- * 곧 다른 트윈이 되고 재동기가 끊긴다 — 그래서 나눈다(이 저장소에서 식별자가 밖에서 오는 것은
42
- * 전부 이 규약을 쓴다: `spaceId`·`locationId`·`equipmentId`·`operationKey`).
43
- *
44
- * 나눴으면 **이름을 반드시 함께 둬야 한다.** 이 자리가 없던 동안 사이트 이름은 model 안에만 있어서
45
- * 목록이 `crew-two` 만 보였다 — 나누기만 하고 절반을 빼먹으면 화면에는 id 만 남는다.
46
- *
47
- * 원본이 이름을 말하지 않으면 비운다(id 를 베끼지 않는다).
48
- */
49
- @Column({ nullable: true })
50
- @Field({ nullable: true, description: 'Human name of this twin (the site name from its master). Empty when the source does not name it — never copied from instanceId.' })
51
- name?: string
52
-
53
- @Column({ nullable: true })
54
- @Field({ nullable: true, description: 'Longer description when the source provides one.' })
55
- description?: string
56
-
57
- /* 어느 도메인 커널이 이 트윈을 운영하는가. 커널 없는 트윈은 없으므로 비어 있을 수 없다
58
- (`TwinEngine.start`·`register` 모두 필수 인자로 받는다). */
59
- @Column()
60
- @Field({ description: 'Domain kernel kind: wms | yms | mes.' })
61
- kind: string
62
-
63
- /*
64
- * **재기동 정책** — 이 트윈은 다시 세워질 때 자기 과거를 어떻게 대하나(ADR-0029 §2).
65
- *
66
- * 'resync' = 외부 실물에서 다시 읽는다(원본이 진실이므로 우리 과거를 이어 붙이지 않는다 → startLive).
67
- * 'resume' = 저널을 이어 세운다(이 트윈이 낳은 타임라인이 곧 사실이다).
68
- * 'reset' = 저널을 비우고 씨앗부터 다시 돌린다(재현 가능한 실험 — 백지 시작이 선언된 거동이다).
69
- *
70
- * ── 왜 트윈에 남았나 (옛 이름 `realityMode`) ────────────────────────────────
71
- * 「현실이 어디서 오나」는 ADR-0029 가 **원본의 종류**로 옮긴 물음이다(`TwinReference.adapterType`) —
72
- * 트윈은 한 종류이고 언제나 원본을 반영한다. 그런데 코드가 이 축으로 실제로 가른 것은 **재기동 거동
73
- * 하나**였고, 그것은 원본의 성질이 아니라 **트윈과 자기 과거의 관계**다: 같은 시뮬레이터 원본을 보는 두
74
- * 트윈이 하나는 이어가고 하나는 매번 처음부터 재현할 수 있다. 그래서 축은 남고 이름만 바뀌었다.
75
- *
76
- * **비어 있을 수 없고, 기본값도 없다.** 예전에는 미선언이 알리지 않고 `sim-experiment`(=저널 초기화)로
77
- * 떨어졌다 — 값이 하나 어긋나는 순간 이력을 지우는 길이다. 이제 읽는 쪽이 **오류를 낸다**
78
- * (`engine/restart-policy.ts`). 선언은 프로비저닝하는 쪽의 몫이다.
79
- */
80
- @Column()
81
- @Field({ description: "Restart policy: 'resync' (read again from the external source) | 'resume' (continue this twin's own journal) | 'reset' (wipe and replay from the seed). No default — an unspecified policy is refused." })
82
- restartPolicy: string
83
-
84
- /* 읽을 때 어휘 세대를 흡수한다(`nodes`/`movers`/`equipmentList` → `locations`/`equipment`). (vocabulary-guard: allow — 세대 이름 없이는 설명할 수 없다.)
85
- 자리마다 리더를 쓰게 하면 다음에 추가되는 자리가 또 빠지고, 빠진 것은 오류가 아니라 **빈 공장**이라
86
- 들어온 것이 없다(2026-08-06: 모델러 엔티티 목록이 통째로 비었다). 상세 `engine/model-vocabulary.ts`. */
87
- @Column({ type: 'simple-json', nullable: true, transformer: modelColumnTransformer })
88
- @Field(type => ScalarObject, { nullable: true, description: 'TwinModelDef blueprint (locations/equipment) required to replay events into state. Older stored boards used nodes/movers/equipmentList; they are normalised on read so consumers see one vocabulary.' }) // vocabulary-guard: allow — 옛 어휘를 흡수하는 것이 이 코드의 일이다(세대 이름을 적어야 흡수할 수 있다)
89
- model?: any
90
-
91
- /*
92
- * 로컬 선언 겹 — **구조는 원천이, 수는 우리가.**
93
- *
94
- * 요금 단가·계약 정보·축전지 충전율처럼 원 시스템이 모르는 값을 넣는 자리다. `model` 에 직접 쓰지
95
- * 않는 이유는 그것이 **원천의 사본**이기 때문이다: 다시 읽기가 사본을 새로 그리면 직접 쓴 값은 알리지 않고
96
- * 사라진다(요금이 사라지면 금액도 사라지고, 사용자는 이유를 알 수 없다).
97
- *
98
- * 그래서 여기 남기고, 모델을 그릴 때마다 그 위에 얹는다(`engine/local-declarations`). 얹힌 값에는
99
- * `source: 'local'` 이 붙는다 — 커널 계약의 `PropertySource` 축(`reference` ↔ `local`)이고, 「밖에서
100
- * 참조해 온 값이냐, 이 안에서 정한 값이냐」에 답한다.
101
- *
102
- * **이름에 장소 낱말을 쓰지 않는다**(옛 이름 `siteDeclarations`): 이 코드에서 `site` 는 **외부
103
- * 시스템이 부르는 사업장**이고(SAP `P3`·Oracle `W01` 이 같은 현장), 여기 담기는 것은 그 외부 시스템이
104
- * **모르는** 값이다 — 이름이 내용과 정반대였다. `space` 도 아니다: 그것은 「어디」에 답하고 이 축은
105
- * 「누가 말했나」에 답한다.
106
- */
107
- @Column({ type: 'simple-json', nullable: true })
108
- @Field(type => ScalarObject, { nullable: true, description: "Locally-declared values layered on top of the reference-derived model (tariff, contract, state of charge) — values whose authority sits here, not in the source system. Kept apart from `model` so a resync cannot silently drop them." })
109
- localDeclarations?: any
110
-
111
- @Column({ nullable: true })
112
- @Field({ nullable: true, description: 'Owning space id (co-location anchor). Promoted from model.spaceId — first-class "space → its twins" query (space-centered ontology).' })
113
- spaceId?: string
114
-
115
- @Column({ nullable: true })
116
- @Field({ nullable: true, description: 'Owning area id within the space (optional scope). Promoted from model.areaId.' })
117
- areaId?: string
118
-
119
- @Column({ nullable: true })
120
- @Field({ nullable: true, description: 'Lifecycle status: running | stopped.' })
121
- status?: string
122
-
123
- /*
124
- * purpose — 이 인스턴스가 운영 트윈인지, 격리된 벤치 사본인지 1급 선언(이름 접두사가 아니라 속성으로 구별).
125
- * 'bench' 는 규모/부하 실험용 격리 사본 — 목록·정리·안전 가드가 이 속성을 키로 동작(운영 트윈 무오염 보장).
126
- *
127
- * **비어 있을 수 없다.** 프로비저닝이 `register` 에서 'operational' 로 각인하고, 벤치 사본만
128
- * `setPurpose` 로 뒤집는다. 예전에는 비워 둔 채 읽는 쪽에서 메웠는데, 그러면 "운영이라고 선언된 것"
129
- * 과 "아무도 말하지 않은 것" 이 같은 값으로 보여서 벤치 격리가 추측에 기대게 된다.
130
- */
131
- @Column()
132
- @Field({ description: "Instance purpose: 'operational' (real twin) | 'bench' (isolated copy for scale/load experiments)." })
133
- purpose: string
134
-
135
- @Column({ nullable: true })
136
- @Field({ nullable: true, description: 'For a bench copy: the source spaceId it was copied from (provenance).' })
137
- copyOf?: string
138
-
139
- /**
140
- * **이 트윈을 다시 읽는 방법** — 어떤 원본에서 나왔나(`MasterOrigin`).
141
- *
142
- * 트윈은 원본을 비출 뿐이므로(ADR-0028) 원본이 달라지면 다시 읽어야 한다. 그런데 이 자리가 없던
143
- * 동안 트윈은 **자기가 무엇에서 나왔는지 몰랐다** — 어댑터로 들어온 트윈은 `TwinReference` 행이
144
- * 있었지만 템플릿으로 세운 트윈에는 아무 표식도 없었고, 그래서 첫날의 모습에 영원히 머무는
145
- * 트윈이 만들어졌다. 원천이 무엇이든 여기 한 자리에 남긴다.
146
- *
147
- * **비어 있을 수 있다** — 이 자리가 생기기 전에 만들어진 트윈이 그렇다. 그때는 "다시 읽을 수
148
- * 없다" 가 사실이므로 화면이 그대로 말한다(짐작해 채우지 않는다).
149
- */
150
- @Column({ type: 'simple-json', nullable: true })
151
- @Field(type => ScalarObject, {
152
- nullable: true,
153
- description:
154
- "How this twin's master can be produced again — {kind:'reference', source} or {kind:'template', templateId, params}. Absent means this twin cannot be re-read from its source."
155
- })
156
- origin?: any
157
-
158
- /*
159
- * `revision` 컬럼은 **없앴다**(2026-08-08).
160
- *
161
- * `ADR-0015` 가 "정의만 있고 write 안 됨 — 프로비저닝에서 최신 저널 revision 을 반영하도록
162
- * 채운다" 고 적어 두었는데, 채우지 않는 편이 맞다. 저널의 최신 번호는 **저널이 아는 사실**이고
163
- * (`TwinEngine.list` 가 `MAX(revision)` 으로 낸다), 여기 복제하면 **같은 사실의 집이 둘**이 된다.
164
- * 이 세션에만 그 부류를 셋 겪었다(`model.operations` 두 집 · `materials` 두 집 · tenantId 중복).
165
- *
166
- * 복제한 값은 반드시 어긋난다 — 저널은 틱마다 늘고 이 컬럼은 저장할 때만 갱신되므로, 화면이
167
- * 어느 쪽을 읽느냐로 다른 숫자가 나온다. 그 들어온 것이 없는 어긋남을 만들 이유가 없다.
168
- */
169
-
170
- @CreateDateColumn()
171
- @Field({ nullable: true, description: 'Timestamp when the instance was first registered.' })
172
- createdAt?: Date
173
-
174
- @UpdateDateColumn()
175
- @Field({ nullable: true, description: 'Timestamp when the instance registry row was last updated.' })
176
- updatedAt?: Date
177
-
178
- /*
179
- * 누가 만들고 누가 고쳤나 — **이 행은 사람이 만든다**(프로비저닝은 사용자 행위)이므로 규약의
180
- * 풀세트를 갖는다. 투영 행(자리·설비·공정)은 반대로 인제스트가 그린 것이라 저자가 사람이 아니고,
181
- * 그 저자는 `sourceRef`+`ingestedAt` 이 이미 말한다 — 그래서 그쪽에는 두지 않는다.
182
- *
183
- * 비어 있을 수 있다: 부팅 자동 프로비저닝처럼 **사람이 없는 경로**로 만들어진 행이 그렇다.
184
- * 그때 아무 사용자를 적어 넣으면 감사 기록이 거짓이 된다.
185
- */
186
- @ManyToOne(type => User, { nullable: true })
187
- @Field(type => User, { nullable: true, description: 'The user who first provisioned this twin. Empty when it was created by a system path (boot provisioning).' })
188
- creator?: User
189
-
190
- @RelationId((e: TwinInstance) => e.creator)
191
- creatorId?: string
192
-
193
- @ManyToOne(type => User, { nullable: true })
194
- @Field(type => User, { nullable: true, description: 'The user who last changed this twin registry row.' })
195
- updater?: User
196
-
197
- @RelationId((e: TwinInstance) => e.updater)
198
- updaterId?: string
199
- }
@@ -1,112 +0,0 @@
1
- /*
2
- * **이 물음이 「여러 종류를 시각순으로」인가** — 순수 판단만 여기 둔다.
3
- *
4
- * 데이터베이스를 부르지 않는다. 그래서 시험이 이 파일을 그대로 부를 수 있다(데코레이터가 없다).
5
- * 판단이 조회 코드 안에 섞여 있으면 그 판단만 확인할 방법이 없고, 그러면 「어떤 물음이 나눠 묻는
6
- * 갈래로 가는가」가 아무도 읽지 못하는 규칙이 된다.
7
- *
8
- * 실측 근거와 고침의 뜻은 `event-type-split.ts` 머리에 있다.
9
- */
10
- import { absoluteTime } from '../../engine/read-time.js'
11
-
12
- /** 질의를 몇 개까지 나눌까 — 대상 × 종류. 이 이상이면 나누는 것이 손해다. */
13
- export const MAX_SPLIT = 24
14
-
15
- /** 종류 목록의 상한 — 이보다 많으면 「이 종류만」이 아니라 사실상 전체다. */
16
- const MAX_TYPES = 12
17
-
18
- export interface SplitShape {
19
- eventTypes: string[]
20
- /**
21
- * 공정 단계 하나로 좁힌 경우 — 그 값을 갈래마다 함께 건다.
22
- *
23
- * 이 필터를 만나면 갈래를 포기하던 것을 고쳤다(2026-08-29). 원장은 종류를 담아 묻고 그 위에 단계
24
- * 칩을 겹치는데, 칩을 고른 순간 예전 경로로 떨어져 **고르지 않은 쪽이 더 빨랐다.**
25
- *
26
- * 단계 컬럼에는 색인이 없다. 그래도 느려지지 않는다 — 종류 정확일치가 색인으로 시각 순서까지 주고,
27
- * 단계는 그 안에서 행마다 확인하는 조건이다(걷는 행이 그 종류의 것으로 이미 좁혀져 있다).
28
- */
29
- bizStep?: string
30
- untilTime?: Date
31
- fromTime?: Date
32
- }
33
-
34
- /**
35
- * 이 물음이 「여러 종류를 시각순으로」인가 — 아니면 `null`.
36
- *
37
- * 받는 모양
38
- * `eventType` 을 `in` 으로 · 시각 상한이나 구간 · 시각 내림차순 정렬
39
- *
40
- * 보내는 모양(일반 경로로)
41
- * 자유 검색어 · 그 밖의 필터(축·상관 식별자·업무 단계) · 그 밖의 정렬이나 연산자
42
- */
43
- export function splitShape(params: any, sortings: any[]): SplitShape | null {
44
- const filters: any[] = Array.isArray(params?.filters) ? params.filters : []
45
- if (typeof params?.search === 'string' && params.search.trim()) return null
46
- if (sortings.length !== 1 || sortings[0]?.name !== 'eventTime' || sortings[0]?.desc !== true) return null
47
-
48
- let eventTypes: string[] | undefined
49
- let untilTime: Date | undefined
50
- let fromTime: Date | undefined
51
- let bizStep: string | undefined
52
- for (const f of filters) {
53
- if (f?.name === 'eventType') {
54
- if (f.operator !== 'in' || !Array.isArray(f.value)) return null
55
- const types: string[] = f.value.map((v: unknown) => String(v ?? '').trim()).filter((t: string) => !!t)
56
- /* 하나면 나눌 것이 없다(이미 정확일치라 색인을 탄다). 너무 많으면 사실상 전체다. */
57
- if (types.length < 2 || types.length > MAX_TYPES) return null
58
- if (eventTypes) return null
59
- eventTypes = [...new Set(types)]
60
- } else if (f?.name === 'bizStep') {
61
- /* 하나로 좁힌 경우만 받는다 — 여러 값이면 종류 × 단계로 갈래가 곱해진다. */
62
- if (f.operator !== 'eq') return null
63
- const v = String(f.value ?? '').trim()
64
- if (!v) return null
65
- if (bizStep) return null
66
- bizStep = v
67
- } else if (f?.name === 'eventTime') {
68
- if (f.operator === 'lte' || f.operator === 'lt') {
69
- untilTime = absoluteTime(f.value) ?? undefined
70
- if (!untilTime) return null
71
- } else if (f.operator === 'between' && Array.isArray(f.value)) {
72
- fromTime = absoluteTime(f.value[0]) ?? undefined
73
- untilTime = absoluteTime(f.value[1]) ?? undefined
74
- if (!fromTime || !untilTime) return null
75
- } else return null
76
- } else return null
77
- }
78
- return eventTypes ? { eventTypes, untilTime, fromTime, bizStep } : null
79
- }
80
-
81
- /**
82
- * **나눠 물은 갈래들을 합쳐 앞에서 `limit` 개** — 이 규율이 정확성의 근거다.
83
- *
84
- * ── 왜 갈래마다 `limit` 까지 받아야 하나 ────────────────────────────────────
85
- * 갈래마다 `limit` 개를 받아 합치면, 합친 것의 앞 `limit` 개는 **전체에서도** 앞 `limit` 개다.
86
- * 어떤 갈래에서 빠진 행은 그 갈래의 `limit` 번째보다 뒤이고, 우리는 전체에서 `limit` 개만 취하므로
87
- * 그 행이 이 페이지에 들어올 수 없다.
88
- *
89
- * 갈래마다 **더 적게** 받으면 그 성질이 깨진다. 한 갈래가 앞을 다 차지하는 경우
90
- * (종류 A 의 마지막이 종류 B 의 첫째보다 앞선다) 그 갈래에서 못 받은 것이 빠지고, 결과는 구간의
91
- * 앞부분만 계산한 것이 된다 — 그런데 화면은 「일부만 읽었다」고만 말하고 어느 부분인지는 말하지 못한다.
92
- * (2026-08-28 · UX 레인이 미리 짚어 준 함정이다.)
93
- *
94
- * 그래서 이 함수는 **`limit` 미만으로 받은 갈래가 있으면 그것을 말한다** — 부르는 쪽이 그 상태로
95
- * 답하지 않게.
96
- */
97
- export function mergeStreams<T>(
98
- streams: readonly T[][],
99
- limit: number,
100
- /** 앞에 와야 하는 것이 음수 — `Array.prototype.sort` 와 같은 규약. */
101
- compare: (a: T, b: T) => number
102
- ): { items: T[]; capped: boolean; underfilled: boolean } {
103
- const underfilled = streams.some(s => s.length > limit)
104
- const merged = streams.flat().sort(compare)
105
- return {
106
- items: merged.slice(0, limit),
107
- /* 합친 것이 상한을 넘었으면 더 있었다는 뜻이다 — 잘랐다는 사실을 부르는 쪽이 말해야 한다. */
108
- capped: merged.length > limit || streams.some(s => s.length >= limit),
109
- /* 갈래가 상한보다 많이 받아 왔다 — 있을 수 없는 일이므로 부르는 쪽이 알아야 한다. */
110
- underfilled
111
- }
112
- }
@@ -1,144 +0,0 @@
1
- import { getRepository } from '@things-factory/shell'
2
-
3
- import { TwinEvent } from '../twin-event/twin-event.js'
4
- import { absoluteTime } from '../../engine/read-time.js'
5
- import { MAX_SPLIT, type SplitShape } from './event-type-split-shape.js'
6
-
7
- /*
8
- * **여러 종류를 시각순으로 — 종류를 하나씩 나눠 묻는다** (2026-08-28 실측).
9
- *
10
- * ── 무엇이 느렸나 ───────────────────────────────────────────────────────────
11
- * 에너지 원장은 「이 여덟 종류를 시각 내림차순으로 50건」을 묻는다. 그 모양에서 sqlite 는 종류 색인을
12
- * **버린다**:
13
- *
14
- * 종류 IN + 시각순 SEARCH USING INDEX ix_twin_event_1 (domain, instance) 37.181초 · 결과 0건
15
- * 같은 조건 · 정렬 없음 SEARCH USING INDEX ix_twin_event_7 (…, event_type=?) 0.003초
16
- * 종류 하나 + 시각순 SEARCH USING INDEX ix_twin_event_7 (…, event_type=?) 0.003초
17
- *
18
- * 정렬을 붙이는 순간 여러 종류의 순서를 합칠 방법이 없어, 시각 색인으로 337만 행을 걸으며 행마다
19
- * 종류를 확인한다. 승화푸드에 에너지 사건은 0건이다 — **없는 것을 찾느라 37초**를 쓴다.
20
- *
21
- * 360 이력이 64초였던 것과 같은 부류다: **거르는 축과 정렬 축이 어긋난다.**
22
- *
23
- * ── 고침 ────────────────────────────────────────────────────────────────────
24
- * 종류를 **정확일치로 하나씩** 물으면 색인이 시각 순서까지 그대로 준다(정렬이 사라진다). 여덟 종류면
25
- * 질의 여덟 개이고 각 0.003초다. 받은 것을 시각순으로 합쳐 한 페이지를 만든다.
26
- *
27
- * 새 색인도, 새 테이블도 필요 없다 — 있는 색인을 쓰게 하는 것이 전부다.
28
- *
29
- * ── 좁게 잡는다 ─────────────────────────────────────────────────────────────
30
- * 이 모양이 아닌 물음은 답하지 않고(`null`) 저널의 일반 경로로 보낸다. 억지로 답하면 목록이 알리지
31
- * 않고 달라진다.
32
- *
33
- * ── ★ **이 갈래를 걷을 조건** ────────────────────────────────────────────────
34
- * 앱에서 종류를 여러 값으로 보내는 곳은 **에너지 원장 한 곳뿐**이다(2026-08-28 확인). 그 화면이
35
- * 종류를 하나씩 고르는 모양으로 바뀌면 이 갈래를 부르는 데가 없어진다 — 그때 **지운다.**
36
- *
37
- * 부르는 데가 없는 갈래를 들고 있으면, 그것이 무언가를 받쳐 주는 것처럼 보이면서 실제로는 아무것도
38
- * 하지 않는다. 지금 살려 두는 이유는 하나다: 실 고객 트윈에서 37초 질의가 돌고 있고 화면 수정은
39
- * 다른 레인의 일이다.
40
- */
41
-
42
- export interface SplitPage {
43
- items: TwinEvent[]
44
- nextCursor?: string
45
- }
46
-
47
- /**
48
- * 나눠 묻고 합쳐 한 페이지 — 답할 수 없으면 `null`.
49
- *
50
- * 이어 읽기 지점은 **모든 갈래에 같이** 건다. 그래야 합친 결과가 커서 아래에서만 나온다 — 갈래마다
51
- * 다르게 걸면 어떤 종류는 이미 지나간 구간을 다시 낸다.
52
- */
53
- export async function eventTypeSplitPage(
54
- domainId: string,
55
- instanceIds: string[],
56
- shape: SplitShape,
57
- limit: number,
58
- /** 동시각을 가리는 축 — 트윈 하나면 `revision`, 여럿이면 기본키(§`cursorTiebreak`). */
59
- tiebreak: 'revision' | 'id',
60
- after?: string
61
- ): Promise<SplitPage | null> {
62
- const pairs = instanceIds.length * shape.eventTypes.length
63
- if (!pairs || pairs > MAX_SPLIT) return null
64
-
65
- let cursor: { at: Date; tie: string | number } | null = null
66
- if (after) {
67
- cursor = decodeCursorPair(after)
68
- if (!cursor) return null
69
- }
70
-
71
- const rows: TwinEvent[][] = []
72
- for (const instanceId of instanceIds) {
73
- for (const eventType of shape.eventTypes) {
74
- const qb = getRepository(TwinEvent)
75
- .createQueryBuilder('e')
76
- .where('e.domain = :domainId', { domainId })
77
- .andWhere('e.instanceId = :instanceId', { instanceId })
78
- /* **정확일치**가 요점이다 — 그래야 색인이 시각 순서까지 준다(§ 위 실측). */
79
- .andWhere('e.eventType = :eventType', { eventType })
80
- /* 단계는 색인이 아니라 행 조건이다 — 종류 정확일치가 이미 걷는 범위를 좁혀 놓았다. */
81
- if (shape.bizStep) qb.andWhere('e.bizStep = :bizStep', { bizStep: shape.bizStep })
82
- if (shape.fromTime) qb.andWhere('e.eventTime >= :fromTime', { fromTime: shape.fromTime })
83
- if (shape.untilTime) qb.andWhere('e.eventTime <= :untilTime', { untilTime: shape.untilTime })
84
- if (cursor) {
85
- qb.andWhere(`(e.eventTime < :curAt OR (e.eventTime = :curAt AND e.${tiebreak} < :curTie))`, {
86
- curAt: cursor.at,
87
- curTie: cursor.tie
88
- })
89
- }
90
- const page = await qb
91
- .orderBy('e.eventTime', 'DESC')
92
- .addOrderBy(`e.${tiebreak}`, 'DESC')
93
- .limit(limit)
94
- .getMany()
95
- .catch(() => null)
96
- /* 한 갈래라도 못 읽으면 합친 결과가 반쪽이다 — 반쪽을 전부인 것처럼 내지 않는다. */
97
- if (!page) return null
98
- rows.push(page)
99
- }
100
- }
101
-
102
- /*
103
- * 합친다. 갈래마다 `limit` 까지 받았으므로, 합쳐서 앞의 `limit` 개는 **전체에서도** 앞의 `limit` 개다
104
- * (각 갈래가 자기 안에서 정렬돼 있고 그보다 앞선 것을 빠뜨릴 수 없다).
105
- */
106
- const merged = rows
107
- .flat()
108
- .sort((a: any, b: any) => {
109
- /* `getMany` 는 엔티티를 주므로 시각이 이미 날짜다 — 감싸면 드라이버 값을 손으로 읽는 모양이 된다. */
110
- const at = (b.eventTime as Date).getTime() - (a.eventTime as Date).getTime()
111
- if (at !== 0) return at
112
- const x = a[tiebreak]
113
- const y = b[tiebreak]
114
- return x === y ? 0 : x < y ? 1 : -1
115
- })
116
- .slice(0, limit)
117
-
118
- const last: any = merged[merged.length - 1]
119
- const nextCursor =
120
- merged.length === limit && last?.eventTime instanceof Date && last[tiebreak] !== undefined
121
- ? encodeCursorPair(last.eventTime, last[tiebreak])
122
- : undefined
123
-
124
- return { items: merged, nextCursor }
125
- }
126
-
127
- /** 저널 경로와 같은 커서 — `[eventTime, 동시각 축]`(§`buildNextCursor`). */
128
- function encodeCursorPair(at: Date, tie: string | number): string {
129
- return Buffer.from(JSON.stringify([at, tie]), 'utf8').toString('base64url')
130
- }
131
-
132
- function decodeCursorPair(cursor: string): { at: Date; tie: string | number } | null {
133
- let values: unknown
134
- try {
135
- values = JSON.parse(Buffer.from(cursor, 'base64url').toString('utf8'))
136
- } catch {
137
- return null
138
- }
139
- if (!Array.isArray(values) || values.length !== 2) return null
140
- const at = absoluteTime(values[0])
141
- const tie = values[1]
142
- if (!at || (typeof tie !== 'string' && typeof tie !== 'number')) return null
143
- return { at, tie }
144
- }
@@ -1,3 +0,0 @@
1
- import { TwinJournalQuery } from './twin-journal-query.js'
2
-
3
- export const resolvers = [TwinJournalQuery]
@@ -1,20 +0,0 @@
1
- /**
2
- * 지난 기록 조회의 정렬 축 — **부르는 쪽이 무엇으로 물었는지에 맞춘다.**
3
- *
4
- * 리졸버 안에 두면 이 규칙을 확인할 방법이 소스를 글자로 전수 조회하는 것뿐이다. 규칙 자체를 부를 수 있게
5
- * 밖으로 뺀다(`test/journal-order-axis.test.ts`).
6
- */
7
- export function journalOrder(q: {
8
- untilTime?: string | null
9
- fromTime?: string | null
10
- fromRevision?: number | null
11
- toRevision?: number | null
12
- }): {
13
- eventTime?: 'DESC'
14
- revision: 'DESC'
15
- } {
16
- /* `revision` 으로 물었으면 그 순서가 물음의 답이다. 거르는 축과 정렬 축을 맞추는 규칙과도 같다. */
17
- const byTime = q.untilTime != null || q.fromTime != null
18
- if (!byTime && (q.fromRevision != null || q.toRevision != null)) return { revision: 'DESC' }
19
- return { eventTime: 'DESC', revision: 'DESC' }
20
- }