@things-factory/headless-twin 10.1.278 → 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,333 +0,0 @@
1
- /*
2
- * **밀어 받는 길의 번호** — 빠진 것을 알아채고, 재기동을 넘어 이어받는다.
3
- *
4
- * ── 왜 이 시험이 있나 (2026-08-31) ────────────────────────────────────────
5
- * 훅이 놓치는 것은 예외가 아니라 정상이다. 우리가 내려가 있을 때, 그쪽이 못 보냈을 때, 네트워크가
6
- * 끊겼을 때. 그 대비가 드문 폴링 하나뿐이었다 — 폴링은 「놓친 것이 있나」를 값으로 알아내는 것이고,
7
- * 번호는 빠진 것을 곧바로 안다.
8
- *
9
- * ── 왜 순수 함수 시험만으로 부족한가 ─────────────────────────────────────
10
- * 번호 판정 자체는 계약 쪽에서 확인한다(`ops-contract/test/webhook-contract.test.ts`). 여기서 보는
11
- * 것은 **배선**이다 — 판정이 응답이 되는가, 커서에 적히는가, 다시 세운 뒤에 읽히는가.
12
- *
13
- * 이 저장소에서 가장 자주 나는 결함이 「자리는 있고 길이 없다」이고, 커서가 정확히 그 모양이었다.
14
- * `TwinReference.liveCursor` 는 재기동을 넘어 사는 자리인데 **훅 경로가 그것을 읽지도 쓰지도 않았다.**
15
- * 쓰는 곳은 폴링 하나뿐이었다.
16
- *
17
- * 그래서 마지막 시험이 저장본을 그대로 두고 **핸들러를 새로 부른다.** 한 프로세스 안에서만 확인하면
18
- * 「적히나」는 보이지만 「다시 세우면 읽히나」는 보이지 않는다.
19
- */
20
- import { test } from 'node:test'
21
- import assert from 'node:assert/strict'
22
-
23
- import { WEBHOOK_STATUS, webhookSenderAction } from '@operato/ops-contract'
24
-
25
- import { handleHook, type HookStore } from '../server/service/reference/reference-hook.js'
26
- import { registerAdapterType, getAdapter } from '../server/service/reference/reference-adapter.js'
27
-
28
- const DOMAIN = 'd-1'
29
- const SOURCE = 'operato-plant'
30
- const TWIN = 'twin-a'
31
- const SECRET = 'shared-secret'
32
- const SCOPE = 'EVENTS'
33
- /** 커서 열쇠에는 트윈이 함께 들어간다 — 연결 하나가 트윈 여럿을 만든다. */
34
- const KEY = `${TWIN}::${SCOPE}`
35
-
36
- /** 보낸 봉투를 그대로 레코드로 내는 커넥터 — 옮길 것이 없으므로 번호만 꺼낸다. */
37
- const ADAPTER_TYPE = 'test-numbered-push'
38
- if (!getAdapter(ADAPTER_TYPE)) {
39
- registerAdapterType({
40
- type: ADAPTER_TYPE,
41
- label: 'numbered push (test)',
42
- handleInbound: (_cfg: any, _site: any, body: any) => ({
43
- items: body?.items ?? [{ record: { moverId: 'eq-1', kind: 'press', status: 'idle' }, seq: body?.seq }],
44
- scope: body?.scope
45
- })
46
- } as any)
47
- }
48
-
49
- /** 저장본 하나 — 프로세스가 아니라 여기에 산다. 그래서 핸들러를 새로 불러도 남는다. */
50
- function makeStore(initial?: unknown): HookStore & { row: any } {
51
- const row = {
52
- id: 'ref-1',
53
- source: SOURCE,
54
- adapterType: ADAPTER_TYPE,
55
- connectionConfig: { hookSecret: SECRET },
56
- scopeSpec: { produced: [{ siteId: 'site-a', instanceId: TWIN }] },
57
- liveCursor: initial
58
- }
59
- return {
60
- row,
61
- load: async (domainId: string, source: string) => (domainId === DOMAIN && source === SOURCE ? row : null),
62
- saveCursor: async (refId: string, cursor: unknown) => {
63
- assert.equal(refId, row.id)
64
- /* 저장소를 흉내 내는 것이라 참조를 그대로 두지 않고 복사해 넣는다 — 같은 객체면 안 적혀도 통과한다. */
65
- row.liveCursor = JSON.parse(JSON.stringify(cursor))
66
- }
67
- }
68
- }
69
-
70
- const applied = (_id: string, records: unknown[]) => ({ applied: records.length, duplicates: 0, rejected: [] })
71
-
72
- function push(store: HookStore, seq: number | undefined, opts: { scope?: string; ingest?: any } = {}) {
73
- return handleHook({
74
- domainId: DOMAIN,
75
- source: SOURCE,
76
- instanceId: TWIN,
77
- headers: { 'x-twin-hook-secret': SECRET },
78
- body: { seq, scope: 'scope' in opts ? opts.scope : SCOPE },
79
- nowMs: Date.parse('2026-08-31T02:00:00.000Z'),
80
- ingest: opts.ingest ?? applied,
81
- store
82
- })
83
- }
84
-
85
- test('★ 첫 봉투를 받고 그 번호를 커서에 적는다', async () => {
86
- const store = makeStore()
87
- const out = await push(store, 918342)
88
-
89
- assert.equal(out.status, WEBHOOK_STATUS.ok)
90
- assert.equal(out.body.sequenceChecked, true)
91
- assert.equal(out.body.lastSeq, 918342)
92
- assert.equal(store.row.liveCursor?.streams?.[KEY]?.seq, 918342, '커서에 적히지 않았다')
93
- })
94
-
95
- test('★ 건너뛴 번호는 409 로 답하고 그 앞부터 달라고 한다', async () => {
96
- const store = makeStore({ streams: { [KEY]: { seq: 4 } } })
97
- const out = await push(store, 7)
98
-
99
- assert.equal(out.status, WEBHOOK_STATUS.sequenceGap)
100
- assert.equal(out.body.expectedSeq, 5)
101
- assert.equal(out.body.lastSeq, 4)
102
- assert.equal(out.body.scope, SCOPE, '어느 줄의 번호인지 함께 말한다')
103
- })
104
-
105
- test('★ 구멍이 났을 때 커서를 올리지 않는다 — 올리면 그 구간이 영영 안 온다', async () => {
106
- const store = makeStore({ streams: { [KEY]: { seq: 4 } } })
107
- await push(store, 7)
108
- assert.equal(store.row.liveCursor.streams[KEY].seq, 4)
109
- })
110
-
111
- test('★ 이미 본 번호는 받아들이되 커서를 뒤로 끌지 않는다 — 재전송이 정상 동작이다', async () => {
112
- const store = makeStore({ streams: { [KEY]: { seq: 9 } } })
113
- const out = await push(store, 9)
114
-
115
- assert.equal(out.status, WEBHOOK_STATUS.ok)
116
- assert.equal(store.row.liveCursor.streams[KEY].seq, 9)
117
- })
118
-
119
- test('★ 반영되지 않았으면 커서를 올리지 않는다 — 트윈이 안 도는 사이의 번호를 지나치면 그 구간이 빈다', async () => {
120
- const store = makeStore({ streams: { [KEY]: { seq: 4 } } })
121
- const out = await push(store, 5, { ingest: () => ({ applied: 0, duplicates: 0, rejected: [] }) })
122
-
123
- assert.equal(out.status, WEBHOOK_STATUS.notLive)
124
- assert.equal(store.row.liveCursor.streams[KEY].seq, 4, '한 건도 안 들어갔는데 번호가 올라갔다')
125
- })
126
-
127
- test('★ 번호를 매기지 않는 원본은 확인하지 않고, 확인하지 않았다고 말한다', async () => {
128
- /* chef · ppms 가 그렇다. 「확인했고 이상 없다」와 같아 보이면 어느 연결이 지켜지는지 알 수 없다. */
129
- const store = makeStore()
130
- const out = await push(store, undefined, { scope: undefined })
131
-
132
- assert.equal(out.status, WEBHOOK_STATUS.ok)
133
- assert.equal(out.body.sequenceChecked, false)
134
- assert.equal(store.row.liveCursor, undefined, '번호가 없으면 커서를 만들지 않는다')
135
- })
136
-
137
- test('★ 번호만 있고 어느 줄인지 없으면 확인하지 않는다 — 짐작한 열쇠는 줄이 늘면 어긋난다', async () => {
138
- const store = makeStore()
139
- const out = await push(store, 918342, { scope: undefined })
140
-
141
- assert.equal(out.status, WEBHOOK_STATUS.ok)
142
- assert.equal(out.body.sequenceChecked, false)
143
- })
144
-
145
- test('★ 줄마다 번호가 따로 간다 — 두 줄이 한 커서에 섞이면 끊임없이 「빠졌다」가 된다', async () => {
146
- const store = makeStore()
147
- await push(store, 5, { scope: 'EVENTS' })
148
- await push(store, 1, { scope: 'MASTER' })
149
-
150
- assert.equal(store.row.liveCursor.streams[`${TWIN}::EVENTS`].seq, 5)
151
- assert.equal(store.row.liveCursor.streams[`${TWIN}::MASTER`].seq, 1)
152
-
153
- /* MASTER 의 1 이 EVENTS 의 5 를 되돌리지 않았으므로 EVENTS 6 이 그대로 이어진다. */
154
- assert.equal((await push(store, 6, { scope: 'EVENTS' })).status, WEBHOOK_STATUS.ok)
155
- })
156
-
157
- test('★ 재기동을 넘어 이어받는다 — 저장본만 남기고 핸들러를 새로 부른다', async () => {
158
- const first = makeStore()
159
- await push(first, 5)
160
- const saved = JSON.parse(JSON.stringify(first.row.liveCursor))
161
-
162
- /* 프로세스가 새로 선 것으로 본다 — 앞의 저장소 객체는 버리고 저장본만 물려준다. */
163
- const second = makeStore(saved)
164
-
165
- assert.equal((await push(second, 7)).status, WEBHOOK_STATUS.sequenceGap, '이어받지 못하면 7 이 그냥 통과한다')
166
- assert.equal((await push(second, 6)).status, WEBHOOK_STATUS.ok)
167
- assert.equal(second.row.liveCursor.streams[KEY].seq, 6)
168
- })
169
-
170
- test('★ 커서를 적지 못해도 이미 들어간 사실을 무르지 않는다 — 다음 번호에서 구멍으로 드러난다', async () => {
171
- const store = makeStore()
172
- const broken: HookStore = { load: store.load, saveCursor: async () => { throw new Error('disk full') } }
173
-
174
- const out = await push(broken, 5)
175
- assert.equal(out.status, WEBHOOK_STATUS.ok, '유입은 이미 끝났다 — 커서를 못 적은 것이 그것을 무를 이유가 아니다')
176
- })
177
-
178
- /* ── 한 요청에 봉투 여럿 ──────────────────────────────────────────────────── */
179
-
180
- /** 번호가 붙은 봉투 여럿을 한 요청으로 보낸다 — 밀어 주는 쪽은 한 건씩 보내지 않는다. */
181
- function pushBatch(store: HookStore, seqs: number[], opts: { scope?: string; ingest?: any } = {}) {
182
- return handleHook({
183
- domainId: DOMAIN,
184
- source: SOURCE,
185
- instanceId: TWIN,
186
- headers: { 'x-twin-hook-secret': SECRET },
187
- body: {
188
- scope: 'scope' in opts ? opts.scope : SCOPE,
189
- items: seqs.map(seq => ({ seq, record: { moverId: `eq-${seq}`, kind: 'press', status: 'idle' } }))
190
- },
191
- nowMs: Date.parse('2026-08-31T02:00:00.000Z'),
192
- ingest: opts.ingest ?? applied,
193
- store
194
- })
195
- }
196
-
197
- test('★ 배치 가운데가 빠지면 그 앞까지만 받는다 — 구멍 뒤를 받으면 그 구멍이 영영 안 메워진다', async () => {
198
- const store = makeStore({ streams: { [KEY]: { seq: 4 } } })
199
- const taken: unknown[][] = []
200
- const out = await pushBatch(store, [5, 6, 9, 10], {
201
- ingest: (_id: string, records: unknown[]) => {
202
- taken.push(records)
203
- return { applied: records.length, duplicates: 0, rejected: [] }
204
- }
205
- })
206
-
207
- assert.equal(taken[0].length, 2, '5·6 만 넣어야 한다')
208
- assert.equal(out.status, WEBHOOK_STATUS.sequenceGap)
209
- assert.equal(out.body.expectedSeq, 7)
210
- assert.equal(out.body.lastSeq, 6, '앞의 것은 받았다는 것을 함께 말한다 — 안 그러면 5·6 을 또 보낸다')
211
- assert.equal(store.row.liveCursor.streams[KEY].seq, 6)
212
- })
213
-
214
- test('★ 배치 전체가 이어지면 끝 번호가 커서가 된다', async () => {
215
- const store = makeStore({ streams: { [KEY]: { seq: 4 } } })
216
- const out = await pushBatch(store, [5, 6, 7])
217
-
218
- assert.equal(out.status, WEBHOOK_STATUS.ok)
219
- assert.equal(out.body.lastSeq, 7)
220
- assert.equal(store.row.liveCursor.streams[KEY].seq, 7)
221
- })
222
-
223
- test('★ 첫 봉투부터 구멍이면 아무것도 넣지 않고 커서도 그대로다', async () => {
224
- const store = makeStore({ streams: { [KEY]: { seq: 4 } } })
225
- let called = false
226
- const out = await pushBatch(store, [9, 10], {
227
- ingest: () => {
228
- called = true
229
- return { applied: 2, duplicates: 0, rejected: [] }
230
- }
231
- })
232
-
233
- assert.equal(called, false, '받을 것이 없는데 유입을 불렀다')
234
- assert.equal(out.status, WEBHOOK_STATUS.sequenceGap)
235
- assert.equal(out.body.expectedSeq, 5)
236
- assert.equal(store.row.liveCursor.streams[KEY].seq, 4)
237
- })
238
-
239
- test('★ 번호가 있는 봉투와 없는 봉투를 섞으면 받지 않는다 — 반쯤 확인한 것을 확인했다고 말하지 않는다', async () => {
240
- const store = makeStore()
241
- const out = await handleHook({
242
- domainId: DOMAIN,
243
- source: SOURCE,
244
- instanceId: TWIN,
245
- headers: { 'x-twin-hook-secret': SECRET },
246
- body: { scope: SCOPE, items: [{ seq: 1, record: {} }, { record: {} }] },
247
- nowMs: Date.parse('2026-08-31T02:00:00.000Z'),
248
- ingest: applied,
249
- store
250
- })
251
-
252
- assert.equal(out.status, WEBHOOK_STATUS.badPayload)
253
- assert.match(String(out.body.error), /mixed batch/)
254
- })
255
-
256
- /* ── 일부만 떨어졌을 때 ───────────────────────────────────────────────────── */
257
-
258
- const REJECT_ONE = (_id: string, records: unknown[]) => ({
259
- applied: records.length - 1,
260
- duplicates: 0,
261
- rejected: [{ record: records[records.length - 1], errors: ['equipment: 계약에 없는 필드 — foo'] }]
262
- })
263
-
264
- test('★ 일부가 떨어지면 422 로 답하고 무엇이 떨어졌는지 함께 준다', async () => {
265
- const store = makeStore({ streams: { [KEY]: { seq: 4 } } })
266
- const out = await pushBatch(store, [5, 6], { ingest: REJECT_ONE })
267
-
268
- assert.equal(out.status, WEBHOOK_STATUS.partial)
269
- assert.equal((out.body.rejected as any[]).length, 1)
270
- assert.match(String((out.body.rejected as any[])[0].errors[0]), /계약에 없는 필드/)
271
- })
272
-
273
- test('★ 떨어진 것이 있어도 다시 보내라고 하지 않는다 — 나머지는 이미 들어갔다', async () => {
274
- assert.equal(webhookSenderAction(WEBHOOK_STATUS.partial), 'partial')
275
- assert.notEqual(webhookSenderAction(WEBHOOK_STATUS.partial), 'resend-from')
276
- })
277
-
278
- test('★ 일부가 떨어져도 받은 데까지 커서가 간다 — 안 그러면 그 구간이 매번 다시 온다', async () => {
279
- const store = makeStore({ streams: { [KEY]: { seq: 4 } } })
280
- const out = await pushBatch(store, [5, 6], { ingest: REJECT_ONE })
281
-
282
- assert.equal(out.body.lastSeq, 6)
283
- assert.equal(store.row.liveCursor.streams[KEY].seq, 6)
284
- })
285
-
286
- test('★ 구멍과 떨어진 것이 함께 나면 한 응답에 둘 다 싣는다', async () => {
287
- /* 두 소식이 갈라져 오면 보내는 쪽은 둘 중 하나만 한다. */
288
- const store = makeStore({ streams: { [KEY]: { seq: 4 } } })
289
- const out = await pushBatch(store, [5, 6, 9], { ingest: REJECT_ONE })
290
-
291
- assert.equal(out.status, WEBHOOK_STATUS.sequenceGap, '연속성이 먼저다 — 그것이 다음에 무엇을 보낼지 정한다')
292
- assert.equal(out.body.expectedSeq, 7)
293
- assert.equal(out.body.lastSeq, 6)
294
- assert.equal((out.body.rejected as any[]).length, 1, '떨어진 것도 함께 알린다')
295
- })
296
-
297
- test('전부 통과하면 떨어진 목록이 빈다 — 없는 것과 안 본 것이 같아 보이지 않게', async () => {
298
- const store = makeStore()
299
- const out = await pushBatch(store, [1, 2])
300
- assert.deepEqual(out.body.rejected, [])
301
- })
302
-
303
- test('★ 한 연결이 만든 두 트윈이 계수기를 함께 쓰지 않는다', async () => {
304
- /*
305
- * 커서는 연결마다 한 행에 산다(`TwinReference.liveCursor`). 그런데 연결 하나가 트윈 여럿을 만든다.
306
- * 보내는 쪽의 단위 이름만으로 열쇠를 잡으면 두 공장이 한 계수기를 쓰고, B 의 1 이 A 의 5 뒤에서
307
- * 「이미 본 번호」로 버려진다.
308
- */
309
- const store = makeStore()
310
- const other = 'twin-b'
311
- store.row.scopeSpec.produced.push({ siteId: 'site-b', instanceId: other })
312
-
313
- const send = (instanceId: string, seq: number) =>
314
- handleHook({
315
- domainId: DOMAIN,
316
- source: SOURCE,
317
- instanceId,
318
- headers: { 'x-twin-hook-secret': SECRET },
319
- body: { scope: SCOPE, items: [{ seq, record: { moverId: 'eq-1', kind: 'press', status: 'idle' } }] },
320
- nowMs: Date.parse('2026-08-31T02:00:00.000Z'),
321
- ingest: applied,
322
- store
323
- })
324
-
325
- await send(TWIN, 5)
326
- const first = await send(other, 1)
327
- assert.equal(first.status, WEBHOOK_STATUS.ok, 'B 공장의 첫 봉투가 A 공장의 번호에 걸려 버려졌다')
328
-
329
- assert.equal(store.row.liveCursor.streams[`${TWIN}::${SCOPE}`].seq, 5)
330
- assert.equal(store.row.liveCursor.streams[`${other}::${SCOPE}`].seq, 1)
331
-
332
- assert.equal((await send(TWIN, 6)).status, WEBHOOK_STATUS.ok, 'A 공장이 B 의 번호에 끌려갔다')
333
- })
@@ -1,70 +0,0 @@
1
- /*
2
- * 커널 인제스트 인터페이스 부하 실측(가정 아닌 측정) — Face1/커널 동기 인터페이스의 처리량 특성.
3
- * apply(이벤트 흡수) · snapshot(전체 투영) · buildEntityDeltas(브로드캐스팅 payload, 't1') 의 비용을 규모별로 잰다.
4
- * 결론은 design/integration/ingest-scale.md §커널 인터페이스에 스펙으로 반영.
5
- * (순수 커널+호스트 매핑, shell 무관 → node:test.)
6
- */
7
- import { test } from 'node:test'
8
- import assert from 'node:assert/strict'
9
-
10
- import { StateProjector } from '@operato/twin-kernel'
11
- import { objectEvent, BIZSTEP, DISP } from '@operato/ops-contract'
12
- import { buildEntityDeltas } from '../shared/entity-delta.ts'
13
-
14
- const T0 = '2026-07-19T00:00:00.000Z'
15
- const model = (nNodes: number) => ({
16
- locations: Array.from({ length: nNodes }, (_, i) => ({ id: `bin-${i}`, type: 'storage', capacity: 100000 })),
17
- equipment: []
18
- })
19
- function envelope(epc: string, location: string): any {
20
- const ev = objectEvent({ eventTime: T0, action: 'OBSERVE' as any, bizStep: BIZSTEP.storing, disposition: DISP.sellable, epcList: [epc], readPoint: location })
21
- return { eventId: 'x', eventType: `epcis.${ev.type}`, eventTime: T0, tenantId: 't', data: ev }
22
- }
23
-
24
- test('bench: apply 처리량(이벤트 흡수)', () => {
25
- const nNodes = 200
26
- const M = 200_000
27
- const proj = new StateProjector(model(nNodes))
28
- const t0 = performance.now()
29
- for (let i = 0; i < M; i++) proj.apply(envelope(`urn:epc:id:sscc:0614141.${i}`, `bin-${i % nNodes}`))
30
- const dt = performance.now() - t0
31
- console.log(` [apply] ${M.toLocaleString()} events in ${dt.toFixed(0)}ms = ${Math.round((M / dt) * 1000).toLocaleString()} ev/s`)
32
- assert.ok(dt > 0)
33
- })
34
-
35
- test('bench: snapshot 비용 vs item 수 (전체 O(N) 재구성)', () => {
36
- for (const N of [1000, 10000, 50000]) {
37
- const proj = new StateProjector(model(200))
38
- for (let i = 0; i < N; i++) proj.apply(envelope(`urn:epc:id:sscc:0614141.${i}`, `bin-${i % 200}`))
39
- const iters = 200
40
- const t0 = performance.now()
41
- for (let k = 0; k < iters; k++) proj.snapshot()
42
- const per = (performance.now() - t0) / iters
43
- console.log(` [snapshot] @ ${N.toLocaleString()} items: ${per.toFixed(3)}ms/call → 최대 ${Math.round(1000 / per).toLocaleString()} snapshot/s`)
44
- }
45
- })
46
-
47
- test('bench: buildEntityDeltas 비용 vs 엔티티 수 (전 엔티티 매번 방출)', () => {
48
- for (const N of [100, 1000, 5000]) {
49
- const proj = new StateProjector(model(N))
50
- for (let i = 0; i < N * 5; i++) proj.apply(envelope(`urn:epc:id:sscc:0614141.${i}`, `bin-${i % N}`))
51
- const snap = proj.snapshot()
52
- const iters = 200
53
- const t0 = performance.now()
54
- for (let k = 0; k < iters; k++) buildEntityDeltas(snap, 't1')
55
- const per = (performance.now() - t0) / iters
56
- console.log(` [buildEntityDeltas] @ ${N.toLocaleString()} locations: ${per.toFixed(3)}ms/call`)
57
- }
58
- })
59
-
60
- test('bench: 브로드캐스팅 1회 총비용(snapshot + buildEntityDeltas) vs 상태 규모', () => {
61
- for (const [locations, items] of [[200, 5000], [1000, 50000], [2000, 100000]]) {
62
- const proj = new StateProjector(model(locations))
63
- for (let i = 0; i < items; i++) proj.apply(envelope(`urn:epc:id:sscc:0614141.${i}`, `bin-${i % locations}`))
64
- const iters = 100
65
- const t0 = performance.now()
66
- for (let k = 0; k < iters; k++) buildEntityDeltas(proj.snapshot(), 't1')
67
- const per = (performance.now() - t0) / iters
68
- console.log(` [브로드캐스팅1회] ${locations.toLocaleString()} locations / ${items.toLocaleString()} items: ${per.toFixed(3)}ms → 최대 ${Math.round(1000 / per).toLocaleString()} 브로드캐스팅/s`)
69
- }
70
- })
@@ -1,56 +0,0 @@
1
- /*
2
- * 같은 사실을 두 번 받았을 때 한 번으로 세는 근거 — **정체**.
3
- *
4
- * 정체를 못 만들면 그 사실은 dedupe 밖이고, 다시 받을 때마다 저널에 새로 앉는다. backfill 이 그것을
5
- * 드러냈다(2026-09-06).
6
- */
7
- import { test } from 'node:test'
8
- import assert from 'node:assert/strict'
9
-
10
- import { factIdentity, takeUnidentified } from '../server/engine/ingest-dedupe.js'
11
-
12
- /* ── 주체가 subjectId 인 사실 ───────────────────────────────────────────────── */
13
-
14
- test('★ 처분과 시험은 subjectId 가 주체다 — 그 이름이 없으면 정체가 안 만들어진다', () => {
15
- /*
16
- * [측정함 2026-09-06] `fillTwinScope` 를 돌릴 때마다 처분 4건 · 시험 3건이 다시 앉았다. 나머지
17
- * 34건은 걸러지는데 이 둘만 계속 늘었다.
18
- *
19
- * 원인은 `discriminatorsOf` 에 `subjectId` 가 없어서 `parts` 가 비고, `factIdentity` 가
20
- * `undefined` 를 낸 것이다. 정체가 없으면 dedupe 밖이다.
21
- */
22
- const disposition = {
23
- eventType: 'nonconformance.disposition',
24
- eventTime: '2026-09-01T02:50:51.832Z',
25
- data: { subjectId: 'LOT-A', decision: 'scrap', quantity: 50 }
26
- }
27
- const id = factIdentity(disposition)
28
- assert.ok(id, '정체를 못 만들면 다시 받을 때마다 새로 앉는다')
29
- assert.ok(id!.includes('subject=LOT-A'), `주체가 정체에 안 들어갔다: ${id}`)
30
- })
31
-
32
- test('★ 다른 로트의 같은 처분은 다른 사실이다', () => {
33
- const at = '2026-09-01T02:50:51.832Z'
34
- const a = factIdentity({ eventType: 'nonconformance.disposition', eventTime: at, data: { subjectId: 'LOT-A', decision: 'scrap' } })
35
- const b = factIdentity({ eventType: 'nonconformance.disposition', eventTime: at, data: { subjectId: 'LOT-F', decision: 'scrap' } })
36
- assert.notEqual(a, b, '두 로트의 처분이 한 사실로 뭉쳤다')
37
- })
38
-
39
- test('★ 같은 사실을 다시 받으면 같은 정체다 — backfill 이 저널을 안 부풀린다', () => {
40
- const rec = { eventType: 'nonconformance.disposition', eventTime: '2026-09-01T02:50:51.832Z', data: { subjectId: 'LOT-A', decision: 'scrap', quantity: 50 } }
41
- assert.equal(factIdentity(rec), factIdentity({ ...rec, data: { ...rec.data } }))
42
- })
43
-
44
- test('★ 시험 결과는 명세도 가른다 — 같은 대상에 시험이 여럿이다', () => {
45
- const at = '2026-09-01T00:00:00.000Z'
46
- const a = factIdentity({ eventType: 'test.result', eventTime: at, data: { subjectId: 'EQ-1', specId: 'CP-PBA-INCOMING' } })
47
- const b = factIdentity({ eventType: 'test.result', eventTime: at, data: { subjectId: 'EQ-1', specId: 'CP-PBA-TEST' } })
48
- assert.notEqual(a, b, '같은 대상의 두 시험이 한 사실로 뭉쳤다')
49
- })
50
-
51
- test('★ 정체를 못 만든 것을 센다 — 조용히 dedupe 밖으로 나가지 않는다', () => {
52
- takeUnidentified()
53
- assert.equal(factIdentity({ eventType: 'made.up.kind', eventTime: '2026-09-01T00:00:00.000Z', data: {} }), undefined)
54
- assert.deepEqual(takeUnidentified(), { 'made.up.kind': 1 })
55
- assert.deepEqual(takeUnidentified(), {}, '읽고 비운다')
56
- })
@@ -1,111 +0,0 @@
1
- /*
2
- * ★ **지금은 조용한 것이 정상이다** — 밤마다 나던 거짓 빨강.
3
- *
4
- * ── 무엇이 틀렸나 (2026-09-04) ──────────────────────────────────────────────
5
- * 유입 건강이 **한 자로 전부를 쟀다.** 10분 안에 아무것도 오지 않으면 「유입 없음」이다. 그런데
6
- * 태양광은 밤에 발전하지 않고, 업무시간만 도는 원천은 저녁에 아무것도 내지 않는다. 정상인데
7
- * **매일 밤 절반이 빨갛게 났다.**
8
- *
9
- * 거짓 빨강이 쌓이면 진짜 빨강도 같이 안 읽힌다. 오늘 UX 레인이 「늘 참인 경고는 벽지가 된다」고
10
- * 한 것과 같은 부류다 — 사흘이면 그 자리에 무엇이 적혀도 안 읽는다.
11
- *
12
- * 그리고 15분마다 긷는 원천은 긷는 사이마다 빨갛다. 이 파일이 고치는 코드가 그 한계를 **스스로
13
- * 주석에 적어 두고 있었다**: 「주기를 알게 되면 그 값으로 견주는 것이 맞다」.
14
- *
15
- * ── 초록도 빨강도 아닌 셋째 값 ──────────────────────────────────────────────
16
- * 조용한 시간을 초록으로 칠하면 **밤에 정말 끊긴 원천**을 아침까지 아무도 모른다. 그래서 답은
17
- * 「지금은 안 오는 것이 맞다」이고, 그것은 다른 값이어야 한다.
18
- */
19
- import { test } from 'node:test'
20
- import assert from 'node:assert/strict'
21
-
22
- import { syncVerdictOf, STALE_AFTER_MS } from '../server/engine/ingest-health.js'
23
-
24
- const NOW = 1_800_000_000_000
25
- const long = NOW - STALE_AFTER_MS - 60_000 /* 한 창을 넘긴 침묵 */
26
-
27
- const at = (over: Record<string, unknown> = {}) =>
28
- syncVerdictOf({
29
- feedState: 'attached',
30
- recent: { offered: 100, rejected: 0 },
31
- lastAtMs: NOW - 1_000,
32
- nowMs: NOW,
33
- lastUndeliveredAtMs: -1,
34
- offeredTotal: 100,
35
- ...over
36
- } as any)
37
-
38
- /* ── 조용한 시간 ──────────────────────────────────────────────────────────── */
39
-
40
- test('★ 조용한 시간의 긴 침묵은 「유입 없음」이 아니다', () => {
41
- assert.equal(at({ lastAtMs: long, quietNow: true }), 'expected-quiet')
42
- })
43
-
44
- test('★ 같은 침묵이 활동 시간이면 「유입 없음」이다', () => {
45
- assert.equal(at({ lastAtMs: long, quietNow: false }), 'no-traffic')
46
- })
47
-
48
- test('★ 달력을 선언하지 않았으면 지금까지처럼 답한다 — 모르는 것을 「조용할 때」로 읽지 않는다', () => {
49
- /*
50
- * `quietNow` 를 주지 않은 원천이 전부 「지금은 조용한 시간」이 되면, 정말 끊긴 원천이 통째로
51
- * 조용해진다. 없으면 옛 거동 그대로다.
52
- */
53
- assert.equal(at({ lastAtMs: long }), 'no-traffic')
54
- })
55
-
56
- test('★ 조용한 시간이어도 사실이 사라지고 있으면 그것이 먼저다', () => {
57
- /*
58
- * 버려지는 중은 **몇 시든 문제**다. 밤이라고 덮으면 밤새 새는 것을 아침에 안다.
59
- */
60
- const v = at({ lastAtMs: long, quietNow: true, lastUndeliveredAtMs: NOW - 1_000 })
61
- assert.equal(v, 'twin-not-running')
62
- })
63
-
64
- test('★ 조용한 시간이어도 결선이 없으면 그것이 먼저다', () => {
65
- assert.equal(at({ feedState: 'detached', lastAtMs: long, quietNow: true }), 'not-connected')
66
- })
67
-
68
- test('★ 한 번도 받지 않았는데 지금이 조용한 시간이면 「모른다」가 아니다', () => {
69
- /*
70
- * 밤에 처음 붙인 태양광 연결이 「기다린다」로 보이면, 사람이 아침까지 무엇을 기다리는지 모른다.
71
- */
72
- assert.equal(at({ lastAtMs: -1, recent: null, offeredTotal: 0, quietNow: true }), 'expected-quiet')
73
- assert.equal(at({ lastAtMs: -1, recent: null, offeredTotal: 0 }), 'unknown')
74
- })
75
-
76
- test('★ 창이 비었어도 조용한 시간이면 정상이다', () => {
77
- assert.equal(at({ recent: { offered: 0, rejected: 0 }, quietNow: true }), 'expected-quiet')
78
- assert.equal(at({ recent: { offered: 0, rejected: 0 } }), 'no-traffic')
79
- })
80
-
81
- test('조용한 시간에도 받고 있으면 받는 중이다 — 침묵이 아니면 이 축이 개입하지 않는다', () => {
82
- assert.equal(at({ quietNow: true }), 'syncing')
83
- })
84
-
85
- /* ── 원천이 선언한 주기 ──────────────────────────────────────────────────── */
86
-
87
- test('★ 15분마다 긷는 원천은 그 주기 안에서 정상이다', () => {
88
- /*
89
- * 창 하나(10분)로 재면 긷는 사이마다 빨갛다. 원천이 주기를 선언하면 그것으로 견준다.
90
- */
91
- const twelveMin = NOW - 12 * 60_000
92
-
93
- assert.equal(at({ lastAtMs: twelveMin }), 'no-traffic', '선언이 없으면 옛 거동')
94
- assert.equal(at({ lastAtMs: twelveMin, expectedSilenceMs: 20 * 60_000 }), 'syncing')
95
- })
96
-
97
- test('★ 선언한 주기를 넘기면 그때는 「유입 없음」이다 — 선언이 면죄부가 아니다', () => {
98
- const thirtyMin = NOW - 30 * 60_000
99
- assert.equal(at({ lastAtMs: thirtyMin, expectedSilenceMs: 20 * 60_000 }), 'no-traffic')
100
- })
101
-
102
- test('0이나 음수 주기는 선언이 아니다 — 창 하나로 돌아간다', () => {
103
- for (const bad of [0, -1, NaN]) {
104
- assert.equal(at({ lastAtMs: long, expectedSilenceMs: bad }), 'no-traffic', `${bad} 를 주기로 받았다`)
105
- }
106
- })
107
-
108
- test('★ 주기와 달력은 다른 축이다 — 주기를 넘겼는데 조용한 시간이면 정상이다', () => {
109
- const thirtyMin = NOW - 30 * 60_000
110
- assert.equal(at({ lastAtMs: thirtyMin, expectedSilenceMs: 20 * 60_000, quietNow: true }), 'expected-quiet')
111
- })