@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
@@ -12,7 +12,7 @@ export interface IngestWindow {
12
12
  * 매핑은 통과했지만 **트윈에 닿지 못한** 수 — 처방은 트윈을 세우는 것이다.
13
13
  *
14
14
  * ── 왜 거부와 따로 세나 (2026-08-20에 겪었다) ─────────────────────────────
15
- * 트윈이 라이브로 돌지 않으면 커널이 레코드를 **조용히 버린다**. 그런데 장부는 그것을 「통과」로 셌다.
15
+ * 트윈이 라이브로 돌지 않으면 커널이 레코드를 **알리지 않고 버린다**. 그런데 장부는 그것을 「통과」로 셌다.
16
16
  * 화면이 「150 들어옴 · 150 통과 · 100%」라고 말하는 동안 150건은 바닥에 버려지고 있었다. 이 기능이
17
17
  * 막으려던 바로 그것을 이 기능이 저지른 셈이다.
18
18
  *
@@ -72,6 +72,26 @@ export interface IngestLedger {
72
72
  */
73
73
  lastUndeliveredAtMs: number;
74
74
  /** 사유별 누적 건수와 **마지막으로 그 사유가 난 시각** — 고친 사유는 시각이 멈춘다. */
75
+ /**
76
+ * **어떤 길로 들어왔나** — 경로마다 건수와 마지막 시각.
77
+ *
78
+ * ── 왜 필요한가 (2026-08-26) ──────────────────────────────────────────────
79
+ * 트윈이 값을 받고 있다는 것은 계기가 말해 주는데, **무엇을 통해 받는지는 아무도 말하지 않았다.**
80
+ * 커넥터가 물어서 받는지, 연결된 시스템이 밀어 주는지, 시나리오가 넣는지, 부하 도구가 넣는지 —
81
+ * 화면에서 구별할 수 없었다. 그 구별이 없으면 「폴링을 웹훅으로 바꿨다」를 확인할 방법도 없다.
82
+ */
83
+ bySource: Record<string, {
84
+ count: number;
85
+ lastAtMs: number;
86
+ }>;
87
+ /**
88
+ * **같은 사실이 두 번 와서 버린 수** — 알리지 않고 버리지 않는다.
89
+ *
90
+ * 이 수가 크면 보내는 쪽이 되풀이 보내고 있다는 뜻이고, 그것은 고칠 일이다(태양광 커넥터가 한 주기에
91
+ * 76건을 되풀이 보내던 것을 이 수로 볼 수 있었어야 했다).
92
+ */
93
+ duplicates: number;
94
+ lastDuplicateAtMs: number;
75
95
  byReason: Record<string, {
76
96
  count: number;
77
97
  lastAtMs: number;
@@ -79,8 +99,8 @@ export interface IngestLedger {
79
99
  /**
80
100
  * 사유 종류가 상한에 닿았나.
81
101
  *
82
- * **접힌 종류 수는 세지 않는다** — 그것을 세려면 이미 본 사유를 모두 기억해야 하고, 그 집합이
83
- * 바로 이 상한으로 막으려던 무한한 집합이다. 접힌 **건수**는 `byReason[OTHER_REASON].count` 가 답한다.
102
+ * **모은 종류 수는 세지 않는다** — 그것을 세려면 이미 본 사유를 모두 기억해야 하고, 그 집합이
103
+ * 바로 이 상한으로 막으려던 무한한 집합이다. 모은 **건수**는 `byReason[OTHER_REASON].count` 가 답한다.
84
104
  */
85
105
  reasonsCapped: boolean;
86
106
  /** 표본을 이미 뜬 사유들 — 같은 사유를 다시 직렬화하지 않기 위한 색인(O(1) 조회). */
@@ -94,12 +114,12 @@ export interface IngestLedger {
94
114
  /**
95
115
  * **원본에 닿지 못한 사실** (2026-08-23) — 「받은 것이 없다」와 **다른 사실**이다.
96
116
  *
97
- * ── 무엇이 조용했나 ─────────────────────────────────────────────────────────
117
+ * ── 무엇이 아무 신호도 내지 않았나 ─────────────────────────────────────────────────────────
98
118
  * 실 원본이 끊겼을 때(접속 시간 초과) 트윈의 **조회 가능한 상태 어디에도** 그 사실이 없었다.
99
119
  * `recordIngest` 는 `onRecords` 가 불릴 때만 도달하고, 읽기가 실패하면 그 문에 오지 않는다.
100
120
  * `TwinReference.lastError` 는 마스터 동기·접속 시험에만 적힌다.
101
121
  *
102
- * 그래서 화면이 볼 수 있는 것은 「새 사실이 없다」뿐이었고, 그것은 **「원본이 조용하다」와 구별되지
122
+ * 그래서 화면이 볼 수 있는 것은 「새 사실이 없다」뿐이었고, 그것은 **「연결된 시스템에서 들어온 것이 없다」와 구별되지
103
123
  * 않는다.** 실증 데모 중에 원본이 끊기면 사용자가 원인을 찾을 수 없다.
104
124
  *
105
125
  * ── 왜 「몇 번」과 「언제부터」를 함께 두나 ──────────────────────────────────
@@ -108,6 +128,17 @@ export interface IngestLedger {
108
128
  *
109
129
  * 성공하면 지운다 — 고쳐진 단절이 화면에 남아 있으면 그것도 거짓이다.
110
130
  */
131
+ /**
132
+ * 마지막으로 끊겼다가 돌아온 것 — 없으면 끊긴 적이 없거나 아직 돌아오지 않은 것이다.
133
+ *
134
+ * 실패 기록(`readFailure`)은 돌아오면 지워진다. 그것만 지우면 「끊긴 적이 있었다」가 화면에서
135
+ * 사라지므로, 돌아온 사실을 따로 남긴다.
136
+ */
137
+ lastRecovery?: {
138
+ atMs: number;
139
+ afterFailures: number;
140
+ downMs: number;
141
+ };
111
142
  readFailure?: {
112
143
  /** 연속 실패 수 — 성공 한 번에 0 으로 돌아간다. */
113
144
  consecutive: number;
@@ -119,6 +150,8 @@ export interface IngestLedger {
119
150
  reason: string;
120
151
  /** 어느 흐름에서 났나(어댑터가 말해 주면). 원본마다 흐름이 다르므로 열려 있다. */
121
152
  stream?: string;
153
+ /** 다음에 다시 물을 때까지 남은 시간(ms) — 커넥터가 물러섰을 때만 있다. */
154
+ nextRetryMs?: number;
122
155
  };
123
156
  /**
124
157
  * **읽었는데 창을 넘길 수 없다** (2026-08-24) — 위와 **다른 사실**이다.
@@ -152,7 +185,7 @@ export interface IngestLedger {
152
185
  * `unhandled` 리듀서가 **받았는데** 담을 자리를 몰랐다
153
186
  * 여기 커넥터가 **보지만 일부러 보내지 않았다** — 이유와 함께
154
187
  *
155
- * 둘 다 「사실이 조용히 사라지지 않게」 세는 것이고, 이유가 다르므로 자리도 다르다.
188
+ * 둘 다 「사실이 오류 없이 사라지지 않게」 세는 것이고, 이유가 다르므로 자리도 다르다.
156
189
  *
157
190
  * 이유를 **문자열로 받는다**: 무엇을 왜 안 받는지는 원본마다 다르고, 계약이 그 목록을 닫으면 새 원본을
158
191
  * 붙일 때마다 계약을 고치게 된다(흐름 열쇠와 같은 규율).
@@ -181,12 +214,30 @@ export interface IngestLedger {
181
214
  * 연속 실패의 시작 시각을 지키는 것이 이 함수의 요점이다: 매번 새로 적으면 「20분째 못 읽는다」를
182
215
  * 말할 수 없고, 화면은 늘 「방금 실패했다」만 보게 된다.
183
216
  */
184
- export declare function recordReadFailure(ledger: IngestLedger, reason: string, nowMs: number, stream?: string): void;
217
+ export declare function recordReadFailure(ledger: IngestLedger, reason: string, nowMs: number, stream?: string,
218
+ /**
219
+ * 다음에 다시 물을 때까지 남은 시간(ms) — 커넥터가 물러섰으면 그 값을 준다 (2026-08-27).
220
+ *
221
+ * 이것이 없으면 화면이 「닿지 못하고 있다」까지만 말하고, 사람은 **언제 다시 시도하는지** 알 수
222
+ * 없다. 그러면 기다려야 하는지 손을 써야 하는지 판단하지 못한다.
223
+ *
224
+ * **연달아 횟수와 시작 시각은 커넥터가 보내지 않는다** — 이 함수가 이미 센다. 두 곳에서 세면
225
+ * 갈라지고, 갈라지면 어느 쪽이 사실인지 알 수 없다.
226
+ */
227
+ nextRetryMs?: number): void;
228
+ /**
229
+ * **끊겼다가 돌아왔다** — 그 사실을 남긴다 (2026-08-27).
230
+ *
231
+ * 실패 기록만 지우면 「끊긴 적이 있었다」가 화면에서 사라진다. 그러면 밤새 두 시간 끊겼던 연결과 한
232
+ * 번도 끊기지 않은 연결이 아침에 똑같이 보인다. 몇 번 실패한 뒤에 돌아왔는지, 얼마나 끊겼는지를 함께
233
+ * 남긴다.
234
+ */
235
+ export declare function recordRecovered(ledger: IngestLedger, afterFailures: number, downMs: number, nowMs: number): void;
185
236
  /**
186
237
  * 읽기가 성공했다 — 단절 기록을 지운다.
187
238
  *
188
239
  * **빈 읽기도 성공이다**: 원본이 「새 것이 없다」고 답한 것은 닿았다는 뜻이다. 그 둘을 같게 두면
189
- * 조용한 원본이 끊긴 원본으로 보인다(고치려던 것의 반대 방향으로 틀린다).
240
+ * 들어온 것이 없는 연결이 끊긴 원본으로 보인다(고치려던 것의 반대 방향으로 틀린다).
190
241
  */
191
242
  export declare function clearReadFailure(ledger: IngestLedger): void;
192
243
  /**
@@ -206,6 +257,15 @@ export declare function recordCursorStall(ledger: IngestLedger, reason: string,
206
257
  * 이유가 같고 수가 달라지면 **마지막 수로 덮는다**: 이것은 누적 사건이 아니라 **지금 세우지 않은 것의
207
258
  * 수**다. 주기마다 8건이면 8이고, 더해서 800이 되면 거짓이다.
208
259
  */
260
+ /**
261
+ * 어떤 길로 몇 건이 들어왔나 — 경로 이름은 부르는 쪽이 정한다.
262
+ *
263
+ * 이름을 자유 문자열로 두는 이유: 길이 늘어난다(지금은 물어보기·시나리오·부하 도구, 다음은 웹훅).
264
+ * 열거로 못 박으면 새 길이 생길 때 이 파일을 함께 고쳐야 하고, 잊으면 그 길이 통계에서 사라진다.
265
+ */
266
+ export declare function recordIngestSource(ledger: IngestLedger, source: string, count: number, nowMs: number): void;
267
+ /** 같은 사실이 두 번 와서 버린 수 — 알리지 않고 버리지 않는다. */
268
+ export declare function recordDuplicates(ledger: IngestLedger, count: number, nowMs: number): void;
209
269
  export declare function recordWithheld(ledger: IngestLedger, reason: string, count: number, nowMs: number): void;
210
270
  /** 창을 넘겼으면 지운다 — 풀린 정체가 화면에 남아 있으면 그것도 거짓이다. */
211
271
  export declare function clearCursorStall(ledger: IngestLedger): void;
@@ -227,7 +287,7 @@ export declare const TREND_LIMIT = 36;
227
287
  * (`unknown bizStep "PUTAWAY_X17"`, `…X18`, …) 키가 무한히 늘어난다. 초당 1만 건 규모에서 이것은
228
288
  * 미미한 오버헤드가 아니라 누수다.
229
289
  *
230
- * 넘치면 `OTHER_REASON` 한 칸에 모으고 **몇 종을 접었는지 함께 낸다**(조용히 자르지 않는다).
290
+ * 넘치면 `OTHER_REASON` 한 칸에 모으고 **몇 종을 모았는지 함께 낸다**(알리지 않고 자르지 않는다).
231
291
  * 30종이면 고칠 곳을 찾기에 충분하다 — 목록을 훑는 일이 아니라 매핑 몇 줄을 고치는 일이다.
232
292
  */
233
293
  export declare const REASON_LIMIT = 30;
@@ -326,6 +386,13 @@ export declare function syncVerdictOf(args: {
326
386
  nowMs?: number;
327
387
  /** 마지막으로 **버려진** 시각. 한 번도 없으면 `-1`. */
328
388
  lastUndeliveredAtMs?: number;
389
+ /**
390
+ * 지금까지 제시된 누적 수 — **「받고 있는 중」과 「오는 것이 없다」를 가르는 사실**이다.
391
+ *
392
+ * 닿은 시각(`lastAtMs`)으로는 가를 수 없다: 빈 읽기도 닿은 것이므로 그 시각이 선다. 창이 아직 닫히지
393
+ * 않았을 때 이 수가 0 이면 오는 것이 없는 것이고, 0 이 아니면 받고 있는 중이다.
394
+ */
395
+ offeredTotal?: number;
329
396
  threshold?: number;
330
397
  }): SyncVerdict;
331
398
  export interface IngestWindowView {
@@ -385,7 +452,7 @@ export interface IngestHealthView {
385
452
  *
386
453
  * 커서 정체(`cursorStall`)와 **섞이지 않는다**: 이쪽은 기다리면 풀리고 그쪽은 기다려도 안 풀린다.
387
454
  *
388
- * 「유입 없음」과 **다른 판정**이다: 유입 없음은 원본이 조용한 것일 수 있고, 이것은 우리가 묻지도
455
+ * 「유입 없음」과 **다른 판정**이다: 유입 없음은 연결된 시스템에서 들어온 것이 없는 것일 수 있고, 이것은 우리가 묻지도
389
456
  * 못한 것이다. 화면은 두 문장을 다르게 말해야 한다 — 실 원본이 끊겼을 때 사용자가 원인을 찾을 수
390
457
  * 있는지가 그 차이다.
391
458
  */
@@ -396,6 +463,19 @@ export interface IngestHealthView {
396
463
  lastAt: string;
397
464
  reason: string;
398
465
  stream?: string;
466
+ /** 다음에 다시 물을 때까지 남은 시간(ms) — 커넥터가 물러섰을 때만 있다. */
467
+ nextRetryMs?: number;
468
+ };
469
+ /**
470
+ * 마지막으로 끊겼다가 돌아온 것 — 없으면 끊긴 적이 없거나 아직 돌아오지 않은 것이다 (2026-08-27).
471
+ *
472
+ * `readFailure` 는 돌아오면 사라진다. 이 칸이 없으면 밤새 끊겼던 연결과 한 번도 끊기지 않은 연결이
473
+ * 아침에 똑같이 보인다.
474
+ */
475
+ lastRecovery?: {
476
+ at: string;
477
+ afterFailures: number;
478
+ downMs: number;
399
479
  };
400
480
  }
401
481
  /**
@@ -5,12 +5,12 @@
5
5
  * ── 한 질문 ─────────────────────────────────────────────────────────────────
6
6
  * 화면에서 값이 변하지 않을 때 원인이 넷인데, 지금까지 **넷이 똑같이 보였다.**
7
7
  * ① 피드가 붙지 않았다 ② 붙었는데 아무것도 오지 않는다
8
- * ③ 오는데 전부 거부된다 ④ 정상인데 현장이 조용하다
8
+ * ③ 오는데 전부 거부된다 ④ 정상인데 현장이 들어온 것이 없다
9
9
  * ③은 특히 나쁘다 — 커넥터의 매핑이 한 글자 틀리면 트윈은 「빈 공장」이 되고, 그 사실이 서버 로그
10
10
  * 한 줄에만 남았다. 현장에 나간 사람은 로그를 뒤져야 했다.
11
11
  *
12
12
  * ── 왜 저널로는 답할 수 없나 ────────────────────────────────────────────────
13
- * **거부된 것은 저널에 없다** — 거부의 뜻이 그것이다. 저널을 접으면 통과한 쪽만 나온다. 거부의 추이는
13
+ * **거부된 것은 저널에 없다** — 거부의 뜻이 그것이다. 저널을 계산하면 통과한 쪽만 나온다. 거부의 추이는
14
14
  * 세는 자리를 따로 두어야 나온다. 이 장부가 그 자리다.
15
15
  *
16
16
  * ── 왜 건마다 저장하지 않나 ─────────────────────────────────────────────────
@@ -24,14 +24,17 @@
24
24
  * ── 지키는 규율 넷 ──────────────────────────────────────────────────────────
25
25
  * ① **닫힌 창만 「최근」이다** — 채우는 중인 창은 과소 집계다(부하 계기판에서 겪었다).
26
26
  * ② **0 과 「없음」을 가른다** — 안 받은 것은 `null`, 받았지만 거부 0 은 `0`.
27
- * ③ **조용히 자르지 않는다** — 표본·추이 상한에서 밀려난 수를 함께 낸다.
27
+ * ③ **알리지 않고 자르지 않는다** — 표본·추이 상한에서 밀려난 수를 함께 낸다.
28
28
  * ④ **통과율에 1 을 함부로 쓰지 않는다** — 1,000건 중 1건 거부는 0.999 다.
29
29
  */
30
30
  Object.defineProperty(exports, "__esModule", { value: true });
31
31
  exports.HEALTHY_ACCEPTED_RATIO = exports.RECORD_MAX = exports.SAMPLE_LIMIT = exports.OTHER_REASON = exports.REASON_LIMIT = exports.TREND_LIMIT = exports.STALE_AFTER_MS = exports.INGEST_WINDOW_MS = void 0;
32
32
  exports.recordReadFailure = recordReadFailure;
33
+ exports.recordRecovered = recordRecovered;
33
34
  exports.clearReadFailure = clearReadFailure;
34
35
  exports.recordCursorStall = recordCursorStall;
36
+ exports.recordIngestSource = recordIngestSource;
37
+ exports.recordDuplicates = recordDuplicates;
35
38
  exports.recordWithheld = recordWithheld;
36
39
  exports.clearCursorStall = clearCursorStall;
37
40
  exports.newIngestLedger = newIngestLedger;
@@ -47,21 +50,44 @@ exports.ingestHealth = ingestHealth;
47
50
  * 연속 실패의 시작 시각을 지키는 것이 이 함수의 요점이다: 매번 새로 적으면 「20분째 못 읽는다」를
48
51
  * 말할 수 없고, 화면은 늘 「방금 실패했다」만 보게 된다.
49
52
  */
50
- function recordReadFailure(ledger, reason, nowMs, stream) {
53
+ function recordReadFailure(ledger, reason, nowMs, stream,
54
+ /**
55
+ * 다음에 다시 물을 때까지 남은 시간(ms) — 커넥터가 물러섰으면 그 값을 준다 (2026-08-27).
56
+ *
57
+ * 이것이 없으면 화면이 「닿지 못하고 있다」까지만 말하고, 사람은 **언제 다시 시도하는지** 알 수
58
+ * 없다. 그러면 기다려야 하는지 손을 써야 하는지 판단하지 못한다.
59
+ *
60
+ * **연달아 횟수와 시작 시각은 커넥터가 보내지 않는다** — 이 함수가 이미 센다. 두 곳에서 세면
61
+ * 갈라지고, 갈라지면 어느 쪽이 사실인지 알 수 없다.
62
+ */
63
+ nextRetryMs) {
51
64
  const prev = ledger.readFailure;
52
65
  ledger.readFailure = {
53
66
  consecutive: (prev?.consecutive ?? 0) + 1,
54
67
  sinceMs: prev?.sinceMs ?? nowMs,
55
68
  lastAtMs: nowMs,
56
69
  reason,
57
- ...(stream ? { stream } : {})
70
+ ...(stream ? { stream } : {}),
71
+ ...(Number.isFinite(nextRetryMs) && nextRetryMs > 0 ? { nextRetryMs: nextRetryMs } : {})
58
72
  };
59
73
  }
74
+ /**
75
+ * **끊겼다가 돌아왔다** — 그 사실을 남긴다 (2026-08-27).
76
+ *
77
+ * 실패 기록만 지우면 「끊긴 적이 있었다」가 화면에서 사라진다. 그러면 밤새 두 시간 끊겼던 연결과 한
78
+ * 번도 끊기지 않은 연결이 아침에 똑같이 보인다. 몇 번 실패한 뒤에 돌아왔는지, 얼마나 끊겼는지를 함께
79
+ * 남긴다.
80
+ */
81
+ function recordRecovered(ledger, afterFailures, downMs, nowMs) {
82
+ if (ledger.readFailure)
83
+ delete ledger.readFailure;
84
+ ledger.lastRecovery = { atMs: nowMs, afterFailures, downMs };
85
+ }
60
86
  /**
61
87
  * 읽기가 성공했다 — 단절 기록을 지운다.
62
88
  *
63
89
  * **빈 읽기도 성공이다**: 원본이 「새 것이 없다」고 답한 것은 닿았다는 뜻이다. 그 둘을 같게 두면
64
- * 조용한 원본이 끊긴 원본으로 보인다(고치려던 것의 반대 방향으로 틀린다).
90
+ * 들어온 것이 없는 연결이 끊긴 원본으로 보인다(고치려던 것의 반대 방향으로 틀린다).
65
91
  */
66
92
  function clearReadFailure(ledger) {
67
93
  if (ledger.readFailure)
@@ -93,6 +119,27 @@ function recordCursorStall(ledger, reason, nowMs, stream) {
93
119
  * 이유가 같고 수가 달라지면 **마지막 수로 덮는다**: 이것은 누적 사건이 아니라 **지금 세우지 않은 것의
94
120
  * 수**다. 주기마다 8건이면 8이고, 더해서 800이 되면 거짓이다.
95
121
  */
122
+ /**
123
+ * 어떤 길로 몇 건이 들어왔나 — 경로 이름은 부르는 쪽이 정한다.
124
+ *
125
+ * 이름을 자유 문자열로 두는 이유: 길이 늘어난다(지금은 물어보기·시나리오·부하 도구, 다음은 웹훅).
126
+ * 열거로 못 박으면 새 길이 생길 때 이 파일을 함께 고쳐야 하고, 잊으면 그 길이 통계에서 사라진다.
127
+ */
128
+ function recordIngestSource(ledger, source, count, nowMs) {
129
+ const key = String(source ?? '').trim() || 'unknown';
130
+ if (count <= 0)
131
+ return;
132
+ const cur = (ledger.bySource[key] ??= { count: 0, lastAtMs: -1 });
133
+ cur.count += count;
134
+ cur.lastAtMs = nowMs;
135
+ }
136
+ /** 같은 사실이 두 번 와서 버린 수 — 알리지 않고 버리지 않는다. */
137
+ function recordDuplicates(ledger, count, nowMs) {
138
+ if (count <= 0)
139
+ return;
140
+ ledger.duplicates += count;
141
+ ledger.lastDuplicateAtMs = nowMs;
142
+ }
96
143
  function recordWithheld(ledger, reason, count, nowMs) {
97
144
  if (!reason || !(count > 0))
98
145
  return;
@@ -128,7 +175,7 @@ exports.TREND_LIMIT = 36;
128
175
  * (`unknown bizStep "PUTAWAY_X17"`, `…X18`, …) 키가 무한히 늘어난다. 초당 1만 건 규모에서 이것은
129
176
  * 미미한 오버헤드가 아니라 누수다.
130
177
  *
131
- * 넘치면 `OTHER_REASON` 한 칸에 모으고 **몇 종을 접었는지 함께 낸다**(조용히 자르지 않는다).
178
+ * 넘치면 `OTHER_REASON` 한 칸에 모으고 **몇 종을 모았는지 함께 낸다**(알리지 않고 자르지 않는다).
132
179
  * 30종이면 고칠 곳을 찾기에 충분하다 — 목록을 훑는 일이 아니라 매핑 몇 줄을 고치는 일이다.
133
180
  */
134
181
  exports.REASON_LIMIT = 30;
@@ -164,6 +211,9 @@ function newIngestLedger() {
164
211
  flushes: 0,
165
212
  lastWriteAtMs: -1,
166
213
  lastUndeliveredAtMs: -1,
214
+ bySource: {},
215
+ duplicates: 0,
216
+ lastDuplicateAtMs: -1,
167
217
  byReason: {},
168
218
  reasonsCapped: false,
169
219
  sampledReasons: new Set(),
@@ -252,7 +302,7 @@ undelivered = 0) {
252
302
  for (const it of items) {
253
303
  const raw = reasonKey(it?.errors);
254
304
  const known = raw in ledger.byReason;
255
- /* 사유 종류 상한 — 넘치면 한 칸으로 접고, **닿았다는 사실**을 표시한다. */
305
+ /* 사유 종류 상한 — 넘치면 한 칸으로 모으고, **닿았다는 사실**을 표시한다. */
256
306
  let key = raw;
257
307
  if (!known && Object.keys(ledger.byReason).length >= exports.REASON_LIMIT) {
258
308
  key = exports.OTHER_REASON;
@@ -308,14 +358,14 @@ function recordJournalWrite(ledger, rows, nowMs, onClosed) {
308
358
  /*
309
359
  * **`lastAtMs` 는 건드리지 않는다.** 그 값은 「마지막 유입」이고, 끊긴 피드를 가려내는 근거다. 쓰기로
310
360
  * 갱신하면 라이브 트윈은 유입이 끊겨도 틱이 만든 델타를 계속 적으므로 **영원히 「방금 받았다」**가 되고,
311
- * 「오래 끊긴 피드에 옛 창으로 초록을 내지 않는다」가 조용히 무력해진다. 축을 따로 든다.
361
+ * 「오래 끊긴 피드에 옛 창으로 초록을 내지 않는다」가 오류 하나 없이 무력해진다. 축을 따로 든다.
312
362
  */
313
363
  ledger.lastWriteAtMs = nowMs;
314
364
  }
315
365
  function syncVerdictOf(args) {
316
366
  /*
317
367
  * ── 버려지고 있는 것이 가장 먼저다 ────────────────────────────────────────
318
- * 트윈이 멈추면 피드는 남아 계속 레코드를 나르고, 커널은 그것을 조용히 버린다. 그 상태를 「해당 없음」
368
+ * 트윈이 멈추면 피드는 남아 계속 레코드를 나르고, 커널은 그것을 알리지 않고 버린다. 그 상태를 「해당 없음」
319
369
  * 이라 부르면 **사실이 사라지는 동안 화면이 안심시킨다** — 실제로 그렇게 떴다(멈춘 트윈 옆에 「150
320
370
  * 통과 · 100%」). 그래서 시뮬·멈춤 판정보다 먼저 본다.
321
371
  *
@@ -353,8 +403,29 @@ function syncVerdictOf(args) {
353
403
  if (args.nowMs - args.lastAtMs > exports.STALE_AFTER_MS)
354
404
  return 'no-traffic';
355
405
  }
356
- if (!args.recent)
357
- return 'unknown';
406
+ /*
407
+ * ── **닿았는데 오는 것이 없다** 를 「모른다」로 답하지 않는다 (2026-08-28) ────
408
+ *
409
+ * 창은 **다음 유입이 있을 때** 닫힌다. 그래서 오는 것이 하나도 없는 트윈은 창이 영원히 닫히지 않고,
410
+ * 이 자리가 `unknown` 을 냈다 — 붙어 있고 37초마다 성공적으로 읽는 트윈이 화면에서 「모른다」였다.
411
+ *
412
+ * 그것이 드러난 계기: 커넥터가 재기동마다 재고 2,665건을 다시 말하던 것을 없앴다. 그러자 정상 상태의
413
+ * 유입이 0 이 되었고, **건강 신호가 그 소음을 타고 있었다**는 것이 보였다.
414
+ *
415
+ * ── 가르는 사실은 **받은 것이 있나**다 (첫 판을 고침) ─────────────────────
416
+ * 처음에는 닿은 시각으로 갈랐다. 그것이 틀렸다 — **빈 읽기도 닿은 것**이라 그 시각은 언제나 선다.
417
+ * 그래서 창을 채우는 중인 트윈(제시 200건)까지 「오는 것이 없다」로 답하게 됐고, 시험이 그것을 잡았다.
418
+ * 받고 있는 중인데 오는 것이 없다고 말하는 것은 **없는 것과 못 본 것을 뒤집는 것**이다.
419
+ *
420
+ * 닿았고 · 제시가 0 오는 것이 없다 `no-traffic`
421
+ * 닿았고 · 제시가 있다 받는 중이고 판정할 창이 아직 없다 `unknown`
422
+ * 한 번도 닿지 않았다 `unknown`(위 `lastAtMs < 0` 갈래)
423
+ */
424
+ if (!args.recent) {
425
+ const touched = typeof args.lastAtMs === 'number' && args.lastAtMs >= 0;
426
+ const nothingOffered = (args.offeredTotal ?? 0) <= 0;
427
+ return touched && nothingOffered ? 'no-traffic' : 'unknown';
428
+ }
358
429
  if (args.recent.offered <= 0)
359
430
  return 'no-traffic';
360
431
  const ratio = (args.recent.offered - args.recent.rejected) / args.recent.offered;
@@ -394,6 +465,8 @@ function ingestHealth(ledger, feedState, threshold = exports.HEALTHY_ACCEPTED_RA
394
465
  recent: recentRaw,
395
466
  lastAtMs: ledger?.lastAtMs ?? -1,
396
467
  lastUndeliveredAtMs: ledger?.lastUndeliveredAtMs ?? -1,
468
+ /* 창이 닫히지 않았을 때 「받는 중」과 「오는 것이 없다」를 가르는 사실. */
469
+ offeredTotal: ledger?.offered ?? 0,
397
470
  nowMs,
398
471
  threshold
399
472
  });
@@ -429,12 +502,22 @@ function ingestHealth(ledger, feedState, threshold = exports.HEALTHY_ACCEPTED_RA
429
502
  since: new Date(ledger.readFailure.sinceMs).toISOString(),
430
503
  lastAt: new Date(ledger.readFailure.lastAtMs).toISOString(),
431
504
  reason: ledger.readFailure.reason,
432
- ...(ledger.readFailure.stream ? { stream: ledger.readFailure.stream } : {})
505
+ ...(ledger.readFailure.stream ? { stream: ledger.readFailure.stream } : {}),
506
+ ...(ledger.readFailure.nextRetryMs ? { nextRetryMs: ledger.readFailure.nextRetryMs } : {})
507
+ }
508
+ }
509
+ : {}),
510
+ ...(ledger?.lastRecovery
511
+ ? {
512
+ lastRecovery: {
513
+ at: new Date(ledger.lastRecovery.atMs).toISOString(),
514
+ afterFailures: ledger.lastRecovery.afterFailures,
515
+ downMs: ledger.lastRecovery.downMs
433
516
  }
434
517
  }
435
518
  : {}),
436
519
  /* 커서 정체도 **이 갈래에서** 내보낸다 — 유입이 없는 장부에서도 정체는 실재한다(읽었으나 못
437
- 넘겼으면 유입이 0이다). 여기서 떨어뜨리면 바로 그 상황에서 조용해진다. */
520
+ 넘겼으면 유입이 0이다). 여기서 떨어뜨리면 바로 그 상황에서 들어온 것이 없어진다. */
438
521
  ...(ledger?.cursorStall
439
522
  ? {
440
523
  cursorStall: {
@@ -448,7 +531,7 @@ function ingestHealth(ledger, feedState, threshold = exports.HEALTHY_ACCEPTED_RA
448
531
  : {}),
449
532
  /*
450
533
  * **세우지 않은 것도 낸다 — 양쪽 갈래에서.** 유입이 한 건도 없는 장부에서도 이 사실은 실재한다
451
- * (원본이 말하는데 전부 안 받는 경우가 있다). 여기서 떨어뜨리면 바로 그 상황에서 조용해진다.
534
+ * (원본이 말하는데 전부 안 받는 경우가 있다). 여기서 떨어뜨리면 바로 그 상황에서 들어온 것이 없어진다.
452
535
  */
453
536
  ...(ledger?.withheld?.length
454
537
  ? {
@@ -479,6 +562,21 @@ function ingestHealth(ledger, feedState, threshold = exports.HEALTHY_ACCEPTED_RA
479
562
  }))
480
563
  }
481
564
  : {}),
565
+ /*
566
+ * **어떤 길로 들어오고 있나** — 화면이 「이 트윈은 무엇을 통해 값을 받나」를 말할 수 있게.
567
+ * 비어 있으면 칸을 만들지 않는다: 아직 아무것도 안 받은 트윈과 「길이 없다」를 구별한다.
568
+ */
569
+ ...(Object.keys(ledger.bySource).length
570
+ ? {
571
+ sources: Object.entries(ledger.bySource)
572
+ .map(([source, v]) => ({ source, count: v.count, lastAt: new Date(v.lastAtMs).toISOString() }))
573
+ .sort((a, b) => b.count - a.count)
574
+ }
575
+ : {}),
576
+ /* 같은 사실이 두 번 와서 버린 수 — 0 이면 칸을 만들지 않는다(버린 적이 없다는 뜻이다). */
577
+ ...(ledger.duplicates
578
+ ? { duplicates: { count: ledger.duplicates, lastAt: new Date(ledger.lastDuplicateAtMs).toISOString() } }
579
+ : {}),
482
580
  total: {
483
581
  offered: ledger.offered,
484
582
  accepted,
@@ -505,7 +603,18 @@ function ingestHealth(ledger, feedState, threshold = exports.HEALTHY_ACCEPTED_RA
505
603
  since: new Date(ledger.readFailure.sinceMs).toISOString(),
506
604
  lastAt: new Date(ledger.readFailure.lastAtMs).toISOString(),
507
605
  reason: ledger.readFailure.reason,
508
- ...(ledger.readFailure.stream ? { stream: ledger.readFailure.stream } : {})
606
+ ...(ledger.readFailure.stream ? { stream: ledger.readFailure.stream } : {}),
607
+ ...(ledger.readFailure.nextRetryMs ? { nextRetryMs: ledger.readFailure.nextRetryMs } : {})
608
+ }
609
+ }
610
+ : {}),
611
+ /* 끊겼다가 돌아온 것 — 지금 닿고 있어도 남긴다(그것이 없으면 밤새의 단절이 사라진다). */
612
+ ...(ledger.lastRecovery
613
+ ? {
614
+ lastRecovery: {
615
+ at: new Date(ledger.lastRecovery.atMs).toISOString(),
616
+ afterFailures: ledger.lastRecovery.afterFailures,
617
+ downMs: ledger.lastRecovery.downMs
509
618
  }
510
619
  }
511
620
  : {}),