@things-factory/headless-twin 10.1.277 → 10.1.279

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (614) hide show
  1. package/package.json +21 -7
  2. package/dist-server/engine/attention-digest.js.map +0 -1
  3. package/dist-server/engine/canonical-ingest.js.map +0 -1
  4. package/dist-server/engine/checkpoint-fold.js.map +0 -1
  5. package/dist-server/engine/command-routing.js.map +0 -1
  6. package/dist-server/engine/declared-stimulus.js.map +0 -1
  7. package/dist-server/engine/energy-topology.js.map +0 -1
  8. package/dist-server/engine/event-time.js.map +0 -1
  9. package/dist-server/engine/index.js.map +0 -1
  10. package/dist-server/engine/ingest-dedupe.js.map +0 -1
  11. package/dist-server/engine/ingest-health.js.map +0 -1
  12. package/dist-server/engine/integration-coverage.js.map +0 -1
  13. package/dist-server/engine/integration-probes.js.map +0 -1
  14. package/dist-server/engine/integration-runner.js.map +0 -1
  15. package/dist-server/engine/integration-target-profile.js.map +0 -1
  16. package/dist-server/engine/kpi-baseline.js.map +0 -1
  17. package/dist-server/engine/kpi-fold.js.map +0 -1
  18. package/dist-server/engine/kpi-query.js.map +0 -1
  19. package/dist-server/engine/kpi-target.js.map +0 -1
  20. package/dist-server/engine/live-attentions.js.map +0 -1
  21. package/dist-server/engine/live-feed-registry.js.map +0 -1
  22. package/dist-server/engine/load-meter.js.map +0 -1
  23. package/dist-server/engine/local-declarations.js.map +0 -1
  24. package/dist-server/engine/log.js.map +0 -1
  25. package/dist-server/engine/loop-lag.js.map +0 -1
  26. package/dist-server/engine/measured-estimator.js.map +0 -1
  27. package/dist-server/engine/measured-yield.js.map +0 -1
  28. package/dist-server/engine/model-basis.js.map +0 -1
  29. package/dist-server/engine/model-gap.js.map +0 -1
  30. package/dist-server/engine/model-refusal.js.map +0 -1
  31. package/dist-server/engine/model-vocabulary.js.map +0 -1
  32. package/dist-server/engine/oee-accumulator.js.map +0 -1
  33. package/dist-server/engine/operation-basis.js.map +0 -1
  34. package/dist-server/engine/producer-guard.js.map +0 -1
  35. package/dist-server/engine/property-effects.js.map +0 -1
  36. package/dist-server/engine/read-time.js.map +0 -1
  37. package/dist-server/engine/restart-policy.js.map +0 -1
  38. package/dist-server/engine/runtime-key.js.map +0 -1
  39. package/dist-server/engine/spec-coverage.js.map +0 -1
  40. package/dist-server/engine/stage-path.js.map +0 -1
  41. package/dist-server/engine/state-axes.js.map +0 -1
  42. package/dist-server/engine/structure-diff.js.map +0 -1
  43. package/dist-server/engine/travel-estimator.js.map +0 -1
  44. package/dist-server/engine/twin-engine.js.map +0 -1
  45. package/dist-server/engine/twin-state-channel.js.map +0 -1
  46. package/dist-server/engine/warm-start.js.map +0 -1
  47. package/dist-server/index.js.map +0 -1
  48. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js.map +0 -1
  49. package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js.map +0 -1
  50. package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js.map +0 -1
  51. package/dist-server/migrations/1786300000000-IndexEventTypeByTime.js.map +0 -1
  52. package/dist-server/migrations/1786400000000-IndexEventCreatedAt.js.map +0 -1
  53. package/dist-server/migrations/1786500000000-CreateTwinSubjectEvents.js.map +0 -1
  54. package/dist-server/migrations/1786600000000-RenameOperatoMesAdapterType.js.map +0 -1
  55. package/dist-server/migrations/1786700000000-AddDispatchRetryColumns.js.map +0 -1
  56. package/dist-server/migrations/1786800000000-CreateTwinReferenceReconciliations.js.map +0 -1
  57. package/dist-server/migrations/index.js.map +0 -1
  58. package/dist-server/routes.js.map +0 -1
  59. package/dist-server/service/actuation/actuation-advisor.js.map +0 -1
  60. package/dist-server/service/actuation/actuation-outcome.js.map +0 -1
  61. package/dist-server/service/actuation/actuation-rule-resolver.js.map +0 -1
  62. package/dist-server/service/actuation/actuation-rule.js.map +0 -1
  63. package/dist-server/service/actuation/approval-gateway.js.map +0 -1
  64. package/dist-server/service/actuation/catch-up-effects.js.map +0 -1
  65. package/dist-server/service/actuation/command-dispatcher.js.map +0 -1
  66. package/dist-server/service/actuation/command-store.js.map +0 -1
  67. package/dist-server/service/actuation/dispatch-after-approval.js.map +0 -1
  68. package/dist-server/service/actuation/effect-match.js.map +0 -1
  69. package/dist-server/service/actuation/index.js.map +0 -1
  70. package/dist-server/service/actuation/retry-plan.js.map +0 -1
  71. package/dist-server/service/actuation/rule-evaluate.js.map +0 -1
  72. package/dist-server/service/actuation/rule-loop.js.map +0 -1
  73. package/dist-server/service/actuation/rule-runner.js.map +0 -1
  74. package/dist-server/service/actuation/rule-wiring.js.map +0 -1
  75. package/dist-server/service/actuation/settle-effects.js.map +0 -1
  76. package/dist-server/service/actuation/sweep-dispatch.js.map +0 -1
  77. package/dist-server/service/actuation/twin-command-resolver.js.map +0 -1
  78. package/dist-server/service/actuation/twin-command.js.map +0 -1
  79. package/dist-server/service/actuation/twin-now.js.map +0 -1
  80. package/dist-server/service/index.js.map +0 -1
  81. package/dist-server/service/reference/actuation-routing.js.map +0 -1
  82. package/dist-server/service/reference/actuation-target.js.map +0 -1
  83. package/dist-server/service/reference/actuation-verification.js.map +0 -1
  84. package/dist-server/service/reference/attention-lane.js.map +0 -1
  85. package/dist-server/service/reference/connection-portability-resolver.js.map +0 -1
  86. package/dist-server/service/reference/connection-portability.js.map +0 -1
  87. package/dist-server/service/reference/control-routing.js.map +0 -1
  88. package/dist-server/service/reference/discovery-result.js.map +0 -1
  89. package/dist-server/service/reference/fill-cadence.js.map +0 -1
  90. package/dist-server/service/reference/fill-dedupe.js.map +0 -1
  91. package/dist-server/service/reference/fill-loop.js.map +0 -1
  92. package/dist-server/service/reference/fill-span.js.map +0 -1
  93. package/dist-server/service/reference/hook-contract.js.map +0 -1
  94. package/dist-server/service/reference/hook-rejected.js.map +0 -1
  95. package/dist-server/service/reference/hook-store.js.map +0 -1
  96. package/dist-server/service/reference/index.js.map +0 -1
  97. package/dist-server/service/reference/ingest-space.js.map +0 -1
  98. package/dist-server/service/reference/knob-defaults.js.map +0 -1
  99. package/dist-server/service/reference/live-cadence.js.map +0 -1
  100. package/dist-server/service/reference/live-feed-lease.js.map +0 -1
  101. package/dist-server/service/reference/live-ingest.js.map +0 -1
  102. package/dist-server/service/reference/reference-adapter.js.map +0 -1
  103. package/dist-server/service/reference/reference-assessment.js.map +0 -1
  104. package/dist-server/service/reference/reference-fill-run.js.map +0 -1
  105. package/dist-server/service/reference/reference-fill.js.map +0 -1
  106. package/dist-server/service/reference/reference-hook.js.map +0 -1
  107. package/dist-server/service/reference/reference-link-groups.js.map +0 -1
  108. package/dist-server/service/reference/reference-links.js.map +0 -1
  109. package/dist-server/service/reference/reference-live.js.map +0 -1
  110. package/dist-server/service/reference/reference-master.js.map +0 -1
  111. package/dist-server/service/reference/reference-probe.js.map +0 -1
  112. package/dist-server/service/reference/reference-progress-channel.js.map +0 -1
  113. package/dist-server/service/reference/reference-progress-subscription.js.map +0 -1
  114. package/dist-server/service/reference/reference-progress.js.map +0 -1
  115. package/dist-server/service/reference/reference-reconciliation-query.js.map +0 -1
  116. package/dist-server/service/reference/reference-reconciliation-writer.js.map +0 -1
  117. package/dist-server/service/reference/reference-reconciliation.js.map +0 -1
  118. package/dist-server/service/reference/reference-registry.js.map +0 -1
  119. package/dist-server/service/reference/reference-resolver.js.map +0 -1
  120. package/dist-server/service/reference/template-registry.js.map +0 -1
  121. package/dist-server/service/reference/twin-reference-reconciliation.js.map +0 -1
  122. package/dist-server/service/reference/twin-reference.js.map +0 -1
  123. package/dist-server/service/twin-attention/index.js.map +0 -1
  124. package/dist-server/service/twin-attention/twin-attention-query.js.map +0 -1
  125. package/dist-server/service/twin-audit/command-audit.js.map +0 -1
  126. package/dist-server/service/twin-audit/index.js.map +0 -1
  127. package/dist-server/service/twin-audit/twin-audit-event.js.map +0 -1
  128. package/dist-server/service/twin-audit/twin-audit-query.js.map +0 -1
  129. package/dist-server/service/twin-backfill/backfill-period-facts.js.map +0 -1
  130. package/dist-server/service/twin-backfill/backfill-shape.js.map +0 -1
  131. package/dist-server/service/twin-backfill/index.js.map +0 -1
  132. package/dist-server/service/twin-backfill/twin-backfill-resolver.js.map +0 -1
  133. package/dist-server/service/twin-control/index.js.map +0 -1
  134. package/dist-server/service/twin-control/twin-control-mutation.js.map +0 -1
  135. package/dist-server/service/twin-event/index.js.map +0 -1
  136. package/dist-server/service/twin-event/journal-count.js.map +0 -1
  137. package/dist-server/service/twin-event/twin-event-keys.js.map +0 -1
  138. package/dist-server/service/twin-event/twin-event-type.js.map +0 -1
  139. package/dist-server/service/twin-event/twin-event.js.map +0 -1
  140. package/dist-server/service/twin-forecast/forecast-metrics.js.map +0 -1
  141. package/dist-server/service/twin-forecast/forecast-tuning.js.map +0 -1
  142. package/dist-server/service/twin-forecast/gap-analytics.js.map +0 -1
  143. package/dist-server/service/twin-forecast/index.js.map +0 -1
  144. package/dist-server/service/twin-forecast/twin-forecast-query.js.map +0 -1
  145. package/dist-server/service/twin-ingest-window/index.js.map +0 -1
  146. package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js.map +0 -1
  147. package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js.map +0 -1
  148. package/dist-server/service/twin-ingest-window/twin-ingest-window.js.map +0 -1
  149. package/dist-server/service/twin-instance/index.js.map +0 -1
  150. package/dist-server/service/twin-instance/twin-instance.js.map +0 -1
  151. package/dist-server/service/twin-journal/event-type-split-shape.js.map +0 -1
  152. package/dist-server/service/twin-journal/event-type-split.js.map +0 -1
  153. package/dist-server/service/twin-journal/index.js.map +0 -1
  154. package/dist-server/service/twin-journal/journal-order.js.map +0 -1
  155. package/dist-server/service/twin-journal/twin-journal-query.js.map +0 -1
  156. package/dist-server/service/twin-lifecycle/domain-catalog.js.map +0 -1
  157. package/dist-server/service/twin-lifecycle/index.js.map +0 -1
  158. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +0 -1
  159. package/dist-server/service/twin-metrics/index.js.map +0 -1
  160. package/dist-server/service/twin-metrics/twin-metrics-query.js.map +0 -1
  161. package/dist-server/service/twin-model/axis-journal-evidence.js.map +0 -1
  162. package/dist-server/service/twin-model/choose-recipe.js.map +0 -1
  163. package/dist-server/service/twin-model/epcis-coverage.js.map +0 -1
  164. package/dist-server/service/twin-model/external-resolver.js.map +0 -1
  165. package/dist-server/service/twin-model/iec61850-coverage.js.map +0 -1
  166. package/dist-server/service/twin-model/index.js.map +0 -1
  167. package/dist-server/service/twin-model/isa95-coverage.js.map +0 -1
  168. package/dist-server/service/twin-model/item-ref.js.map +0 -1
  169. package/dist-server/service/twin-model/name-index.js.map +0 -1
  170. package/dist-server/service/twin-model/project-structure.js.map +0 -1
  171. package/dist-server/service/twin-model/standard-coverage.js.map +0 -1
  172. package/dist-server/service/twin-model/status-tally.js.map +0 -1
  173. package/dist-server/service/twin-model/twin-equipment.js.map +0 -1
  174. package/dist-server/service/twin-model/twin-lineage-query.js.map +0 -1
  175. package/dist-server/service/twin-model/twin-location.js.map +0 -1
  176. package/dist-server/service/twin-model/twin-model-item-query.js.map +0 -1
  177. package/dist-server/service/twin-model/twin-model-mutation.js.map +0 -1
  178. package/dist-server/service/twin-model/twin-model-query.js.map +0 -1
  179. package/dist-server/service/twin-model/twin-model-tree-query.js.map +0 -1
  180. package/dist-server/service/twin-model/twin-operation.js.map +0 -1
  181. package/dist-server/service/twin-readiness/index.js.map +0 -1
  182. package/dist-server/service/twin-readiness/twin-readiness-query.js.map +0 -1
  183. package/dist-server/service/twin-space/area-resolver.js.map +0 -1
  184. package/dist-server/service/twin-space/index.js.map +0 -1
  185. package/dist-server/service/twin-space/move-space.js.map +0 -1
  186. package/dist-server/service/twin-space/representation-role.js.map +0 -1
  187. package/dist-server/service/twin-space/space-integrity.js.map +0 -1
  188. package/dist-server/service/twin-space/twin-area.js.map +0 -1
  189. package/dist-server/service/twin-space/twin-space-area.js.map +0 -1
  190. package/dist-server/service/twin-space/twin-space-representation.js.map +0 -1
  191. package/dist-server/service/twin-space/twin-space-resolver.js.map +0 -1
  192. package/dist-server/service/twin-space/twin-space.js.map +0 -1
  193. package/dist-server/service/twin-state/index.js.map +0 -1
  194. package/dist-server/service/twin-state/twin-state-subscription.js.map +0 -1
  195. package/dist-server/service/twin-structure/index.js.map +0 -1
  196. package/dist-server/service/twin-structure/twin-structure.js.map +0 -1
  197. package/dist-server/service/twin-subject/event-subjects.js.map +0 -1
  198. package/dist-server/service/twin-subject/index.js.map +0 -1
  199. package/dist-server/service/twin-subject/item-resolver.js.map +0 -1
  200. package/dist-server/service/twin-subject/subject-query-shape.js.map +0 -1
  201. package/dist-server/service/twin-subject/twin-subject-backfill.js.map +0 -1
  202. package/dist-server/service/twin-subject/twin-subject-event.js.map +0 -1
  203. package/dist-server/service/twin-subject/twin-subject-fast-path.js.map +0 -1
  204. package/dist-server/service/twin-subject/twin-subject-query.js.map +0 -1
  205. package/dist-server/service/twin-subject/twin-subject-writer.js.map +0 -1
  206. package/dist-server/service/twin-target/index.js.map +0 -1
  207. package/dist-server/service/twin-target/twin-target-resolver.js.map +0 -1
  208. package/dist-server/service/twin-target/twin-target.js.map +0 -1
  209. package/dist-shared/axis-read.js.map +0 -1
  210. package/dist-shared/entity-delta.js.map +0 -1
  211. package/dist-shared/kpi-broadcast.js.map +0 -1
  212. package/dist-shared/touched-items.js.map +0 -1
  213. package/dist-shared/twin-level.js.map +0 -1
  214. package/server/engine/attention-digest.ts +0 -102
  215. package/server/engine/canonical-ingest.ts +0 -511
  216. package/server/engine/checkpoint-fold.ts +0 -12
  217. package/server/engine/command-routing.ts +0 -67
  218. package/server/engine/declared-stimulus.ts +0 -66
  219. package/server/engine/energy-topology.ts +0 -189
  220. package/server/engine/event-time.ts +0 -96
  221. package/server/engine/index.ts +0 -51
  222. package/server/engine/ingest-dedupe.ts +0 -24
  223. package/server/engine/ingest-health.ts +0 -24
  224. package/server/engine/integration-coverage.ts +0 -147
  225. package/server/engine/integration-probes.ts +0 -144
  226. package/server/engine/integration-runner.ts +0 -95
  227. package/server/engine/integration-target-profile.ts +0 -103
  228. package/server/engine/kpi-baseline.ts +0 -202
  229. package/server/engine/kpi-fold.ts +0 -1516
  230. package/server/engine/kpi-query.ts +0 -1210
  231. package/server/engine/kpi-target.ts +0 -248
  232. package/server/engine/live-attentions.ts +0 -30
  233. package/server/engine/live-feed-registry.ts +0 -59
  234. package/server/engine/load-meter.ts +0 -393
  235. package/server/engine/local-declarations.ts +0 -779
  236. package/server/engine/log.ts +0 -72
  237. package/server/engine/loop-lag.ts +0 -120
  238. package/server/engine/measured-estimator.ts +0 -91
  239. package/server/engine/measured-yield.ts +0 -89
  240. package/server/engine/model-basis.ts +0 -162
  241. package/server/engine/model-gap.ts +0 -168
  242. package/server/engine/model-refusal.ts +0 -31
  243. package/server/engine/model-vocabulary.ts +0 -82
  244. package/server/engine/oee-accumulator.ts +0 -195
  245. package/server/engine/operation-basis.ts +0 -131
  246. package/server/engine/producer-guard.ts +0 -64
  247. package/server/engine/property-effects.ts +0 -216
  248. package/server/engine/read-time.ts +0 -77
  249. package/server/engine/restart-policy.ts +0 -55
  250. package/server/engine/runtime-key.ts +0 -58
  251. package/server/engine/spec-coverage.ts +0 -105
  252. package/server/engine/stage-path.ts +0 -172
  253. package/server/engine/state-axes.ts +0 -60
  254. package/server/engine/structure-diff.ts +0 -88
  255. package/server/engine/travel-estimator.ts +0 -138
  256. package/server/engine/twin-engine.ts +0 -4979
  257. package/server/engine/twin-state-channel.ts +0 -39
  258. package/server/engine/warm-start.ts +0 -265
  259. package/server/index.ts +0 -90
  260. package/server/migrations/1786000000000-RenameTwinInstanceBoardToModel.ts +0 -43
  261. package/server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.ts +0 -54
  262. package/server/migrations/1786200000000-CarryLiveFeedCursor.ts +0 -53
  263. package/server/migrations/1786300000000-IndexEventTypeByTime.ts +0 -48
  264. package/server/migrations/1786400000000-IndexEventCreatedAt.ts +0 -38
  265. package/server/migrations/1786500000000-CreateTwinSubjectEvents.ts +0 -93
  266. package/server/migrations/1786600000000-RenameOperatoMesAdapterType.ts +0 -66
  267. package/server/migrations/1786700000000-AddDispatchRetryColumns.ts +0 -82
  268. package/server/migrations/1786800000000-CreateTwinReferenceReconciliations.ts +0 -39
  269. package/server/migrations/index.ts +0 -25
  270. package/server/routes.ts +0 -75
  271. package/server/service/actuation/actuation-advisor.ts +0 -131
  272. package/server/service/actuation/actuation-outcome.ts +0 -97
  273. package/server/service/actuation/actuation-rule-resolver.ts +0 -147
  274. package/server/service/actuation/actuation-rule.ts +0 -139
  275. package/server/service/actuation/approval-gateway.ts +0 -44
  276. package/server/service/actuation/catch-up-effects.ts +0 -152
  277. package/server/service/actuation/command-dispatcher.ts +0 -474
  278. package/server/service/actuation/command-store.ts +0 -236
  279. package/server/service/actuation/dispatch-after-approval.ts +0 -71
  280. package/server/service/actuation/effect-match.ts +0 -124
  281. package/server/service/actuation/index.ts +0 -27
  282. package/server/service/actuation/retry-plan.ts +0 -145
  283. package/server/service/actuation/rule-evaluate.ts +0 -352
  284. package/server/service/actuation/rule-loop.ts +0 -160
  285. package/server/service/actuation/rule-runner.ts +0 -216
  286. package/server/service/actuation/rule-wiring.ts +0 -84
  287. package/server/service/actuation/settle-effects.ts +0 -115
  288. package/server/service/actuation/sweep-dispatch.ts +0 -179
  289. package/server/service/actuation/twin-command-resolver.ts +0 -387
  290. package/server/service/actuation/twin-command.ts +0 -232
  291. package/server/service/actuation/twin-now.ts +0 -97
  292. package/server/service/index.ts +0 -100
  293. package/server/service/reference/actuation-routing.ts +0 -192
  294. package/server/service/reference/actuation-target.ts +0 -163
  295. package/server/service/reference/actuation-verification.ts +0 -85
  296. package/server/service/reference/attention-lane.ts +0 -21
  297. package/server/service/reference/connection-portability-resolver.ts +0 -171
  298. package/server/service/reference/connection-portability.ts +0 -329
  299. package/server/service/reference/control-routing.ts +0 -62
  300. package/server/service/reference/discovery-result.ts +0 -95
  301. package/server/service/reference/fill-cadence.ts +0 -29
  302. package/server/service/reference/fill-dedupe.ts +0 -66
  303. package/server/service/reference/fill-loop.ts +0 -153
  304. package/server/service/reference/fill-span.ts +0 -31
  305. package/server/service/reference/hook-contract.ts +0 -364
  306. package/server/service/reference/hook-rejected.ts +0 -53
  307. package/server/service/reference/hook-store.ts +0 -28
  308. package/server/service/reference/index.ts +0 -18
  309. package/server/service/reference/ingest-space.ts +0 -104
  310. package/server/service/reference/knob-defaults.ts +0 -59
  311. package/server/service/reference/live-cadence.ts +0 -129
  312. package/server/service/reference/live-feed-lease.ts +0 -56
  313. package/server/service/reference/live-ingest.ts +0 -94
  314. package/server/service/reference/reference-adapter.ts +0 -985
  315. package/server/service/reference/reference-assessment.ts +0 -250
  316. package/server/service/reference/reference-fill-run.ts +0 -179
  317. package/server/service/reference/reference-fill.ts +0 -223
  318. package/server/service/reference/reference-hook.ts +0 -479
  319. package/server/service/reference/reference-link-groups.ts +0 -21
  320. package/server/service/reference/reference-links.ts +0 -77
  321. package/server/service/reference/reference-live.ts +0 -420
  322. package/server/service/reference/reference-master.ts +0 -999
  323. package/server/service/reference/reference-probe.ts +0 -264
  324. package/server/service/reference/reference-progress-channel.ts +0 -26
  325. package/server/service/reference/reference-progress-subscription.ts +0 -78
  326. package/server/service/reference/reference-progress.ts +0 -95
  327. package/server/service/reference/reference-reconciliation-query.ts +0 -28
  328. package/server/service/reference/reference-reconciliation-writer.ts +0 -38
  329. package/server/service/reference/reference-reconciliation.ts +0 -55
  330. package/server/service/reference/reference-registry.ts +0 -17
  331. package/server/service/reference/reference-resolver.ts +0 -969
  332. package/server/service/reference/template-registry.ts +0 -85
  333. package/server/service/reference/twin-reference-reconciliation.ts +0 -27
  334. package/server/service/reference/twin-reference.ts +0 -190
  335. package/server/service/twin-attention/index.ts +0 -3
  336. package/server/service/twin-attention/twin-attention-query.ts +0 -70
  337. package/server/service/twin-audit/command-audit.ts +0 -114
  338. package/server/service/twin-audit/index.ts +0 -5
  339. package/server/service/twin-audit/twin-audit-event.ts +0 -158
  340. package/server/service/twin-audit/twin-audit-query.ts +0 -72
  341. package/server/service/twin-backfill/backfill-period-facts.ts +0 -168
  342. package/server/service/twin-backfill/backfill-shape.ts +0 -86
  343. package/server/service/twin-backfill/index.ts +0 -3
  344. package/server/service/twin-backfill/twin-backfill-resolver.ts +0 -35
  345. package/server/service/twin-control/index.ts +0 -3
  346. package/server/service/twin-control/twin-control-mutation.ts +0 -150
  347. package/server/service/twin-event/index.ts +0 -3
  348. package/server/service/twin-event/journal-count.ts +0 -53
  349. package/server/service/twin-event/twin-event-keys.ts +0 -215
  350. package/server/service/twin-event/twin-event-type.ts +0 -68
  351. package/server/service/twin-event/twin-event.ts +0 -250
  352. package/server/service/twin-forecast/forecast-metrics.ts +0 -106
  353. package/server/service/twin-forecast/forecast-tuning.ts +0 -40
  354. package/server/service/twin-forecast/gap-analytics.ts +0 -139
  355. package/server/service/twin-forecast/index.ts +0 -3
  356. package/server/service/twin-forecast/twin-forecast-query.ts +0 -486
  357. package/server/service/twin-ingest-window/index.ts +0 -7
  358. package/server/service/twin-ingest-window/twin-ingest-window-query.ts +0 -125
  359. package/server/service/twin-ingest-window/twin-ingest-window-writer.ts +0 -57
  360. package/server/service/twin-ingest-window/twin-ingest-window.ts +0 -113
  361. package/server/service/twin-instance/index.ts +0 -3
  362. package/server/service/twin-instance/twin-instance.ts +0 -199
  363. package/server/service/twin-journal/event-type-split-shape.ts +0 -112
  364. package/server/service/twin-journal/event-type-split.ts +0 -144
  365. package/server/service/twin-journal/index.ts +0 -3
  366. package/server/service/twin-journal/journal-order.ts +0 -20
  367. package/server/service/twin-journal/twin-journal-query.ts +0 -615
  368. package/server/service/twin-lifecycle/domain-catalog.ts +0 -51
  369. package/server/service/twin-lifecycle/index.ts +0 -3
  370. package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +0 -285
  371. package/server/service/twin-metrics/index.ts +0 -3
  372. package/server/service/twin-metrics/twin-metrics-query.ts +0 -172
  373. package/server/service/twin-model/axis-journal-evidence.ts +0 -57
  374. package/server/service/twin-model/choose-recipe.ts +0 -31
  375. package/server/service/twin-model/epcis-coverage.ts +0 -251
  376. package/server/service/twin-model/external-resolver.ts +0 -173
  377. package/server/service/twin-model/iec61850-coverage.ts +0 -111
  378. package/server/service/twin-model/index.ts +0 -25
  379. package/server/service/twin-model/isa95-coverage.ts +0 -320
  380. package/server/service/twin-model/item-ref.ts +0 -80
  381. package/server/service/twin-model/name-index.ts +0 -94
  382. package/server/service/twin-model/project-structure.ts +0 -213
  383. package/server/service/twin-model/standard-coverage.ts +0 -35
  384. package/server/service/twin-model/status-tally.ts +0 -37
  385. package/server/service/twin-model/twin-equipment.ts +0 -191
  386. package/server/service/twin-model/twin-lineage-query.ts +0 -327
  387. package/server/service/twin-model/twin-location.ts +0 -147
  388. package/server/service/twin-model/twin-model-item-query.ts +0 -1029
  389. package/server/service/twin-model/twin-model-mutation.ts +0 -503
  390. package/server/service/twin-model/twin-model-query.ts +0 -792
  391. package/server/service/twin-model/twin-model-tree-query.ts +0 -211
  392. package/server/service/twin-model/twin-operation.ts +0 -157
  393. package/server/service/twin-readiness/index.ts +0 -3
  394. package/server/service/twin-readiness/twin-readiness-query.ts +0 -96
  395. package/server/service/twin-space/area-resolver.ts +0 -75
  396. package/server/service/twin-space/index.ts +0 -8
  397. package/server/service/twin-space/move-space.ts +0 -262
  398. package/server/service/twin-space/representation-role.ts +0 -15
  399. package/server/service/twin-space/space-integrity.ts +0 -293
  400. package/server/service/twin-space/twin-area.ts +0 -63
  401. package/server/service/twin-space/twin-space-area.ts +0 -66
  402. package/server/service/twin-space/twin-space-representation.ts +0 -99
  403. package/server/service/twin-space/twin-space-resolver.ts +0 -582
  404. package/server/service/twin-space/twin-space.ts +0 -148
  405. package/server/service/twin-state/index.ts +0 -3
  406. package/server/service/twin-state/twin-state-subscription.ts +0 -62
  407. package/server/service/twin-structure/index.ts +0 -3
  408. package/server/service/twin-structure/twin-structure.ts +0 -96
  409. package/server/service/twin-subject/event-subjects.ts +0 -162
  410. package/server/service/twin-subject/index.ts +0 -10
  411. package/server/service/twin-subject/item-resolver.ts +0 -92
  412. package/server/service/twin-subject/subject-query-shape.ts +0 -84
  413. package/server/service/twin-subject/twin-subject-backfill.ts +0 -196
  414. package/server/service/twin-subject/twin-subject-event.ts +0 -101
  415. package/server/service/twin-subject/twin-subject-fast-path.ts +0 -346
  416. package/server/service/twin-subject/twin-subject-query.ts +0 -210
  417. package/server/service/twin-subject/twin-subject-writer.ts +0 -189
  418. package/server/service/twin-target/index.ts +0 -5
  419. package/server/service/twin-target/twin-target-resolver.ts +0 -142
  420. package/server/service/twin-target/twin-target.ts +0 -97
  421. package/server/types/global.d.ts +0 -22
  422. package/shared/axis-read.ts +0 -28
  423. package/shared/entity-delta.ts +0 -335
  424. package/shared/kpi-broadcast.ts +0 -13
  425. package/shared/touched-items.ts +0 -73
  426. package/shared/twin-level.ts +0 -48
  427. package/test/ack-shape-alignment.test.ts +0 -97
  428. package/test/actuation-advisor.test.ts +0 -55
  429. package/test/actuation-approval-door.test.ts +0 -411
  430. package/test/actuation-dispatch.test.ts +0 -209
  431. package/test/actuation-effect.test.ts +0 -162
  432. package/test/actuation-outcome.test.ts +0 -152
  433. package/test/actuation-rule-runner.test.ts +0 -281
  434. package/test/actuation-rule.test.ts +0 -266
  435. package/test/actuation-seam.test.ts +0 -255
  436. package/test/actuation-settle.test.ts +0 -164
  437. package/test/actuation-target.test.ts +0 -145
  438. package/test/actuation-verification-state.test.ts +0 -139
  439. package/test/adopt-structure-live.test.ts +0 -133
  440. package/test/aggregate-not-findone.test.ts +0 -112
  441. package/test/area-resolver-db.test.ts +0 -110
  442. package/test/attention-digest.test.ts +0 -161
  443. package/test/axis-declaration-passthrough-db.test.ts +0 -152
  444. package/test/axis-journal-evidence.test.ts +0 -71
  445. package/test/axis-read.test.ts +0 -188
  446. package/test/backfill-shape.test.ts +0 -89
  447. package/test/boot-resume.test.ts +0 -287
  448. package/test/broadcast-cost-baseline.test.ts +0 -201
  449. package/test/broadcast-period.test.ts +0 -58
  450. package/test/broadcast-queue-overflow.test.ts +0 -244
  451. package/test/canonical-ingest-vocabularies.test.ts +0 -451
  452. package/test/canonical-quantity-door.test.ts +0 -61
  453. package/test/capability-mapping.test.ts +0 -89
  454. package/test/checkpoint-refuses-empty.test.ts +0 -103
  455. package/test/choose-recipe.test.ts +0 -117
  456. package/test/column-type-portability.test.ts +0 -122
  457. package/test/command-routing.test.ts +0 -61
  458. package/test/command-store-writes-columns.test.ts +0 -126
  459. package/test/connection-portability-doors.test.ts +0 -87
  460. package/test/connector-capability-declaration.test.ts +0 -195
  461. package/test/contract-layer-guard.test.ts +0 -48
  462. package/test/control-capability.test.ts +0 -98
  463. package/test/cursor-stall-not-read-failure.test.ts +0 -126
  464. package/test/declaration-reaches-model.test.ts +0 -226
  465. package/test/declared-location-types.test.ts +0 -89
  466. package/test/declared-stimulus.test.ts +0 -88
  467. package/test/dedupe-transformation.test.ts +0 -112
  468. package/test/discovery-result.test.ts +0 -75
  469. package/test/dispatch-after-approval-source.test.ts +0 -81
  470. package/test/duration-estimators.test.ts +0 -144
  471. package/test/energy-topology.test.ts +0 -113
  472. package/test/entity-delta.test.ts +0 -352
  473. package/test/equipment-identity-reaches.test.ts +0 -57
  474. package/test/event-subjects.test.ts +0 -148
  475. package/test/event-time-column.test.ts +0 -67
  476. package/test/event-type-split.test.ts +0 -178
  477. package/test/external-resolver.test.ts +0 -177
  478. package/test/fact-scope-wiring.test.ts +0 -96
  479. package/test/fill-dedupe.test.ts +0 -59
  480. package/test/fill-loop.test.ts +0 -35
  481. package/test/first-envelope.test.ts +0 -153
  482. package/test/fold-gap-speaks.test.ts +0 -53
  483. package/test/fold-shift-dst.test.ts +0 -110
  484. package/test/forecast-metrics.test.ts +0 -157
  485. package/test/forecast-tuning.test.ts +0 -42
  486. package/test/gap-analytics.test.ts +0 -113
  487. package/test/generated-not-counted.test.ts +0 -99
  488. package/test/guard-roots.ts +0 -76
  489. package/test/home-in-area.test.ts +0 -90
  490. package/test/hook-address.test.ts +0 -28
  491. package/test/hook-rejected-shape.test.ts +0 -86
  492. package/test/hook-response-sum.test.ts +0 -193
  493. package/test/hook-sequence.test.ts +0 -333
  494. package/test/ingest-bench.test.ts +0 -70
  495. package/test/ingest-dedupe.test.ts +0 -56
  496. package/test/ingest-expected-quiet.test.ts +0 -111
  497. package/test/ingest-health-engine.test.ts +0 -248
  498. package/test/ingest-health-wiring.test.ts +0 -120
  499. package/test/ingest-health.test.ts +0 -306
  500. package/test/ingest-history.test.ts +0 -247
  501. package/test/ingest-idempotent.test.ts +0 -211
  502. package/test/ingest-reconcile-four-ways.test.ts +0 -97
  503. package/test/ingest-rules-header.test.ts +0 -100
  504. package/test/ingest-running-guard.test.ts +0 -136
  505. package/test/ingest-space.test.ts +0 -78
  506. package/test/ingest-window-rolls-unobserved.test.ts +0 -72
  507. package/test/ingest-wiring-guard.test.ts +0 -197
  508. package/test/instance-cache-lifecycle.test.ts +0 -110
  509. package/test/intake-mapping-parity.test.ts +0 -175
  510. package/test/integration-probes.test.ts +0 -103
  511. package/test/integration-runner.test.ts +0 -95
  512. package/test/item-ref.test.ts +0 -78
  513. package/test/journal-order-axis.test.ts +0 -80
  514. package/test/journal-read-discipline.test.ts +0 -186
  515. package/test/journal-retention.test.ts +0 -275
  516. package/test/journal-sort-axis.test.ts +0 -142
  517. package/test/journal-write-door.test.ts +0 -110
  518. package/test/journal-write-trend.test.ts +0 -115
  519. package/test/kernel-kind-guard.test.ts +0 -98
  520. package/test/knob-defaults.test.ts +0 -72
  521. package/test/kpi-baseline-db.test.ts +0 -216
  522. package/test/kpi-baseline.test.ts +0 -196
  523. package/test/kpi-fold.test.ts +0 -1456
  524. package/test/kpi-query-bench.test.ts +0 -130
  525. package/test/lens-own-places.test.ts +0 -50
  526. package/test/lineage-survives-restart.test.ts +0 -234
  527. package/test/live-cadence.test.ts +0 -170
  528. package/test/live-cursor-wiring.test.ts +0 -87
  529. package/test/live-feed-lease.test.ts +0 -63
  530. package/test/live-feed-registry.test.ts +0 -75
  531. package/test/live-kernel-facts.test.ts +0 -161
  532. package/test/live-mirror-parity.test.ts +0 -286
  533. package/test/load-meter.test.ts +0 -328
  534. package/test/local-declarations.test.ts +0 -662
  535. package/test/log-stamp.test.ts +0 -59
  536. package/test/loop-lag.test.ts +0 -82
  537. package/test/master-to-twin.test.ts +0 -279
  538. package/test/measured-yield.test.ts +0 -90
  539. package/test/merge-streams.test.ts +0 -70
  540. package/test/mirror-resumes-from-checkpoint.test.ts +0 -192
  541. package/test/model-basis.test.ts +0 -141
  542. package/test/model-gap.test.ts +0 -153
  543. package/test/model-refusal.test.ts +0 -75
  544. package/test/model-vocabulary.test.ts +0 -114
  545. package/test/move-space.test.ts +0 -149
  546. package/test/mutation-gate.test.ts +0 -122
  547. package/test/oee-accumulator.test.ts +0 -204
  548. package/test/oee-site-calendar.test.ts +0 -146
  549. package/test/open-doors.test.ts +0 -197
  550. package/test/operation-basis.test.ts +0 -127
  551. package/test/operational-vocabulary.test.ts +0 -108
  552. package/test/operations-capability-db.test.ts +0 -165
  553. package/test/order-and-transaction-split.test.ts +0 -107
  554. package/test/order-fold-host.test.ts +0 -112
  555. package/test/producer-guard.test.ts +0 -66
  556. package/test/project-structure-db.test.ts +0 -226
  557. package/test/projection-reaches-screen.test.ts +0 -277
  558. package/test/projection-reads-declared.test.ts +0 -109
  559. package/test/property-effects.test.ts +0 -128
  560. package/test/provenance-promotion.test.ts +0 -99
  561. package/test/read-failure-ledger.test.ts +0 -106
  562. package/test/read-failure-visible.test.ts +0 -145
  563. package/test/read-time.test.ts +0 -118
  564. package/test/reference-fill.test.ts +0 -235
  565. package/test/reference-grounding.test.ts +0 -70
  566. package/test/reference-hook.test.ts +0 -177
  567. package/test/reference-links.test.ts +0 -56
  568. package/test/reference-reconciliation.test.ts +0 -39
  569. package/test/registry-key-guard.test.ts +0 -80
  570. package/test/rejection-carries-event-id.test.ts +0 -101
  571. package/test/rename-twin.test.ts +0 -89
  572. package/test/resolve-ts-siblings.mjs +0 -52
  573. package/test/restart-policy.test.ts +0 -111
  574. package/test/resync-origin-site.test.ts +0 -83
  575. package/test/retry-plan.test.ts +0 -139
  576. package/test/revision-axis.test.ts +0 -110
  577. package/test/runtime-key.test.ts +0 -66
  578. package/test/save-intake-collision.test.ts +0 -91
  579. package/test/scale-twin-bench.test.ts +0 -103
  580. package/test/secrets-at-rest.test.ts +0 -135
  581. package/test/snapshot-freshness.test.ts +0 -60
  582. package/test/source-outcome-audit.test.ts +0 -104
  583. package/test/space-integrity.test.ts +0 -223
  584. package/test/space-representation.test.ts +0 -66
  585. package/test/space-scope-includes-stopped.test.ts +0 -55
  586. package/test/spec-coverage.test.ts +0 -113
  587. package/test/stage-path.test.ts +0 -95
  588. package/test/standard-coverage.test.ts +0 -148
  589. package/test/state-axes.test.ts +0 -74
  590. package/test/status-tally.test.ts +0 -55
  591. package/test/streamline-e2e.test.ts +0 -76
  592. package/test/structure-revision-db.test.ts +0 -315
  593. package/test/subject-fast-path.test.ts +0 -148
  594. package/test/subject-read-model.test.ts +0 -175
  595. package/test/sweep-dispatch.test.ts +0 -191
  596. package/test/tenant-registry-db.test.ts +0 -149
  597. package/test/time-range.test.ts +0 -152
  598. package/test/touched-items.test.ts +0 -61
  599. package/test/twin-audit.test.ts +0 -83
  600. package/test/twin-event-keys.test.ts +0 -193
  601. package/test/twin-model-item-db.test.ts +0 -319
  602. package/test/twin-model-parent-relation-db.test.ts +0 -125
  603. package/test/twin-model-tree-db.test.ts +0 -209
  604. package/test/twin-origin-resync.test.ts +0 -133
  605. package/test/twin-state-channel.test.ts +0 -111
  606. package/test/vocabulary-guard.test.ts +0 -43
  607. package/test/warm-start-seam.test.ts +0 -162
  608. package/test/warm-start.test.ts +0 -297
  609. package/test/withheld-door.test.ts +0 -95
  610. package/test/yield-loop.test.ts +0 -199
  611. package/tsconfig.json +0 -15
  612. package/tsconfig.shared.json +0 -23
  613. package/tsconfig.shared.tsbuildinfo +0 -1
  614. package/tsconfig.tsbuildinfo +0 -1
@@ -1,59 +0,0 @@
1
- /*
2
- * 로그에 **시각이 있다** — 그리고 어떤 인자도 버리지 않는다 (2026-08-22).
3
- *
4
- * 루프가 55초 막힌 것을 계기로 알아냈는데 그 시각에 무슨 일이 있었는지 로그에서 찾을 수 없었다.
5
- * 트윈의 줄이 `console.log` 로 나가 시각이 없었기 때문이다. 이 시험이 지키는 것:
6
- * ① 형식 — 프레임워크 줄과 같은 모양, **밀리초까지**(계기의 값이 epoch ms 다)
7
- * ② 지역 시각 — 프레임워크의 다른 줄과 같은 기준(UTC 로 찍으면 나란히 읽을 수 없다)
8
- * ③ 인자를 버리지 않는다 — 오류는 스택까지(`console.error(msg, err)` 로 쓰던 자리가 많다)
9
- * ④ 트윈 소스에 `console.` 직접 호출이 남지 않는다 — 하나라도 남으면 그 줄만 시각이 없다
10
- */
11
- import { test } from 'node:test'
12
- import assert from 'node:assert/strict'
13
- import { readFileSync, readdirSync } from 'node:fs'
14
- import { fileURLToPath } from 'node:url'
15
-
16
- import { line, stamp } from '../server/engine/log.ts'
17
-
18
- test('시각은 밀리초와 오프셋까지 적는다 — 같은 초 안의 순서를 가릴 수 있게', () => {
19
- const s = stamp(new Date(2026, 7, 22, 5, 54, 12, 345))
20
- assert.match(s, /^2026-08-22T05:54:12\.345[+-]\d\d:\d\d$/, `형식이 다르다: ${s}`)
21
- })
22
-
23
- test('지역 시각으로 적는다 — 프레임워크의 다른 줄과 같은 기준', () => {
24
- const at = new Date(2026, 0, 2, 3, 4, 5, 6)
25
- const s = stamp(at)
26
- assert.ok(s.startsWith('2026-01-02T03:04:05.006'), `지역 시각이 아니다: ${s}`)
27
- })
28
-
29
- test('오류는 스택까지 남는다 — 「어디서 났나」를 잃지 않게', () => {
30
- const err = new Error('불이 났다')
31
- const out = line(['[twin-engine] 저장 실패', err])
32
- assert.ok(out.includes('[twin-engine] 저장 실패'))
33
- assert.ok(out.includes('불이 났다'))
34
- assert.ok(out.includes('log-stamp.test'), '스택이 있어야 어느 자리에서 났는지 알 수 있다')
35
- })
36
-
37
- test('값이 없어도 있었다는 사실은 남긴다 — 알리지 않고 지우지 않는다', () => {
38
- assert.equal(line(['a', undefined, null, 0]), 'a undefined null 0')
39
- const circular: any = { name: 'ㄱ' }
40
- circular.self = circular
41
- assert.ok(line(['보고', circular]).startsWith('보고 '), '순환 참조에도 줄이 남아야 한다')
42
- })
43
-
44
- test('트윈 소스에 console 직접 호출이 남아 있지 않다 — 한 줄이라도 남으면 그 줄만 시각이 없다', () => {
45
- const root = fileURLToPath(new URL('../server/', import.meta.url))
46
- const offenders: string[] = []
47
- const walk = (dir: string) => {
48
- for (const e of readdirSync(dir, { withFileTypes: true })) {
49
- const p = dir + e.name
50
- if (e.isDirectory()) walk(p + '/')
51
- else if (e.name.endsWith('.ts') && e.name !== 'log.ts') {
52
- const src = readFileSync(p, 'utf-8')
53
- for (const m of src.matchAll(/console\.(log|warn|error)\(/g)) offenders.push(`${p.slice(root.length)} console.${m[1]}`)
54
- }
55
- }
56
- }
57
- walk(root)
58
- assert.deepEqual(offenders, [], `시각 없는 로그가 남아 있다 — twinLog·twinWarn·twinError 를 쓴다:\n ${offenders.join('\n ')}`)
59
- })
@@ -1,82 +0,0 @@
1
- /*
2
- * 루프 지체 계기 — **원인을 지어내지 않기 위한 값**이 정확한지 본다 (2026-08-21).
3
- *
4
- * 지키는 것:
5
- * ① 늦게 깨어난 만큼만 지체다 — 제때 깨어난 표본은 0 이고, 0 을 정체로 세지 않는다.
6
- * ② 창이 닫히기 전에는 `recent` 가 **null** 이다(채우는 중인 창을 「지금」으로 읽으면 과소 집계다).
7
- * ③ 가장 길게 막힌 **시각**을 든다 — 언제였는지가 원인을 가리는 근거다.
8
- * ④ 문턱 이하의 흔들림은 정체로 세지 않는다.
9
- */
10
- import { test } from 'node:test'
11
- import assert from 'node:assert/strict'
12
-
13
- import { LoopLagSampler } from '../server/engine/loop-lag.ts'
14
-
15
- /** 시계를 손으로 밀어 넣는다 — 실제 타이머로 재면 기계 상태가 결과를 정한다. */
16
- function sampler(sampleMs = 500, stallMs = 200, windowMs = 10_000) {
17
- let now = 1_000_000
18
- const s = new LoopLagSampler(sampleMs, stallMs, windowMs, () => now)
19
- return { s, advance: (ms: number) => (now += ms), at: () => now }
20
- }
21
-
22
- test('제때 깨어난 표본은 지체가 0 이고 정체로 세지 않는다', () => {
23
- const { s, advance, at } = sampler()
24
- for (let i = 0; i < 4; i++) {
25
- advance(500)
26
- assert.equal(s.sample(at()), 0)
27
- }
28
- assert.equal(s.view().total.stalls, 0)
29
- assert.equal(s.view().total.maxMs, 0)
30
- assert.equal(s.view().total.samples, 4)
31
- })
32
-
33
- test('늦게 깨어난 만큼이 지체다 — 그 초과분만', () => {
34
- const { s, advance, at } = sampler()
35
- advance(500)
36
- s.sample(at())
37
- advance(4_600) // 예정보다 4,100ms 늦게
38
- assert.equal(s.sample(at()), 4_100)
39
- assert.equal(s.view().total.maxMs, 4_100)
40
- assert.equal(s.view().total.stalls, 1)
41
- })
42
-
43
- test('문턱 이하의 흔들림은 정체가 아니다 — 값은 남기고 세지는 않는다', () => {
44
- const { s, advance, at } = sampler(500, 200)
45
- advance(650) // 150ms 지체 — 문턱 200 미만
46
- s.sample(at())
47
- const v = s.view()
48
- assert.equal(v.total.maxMs, 150)
49
- assert.equal(v.total.stalls, 0, '문턱 이하를 세면 정상 상태가 정체로 보인다')
50
- })
51
-
52
- test('창이 닫히기 전에는 recent 가 null 이다 — 채우는 중인 창을 「지금」으로 읽지 않는다', () => {
53
- const { s, advance, at } = sampler(500, 200, 2_000)
54
- advance(500)
55
- s.sample(at())
56
- assert.equal(s.view().recent, null)
57
-
58
- /* 창 길이를 넘기면 그 창이 닫혀 `recent` 가 된다. */
59
- advance(2_000)
60
- s.sample(at())
61
- const v = s.view()
62
- assert.ok(v.recent, '창 길이를 넘겼으면 닫힌 창이 있어야 한다')
63
- assert.equal(v.recent!.stalls, 1, '1,500ms 지체는 정체 한 번이다')
64
- })
65
-
66
- test('가장 길게 막힌 시각을 든다 — 언제였는지가 원인을 가린다', () => {
67
- const { s, advance, at } = sampler()
68
- advance(500)
69
- s.sample(at())
70
- advance(3_000)
71
- const worst = at()
72
- s.sample(worst)
73
- advance(500)
74
- s.sample(at())
75
- assert.equal(s.view().worstAtMs, worst)
76
- })
77
-
78
- test('한 번도 재지 않았으면 정체 시각은 null 이다 — 0 으로 적지 않는다', () => {
79
- const { s } = sampler()
80
- assert.equal(s.view().worstAtMs, null)
81
- assert.equal(s.view().recent, null)
82
- })
@@ -1,279 +0,0 @@
1
- /*
2
- * masterToTwin — 모델→model 토폴로지 변환 시임. 템플릿/레퍼런스 master → model{locations,equipment,layout,spaceId}+space.
3
- * 스트림라인의 "모델링→board" 연결부: 템플릿(build)이 낸 master 를 커널이 소비할 TwinModelDef 로 바꾼다.
4
- * role(location/area/both) 분기·footprint→layout·spaceId 파생·미지 타입 경고를 고정.
5
- */
6
- import { test } from 'node:test'
7
- import assert from 'node:assert/strict'
8
-
9
- import { masterToTwin } from '../server/service/reference/reference-master.ts'
10
- import { DOMAIN_CATALOG } from '@operato/ops-contract'
11
-
12
- /** WMS 단위적재 템플릿이 내는 것과 동형인 현실적 master(coordinate-free). */
13
- const wmsMaster = () => ({
14
- source: 'wh-seoul',
15
- system: 'wms' as const,
16
- siteName: '서울 창고',
17
- space: { width: 90, depth: 40, unit: 'm', geo: { lat: 37.5, lon: 127.0, rotation: 0 } },
18
- locations: [
19
- { id: 'a-dc', type: 'warehouse', role: 'area' as const, name: '창고' },
20
- { id: 'dock-recv', type: 'dock', role: 'location' as const, name: '입고 도크', capacity: 100 },
21
- { id: 'rack-1', type: 'storage', role: 'location' as const, name: '랙1', parentId: 'a-dc', capacity: 60 },
22
- { id: 'rack-2', type: 'storage', role: 'location' as const, name: '랙2', parentId: 'a-dc', capacity: 60 },
23
- { id: 'dock-ship', type: 'dock-ship', role: 'location' as const, name: '출고 도크', capacity: 100 }
24
- ],
25
- equipment: [{ id: 'fk-1', kind: 'forklift', homeLocationId: 'dock-recv' }]
26
- })
27
-
28
- test('locations role → 노드/영역 분기, equipment → 무버', () => {
29
- const { model, spaceContent } = masterToTwin(wmsMaster())
30
- assert.deepEqual(model.locations.map((n: any) => n.id).sort(), ['dock-recv', 'dock-ship', 'rack-1', 'rack-2'], '노드=role location')
31
- assert.equal(spaceContent.areas.length, 1, '영역=role area')
32
- assert.equal(spaceContent.areas[0].id, 'a-dc')
33
- assert.deepEqual(model.equipment, [{ id: 'fk-1', kind: 'forklift', homeLocation: 'dock-recv', mtbfMs: undefined, mttrMs: undefined }], '마스터 equipment→보드 equipment(homeLocationId→homeLocation, identity 통과)')
34
- assert.equal(model.locations.find((n: any) => n.id === 'rack-1').capacity, 60, 'capacity 전달')
35
- assert.equal(model.locations.find((n: any) => n.id === 'dock-recv').parentId, undefined, 'parentId 없으면 undefined')
36
- })
37
-
38
- test('coordinate-free: footprint 없으면 layout 비어있음(미배치 → A2)', () => {
39
- const { model } = masterToTwin(wmsMaster())
40
- assert.deepEqual(model.layout, {}, '좌표 없는 master → layout {}')
41
- })
42
-
43
- test('footprint 있으면 layout = 중심좌표', () => {
44
- const m = wmsMaster()
45
- ;(m.locations[1] as any).footprint = { x: 10, y: 20, w: 4, h: 6 } // dock-recv
46
- const { model } = masterToTwin(m)
47
- assert.deepEqual(model.layout['dock-recv'], { x: 12, y: 23 }, '중심 = x+w/2, y+h/2')
48
- assert.equal(model.layout['rack-1'], undefined, 'footprint 없는 노드는 layout 없음')
49
- })
50
-
51
- test('spaceId: 명시 시 참조, 없으면 source 파생 (공동배치 시임)', () => {
52
- assert.equal(masterToTwin(wmsMaster()).model.spaceId, 'wh-seoul-site', '없으면 {source}-site')
53
- const shared = wmsMaster()
54
- ;(shared.space as any).spaceId = 'rosarito-site'
55
- assert.equal(masterToTwin(shared).model.spaceId, 'rosarito-site', '명시 시 공유(다시스템 co-location)')
56
- })
57
-
58
- test('미지 노드 타입 경고 — 카탈로그 있으면 검증(버리진 않음)', () => {
59
- const m = wmsMaster()
60
- ;(m.locations as any).push({ id: 'weird', type: '__unknown__', role: 'location', capacity: 1 })
61
- const withCat = masterToTwin(m, DOMAIN_CATALOG)
62
- /* 경고는 프로즈가 아니라 **코드+파라미터**다(화면이 다섯 언어로 렌더한다) — 문구가 아니라 계약을 본다. */
63
- assert.ok(
64
- withCat.warnings.some(w => w.code === 'unknown-location-type' && w.params?.type === '__unknown__'),
65
- `미지 타입 경고: ${JSON.stringify(withCat.warnings)}`
66
- )
67
- assert.ok(withCat.model.locations.some((n: any) => n.id === 'weird'), '경고해도 노드는 유지(반영 우선)')
68
- // 정상 타입만이면 경고 0
69
- assert.equal(masterToTwin(wmsMaster(), DOMAIN_CATALOG).warnings.length, 0, '알려진 타입만 → 경고 0')
70
- // 카탈로그 없으면 검증 생략
71
- assert.equal(masterToTwin(m).warnings.length, 0, '카탈로그 미제공 → 경고 생략')
72
- })
73
-
74
- test("role 'both' 는 노드·영역 양쪽에 등장(도크 도어 등)", () => {
75
- const m = wmsMaster()
76
- ;(m.locations as any).push({ id: 'dock-door-1', type: 'dock-door', role: 'both', name: '도어1', capacity: 1 })
77
- const { model, spaceContent } = masterToTwin(m)
78
- assert.ok(model.locations.some((n: any) => n.id === 'dock-door-1'), 'both → 노드')
79
- assert.ok(spaceContent.areas.some((a: any) => a.id === 'dock-door-1'), 'both → 영역')
80
- })
81
-
82
- test('space content: 크기·geo·표현 전달', () => {
83
- const { spaceContent } = masterToTwin(wmsMaster())
84
- assert.equal(spaceContent.width, 90)
85
- assert.equal(spaceContent.depth, 40)
86
- assert.equal(spaceContent.unit, 'm')
87
- assert.equal(spaceContent.geo.lat, 37.5)
88
- })
89
-
90
- test('현장 물질화(#4): 표현 없고 geo 있으면 기본 map 표현 합성 — "알아볼 현장" 보장', () => {
91
- const { spaceContent } = masterToTwin(wmsMaster()) // wmsMaster = geo 있고 representations 없음
92
- assert.equal(spaceContent.representations.length, 1, '기본 표현 1개 합성')
93
- const r = spaceContent.representations[0]
94
- assert.equal(r.type, 'map', 'map 표현')
95
- assert.equal(r.primary, true)
96
- assert.deepEqual(r.center, { lat: 37.5, lon: 127.0 }, 'geo 로 센터')
97
- assert.equal(spaceContent.primaryId, r.id, 'primaryId = 합성 표현')
98
- })
99
-
100
- test('현장 물질화(#4): master 가 표현을 주면 보존(합성 안 함)', () => {
101
- const m: any = wmsMaster()
102
- m.space.representations = [{ id: 'r-board', type: 'board', primary: true, boardId: 'b1' }]
103
- const { spaceContent } = masterToTwin(m)
104
- assert.equal(spaceContent.representations.length, 1)
105
- assert.equal(spaceContent.representations[0].type, 'board', '주어진 표현 보존(덮어쓰지 않음)')
106
- })
107
-
108
- test('현장 물질화(#4): 표현도 geo 도 없으면 빈 표현 + 경고(정직)', () => {
109
- const m: any = wmsMaster()
110
- m.space.geo = undefined
111
- const { spaceContent, warnings } = masterToTwin(m)
112
- assert.equal(spaceContent.representations.length, 0, '합성 불가')
113
- assert.ok(
114
- warnings.some(w => w.code === 'no-viewable-representation'),
115
- '뷰 없는 공간 경고 표면화'
116
- )
117
- })
118
-
119
- /* ── 공정 명세 통과 (ISA-95 OperationsSegment) ──────────────────────────────
120
- *
121
- * 시뮬레이션의 소요·수율이 커널 상수였던 것을 데이터로 옮기는 경로의 마지막 한 칸: 마스터가 명세를
122
- * 말하면 model 를 통해 커널까지 **손대지 않고** 간다. 기간은 표준 표기(ISO 8601)로 그대로 흐른다 —
123
- * 여기서 밀리초로 바꾸면 표준과 어긋나고, 커널이 다시 해석할 기회를 잃는다.
124
- */
125
- const mesMaster = () => ({
126
- source: 'plant-1',
127
- system: 'mes' as const,
128
- siteName: '공장',
129
- space: { width: 100, depth: 50, geo: { lat: 32.3, lon: -117.0 } },
130
- locations: [
131
- { id: 'a-prod', type: 'factory', role: 'area' as const, name: '생산' },
132
- { id: 'cut-1', type: 'cut-station', role: 'location' as const, name: '절단', capacity: 4 }
133
- ],
134
- equipment: [{ id: 'mch-1', kind: 'cutter', homeLocationId: 'cut-1' }],
135
- operations: [
136
- {
137
- key: 'cut', label: 'cutting', intent: 'process' as const, locationType: 'cut-station', resourceType: 'cutter',
138
- duration: 'PT25M',
139
- variability: { distribution: 'triangular' as const, min: 'PT20M', max: 'PT35M', mode: 'PT24M' },
140
- parameters: [{ id: 'yield', value: '0.995' }]
141
- }
142
- ]
143
- })
144
-
145
- test('공정 명세가 model 로 그대로 통과한다 — 표준 표기 유지, 값 변형 없음', () => {
146
- const { model, warnings } = masterToTwin(mesMaster(), DOMAIN_CATALOG)
147
- assert.equal((model as any).operations.length, 1)
148
- const op = (model as any).operations[0]
149
- assert.equal(op.duration, 'PT25M', 'ISO 8601 기간을 밀리초로 바꾸지 않는다')
150
- assert.deepEqual(op.variability, { distribution: 'triangular', min: 'PT20M', max: 'PT35M', mode: 'PT24M' })
151
- assert.deepEqual(op.parameters, [{ id: 'yield', value: '0.995' }])
152
- assert.equal(warnings.length, 0)
153
- })
154
-
155
- test('명세를 전달하지 않으면 키를 만들지 않는다 — 빈 배열을 "선언했다" 로 보고하지 않는다', () => {
156
- const { model } = masterToTwin(wmsMaster(), DOMAIN_CATALOG)
157
- assert.equal('operations' in (model as any), false)
158
- })
159
-
160
- test('내용 없는 명세는 경고한다 — 선언했는데 아무 말도 하지 않는 명세는 침묵하지 않는다', () => {
161
- const m: any = mesMaster()
162
- m.operations = [{ key: 'cut', label: 'cutting', intent: 'process' }]
163
- const { warnings } = masterToTwin(m, DOMAIN_CATALOG)
164
- assert.ok(
165
- warnings.some(w => w.code === 'operation-without-duration' && w.params?.operation === 'cut'),
166
- `기본값으로 굴러갈 것을 알린다: ${JSON.stringify(warnings)}`
167
- )
168
- })
169
-
170
- /* ── 처리 능력·교대 통과 ─────────────────────────────────────────────────
171
- *
172
- * `capacity` 한 필드가 저장 용량과 처리 능력을 겸하던 것을 갈랐다. 인제스트도 두 축을 따로 실어야
173
- * 커널이 "20개를 쌓아 두지만 한 번에 한 대만 깎는다" 를 표현할 수 있다. 교대도 같다.
174
- */
175
- test('처리 능력과 교대가 model 로 통과한다 — 저장 용량과 섞이지 않는다', () => {
176
- const m: any = mesMaster()
177
- m.locations[1].parallelism = 1 // cut-1: 저장 4, 동시 처리 1
178
- m.equipment[0].window = { startHour: 8, endHour: 18 }
179
- const { model } = masterToTwin(m, DOMAIN_CATALOG)
180
- const location = (model as any).locations.find((n: any) => n.id === 'cut-1')
181
- assert.equal(location.capacity, 4, '저장 용량')
182
- assert.equal(location.parallelism, 1, '처리 능력 — 다른 축')
183
- assert.deepEqual((model as any).equipment[0].window, { startHour: 8, endHour: 18 })
184
- })
185
-
186
- test('선언하지 않으면 키를 만들지 않는다 — 미지정과 0 을 같게 다루지 않는다', () => {
187
- const { model } = masterToTwin(mesMaster(), DOMAIN_CATALOG)
188
- const location = (model as any).locations.find((n: any) => n.id === 'cut-1')
189
- assert.equal('parallelism' in location, false)
190
- assert.equal('window' in (model as any).equipment[0], false)
191
- })
192
-
193
- /*
194
- * ★ **이름이 첫 문에서 사라지고 있었다.**
195
- *
196
- * 인제스트가 자리·설비·사람·자산을 보드로 옮길 때 `name` 을 빼고 있었다. 그러면 모델에도 없고,
197
- * 모델에서 그리는 투영 행에도 없으므로 **어떤 화면도 이름을 만들 수 없다** — 목록·표·관계 그림이
198
- * 전부 `cut-station` 같은 id 를 찍었다. 표면마다 따로 나타나지만 결함은 이 한 자리다.
199
- *
200
- * 업무키를 따로 두는 설계(식별자는 원본이 정한다)에서는 **이름을 함께 싣는 것이 그 설계의 절반**이다.
201
- * 나누기만 하고 이름을 빼면 화면에 남는 것은 id 뿐이다.
202
- */
203
- test('이름이 보드로 통과한다 — 업무키를 나눈 설계의 나머지 절반', () => {
204
- const m: any = mesMaster()
205
- m.locations[1].name = '프레임 절단'
206
- m.equipment[0].name = '절단기 1호'
207
- const { model } = masterToTwin(m, DOMAIN_CATALOG)
208
- const location = (model as any).locations.find((n: any) => n.id === 'cut-1')
209
- assert.equal(location.name, '프레임 절단', '자리 이름이 모델에 실려야 한다')
210
- assert.equal((model as any).equipment[0].name, '절단기 1호', '설비 이름이 모델에 실려야 한다')
211
- })
212
-
213
- test('이름 없는 원본은 이름 없이 통과한다 — id 를 이름으로 베끼지 않는다', () => {
214
- const m: any = mesMaster()
215
- delete m.locations[1].name // 이름을 말하지 않는 원본
216
- const { model } = masterToTwin(m, DOMAIN_CATALOG)
217
- const location = (model as any).locations.find((n: any) => n.id === 'cut-1')
218
- /* 키 자체를 만들지 않는다: id 를 넣어 두면 "이름이 있다" 가 거짓이 되고, 화면은 이름 없음을
219
- 알아볼 수 없게 된다(그러면 "이름을 지어 주세요" 라고 말할 수도 없다). */
220
- assert.equal('name' in location, false, '원본이 이름을 말하지 않았으면 키가 없어야 한다')
221
- })
222
-
223
- /*
224
- * ★ 검사 명세가 모델로 통과한다 — **참조가 가리킬 대상이 실린다.**
225
- *
226
- * 자원은 예전부터 `testSpecificationIds` 로 시험을 가리킬 수 있었지만 가리켜지는 대상이 없었다. 인제스트가
227
- * 명세를 흘리면 축이 서 있어도 여전히 허공을 가리킨다 — 그래서 이 문에서 통과를 못 박는다.
228
- *
229
- * 표시명은 `name` 으로 옮긴다(등급과 같은 규칙) — 그러지 않으면 화면의 "설명" 열에 이름이 앉는다.
230
- */
231
- test('검사 명세가 모델로 통과한다 — 표시명은 name 으로', () => {
232
- const m: any = mesMaster()
233
- m.testSpecifications = [{ id: 'weld-cert', description: 'twin.x.test.weld', version: '2026.1' }]
234
- const { model } = masterToTwin(m, DOMAIN_CATALOG) as any
235
- const specs = (model as any).testSpecifications
236
- assert.equal(specs?.length, 1, '명세가 모델에 실려야 한다')
237
- assert.equal(specs[0].id, 'weld-cert')
238
- assert.equal(specs[0].name, 'twin.x.test.weld', '표시명은 name 자리에 온다(어휘를 하나로)')
239
- assert.equal('description' in specs[0], false, '두 자리에 같은 값을 두지 않는다')
240
- assert.equal(specs[0].version, '2026.1', '버전이 남아야 한다 — 어느 버전으로 검증했나')
241
- })
242
-
243
- test('선언하지 않으면 키를 만들지 않는다 — 빈 배열을 "선언했다" 로 보고하지 않는다', () => {
244
- const { model } = masterToTwin(mesMaster(), DOMAIN_CATALOG) as any
245
- assert.equal('testSpecifications' in (model as any), false)
246
- })
247
-
248
- /*
249
- * ── 자리의 속성이 커널까지 간다 (2026-08-14, EMS 4단계) ─────────────────────
250
- *
251
- * 에너지 커널은 계약전력을 **자리 속성**(`contract.kW`)에서 읽고, 없으면 계약 대비 판정을 아예
252
- * 하지 않는다. 그래서 이 통과가 끊기면 결과가 「오류 없이 판정만 사라지는」 모양이 된다 — 화면에는
253
- * 트윈이 정상으로 보이고 피크 경고만 영원히 오지 않는다. 눈으로는 보이지 않는 부류다.
254
- *
255
- * 실제로 처음에는 끊겨 있었다(타입만 열고 변환을 잇지 않았다).
256
- */
257
- test('자리의 속성을 모델로 통과시킨다 — 계약전력이 커널에 닿는 유일한 길', () => {
258
- const m = {
259
- source: 'ems-1',
260
- system: 'ems' as const,
261
- siteName: '공장',
262
- space: { width: 10, depth: 10 },
263
- locations: [
264
- {
265
- id: 'incoming-1',
266
- type: 'incoming',
267
- role: 'location' as const,
268
- capacity: 0,
269
- properties: [{ id: 'contract.kW', value: '4000', dataType: 'xs:double', uom: 'KWT' }]
270
- },
271
- { id: 'feeder-1', type: 'feeder', role: 'location' as const, capacity: 0 }
272
- ]
273
- }
274
- const { model } = masterToTwin(m as any)
275
- const incoming = model.locations.find((l: any) => l.id === 'incoming-1') as any
276
- assert.deepEqual(incoming.properties, m.locations[0].properties, '손대지 않고 나른다')
277
- const feeder = model.locations.find((l: any) => l.id === 'feeder-1') as any
278
- assert.equal('properties' in feeder, false, '없는 것을 빈 배열로 만들지 않는다(모름과 없음을 섞지 않는다)')
279
- })
@@ -1,90 +0,0 @@
1
- /*
2
- * 실측 양품률 — **이력에서 배운 수율이 선언값·상수를 이긴다.**
3
- *
4
- * ── 왜 (2026-08-19) ─────────────────────────────────────────────────────────
5
- * 소요시간에는 이력 층이 있었는데 수율에는 없었다. 양품률 기본값은 커널 소스의 상수(0.8)였고 **그 상수가
6
- * 불량 과다 주목 신호까지 만들었다.** 이제 커널이 판정을 작업 완료에 적고(`outcome`), 폴드가 축으로 들고,
7
- * KPI 가 종류별로 세고(`quality`), 이 모듈이 비율로 바꿔 커널 시임에 넣는다.
8
- *
9
- * 이 시험이 지키는 것:
10
- * ① 분모는 **판정된 것만** — 이동·체류를 섞으면 양품률이 낮게 나온다.
11
- * ② 표본이 모자라면 **배우지 않는다** — 비율은 드문 사건을 재는 값이라 작은 표본이 잡음을 만든다.
12
- * ③ 0 도 사실이다 — 전량 불량이면 0 을 배운다(「값이 없다」와 다르다).
13
- * ④ 모르는 종류에는 `undefined` — 그러면 커널이 선언값·상수로 내려간다.
14
- * ⑤ 배우지 못한 것을 **밝힌다** — 알리지 않고 일부만 반영하지 않는다.
15
- */
16
- import { test } from 'node:test'
17
- import assert from 'node:assert/strict'
18
- import { readFileSync } from 'node:fs'
19
- import { fileURLToPath } from 'node:url'
20
-
21
- import { buildYieldEstimator, DEFAULT_YIELD_MIN_SAMPLES } from '../server/engine/measured-yield.ts'
22
-
23
- const group = (key: string, good: number, scrap: number) => ({ key, quality: { good, scrap } })
24
-
25
- test('판정된 것만 분모다 — 이동·체류가 섞이지 않는다', () => {
26
- /* tasks 는 1000 건이어도 판정은 40 건뿐인 종류가 정상이다(중간 스테이션은 품질을 가리지 않는다). */
27
- const r = buildYieldEstimator([{ key: 'assembly', tasks: 1000, quality: { good: 36, scrap: 4 } } as any])
28
- assert.equal(r.learned.assembly, 0.9, '36/40 = 0.9')
29
- assert.deepEqual(r.samples.assembly, { good: 36, scrap: 4 })
30
- })
31
-
32
- test('표본이 모자라면 배우지 않고 그 사실을 낸다 — 세 건 중 한 건 불량은 33% 가 아니다', () => {
33
- const r = buildYieldEstimator([group('weld', 2, 1)])
34
- assert.deepEqual(r.learned, {})
35
- assert.deepEqual(r.skipped, [{ kind: 'weld', judged: 3 }])
36
- assert.equal(r.estimator, undefined, '배운 것이 없으면 시임을 만들지 않는다')
37
- assert.equal(r.minSamples, DEFAULT_YIELD_MIN_SAMPLES)
38
- })
39
-
40
- test('하한은 소요보다 높다 — 비율은 드문 사건을 재는 값이다', () => {
41
- /* 불량률 5% 인 공정은 20건에서 불량이 한 건이다 — 그 아래로 내려가면 이력이 잡음이 된다. */
42
- assert.ok(DEFAULT_YIELD_MIN_SAMPLES >= 20, `하한이 ${DEFAULT_YIELD_MIN_SAMPLES} 이면 비율에 너무 낮다`)
43
- })
44
-
45
- test('전량 불량은 0 을 배운다 — 「값이 없다」와 구별한다', () => {
46
- const r = buildYieldEstimator([group('paint', 0, 25)])
47
- assert.equal(r.learned.paint, 0)
48
- assert.equal(r.estimator!.estimate({ kind: 'paint' }), 0, '0 을 답한다(undefined 로 뭉개지 않는다)')
49
- })
50
-
51
- test('판정이 아예 없는 종류는 건너뛴 것이 아니다 — 품질을 가리지 않는 공정이 정상이다', () => {
52
- const r = buildYieldEstimator([{ key: 'putaway', tasks: 500 } as any])
53
- assert.deepEqual(r.learned, {})
54
- assert.deepEqual(r.skipped, [], '표본 부족으로 세지 않는다')
55
- })
56
-
57
- test('모르는 종류에는 undefined — 커널이 선언값·상수로 내려갈 수 있게', () => {
58
- const r = buildYieldEstimator([group('weld', 30, 2)])
59
- assert.equal(r.estimator!.estimate({ kind: 'weld' }), 30 / 32)
60
- assert.equal(r.estimator!.estimate({ kind: 'paint' }), undefined)
61
- })
62
-
63
- test("'unknown' 축은 쓰지 않는다 — 종류를 모르는 기록을 특정 종류의 근거로 삼지 않는다", () => {
64
- const r = buildYieldEstimator([group('unknown', 100, 5)])
65
- assert.deepEqual(r.learned, {})
66
- })
67
-
68
- test('빈 입력에도 답을 만든다 — 부르는 쪽이 조건문을 두 벌 갖지 않게', () => {
69
- for (const input of [undefined, []]) {
70
- const r = buildYieldEstimator(input as any)
71
- assert.deepEqual(r.learned, {})
72
- assert.equal(r.estimator, undefined)
73
- }
74
- })
75
-
76
- /*
77
- * ── 사슬이 이어져 있나 (소스로 지킨다) ──────────────────────────────────────
78
- * 이 층은 넷이 이어져야 뜻이 있다: 커널이 판정을 적고 → 폴드가 축으로 들고 → KPI 가 세고 → 여기서 비율.
79
- * 한 칸만 빠져도 화면은 「이력에서 배운 값」이라고 말하면서 상수로 돈다. 실 앱에서 관측하려면 라인이
80
- * 한 바퀴 돌아야 하므로(판정은 완료에서 일어난다), 경로는 여기서 지킨다.
81
- */
82
- test('사슬 넷이 이어져 있다 — 판정→축→집계→비율', () => {
83
- const hostSrc = (f: string) => readFileSync(fileURLToPath(new URL(`../server/${f}`, import.meta.url)), 'utf-8')
84
- assert.match(hostSrc('engine/kpi-fold.ts'), /facets\.outcome/, 'KPI 가 판정 축을 읽는다')
85
- assert.match(hostSrc('engine/kpi-fold.ts'), /quality\?: \{ good: number; scrap: number \}/, '종류별로 센다')
86
- const engine = hostSrc('engine/twin-engine.ts')
87
- assert.match(engine, /buildYieldEstimator\(kpi\?\.groups\?\.items/, '같은 폴드에서 배운다(두 번 계산하지 않는다)')
88
- assert.match(engine, /kernel\.yieldEstimator = yields\.estimator/, '커널 시임에 넣는다')
89
- assert.match(engine, /yieldOf missing/, '옛 커널이면 그 사실을 말한다')
90
- })
@@ -1,70 +0,0 @@
1
- /*
2
- * ★ 나눠 묻고 합치는 규율 — 갈래마다 상한까지 받아야 합친 결과가 정확하다.
3
- *
4
- * ── 왜 이 시험이 있나 (2026-08-28) ──────────────────────────────────────────
5
- * 「종류 IN + 시각순」은 색인을 못 쓴다. 그래서 종류를 하나씩 정확일치로 묻고 합치는데, 그때 함정이
6
- * 하나 있다 — UX 레인이 구현 전에 짚어 주었다.
7
- *
8
- * 「갈래마다 상한을 걸면 합친 결과가 시각순으로 온전하지 않다.
9
- * 종류 A 의 마지막이 종류 B 의 첫째보다 이를 수 있다.」
10
- *
11
- * 그 지적은 **갈래마다 상한보다 적게 받을 때** 참이다. 상한까지 받으면 성질이 선다: 어떤 갈래에서 빠진
12
- * 행은 그 갈래의 상한 번째보다 뒤이고, 우리는 전체에서 상한 개만 취하므로 그 행이 이 페이지에 들어올 수
13
- * 없다. 이 시험이 그 성질을 못박는다.
14
- */
15
- import { test } from 'node:test'
16
- import assert from 'node:assert/strict'
17
-
18
- import { mergeStreams } from '../server/service/twin-journal/event-type-split-shape.js'
19
-
20
- const byN = (a: { n: number }, b: { n: number }) => a.n - b.n
21
- const seq = (from: number, count: number) => Array.from({ length: count }, (_, i) => ({ n: from + i }))
22
-
23
- test('★ 한 갈래가 앞을 다 차지해도 전체에서 앞 limit 개가 나온다 — 짚어 준 그 경우다', () => {
24
- /*
25
- * A 가 1~5, B 가 100~104. limit 3 이면 답은 A 의 1,2,3 이다. B 는 한 건도 들어오지 않는 것이 맞다.
26
- */
27
- const r = mergeStreams([seq(1, 5), seq(100, 5)], 3, byN)
28
- assert.deepEqual(r.items.map(x => x.n), [1, 2, 3])
29
- assert.equal(r.capped, true, '더 있었다는 사실을 말해야 한다')
30
- })
31
-
32
- test('★ 갈래를 섞어도 시각순이 유지된다', () => {
33
- const a = [{ n: 1 }, { n: 4 }, { n: 7 }]
34
- const b = [{ n: 2 }, { n: 5 }, { n: 8 }]
35
- const c = [{ n: 3 }, { n: 6 }, { n: 9 }]
36
- const r = mergeStreams([a, b, c], 9, byN)
37
- assert.deepEqual(r.items.map(x => x.n), [1, 2, 3, 4, 5, 6, 7, 8, 9])
38
- assert.equal(r.capped, false, '상한에 닿지 않았으면 잘리지 않았다')
39
- })
40
-
41
- test('★ 상한에 닿은 갈래가 있으면 잘렸다고 말한다 — 숫자가 알리지 않고 작아지지 않게', () => {
42
- /* 한 갈래가 정확히 상한만큼 받아 왔으면 그 갈래에 더 있었을 수 있다. */
43
- const r = mergeStreams([seq(1, 3), seq(10, 1)], 3, byN)
44
- assert.equal(r.items.length, 3)
45
- assert.equal(r.capped, true)
46
- })
47
-
48
- test('상한에 못 닿았고 합쳐도 상한 미만이면 잘리지 않았다', () => {
49
- const r = mergeStreams([seq(1, 2), seq(10, 2)], 10, byN)
50
- assert.deepEqual(r.items.map(x => x.n), [1, 2, 10, 11])
51
- assert.equal(r.capped, false)
52
- })
53
-
54
- test('빈 갈래가 섞여도 답이 같다 — 그 종류가 그 구간에 없는 것은 정상이다', () => {
55
- const r = mergeStreams([[], seq(5, 2), []], 10, byN)
56
- assert.deepEqual(r.items.map(x => x.n), [5, 6])
57
- assert.equal(r.capped, false)
58
- })
59
-
60
- test('★ 갈래가 상한보다 많이 받아 오면 그 사실을 말한다 — 있을 수 없는 일이다', () => {
61
- /* 부르는 쪽이 상한을 잘못 걸었다는 뜻이고, 그 상태로 답하면 합친 결과를 믿을 수 없다. */
62
- const r = mergeStreams([seq(1, 5)], 3, byN)
63
- assert.equal(r.underfilled, true)
64
- })
65
-
66
- test('갈래가 하나면 그냥 앞에서 자른 것과 같다', () => {
67
- const r = mergeStreams([seq(1, 5)], 5, byN)
68
- assert.deepEqual(r.items.map(x => x.n), [1, 2, 3, 4, 5])
69
- assert.equal(r.underfilled, false)
70
- })