@things-factory/headless-twin 10.0.17 โ†’ 10.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/dist-server/engine/canonical-ingest.d.ts +12 -85
  2. package/dist-server/engine/canonical-ingest.js +92 -26
  3. package/dist-server/engine/canonical-ingest.js.map +1 -1
  4. package/dist-server/engine/energy-topology.js +3 -3
  5. package/dist-server/engine/energy-topology.js.map +1 -1
  6. package/dist-server/engine/kpi-fold.d.ts +91 -3
  7. package/dist-server/engine/kpi-fold.js +149 -25
  8. package/dist-server/engine/kpi-fold.js.map +1 -1
  9. package/dist-server/engine/kpi-query.js +99 -11
  10. package/dist-server/engine/kpi-query.js.map +1 -1
  11. package/dist-server/engine/local-declarations.js +6 -5
  12. package/dist-server/engine/local-declarations.js.map +1 -1
  13. package/dist-server/engine/model-vocabulary.js +2 -2
  14. package/dist-server/engine/model-vocabulary.js.map +1 -1
  15. package/dist-server/engine/oee-accumulator.d.ts +2 -1
  16. package/dist-server/engine/oee-accumulator.js +3 -2
  17. package/dist-server/engine/oee-accumulator.js.map +1 -1
  18. package/dist-server/engine/twin-engine.d.ts +72 -2
  19. package/dist-server/engine/twin-engine.js +150 -4
  20. package/dist-server/engine/twin-engine.js.map +1 -1
  21. package/dist-server/routes.js +1 -1
  22. package/dist-server/routes.js.map +1 -1
  23. package/dist-server/service/index.d.ts +1 -1
  24. package/dist-server/service/index.js +3 -0
  25. package/dist-server/service/index.js.map +1 -1
  26. package/dist-server/service/reference/reference-live.js +1 -1
  27. package/dist-server/service/reference/reference-live.js.map +1 -1
  28. package/dist-server/service/reference/reference-master.d.ts +11 -2
  29. package/dist-server/service/reference/reference-master.js +1 -1
  30. package/dist-server/service/reference/reference-master.js.map +1 -1
  31. package/dist-server/service/reference/reference-resolver.js +2 -2
  32. package/dist-server/service/reference/reference-resolver.js.map +1 -1
  33. package/dist-server/service/reference/template-registry.d.ts +1 -1
  34. package/dist-server/service/reference/template-registry.js.map +1 -1
  35. package/dist-server/service/twin-backfill/backfill-period-facts.d.ts +24 -0
  36. package/dist-server/service/twin-backfill/backfill-period-facts.js +96 -0
  37. package/dist-server/service/twin-backfill/backfill-period-facts.js.map +1 -0
  38. package/dist-server/service/twin-backfill/backfill-shape.d.ts +34 -0
  39. package/dist-server/service/twin-backfill/backfill-shape.js +75 -0
  40. package/dist-server/service/twin-backfill/backfill-shape.js.map +1 -0
  41. package/dist-server/service/twin-backfill/index.d.ts +2 -0
  42. package/dist-server/service/twin-backfill/index.js +6 -0
  43. package/dist-server/service/twin-backfill/index.js.map +1 -0
  44. package/dist-server/service/twin-backfill/twin-backfill-resolver.d.ts +10 -0
  45. package/dist-server/service/twin-backfill/twin-backfill-resolver.js +44 -0
  46. package/dist-server/service/twin-backfill/twin-backfill-resolver.js.map +1 -0
  47. package/dist-server/service/twin-control/twin-control-mutation.js +2 -2
  48. package/dist-server/service/twin-control/twin-control-mutation.js.map +1 -1
  49. package/dist-server/service/twin-lifecycle/domain-catalog.js +2 -1
  50. package/dist-server/service/twin-lifecycle/domain-catalog.js.map +1 -1
  51. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +1 -1
  52. package/dist-server/service/twin-model/name-index.js +1 -1
  53. package/dist-server/service/twin-model/name-index.js.map +1 -1
  54. package/dist-server/service/twin-model/project-structure.js +4 -3
  55. package/dist-server/service/twin-model/project-structure.js.map +1 -1
  56. package/dist-server/service/twin-model/twin-equipment.d.ts +1 -1
  57. package/dist-server/service/twin-model/twin-equipment.js +2 -2
  58. package/dist-server/service/twin-model/twin-equipment.js.map +1 -1
  59. package/dist-server/service/twin-model/twin-model-item-query.js +1 -1
  60. package/dist-server/service/twin-model/twin-model-item-query.js.map +1 -1
  61. package/dist-server/service/twin-model/twin-model-query.js +4 -4
  62. package/dist-server/service/twin-model/twin-model-query.js.map +1 -1
  63. package/dist-server/service/twin-model/twin-model-tree-query.js +1 -1
  64. package/dist-server/service/twin-model/twin-model-tree-query.js.map +1 -1
  65. package/dist-server/service/twin-space/twin-space-resolver.js +1 -1
  66. package/dist-server/service/twin-space/twin-space-resolver.js.map +1 -1
  67. package/dist-shared/entity-delta.js +1 -1
  68. package/dist-shared/entity-delta.js.map +1 -1
  69. package/package.json +7 -6
  70. package/server/engine/canonical-ingest.ts +72 -84
  71. package/server/engine/energy-topology.ts +1 -1
  72. package/server/engine/kpi-fold.ts +219 -36
  73. package/server/engine/kpi-query.ts +97 -4
  74. package/server/engine/local-declarations.ts +2 -1
  75. package/server/engine/model-vocabulary.ts +1 -1
  76. package/server/engine/oee-accumulator.ts +4 -2
  77. package/server/engine/twin-engine.ts +163 -5
  78. package/server/routes.ts +6 -1
  79. package/server/service/index.ts +3 -0
  80. package/server/service/reference/reference-live.ts +8 -2
  81. package/server/service/reference/reference-master.ts +12 -3
  82. package/server/service/reference/reference-resolver.ts +1 -1
  83. package/server/service/reference/template-registry.ts +1 -1
  84. package/server/service/twin-backfill/backfill-period-facts.ts +168 -0
  85. package/server/service/twin-backfill/backfill-shape.ts +86 -0
  86. package/server/service/twin-backfill/index.ts +3 -0
  87. package/server/service/twin-backfill/twin-backfill-resolver.ts +35 -0
  88. package/server/service/twin-control/twin-control-mutation.ts +1 -1
  89. package/server/service/twin-lifecycle/domain-catalog.ts +2 -1
  90. package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +1 -1
  91. package/server/service/twin-model/name-index.ts +1 -1
  92. package/server/service/twin-model/project-structure.ts +3 -2
  93. package/server/service/twin-model/twin-equipment.ts +14 -2
  94. package/server/service/twin-model/twin-model-item-query.ts +1 -1
  95. package/server/service/twin-model/twin-model-query.ts +2 -2
  96. package/server/service/twin-model/twin-model-tree-query.ts +1 -1
  97. package/server/service/twin-space/twin-space-resolver.ts +1 -1
  98. package/shared/entity-delta.ts +1 -1
  99. package/test/axis-read.test.ts +4 -3
  100. package/test/backfill-shape.test.ts +89 -0
  101. package/test/broadcast-cost-baseline.test.ts +2 -1
  102. package/test/canonical-ingest-vocabularies.test.ts +82 -3
  103. package/test/capability-mapping.test.ts +1 -1
  104. package/test/contract-layer-guard.test.ts +48 -0
  105. package/test/declaration-reaches-model.test.ts +2 -0
  106. package/test/equipment-identity-reaches.test.ts +57 -0
  107. package/test/fact-scope-wiring.test.ts +96 -0
  108. package/test/generated-not-counted.test.ts +99 -0
  109. package/test/ingest-bench.test.ts +2 -1
  110. package/test/ingest-wiring-guard.test.ts +197 -0
  111. package/test/kpi-fold.test.ts +81 -0
  112. package/test/live-mirror-parity.test.ts +6 -3
  113. package/test/local-declarations.test.ts +3 -2
  114. package/test/master-to-twin.test.ts +2 -2
  115. package/test/oee-accumulator.test.ts +18 -3
  116. package/test/projection-reaches-screen.test.ts +5 -0
  117. package/test/projection-reads-declared.test.ts +109 -0
  118. package/test/property-effects.test.ts +7 -3
  119. package/test/scale-twin-bench.test.ts +2 -1
  120. package/test/vocabulary-guard.test.ts +1 -1
  121. package/tsconfig.shared.tsbuildinfo +1 -1
  122. package/tsconfig.tsbuildinfo +1 -1
@@ -54,9 +54,10 @@ const attention_digest_js_1 = require("./attention-digest.js");
54
54
  const live_feed_registry_js_1 = require("./live-feed-registry.js");
55
55
  const ingest_health_js_1 = require("./ingest-health.js");
56
56
  const ingest_dedupe_js_1 = require("./ingest-dedupe.js");
57
- const twin_kernel_1 = require("@operato/twin-kernel");
57
+ const ops_contract_1 = require("@operato/ops-contract");
58
58
  /* ์ปค๋„ ๋Ÿฐํƒ€์ž„ ๋กœ๋“œ โ€” CJS ๋ฒˆ๋“ค(dist-cjs). ํƒ€์ž…์€ ์œ„ import type ๋กœ. replay = ์ด๋ฒคํŠธ์—ดโ†’์ƒํƒœ ์žฌ๊ตฌ์„ฑ(๋ณต๊ตฌยท์‹œ๊ฐ„์—ฌํ–‰). */
59
- const { WmsKernel, YmsKernel, MesKernel, EmsKernel, TwinRuntime, StateProjector, replay, replayFrom, replayWithCheckpoint, replaySegments, readBoardLocations, readBoardEquipment, DOMAIN_CATALOG, OP_EVENT, validateScenario } = require('@operato/twin-kernel');
59
+ const { WmsKernel, YmsKernel, MesKernel, EmsKernel, TwinRuntime, StateProjector, replay, replayFrom, replayWithCheckpoint, replaySegments } = require('@operato/twin-kernel');
60
+ const { readBoardLocations, readBoardEquipment, DOMAIN_CATALOG, OP_EVENT, validateScenario } = require('@operato/ops-contract');
60
61
  const KERNELS = { wms: WmsKernel, yms: YmsKernel, mes: MesKernel, ems: EmsKernel };
61
62
  /**
62
63
  * ์‹œ๊ฐ์ถ•์„ ๊ตฌํ•  ๋•Œ ํ•œ ๋ฒˆ์— ๋„์šฐ๋Š” ํŠธ์œˆ ์ˆ˜.
@@ -1366,6 +1367,7 @@ class TwinEngine {
1366
1367
  return this.instances[key];
1367
1368
  const Kernel = kernelFor(kind);
1368
1369
  const kernel = new Kernel(domainId, undefined, this.productionSpecOf(model));
1370
+ kernel.scopeId = id;
1369
1371
  kernel.loadTwinModel(model); // ๊ตฌ์กฐ๋งŒ. ์ƒํƒœ๋Š” ์•„๋ž˜ ์›œ์Šคํƒ€ํŠธ๊ฐ€ ์ฃผ์ž…ํ•œ๋‹ค.
1370
1372
  this.applyOperations(kernel, model, id); // ์‹œ๊ฐ„ยท์ˆ˜์œจ ๋ช…์„ธ(์žˆ์œผ๋ฉด) โ€” ์—†์œผ๋ฉด ์ปค๋„ ๊ธฐ๋ณธ๊ฐ’
1371
1373
  /* ์ถ”์ •๊ธฐ๋Š” DB ์กฐํšŒ๋ฅผ ํฌํ•จํ•ด ๋น„๋™๊ธฐ โ€” ๊ธฐ๋™์„ ๋ง‰์ง€ ์•Š๊ณ  ๋ถ™๋Š”๋‹ค(๋ถ™๊ธฐ ์ „ ์ž‘์—…์€ ๋ช…์„ธยท์ƒ์ˆ˜๋กœ ์‚ฐ์ถœ). */
@@ -1559,6 +1561,7 @@ class TwinEngine {
1559
1561
  return this.instances[key];
1560
1562
  const Kernel = kernelFor(kind);
1561
1563
  const kernel = new Kernel(domainId, undefined, this.productionSpecOf(model));
1564
+ kernel.scopeId = id;
1562
1565
  kernel.loadTwinModel(model);
1563
1566
  /* **์„ธ์šฐ๋Š” ์ชฝ์ด ์•„๋Š” ์‚ฌ์‹ค์€ ์„ธ์šธ ๋•Œ ๋งํ•œ๋‹ค.** ์˜ˆ์ „์—๋Š” ์ฒซ ์ด๋ฒคํŠธ๊ฐ€ ๋„์ฐฉํ•ด์•ผ ์ปค๋„์ด ์Šค์Šค๋กœ๋ฅผ
1564
1567
  ๊ด€์ธก ๊ตฌ๋™์œผ๋กœ ์—ฌ๊ฒผ๊ณ , ๊ทธ๋ž˜์„œ ์•„์ง ์•„๋ฌด๊ฒƒ๋„ ๋ชป ๋ฐ›์€ ๋ฏธ๋Ÿฌ๋Š” ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ์ทจ๊ธ‰์„ ๋ฐ›์•˜๋‹ค. */
@@ -2164,9 +2167,20 @@ class TwinEngine {
2164
2167
  if (carried.length)
2165
2168
  jobs.push(this.persistCarried(inst.domainId, inst.id, carried));
2166
2169
  if (plain.length && inst.revision != null) {
2170
+ /*
2171
+ * โ”€โ”€ ๋งˆ๊ฐ๋œ ๊ตฌ๊ฐ„ ์‚ฌ์‹ค์€ ํ•œ ๋ฒˆ๋งŒ ์ ๋Š”๋‹ค (2026-08-30) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
2172
+ *
2173
+ * ์ด๋ฏธ ์žˆ๋Š” ๊ฒƒ์„ ๊ฑธ๋Ÿฌ๋‚ธ ๋’ค์— ๋ฒˆํ˜ธ๋ฅผ ๋งค๊ธด๋‹ค. ๊ฑธ๋Ÿฌ๋‚ด๊ธฐ ์ „์— ๋งค๊ธฐ๋ฉด **์“ฐ์ง€ ์•Š์€ ๋ฒˆํ˜ธ๊ฐ€ ๋น„๊ณ **,
2174
+ * ๊ทธ ๊ตฌ๋ฉ์ด ์ €๋„์˜ ๋ฆฌ๋น„์ „ ์—ฐ์†์„ฑ์„ ๋Š๋Š”๋‹ค.
2175
+ */
2176
+ /*
2177
+ * ๋ฒˆํ˜ธ๋Š” **๋จผ์ € ์žก๋Š”๋‹ค**(๋™๊ธฐ). ๊ฑธ๋Ÿฌ๋‚ธ ๋’ค์— ์žก์œผ๋ฉด ๋‘ flush ๊ฐ€ ๊ฒน์น  ๋•Œ ๊ฐ™์€ ๋ฒˆํ˜ธ๋ฅผ ๋‘ ๋ฒˆ ์“ด๋‹ค.
2178
+ * ๊ฑธ๋Ÿฌ์ง„ ๋งŒํผ ๋ฒˆํ˜ธ๊ฐ€ ๋น„์ง€๋งŒ, ๊ทธ ๊ตฌ๋ฉ์€ ํ•ด๋กญ์ง€ ์•Š๋‹ค โ€” ๋ฆฌ๋น„์ „์€ ๊ฐ™์€ ์‹œ๊ฐ์„ ๊ฐ€๋ฆฌ๋Š” ๋ฐ๋งŒ ์“ฐ๊ณ 
2179
+ * ์ด์–ด์ง์„ ์š”๊ตฌํ•˜์ง€ ์•Š๋Š”๋‹ค(์ €๋„ ๋จธ๋ฆฌ๋Š” ์ตœ๋Œ€๊ฐ’์ด๋‹ค).
2180
+ */
2167
2181
  const start = inst.revision;
2168
2182
  inst.revision = start + plain.length;
2169
- jobs.push(this.persistBatch(inst.domainId, inst.id, plain, start));
2183
+ jobs.push(this.dropAlreadyWritten(inst.domainId, inst.id, plain).then(fresh => fresh.length ? this.persistBatch(inst.domainId, inst.id, fresh, start) : undefined));
2170
2184
  }
2171
2185
  if (!jobs.length)
2172
2186
  return Promise.resolve();
@@ -2193,6 +2207,76 @@ class TwinEngine {
2193
2207
  * ์˜ˆ์ „์—๋Š” ์ด ๊ฒฝ๋กœ๊ฐ€ **๋ธํƒ€๋งˆ๋‹ค ํ•œ ํ–‰์”ฉ** ์ €์žฅํ–ˆ๋‹ค(๊ทธ๋ฆฌ๊ณ  ํ–‰๋งˆ๋‹ค ๊ตฌ์กฐ ๋ฆฌ๋น„์ „์„ ๋ฌผ์—ˆ๋‹ค). ๊ทœ๋ชจ์—์„œ ๊ทธ๊ฒƒ์ด
2194
2208
  * ํ˜ธ์ŠคํŠธ๋ฅผ ๋จน์—ˆ๋‹ค(ยง7.1 ์‹ค์ธก). ์—ฌ๊ธฐ์„œ ๊ตฌ์กฐ ๋ฆฌ๋น„์ „์€ **ํ•œ ๋ฒˆ๋งŒ** ๋ฌป๋Š”๋‹ค.
2195
2209
  */
2210
+ /**
2211
+ * **๋งˆ๊ฐ๋œ ๊ตฌ๊ฐ„ ์‚ฌ์‹ค์€ ํ•œ ๋ฒˆ๋งŒ ์ ๋Š”๋‹ค** โ€” ๊ฐ™์€ ์‚ฌ์‹ค์ด ๋‘ ๋ฒˆ ์˜ค๋ฉด ํ•œ ์‚ฌ์‹ค์ด๋‹ค (2026-08-30).
2212
+ *
2213
+ * โ”€โ”€ ์™œ ์“ฐ๋Š” ์ž๋ฆฌ์—์„œ ๋ง‰๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
2214
+ * ์ปค๋„์ด ๊ทธ ์‚ฌ์‹ค๋“ค์˜ ์ •์ฒด์„ฑ์„ ๋‚ด์šฉ์—์„œ ๋งŒ๋“ ๋‹ค(์ข…๋ฅ˜ยท๋Œ€์ƒยท์‹œ์ž‘ยท๋). ๊ทธ๋Ÿฐ๋ฐ ์ €๋„์˜ ๊ธฐ๋ณธํ‚ค๋Š” ์ƒˆ๋กœ
2215
+ * ๋งŒ๋“œ๋Š” uuid ๋ผ, **id ๊ฐ€ ๊ธ€์ž ํ•˜๋‚˜๊นŒ์ง€ ๊ฐ™์•„๋„ ํ–‰์ด ๋”ฐ๋กœ ์Œ“์˜€๋‹ค.**
2216
+ *
2217
+ * ์‹ค์ธก(2026-08-30): ๋ฐœ์ „ ๋‹จ๊ฐ€๊ฐ€ ํ–‰ 7๊ฐœยท์„œ๋กœ ๋‹ค๋ฅธ id 4๊ฐœ์˜€๋‹ค. 8์›” 27์ผ ๋‹จ๊ฐ€๊ฐ€ ์„ธ ๋ฒŒ ์žˆ์—ˆ๊ณ ,
2218
+ * ๊ทธ ๊ตฌ๊ฐ„์˜ ์ˆ˜์ต์ด ์„ธ ๋ฒˆ ์„ธ์–ด์ง„๋‹ค.
2219
+ *
2220
+ * ์ปค๋„ฅํ„ฐ๊ฐ€ ์ปค์„œ๋กœ ๋ง‰๋Š” ๊ฒƒ์ด ์ฒซ ๋ฐฉ์–ด์„ ์ด๊ณ  ๊ทธ์ชฝ๋„ ๊ณ ์ณค๋‹ค. ๊ทธ๋Ÿฐ๋ฐ **์ปค๋„ฅํ„ฐ๊ฐ€ ํ•œ ๋ฒˆ ์‹ค์ˆ˜ํ•˜๋ฉด ์ €๋„์ด
2221
+ * ๋ถ€ํ’€๊ณ  ๊ทธ ์œ„์˜ ๋ชจ๋“  ํ•ฉ์ด ํ‹€๋ฆฐ๋‹ค.** ์ •์ฒด์„ฑ์€ ์ปค๋„์ด ์„ ์–ธํ•œ ์‚ฌ์‹ค์ด๋ฏ€๋กœ, ์–ด๋А ๋ฌธ์œผ๋กœ ๋“ค์–ด์˜ค๋“ 
2222
+ * ์ง€์ผœ์ ธ์•ผ ํ•œ๋‹ค โ€” ์ฑ„์šฐ๊ธฐ ๊ฒฝ๋กœ์—๋งŒ ์žˆ์œผ๋ฉด ๊ทธ ๋ณด์ฆ์€ ใ€Œ์–ด๋А ๋ฌธ์œผ๋กœ ์™”๋А๋ƒใ€์— ๊ฑธ๋ฆฐ๋‹ค.
2223
+ *
2224
+ * โ”€โ”€ ๊ฐ’์ด ์‹ผ ์ด์œ  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
2225
+ * ๋งˆ๊ฐ๋œ ๊ตฌ๊ฐ„ ์‚ฌ์‹ค๋งŒ ๋ณธ๋‹ค(์‹œ์ ์˜ ๊ด€์ธก์€ ๊ทธ๋Œ€๋กœ ์ง€๋‚œ๋‹ค โ€” ๋ฐ˜๋ณต์ด ๋œป์„ ๊ฐ€์ง„๋‹ค). ๊ทธ๊ฒƒ๋“ค์€ ๋“œ๋ฌผ์–ด์„œ
2226
+ * (ํ•œ ์‹œ๊ฐ„์— ํ•œ ์ค„) ํ•œ ๋ฌถ์Œ์— ๋ช‡ ๊ฐœ๋ฟ์ด๊ณ , ๊ทธ ๊ตฌ๊ฐ„์˜ ๊ทธ ์ข…๋ฅ˜๋งŒ ์ƒ‰์ธ์œผ๋กœ ์ฝ๋Š”๋‹ค.
2227
+ */
2228
+ static { this.PERIOD_FACT_TYPES = new Set([
2229
+ 'energy.usage.period',
2230
+ 'energy.generation.period',
2231
+ 'energy.generation.price',
2232
+ 'energy.tariff.basis',
2233
+ 'energy.bill'
2234
+ ]); }
2235
+ static async dropAlreadyWritten(domainId, instanceId, envelopes) {
2236
+ const periodFacts = envelopes.filter(e => this.PERIOD_FACT_TYPES.has(String(e?.eventType)) && typeof e?.eventId === 'string');
2237
+ if (!periodFacts.length)
2238
+ return envelopes;
2239
+ const times = periodFacts.map(e => Date.parse(String(e.eventTime))).filter(n => Number.isFinite(n));
2240
+ if (!times.length)
2241
+ return envelopes;
2242
+ const types = [...new Set(periodFacts.map(e => String(e.eventType)))];
2243
+ const existing = await (0, shell_1.getRepository)(twin_event_js_1.TwinEvent)
2244
+ .createQueryBuilder('e')
2245
+ .select(['e.payload AS "payload"'])
2246
+ .where('e.domain = :domainId', { domainId })
2247
+ .andWhere('e.instanceId = :instanceId', { instanceId })
2248
+ .andWhere('e.eventType IN (:...types)', { types })
2249
+ .andWhere('e.eventTime BETWEEN :fromAt AND :toAt', { fromAt: new Date(Math.min(...times)), toAt: new Date(Math.max(...times)) })
2250
+ .getRawMany()
2251
+ .catch(() => []);
2252
+ const seen = new Set();
2253
+ for (const row of existing) {
2254
+ let p = row.payload;
2255
+ if (typeof p === 'string') {
2256
+ try {
2257
+ p = JSON.parse(p);
2258
+ }
2259
+ catch {
2260
+ p = undefined;
2261
+ }
2262
+ }
2263
+ if (typeof p?.eventId === 'string' && p.eventId)
2264
+ seen.add(p.eventId);
2265
+ }
2266
+ /* ํ•œ ๋ฌถ์Œ ์•ˆ์— ๊ฐ™์€ ๊ฒƒ์ด ๋‘˜ ์žˆ์–ด๋„ ํ•˜๋‚˜๋งŒ ์ ๋Š”๋‹ค. */
2267
+ const kept = [];
2268
+ for (const e of envelopes) {
2269
+ if (!this.PERIOD_FACT_TYPES.has(String(e?.eventType)) || typeof e?.eventId !== 'string') {
2270
+ kept.push(e);
2271
+ continue;
2272
+ }
2273
+ if (seen.has(e.eventId))
2274
+ continue;
2275
+ seen.add(e.eventId);
2276
+ kept.push(e);
2277
+ }
2278
+ return kept;
2279
+ }
2196
2280
  static async persistCarried(domainId, instanceId, items) {
2197
2281
  const repo = (0, shell_1.getRepository)(twin_event_js_1.TwinEvent);
2198
2282
  const structureRev = await this.structureRevOf(domainId, instanceId);
@@ -2301,6 +2385,23 @@ class TwinEngine {
2301
2385
  }));
2302
2386
  }
2303
2387
  /**
2388
+ * โ”€โ”€ **ํŠธ์œˆ์€ ์„ค๋น„์˜ ๋งˆ์Šคํ„ฐ๊ฐ€ ์•„๋‹ˆ๋‹ค** (์‚ฌ์šฉ์ž ๊ฒฐ์ • 2026-08-30) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
2389
+ *
2390
+ * ์ธ์›ยท์„ค๋น„ยท์ž์‚ฐ์˜ ๋งˆ์Šคํ„ฐ๋Š” `@things-factory/ops-master` ๋‹ค. ํŠธ์œˆ์€ ๊ทธ๊ฒƒ์„ **๋‹น๊ฒจ ์™€** ๋ชจ๋ธ์—
2391
+ * ๋ฐ˜์˜ํ•˜๊ณ , ์—ฌ๊ธฐ ๋‚จ๋Š” ๊ฒƒ์€ ๊ทธ ๊ฒฐ๊ณผ์˜ ์บ์‹œ๋‹ค.
2392
+ *
2393
+ * ๊ทธ๋ž˜์„œ ์ด ํ•จ์ˆ˜๊ฐ€ ํ•˜๋Š” ์ผ์— ์„ ์ด ์žˆ๋‹ค.
2394
+ *
2395
+ * ํŠธ์œˆ ์•ˆ์—์„œ ์‚ฌ๋žŒ์ด ๋”ํ•œ ์„ค๋น„ ๊ฐ€์ •ยท์‹œ๋ฎฌ๋ ˆ์ด์…˜์˜ ์‚ฌ์‹ค์ด๋‹ค โ€” ํŠธ์œˆ์ด ๋“ ๋‹ค (์ง€๊ธˆ ์ด ํ•จ์ˆ˜)
2396
+ * ํ˜„์žฅ์— ์‹ค์ œ๋กœ ์žˆ๋Š” ์„ค๋น„ ๋งˆ์Šคํ„ฐ์˜ ์‚ฌ์‹ค์ด๋‹ค โ€” ํŠธ์œˆ์ด ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค
2397
+ *
2398
+ * ์ด ํ•จ์ˆ˜๋Š” **ํŠธ์œˆ ์ œ์–ด ๋ช…๋ น**(`resource.add`) ๋’ค์—๋งŒ ๋ถˆ๋ฆฐ๋‹ค. ๊ด€์ธก์—์„œ ์„ค๋น„๊ฐ€ ์ƒ๊ธฐ๋Š” ๊ฒฝ๋กœ๊ฐ€ ์•„๋‹ˆ๋‹ค.
2399
+ * ๊ด€์ธก์œผ๋กœ ๋ชจ๋ฅด๋Š” ์„ค๋น„๊ฐ€ ๋“ค์–ด์˜ค๋ฉด ๊ทธ๊ฒƒ์€ **๋งˆ์Šคํ„ฐ์— ์—†๋Š” ๊ฒƒ**์ด๊ณ , ํŠธ์œˆ์ด ์กฐ์šฉํžˆ ๋งŒ๋“ค์–ด ์ฃผ๋ฉด ๋‘
2400
+ * ๊ณณ์ด ์„œ๋กœ ๋‹ค๋ฅธ ์„ค๋น„ ๋ชฉ๋ก์„ ๊ฐ–๊ฒŒ ๋œ๋‹ค. ๊ทธ๋•Œ๋Š” ๋งŒ๋“ค์ง€ ๋ง๊ณ  ใ€Œ๋ชจ๋ฅด๋Š” ์„ค๋น„๊ฐ€ ์™”๋‹คใ€๋กœ ์„ธ์–ด์•ผ ํ•œ๋‹ค.
2401
+ *
2402
+ * ๋‹น๊ฒจ ์˜ค๋Š” ๊ธธ์ด ๋ถ™์œผ๋ฉด ์ด ์ฃผ์„์˜ ์œ„์ชฝ ์ ˆ๋ฐ˜๋งŒ ๋‚จ๋Š”๋‹ค.
2403
+ *
2404
+ * โ”€โ”€ ์›๋ž˜ ์„ค๋ช… โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
2304
2405
  * ๋ผ์ด๋ธŒ ๊ตฌ์กฐ ๋ณ€์ด(resource.add ๋“ฑ)๋ฅผ ์ €์žฅ๋œ model ์— ๋ฐ˜์˜ โ€” ๋Ÿฐํƒ€์ž„ ์ปค๋„์˜ ๋ฌด๋ฒ„๋ฅผ registry model.equipment ์— ๋™๊ธฐ.
2305
2406
  * ์ด๊ฒŒ ์—†์œผ๋ฉด ๋Ÿฐํƒ€์ž„์—” ์ถ”๊ฐ€๋ผ๋„(์ƒํƒœยท์ €๋„์—” ๋ฐ˜์˜) ์ €์žฅ model ๋Š” ์›๋ณธ์ด๋ผ ํ”„๋กœ๋น„์ €๋‹ ํŽธ์ง‘๊ธฐยท์žฌ๊ธฐ๋™(loadTwinModel)์ด
2306
2407
  * ์ถ”๊ฐ€๋ถ„์„ ์žƒ๋Š”๋‹ค. ๊ธฐ์กด model.equipment ํ•ญ๋ชฉ์€ ๋ณด์กด(homeLocation ์œ ์ง€)ํ•˜๊ณ  ์ƒˆ id ๋งŒ append(์ถ”๊ฐ€ ์‹œ์  location=homeLocation).
@@ -3104,7 +3205,7 @@ class TwinEngine {
3104
3205
  */
3105
3206
  if (model?.utcOffsetMinutes === undefined) {
3106
3207
  for (const e of (model?.equipment ?? [])) {
3107
- const hasProfile = (e?.properties ?? []).some(p => String(p?.id) === twin_kernel_1.EMS_PROPERTY.genDailyProfile && String(p?.value ?? '').trim());
3208
+ const hasProfile = (e?.properties ?? []).some(p => String(p?.id) === ops_contract_1.EMS_PROPERTY.genDailyProfile && String(p?.value ?? '').trim());
3108
3209
  if (hasProfile)
3109
3210
  warnings.push((0, reference_master_js_3.generationWithoutTimeZone)(String(model?.spaceId ?? ''), String(e.id)));
3110
3211
  }
@@ -4003,6 +4104,51 @@ class TwinEngine {
4003
4104
  * `offered` ๋Š” **์ œ์‹œ๋œ ๋ ˆ์ฝ”๋“œ ์ˆ˜**๋‹ค(๊ฑฐ๋ถ€ ์—ฌ๋ถ€ ๋ฌด๊ด€). ํ†ต๊ณผ์œจ์„ ์„œ๋กœ ๋‹ค๋ฅธ ๋‘ ๊ณ„์ˆ˜๊ธฐ์—์„œ ๋‚˜๋ˆ  ๊ณ„์‚ฐํ•˜๋ฉด
4004
4105
  * ๋ถ„๋ชจ์™€ ๋ถ„์ž๊ฐ€ ๋‹ค๋ฅธ ๊ฒƒ์„ ์„ธ๊ฒŒ ๋˜๋ฏ€๋กœ, ํ•œ์ž๋ฆฌ์—์„œ ๋ณธ ์ˆ˜๋ฅผ ๊ทธ๋Œ€๋กœ ๋„˜๊ธด๋‹ค.
4005
4106
  */
4107
+ /**
4108
+ * ์ด ํŠธ์œˆ์˜ ์ €๋„์ด ์ง€๊ธˆ ๋ช‡ ๋ฒˆ๊นŒ์ง€ ์ ํ˜”๋‚˜ โ€” **์ ‘๊ทผ์ž๋กœ ๋‚ธ๋‹ค.**
4109
+ *
4110
+ * ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋ฅผ ๋ฐ–์—์„œ ์ง์ ‘ ์ƒ‰์ธํ•˜์ง€ ์•Š๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ด ์ด ์ €์žฅ์†Œ์˜ ๊ทœ์œจ์ด๋‹ค(ยง`engine-registry-access`).
4111
+ * ์ง€๋‚œ ๊ธฐ๋ก์„ ์ฑ„์šฐ๋Š” ๊ธธ์ด ๋‹ค์Œ ๋ฒˆํ˜ธ๋ฅผ ์•Œ์•„์•ผ ํ•ด์„œ ์—ด์—ˆ๋‹ค.
4112
+ *
4113
+ * ํŠธ์œˆ์ด ๋„๋Š” ์ค‘์ด ์•„๋‹ˆ๋ฉด 0 ์ด๋‹ค โ€” ๊ทธ๋•Œ๋Š” ์ €๋„๋งŒ ์žˆ๊ณ  ์ด์–ด ๋ถ™์ผ ๋ฒˆํ˜ธ๋ฅผ ์ปค๋„์ด ๋“ค๊ณ  ์žˆ์ง€ ์•Š๋‹ค.
4114
+ */
4115
+ /**
4116
+ * ๋งˆ๊ฐ๋œ ๊ตฌ๊ฐ„ ์‚ฌ์‹ค์˜ **์ด๋ฆ„์„ ์ง€์„ ๋•Œ ์“ธ ๋ฒ”์œ„์™€ ์„ ์–ธ** โ€” ์œ ์ž… ๋ฌธ์— ๋„˜๊ธด๋‹ค.
4117
+ *
4118
+ * โ”€โ”€ ์™œ ํ˜ธ์ŠคํŠธ๊ฐ€ ์ฃผ๋‚˜ (2026-08-30) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
4119
+ * ์ปค๋„์€ `new Kernel(domainId, โ€ฆ)` ์œผ๋กœ ์„œ๋ฏ€๋กœ **์ž๊ธฐ๊ฐ€ ์–ด๋А ํŠธ์œˆ์ธ์ง€ ๋ชจ๋ฅธ๋‹ค.** ๊ทธ๋Ÿฐ๋ฐ ์„ค๋น„ ๋ฒˆํ˜ธ๋Š”
4120
+ * ํŠธ์œˆ ์•ˆ์—์„œ๋งŒ ํ†ตํ•˜๋Š” ์ด๋ฆ„ํ‘œ๋ผ, ํ•œ ๋„๋ฉ”์ธ์— ํ˜„์žฅ์ด ๋‘˜์ด๋ฉด ์„œ๋กœ ๋‹ค๋ฅธ ์„ค๋น„์˜ ๊ฐ™์€ ๋‚ ์ด ํ•œ ์‚ฌ์‹ค์ด
4121
+ * ๋œ๋‹ค. ์‹ค์ธก์œผ๋กœ ๊ทธ ์ผ์ด ๋‚ฌ๋‹ค โ€” ๋‘ ๋ฐœ์ „์†Œ์˜ `002` ๊ฐ€ ๊ฒน์ณ, ์—ฌ๋Ÿฌ ํ˜„์žฅ์„ ํ•จ๊ป˜ ๊ณ„์‚ฐํ•˜๋Š” ์„ฑ๊ณผ ํ™”๋ฉด์—์„œ
4122
+ * ํ•œ์ชฝ ๋ฐœ์ „๋Ÿ‰์ด ์‚ฌ๋ผ์ง„๋‹ค.
4123
+ *
4124
+ * ์„ ์–ธ๋œ ์ •์ฒด์„ฑ์€ **์ปค๋„์ด ๋‹ตํ•œ๋‹ค**(ยง`FlowEngine.equipmentIdentity`) โ€” ํŒ์ •์„ ๋‘ ๊ณณ์— ๋‘์ง€ ์•Š๋Š”๋‹ค.
4125
+ * ํŠธ์œˆ์ด ๋Œ๊ณ  ์žˆ์ง€ ์•Š์œผ๋ฉด ์„ ์–ธ์„ ๋ฌผ์„ ๊ณณ์ด ์—†์œผ๋ฏ€๋กœ ๋ฒ”์œ„๋งŒ ๋„˜๊ธด๋‹ค(๊ทธ๋•Œ๋„ ๊ฒน์น˜์ง€๋Š” ์•Š๋Š”๋‹ค).
4126
+ */
4127
+ static factScope(domainId, instanceId) {
4128
+ const inst = this.instances[(0, runtime_key_js_1.runtimeKey)(domainId, instanceId)];
4129
+ const kernel = inst?.kernel;
4130
+ if (typeof kernel?.equipmentIdentity !== 'function')
4131
+ return { scopeId: instanceId };
4132
+ return {
4133
+ scopeId: instanceId,
4134
+ identityOf: (kind, localId) => (kind === 'equipment' ? kernel.equipmentIdentity(localId) : undefined)
4135
+ };
4136
+ }
4137
+ static journalHead(domainId, instanceId) {
4138
+ const inst = this.instances[(0, runtime_key_js_1.runtimeKey)(domainId, instanceId)];
4139
+ return Number(inst?.revision ?? 0);
4140
+ }
4141
+ /**
4142
+ * ์ €๋„์— ๊ทธ๋งŒํผ ์ ์—ˆ์œผ๋‹ˆ ๋ฒˆํ˜ธ๋ฅผ ๋ฐ€์–ด ์ค€๋‹ค.
4143
+ *
4144
+ * ๋ฐ€์–ด ์ฃผ์ง€ ์•Š์œผ๋ฉด ๋‹ค์Œ์— ๋ผ์ด๋ธŒ๊ฐ€ **๊ฐ™์€ ๋ฒˆํ˜ธ๋ฅผ ๋‹ค์‹œ ์“ด๋‹ค** โ€” ๊ฐ™์€ ์‹œ๊ฐ์˜ ๋‘ ์‚ฌ์‹ค์„ ๊ฐ€๋ฆด ์ˆ˜ ์—†๊ฒŒ ๋œ๋‹ค.
4145
+ */
4146
+ static advanceJournalHead(domainId, instanceId, by) {
4147
+ const inst = this.instances[(0, runtime_key_js_1.runtimeKey)(domainId, instanceId)];
4148
+ if (!inst || !(by > 0))
4149
+ return;
4150
+ inst.revision = Number(inst.revision ?? 0) + by;
4151
+ }
4006
4152
  static recordIngestResult(domainId, instanceId, offered, rejected, nowMs = Date.now(),
4007
4153
  /**
4008
4154
  * ๋งคํ•‘์€ ํ†ต๊ณผํ–ˆ๋Š”๋ฐ **์ปค๋„์ด ๋ฐ›์ง€ ์•Š์€** ์ˆ˜(`ingestLive` ์˜ ๋ฐ˜ํ™˜๊ณผ ๊ฒฌ์ฃผ์–ด ์–ป๋Š”๋‹ค).