@things-factory/headless-twin 10.0.11 โ†’ 10.0.12

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 (125) hide show
  1. package/dist-server/engine/canonical-ingest.d.ts +25 -2
  2. package/dist-server/engine/canonical-ingest.js +48 -10
  3. package/dist-server/engine/canonical-ingest.js.map +1 -1
  4. package/dist-server/engine/declared-stimulus.d.ts +43 -0
  5. package/dist-server/engine/declared-stimulus.js +57 -0
  6. package/dist-server/engine/declared-stimulus.js.map +1 -0
  7. package/dist-server/engine/index.d.ts +2 -0
  8. package/dist-server/engine/index.js +2 -0
  9. package/dist-server/engine/index.js.map +1 -1
  10. package/dist-server/engine/kpi-fold.d.ts +12 -0
  11. package/dist-server/engine/kpi-fold.js +21 -1
  12. package/dist-server/engine/kpi-fold.js.map +1 -1
  13. package/dist-server/engine/kpi-query.d.ts +3 -3
  14. package/dist-server/engine/kpi-query.js +4 -4
  15. package/dist-server/engine/kpi-query.js.map +1 -1
  16. package/dist-server/engine/live-feed-registry.d.ts +1 -1
  17. package/dist-server/engine/live-feed-registry.js +1 -1
  18. package/dist-server/engine/live-feed-registry.js.map +1 -1
  19. package/dist-server/engine/local-declarations.d.ts +3 -6
  20. package/dist-server/engine/local-declarations.js +97 -16
  21. package/dist-server/engine/local-declarations.js.map +1 -1
  22. package/dist-server/engine/measured-yield.d.ts +42 -0
  23. package/dist-server/engine/measured-yield.js +75 -0
  24. package/dist-server/engine/measured-yield.js.map +1 -0
  25. package/dist-server/engine/operation-basis.d.ts +16 -0
  26. package/dist-server/engine/operation-basis.js +20 -2
  27. package/dist-server/engine/operation-basis.js.map +1 -1
  28. package/dist-server/engine/property-effects.js +17 -0
  29. package/dist-server/engine/property-effects.js.map +1 -1
  30. package/dist-server/engine/restart-policy.d.ts +13 -0
  31. package/dist-server/engine/restart-policy.js +52 -0
  32. package/dist-server/engine/restart-policy.js.map +1 -0
  33. package/dist-server/engine/spec-coverage.d.ts +8 -0
  34. package/dist-server/engine/spec-coverage.js +3 -1
  35. package/dist-server/engine/spec-coverage.js.map +1 -1
  36. package/dist-server/engine/twin-engine.d.ts +48 -15
  37. package/dist-server/engine/twin-engine.js +179 -39
  38. package/dist-server/engine/twin-engine.js.map +1 -1
  39. package/dist-server/index.js +1 -1
  40. package/dist-server/index.js.map +1 -1
  41. package/dist-server/service/index.d.ts +1 -1
  42. package/dist-server/service/reference/control-routing.d.ts +14 -0
  43. package/dist-server/service/reference/control-routing.js +64 -0
  44. package/dist-server/service/reference/control-routing.js.map +1 -0
  45. package/dist-server/service/reference/index.d.ts +1 -0
  46. package/dist-server/service/reference/index.js +2 -0
  47. package/dist-server/service/reference/index.js.map +1 -1
  48. package/dist-server/service/reference/reference-adapter.d.ts +67 -0
  49. package/dist-server/service/reference/reference-adapter.js +18 -0
  50. package/dist-server/service/reference/reference-adapter.js.map +1 -1
  51. package/dist-server/service/reference/reference-live.js +3 -3
  52. package/dist-server/service/reference/reference-live.js.map +1 -1
  53. package/dist-server/service/reference/reference-resolver.d.ts +3 -3
  54. package/dist-server/service/reference/reference-resolver.js +35 -18
  55. package/dist-server/service/reference/reference-resolver.js.map +1 -1
  56. package/dist-server/service/twin-audit/command-audit.d.ts +34 -0
  57. package/dist-server/service/twin-audit/command-audit.js +15 -1
  58. package/dist-server/service/twin-audit/command-audit.js.map +1 -1
  59. package/dist-server/service/twin-audit/twin-audit-event.d.ts +3 -0
  60. package/dist-server/service/twin-audit/twin-audit-event.js +10 -0
  61. package/dist-server/service/twin-audit/twin-audit-event.js.map +1 -1
  62. package/dist-server/service/twin-control/twin-control-mutation.d.ts +15 -2
  63. package/dist-server/service/twin-control/twin-control-mutation.js +85 -34
  64. package/dist-server/service/twin-control/twin-control-mutation.js.map +1 -1
  65. package/dist-server/service/twin-instance/twin-instance.d.ts +1 -1
  66. package/dist-server/service/twin-instance/twin-instance.js +2 -2
  67. package/dist-server/service/twin-instance/twin-instance.js.map +1 -1
  68. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js +2 -1
  69. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +1 -1
  70. package/dist-server/service/twin-model/twin-model-query.js +1 -1
  71. package/dist-server/service/twin-model/twin-model-query.js.map +1 -1
  72. package/package.json +3 -3
  73. package/server/engine/canonical-ingest.ts +78 -14
  74. package/server/engine/declared-stimulus.ts +66 -0
  75. package/server/engine/index.ts +2 -0
  76. package/server/engine/kpi-fold.ts +29 -1
  77. package/server/engine/kpi-query.ts +8 -8
  78. package/server/engine/live-feed-registry.ts +2 -2
  79. package/server/engine/local-declarations.ts +97 -19
  80. package/server/engine/measured-yield.ts +89 -0
  81. package/server/engine/operation-basis.ts +33 -2
  82. package/server/engine/property-effects.ts +17 -0
  83. package/server/engine/restart-policy.ts +55 -0
  84. package/server/engine/spec-coverage.ts +23 -3
  85. package/server/engine/twin-engine.ts +201 -42
  86. package/server/index.ts +1 -1
  87. package/server/service/reference/control-routing.ts +62 -0
  88. package/server/service/reference/index.ts +1 -0
  89. package/server/service/reference/reference-adapter.ts +78 -0
  90. package/server/service/reference/reference-live.ts +3 -3
  91. package/server/service/reference/reference-resolver.ts +46 -7
  92. package/server/service/twin-audit/command-audit.ts +34 -1
  93. package/server/service/twin-audit/twin-audit-event.ts +20 -0
  94. package/server/service/twin-control/twin-control-mutation.ts +75 -28
  95. package/server/service/twin-instance/twin-instance.ts +16 -10
  96. package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +2 -1
  97. package/server/service/twin-model/twin-model-query.ts +1 -1
  98. package/test/adopt-structure-live.test.ts +7 -7
  99. package/test/boot-resume.test.ts +3 -3
  100. package/test/control-capability.test.ts +103 -0
  101. package/test/declared-stimulus.test.ts +88 -0
  102. package/test/ingest-running-guard.test.ts +5 -5
  103. package/test/instance-cache-lifecycle.test.ts +1 -1
  104. package/test/kpi-baseline-db.test.ts +1 -1
  105. package/test/kpi-query-bench.test.ts +1 -1
  106. package/test/lineage-survives-restart.test.ts +3 -3
  107. package/test/live-feed-registry.test.ts +6 -6
  108. package/test/local-declarations.test.ts +108 -1
  109. package/test/measured-yield.test.ts +90 -0
  110. package/test/operation-basis.test.ts +28 -1
  111. package/test/operational-vocabulary.test.ts +108 -0
  112. package/test/operations-capability-db.test.ts +4 -4
  113. package/test/project-structure-db.test.ts +1 -1
  114. package/test/projection-reaches-screen.test.ts +1 -1
  115. package/test/property-effects.test.ts +28 -0
  116. package/test/restart-policy.test.ts +111 -0
  117. package/test/resync-origin-site.test.ts +7 -1
  118. package/test/source-outcome-audit.test.ts +104 -0
  119. package/test/structure-revision-db.test.ts +27 -27
  120. package/test/tenant-registry-db.test.ts +2 -2
  121. package/test/twin-model-item-db.test.ts +3 -3
  122. package/test/twin-model-tree-db.test.ts +7 -7
  123. package/test/twin-origin-resync.test.ts +4 -4
  124. package/test/yield-loop.test.ts +144 -0
  125. package/tsconfig.tsbuildinfo +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"kpi-fold.js","sourceRoot":"","sources":["../../server/engine/kpi-fold.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * ์—…๋ฌด KPI ํด๋“œ โ€” **์ด๋ฒคํŠธ ์ €๋„์„ ์ ‘์–ด** ์‹œ๊ฐ„์ฐฝ ์ง€ํ‘œ๋ฅผ ๋งŒ๋“ ๋‹ค(์ˆœ์ˆ˜).\n *\n * โ”€โ”€ ์™œ ํ•„์š”ํ•œ๊ฐ€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ง€๊ธˆ ํŠธ์œˆ์ด ๋‹ตํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ \"์ด ์ˆœ๊ฐ„์˜ ๊ฐ’\"(์ ์œ  92%)๊ณผ \"์ธํ”„๋ผ ๋ถ€ํ•˜\"(์ดˆ๋‹น ์ด๋ฒคํŠธ ์ˆ˜)๋ฟ์ด๋‹ค.\n * ์šด์˜์ด ๋ฌป๋Š” ๊ฒƒ์€ ๋‹ค๋ฅด๋‹ค โ€” **์ง€๋‚œ ํ•œ ์‹œ๊ฐ„์— ๋ช‡ ๊ฑด ์ฒ˜๋ฆฌํ–ˆ๋‚˜, ํ•œ ๊ฑด์— ์–ผ๋งˆ๋‚˜ ๊ฑธ๋ฆฌ๋‚˜, ์ž์›์€ ์–ผ๋งˆ๋‚˜\n * ์ผํ–ˆ๋‚˜.** ๊ทธ ๊ฐ’์ด ์—†์œผ๋ฉด AI ๋Š” \"์ ์œ  92%\" ๋Š” ๋งํ•ด๋„ \"๋ชฉํ‘œ๋ณด๋‹ค ๋‚˜์œ๊ฐ€\" ๋Š” ๋‹ตํ•  ์ˆ˜ ์—†๋‹ค.\n *\n * โ”€โ”€ ์›๋ฃŒ๋Š” ์ด๋ฏธ ์žˆ๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ €๋„(`TwinEvent`)์— `task.status`ยท`order.status`ยท`equipment.status` ์ „์ด๊ฐ€ `eventTime`(ISO)๊ณผ ํ•จ๊ป˜\n * append-only ๋กœ ์Œ“์ธ๋‹ค. ๊ทธ๋ž˜์„œ ์ƒˆ ๊ณ„์ธก์„ ์‹ฌ์„ ํ•„์š”๊ฐ€ ์—†๋‹ค โ€” **์ ‘๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.**\n * ๊ฐ™์€ ๋ชจ์–‘์˜ ์„ ๋ก€๊ฐ€ ์ด ํด๋”์— ์žˆ๋‹ค(`oee-accumulator.ts` โ€” equipment ์ „์ด๋ฅผ ์ ‘์–ด OEE ์นด์šดํ„ฐ ์ƒ์‚ฐ).\n *\n * โ”€โ”€ ์ด ํŒŒ์ผ์ด ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ยท ๋ชฉํ‘œ์™€ ๋น„๊ตํ•˜์ง€ ์•Š๋Š”๋‹ค. \"95% ๋ชฉํ‘œ ๋Œ€๋น„\" ๋Š” ๋ชฉํ‘œ๋ฅผ ์ €์žฅํ•˜๋Š” ๋ณ„๊ฐœ ์ธต(๊ฒฝ์˜ KPI)์˜ ๋ชซ์ด๊ณ ,\n * ์ด ์ธต์€ **์‚ฌ์‹ค๋งŒ** ์ƒ์‚ฐํ•œ๋‹ค. ๋‘ ์ธต์„ ์„ž์œผ๋ฉด ๋ชฉํ‘œ๋ฅผ ์ •์˜ํ•˜์ง€ ์•Š์€ ํ˜„์žฅ์€ ์‚ฌ์‹ค์กฐ์ฐจ ๋ชป ๋ณธ๋‹ค.\n * ยท ์ฒด๋ฅ˜์‹œ๊ฐ„(dwell)์€ ์•„์ง ๋‚ด์ง€ ์•Š๋Š”๋‹ค. ๋ฌผ๊ฑด์ด ๋…ธ๋“œ์— ๋จธ๋ฌธ ์‹œ๊ฐ„์€ item ๋‹จ์œ„ ์ด๋ฒคํŠธ(epcis.*)๋ฅผ\n * ์ง์ง€์–ด์•ผ ํ•˜๊ณ , ๊ทธ ์ง๋งž์ถค ๊ทœ์น™์ด ๋„๋ฉ”์ธ๋งˆ๋‹ค ๋‹ค๋ฅด๋‹ค. **์—†๋Š” ๊ฒƒ์„ 0 ์œผ๋กœ ๊พธ๋ฏธ์ง€ ์•Š๋Š”๋‹ค.**\n * ยท DBยท์ปค๋„์„ ๋ชจ๋ฅธ๋‹ค. ์ž…๋ ฅ์€ ํ‰๋ฒ”ํ•œ ๋ฐฐ์—ด์ด๊ณ  ์ถœ๋ ฅ์€ ํ‰๋ฒ”ํ•œ ๊ฐ์ฒด๋‹ค(ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ’์‹ธ๋‹ค).\n */\n\n/*\n * ์ง๋งž์ถค์€ **์ปค๋„์ด ์†Œ์œ ํ•œ๋‹ค**(`foldTaskRecords`). ์™„๋ฃŒ๋Š” ์ž‘์—…๋‹น ํ•˜๋‚˜ยท๋‚˜์ค‘ ๊ฒƒ์ด ์‚ฌ์‹ค, ์ฐฉ์ˆ˜๋Š” ์ฒ˜์Œ ๊ฒƒ,\n * ์ข…๋ฅ˜ยท์˜ค๋”๋Š” ์–ด๋А ์ „์ด์—์„œ๋“  โ€” ๊ทธ ๊ทœ์น™์€ ์ปค๋„ ์ƒํƒœ ๊ธฐ๊ณ„์—์„œ ๋‚˜์˜ค๋Š” ์ง€์‹์ด๋‹ค. ์—ฌ๊ธฐ์„œ ๋‹ค์‹œ ์ ์—ˆ๋”๋‹ˆ\n * ๊ณต์ • ํƒ€์ž„๋ผ์ธ๊ณผ **๋‹ค๋ฅธ ๋‹ต**์„ ๋ƒˆ๋‹ค(์žฌ์ „์†ก๋œ ์™„๋ฃŒ๋ฅผ ๋‘ ๊ฑด์œผ๋กœ ์„ธ์–ด ์ฒ˜๋ฆฌ๋Ÿ‰ยท์ ์œ ๊ฐ€ ๋ถ€ํ’€๋ ค์กŒ๋‹ค).\n * ์ด ํŒŒ์ผ์€ ์ด์ œ \"์ ‘ํžŒ ๊ธฐ๋ก โ†’ ์ฐฝ ์ง€ํ‘œ\" ๋งŒ ํ•œ๋‹ค.\n */\nimport {\n ENERGY_EVENT,\n attributeEnergy,\n electricityCost,\n energyIntensity,\n energyOfWindows,\n foldTaskRecords,\n activeShiftAt,\n type ElectricityCost,\n type TariffDeclaration,\n type TaskFacets,\n type WorkCalendarEntry\n} from '@operato/twin-kernel'\n\n/** ์ €๋„ ํ•œ ์ค„ โ€” ํ•„์š”ํ•œ ๊ฒƒ๋งŒ(์—”ํ‹ฐํ‹ฐยทtypeorm ๋น„์˜์กด). */\nexport interface KpiEvent {\n eventType?: string\n /** ISO ์‹œ๊ฐ. ํŒŒ์‹ฑ ๋ถˆ๊ฐ€ํ•˜๋ฉด ๊ทธ ์ค„์€ ๋ฒ„๋ฆฐ๋‹ค(์กฐ์šฉํžˆ 0 ์œผ๋กœ ์„ธ์ง€ ์•Š๋Š”๋‹ค). */\n eventTime?: string\n payload?: any\n}\n\nexport interface KpiWindow {\n /** ์ฐฝ์˜ ์‹œ์ž‘ยท๋(epoch ms). ์™„๋ฃŒ ์‹œ๊ฐ์ด ์ด ์•ˆ์— ๋“  ๊ฒƒ๋งŒ ์„ฑ๊ณผ๋กœ ์„ผ๋‹ค. */\n fromMs: number\n toMs: number\n}\n\nexport interface DurationStats {\n /** ์ง์ด ๋งž์•„ ๊ณ„์‚ฐ๋œ ๊ฑด์ˆ˜. */\n count: number\n /**\n * ํ•˜์œ„ ๊ผฌ๋ฆฌ โ€” **๋ถ„ํฌ๋ฅผ ์–‘์ชฝ์—์„œ ์ ‘์ง€ํ•˜๊ธฐ ์œ„ํ•ด** ๋‚ธ๋‹ค.\n * p50ยทp90 ๋งŒ ์žˆ์œผ๋ฉด ์•„๋ž˜์ชฝ ํผ์ง์„ ์œ„์ชฝ์—์„œ ๊ฑฐ์šธ์ฒ˜๋Ÿผ ๋ฒ ๊ปด ์“ธ ์ˆ˜๋ฐ–์— ์—†๋‹ค(๋ฐœ๋ช…). ๊ด€์ธก์ด ๋งํ•˜๊ฒŒ ํ•œ๋‹ค.\n */\n p10Ms: number\n p50Ms: number\n p90Ms: number\n avgMs: number\n}\n\n/**\n * ๊ด€์  ์ถ• โ€” **๊ฐ™์€ ์‚ฌ์‹ค์„ ๋‹ค๋ฅธ ๊ฐ์œผ๋กœ** ๋ณธ๋‹ค.\n *\n * ๊ณ ์ •๋œ ํ•œ ๋ Œ์ฆˆ(์ž์›๋ณ„)๋งŒ ๋‚ผ ์ˆ˜ ์žˆ์œผ๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ \"๊ตฌ์—ญ๋ณ„๋กœ๋Š”?\" ์ด๋ผ๊ณ  ๋ฌผ์–ด๋„ ๋‹ต์ด ์—†๋‹ค. ์‚ฌ์‹ค ๊ณ„์‚ฐ์ด\n * ์ถ•์„ ๋ชป ๋‚ด๋ฉด AI ๋„ ๋ชป ๋‚ธ๋‹ค โ€” ๊ทธ๋ž˜์„œ ์ถ•์€ ๊ณ„์‚ฐ ์ธต์˜ ๋Šฅ๋ ฅ์ด์–ด์•ผ ํ•œ๋‹ค.\n *\n * resource ์ž์›๋ณ„(๋ˆ„๊ฐ€ ํ–ˆ๋‚˜) taskKind ์ž‘์—… ์ข…๋ฅ˜๋ณ„(๋ฌด์—‡์„ ํ–ˆ๋‚˜)\n * location ๋„์ฐฉ ์ง€์ ๋ณ„(์–ด๋””์„œ) order ์˜ค๋”๋ณ„(๋ฌด์—‡์„ ์œ„ํ•ด)\n * area ๊ตฌ์—ญ๋ณ„ โ€” ๋…ธ๋“œโ†’๊ตฌ์—ญ ์ง€๋„๊ฐ€ ํ•„์š”ํ•˜๋‹ค(์ด๋ฒคํŠธ์— ์—†๋‹ค. ํ˜ธ์ถœ๋ถ€๊ฐ€ ์ค€๋‹ค)\n * shift ๊ต๋Œ€๋ณ„(์–ธ์ œ) โ€” ์™„๋ฃŒ ์‹œ๊ฐ + ํ˜„์žฅ์˜ ์‹œ๊ฐ ๊ธฐ์ค€์—์„œ **๊ณ„์‚ฐํ•œ๋‹ค**(์ด๋ฒคํŠธ์— ์—†๋‹ค)\n */\nexport type KpiGroupBy = 'resource' | 'taskKind' | 'location' | 'order' | 'area' | 'shift'\n\nexport interface KpiGroup {\n /** ์ถ•์˜ ๊ฐ’(์ž์› idยท์ž‘์—… ์ข…๋ฅ˜ยท๋…ธ๋“œ idยท์˜ค๋” idยท๊ตฌ์—ญ id). ๊ฐ’์ด ์—†๋˜ ๊ธฐ๋ก์€ 'unknown'. */\n key: string\n /** ์ด ์ถ•์—์„œ ์™„๋ฃŒ๋œ ๊ฑด์ˆ˜. */\n tasks: number\n leadTime: DurationStats\n workTime: DurationStats\n waitTime: DurationStats\n /** ์ด ์ถ•์— ๋ถ™์–ด ์žˆ๋˜ ์‹œ๊ฐ„์˜ ํ•ฉ(์ž์› ์ถ•์—์„œ ํŠนํžˆ ์˜๋ฏธ ์žˆ๋‹ค). */\n busyMs: number\n}\n\nexport interface KpiResult {\n window: { fromMs: number; toMs: number }\n /** ์ฐฝ ์•ˆ์— **์™„๋ฃŒ๋œ** ๊ฑด์ˆ˜ โ€” ์„ฑ๊ณผ๋Š” ์™„๋ฃŒ ์‹œ์ ์œผ๋กœ ์„ผ๋‹ค(์‹œ์ž‘ ์‹œ์ ์œผ๋กœ ์„ธ๋ฉด ์ง„ํ–‰ ์ค‘์ธ ๊ฒƒ์ด ์„ž์ธ๋‹ค). */\n throughput: { tasks: number; orders: number }\n /**\n * ์—๋„ˆ์ง€ โ€” **์ด ์ฐฝ์˜ ์ „๋ ฅ๋Ÿ‰๊ณผ ์›๋‹จ์œ„.** ์—๋„ˆ์ง€ ํŠธ์œˆ์ด ์—†์œผ๋ฉด `undefined`(0 ์ด ์•„๋‹ˆ๋‹ค).\n *\n * โ”€โ”€ ์™œ KPI ํด๋“œ ์•ˆ์— ์žˆ๋‚˜ (2026-08-14, ยง10 7๋‹จ๊ณ„) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์›๋‹จ์œ„๋Š” ๋ถ„์ž(์ „๋ ฅ๋Ÿ‰)์™€ ๋ถ„๋ชจ(์‚ฐ์ถœ)๋ฅผ **๊ฐ™์€ ์ฐฝ**์—์„œ ๋‚˜๋ˆˆ ๊ฐ’์ด๋‹ค. ์งˆ์˜๋ฅผ ๋”ฐ๋กœ ๋‘๋ฉด ๋‘ ์ฐฝ์„ ๋งž์ถ”๋Š”\n * ์ผ์ด ์†Œ๋น„์ฒ˜์˜ ๋ชซ์ด ๋˜๊ณ , ์–ด๊ธ‹๋‚œ ๋‘ ์‚ฌ์‹ค์„ ๋‚˜๋ˆˆ ์ˆซ์ž๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋œปํ•˜์ง€ ์•Š๋Š”๋‹ค(์ปค๋„์˜ ๊ทœ์น™์ด ๊ทธ๊ฒƒ์„\n * ๊ฑฐ์ ˆํ•œ๋‹ค). ๊ฐ™์€ ํด๋“œ ์•ˆ์— ๋‘๋ฉด ์ฐฝ์ด ํ•˜๋‚˜๋ฟ์ด๋ผ ์–ด๊ธ‹๋‚  ์ˆ˜ ์—†๋‹ค.\n *\n * ๋ถ„์ž๋Š” **์ €๋„์˜ ๊ตฌ๊ฐ„ ๋งˆ๊ฐ ์‚ฌ๊ฑด**์—์„œ ์˜จ๋‹ค(`energy.demand.window`) โ€” ์ปค๋„ ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๋ผ ์ €๋„์ด๋ฏ€๋กœ\n * ๋ฉˆ์ถ˜ ํŠธ์œˆยท๊ณผ๊ฑฐ ๊ตฌ๊ฐ„์—๋„ ๋‹ตํ•  ์ˆ˜ ์žˆ๋‹ค.\n */\n energy?: {\n /** ์ด ์ฐฝ์˜ ์ „๋ ฅ๋Ÿ‰. ์…€ ์ˆ˜ ์žˆ๋Š” ๊ตฌ๊ฐ„์ด ์—†์œผ๋ฉด `undefined`. */\n kWh?: number\n /**\n * ์ด ์ฐฝ์˜ **์ตœ๋Œ€์ˆ˜์š”**(kW)์™€ ๊ทธ๊ฒƒ์ด ๋‚œ ๊ตฌ๊ฐ„์˜ ์‹œ์ž‘.\n *\n * ์ „๋ ฅ๋Ÿ‰๊ณผ ๋‹ค๋ฅธ ์งˆ๋ฌธ์ด๋‹ค: ์ „๋ ฅ๋Ÿ‰์€ ์š”๊ธˆ์˜ ์‚ฌ์šฉ๋Ÿ‰ ๋ถ€๋ถ„์ด๊ณ , ์ตœ๋Œ€์ˆ˜์š”๋Š” **๊ธฐ๋ณธ์š”๊ธˆ**๊ณผ ๊ณ„์•ฝ ์œ„๋ฐ˜์„\n * ์ •ํ•œ๋‹ค. ํ‰๊ท ์œผ๋กœ ๊ฐˆ์Œํ•  ์ˆ˜ ์—†์–ด์„œ ์ปค๋„์ด ๊ตฌ๊ฐ„์˜ ์ตœ๋Œ€๋“ค ์ค‘ ๊ฐ€์žฅ ํฐ ๊ฐ’์„ ๋”ฐ๋กœ ๋‚ธ๋‹ค.\n */\n peakKW?: number\n peakStartMs?: number\n /**\n * ๊ทธ ํ”ผํฌ ๊ตฌ๊ฐ„์—์„œ **์„ค๋น„๊ฐ€ ๋Œ์–ด๋‹น๊ธด** ์ตœ๋Œ€(๋ฐœ์ „ยท๋ฐฉ์ „ ์ฐจ๊ฐ ์ „)์™€ ๊ทธ ์ฐจ์ด(๊นŽ์ธ ์–‘).\n *\n * ์š”๊ธˆ์€ ๊ณ„ํ†ต ์ˆ˜์š”(`peakKW`)๋กœ ๋งค๊ฒจ์ง€์ง€๋งŒ, ใ€Œ๋ฌด์—‡์ด ๊ทธ ์ˆ˜์š”๋ฅผ ๋งŒ๋“ค์—ˆ๋‚˜ใ€์™€ ใ€Œ๋ฌด์—‡์ด ๋œ์–ด๋ƒˆ๋‚˜ใ€๋Š”\n * ์ด ๋‘ ์ˆ˜์˜ ๊ฐ„๊ฒฉ์ด ๋‹ตํ•œ๋‹ค. ๋ฐœ์ „ยท์ถ•์ „์„ ์„ ์–ธํ•˜์ง€ ์•Š์€ ํ˜„์žฅ์—์„œ๋Š” ์—†๋‹ค(์ฐจ๊ฐํ•  ๊ฒƒ์ด ์—†๋‹ค).\n */\n peakGrossKW?: number\n shavedKW?: number\n /** ํŒŒ์ƒ์˜ ๊ทผ๊ฑฐ โ€” ๊ตฌ๊ฐ„ ํ‰๊ท ๋ถ€ํ•˜ ร— ๊ธธ์ด(`mean-kw`). */\n basis: string\n /** ์„ผ ๊ตฌ๊ฐ„ ์ˆ˜ ยท ๋ชป ์„ผ ๊ตฌ๊ฐ„ ์ˆ˜(๊ณ„์ธก์ด ๋Š๊ธด ๊ตฌ๊ฐ„) โ€” ์กฐ์šฉํžˆ ์ž๋ฅด์ง€ ์•Š๋Š”๋‹ค. */\n counted: number\n skipped: number\n /** ์™„๋ฃŒ ์˜ค๋”๋‹น ์ „๋ ฅ๋Ÿ‰ โ€” ๋‹ตํ•  ์ˆ˜ ์—†์œผ๋ฉด `null` ๊ณผ ์ด์œ . */\n intensity: { value: number | null; unit?: string; reason?: string }\n /**\n * ๋ฐฐ์ „ ๊ณ„ํ†ต์˜ **์ž๋ฆฌ๋ณ„ ๋ชซ** โ€” ใ€Œ์ด ๋ถ„๊ธฐ๊ฐ€ ์–ผ๋งˆ ์ผ๋‚˜ใ€.\n *\n * โ”€โ”€ ์ด๊ฒƒ์€ ์ธก์ •์ด ์•„๋‹ˆ๋ผ ๋ฐฐ๋ถ„์ด๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ €๋„์— ์žˆ๋Š” ์—๋„ˆ์ง€ ์‚ฌ์‹ค์€ **ํ˜„์žฅ ์ด๋Ÿ‰ ํ•œ ์ค„**์ด๋‹ค(๋ฟŒ๋ฆฌ ๊ณ„๋Ÿ‰๊ธฐ ํ•ฉ). ๊ณ„๋Ÿ‰๊ธฐ๋ณ„ ๊ตฌ๊ฐ„ ์‚ฌ์‹ค์ด ์—†์œผ๋ฏ€๋กœ\n * ์ž๋ฆฌ๋ณ„ ๋ชซ์€ **๋‚˜๋ˆˆ ๊ฒƒ**์ด๊ณ , ๋ฌด์—‡์œผ๋กœ ๋‚˜๋ˆด๋Š”์ง€(`weightKind`)๋ฅผ ๊ฐ’๊ณผ ํ•จ๊ป˜ ๋‚ธ๋‹ค. ๊ทผ๊ฑฐ๋ฅผ ๊ฐ์ถ”๋ฉด\n * ๋‚˜๋ˆˆ ์ˆซ์ž๊ฐ€ ์žฐ ์ˆซ์ž์™€ ๊ฐ™์€ ๋ฌด๊ฒŒ๋กœ ์ฝํžŒ๋‹ค โ€” CBAMยทESG ๋ณด๊ณ ์—์„œ ์ฒซ ์งˆ๋ฌธ์— ๊นจ์ง€๋Š” ์ง€์ ์ด๋‹ค.\n *\n * ๊ฐ€์ค‘์น˜๋Š” **์ž‘์—… ๊ฐ€๋™์‹œ๊ฐ„**์ด๋‹ค. ์ •๊ฒฉ(kW)์œผ๋กœ ๋‚˜๋ˆ„์ง€ ์•Š๋Š”๋‹ค: ์‹œ๋ฎฌ ํŠธ์œˆ์˜ ์ด๋ถ€ํ•˜๊ฐ€ ์ •๊ฒฉ์˜ ํ•ฉ์œผ๋กœ\n * ํŒŒ์ƒ๋˜๋ฏ€๋กœ, ๊ทธ ์ด๋Ÿ‰์„ ๋‹ค์‹œ ์ •๊ฒฉ์œผ๋กœ ๋‚˜๋ˆ„๋ฉด ๋„ฃ์€ ๊ฐ’์ด ๊ทธ๋Œ€๋กœ ๋‚˜์˜ค๋Š” ๋™์–ด๋ฐ˜๋ณต์ด ๋œ๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ ์ด ๊ฐ’์—๋Š” **๊ฐ€์ •์ด ํ•˜๋‚˜ ์‹ค๋ ค ์žˆ๋‹ค**: ์ „๊ธฐ๊ฐ€ ๊ฐ€๋™์‹œ๊ฐ„์— ๋น„๋ก€ํ•œ๋‹ค. ๊ณต์กฐยท์กฐ๋ช…์ฒ˜๋Ÿผ ๊ณต์ •์—\n * ๋ถ™์ง€ ์•Š๋Š” ๋ถ€ํ•˜๋„ ๊ทธ ๋น„์œจ์— ์„ž์ธ๋‹ค โ€” ํ™”๋ฉด์ด ๊ทธ ๋ฌธ์žฅ์„ ํ•จ๊ป˜ ๋งํ•ด์•ผ ํ•œ๋‹ค.\n */\n byFeeder?: {\n /** ์ž๋ฆฌ(๋ถ„๊ธฐยท์ˆ˜์ „) id. ์ž๋ฆฌ๋ฅผ ๋ชจ๋ฅด๋Š” ์ž์›์€ `unknown` ์œผ๋กœ ๋ชจ์ธ๋‹ค(์กฐ์šฉํžˆ ๋ฒ„๋ฆฌ์ง€ ์•Š๋Š”๋‹ค). */\n key: string\n kWh: number\n /**\n * ์ด ๋ชซ์˜ ๊ทผ๊ฑฐ โ€” **์ปค๋„์ด ์ •ํ•œ๋‹ค.**\n *\n * ์„ ์–ธ๋œ ๋ถ€ํ•˜๊ฐ€ ์—ฌ๋Ÿฟ์ด๋ฉด ๋ฐฐ๋ถ„(`apportioned`)์ด๋‹ค. ์„ ์–ธ๋œ ๋ถ€ํ•˜๊ฐ€ **ํ•˜๋‚˜๋ฟ์ธ** ํ˜„์žฅ์—์„œ๋Š” ์ปค๋„์ด\n * ใ€Œ๊ทธ ๊ณ„๋Ÿ‰๊ธฐ๋Š” ๊ทธ๊ฒƒ๋งŒ ์žฐ๋‹คใ€๊ณ  ์ฝ์–ด `measured` ๋ฅผ ๋‚ธ๋‹ค โ€” ๋ชจ๋ธ์ด ๊ทธ๋ ‡๊ฒŒ ๋งํ–ˆ์œผ๋ฏ€๋กœ ๊ทธ๊ฒƒ๋„ ์‚ฌ์‹ค์ด๋‹ค.\n * ์šฐ๋ฆฌ๊ฐ€ ์–ด๋А ์ชฝ์œผ๋กœ๋„ ๋‚™์ธ์ฐ์ง€ ์•Š๋Š”๋‹ค.\n */\n basis: 'apportioned' | 'measured'\n /**\n * ๋ฌด์—‡์œผ๋กœ ๋‚˜๋ˆด๋‚˜ โ€” **๋ฐฐ๋ถ„์ผ ๋•Œ๋งŒ** ์žˆ๋‹ค.\n *\n * ๋ถ„๊ธฐ๋งˆ๋‹ค ๊ณ„๋Ÿ‰๊ธฐ๊ฐ€ ์žˆ๋Š” ํ˜„์žฅ์—์„œ๋Š” ๋‚˜๋ˆ„์ง€ ์•Š๋Š”๋‹ค(๊ทธ ๊ฐ’์ด ๊ณง ๊ณ„๋Ÿ‰์ด๋‹ค). ๊ทธ๋•Œ ์ด ์นธ์„\n * `runtimeMs` ๋กœ ์ฑ„์šฐ๋ฉด ใ€Œ๊ฐ€๋™์‹œ๊ฐ„์œผ๋กœ ๋‚˜๋ˆด๋‹คใ€๋Š” ์—†๋Š” ์‚ฌ์‹ค์„ ๋งํ•˜๊ฒŒ ๋œ๋‹ค.\n */\n weightKind?: 'runtimeMs'\n /** ์ด ์ž๋ฆฌ์˜ ๋ชซ์ด ์ „์ฒด์˜ ์–ผ๋งˆ์˜€๋‚˜ โ€” ๋ฐฐ๋ถ„์ผ ๋•Œ๋งŒ. */\n weightShare?: number\n /**\n * **ํ”ผํฌ๊ฐ€ ์ฐํžŒ ์ˆœ๊ฐ„** ์ด ๋ถ„๊ธฐ๊ฐ€ ์–ผ๋งˆ์˜€๋‚˜(kW) โ€” ์š”๊ธˆ์ด ๊ฑธ๋ฆฐ ์ˆ˜๋‹ค.\n *\n * ์ฐฝ์˜ ํ‰๊ท ์ด๋‚˜ ํ•ฉ์ด ์•„๋‹ˆ๋‹ค: ์ตœ๋Œ€์ˆ˜์š”๋ฅผ ๋‚ธ ๊ตฌ๊ฐ„์˜ ๊ทธ ์ˆœ๊ฐ„ ๊ฐ’์ด๋‹ค(๋‹ค๋ฅธ ์ˆœ๊ฐ„์„ ์„ž์œผ๋ฉด ใ€Œ์–ด๋А ๋ถ„๊ธฐ๋ฅผ\n * ๊นŽ์•„์•ผ ํ”ผํฌ๊ฐ€ ๋‚ด๋ ค๊ฐ€๋‚˜ใ€์˜ ๋‹ต์ด ํ๋ ค์ง„๋‹ค). ๊ทธ ๊ตฌ๊ฐ„์— ์ด ๋ถ„๊ธฐ์˜ ํ‘œ๋ณธ์ด ์—†์—ˆ์œผ๋ฉด **์—†๋‹ค**.\n */\n peakKW?: number\n }[]\n /**\n * ๋‚˜๋ˆ„์ง€ ๋ชปํ•œ ์–‘๊ณผ ๊ทธ ์ด์œ  โ€” **์กฐ์šฉํžˆ 0 ์œผ๋กœ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค.**\n * `no-weights` = ๊ทธ ์ฐฝ์— ๋Œ์•„๊ฐ„ ์ž์›์ด ์—†๋‹ค(๊ฐ€๋™์‹œ๊ฐ„์ด ์ „๋ถ€ 0). ๊ทธ๋Ÿฌ๋ฉด ์ด๋Ÿ‰์€ ๊ทธ๋Œ€๋กœ ๋‚จ๋Š”๋‹ค.\n */\n unattributedKWh?: number\n /**\n * ์™œ ๋‚˜๋ˆ„์ง€ ๋ชปํ–ˆ๋‚˜(์ปค๋„ ์ฝ”๋“œ) โ€” `no-weights`(๊ฐ€๋™์‹œ๊ฐ„์ด ์ „๋ถ€ 0) ยท `no-consumers`(๋ฎ๋Š” ๋Œ€์ƒ ๋ฏธ์„ ์–ธ) ยท\n * `not-submetered`(๋ฟŒ๋ฆฌ์—์„œ ์žฌ์—ˆ์œผ๋‚˜ ํ•˜์œ„ ๊ณ„๋Ÿ‰์ด ๋ฎ์ง€ ์•Š๋Š” ๋ถ€๋ถ„ โ€” ๊ฒฐ์†์ด ์•„๋‹ˆ๋ผ ๊ณ„๋Ÿ‰ ๋ฒ”์œ„์˜ ์‚ฌ์‹ค).\n */\n unattributedReason?: string\n /**\n * ๋ถ„๊ธฐ ๊ณ„๋Ÿ‰์˜ ํ•ฉ์ด ๋ฟŒ๋ฆฌ ๊ณ„๋Ÿ‰๋ณด๋‹ค **ํฐ** ์–‘ โ€” ๋‘ ๊ณ„๋Ÿ‰๊ธฐ์˜ ํšŒ๊ณ„๊ฐ€ ๋‹ค๋ฅด๋‹ค๋Š” ์‚ฌ์‹ค์ด๋‹ค.\n *\n * ๊ฐ’์„ ๊นŽ์•„ ๋งž์ถ”์ง€ ์•Š๋Š”๋‹ค: ๊ทธ๊ฒƒ์€ ๊ณ„๋Ÿ‰์„ ์šฐ๋ฆฌ๊ฐ€ ๊ณ ์ณ ์“ฐ๋Š” ์ผ์ด๊ณ , ์–ด๋А ์ชฝ์ด ๋งž๋Š”์ง€๋Š” ํ˜„์žฅ์ด ์•ˆ๋‹ค.\n */\n submeterExcessKWh?: number\n /**\n * ๋ฐฐ๋ถ„์—์„œ **๋น ์ง„ ์ž์› ์ˆ˜** โ€” ๊ทธ ์ฐฝ์— ๊ฐ€๋™ ๊ธฐ๋ก์ด ์—†๋Š” ์„ค๋น„๋‹ค. 0kWh ๋ฅผ ์ฃผ์ง€ ์•Š๋Š” ๋Œ€์‹  ๋ช‡ ๋Œ€๊ฐ€\n * ๋น ์กŒ๋Š”์ง€ ์„ผ๋‹ค(๋Œ€๊ธฐ์ „๋ ฅ์ด ์žˆ๋Š” ์„ค๋น„์—์„œ 0 ์€ ๊ณง ๊ฑฐ์ง“์ด๋‹ค).\n */\n excludedResources?: number\n /**\n * ์ด ์ฐฝ์˜ ์ „๊ธฐ์š”๊ธˆ โ€” **์ฒญ๊ตฌ์„œ๊ฐ€ ์•„๋‹ˆ๋‹ค.** ๊ณ„์‚ฐ๊ณผ ๊ทธ ํ•œ๊ณ„(TOUยท๋ž˜์นซยท์ตœ์†Œ์ฒญ๊ตฌ์•ก ๋ฏธ๋ชจ๋ธ)๋Š” ์ปค๋„\n * (`electricityCost`)์ด ๊ฐ–๊ณ  ์—ฌ๊ธฐ์„œ๋Š” ๋‚˜๋ฅธ๋‹ค. ๋‹จ๊ฐ€๊ฐ€ ์—†์œผ๋ฉด `reason: 'no-tariff'` ๋กœ ์˜จ๋‹ค.\n */\n cost?: ElectricityCost\n }\n /** ๋ฆฌ๋“œํƒ€์ž„ โ€” ์ƒ์„ฑ(created)์—์„œ ์™„๋ฃŒ๊นŒ์ง€. ์‚ฌ์šฉ์ž๊ฐ€ ์ฒด๊ฐํ•˜๋Š” ์†Œ์š” ์‹œ๊ฐ„. */\n leadTime: DurationStats\n /** ์ž‘์—…์‹œ๊ฐ„ โ€” ์ฐฉ์ˆ˜(in-progress)์—์„œ ์™„๋ฃŒ๊นŒ์ง€. ๋Œ€๊ธฐ๋ฅผ ๋บ€ ์‹ค์ž‘์—…. */\n workTime: DurationStats\n /** ๋Œ€๊ธฐ์‹œ๊ฐ„ โ€” ์ƒ์„ฑ์—์„œ ์ฐฉ์ˆ˜๊นŒ์ง€. ์ž์›์ด ๋ถ€์กฑํ•˜๋ฉด ์—ฌ๊ธฐ๊ฐ€ ๋Š˜์–ด๋‚œ๋‹ค. */\n waitTime: DurationStats\n /** ์ž์›๋ณ„ ์ ์œ  โ€” ์ž‘์—…์— ๋ถ™์–ด ์žˆ๋˜ ์‹œ๊ฐ„์˜ ํ•ฉ๊ณผ ์ฐฝ ๋Œ€๋น„ ๋น„์œจ(์ž‘์—…์œผ๋กœ ์„ค๋ช…๋˜๋Š” ๋ถ€๋ถ„๋งŒ). */\n utilization: { resourceId: string; busyMs: number; ratio: number }[]\n /**\n * **์…ˆ์—์„œ ๋น ์ง„ ๊ฒƒ** โ€” ์™„๋ฃŒ๋Š” ์ฐฝ ์•ˆ์ด์ง€๋งŒ ์‹œ์ž‘ ์ด๋ฒคํŠธ๋ฅผ ๋ชป ์ฐพ์€ ๊ฑด์ˆ˜.\n * ์กฐํšŒ ๊ตฌ๊ฐ„์ด ์งง์•„ ์‹œ์ž‘์ด ์ž˜๋ ธ๊ฑฐ๋‚˜ ์ €๋„์ด ์œ ์‹ค๋œ ๊ฒฝ์šฐ๋‹ค. ์ด ๊ฐ’์„ ์ˆจ๊ธฐ๋ฉด ํ‰๊ท ์ด ์กฐ์šฉํžˆ ๊ฑฐ์ง“์ด ๋œ๋‹ค.\n */\n unpaired: { leadTime: number; workTime: number }\n /**\n * ์†Œ๋น„ํ•œ ์ด๋ฒคํŠธ ์ˆ˜ โ€” **๋„˜๊ฒจ๋ฐ›์€ ๋ฐฐ์—ด ์ „์ฒด**(์ฐฝ ์•ž lookback ํฌํ•จ). ์ง„๋‹จ์šฉ์ด๋‹ค.\n *\n * \"์ธก์ •๋œ ๊ธฐ๋ก์ด ์žˆ๋Š”๊ฐ€\" ์˜ ํŒ๋‹จ์—๋Š” ์“ฐ์ง€ ๋ง ๊ฒƒ โ€” ํ˜ธ์ถœ๋ถ€๋Š” ์ฐฝ๋ณด๋‹ค ์•ž๊นŒ์ง€ ์ฝ์–ด ๋„˜๊ธฐ๋ฏ€๋กœ(์™„๋ฃŒ๋œ ์ž‘์—…์˜\n * ์‹œ์ž‘์ด ์ฐฝ ๋ฐ–์ผ ์ˆ˜ ์žˆ๋‹ค) ์ฐฝ ์•ˆ์ด ๋น„์–ด ์žˆ์–ด๋„ ์ด ๊ฐ’์€ 0 ์ด ์•„๋‹ˆ๋‹ค. ๊ทธ ํŒ๋‹จ์€ `eventsInWindow` ๋กœ ํ•œ๋‹ค.\n */\n eventsSeen: number\n /**\n * **์ฐฝ ์•ˆ์—** ๋“ค์–ด์˜จ ์ด๋ฒคํŠธ ์ˆ˜ โ€” \"์ด ๊ตฌ๊ฐ„์— ์ธก์ •ํ•  ๊ธฐ๋ก์ด ์žˆ์—ˆ๋Š”๊ฐ€\" ์˜ ์ •๋‹ต.\n *\n * ์ด๊ฒƒ์ด 0 ์ด๋ฉด \"์ฒ˜๋ฆฌ๋Ÿ‰ 0\" ์ด ์•„๋‹ˆ๋ผ **\"๊ธฐ๋ก์ด ์—†๋‹ค\"** ๋‹ค. ๋‘ ์ƒํ™ฉ์„ ์„ž์œผ๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์ž˜๋ชป๋œ ๊ฒฐ๋ก ์„\n * ๋‚ธ๋‹ค(์•ž ๊ตฌ๊ฐ„์˜ ๊ธฐ๋ก๋งŒ ์ฝ์–ด ๋†“๊ณ  \"0๊ฑด ์ฒ˜๋ฆฌ\" ๋ผ๊ณ  ๋งํ•˜๋Š” ์ผ์ด ์‹ค์ œ๋กœ ๊ฐ€๋Šฅํ–ˆ๋‹ค).\n */\n eventsInWindow: number\n /** ์š”์ฒญํ•œ ๊ด€์ ์œผ๋กœ ์ชผ๊ฐ  ๊ฐ’(์š”์ฒญํ–ˆ์„ ๋•Œ๋งŒ). */\n groups?: { by: KpiGroupBy; items: KpiGroup[]; truncated?: number; truncatedTasks?: number }\n}\n\n/**\n * ์ฐฝ์˜ ์ „๋ ฅ๋Ÿ‰์„ **๋ฐฐ์ „ ๊ณ„ํ†ต์˜ ์ž๋ฆฌ๋ณ„๋กœ ๋‚˜๋ˆˆ๋‹ค** โ€” ๊ทผ๊ฑฐ๋ฅผ ํ•จ๊ป˜.\n *\n * โ”€โ”€ ์™œ ์ปค๋„ ํ•จ์ˆ˜๋ฅผ ์“ฐ๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ใ€Œ๋‚˜๋ˆŒ ๊ทผ๊ฑฐ๊ฐ€ ์—†์œผ๋ฉด ๋‚˜๋ˆ„์ง€ ์•Š๋Š”๋‹คใ€ยทใ€Œํ•ฉ์€ ๋ณด์กด๋œ๋‹คใ€ยทใ€Œ๋ชซ์ด 0 ์ด๋ฉด 0kWh ๋ฅผ ์ฃผ์ง€ ์•Š๋Š”๋‹คใ€๋Š” ๊ทœ์น™์ด\n * ์ปค๋„์˜ `attributeEnergy` ์— ์ด๋ฏธ ์žˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๋‹ค์‹œ ์“ฐ๋ฉด ๋‘ ๋ฒŒ์ด ๋˜๊ณ , ๊ทธ๋•Œ๋ถ€ํ„ฐ ๋‘ ํ™”๋ฉด์ด ๋‹ค๋ฅธ ํ•ฉ์„\n * ๋งํ•œ๋‹ค. ์ด ํ•จ์ˆ˜๊ฐ€ ํ•˜๋Š” ์ผ์€ **์žฌ๋ฃŒ๋ฅผ ๋ชจ์•„ ๋„˜๊ธฐ๊ณ  ๋‹ต์„ ์ž๋ฆฌ๋ณ„๋กœ ๋ฌถ๋Š” ๊ฒƒ**๋ฟ์ด๋‹ค.\n *\n * โ”€โ”€ ๊ฐ€์ค‘์น˜๋Š” ๊ฐ€๋™์‹œ๊ฐ„์ด๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ •๊ฒฉ(kW)์œผ๋กœ ๋‚˜๋ˆ„์ง€ ์•Š๋Š”๋‹ค: ์‹œ๋ฎฌ ํŠธ์œˆ์˜ ์ด๋ถ€ํ•˜๊ฐ€ ์ •๊ฒฉ์˜ ํ•ฉ์—์„œ ํŒŒ์ƒ๋˜๋ฏ€๋กœ ๊ทธ ์ด๋Ÿ‰์„ ๋‹ค์‹œ ์ •๊ฒฉ์œผ๋กœ\n * ๋‚˜๋ˆ„๋ฉด ๋„ฃ์€ ๊ฐ’์ด ๊ทธ๋Œ€๋กœ ๋‚˜์˜จ๋‹ค(์ƒˆ ์ •๋ณด 0์˜ ๋™์–ด๋ฐ˜๋ณต). ๊ฐ€๋™์‹œ๊ฐ„์€ **์ €๋„์ด ๊ด€์ธกํ•œ ์‚ฌ์‹ค**์ด๋‹ค.\n *\n * ์ž๋ฆฌ๋ฅผ ๋ชจ๋ฅด๋Š” ์ž์›์€ `unknown` ์œผ๋กœ ๋ชจ์ธ๋‹ค โ€” ๋นผ๋ฉด ํ•ฉ์ด ์ค„๊ณ , ์•„๋ฌด ์ž๋ฆฌ์— ๋„ฃ์œผ๋ฉด ๊ฑฐ์ง“์ด ๋œ๋‹ค.\n */\nfunction feederShares(\n kWh: number | undefined,\n utilization: { resourceId: string; busyMs: number }[],\n resourceFeeder?: Record<string, string>\n): Partial<NonNullable<KpiResult['energy']>> {\n /* ์„ ์–ธ์ด ์—†์œผ๋ฉด ๋ถ„ํ•ดํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” ์ž๋ฆฌ๋ฅผ ๋ชจ๋ฅด๋Š” ์ฑ„ ๋‚˜๋ˆˆ ์ˆซ์ž๋Š” ์•„๋ฌด ๊ฒƒ์˜ ๋ชซ๋„ ์•„๋‹ˆ๋‹ค. */\n if (!resourceFeeder || !Object.keys(resourceFeeder).length) return {}\n if (kWh === undefined || !(kWh > 0)) return {}\n\n /*\n * โ”€โ”€ ํ’€์ด **๋ฌด์—‡์„ ๋ฎ๋Š”์ง€ ์‚ฌ์‹ค๋Œ€๋กœ** ๋งํ•œ๋‹ค (2026-08-17) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n *\n * ์ฒ˜์Œ์—๋Š” ใ€Œ๊ทธ ์ฐฝ์— ๋Œ์•„๊ฐ„ ์ž์›ใ€๋งŒ ๋ฎ๋Š”๋‹ค๊ณ  ๋„˜๊ฒผ๋‹ค. ๊ทธ๋Ÿฌ์ž ๋Œ์•„๊ฐ„ ์ž์›์ด ํ•˜๋‚˜์ธ ์ฐฝ์—์„œ ์ปค๋„์ด\n * ๊ทธ๊ฒƒ์„ **`measured`(์ „์šฉ ๊ณ„๋Ÿ‰)** ๋กœ ํŒ์ •ํ–ˆ๋‹ค โ€” ์ปค๋„์˜ ๊ทœ์น™์€ ์˜ณ๋‹ค(ใ€Œ๋ฎ๋Š” ์†Œ๋น„์ฒ˜๊ฐ€ ํ•˜๋‚˜๋ฉด ๊ทธ\n * ๊ณ„๋Ÿ‰๊ธฐ๋Š” ๊ทธ๊ฒƒ๋งŒ ์žฐ๋‹ค๋Š” ์„ ์–ธ์ด๋‹คใ€). ํ‹€๋ฆฐ ๊ฒƒ์€ ๋‚ด ์„ ์–ธ์ด์—ˆ๋‹ค: ํ˜„์žฅ ๊ณ„๋Ÿ‰๊ธฐ๋Š” ๋Œ์•„๊ฐ„ ๊ฒƒ๋งŒ ์žฌ์ง€ ์•Š๋Š”๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ **์„ ์–ธ๋œ ๋ถ€ํ•˜ ์ „๋ถ€**๋ฅผ ๋ฎ๋Š”๋‹ค๊ณ  ๋งํ•œ๋‹ค(`resourceFeeder` ์˜ ํ‚ค๊ฐ€ ๊ณง ๊ทธ ์„ ์–ธ์ด๋‹ค).\n * ๊ทธ๋Ÿฌ๋ฉด ๊ทธ ์ฐฝ์— ๋Œ์ง€ ์•Š์€ ์„ค๋น„๋Š” ๋ชซ 0 ์œผ๋กœ **๋ฐฐ๋ถ„์—์„œ ๋น ์ง€๊ณ  ๊ทธ ์ˆ˜๊ฐ€ ๋ณด๊ณ ๋œ๋‹ค** โ€” 0kWh ๋ฅผ ์ฃผ๋Š”\n * ๋Œ€์‹  ใ€Œ์ด ์„ค๋น„๋Š” ์ด ์ฐฝ์— ๊ฐ€๋™ ๊ธฐ๋ก์ด ์—†๋‹คใ€๋ฅผ ๋งํ•˜๋Š” ์ชฝ์ด๋‹ค.\n */\n /*\n * ๋ฎ๋Š” ๋Œ€์ƒ์€ **์„ ์–ธ๋œ ๋ถ€ํ•˜ โˆช ๊ทธ ์ฐฝ์— ๋Œ์•„๊ฐ„ ์ž์›**์ด๋‹ค.\n *\n * ์„ ์–ธ๋งŒ ์“ฐ๋ฉด, ๋Œ์•˜๋Š”๋ฐ ์ „๊ธฐ ๊ณ„ํ†ต์— ์„ ์–ธ๋˜์ง€ ์•Š์€ ์„ค๋น„์˜ ๋ชซ์ด ๋‚˜๋จธ์ง€ ์„ค๋น„์— ์–นํžŒ๋‹ค โ€” ๊ทธ ์„ค๋น„๊ฐ€\n * ์•ˆ ์“ด ์ „๊ธฐ๋ฅผ ์“ด ๊ฒƒ์œผ๋กœ ๋งŒ๋“ ๋‹ค. ๋Œ์•„๊ฐ„ ๊ฒƒ๋งŒ ์“ฐ๋ฉด, ์„ ์–ธ๋์ง€๋งŒ ์‰ฐ ์„ค๋น„๊ฐ€ ์‚ฌ๋ผ์ ธ ใ€Œ์ด ์ฐฝ์— ์•ˆ ๋Œ์•˜๋‹คใ€๋ฅผ\n * ๋งํ•  ์ˆ˜ ์—†๋‹ค. ๋‘˜์„ ํ•ฉํ•ด์•ผ ๋‘ ์‚ฌ์‹ค์ด ๋‹ค ๋‚จ๋Š”๋‹ค(์ž๋ฆฌ๋ฅผ ๋ชจ๋ฅด๋Š” ๋ชซ์€ `unknown` ์œผ๋กœ ๋ชจ์ธ๋‹ค).\n */\n const busyOf = new Map(utilization.map(u => [u.resourceId, u.busyMs]))\n const ids = new Set<string>([...Object.keys(resourceFeeder), ...busyOf.keys()])\n const consumers = [...ids].map(id => ({ id, weight: busyOf.get(id) ?? 0 }))\n if (!consumers.length) return {}\n\n const r = attributeEnergy({\n pools: [{ meterId: 'site', kWh, consumerIds: consumers.map(c => c.id) }],\n consumers,\n weightKind: 'runtimeMs'\n })\n\n const byKey = new Map<string, { kWh: number; weightShare: number; apportioned: boolean }>()\n for (const sh of r.shares) {\n /* ์ž๋ฆฌ๋ฅผ ๋ชจ๋ฅด๋ฉด `unknown` โ€” ๊ทธ ๋ชซ์ด ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์€ ๋‚จ๊ธฐ๊ณ , ์–ด๋””์˜ ๊ฒƒ์ธ์ง€๋Š” ์ง€์–ด๋‚ด์ง€ ์•Š๋Š”๋‹ค. */\n const key = resourceFeeder[sh.consumerId] ?? 'unknown'\n const cur = byKey.get(key) ?? { kWh: 0, weightShare: 0, apportioned: false }\n cur.kWh += sh.kWh\n cur.weightShare += sh.weightShare ?? 0\n /* **๊ทผ๊ฑฐ๋Š” ์ปค๋„์ด ์ •ํ•œ๋‹ค.** ์—ฌ๊ธฐ์„œ ๋‚™์ธ์ฐ์œผ๋ฉด ์ปค๋„์ด ใ€Œ์Ÿ€๋‹คใ€๊ณ  ํ•œ ๊ฒƒ์„ ใ€Œ๋‚˜๋ˆด๋‹คใ€๊ณ  ๋ฐ”๊ฟ” ๋งํ•˜๊ฑฐ๋‚˜\n ๊ทธ ๋ฐ˜๋Œ€๊ฐ€ ๋œ๋‹ค. ์„ž์ด๋ฉด ์•ฝํ•œ ์ชฝ(๋ฐฐ๋ถ„)์œผ๋กœ ์ ๋Š”๋‹ค โ€” ๊ฐ•ํ•œ ์ฃผ์žฅ์„ ์˜ฌ๋ ค ์žก์ง€ ์•Š๋Š”๋‹ค. */\n if (sh.basis === 'apportioned') cur.apportioned = true\n byKey.set(key, cur)\n }\n\n const byFeeder = [...byKey.entries()]\n .map(([key, v]) => ({\n key,\n kWh: v.kWh,\n basis: (v.apportioned ? 'apportioned' : 'measured') as 'apportioned' | 'measured',\n weightKind: 'runtimeMs' as const,\n weightShare: v.weightShare\n }))\n .sort((a, b) => b.kWh - a.kWh)\n\n const un = r.unattributed.reduce((sum, u) => sum + u.kWh, 0)\n return {\n ...(byFeeder.length ? { byFeeder } : {}),\n ...(un > 0 ? { unattributedKWh: un, unattributedReason: r.unattributed[0]?.reason } : {}),\n ...(r.excluded.length ? { excludedResources: r.excluded.length } : {})\n }\n}\n\n/**\n * ๋ถ„๊ธฐ๋ณ„ ์ „๋ ฅ๋Ÿ‰์„ **๊ณ„๋Ÿ‰์œผ๋กœ** ์ฝ๋Š”๋‹ค โ€” ๊ณ„๋Ÿ‰์ด ์žˆ์œผ๋ฉด ๋ฐฐ๋ถ„ํ•˜์ง€ ์•Š๋Š”๋‹ค.\n *\n * โ”€โ”€ ์™œ ํ•„์š”ํ–ˆ๋‚˜ (2026-08-18) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์‹ค ๊ฒŒ์ดํŠธ์›จ์ด๋Š” ๋ถ„๊ธฐ๋งˆ๋‹ค ๊ณ„๋Ÿ‰๊ธฐ๋ฅผ ๋ณด๋‚ธ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ํ™”๋ฉด์€ ใ€Œ๋‚˜๋ˆ„์ง€ ๋ชปํ•จใ€์œผ๋กœ ๋‹ตํ•˜๊ณ  ์žˆ์—ˆ๋‹ค โ€” ์—ฌ๊ธฐ์—\n * ๊ฐ€๋™์‹œ๊ฐ„ ๋ฐฐ๋ถ„ ๊ฒฝ๋กœ๋งŒ ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ณ„๋Ÿ‰์ด ์žˆ๋Š”๋ฐ ๋ฐฐ๋ถ„์œผ๋กœ ๋งํ•˜๋ฉด **๊ทผ๊ฑฐ๋ฅผ ์‹ค์ œ๋ณด๋‹ค ์•ฝํ•˜๊ฒŒ** ๋ณด๊ณ ํ•˜๋Š”\n * ๊ฒƒ์ด๊ณ , ๊ทธ ์œ„์— ์„ธ์šด SEU ํŒ๋‹จ์ด ๋ฌด๊ฑฐ์šด ๊ฐ’์„ ๋†“์นœ๋‹ค. ๋ฏธ๋Ÿฌ ํŠธ์œˆ์—๋Š” ์„ค๋น„ ๊ฐ€๋™ ๊ธฐ๋ก์กฐ์ฐจ ์—†์–ด์„œ\n * (์›์ฒœ์ด ๊ณ„๋Ÿ‰๋งŒ ์ค€๋‹ค) ๊ทธ ๊ฒฝ๋กœ๋กœ๋Š” ๋ถ„๊ธฐ๋ณ„ ๊ฐ’์ด ์˜์›ํžˆ ๋‚˜์˜ค์ง€ ์•Š์•˜๋‹ค.\n *\n * ๊ฐ’์˜ ์ถœ์ฒ˜๋Š” ์ปค๋„์ด ๊ตฌ๊ฐ„ ๋งˆ๊ฐ ์‚ฌ์‹ค์— ์‹ค์–ด ์ฃผ๋Š” **์ง€์ ๋ณ„ ๋ชซ**์ด๋‹ค(์ ์‚ฐ์˜ ๋บ„์…ˆ). ํ‘œ๋ณธ์„ ์ง์ ‘ ์ฝ์ง€ ์•Š๋Š”\n * ์ด์œ ๋Š” ์กฐํšŒ ์ƒํ•œ์ด๋‹ค โ€” ๊ณ„์ธก์€ ์ดˆ๋‹น ์—ฌ๋Ÿฌ ๊ฑด์ด๋ผ ํ‘œ๋ณธ์œผ๋กœ๋Š” ์ฐฝ์„ ์ฑ„์šฐ๊ธฐ ์ „์— ์ƒํ•œ์— ๊ฑธ๋ฆฐ๋‹ค.\n *\n * ๋‚˜๋จธ์ง€(๋ฟŒ๋ฆฌ โˆ’ ๋ถ„๊ธฐ ํ•ฉ)๋Š” **๋ฒ„๋ฆฌ์ง€๋„ ์–น์ง€๋„ ์•Š๋Š”๋‹ค**: ์ˆ˜์ „ ์ง๊ฒฐ ๋ถ€ํ•˜ยท์†์‹คยท๊ณ„๋Ÿ‰๋˜์ง€ ์•Š์€ ํšŒ๋กœ๊ฐ€ ๊ทธ\n * ์ฐจ์ด์ด๋ฏ€๋กœ, ์–ด๋А ๋ถ„๊ธฐ์— ์–น์œผ๋ฉด ๊ทธ ๋ถ„๊ธฐ๊ฐ€ ์“ฐ์ง€ ์•Š์€ ์ „๊ธฐ๋ฅผ ์“ด ๊ฒƒ์œผ๋กœ ๋งŒ๋“ ๋‹ค. ์ปค๋„์˜ `remainder` ํ’€๋กœ\n * ๋„˜๊ฒจ ใ€Œํ•˜์œ„ ๊ณ„๋Ÿ‰์ด ๋ฎ์ง€ ์•Š๋Š”๋‹คใ€๋กœ ๋‚จ๊ธด๋‹ค.\n *\n * ๋ถ„๊ธฐ ๊ณ„๋Ÿ‰ ํ•ฉ์ด ๋ฟŒ๋ฆฌ๋ณด๋‹ค ํฌ๋ฉด(ํšŒ๊ณ„๊ฐ€ ๋‹ค๋ฅธ ๋‘ ๊ณ„๋Ÿ‰๊ธฐ) **๊ทธ ์‚ฌ์‹ค์„ ๋‚ธ๋‹ค** โ€” ๊ฐ’์„ ๊นŽ์•„ ๋งž์ถ”๋ฉด ๊ณ„๋Ÿ‰์„\n * ์šฐ๋ฆฌ๊ฐ€ ๊ณ ์ณ ์“ฐ๋Š” ๊ฒƒ์ด๋‹ค.\n */\nfunction measuredFeeders(\n windows: readonly {\n startMs: number\n endMs: number\n maxKW?: number\n points: { id: string; kWh: number; root: boolean }[]\n pointsAtPeak?: { id: string; kW: number }[]\n }[],\n range: { startMs: number; endMs: number },\n totalKWh: number | undefined,\n meterFeeder?: Record<string, string>\n): Partial<NonNullable<KpiResult['energy']>> | undefined {\n if (!meterFeeder || !Object.keys(meterFeeder).length) return undefined\n if (totalKWh === undefined || !(totalKWh > 0)) return undefined\n\n /* ์ฐฝ์— ์˜จ์ „ํžˆ ๋“  ๊ตฌ๊ฐ„๋งŒ โ€” ์ „์ฒด ์ „๋ ฅ๋Ÿ‰๊ณผ ๊ฐ™์€ ๊ทœ์น™์ด์–ด์•ผ ๋ชซ๊ณผ ํ•ฉ์ด ๊ฐ™์€ ์ฐฝ์„ ๋งํ•œ๋‹ค. */\n const byFeederKWh = new Map<string, number>()\n let sawPoints = false\n for (const w of windows) {\n if (!(w.startMs >= range.startMs && w.endMs <= range.endMs)) continue\n for (const p of w.points ?? []) {\n const feeder = meterFeeder[p.id]\n if (!feeder) continue // ๋ฟŒ๋ฆฌ ๊ณ„๋Ÿ‰๊ธฐยท๋ชจ๋ฅด๋Š” ์ง€์  โ€” ๋ถ„๊ธฐ์˜ ๋ชซ์ด ์•„๋‹ˆ๋‹ค\n sawPoints = true\n byFeederKWh.set(feeder, (byFeederKWh.get(feeder) ?? 0) + p.kWh)\n }\n }\n if (!sawPoints) return undefined // ๊ณ„๋Ÿ‰์ด ์—†์œผ๋ฉด ์ด ๊ฒฝ๋กœ๋ฅผ ์“ฐ์ง€ ์•Š๋Š”๋‹ค(๋ฐฐ๋ถ„์œผ๋กœ ๋Œ์•„๊ฐ„๋‹ค)\n\n const feeders = [...byFeederKWh.entries()].filter(([, kWh]) => kWh > 0)\n if (!feeders.length) return undefined\n const submetered = feeders.reduce((sum, [, kWh]) => sum + kWh, 0)\n const remainder = totalKWh - submetered\n\n const r = attributeEnergy({\n pools: [\n ...feeders.map(([feeder, kWh]) => ({ meterId: `${feeder}:meter`, kWh, consumerIds: [feeder] })),\n ...(remainder > 0 ? [{ meterId: 'root:remainder', kWh: remainder, consumerIds: [], remainder: true }] : [])\n ],\n consumers: feeders.map(([feeder]) => ({ id: feeder }))\n })\n\n /*\n * โ”€โ”€ ํ”ผํฌ๋ฅผ ๋งŒ๋“  ๋ถ„๊ธฐ (2026-08-18) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n *\n * ์š”๊ธˆ์€ kW ๋กœ ๋งค๊ฒจ์ง€๋ฏ€๋กœ ใ€Œ์–ด๋А ๋ถ„๊ธฐ๋ฅผ ๊นŽ์•„์•ผ ํ”ผํฌ๊ฐ€ ๋‚ด๋ ค๊ฐ€๋‚˜ใ€๊ฐ€ ์‹ค๋ฌด์˜ ์งˆ๋ฌธ์ด๋‹ค. ๊ทธ ๋‹ต์€ **ํ”ผํฌ๊ฐ€\n * ์ฐํžŒ ๊ตฌ๊ฐ„์˜ ๊ทธ ์ˆœ๊ฐ„** ๊ฐ’์ด๊ณ , ์ฐฝ ์•ˆ์˜ ์—ฌ๋Ÿฌ ๊ตฌ๊ฐ„์„ ๋”ํ•˜๊ฑฐ๋‚˜ ํ‰๊ท ํ•˜๋ฉด ๋œป์ด ์‚ฌ๋ผ์ง„๋‹ค(๋‹ค๋ฅธ ์ˆœ๊ฐ„์˜ ๊ฐ’์„\n * ์„ž๋Š” ๊ฒƒ์ด๋‹ค). ๊ทธ๋ž˜์„œ **์ตœ๋Œ€์ˆ˜์š”๋ฅผ ๋‚ธ ๊ตฌ๊ฐ„ ํ•˜๋‚˜**๋งŒ ๊ณจ๋ผ ๊ทธ ์ˆœ๊ฐ„์˜ ์ง€์  ๊ฐ’์„ ์“ด๋‹ค.\n */\n const peakWindow = windows\n .filter(w => w.startMs >= range.startMs && w.endMs <= range.endMs && Number.isFinite(Number(w.maxKW)))\n .reduce<(typeof windows)[number] | undefined>((best, w) => (!best || Number(w.maxKW) > Number(best.maxKW) ? w : best), undefined)\n const peakOf = new Map<string, number>()\n for (const p of peakWindow?.pointsAtPeak ?? []) {\n const feeder = meterFeeder[p.id]\n if (!feeder) continue // ๋ฟŒ๋ฆฌ ๊ณ„๋Ÿ‰๊ธฐยท๋ชจ๋ฅด๋Š” ์ง€์  โ€” ๋ถ„๊ธฐ์˜ ๋ชซ์ด ์•„๋‹ˆ๋‹ค\n peakOf.set(feeder, (peakOf.get(feeder) ?? 0) + p.kW)\n }\n\n const byFeeder = r.shares\n .map(sh => ({\n key: sh.consumerId,\n kWh: sh.kWh,\n basis: sh.basis,\n weightKind: undefined,\n weightShare: undefined,\n /* ํ”ผํฌ ์ˆœ๊ฐ„์˜ ๊ฐ’์ด ์—†์œผ๋ฉด ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค โ€” ๊ทธ ๊ตฌ๊ฐ„์— ์ด ๋ถ„๊ธฐ์˜ ํ‘œ๋ณธ์ด ์—†์—ˆ๋‹ค๋Š” ๋œป์ด๋‹ค. */\n ...(peakOf.has(sh.consumerId) ? { peakKW: peakOf.get(sh.consumerId) } : {})\n }))\n .sort((a, b) => b.kWh - a.kWh) as NonNullable<KpiResult['energy']>['byFeeder']\n\n const un = r.unattributed.reduce((sum, u) => sum + u.kWh, 0)\n return {\n ...(byFeeder?.length ? { byFeeder } : {}),\n ...(un > 0 ? { unattributedKWh: un, unattributedReason: r.unattributed[0]?.reason } : {}),\n /* ๋ถ„๊ธฐ ํ•ฉ์ด ๋ฟŒ๋ฆฌ๋ฅผ ๋„˜์—ˆ๋‹ค โ€” ๋‘ ๊ณ„๋Ÿ‰๊ธฐ์˜ ํšŒ๊ณ„๊ฐ€ ๋‹ค๋ฅด๋‹ค๋Š” ์‚ฌ์‹ค์ด๋‹ค(๊นŽ์•„ ๋งž์ถ”์ง€ ์•Š๋Š”๋‹ค). */\n ...(remainder < 0 ? { submeterExcessKWh: -remainder } : {})\n }\n}\n\n/** ํด๋“œ ์˜ต์…˜ โ€” ๊ด€์  ์ถ•๊ณผ, ๊ทธ ์ถ•์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์ด๋ฒคํŠธ ๋ฐ–์—์„œ ์™€์•ผ ํ•˜๋Š” ์ง€๋„. */\nexport interface KpiFoldOptions {\n groupBy?: KpiGroupBy\n /**\n * ๋…ธ๋“œ โ†’ ๊ตฌ์—ญ ์ง€๋„. **์ด๋ฒคํŠธ์—๋Š” ๊ตฌ์—ญ์ด ์—†๋‹ค**(๋…ธ๋“œ๊นŒ์ง€๋งŒ ์žˆ๋‹ค) โ€” ์Šค๋ƒ…์ƒทยท๋งˆ์Šคํ„ฐ๊ฐ€ ์•„๋Š” ๊ฐ’์ด๋ผ\n * ํ˜ธ์ถœ๋ถ€๊ฐ€ ๋„˜๊ธด๋‹ค. ์—†์œผ๋ฉด ๊ตฌ์—ญ ์ถ•์€ 'unknown' ์œผ๋กœ ๋ชจ์ธ๋‹ค(์กฐ์šฉํžˆ ๋‹ค๋ฅธ ์ถ•์œผ๋กœ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค).\n */\n locationArea?: Record<string, string>\n /**\n * ์ž์› โ†’ **๋ฐฐ์ „ ๊ณ„ํ†ต์˜ ์ž๋ฆฌ**(๋ถ„๊ธฐยท์ˆ˜์ „) ์ง€๋„.\n *\n * โ”€โ”€ ์™œ ๋ฐ–์—์„œ ์˜ค๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ด๋ฒคํŠธ์—๋Š” ์ „๊ธฐ ๊ณ„ํ†ต์ด ์—†๋‹ค. ใ€Œ์ด ์„ค๋น„๊ฐ€ ์–ด๋А ๋ถ„๊ธฐ์—์„œ ๋จน๋Š”๊ฐ€ใ€๋Š” ์—๋„ˆ์ง€ ํŠธ์œˆ์˜ ๋ชจ๋ธ์ด ์•„๋Š”\n * ์„ ์–ธ์ด๊ณ (์„ค๋น„ ํ•˜๋‚˜์— ์‚ฌ์‹ค ๋‘˜ โ€” ๊ณต์žฅ์—์„œ๋Š” ์ž์›, ์ „๊ธฐ์—์„œ๋Š” ๋ถ€ํ•˜), ๊ทธ ์„ ์–ธ์„ ์ฝ๋Š” ๊ฒƒ์€ ํ˜ธ์ถœ๋ถ€์˜ ์ผ์ด๋‹ค.\n *\n * ์—†์œผ๋ฉด ๋ถ„๊ธฐ ๋ถ„ํ•ด๋ฅผ **ํ•˜์ง€ ์•Š๋Š”๋‹ค** โ€” ์ž๋ฆฌ๋ฅผ ๋ชจ๋ฅด๋Š” ์ฑ„ ๋‚˜๋ˆ„๋ฉด ๊ทธ ์ˆซ์ž๋Š” ์•„๋ฌด ๊ฒƒ์˜ ๋ชซ๋„ ์•„๋‹ˆ๋‹ค.\n */\n resourceFeeder?: Record<string, string>\n /**\n * **๊ณ„๋Ÿ‰ ์ง€์  โ†’ ๊ทธ๊ฒƒ์ด ์žฌ๋Š” ๋ถ„๊ธฐ** ์ง€๋„.\n *\n * ์žˆ์œผ๋ฉด ๋ถ„๊ธฐ๋ณ„ ์ „๋ ฅ๋Ÿ‰์„ ๊ณ„๋Ÿ‰์œผ๋กœ ์ฝ๋Š”๋‹ค(๋ฐฐ๋ถ„๋ณด๋‹ค ๊ฐ•ํ•œ ๊ทผ๊ฑฐ). ์ด ์ง€๋„๋Š” ๋ชจ๋ธ์˜ ์„ ์–ธ์—์„œ ์˜ค๊ณ \n * (๊ณ„๋Ÿ‰๊ธฐ์˜ ์ž๋ฆฌ), ๊ทธ๊ฒƒ์„ ์ฝ๋Š” ๊ฒƒ์€ ํ˜ธ์ถœ๋ถ€์˜ ์ผ์ด๋‹ค โ€” ํด๋“œ๋Š” ์ €๋„๋งŒ ๋ณธ๋‹ค.\n */\n meterFeeder?: Record<string, string>\n /**\n * ์„ ์–ธ๋œ **์ „๊ธฐ์š”๊ธˆ ๋‹จ๊ฐ€** โ€” ์ˆ˜๋ฅผ ๊ธˆ์•ก์œผ๋กœ ๋ฐ”๊พธ๋Š” ์œ ์ผํ•œ ์ž…๋ ฅ.\n *\n * ์ด๋ฒคํŠธ์—๋Š” ์š”๊ธˆ์ด ์—†๋‹ค. ๋‹จ๊ฐ€๋Š” ํ˜„์žฅ์˜ ๊ณ„์•ฝ์ด๊ณ (์—๋„ˆ์ง€ ํŠธ์œˆ ๋ชจ๋ธ์˜ ์ˆ˜์ „ ์ž๋ฆฌ์— ์„ ์–ธํ•œ๋‹ค), ๊ทธ๊ฒƒ์„\n * ์ฝ๋Š” ๊ฒƒ์€ ํ˜ธ์ถœ๋ถ€์˜ ์ผ์ด๋‹ค. ์—†์œผ๋ฉด ๊ธˆ์•ก์„ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค โ€” ์ง์ž‘ํ•œ ๋‹จ๊ฐ€๋กœ ๋‚ธ ๊ธˆ์•ก์€ ์ˆซ์ž๊ฐ€ ์žˆ๋‹ค๋Š”\n * ๊ฒƒ๋งŒ์œผ๋กœ ์‚ฌ๋žŒ์„ ๊ฒฐ์ •์œผ๋กœ ๋ฐ€์–ด๋ถ™์ธ๋‹ค.\n */\n tariff?: TariffDeclaration\n /**\n * ๊ต๋Œ€ ์„ ์–ธ โ€” **์ด๋ฒคํŠธ์—๋Š” ๊ต๋Œ€๊ฐ€ ์—†๋‹ค**(์‹œ๊ฐ๋งŒ ์žˆ๋‹ค). ํ˜„์žฅ ๋งˆ์Šคํ„ฐ๊ฐ€ ์•„๋Š” ๊ฐ’์ด๋ผ ํ˜ธ์ถœ๋ถ€๊ฐ€ ๋„˜๊ธด๋‹ค.\n * ์—†์œผ๋ฉด ๊ต๋Œ€ ์ถ•์€ 'unknown' ์œผ๋กœ ๋ชจ์ธ๋‹ค(๋‹ค๋ฅธ ์ถ•์œผ๋กœ ์กฐ์šฉํžˆ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค).\n */\n shifts?: WorkCalendarEntry[]\n /**\n * ํ˜„์žฅ์˜ ์‹œ๊ฐ ๊ธฐ์ค€(๋ถ„) โ€” ๊ต๋Œ€ ์ถ•์ด `HH:MM` ์„ ์–ด๋А ๊ธฐ์ค€์œผ๋กœ ์ฝ์„์ง€. **๊ณต๊ฐ„์ด ๊ฐ–๋Š” ๊ฐ’**์ด๋‹ค\n * (ํ…Œ๋„ŒํŠธ๊ฐ€ ์•„๋‹ˆ๋‹ค: ํ•œ ํ…Œ๋„ŒํŠธ๊ฐ€ ๋‹ค๋ฅธ ์‹œ๊ฐ„๋Œ€์˜ ๊ณต์žฅ์„ ํ•จ๊ป˜ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค). ์—†์œผ๋ฉด UTC.\n */\n utcOffsetMinutes?: number\n /**\n * ์ถ•์˜ ์ƒํ•œ(๊ธฐ๋ณธ 20). ๋„˜์น˜๋ฉด ์ž˜๋ผ๋‚ด๊ณ  **์ž˜๋ฆฐ ์ถ•์˜ ์ˆ˜์™€ ๊ทธ ์•ˆ์˜ ๊ฑด์ˆ˜๋ฅผ ํ•จ๊ป˜ ์•Œ๋ฆฐ๋‹ค**.\n *\n * ์ถ•์˜ ์ˆ˜๋งŒ ์•Œ๋ฆฌ๋ฉด ๋ถ€์กฑํ•˜๋‹ค โ€” \"๊ทธ ์™ธ 89๊ฐœ\" ๋กœ๋Š” ๊ทธ๊ฒƒ์ด 3๊ฑด์ธ์ง€ 300๊ฑด์ธ์ง€ ๋ชจ๋ฅธ๋‹ค. ๋ณด์—ฌ์ค€ ์ถ•์ด ์ „๋ถ€์ธ\n * ๊ฒƒ์ฒ˜๋Ÿผ ์ฝํžˆ๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ๊ผฌ๋ฆฌ๋ฅผ ๋†“์นœ๋‹ค.\n */\n groupLimit?: number\n}\n\n/* โ”€โ”€ ๊ด€์  ์ถ•์˜ ์žฌ๋ฃŒ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ถ•์˜ ๊ฐ’์€ ์ด๋ฒคํŠธ payload ์— ์ด๋ฏธ ๋“ค์–ด ์žˆ๋‹ค(`TaskStatusDelta`: kindยทorderIdยทfromNodeยทtoNodeยท\n * resourceRef). ์ƒˆ ๊ณ„์ธก์„ ์‹ฌ์„ ํ•„์š”๊ฐ€ ์—†๋‹ค โ€” **์ด๋ฏธ ์Œ“์ธ ์ €๋„์„ ๋‹ค๋ฅด๊ฒŒ ๋ฌถ๊ธฐ๋งŒ** ํ•œ๋‹ค.\n */\n/** ์ฐฝ ์•ˆ์— ์™„๋ฃŒ๋œ ํ•œ ๊ฑด์˜ ๊ธฐ๋ก โ€” ํ†ต๊ณ„์˜ ์›๋ฃŒ์ด์ž ๊ด€์  ์ถ•์˜ ์›๋ฃŒ. */\ninterface CompletionRecord {\n taskId: string\n at: number\n facets: TaskFacets\n leadMs?: number\n workMs?: number\n waitMs?: number\n}\n\n/** ์ด ๊ธฐ๋ก์ด ์š”์ฒญํ•œ ์ถ•์—์„œ ์–ด๋А ๊ฐ’์— ์†ํ•˜๋Š”๊ฐ€. ๊ฐ’์ด ์—†์œผ๋ฉด 'unknown'(์กฐ์šฉํžˆ ๋ฒ„๋ฆฌ์ง€ ์•Š๋Š”๋‹ค). */\nfunction facetKey(rec: CompletionRecord, options: KpiFoldOptions): string {\n const f = rec.facets\n switch (options.groupBy) {\n case 'resource':\n return f.resource ?? 'unknown'\n case 'taskKind':\n return f.kind ?? 'unknown'\n case 'location':\n return f.location ?? 'unknown'\n case 'order':\n return f.order ?? 'unknown'\n case 'area':\n /* ๊ตฌ์—ญ์€ ์ด๋ฒคํŠธ ๋ฐ–์˜ ์ง€์‹์ด๋‹ค โ€” ์ง€๋„๊ฐ€ ์—†์œผ๋ฉด ์—†๋‹ค๊ณ  ๋งํ•œ๋‹ค(๋…ธ๋“œ id ๋กœ ๋Œ€์ฒดํ•˜๋ฉด ์‚ฌ์šฉ์ž๊ฐ€\n * ๊ทธ๊ฒƒ์„ ๊ตฌ์—ญ์œผ๋กœ ์˜คํ•ดํ•œ๋‹ค). */\n return (f.location && options.locationArea?.[f.location]) ?? 'unknown'\n case 'shift':\n /*\n * ๊ต๋Œ€๋Š” **์ €๋„์— ์ฐํ˜€ ์žˆ์ง€ ์•Š๋‹ค โ€” ๊ณ„์‚ฐํ•œ๋‹ค.**\n *\n * ์ด๋ฒคํŠธ์— ๊ต๋Œ€ ์ด๋ฆ„์„ ์Šคํƒฌํ”„ํ•˜๋ฉด ๋‘ ๊ฐ€์ง€๊ฐ€ ๋ฌด๋„ˆ์ง„๋‹ค: โ‘  ๊ฐ™์€ ์‚ฌ์‹ค์ด ๋‘ ๊ณณ์— ์ƒ๊ธฐ๊ณ ,\n * โ‘ก ๋‚˜์ค‘์— ๊ต๋Œ€ ์‹œ๊ฐ„์„ ๊ณ ์น˜๋ฉด **๊ณผ๊ฑฐ๊ฐ€ ์˜› ๊ตฌ๋ถ„์œผ๋กœ ๊ตณ์–ด** ๋‹ค์‹œ ์…€ ์ˆ˜ ์—†๋‹ค. ๊ต๋Œ€๋Š”\n * `์™„๋ฃŒ ์‹œ๊ฐ + ํ˜„์žฅ์˜ ์‹œ๊ฐ ๊ธฐ์ค€ + ๊ต๋Œ€ ์„ ์–ธ`์—์„œ ๋‚˜์˜ค๋Š” ์ˆœ์ˆ˜ ํŒŒ์ƒ์ด๋ฏ€๋กœ ์—ฌ๊ธฐ์„œ ๋‚ธ๋‹ค โ€”\n * ๋ผ์ด๋ธŒยทํžˆ์Šคํ† ๋ฆฌยท์˜ˆ์ธก์ด **์ปค๋„๊ณผ ๊ฐ™์€ ํ•จ์ˆ˜**(`activeShiftOf`)๋ฅผ ์“ด๋‹ค.\n *\n * ์„ ์–ธ์ด ์—†์œผ๋ฉด 'unknown' ์ด๋‹ค. ๊ต๋Œ€๋ฅผ ๋‚˜๋ˆ  ๋†“์ง€ ์•Š์€ ํ˜„์žฅ์— ์ด๋ฆ„์„ ์ง€์–ด๋‚ด์ง€ ์•Š๋Š”๋‹ค.\n */\n if (!options.shifts?.length) return 'unknown'\n /* ์‹œ๊ฐ๊นŒ์ง€ ๋„˜๊ธด๋‹ค โ€” **ํœด์ผ์— ์ผ์–ด๋‚œ ์ผ์€ ์–ด๋А ๊ต๋Œ€์—๋„ ์†ํ•˜์ง€ ์•Š๋Š”๋‹ค.** ๋˜ํ’€์ด๋งŒ ๋ณด๋ฉด ๊ทธ๋‚  ์„œ์ง€๋„\n ์•Š์€ ๊ต๋Œ€์— ์ง‘๊ณ„๋ผ, ๊ต๋Œ€๋ณ„ ์„ฑ๊ณผ๊ฐ€ ์กฐ์šฉํžˆ ๊ฑฐ์ง“์ด ๋œ๋‹ค. */\n return activeShiftAt(options.shifts, rec.at, options.utcOffsetMinutes) ?? 'unknown'\n default:\n return 'unknown'\n }\n}\n\n/**\n * ๊ธฐ๋ก์„ ์ถ•์œผ๋กœ ๋ฌถ์–ด ์ถ•๋ณ„ ํ†ต๊ณ„๋ฅผ ๋‚ธ๋‹ค โ€” **์ „์ฒด์™€ ๊ฐ™์€ ๊ทœ์น™**์œผ๋กœ(๊ฐ™์€ stats ํ•จ์ˆ˜, ๊ฐ™์€ ์ฐฝ).\n *\n * ์ถ•์˜ ๊ฐ’์ด ์•„์ฃผ ๋งŽ์„ ์ˆ˜ ์žˆ๋‹ค(์˜ค๋” ์ถ•์€ ์ˆ˜์ฒœ ๊ฐœ). ๊ทธ๋ž˜์„œ ๊ฑด์ˆ˜ ํฐ ๊ฒƒ๋ถ€ํ„ฐ ์ƒํ•œ๊นŒ์ง€๋งŒ ๋Œ๋ ค์ฃผ๊ณ \n * **์ž˜๋ผ๋‚ธ ์ˆ˜๋ฅผ ํ•จ๊ป˜ ์•Œ๋ฆฐ๋‹ค** โ€” ์กฐ์šฉํ•œ ์ ˆ๋‹จ์€ \"์ด๊ฒŒ ์ „๋ถ€\" ๋ผ๋Š” ๊ฑฐ์ง“์„ ๋งŒ๋“ ๋‹ค.\n */\nfunction groupRecords(\n records: CompletionRecord[],\n options: KpiFoldOptions\n): { by: KpiGroupBy; items: KpiGroup[]; truncated?: number; truncatedTasks?: number } {\n const by = options.groupBy as KpiGroupBy\n const bins = new Map<string, CompletionRecord[]>()\n for (const rec of records) {\n const key = facetKey(rec, options)\n const bin = bins.get(key)\n if (bin) bin.push(rec)\n else bins.set(key, [rec])\n }\n\n const all = [...bins.entries()]\n .map(([key, rows]) => ({\n key,\n tasks: rows.length,\n leadTime: stats(rows.map(r => r.leadMs).filter((v): v is number => v !== undefined)),\n workTime: stats(rows.map(r => r.workMs).filter((v): v is number => v !== undefined)),\n waitTime: stats(rows.map(r => r.waitMs).filter((v): v is number => v !== undefined)),\n busyMs: rows.reduce((a, r) => a + (r.workMs ?? 0), 0)\n }))\n .sort((a, b) => b.tasks - a.tasks || (a.key < b.key ? -1 : 1))\n\n const limit = Math.max(1, Math.min(100, options.groupLimit ?? 20))\n const items = all.slice(0, limit)\n const dropped = all.slice(limit)\n /* ์ถ•๋ณ„๋กœ \"์ฐฝ ๋Œ€๋น„ ๋น„์œจ\" ์€ ๋‚ด์ง€ ์•Š๋Š”๋‹ค โ€” ์ž์› ์•„๋‹Œ ์ถ•(์˜ค๋”ยท์ž‘์—…์ข…๋ฅ˜)์—์„œ ๊ทธ ๋น„์œจ์€ ์˜๋ฏธ๊ฐ€ ์—†๊ณ ,\n * ์˜๋ฏธ ์—†๋Š” ์ˆซ์ž๋ฅผ ๋‚ด๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ๊ทธ๊ฒƒ์œผ๋กœ ํŒ๋‹จํ•œ๋‹ค. ์ž์› ์ ์œ ๋Š” `utilization` ์ด ์ด๋ฏธ ๋‚ธ๋‹ค. */\n return {\n by,\n items,\n ...(dropped.length\n ? { truncated: dropped.length, truncatedTasks: dropped.reduce((a, g) => a + g.tasks, 0) }\n : {})\n }\n}\n\nfunction ms(value: string | undefined): number | null {\n if (!value) return null\n const t = Date.parse(value)\n return Number.isFinite(t) ? t : null\n}\n\n/** ๋ถ„์œ„์ˆ˜ โ€” ์ •๋ ฌ๋œ ๊ฐ’์—์„œ ์„ ํ˜• ๋ณด๊ฐ„ ์—†์ด ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ์•„๋ž˜ ๊ฐ’(์ž‘์€ ํ‘œ๋ณธ์—์„œ ๊ณผ์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค). */\nfunction quantile(sorted: number[], q: number): number {\n if (sorted.length === 0) return 0\n const idx = Math.min(sorted.length - 1, Math.max(0, Math.floor(q * sorted.length)))\n return sorted[idx]\n}\n\nfunction stats(values: number[]): DurationStats {\n if (values.length === 0) return { count: 0, p10Ms: 0, p50Ms: 0, p90Ms: 0, avgMs: 0 }\n const sorted = [...values].sort((a, b) => a - b)\n const sum = sorted.reduce((a, b) => a + b, 0)\n return {\n count: sorted.length,\n p10Ms: quantile(sorted, 0.1),\n p50Ms: quantile(sorted, 0.5),\n p90Ms: quantile(sorted, 0.9),\n avgMs: Math.round(sum / sorted.length)\n }\n}\n\n/**\n * ์ด๋ฒคํŠธ๋ฅผ ์ ‘์–ด ์‹œ๊ฐ„์ฐฝ KPI ๋ฅผ ๋งŒ๋“ ๋‹ค.\n *\n * **ํ˜ธ์ถœ๋ถ€ ๊ทœ์•ฝ**: `events` ๋Š” ์ฐฝ๋ณด๋‹ค **๋„‰๋„‰ํžˆ ์•ž๊นŒ์ง€** ๋‹ด์•„ ๋„˜๊ธด๋‹ค(์˜ˆ: ์ฐฝ ์‹œ์ž‘ โˆ’ ๋ฆฌ๋“œํƒ€์ž„ ์ƒํ•œ).\n * ์™„๋ฃŒ๋œ ์ž‘์—…์˜ ์‹œ์ž‘ ์ด๋ฒคํŠธ๊ฐ€ ์ฐฝ ๋ฐ–์— ์žˆ์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋ชป ์ฐพ์€ ๊ฒƒ์€ `unpaired` ๋กœ ์•Œ๋ฆฐ๋‹ค โ€”\n * ํ‰๊ท ์—์„œ ์กฐ์šฉํžˆ ๋น ์ง€๋ฉด ์ง€ํ‘œ๊ฐ€ ๊ฑฐ์ง“์ด ๋œ๋‹ค.\n *\n * ์‹œ๊ฐ„์ถ•์€ `eventTime`(ISO) ์ฐจ๋ถ„์ด๋‹ค. sim ํด๋ก์ด ์‹ค์ œ ์‹œ๊ฐ๊ณผ ์˜คํ”„์…‹์ด ์žˆ์–ด๋„ **์ฐจ๋ถ„์€ ์ •ํ™•**ํ•˜๋‹ค\n * (๊ณ ์ • ์˜คํ”„์…‹์€ ์ƒ์‡„๋œ๋‹ค). ํŒŒ์‹ฑ ๋ถˆ๊ฐ€ํ•œ ์ค„์€ ๋ฒ„๋ฆฐ๋‹ค.\n */\nexport function foldKpi(events: KpiEvent[], window: KpiWindow, options: KpiFoldOptions = {}): KpiResult {\n /* ์ž‘์—… ์ง๋งž์ถค์€ **์ปค๋„ ๊ทœ์น™**์œผ๋กœ(์ค‘๋ณต ๊ตฌํ˜„ ๊ธˆ์ง€ โ€” ๋‘ ๊ณณ์— ์ ์œผ๋ฉด ๊ฐ™์€ ์ €๋„๋กœ ๋‹ค๋ฅธ ๋‹ต์ด ๋‚˜์˜จ๋‹ค). */\n const { records: tasks } = foldTaskRecords(events.filter(e => e.eventType === 'task.status'))\n let completedOrders = 0\n let seen = 0\n let inWindow = 0\n\n for (const e of events) {\n const at = ms(e.eventTime)\n if (at === null) continue\n seen++\n if (at >= window.fromMs && at <= window.toMs) inWindow++\n const d = e.payload?.data ?? e.payload ?? {}\n\n if (e.eventType === 'order.status') {\n /* ์˜ค๋” ์™„๋ฃŒ ์–ดํœ˜๋Š” ๋„๋ฉ”์ธ ์†Œ์œ ๋‹ค โ€” ์ฝ”์–ด๊ฐ€ ๊ฐ•์ œํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ž˜์„œ ์ด๋ฆ„์„ ํ•˜๋‚˜๋กœ ๋ชป ๋ฐ•์ง€ ์•Š๊ณ \n * ์™„๋ฃŒ๋กœ ์ฝํžˆ๋Š” ํ‘œํ˜„์„ ๋„“๊ฒŒ ๋ฐ›๋Š”๋‹ค(๊ทธ ๋ฐ–์€ ์„ธ์ง€ ์•Š๋Š”๋‹ค). */\n const status = String(d.status ?? '').toLowerCase()\n if (at >= window.fromMs && at <= window.toMs && (status === 'completed' || status === 'fulfilled' || status === 'done')) {\n completedOrders++\n }\n }\n }\n\n /*\n * ์—๋„ˆ์ง€ โ€” ์ฐฝ์— **์˜จ์ „ํžˆ ๋“ ** ๊ตฌ๊ฐ„ ๋งˆ๊ฐ ์‚ฌ๊ฑด๋งŒ ์„ผ๋‹ค(๊ฑธ์นœ ๊ตฌ๊ฐ„์€ ์ปค๋„ ๊ทœ์น™์ด ๋บ€๋‹ค).\n * ์‚ฌ๊ฑด์ด ํ•˜๋‚˜๋„ ์—†์œผ๋ฉด ์ด ํŠธ์œˆ์—๋Š” ์—๋„ˆ์ง€๊ฐ€ ์—†๋Š” ๊ฒƒ์ด๋ฏ€๋กœ ๋ธ”๋ก ์ž์ฒด๋ฅผ ๋‚ด์ง€ ์•Š๋Š”๋‹ค.\n */\n const demandWindows = events\n .filter(e => e.eventType === ENERGY_EVENT.demandWindow)\n .map(e => {\n const d = e.payload?.data ?? e.payload ?? {}\n /* ์ตœ๋Œ€(`maxKW`)๋„ ํ•จ๊ป˜ ๋„˜๊ธด๋‹ค โ€” ์š”๊ธˆ์ด ๊ฑธ๋ฆฌ๋Š” ์ˆ˜๋Š” ํ‰๊ท ์ด ์•„๋‹ˆ๋ผ ์ตœ๋Œ€๋‹ค.\n ์ด๋ถ€ํ•˜(`grossMaxKW`)๋Š” ใ€Œ๋ฌด์—‡์ด ๊นŽ์˜€๋‚˜ใ€๋ฅผ ๋˜์งš๋Š” ์ถ•์ด๋‹ค(๋ฐœ์ „ยท๋ฐฉ์ „ ์ฐจ๊ฐ ์ „). */\n return {\n startMs: Number(d.startMs),\n endMs: Number(d.endMs),\n meanKW: Number(d.meanKW),\n maxKW: Number(d.maxKW),\n grossMaxKW: Number(d.grossMaxKW),\n /* ์ง€์ ๋ณ„ ๋ชซ โ€” ๊ณ„๋Ÿ‰์ด ๋ถ„๊ธฐ์— ์žˆ์œผ๋ฉด ๊ทธ ๊ฐ’์€ **์ธก์ •**์ด๋‹ค(๋ฐฐ๋ถ„์ด ์•„๋‹ˆ๋‹ค). ์ปค๋„์ด ๊ณ„์ธต ํŒ์ •\n (`root`)๊นŒ์ง€ ์‹ค์–ด ์ฃผ๋ฏ€๋กœ ์—ฌ๊ธฐ์„œ ๊ฐ™์€ ๊ทœ์น™์„ ๋‹ค์‹œ ์“ฐ์ง€ ์•Š๋Š”๋‹ค. */\n points: (Array.isArray(d.points) ? d.points : [])\n .map((p: any) => ({ id: String(p?.id ?? ''), kWh: Number(p?.kWh), root: p?.root === true }))\n .filter((p: any) => p.id && Number.isFinite(p.kWh)),\n /* ํ”ผํฌ๊ฐ€ ์ฐํžŒ ์ˆœ๊ฐ„์˜ ์ง€์ ๋ณ„ kW โ€” ์š”๊ธˆ์ด ๊ฑธ๋ฆฐ ์ˆ˜๋Š” kW ๋‹ค(์ „๋ ฅ๋Ÿ‰์ด ํฐ ๋ถ„๊ธฐ์™€ ํ”ผํฌ๋ฅผ ๋งŒ๋“  ๋ถ„๊ธฐ๋Š” ๋‹ค๋ฅด๋‹ค). */\n pointsAtPeak: (Array.isArray(d.pointsAtPeak) ? d.pointsAtPeak : [])\n .map((p: any) => ({ id: String(p?.id ?? ''), kW: Number(p?.kW) }))\n .filter((p: any) => p.id && Number.isFinite(p.kW))\n }\n })\n .filter(w => Number.isFinite(w.startMs) && Number.isFinite(w.endMs))\n\n const leads: number[] = []\n const works: number[] = []\n const waits: number[] = []\n const busyByResource = new Map<string, number>()\n /* ์ฐฝ ์•ˆ์— ์™„๋ฃŒ๋œ ๊ฑด๋“ค์˜ **๊ธฐ๋ก** โ€” ํ†ต๊ณ„๋ฅผ ๋‚ธ ๋’ค์—๋„ ๋ฒ„๋ฆฌ์ง€ ์•Š๋Š”๋‹ค. ๊ด€์  ์ถ•์€ ๊ฐ™์€ ๊ธฐ๋ก์„ ๋‹ค์‹œ\n * ๋ฌถ๋Š” ๊ฒƒ์ผ ๋ฟ์ด๋ฏ€๋กœ, ๊ธฐ๋ก์„ ๋‚จ๊ธฐ๋ฉด ์ถ•์„ ํ•˜๋‚˜ ๋” ๋ถ™์ด๋Š” ๊ฐ’์ด ๊ฑฐ์˜ 0 ์ด ๋œ๋‹ค. */\n const records: CompletionRecord[] = []\n let tasksInWindow = 0\n let unpairedLead = 0\n let unpairedWork = 0\n\n for (const t of tasks) {\n const completed = t.completedMs\n if (completed === undefined) continue // ์•„์ง ์™„๋ฃŒ๋˜์ง€ ์•Š์€ ์ž‘์—… โ€” ์„ฑ๊ณผ๋กœ ์„ธ์ง€ ์•Š๋Š”๋‹ค\n if (completed < window.fromMs || completed > window.toMs) continue // ์„ฑ๊ณผ๋Š” ์™„๋ฃŒ ์‹œ์ ์œผ๋กœ ์„ผ๋‹ค\n tasksInWindow++\n const c = t.createdMs\n const s = t.startedMs\n const rec: CompletionRecord = { taskId: t.taskId, at: completed, facets: t.facets }\n const resource = rec.facets.resource\n if (c !== undefined && completed >= c) leads.push((rec.leadMs = completed - c))\n else unpairedLead++\n if (s !== undefined && completed >= s) {\n const busy = completed - s\n works.push((rec.workMs = busy))\n if (resource) busyByResource.set(resource, (busyByResource.get(resource) ?? 0) + busy)\n } else {\n unpairedWork++\n }\n if (c !== undefined && s !== undefined && s >= c) waits.push((rec.waitMs = s - c))\n records.push(rec)\n }\n\n const span = Math.max(1, window.toMs - window.fromMs)\n const utilization = [...busyByResource.entries()]\n .map(([resourceId, busyMs]) => ({ resourceId, busyMs, ratio: Math.min(1, busyMs / span) }))\n .sort((a, b) => b.busyMs - a.busyMs)\n\n return {\n window: { fromMs: window.fromMs, toMs: window.toMs },\n throughput: { tasks: tasksInWindow, orders: completedOrders },\n ...(demandWindows.length\n ? (() => {\n const e = energyOfWindows(demandWindows, { startMs: window.fromMs, endMs: window.toMs })\n /* ๋ถ„๋ชจ๋Š” **์™„๋ฃŒ ์˜ค๋”**๋‹ค(๋Œ€๋‹น ์ „๋ ฅ). ์ฐฝ์— ์™„๋ฃŒ๊ฐ€ ์—†์œผ๋ฉด ์ปค๋„ ๊ทœ์น™์ด ใ€Œ์ •์˜๋˜์ง€ ์•Š์Œใ€์œผ๋กœ ๋‹ตํ•œ๋‹ค. */\n const i = energyIntensity({\n kWh: e.kWh,\n energyWindow: e.window,\n denominator: { kind: 'output', value: completedOrders, window: e.window }\n })\n return {\n energy: {\n ...(e.kWh !== undefined ? { kWh: e.kWh } : {}),\n /* ์ด ์ฐฝ์˜ ์ตœ๋Œ€์ˆ˜์š” โ€” ๊ณ„์•ฝ ๋Œ€๋น„ ํŒ์ •์ด ๋ณด๋Š” ์ˆ˜๋‹ค(์ „๋ ฅ๋Ÿ‰๊ณผ ๊ฐ™์€ ๊ตฌ๊ฐ„ ์ง‘ํ•ฉ์—์„œ ์™”๋‹ค). */\n ...(e.peakKW !== undefined ? { peakKW: e.peakKW, peakStartMs: e.peakStartMs } : {}),\n /* ๊นŽ์ธ ์–‘์€ **๊ฐ™์€ ๊ตฌ๊ฐ„์˜ ๋‘ ์ˆ˜**์˜ ์ฐจ์ด๋‹ค โ€” ์—ฌ๊ธฐ์„œ ํ•œ ๋ฒˆ๋งŒ ๊ณ„์‚ฐํ•ด ๋‘ ๊ณณ์ด ๊ฐˆ๋ผ์ง€์ง€ ์•Š๊ฒŒ. */\n ...(e.peakGrossKW !== undefined && e.peakKW !== undefined\n ? { peakGrossKW: e.peakGrossKW, ...(e.peakGrossKW > e.peakKW ? { shavedKW: e.peakGrossKW - e.peakKW } : {}) }\n : {}),\n basis: e.basis,\n counted: e.counted,\n skipped: e.skipped,\n intensity:\n i.value === null\n ? { value: null, reason: (i as any).reason }\n : { value: i.value, unit: (i as any).unit },\n ...(measuredFeeders(demandWindows, { startMs: window.fromMs, endMs: window.toMs }, e.kWh, options.meterFeeder) ??\n feederShares(e.kWh, utilization, options.resourceFeeder)),\n /* ๊ธˆ์•ก์€ ๊ฐ™์€ ์ฐฝ์˜ ์ „๋ ฅ๋Ÿ‰ยท์ตœ๋Œ€์ˆ˜์š”์—์„œ ๋‚˜์˜จ๋‹ค โ€” ์ฐฝ์ด ํ•˜๋‚˜๋ฟ์ด๋ผ ์–ด๊ธ‹๋‚  ์ˆ˜ ์—†๋‹ค. */\n ...(options.tariff ? { cost: electricityCost({ kWh: e.kWh, peakKW: e.peakKW, tariff: options.tariff }) } : {})\n }\n }\n })()\n : {}),\n leadTime: stats(leads),\n workTime: stats(works),\n waitTime: stats(waits),\n utilization,\n unpaired: { leadTime: unpairedLead, workTime: unpairedWork },\n eventsSeen: seen,\n eventsInWindow: inWindow,\n ...(options.groupBy ? { groups: groupRecords(records, options) } : {})\n }\n}\n\n/**\n * ๊ด€์  ร— ๋น„๊ต ๊ต์ฐจ โ€” **\"๊ตฌ์—ญ๋ณ„๋กœ ์–ด์ œ ๋Œ€๋น„ ์–ด๋–ค๊ฐ€\"**.\n *\n * ์ถ•(๋ฌด์—‡์„)๊ณผ ๋น„๊ต(์–ธ์ œ ๋Œ€๋น„)๋ฅผ ๋”ฐ๋กœ ๋ณด๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ๋จธ๋ฆฟ์†์—์„œ ๋‘ ํ‘œ๋ฅผ ๋Œ€์กฐํ•ด์•ผ ํ•œ๋‹ค. ์šด์˜์—์„œ ๊ฐ€์žฅ\n * ๊ฐ’ ์žˆ๋Š” ์งˆ๋ฌธ์€ ๊ทธ ๊ต์ฐจ๋‹ค: ์ „์ฒด๋Š” ๋น„์Šทํ•œ๋ฐ **ํ•œ ๊ตฌ์—ญ๋งŒ ๋‚˜๋น ์ง„** ๊ฒฝ์šฐ๋ฅผ ์ „์ฒด ์ˆซ์ž๋กœ๋Š” ์ ˆ๋Œ€ ๋ชป ๋ณธ๋‹ค.\n *\n * ์ •์ง์„ฑ ๊ทœ์œจ:\n * ยท ๋‘ ๊ตฌ๊ฐ„์— **๋ชจ๋‘ ์žˆ๋Š”** ์ถ•๋งŒ delta ๋ฅผ ๋‚ธ๋‹ค.\n * ยท ์ง€๊ธˆ๋งŒ ์žˆ๋Š” ์ถ•์€ `isNew`(์ด์ „์— ์—†๋˜ ์ผ) โ€” delta ๋ฅผ ๊ฑด์ˆ˜์™€ ๊ฐ™๊ฒŒ ์ ์œผ๋ฉด \"๋Š˜์—ˆ๋‹ค\" ๋กœ ์˜ค๋…๋œ๋‹ค.\n * ยท **์‚ฌ๋ผ์ง„ ์ถ•**(์ „์— ์žˆ์—ˆ๊ณ  ์ง€๊ธˆ ์—†๋Š” ๊ฒƒ)์€ ๋”ฐ๋กœ ๋Œ๋ ค์ค€๋‹ค. ํ‘œ์—์„œ ๊ทธ๋ƒฅ ๋น ์ง€๋ฉด **๋ฉˆ์ถ˜ ๊ตฌ์—ญ์ด\n * ๋ˆˆ์— ๋ณด์ด์ง€ ์•Š๋Š”๋‹ค** โ€” ์šด์˜์—์„œ๋Š” ์ด๊ฒƒ์ด ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์‹ ํ˜ธ์ผ ์ˆ˜ ์žˆ๋‹ค.\n */\nexport interface CrossedGroup extends KpiGroup {\n /** ๋น„๊ต ๊ตฌ๊ฐ„์˜ ๊ฑด์ˆ˜(๋‘ ๊ตฌ๊ฐ„์— ๋ชจ๋‘ ์žˆ์„ ๋•Œ๋งŒ). */\n prevTasks?: number\n /** ํ˜„์žฌ โˆ’ ๋น„๊ต๊ตฌ๊ฐ„ ๊ฑด์ˆ˜(๋‘ ๊ตฌ๊ฐ„์— ๋ชจ๋‘ ์žˆ์„ ๋•Œ๋งŒ). */\n deltaTasks?: number\n /** ๋น„๊ต ๊ตฌ๊ฐ„ ๋Œ€๋น„ ์ž‘์—…์‹œ๊ฐ„ ์ค‘์•™๊ฐ’ ์ฐจ์ด(๋‘˜ ๋‹ค ์ธก์ •๋œ ๋•Œ๋งŒ). */\n deltaWorkP50Ms?: number\n /** ๋น„๊ต ๊ตฌ๊ฐ„์—๋Š” ์—†๋˜ ์ถ• โ€” delta ๋Œ€์‹  ์ด ํ‘œ์‹์„ ์ค€๋‹ค. */\n isNew?: boolean\n}\n\nexport function crossGroups(\n now: KpiGroup[],\n prev: KpiGroup[]\n): { items: CrossedGroup[]; disappeared: { key: string; tasks: number }[] } {\n const before = new Map(prev.map(g => [g.key, g]))\n const items: CrossedGroup[] = now.map(g => {\n const p = before.get(g.key)\n if (!p) return { ...g, isNew: true }\n return {\n ...g,\n prevTasks: p.tasks,\n deltaTasks: g.tasks - p.tasks,\n ...(deltaP50(g.workTime, p.workTime) !== undefined ? { deltaWorkP50Ms: deltaP50(g.workTime, p.workTime) } : {})\n }\n })\n const present = new Set(now.map(g => g.key))\n const disappeared = prev.filter(g => !present.has(g.key)).map(g => ({ key: g.key, tasks: g.tasks }))\n return { items, disappeared }\n}\n\n/* โ”€โ”€ ์‹œ๊ฐ„ ๋น„๊ต โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ˆซ์ž ํ•˜๋‚˜๋กœ๋Š” ์ข‹์•„์กŒ๋Š”์ง€ ๋‚˜๋น ์กŒ๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค(\"29์ดˆ\" ๊ฐ€ ๊ฐœ์„ ์ธ์ง€ ์•…ํ™”์ธ์ง€). ๊ฐ™์€ ๊ธธ์ด์˜ ์ฐฝ์„ ์˜ฎ๊ฒจ\n * ํ•œ ๋ฒˆ ๋” ์ ‘์œผ๋ฉด ๋˜๋ฏ€๋กœ(ํด๋“œ๋Š” ์ˆœ์ˆ˜) ๊ฐ’์‹ธ๋‹ค. ์ฐฝ ์˜ฎ๊ธฐ๊ธฐ์™€ ์ฐจ์ด ๊ณ„์‚ฐ์€ ๊ณ„์‚ฐ ๊ทœ์น™์ด๋ผ ์—ฌ๊ธฐ ์žˆ๋‹ค โ€”\n * ์กฐํšŒ ์ธต์— ๋‘๋ฉด ํ…Œ์ŠคํŠธ๊ฐ€ DB ๋ฅผ ๋Œ๊ณ  ์™€์•ผ ํ•œ๋‹ค.\n */\n\n/**\n * ๋น„๊ต ๊ตฌ๊ฐ„์˜ ์ฐฝ โ€” ๊ฐ™์€ **๊ธธ์ด**๋กœ ์˜ฎ๊ธด๋‹ค.\n *\n * previous: ๋ฐ”๋กœ ์•ž ๊ตฌ๊ฐ„(๊ฒฝ๊ณ„๊ฐ€ ๋งž๋ฌผ๋ฆฌ๊ฒŒ โ€” ๊ฒน์น˜๊ฑฐ๋‚˜ ๋ฒŒ์–ด์ง€๋ฉด ๊ตฌ๊ฐ„์˜ ํ•ฉ์ด ์–ด๊ธ‹๋‚œ๋‹ค).\n * yesterday: ์ •ํ™•ํžˆ 24์‹œ๊ฐ„ ์ „ ๊ฐ™์€ ์ž๋ฆฌ. ์‹œ๋ฎฌ ํŠธ์œˆ์˜ ํด๋ก์ด ์‹ค์ œ ์‹œ๊ฐ๊ณผ ๋‹ฌ๋ผ๋„ **์ฐจ๋ถ„์€ ์ •ํ™•**ํ•˜๋‹ค.\n */\nexport function shiftWindow(fromMs: number, toMs: number, basis: 'previous' | 'yesterday'): KpiWindow {\n const span = toMs - fromMs\n const back = basis === 'yesterday' ? 24 * 60 * 60_000 : span\n return { fromMs: fromMs - back, toMs: toMs - back }\n}\n\n/**\n * ์ค‘์•™๊ฐ’ ์ฐจ์ด(ํ˜„์žฌ โˆ’ ๋น„๊ต๊ตฌ๊ฐ„) โ€” **๋‘˜ ๋‹ค ์ธก์ •๋œ ๊ฒƒ๋งŒ** ๋‚ธ๋‹ค.\n *\n * ํ•œ์ชฝ์ด ๊ฒฐ์ธก์ด๋ฉด ์ฐจ์ด๋Š” **์—†๋Š” ๊ฒƒ**์ด๋‹ค(0 ์ด ์•„๋‹ˆ๋‹ค). 0 ์œผ๋กœ ๋‚ด๋ฉด \"๋ณ€ํ™” ์—†์Œ\" ์ด๋ผ๋Š” ๊ฑฐ์ง“์ด ๋œ๋‹ค.\n * ์ข‹๊ณ  ๋‚˜์จ์€ ํŒ๋‹จํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” ์ฒ˜๋ฆฌ๋Ÿ‰์€ ํด์ˆ˜๋ก, ์†Œ์š”๋Š” ์ž‘์„์ˆ˜๋ก ์ข‹๋‹ค๋Š” ํ•ด์„์€ ์†Œ๋น„์ฒ˜์˜ ๋ชซ์ด๋‹ค.\n */\nexport function deltaP50(now: DurationStats, prev: DurationStats): number | undefined {\n return now.count > 0 && prev.count > 0 ? now.p50Ms - prev.p50Ms : undefined\n}\n\n/** ๊ตฌ๊ฐ„ ํ•˜๋‚˜์˜ ์ตœ์†Œ ์š”์•ฝ โ€” ์ถ”์„ธ๋ฅผ ๊ทธ๋ฆด ์ •๋ณด๋งŒ(์ „์ฒด KPI ๋ฅผ ๊ตฌ๊ฐ„๋งˆ๋‹ค ์‹ค์–ด ๋ณด๋‚ด์ง€ ์•Š๋Š”๋‹ค). */\nexport interface KpiBucket {\n fromMs: number\n toMs: number\n tasks: number\n orders: number\n /** ๊ทธ ๊ตฌ๊ฐ„์˜ ์ž‘์—…์‹œ๊ฐ„ ์ค‘์•™๊ฐ’ โ€” ์ถ”์„ธ์—์„œ \"๋А๋ ค์ง€๊ณ  ์žˆ๋Š”๊ฐ€\" ๋ฅผ ๋ณด๋Š” ๊ฐ’. */\n workP50Ms: number\n}\n\n/**\n * ์ฐฝ์„ N ๋“ฑ๋ถ„ํ•ด ๊ตฌ๊ฐ„๋ณ„๋กœ ์ ‘๋Š”๋‹ค โ€” **๊ฐ™์€ ์ด๋ฒคํŠธ๋ฅผ ์ฐฝ๋งŒ ๋ฐ”๊ฟ”** ๋‹ค์‹œ ์ ‘๋Š”๋‹ค(์กฐํšŒ ์ถ”๊ฐ€ ์—†์Œ).\n *\n * ๋งˆ์ง€๋ง‰ ๊ตฌ๊ฐ„์€ ๋‚˜๋จธ์ง€๋ฅผ ํก์ˆ˜ํ•œ๋‹ค(๋ถ€๋™์†Œ์ˆ˜ ๋‚˜๋ˆ—์…ˆ์œผ๋กœ ๋์ด ๋ฐ€๋ฆฌ๋ฉด ๋งˆ์ง€๋ง‰ ์™„๋ฃŒ๊ฐ€ ๋น ์ง„๋‹ค).\n * `count <= 1` ์ด๋ฉด ์ชผ๊ฐค ๊ฒƒ์ด ์—†์œผ๋ฏ€๋กœ ๋นˆ ๋ฐฐ์—ด โ€” ํ˜ธ์ถœ๋ถ€๊ฐ€ \"์ถ”์„ธ ์—†์Œ\" ์œผ๋กœ ๋‹ค๋ฃฌ๋‹ค.\n */\nexport function foldKpiBuckets(events: KpiEvent[], window: KpiWindow, count: number): KpiBucket[] {\n const n = Math.max(0, Math.min(48, Math.floor(count)))\n if (n <= 1) return []\n const step = (window.toMs - window.fromMs) / n\n const out: KpiBucket[] = []\n for (let i = 0; i < n; i++) {\n const fromMs = window.fromMs + step * i\n const toMs = i === n - 1 ? window.toMs : window.fromMs + step * (i + 1)\n const b = foldKpi(events, { fromMs, toMs })\n out.push({ fromMs, toMs, tasks: b.throughput.tasks, orders: b.throughput.orders, workP50Ms: b.workTime.p50Ms })\n }\n return out\n}\n"]}
1
+ {"version":3,"file":"kpi-fold.js","sourceRoot":"","sources":["../../server/engine/kpi-fold.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;AAgmBH,0BAwIC;AAyBD,kCAkBC;AAcD,kCAIC;AAQD,4BAEC;AAkBD,wCAYC;AA30BD;;;;;GAKG;AACH,sDAY6B;AA6M7B;;;;;;;;;;;;;GAaG;AACH,SAAS,YAAY,CACnB,GAAuB,EACvB,WAAqD,EACrD,cAAuC;IAEvC,uDAAuD;IACvD,IAAI,CAAC,cAAc,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,MAAM;QAAE,OAAO,EAAE,CAAA;IACrE,IAAI,GAAG,KAAK,SAAS,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;QAAE,OAAO,EAAE,CAAA;IAE9C;;;;;;;;;;OAUG;IACH;;;;;;OAMG;IACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IACtE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAS,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;IAC/E,MAAM,SAAS,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;IAC3E,IAAI,CAAC,SAAS,CAAC,MAAM;QAAE,OAAO,EAAE,CAAA;IAEhC,MAAM,CAAC,GAAG,IAAA,6BAAe,EAAC;QACxB,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QACxE,SAAS;QACT,UAAU,EAAE,WAAW;KACxB,CAAC,CAAA;IAEF,MAAM,KAAK,GAAG,IAAI,GAAG,EAAsE,CAAA;IAC3F,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;QAC1B,8DAA8D;QAC9D,MAAM,GAAG,GAAG,cAAc,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,SAAS,CAAA;QACtD,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,CAAA;QAC5E,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,CAAA;QACjB,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,WAAW,IAAI,CAAC,CAAA;QACtC;8DACsD;QACtD,IAAI,EAAE,CAAC,KAAK,KAAK,aAAa;YAAE,GAAG,CAAC,WAAW,GAAG,IAAI,CAAA;QACtD,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;IACrB,CAAC;IAED,MAAM,QAAQ,GAAG,CAAC,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;SAClC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAClB,GAAG;QACH,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,KAAK,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAA+B;QACjF,UAAU,EAAE,WAAoB;QAChC,WAAW,EAAE,CAAC,CAAC,WAAW;KAC3B,CAAC,CAAC;SACF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;IAEhC,MAAM,EAAE,GAAG,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;IAC5D,OAAO;QACL,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,EAAE,EAAE,kBAAkB,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzF,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACvE,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,SAAS,eAAe,CACtB,OAMG,EACH,KAAyC,EACzC,QAA4B,EAC5B,WAAoC;IAEpC,IAAI,CAAC,WAAW,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM;QAAE,OAAO,SAAS,CAAA;IACtE,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC;QAAE,OAAO,SAAS,CAAA;IAE/D,sDAAsD;IACtD,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAA;IAC7C,IAAI,SAAS,GAAG,KAAK,CAAA;IACrB,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC;YAAE,SAAQ;QACrE,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;YAChC,IAAI,CAAC,MAAM;gBAAE,SAAQ,CAAC,6BAA6B;YACnD,SAAS,GAAG,IAAI,CAAA;YAChB,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;QACjE,CAAC;IACH,CAAC;IACD,IAAI,CAAC,SAAS;QAAE,OAAO,SAAS,CAAA,CAAC,kCAAkC;IAEnE,MAAM,OAAO,GAAG,CAAC,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAA;IACvE,IAAI,CAAC,OAAO,CAAC,MAAM;QAAE,OAAO,SAAS,CAAA;IACrC,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC,CAAC,CAAA;IACjE,MAAM,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAA;IAEvC,MAAM,CAAC,GAAG,IAAA,6BAAe,EAAC;QACxB,KAAK,EAAE;YACL,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,MAAM,QAAQ,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC/F,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,GAAG,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SAC5G;QACD,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;KACvD,CAAC,CAAA;IAEF;;;;;;OAMG;IACH,MAAM,UAAU,GAAG,OAAO;SACvB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;SACrG,MAAM,CAAuC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAA;IACnI,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAA;IACxC,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,YAAY,IAAI,EAAE,EAAE,CAAC;QAC/C,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QAChC,IAAI,CAAC,MAAM;YAAE,SAAQ,CAAC,6BAA6B;QACnD,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAA;IACtD,CAAC;IAED,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM;SACtB,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACV,GAAG,EAAE,EAAE,CAAC,UAAU;QAClB,GAAG,EAAE,EAAE,CAAC,GAAG;QACX,KAAK,EAAE,EAAE,CAAC,KAAK;QACf,UAAU,EAAE,SAAS;QACrB,WAAW,EAAE,SAAS;QACtB,uDAAuD;QACvD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5E,CAAC,CAAC;SACF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAiD,CAAA;IAEhF,MAAM,EAAE,GAAG,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;IAC5D,OAAO;QACL,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,EAAE,EAAE,kBAAkB,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzF,uDAAuD;QACvD,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5D,CAAA;AACH,CAAC;AAoED,+DAA+D;AAC/D,SAAS,QAAQ,CAAC,GAAqB,EAAE,OAAuB;IAC9D,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAA;IACpB,QAAQ,OAAO,CAAC,OAAO,EAAE,CAAC;QACxB,KAAK,UAAU;YACb,OAAO,CAAC,CAAC,QAAQ,IAAI,SAAS,CAAA;QAChC,KAAK,UAAU;YACb,OAAO,CAAC,CAAC,IAAI,IAAI,SAAS,CAAA;QAC5B,KAAK,UAAU;YACb,OAAO,CAAC,CAAC,QAAQ,IAAI,SAAS,CAAA;QAChC,KAAK,OAAO;YACV,OAAO,CAAC,CAAC,KAAK,IAAI,SAAS,CAAA;QAC7B,KAAK,MAAM;YACT;iCACqB;YACrB,OAAO,CAAC,CAAC,CAAC,QAAQ,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,SAAS,CAAA;QACxE,KAAK,OAAO;YACV;;;;;;;;;eASG;YACH,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM;gBAAE,OAAO,SAAS,CAAA;YAC7C;iDACqC;YACrC,OAAO,IAAA,2BAAa,EAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,gBAAgB,CAAC,IAAI,SAAS,CAAA;QACrF;YACE,OAAO,SAAS,CAAA;IACpB,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAS,SAAS,CAAC,IAAwB;IACzC,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAA;QAC1B,IAAI,CAAC,KAAK,MAAM;YAAE,IAAI,EAAE,CAAA;aACnB,IAAI,CAAC,KAAK,OAAO;YAAE,KAAK,EAAE,CAAA;IACjC,CAAC;IACD,OAAO,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;AAC7D,CAAC;AAED;;;;;GAKG;AACH,SAAS,YAAY,CACnB,OAA2B,EAC3B,OAAuB;IAEvB,MAAM,EAAE,GAAG,OAAO,CAAC,OAAqB,CAAA;IACxC,MAAM,IAAI,GAAG,IAAI,GAAG,EAA8B,CAAA;IAClD,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QAClC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACzB,IAAI,GAAG;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;;YACjB,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;IAC3B,CAAC;IAED,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;SAC5B,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QACrB,GAAG;QACH,KAAK,EAAE,IAAI,CAAC,MAAM;QAClB,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;QACpF,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;QACpF,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;QACpF,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;QACrD,GAAG,SAAS,CAAC,IAAI,CAAC;KACnB,CAAC,CAAC;SACF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAEhE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,CAAA;IAClE,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;IACjC,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAChC;oEACgE;IAChE,OAAO;QACL,EAAE;QACF,KAAK;QACL,GAAG,CAAC,OAAO,CAAC,MAAM;YAChB,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE;YACzF,CAAC,CAAC,EAAE,CAAC;KACR,CAAA;AACH,CAAC;AAED,SAAS,EAAE,CAAC,KAAyB;IACnC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACvB,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAC3B,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AACtC,CAAC;AAED,4DAA4D;AAC5D,SAAS,QAAQ,CAAC,MAAgB,EAAE,CAAS;IAC3C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAA;IACjC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IACnF,OAAO,MAAM,CAAC,GAAG,CAAC,CAAA;AACpB,CAAC;AAED,SAAS,KAAK,CAAC,MAAgB;IAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAA;IACpF,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IAChD,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;IAC7C,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,MAAM;QACpB,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC;QAC5B,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC;QAC5B,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC;QAC5B,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC;KACvC,CAAA;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,OAAO,CAAC,MAAkB,EAAE,MAAiB,EAAE,UAA0B,EAAE;IACzF,gEAAgE;IAChE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,IAAA,6BAAe,EAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,aAAa,CAAC,CAAC,CAAA;IAC7F,IAAI,eAAe,GAAG,CAAC,CAAA;IACvB,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,IAAI,QAAQ,GAAG,CAAC,CAAA;IAEhB,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;QAC1B,IAAI,EAAE,KAAK,IAAI;YAAE,SAAQ;QACzB,IAAI,EAAE,CAAA;QACN,IAAI,EAAE,IAAI,MAAM,CAAC,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC,IAAI;YAAE,QAAQ,EAAE,CAAA;QACxD,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,CAAC,OAAO,IAAI,EAAE,CAAA;QAE5C,IAAI,CAAC,CAAC,SAAS,KAAK,cAAc,EAAE,CAAC;YACnC;kDACsC;YACtC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAA;YACnD,IAAI,EAAE,IAAI,MAAM,CAAC,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW,IAAI,MAAM,KAAK,WAAW,IAAI,MAAM,KAAK,MAAM,CAAC,EAAE,CAAC;gBACxH,eAAe,EAAE,CAAA;YACnB,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,MAAM,aAAa,GAAG,MAAM;SACzB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,0BAAY,CAAC,YAAY,CAAC;SACtD,GAAG,CAAC,CAAC,CAAC,EAAE;QACP,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,CAAC,OAAO,IAAI,EAAE,CAAA;QAC5C;gEACwD;QACxD,OAAO;YACL,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;YAC1B,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;YACtB,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;YACxB,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;YACtB,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC;YAChC;yDAC6C;YAC7C,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;iBAC9C,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,KAAK,IAAI,EAAE,CAAC,CAAC;iBAC3F,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACrD,oEAAoE;YACpE,YAAY,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;iBAChE,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;iBACjE,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SACrD,CAAA;IACH,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAA;IAEtE,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,MAAM,cAAc,GAAG,IAAI,GAAG,EAAkB,CAAA;IAChD;uDACmD;IACnD,MAAM,OAAO,GAAuB,EAAE,CAAA;IACtC,IAAI,aAAa,GAAG,CAAC,CAAA;IACrB,IAAI,YAAY,GAAG,CAAC,CAAA;IACpB,IAAI,YAAY,GAAG,CAAC,CAAA;IAEpB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,SAAS,GAAG,CAAC,CAAC,WAAW,CAAA;QAC/B,IAAI,SAAS,KAAK,SAAS;YAAE,SAAQ,CAAC,6BAA6B;QACnE,IAAI,SAAS,GAAG,MAAM,CAAC,MAAM,IAAI,SAAS,GAAG,MAAM,CAAC,IAAI;YAAE,SAAQ,CAAC,iBAAiB;QACpF,aAAa,EAAE,CAAA;QACf,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAA;QACrB,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAA;QACrB,MAAM,GAAG,GAAqB,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAA;QACnF,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAA;QACpC,IAAI,CAAC,KAAK,SAAS,IAAI,SAAS,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,CAAA;;YAC1E,YAAY,EAAE,CAAA;QACnB,IAAI,CAAC,KAAK,SAAS,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,SAAS,GAAG,CAAC,CAAA;YAC1B,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAA;YAC/B,IAAI,QAAQ;gBAAE,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;QACxF,CAAC;aAAM,CAAC;YACN,YAAY,EAAE,CAAA;QAChB,CAAC;QACD,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;QAClF,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACnB,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAA;IACrD,MAAM,WAAW,GAAG,CAAC,GAAG,cAAc,CAAC,OAAO,EAAE,CAAC;SAC9C,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC;SAC1F,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAA;IAEtC,OAAO;QACL,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE;QACpD,UAAU,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,eAAe,EAAE;QAC7D,GAAG,CAAC,aAAa,CAAC,MAAM;YACtB,CAAC,CAAC,CAAC,GAAG,EAAE;gBACJ,MAAM,CAAC,GAAG,IAAA,6BAAe,EAAC,aAAa,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;gBACxF,+DAA+D;gBAC/D,MAAM,CAAC,GAAG,IAAA,6BAAe,EAAC;oBACxB,GAAG,EAAE,CAAC,CAAC,GAAG;oBACV,YAAY,EAAE,CAAC,CAAC,MAAM;oBACtB,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;iBAC1E,CAAC,CAAA;gBACF,OAAO;oBACL,MAAM,EAAE;wBACN,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;wBAC9C,sDAAsD;wBACtD,GAAG,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;wBACnF,4DAA4D;wBAC5D,GAAG,CAAC,CAAC,CAAC,WAAW,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS;4BACvD,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;4BAC7G,CAAC,CAAC,EAAE,CAAC;wBACP,KAAK,EAAE,CAAC,CAAC,KAAK;wBACd,OAAO,EAAE,CAAC,CAAC,OAAO;wBAClB,OAAO,EAAE,CAAC,CAAC,OAAO;wBAClB,SAAS,EACP,CAAC,CAAC,KAAK,KAAK,IAAI;4BACd,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAG,CAAS,CAAC,MAAM,EAAE;4BAC5C,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAG,CAAS,CAAC,IAAI,EAAE;wBAC/C,GAAG,CAAC,eAAe,CAAC,aAAa,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC,WAAW,CAAC;4BAC5G,YAAY,CAAC,CAAC,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;wBAC3D,mDAAmD;wBACnD,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAA,6BAAe,EAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;qBAC/G;iBACF,CAAA;YACH,CAAC,CAAC,EAAE;YACN,CAAC,CAAC,EAAE,CAAC;QACP,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC;QACtB,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC;QACtB,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC;QACtB,WAAW;QACX,QAAQ,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE;QAC5D,UAAU,EAAE,IAAI;QAChB,cAAc,EAAE,QAAQ;QACxB,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACvE,CAAA;AACH,CAAC;AAyBD,SAAgB,WAAW,CACzB,GAAe,EACf,IAAgB;IAEhB,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;IACjD,MAAM,KAAK,GAAmB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;QACxC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;QAC3B,IAAI,CAAC,CAAC;YAAE,OAAO,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;QACpC,OAAO;YACL,GAAG,CAAC;YACJ,SAAS,EAAE,CAAC,CAAC,KAAK;YAClB,UAAU,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK;YAC7B,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAChH,CAAA;IACH,CAAC,CAAC,CAAA;IACF,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IAC5C,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;IACpG,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,CAAA;AAC/B,CAAC;AAED;;;;GAIG;AAEH;;;;;GAKG;AACH,SAAgB,WAAW,CAAC,MAAc,EAAE,IAAY,EAAE,KAA+B;IACvF,MAAM,IAAI,GAAG,IAAI,GAAG,MAAM,CAAA;IAC1B,MAAM,IAAI,GAAG,KAAK,KAAK,WAAW,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAA;IAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,CAAA;AACrD,CAAC;AAED;;;;;GAKG;AACH,SAAgB,QAAQ,CAAC,GAAkB,EAAE,IAAmB;IAC9D,OAAO,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;AAC7E,CAAC;AAYD;;;;;GAKG;AACH,SAAgB,cAAc,CAAC,MAAkB,EAAE,MAAiB,EAAE,KAAa;IACjF,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACtD,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAA;IACrB,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IAC9C,MAAM,GAAG,GAAgB,EAAE,CAAA;IAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,GAAG,IAAI,GAAG,CAAC,CAAA;QACvC,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;QACvE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;QAC3C,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;IACjH,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC","sourcesContent":["/*\n * ์—…๋ฌด KPI ํด๋“œ โ€” **์ด๋ฒคํŠธ ์ €๋„์„ ์ ‘์–ด** ์‹œ๊ฐ„์ฐฝ ์ง€ํ‘œ๋ฅผ ๋งŒ๋“ ๋‹ค(์ˆœ์ˆ˜).\n *\n * โ”€โ”€ ์™œ ํ•„์š”ํ•œ๊ฐ€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ง€๊ธˆ ํŠธ์œˆ์ด ๋‹ตํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ \"์ด ์ˆœ๊ฐ„์˜ ๊ฐ’\"(์ ์œ  92%)๊ณผ \"์ธํ”„๋ผ ๋ถ€ํ•˜\"(์ดˆ๋‹น ์ด๋ฒคํŠธ ์ˆ˜)๋ฟ์ด๋‹ค.\n * ์šด์˜์ด ๋ฌป๋Š” ๊ฒƒ์€ ๋‹ค๋ฅด๋‹ค โ€” **์ง€๋‚œ ํ•œ ์‹œ๊ฐ„์— ๋ช‡ ๊ฑด ์ฒ˜๋ฆฌํ–ˆ๋‚˜, ํ•œ ๊ฑด์— ์–ผ๋งˆ๋‚˜ ๊ฑธ๋ฆฌ๋‚˜, ์ž์›์€ ์–ผ๋งˆ๋‚˜\n * ์ผํ–ˆ๋‚˜.** ๊ทธ ๊ฐ’์ด ์—†์œผ๋ฉด AI ๋Š” \"์ ์œ  92%\" ๋Š” ๋งํ•ด๋„ \"๋ชฉํ‘œ๋ณด๋‹ค ๋‚˜์œ๊ฐ€\" ๋Š” ๋‹ตํ•  ์ˆ˜ ์—†๋‹ค.\n *\n * โ”€โ”€ ์›๋ฃŒ๋Š” ์ด๋ฏธ ์žˆ๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ €๋„(`TwinEvent`)์— `task.status`ยท`order.status`ยท`equipment.status` ์ „์ด๊ฐ€ `eventTime`(ISO)๊ณผ ํ•จ๊ป˜\n * append-only ๋กœ ์Œ“์ธ๋‹ค. ๊ทธ๋ž˜์„œ ์ƒˆ ๊ณ„์ธก์„ ์‹ฌ์„ ํ•„์š”๊ฐ€ ์—†๋‹ค โ€” **์ ‘๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.**\n * ๊ฐ™์€ ๋ชจ์–‘์˜ ์„ ๋ก€๊ฐ€ ์ด ํด๋”์— ์žˆ๋‹ค(`oee-accumulator.ts` โ€” equipment ์ „์ด๋ฅผ ์ ‘์–ด OEE ์นด์šดํ„ฐ ์ƒ์‚ฐ).\n *\n * โ”€โ”€ ์ด ํŒŒ์ผ์ด ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ยท ๋ชฉํ‘œ์™€ ๋น„๊ตํ•˜์ง€ ์•Š๋Š”๋‹ค. \"95% ๋ชฉํ‘œ ๋Œ€๋น„\" ๋Š” ๋ชฉํ‘œ๋ฅผ ์ €์žฅํ•˜๋Š” ๋ณ„๊ฐœ ์ธต(๊ฒฝ์˜ KPI)์˜ ๋ชซ์ด๊ณ ,\n * ์ด ์ธต์€ **์‚ฌ์‹ค๋งŒ** ์ƒ์‚ฐํ•œ๋‹ค. ๋‘ ์ธต์„ ์„ž์œผ๋ฉด ๋ชฉํ‘œ๋ฅผ ์ •์˜ํ•˜์ง€ ์•Š์€ ํ˜„์žฅ์€ ์‚ฌ์‹ค์กฐ์ฐจ ๋ชป ๋ณธ๋‹ค.\n * ยท ์ฒด๋ฅ˜์‹œ๊ฐ„(dwell)์€ ์•„์ง ๋‚ด์ง€ ์•Š๋Š”๋‹ค. ๋ฌผ๊ฑด์ด ๋…ธ๋“œ์— ๋จธ๋ฌธ ์‹œ๊ฐ„์€ item ๋‹จ์œ„ ์ด๋ฒคํŠธ(epcis.*)๋ฅผ\n * ์ง์ง€์–ด์•ผ ํ•˜๊ณ , ๊ทธ ์ง๋งž์ถค ๊ทœ์น™์ด ๋„๋ฉ”์ธ๋งˆ๋‹ค ๋‹ค๋ฅด๋‹ค. **์—†๋Š” ๊ฒƒ์„ 0 ์œผ๋กœ ๊พธ๋ฏธ์ง€ ์•Š๋Š”๋‹ค.**\n * ยท DBยท์ปค๋„์„ ๋ชจ๋ฅธ๋‹ค. ์ž…๋ ฅ์€ ํ‰๋ฒ”ํ•œ ๋ฐฐ์—ด์ด๊ณ  ์ถœ๋ ฅ์€ ํ‰๋ฒ”ํ•œ ๊ฐ์ฒด๋‹ค(ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ’์‹ธ๋‹ค).\n */\n\n/*\n * ์ง๋งž์ถค์€ **์ปค๋„์ด ์†Œ์œ ํ•œ๋‹ค**(`foldTaskRecords`). ์™„๋ฃŒ๋Š” ์ž‘์—…๋‹น ํ•˜๋‚˜ยท๋‚˜์ค‘ ๊ฒƒ์ด ์‚ฌ์‹ค, ์ฐฉ์ˆ˜๋Š” ์ฒ˜์Œ ๊ฒƒ,\n * ์ข…๋ฅ˜ยท์˜ค๋”๋Š” ์–ด๋А ์ „์ด์—์„œ๋“  โ€” ๊ทธ ๊ทœ์น™์€ ์ปค๋„ ์ƒํƒœ ๊ธฐ๊ณ„์—์„œ ๋‚˜์˜ค๋Š” ์ง€์‹์ด๋‹ค. ์—ฌ๊ธฐ์„œ ๋‹ค์‹œ ์ ์—ˆ๋”๋‹ˆ\n * ๊ณต์ • ํƒ€์ž„๋ผ์ธ๊ณผ **๋‹ค๋ฅธ ๋‹ต**์„ ๋ƒˆ๋‹ค(์žฌ์ „์†ก๋œ ์™„๋ฃŒ๋ฅผ ๋‘ ๊ฑด์œผ๋กœ ์„ธ์–ด ์ฒ˜๋ฆฌ๋Ÿ‰ยท์ ์œ ๊ฐ€ ๋ถ€ํ’€๋ ค์กŒ๋‹ค).\n * ์ด ํŒŒ์ผ์€ ์ด์ œ \"์ ‘ํžŒ ๊ธฐ๋ก โ†’ ์ฐฝ ์ง€ํ‘œ\" ๋งŒ ํ•œ๋‹ค.\n */\nimport {\n ENERGY_EVENT,\n attributeEnergy,\n electricityCost,\n energyIntensity,\n energyOfWindows,\n foldTaskRecords,\n activeShiftAt,\n type ElectricityCost,\n type TariffDeclaration,\n type TaskFacets,\n type WorkCalendarEntry\n} from '@operato/twin-kernel'\n\n/** ์ €๋„ ํ•œ ์ค„ โ€” ํ•„์š”ํ•œ ๊ฒƒ๋งŒ(์—”ํ‹ฐํ‹ฐยทtypeorm ๋น„์˜์กด). */\nexport interface KpiEvent {\n eventType?: string\n /** ISO ์‹œ๊ฐ. ํŒŒ์‹ฑ ๋ถˆ๊ฐ€ํ•˜๋ฉด ๊ทธ ์ค„์€ ๋ฒ„๋ฆฐ๋‹ค(์กฐ์šฉํžˆ 0 ์œผ๋กœ ์„ธ์ง€ ์•Š๋Š”๋‹ค). */\n eventTime?: string\n payload?: any\n}\n\nexport interface KpiWindow {\n /** ์ฐฝ์˜ ์‹œ์ž‘ยท๋(epoch ms). ์™„๋ฃŒ ์‹œ๊ฐ์ด ์ด ์•ˆ์— ๋“  ๊ฒƒ๋งŒ ์„ฑ๊ณผ๋กœ ์„ผ๋‹ค. */\n fromMs: number\n toMs: number\n}\n\nexport interface DurationStats {\n /** ์ง์ด ๋งž์•„ ๊ณ„์‚ฐ๋œ ๊ฑด์ˆ˜. */\n count: number\n /**\n * ํ•˜์œ„ ๊ผฌ๋ฆฌ โ€” **๋ถ„ํฌ๋ฅผ ์–‘์ชฝ์—์„œ ์ ‘์ง€ํ•˜๊ธฐ ์œ„ํ•ด** ๋‚ธ๋‹ค.\n * p50ยทp90 ๋งŒ ์žˆ์œผ๋ฉด ์•„๋ž˜์ชฝ ํผ์ง์„ ์œ„์ชฝ์—์„œ ๊ฑฐ์šธ์ฒ˜๋Ÿผ ๋ฒ ๊ปด ์“ธ ์ˆ˜๋ฐ–์— ์—†๋‹ค(๋ฐœ๋ช…). ๊ด€์ธก์ด ๋งํ•˜๊ฒŒ ํ•œ๋‹ค.\n */\n p10Ms: number\n p50Ms: number\n p90Ms: number\n avgMs: number\n}\n\n/**\n * ๊ด€์  ์ถ• โ€” **๊ฐ™์€ ์‚ฌ์‹ค์„ ๋‹ค๋ฅธ ๊ฐ์œผ๋กœ** ๋ณธ๋‹ค.\n *\n * ๊ณ ์ •๋œ ํ•œ ๋ Œ์ฆˆ(์ž์›๋ณ„)๋งŒ ๋‚ผ ์ˆ˜ ์žˆ์œผ๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ \"๊ตฌ์—ญ๋ณ„๋กœ๋Š”?\" ์ด๋ผ๊ณ  ๋ฌผ์–ด๋„ ๋‹ต์ด ์—†๋‹ค. ์‚ฌ์‹ค ๊ณ„์‚ฐ์ด\n * ์ถ•์„ ๋ชป ๋‚ด๋ฉด AI ๋„ ๋ชป ๋‚ธ๋‹ค โ€” ๊ทธ๋ž˜์„œ ์ถ•์€ ๊ณ„์‚ฐ ์ธต์˜ ๋Šฅ๋ ฅ์ด์–ด์•ผ ํ•œ๋‹ค.\n *\n * resource ์ž์›๋ณ„(๋ˆ„๊ฐ€ ํ–ˆ๋‚˜) taskKind ์ž‘์—… ์ข…๋ฅ˜๋ณ„(๋ฌด์—‡์„ ํ–ˆ๋‚˜)\n * location ๋„์ฐฉ ์ง€์ ๋ณ„(์–ด๋””์„œ) order ์˜ค๋”๋ณ„(๋ฌด์—‡์„ ์œ„ํ•ด)\n * area ๊ตฌ์—ญ๋ณ„ โ€” ๋…ธ๋“œโ†’๊ตฌ์—ญ ์ง€๋„๊ฐ€ ํ•„์š”ํ•˜๋‹ค(์ด๋ฒคํŠธ์— ์—†๋‹ค. ํ˜ธ์ถœ๋ถ€๊ฐ€ ์ค€๋‹ค)\n * shift ๊ต๋Œ€๋ณ„(์–ธ์ œ) โ€” ์™„๋ฃŒ ์‹œ๊ฐ + ํ˜„์žฅ์˜ ์‹œ๊ฐ ๊ธฐ์ค€์—์„œ **๊ณ„์‚ฐํ•œ๋‹ค**(์ด๋ฒคํŠธ์— ์—†๋‹ค)\n */\nexport type KpiGroupBy = 'resource' | 'taskKind' | 'location' | 'order' | 'area' | 'shift'\n\nexport interface KpiGroup {\n /** ์ถ•์˜ ๊ฐ’(์ž์› idยท์ž‘์—… ์ข…๋ฅ˜ยท๋…ธ๋“œ idยท์˜ค๋” idยท๊ตฌ์—ญ id). ๊ฐ’์ด ์—†๋˜ ๊ธฐ๋ก์€ 'unknown'. */\n key: string\n /** ์ด ์ถ•์—์„œ ์™„๋ฃŒ๋œ ๊ฑด์ˆ˜. */\n tasks: number\n leadTime: DurationStats\n workTime: DurationStats\n waitTime: DurationStats\n /** ์ด ์ถ•์— ๋ถ™์–ด ์žˆ๋˜ ์‹œ๊ฐ„์˜ ํ•ฉ(์ž์› ์ถ•์—์„œ ํŠนํžˆ ์˜๋ฏธ ์žˆ๋‹ค). */\n busyMs: number\n /**\n * **ํ’ˆ์งˆ ํŒ์ •์ด ์žˆ์—ˆ๋˜ ๊ฑด์ˆ˜๋งŒ** ์„ผ๋‹ค (2026-08-19).\n *\n * ํŒ์ •์ด ์—†๋Š” ์ž‘์—…(์ด๋™ยท์ฒด๋ฅ˜ยท์ค‘๊ฐ„ ์Šคํ…Œ์ด์…˜)์€ ์–ด๋А ์ชฝ์—๋„ ์„ธ์ง€ ์•Š๋Š”๋‹ค โ€” ๋ชจ๋ฆ„์„ ์–‘ํ’ˆ์œผ๋กœ ์„ธ๋ฉด ์–‘ํ’ˆ๋ฅ ์ด\n * ์กฐ์šฉํžˆ 100% ๋กœ ์˜ฌ๋ผ๊ฐ„๋‹ค. ๊ทธ๋ž˜์„œ `good + scrap` ์€ `tasks` ๋ณด๋‹ค ์ž‘์„ ์ˆ˜ ์žˆ๊ณ , ๊ทธ๊ฒƒ์ด ์ •์ƒ์ด๋‹ค.\n *\n * ํŒ์ •์ด ํ•˜๋‚˜๋„ ์—†์œผ๋ฉด **ํ•„๋“œ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค**(0/0 ์„ ใ€Œ์–‘ํ’ˆ๋ฅ  0%ใ€๋กœ ์ฝํžˆ๊ฒŒ ๋‘์ง€ ์•Š๋Š”๋‹ค).\n */\n quality?: { good: number; scrap: number }\n}\n\nexport interface KpiResult {\n window: { fromMs: number; toMs: number }\n /** ์ฐฝ ์•ˆ์— **์™„๋ฃŒ๋œ** ๊ฑด์ˆ˜ โ€” ์„ฑ๊ณผ๋Š” ์™„๋ฃŒ ์‹œ์ ์œผ๋กœ ์„ผ๋‹ค(์‹œ์ž‘ ์‹œ์ ์œผ๋กœ ์„ธ๋ฉด ์ง„ํ–‰ ์ค‘์ธ ๊ฒƒ์ด ์„ž์ธ๋‹ค). */\n throughput: { tasks: number; orders: number }\n /**\n * ์—๋„ˆ์ง€ โ€” **์ด ์ฐฝ์˜ ์ „๋ ฅ๋Ÿ‰๊ณผ ์›๋‹จ์œ„.** ์—๋„ˆ์ง€ ํŠธ์œˆ์ด ์—†์œผ๋ฉด `undefined`(0 ์ด ์•„๋‹ˆ๋‹ค).\n *\n * โ”€โ”€ ์™œ KPI ํด๋“œ ์•ˆ์— ์žˆ๋‚˜ (2026-08-14, ยง10 7๋‹จ๊ณ„) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์›๋‹จ์œ„๋Š” ๋ถ„์ž(์ „๋ ฅ๋Ÿ‰)์™€ ๋ถ„๋ชจ(์‚ฐ์ถœ)๋ฅผ **๊ฐ™์€ ์ฐฝ**์—์„œ ๋‚˜๋ˆˆ ๊ฐ’์ด๋‹ค. ์งˆ์˜๋ฅผ ๋”ฐ๋กœ ๋‘๋ฉด ๋‘ ์ฐฝ์„ ๋งž์ถ”๋Š”\n * ์ผ์ด ์†Œ๋น„์ฒ˜์˜ ๋ชซ์ด ๋˜๊ณ , ์–ด๊ธ‹๋‚œ ๋‘ ์‚ฌ์‹ค์„ ๋‚˜๋ˆˆ ์ˆซ์ž๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋œปํ•˜์ง€ ์•Š๋Š”๋‹ค(์ปค๋„์˜ ๊ทœ์น™์ด ๊ทธ๊ฒƒ์„\n * ๊ฑฐ์ ˆํ•œ๋‹ค). ๊ฐ™์€ ํด๋“œ ์•ˆ์— ๋‘๋ฉด ์ฐฝ์ด ํ•˜๋‚˜๋ฟ์ด๋ผ ์–ด๊ธ‹๋‚  ์ˆ˜ ์—†๋‹ค.\n *\n * ๋ถ„์ž๋Š” **์ €๋„์˜ ๊ตฌ๊ฐ„ ๋งˆ๊ฐ ์‚ฌ๊ฑด**์—์„œ ์˜จ๋‹ค(`energy.demand.window`) โ€” ์ปค๋„ ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๋ผ ์ €๋„์ด๋ฏ€๋กœ\n * ๋ฉˆ์ถ˜ ํŠธ์œˆยท๊ณผ๊ฑฐ ๊ตฌ๊ฐ„์—๋„ ๋‹ตํ•  ์ˆ˜ ์žˆ๋‹ค.\n */\n energy?: {\n /** ์ด ์ฐฝ์˜ ์ „๋ ฅ๋Ÿ‰. ์…€ ์ˆ˜ ์žˆ๋Š” ๊ตฌ๊ฐ„์ด ์—†์œผ๋ฉด `undefined`. */\n kWh?: number\n /**\n * ์ด ์ฐฝ์˜ **์ตœ๋Œ€์ˆ˜์š”**(kW)์™€ ๊ทธ๊ฒƒ์ด ๋‚œ ๊ตฌ๊ฐ„์˜ ์‹œ์ž‘.\n *\n * ์ „๋ ฅ๋Ÿ‰๊ณผ ๋‹ค๋ฅธ ์งˆ๋ฌธ์ด๋‹ค: ์ „๋ ฅ๋Ÿ‰์€ ์š”๊ธˆ์˜ ์‚ฌ์šฉ๋Ÿ‰ ๋ถ€๋ถ„์ด๊ณ , ์ตœ๋Œ€์ˆ˜์š”๋Š” **๊ธฐ๋ณธ์š”๊ธˆ**๊ณผ ๊ณ„์•ฝ ์œ„๋ฐ˜์„\n * ์ •ํ•œ๋‹ค. ํ‰๊ท ์œผ๋กœ ๊ฐˆ์Œํ•  ์ˆ˜ ์—†์–ด์„œ ์ปค๋„์ด ๊ตฌ๊ฐ„์˜ ์ตœ๋Œ€๋“ค ์ค‘ ๊ฐ€์žฅ ํฐ ๊ฐ’์„ ๋”ฐ๋กœ ๋‚ธ๋‹ค.\n */\n peakKW?: number\n peakStartMs?: number\n /**\n * ๊ทธ ํ”ผํฌ ๊ตฌ๊ฐ„์—์„œ **์„ค๋น„๊ฐ€ ๋Œ์–ด๋‹น๊ธด** ์ตœ๋Œ€(๋ฐœ์ „ยท๋ฐฉ์ „ ์ฐจ๊ฐ ์ „)์™€ ๊ทธ ์ฐจ์ด(๊นŽ์ธ ์–‘).\n *\n * ์š”๊ธˆ์€ ๊ณ„ํ†ต ์ˆ˜์š”(`peakKW`)๋กœ ๋งค๊ฒจ์ง€์ง€๋งŒ, ใ€Œ๋ฌด์—‡์ด ๊ทธ ์ˆ˜์š”๋ฅผ ๋งŒ๋“ค์—ˆ๋‚˜ใ€์™€ ใ€Œ๋ฌด์—‡์ด ๋œ์–ด๋ƒˆ๋‚˜ใ€๋Š”\n * ์ด ๋‘ ์ˆ˜์˜ ๊ฐ„๊ฒฉ์ด ๋‹ตํ•œ๋‹ค. ๋ฐœ์ „ยท์ถ•์ „์„ ์„ ์–ธํ•˜์ง€ ์•Š์€ ํ˜„์žฅ์—์„œ๋Š” ์—†๋‹ค(์ฐจ๊ฐํ•  ๊ฒƒ์ด ์—†๋‹ค).\n */\n peakGrossKW?: number\n shavedKW?: number\n /** ํŒŒ์ƒ์˜ ๊ทผ๊ฑฐ โ€” ๊ตฌ๊ฐ„ ํ‰๊ท ๋ถ€ํ•˜ ร— ๊ธธ์ด(`mean-kw`). */\n basis: string\n /** ์„ผ ๊ตฌ๊ฐ„ ์ˆ˜ ยท ๋ชป ์„ผ ๊ตฌ๊ฐ„ ์ˆ˜(๊ณ„์ธก์ด ๋Š๊ธด ๊ตฌ๊ฐ„) โ€” ์กฐ์šฉํžˆ ์ž๋ฅด์ง€ ์•Š๋Š”๋‹ค. */\n counted: number\n skipped: number\n /** ์™„๋ฃŒ ์˜ค๋”๋‹น ์ „๋ ฅ๋Ÿ‰ โ€” ๋‹ตํ•  ์ˆ˜ ์—†์œผ๋ฉด `null` ๊ณผ ์ด์œ . */\n intensity: { value: number | null; unit?: string; reason?: string }\n /**\n * ๋ฐฐ์ „ ๊ณ„ํ†ต์˜ **์ž๋ฆฌ๋ณ„ ๋ชซ** โ€” ใ€Œ์ด ๋ถ„๊ธฐ๊ฐ€ ์–ผ๋งˆ ์ผ๋‚˜ใ€.\n *\n * โ”€โ”€ ์ด๊ฒƒ์€ ์ธก์ •์ด ์•„๋‹ˆ๋ผ ๋ฐฐ๋ถ„์ด๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ €๋„์— ์žˆ๋Š” ์—๋„ˆ์ง€ ์‚ฌ์‹ค์€ **ํ˜„์žฅ ์ด๋Ÿ‰ ํ•œ ์ค„**์ด๋‹ค(๋ฟŒ๋ฆฌ ๊ณ„๋Ÿ‰๊ธฐ ํ•ฉ). ๊ณ„๋Ÿ‰๊ธฐ๋ณ„ ๊ตฌ๊ฐ„ ์‚ฌ์‹ค์ด ์—†์œผ๋ฏ€๋กœ\n * ์ž๋ฆฌ๋ณ„ ๋ชซ์€ **๋‚˜๋ˆˆ ๊ฒƒ**์ด๊ณ , ๋ฌด์—‡์œผ๋กœ ๋‚˜๋ˆด๋Š”์ง€(`weightKind`)๋ฅผ ๊ฐ’๊ณผ ํ•จ๊ป˜ ๋‚ธ๋‹ค. ๊ทผ๊ฑฐ๋ฅผ ๊ฐ์ถ”๋ฉด\n * ๋‚˜๋ˆˆ ์ˆซ์ž๊ฐ€ ์žฐ ์ˆซ์ž์™€ ๊ฐ™์€ ๋ฌด๊ฒŒ๋กœ ์ฝํžŒ๋‹ค โ€” CBAMยทESG ๋ณด๊ณ ์—์„œ ์ฒซ ์งˆ๋ฌธ์— ๊นจ์ง€๋Š” ์ง€์ ์ด๋‹ค.\n *\n * ๊ฐ€์ค‘์น˜๋Š” **์ž‘์—… ๊ฐ€๋™์‹œ๊ฐ„**์ด๋‹ค. ์ •๊ฒฉ(kW)์œผ๋กœ ๋‚˜๋ˆ„์ง€ ์•Š๋Š”๋‹ค: ์‹œ๋ฎฌ ํŠธ์œˆ์˜ ์ด๋ถ€ํ•˜๊ฐ€ ์ •๊ฒฉ์˜ ํ•ฉ์œผ๋กœ\n * ํŒŒ์ƒ๋˜๋ฏ€๋กœ, ๊ทธ ์ด๋Ÿ‰์„ ๋‹ค์‹œ ์ •๊ฒฉ์œผ๋กœ ๋‚˜๋ˆ„๋ฉด ๋„ฃ์€ ๊ฐ’์ด ๊ทธ๋Œ€๋กœ ๋‚˜์˜ค๋Š” ๋™์–ด๋ฐ˜๋ณต์ด ๋œ๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ ์ด ๊ฐ’์—๋Š” **๊ฐ€์ •์ด ํ•˜๋‚˜ ์‹ค๋ ค ์žˆ๋‹ค**: ์ „๊ธฐ๊ฐ€ ๊ฐ€๋™์‹œ๊ฐ„์— ๋น„๋ก€ํ•œ๋‹ค. ๊ณต์กฐยท์กฐ๋ช…์ฒ˜๋Ÿผ ๊ณต์ •์—\n * ๋ถ™์ง€ ์•Š๋Š” ๋ถ€ํ•˜๋„ ๊ทธ ๋น„์œจ์— ์„ž์ธ๋‹ค โ€” ํ™”๋ฉด์ด ๊ทธ ๋ฌธ์žฅ์„ ํ•จ๊ป˜ ๋งํ•ด์•ผ ํ•œ๋‹ค.\n */\n byFeeder?: {\n /** ์ž๋ฆฌ(๋ถ„๊ธฐยท์ˆ˜์ „) id. ์ž๋ฆฌ๋ฅผ ๋ชจ๋ฅด๋Š” ์ž์›์€ `unknown` ์œผ๋กœ ๋ชจ์ธ๋‹ค(์กฐ์šฉํžˆ ๋ฒ„๋ฆฌ์ง€ ์•Š๋Š”๋‹ค). */\n key: string\n kWh: number\n /**\n * ์ด ๋ชซ์˜ ๊ทผ๊ฑฐ โ€” **์ปค๋„์ด ์ •ํ•œ๋‹ค.**\n *\n * ์„ ์–ธ๋œ ๋ถ€ํ•˜๊ฐ€ ์—ฌ๋Ÿฟ์ด๋ฉด ๋ฐฐ๋ถ„(`apportioned`)์ด๋‹ค. ์„ ์–ธ๋œ ๋ถ€ํ•˜๊ฐ€ **ํ•˜๋‚˜๋ฟ์ธ** ํ˜„์žฅ์—์„œ๋Š” ์ปค๋„์ด\n * ใ€Œ๊ทธ ๊ณ„๋Ÿ‰๊ธฐ๋Š” ๊ทธ๊ฒƒ๋งŒ ์žฐ๋‹คใ€๊ณ  ์ฝ์–ด `measured` ๋ฅผ ๋‚ธ๋‹ค โ€” ๋ชจ๋ธ์ด ๊ทธ๋ ‡๊ฒŒ ๋งํ–ˆ์œผ๋ฏ€๋กœ ๊ทธ๊ฒƒ๋„ ์‚ฌ์‹ค์ด๋‹ค.\n * ์šฐ๋ฆฌ๊ฐ€ ์–ด๋А ์ชฝ์œผ๋กœ๋„ ๋‚™์ธ์ฐ์ง€ ์•Š๋Š”๋‹ค.\n */\n basis: 'apportioned' | 'measured'\n /**\n * ๋ฌด์—‡์œผ๋กœ ๋‚˜๋ˆด๋‚˜ โ€” **๋ฐฐ๋ถ„์ผ ๋•Œ๋งŒ** ์žˆ๋‹ค.\n *\n * ๋ถ„๊ธฐ๋งˆ๋‹ค ๊ณ„๋Ÿ‰๊ธฐ๊ฐ€ ์žˆ๋Š” ํ˜„์žฅ์—์„œ๋Š” ๋‚˜๋ˆ„์ง€ ์•Š๋Š”๋‹ค(๊ทธ ๊ฐ’์ด ๊ณง ๊ณ„๋Ÿ‰์ด๋‹ค). ๊ทธ๋•Œ ์ด ์นธ์„\n * `runtimeMs` ๋กœ ์ฑ„์šฐ๋ฉด ใ€Œ๊ฐ€๋™์‹œ๊ฐ„์œผ๋กœ ๋‚˜๋ˆด๋‹คใ€๋Š” ์—†๋Š” ์‚ฌ์‹ค์„ ๋งํ•˜๊ฒŒ ๋œ๋‹ค.\n */\n weightKind?: 'runtimeMs'\n /** ์ด ์ž๋ฆฌ์˜ ๋ชซ์ด ์ „์ฒด์˜ ์–ผ๋งˆ์˜€๋‚˜ โ€” ๋ฐฐ๋ถ„์ผ ๋•Œ๋งŒ. */\n weightShare?: number\n /**\n * **ํ”ผํฌ๊ฐ€ ์ฐํžŒ ์ˆœ๊ฐ„** ์ด ๋ถ„๊ธฐ๊ฐ€ ์–ผ๋งˆ์˜€๋‚˜(kW) โ€” ์š”๊ธˆ์ด ๊ฑธ๋ฆฐ ์ˆ˜๋‹ค.\n *\n * ์ฐฝ์˜ ํ‰๊ท ์ด๋‚˜ ํ•ฉ์ด ์•„๋‹ˆ๋‹ค: ์ตœ๋Œ€์ˆ˜์š”๋ฅผ ๋‚ธ ๊ตฌ๊ฐ„์˜ ๊ทธ ์ˆœ๊ฐ„ ๊ฐ’์ด๋‹ค(๋‹ค๋ฅธ ์ˆœ๊ฐ„์„ ์„ž์œผ๋ฉด ใ€Œ์–ด๋А ๋ถ„๊ธฐ๋ฅผ\n * ๊นŽ์•„์•ผ ํ”ผํฌ๊ฐ€ ๋‚ด๋ ค๊ฐ€๋‚˜ใ€์˜ ๋‹ต์ด ํ๋ ค์ง„๋‹ค). ๊ทธ ๊ตฌ๊ฐ„์— ์ด ๋ถ„๊ธฐ์˜ ํ‘œ๋ณธ์ด ์—†์—ˆ์œผ๋ฉด **์—†๋‹ค**.\n */\n peakKW?: number\n }[]\n /**\n * ๋‚˜๋ˆ„์ง€ ๋ชปํ•œ ์–‘๊ณผ ๊ทธ ์ด์œ  โ€” **์กฐ์šฉํžˆ 0 ์œผ๋กœ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค.**\n * `no-weights` = ๊ทธ ์ฐฝ์— ๋Œ์•„๊ฐ„ ์ž์›์ด ์—†๋‹ค(๊ฐ€๋™์‹œ๊ฐ„์ด ์ „๋ถ€ 0). ๊ทธ๋Ÿฌ๋ฉด ์ด๋Ÿ‰์€ ๊ทธ๋Œ€๋กœ ๋‚จ๋Š”๋‹ค.\n */\n unattributedKWh?: number\n /**\n * ์™œ ๋‚˜๋ˆ„์ง€ ๋ชปํ–ˆ๋‚˜(์ปค๋„ ์ฝ”๋“œ) โ€” `no-weights`(๊ฐ€๋™์‹œ๊ฐ„์ด ์ „๋ถ€ 0) ยท `no-consumers`(๋ฎ๋Š” ๋Œ€์ƒ ๋ฏธ์„ ์–ธ) ยท\n * `not-submetered`(๋ฟŒ๋ฆฌ์—์„œ ์žฌ์—ˆ์œผ๋‚˜ ํ•˜์œ„ ๊ณ„๋Ÿ‰์ด ๋ฎ์ง€ ์•Š๋Š” ๋ถ€๋ถ„ โ€” ๊ฒฐ์†์ด ์•„๋‹ˆ๋ผ ๊ณ„๋Ÿ‰ ๋ฒ”์œ„์˜ ์‚ฌ์‹ค).\n */\n unattributedReason?: string\n /**\n * ๋ถ„๊ธฐ ๊ณ„๋Ÿ‰์˜ ํ•ฉ์ด ๋ฟŒ๋ฆฌ ๊ณ„๋Ÿ‰๋ณด๋‹ค **ํฐ** ์–‘ โ€” ๋‘ ๊ณ„๋Ÿ‰๊ธฐ์˜ ํšŒ๊ณ„๊ฐ€ ๋‹ค๋ฅด๋‹ค๋Š” ์‚ฌ์‹ค์ด๋‹ค.\n *\n * ๊ฐ’์„ ๊นŽ์•„ ๋งž์ถ”์ง€ ์•Š๋Š”๋‹ค: ๊ทธ๊ฒƒ์€ ๊ณ„๋Ÿ‰์„ ์šฐ๋ฆฌ๊ฐ€ ๊ณ ์ณ ์“ฐ๋Š” ์ผ์ด๊ณ , ์–ด๋А ์ชฝ์ด ๋งž๋Š”์ง€๋Š” ํ˜„์žฅ์ด ์•ˆ๋‹ค.\n */\n submeterExcessKWh?: number\n /**\n * ๋ฐฐ๋ถ„์—์„œ **๋น ์ง„ ์ž์› ์ˆ˜** โ€” ๊ทธ ์ฐฝ์— ๊ฐ€๋™ ๊ธฐ๋ก์ด ์—†๋Š” ์„ค๋น„๋‹ค. 0kWh ๋ฅผ ์ฃผ์ง€ ์•Š๋Š” ๋Œ€์‹  ๋ช‡ ๋Œ€๊ฐ€\n * ๋น ์กŒ๋Š”์ง€ ์„ผ๋‹ค(๋Œ€๊ธฐ์ „๋ ฅ์ด ์žˆ๋Š” ์„ค๋น„์—์„œ 0 ์€ ๊ณง ๊ฑฐ์ง“์ด๋‹ค).\n */\n excludedResources?: number\n /**\n * ์ด ์ฐฝ์˜ ์ „๊ธฐ์š”๊ธˆ โ€” **์ฒญ๊ตฌ์„œ๊ฐ€ ์•„๋‹ˆ๋‹ค.** ๊ณ„์‚ฐ๊ณผ ๊ทธ ํ•œ๊ณ„(TOUยท๋ž˜์นซยท์ตœ์†Œ์ฒญ๊ตฌ์•ก ๋ฏธ๋ชจ๋ธ)๋Š” ์ปค๋„\n * (`electricityCost`)์ด ๊ฐ–๊ณ  ์—ฌ๊ธฐ์„œ๋Š” ๋‚˜๋ฅธ๋‹ค. ๋‹จ๊ฐ€๊ฐ€ ์—†์œผ๋ฉด `reason: 'no-tariff'` ๋กœ ์˜จ๋‹ค.\n */\n cost?: ElectricityCost\n }\n /** ๋ฆฌ๋“œํƒ€์ž„ โ€” ์ƒ์„ฑ(created)์—์„œ ์™„๋ฃŒ๊นŒ์ง€. ์‚ฌ์šฉ์ž๊ฐ€ ์ฒด๊ฐํ•˜๋Š” ์†Œ์š” ์‹œ๊ฐ„. */\n leadTime: DurationStats\n /** ์ž‘์—…์‹œ๊ฐ„ โ€” ์ฐฉ์ˆ˜(in-progress)์—์„œ ์™„๋ฃŒ๊นŒ์ง€. ๋Œ€๊ธฐ๋ฅผ ๋บ€ ์‹ค์ž‘์—…. */\n workTime: DurationStats\n /** ๋Œ€๊ธฐ์‹œ๊ฐ„ โ€” ์ƒ์„ฑ์—์„œ ์ฐฉ์ˆ˜๊นŒ์ง€. ์ž์›์ด ๋ถ€์กฑํ•˜๋ฉด ์—ฌ๊ธฐ๊ฐ€ ๋Š˜์–ด๋‚œ๋‹ค. */\n waitTime: DurationStats\n /** ์ž์›๋ณ„ ์ ์œ  โ€” ์ž‘์—…์— ๋ถ™์–ด ์žˆ๋˜ ์‹œ๊ฐ„์˜ ํ•ฉ๊ณผ ์ฐฝ ๋Œ€๋น„ ๋น„์œจ(์ž‘์—…์œผ๋กœ ์„ค๋ช…๋˜๋Š” ๋ถ€๋ถ„๋งŒ). */\n utilization: { resourceId: string; busyMs: number; ratio: number }[]\n /**\n * **์…ˆ์—์„œ ๋น ์ง„ ๊ฒƒ** โ€” ์™„๋ฃŒ๋Š” ์ฐฝ ์•ˆ์ด์ง€๋งŒ ์‹œ์ž‘ ์ด๋ฒคํŠธ๋ฅผ ๋ชป ์ฐพ์€ ๊ฑด์ˆ˜.\n * ์กฐํšŒ ๊ตฌ๊ฐ„์ด ์งง์•„ ์‹œ์ž‘์ด ์ž˜๋ ธ๊ฑฐ๋‚˜ ์ €๋„์ด ์œ ์‹ค๋œ ๊ฒฝ์šฐ๋‹ค. ์ด ๊ฐ’์„ ์ˆจ๊ธฐ๋ฉด ํ‰๊ท ์ด ์กฐ์šฉํžˆ ๊ฑฐ์ง“์ด ๋œ๋‹ค.\n */\n unpaired: { leadTime: number; workTime: number }\n /**\n * ์†Œ๋น„ํ•œ ์ด๋ฒคํŠธ ์ˆ˜ โ€” **๋„˜๊ฒจ๋ฐ›์€ ๋ฐฐ์—ด ์ „์ฒด**(์ฐฝ ์•ž lookback ํฌํ•จ). ์ง„๋‹จ์šฉ์ด๋‹ค.\n *\n * \"์ธก์ •๋œ ๊ธฐ๋ก์ด ์žˆ๋Š”๊ฐ€\" ์˜ ํŒ๋‹จ์—๋Š” ์“ฐ์ง€ ๋ง ๊ฒƒ โ€” ํ˜ธ์ถœ๋ถ€๋Š” ์ฐฝ๋ณด๋‹ค ์•ž๊นŒ์ง€ ์ฝ์–ด ๋„˜๊ธฐ๋ฏ€๋กœ(์™„๋ฃŒ๋œ ์ž‘์—…์˜\n * ์‹œ์ž‘์ด ์ฐฝ ๋ฐ–์ผ ์ˆ˜ ์žˆ๋‹ค) ์ฐฝ ์•ˆ์ด ๋น„์–ด ์žˆ์–ด๋„ ์ด ๊ฐ’์€ 0 ์ด ์•„๋‹ˆ๋‹ค. ๊ทธ ํŒ๋‹จ์€ `eventsInWindow` ๋กœ ํ•œ๋‹ค.\n */\n eventsSeen: number\n /**\n * **์ฐฝ ์•ˆ์—** ๋“ค์–ด์˜จ ์ด๋ฒคํŠธ ์ˆ˜ โ€” \"์ด ๊ตฌ๊ฐ„์— ์ธก์ •ํ•  ๊ธฐ๋ก์ด ์žˆ์—ˆ๋Š”๊ฐ€\" ์˜ ์ •๋‹ต.\n *\n * ์ด๊ฒƒ์ด 0 ์ด๋ฉด \"์ฒ˜๋ฆฌ๋Ÿ‰ 0\" ์ด ์•„๋‹ˆ๋ผ **\"๊ธฐ๋ก์ด ์—†๋‹ค\"** ๋‹ค. ๋‘ ์ƒํ™ฉ์„ ์„ž์œผ๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์ž˜๋ชป๋œ ๊ฒฐ๋ก ์„\n * ๋‚ธ๋‹ค(์•ž ๊ตฌ๊ฐ„์˜ ๊ธฐ๋ก๋งŒ ์ฝ์–ด ๋†“๊ณ  \"0๊ฑด ์ฒ˜๋ฆฌ\" ๋ผ๊ณ  ๋งํ•˜๋Š” ์ผ์ด ์‹ค์ œ๋กœ ๊ฐ€๋Šฅํ–ˆ๋‹ค).\n */\n eventsInWindow: number\n /** ์š”์ฒญํ•œ ๊ด€์ ์œผ๋กœ ์ชผ๊ฐ  ๊ฐ’(์š”์ฒญํ–ˆ์„ ๋•Œ๋งŒ). */\n groups?: { by: KpiGroupBy; items: KpiGroup[]; truncated?: number; truncatedTasks?: number }\n}\n\n/**\n * ์ฐฝ์˜ ์ „๋ ฅ๋Ÿ‰์„ **๋ฐฐ์ „ ๊ณ„ํ†ต์˜ ์ž๋ฆฌ๋ณ„๋กœ ๋‚˜๋ˆˆ๋‹ค** โ€” ๊ทผ๊ฑฐ๋ฅผ ํ•จ๊ป˜.\n *\n * โ”€โ”€ ์™œ ์ปค๋„ ํ•จ์ˆ˜๋ฅผ ์“ฐ๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ใ€Œ๋‚˜๋ˆŒ ๊ทผ๊ฑฐ๊ฐ€ ์—†์œผ๋ฉด ๋‚˜๋ˆ„์ง€ ์•Š๋Š”๋‹คใ€ยทใ€Œํ•ฉ์€ ๋ณด์กด๋œ๋‹คใ€ยทใ€Œ๋ชซ์ด 0 ์ด๋ฉด 0kWh ๋ฅผ ์ฃผ์ง€ ์•Š๋Š”๋‹คใ€๋Š” ๊ทœ์น™์ด\n * ์ปค๋„์˜ `attributeEnergy` ์— ์ด๋ฏธ ์žˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๋‹ค์‹œ ์“ฐ๋ฉด ๋‘ ๋ฒŒ์ด ๋˜๊ณ , ๊ทธ๋•Œ๋ถ€ํ„ฐ ๋‘ ํ™”๋ฉด์ด ๋‹ค๋ฅธ ํ•ฉ์„\n * ๋งํ•œ๋‹ค. ์ด ํ•จ์ˆ˜๊ฐ€ ํ•˜๋Š” ์ผ์€ **์žฌ๋ฃŒ๋ฅผ ๋ชจ์•„ ๋„˜๊ธฐ๊ณ  ๋‹ต์„ ์ž๋ฆฌ๋ณ„๋กœ ๋ฌถ๋Š” ๊ฒƒ**๋ฟ์ด๋‹ค.\n *\n * โ”€โ”€ ๊ฐ€์ค‘์น˜๋Š” ๊ฐ€๋™์‹œ๊ฐ„์ด๋‹ค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ •๊ฒฉ(kW)์œผ๋กœ ๋‚˜๋ˆ„์ง€ ์•Š๋Š”๋‹ค: ์‹œ๋ฎฌ ํŠธ์œˆ์˜ ์ด๋ถ€ํ•˜๊ฐ€ ์ •๊ฒฉ์˜ ํ•ฉ์—์„œ ํŒŒ์ƒ๋˜๋ฏ€๋กœ ๊ทธ ์ด๋Ÿ‰์„ ๋‹ค์‹œ ์ •๊ฒฉ์œผ๋กœ\n * ๋‚˜๋ˆ„๋ฉด ๋„ฃ์€ ๊ฐ’์ด ๊ทธ๋Œ€๋กœ ๋‚˜์˜จ๋‹ค(์ƒˆ ์ •๋ณด 0์˜ ๋™์–ด๋ฐ˜๋ณต). ๊ฐ€๋™์‹œ๊ฐ„์€ **์ €๋„์ด ๊ด€์ธกํ•œ ์‚ฌ์‹ค**์ด๋‹ค.\n *\n * ์ž๋ฆฌ๋ฅผ ๋ชจ๋ฅด๋Š” ์ž์›์€ `unknown` ์œผ๋กœ ๋ชจ์ธ๋‹ค โ€” ๋นผ๋ฉด ํ•ฉ์ด ์ค„๊ณ , ์•„๋ฌด ์ž๋ฆฌ์— ๋„ฃ์œผ๋ฉด ๊ฑฐ์ง“์ด ๋œ๋‹ค.\n */\nfunction feederShares(\n kWh: number | undefined,\n utilization: { resourceId: string; busyMs: number }[],\n resourceFeeder?: Record<string, string>\n): Partial<NonNullable<KpiResult['energy']>> {\n /* ์„ ์–ธ์ด ์—†์œผ๋ฉด ๋ถ„ํ•ดํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” ์ž๋ฆฌ๋ฅผ ๋ชจ๋ฅด๋Š” ์ฑ„ ๋‚˜๋ˆˆ ์ˆซ์ž๋Š” ์•„๋ฌด ๊ฒƒ์˜ ๋ชซ๋„ ์•„๋‹ˆ๋‹ค. */\n if (!resourceFeeder || !Object.keys(resourceFeeder).length) return {}\n if (kWh === undefined || !(kWh > 0)) return {}\n\n /*\n * โ”€โ”€ ํ’€์ด **๋ฌด์—‡์„ ๋ฎ๋Š”์ง€ ์‚ฌ์‹ค๋Œ€๋กœ** ๋งํ•œ๋‹ค (2026-08-17) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n *\n * ์ฒ˜์Œ์—๋Š” ใ€Œ๊ทธ ์ฐฝ์— ๋Œ์•„๊ฐ„ ์ž์›ใ€๋งŒ ๋ฎ๋Š”๋‹ค๊ณ  ๋„˜๊ฒผ๋‹ค. ๊ทธ๋Ÿฌ์ž ๋Œ์•„๊ฐ„ ์ž์›์ด ํ•˜๋‚˜์ธ ์ฐฝ์—์„œ ์ปค๋„์ด\n * ๊ทธ๊ฒƒ์„ **`measured`(์ „์šฉ ๊ณ„๋Ÿ‰)** ๋กœ ํŒ์ •ํ–ˆ๋‹ค โ€” ์ปค๋„์˜ ๊ทœ์น™์€ ์˜ณ๋‹ค(ใ€Œ๋ฎ๋Š” ์†Œ๋น„์ฒ˜๊ฐ€ ํ•˜๋‚˜๋ฉด ๊ทธ\n * ๊ณ„๋Ÿ‰๊ธฐ๋Š” ๊ทธ๊ฒƒ๋งŒ ์žฐ๋‹ค๋Š” ์„ ์–ธ์ด๋‹คใ€). ํ‹€๋ฆฐ ๊ฒƒ์€ ๋‚ด ์„ ์–ธ์ด์—ˆ๋‹ค: ํ˜„์žฅ ๊ณ„๋Ÿ‰๊ธฐ๋Š” ๋Œ์•„๊ฐ„ ๊ฒƒ๋งŒ ์žฌ์ง€ ์•Š๋Š”๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ **์„ ์–ธ๋œ ๋ถ€ํ•˜ ์ „๋ถ€**๋ฅผ ๋ฎ๋Š”๋‹ค๊ณ  ๋งํ•œ๋‹ค(`resourceFeeder` ์˜ ํ‚ค๊ฐ€ ๊ณง ๊ทธ ์„ ์–ธ์ด๋‹ค).\n * ๊ทธ๋Ÿฌ๋ฉด ๊ทธ ์ฐฝ์— ๋Œ์ง€ ์•Š์€ ์„ค๋น„๋Š” ๋ชซ 0 ์œผ๋กœ **๋ฐฐ๋ถ„์—์„œ ๋น ์ง€๊ณ  ๊ทธ ์ˆ˜๊ฐ€ ๋ณด๊ณ ๋œ๋‹ค** โ€” 0kWh ๋ฅผ ์ฃผ๋Š”\n * ๋Œ€์‹  ใ€Œ์ด ์„ค๋น„๋Š” ์ด ์ฐฝ์— ๊ฐ€๋™ ๊ธฐ๋ก์ด ์—†๋‹คใ€๋ฅผ ๋งํ•˜๋Š” ์ชฝ์ด๋‹ค.\n */\n /*\n * ๋ฎ๋Š” ๋Œ€์ƒ์€ **์„ ์–ธ๋œ ๋ถ€ํ•˜ โˆช ๊ทธ ์ฐฝ์— ๋Œ์•„๊ฐ„ ์ž์›**์ด๋‹ค.\n *\n * ์„ ์–ธ๋งŒ ์“ฐ๋ฉด, ๋Œ์•˜๋Š”๋ฐ ์ „๊ธฐ ๊ณ„ํ†ต์— ์„ ์–ธ๋˜์ง€ ์•Š์€ ์„ค๋น„์˜ ๋ชซ์ด ๋‚˜๋จธ์ง€ ์„ค๋น„์— ์–นํžŒ๋‹ค โ€” ๊ทธ ์„ค๋น„๊ฐ€\n * ์•ˆ ์“ด ์ „๊ธฐ๋ฅผ ์“ด ๊ฒƒ์œผ๋กœ ๋งŒ๋“ ๋‹ค. ๋Œ์•„๊ฐ„ ๊ฒƒ๋งŒ ์“ฐ๋ฉด, ์„ ์–ธ๋์ง€๋งŒ ์‰ฐ ์„ค๋น„๊ฐ€ ์‚ฌ๋ผ์ ธ ใ€Œ์ด ์ฐฝ์— ์•ˆ ๋Œ์•˜๋‹คใ€๋ฅผ\n * ๋งํ•  ์ˆ˜ ์—†๋‹ค. ๋‘˜์„ ํ•ฉํ•ด์•ผ ๋‘ ์‚ฌ์‹ค์ด ๋‹ค ๋‚จ๋Š”๋‹ค(์ž๋ฆฌ๋ฅผ ๋ชจ๋ฅด๋Š” ๋ชซ์€ `unknown` ์œผ๋กœ ๋ชจ์ธ๋‹ค).\n */\n const busyOf = new Map(utilization.map(u => [u.resourceId, u.busyMs]))\n const ids = new Set<string>([...Object.keys(resourceFeeder), ...busyOf.keys()])\n const consumers = [...ids].map(id => ({ id, weight: busyOf.get(id) ?? 0 }))\n if (!consumers.length) return {}\n\n const r = attributeEnergy({\n pools: [{ meterId: 'site', kWh, consumerIds: consumers.map(c => c.id) }],\n consumers,\n weightKind: 'runtimeMs'\n })\n\n const byKey = new Map<string, { kWh: number; weightShare: number; apportioned: boolean }>()\n for (const sh of r.shares) {\n /* ์ž๋ฆฌ๋ฅผ ๋ชจ๋ฅด๋ฉด `unknown` โ€” ๊ทธ ๋ชซ์ด ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์€ ๋‚จ๊ธฐ๊ณ , ์–ด๋””์˜ ๊ฒƒ์ธ์ง€๋Š” ์ง€์–ด๋‚ด์ง€ ์•Š๋Š”๋‹ค. */\n const key = resourceFeeder[sh.consumerId] ?? 'unknown'\n const cur = byKey.get(key) ?? { kWh: 0, weightShare: 0, apportioned: false }\n cur.kWh += sh.kWh\n cur.weightShare += sh.weightShare ?? 0\n /* **๊ทผ๊ฑฐ๋Š” ์ปค๋„์ด ์ •ํ•œ๋‹ค.** ์—ฌ๊ธฐ์„œ ๋‚™์ธ์ฐ์œผ๋ฉด ์ปค๋„์ด ใ€Œ์Ÿ€๋‹คใ€๊ณ  ํ•œ ๊ฒƒ์„ ใ€Œ๋‚˜๋ˆด๋‹คใ€๊ณ  ๋ฐ”๊ฟ” ๋งํ•˜๊ฑฐ๋‚˜\n ๊ทธ ๋ฐ˜๋Œ€๊ฐ€ ๋œ๋‹ค. ์„ž์ด๋ฉด ์•ฝํ•œ ์ชฝ(๋ฐฐ๋ถ„)์œผ๋กœ ์ ๋Š”๋‹ค โ€” ๊ฐ•ํ•œ ์ฃผ์žฅ์„ ์˜ฌ๋ ค ์žก์ง€ ์•Š๋Š”๋‹ค. */\n if (sh.basis === 'apportioned') cur.apportioned = true\n byKey.set(key, cur)\n }\n\n const byFeeder = [...byKey.entries()]\n .map(([key, v]) => ({\n key,\n kWh: v.kWh,\n basis: (v.apportioned ? 'apportioned' : 'measured') as 'apportioned' | 'measured',\n weightKind: 'runtimeMs' as const,\n weightShare: v.weightShare\n }))\n .sort((a, b) => b.kWh - a.kWh)\n\n const un = r.unattributed.reduce((sum, u) => sum + u.kWh, 0)\n return {\n ...(byFeeder.length ? { byFeeder } : {}),\n ...(un > 0 ? { unattributedKWh: un, unattributedReason: r.unattributed[0]?.reason } : {}),\n ...(r.excluded.length ? { excludedResources: r.excluded.length } : {})\n }\n}\n\n/**\n * ๋ถ„๊ธฐ๋ณ„ ์ „๋ ฅ๋Ÿ‰์„ **๊ณ„๋Ÿ‰์œผ๋กœ** ์ฝ๋Š”๋‹ค โ€” ๊ณ„๋Ÿ‰์ด ์žˆ์œผ๋ฉด ๋ฐฐ๋ถ„ํ•˜์ง€ ์•Š๋Š”๋‹ค.\n *\n * โ”€โ”€ ์™œ ํ•„์š”ํ–ˆ๋‚˜ (2026-08-18) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์‹ค ๊ฒŒ์ดํŠธ์›จ์ด๋Š” ๋ถ„๊ธฐ๋งˆ๋‹ค ๊ณ„๋Ÿ‰๊ธฐ๋ฅผ ๋ณด๋‚ธ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ํ™”๋ฉด์€ ใ€Œ๋‚˜๋ˆ„์ง€ ๋ชปํ•จใ€์œผ๋กœ ๋‹ตํ•˜๊ณ  ์žˆ์—ˆ๋‹ค โ€” ์—ฌ๊ธฐ์—\n * ๊ฐ€๋™์‹œ๊ฐ„ ๋ฐฐ๋ถ„ ๊ฒฝ๋กœ๋งŒ ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ณ„๋Ÿ‰์ด ์žˆ๋Š”๋ฐ ๋ฐฐ๋ถ„์œผ๋กœ ๋งํ•˜๋ฉด **๊ทผ๊ฑฐ๋ฅผ ์‹ค์ œ๋ณด๋‹ค ์•ฝํ•˜๊ฒŒ** ๋ณด๊ณ ํ•˜๋Š”\n * ๊ฒƒ์ด๊ณ , ๊ทธ ์œ„์— ์„ธ์šด SEU ํŒ๋‹จ์ด ๋ฌด๊ฑฐ์šด ๊ฐ’์„ ๋†“์นœ๋‹ค. ๋ฏธ๋Ÿฌ ํŠธ์œˆ์—๋Š” ์„ค๋น„ ๊ฐ€๋™ ๊ธฐ๋ก์กฐ์ฐจ ์—†์–ด์„œ\n * (์›์ฒœ์ด ๊ณ„๋Ÿ‰๋งŒ ์ค€๋‹ค) ๊ทธ ๊ฒฝ๋กœ๋กœ๋Š” ๋ถ„๊ธฐ๋ณ„ ๊ฐ’์ด ์˜์›ํžˆ ๋‚˜์˜ค์ง€ ์•Š์•˜๋‹ค.\n *\n * ๊ฐ’์˜ ์ถœ์ฒ˜๋Š” ์ปค๋„์ด ๊ตฌ๊ฐ„ ๋งˆ๊ฐ ์‚ฌ์‹ค์— ์‹ค์–ด ์ฃผ๋Š” **์ง€์ ๋ณ„ ๋ชซ**์ด๋‹ค(์ ์‚ฐ์˜ ๋บ„์…ˆ). ํ‘œ๋ณธ์„ ์ง์ ‘ ์ฝ์ง€ ์•Š๋Š”\n * ์ด์œ ๋Š” ์กฐํšŒ ์ƒํ•œ์ด๋‹ค โ€” ๊ณ„์ธก์€ ์ดˆ๋‹น ์—ฌ๋Ÿฌ ๊ฑด์ด๋ผ ํ‘œ๋ณธ์œผ๋กœ๋Š” ์ฐฝ์„ ์ฑ„์šฐ๊ธฐ ์ „์— ์ƒํ•œ์— ๊ฑธ๋ฆฐ๋‹ค.\n *\n * ๋‚˜๋จธ์ง€(๋ฟŒ๋ฆฌ โˆ’ ๋ถ„๊ธฐ ํ•ฉ)๋Š” **๋ฒ„๋ฆฌ์ง€๋„ ์–น์ง€๋„ ์•Š๋Š”๋‹ค**: ์ˆ˜์ „ ์ง๊ฒฐ ๋ถ€ํ•˜ยท์†์‹คยท๊ณ„๋Ÿ‰๋˜์ง€ ์•Š์€ ํšŒ๋กœ๊ฐ€ ๊ทธ\n * ์ฐจ์ด์ด๋ฏ€๋กœ, ์–ด๋А ๋ถ„๊ธฐ์— ์–น์œผ๋ฉด ๊ทธ ๋ถ„๊ธฐ๊ฐ€ ์“ฐ์ง€ ์•Š์€ ์ „๊ธฐ๋ฅผ ์“ด ๊ฒƒ์œผ๋กœ ๋งŒ๋“ ๋‹ค. ์ปค๋„์˜ `remainder` ํ’€๋กœ\n * ๋„˜๊ฒจ ใ€Œํ•˜์œ„ ๊ณ„๋Ÿ‰์ด ๋ฎ์ง€ ์•Š๋Š”๋‹คใ€๋กœ ๋‚จ๊ธด๋‹ค.\n *\n * ๋ถ„๊ธฐ ๊ณ„๋Ÿ‰ ํ•ฉ์ด ๋ฟŒ๋ฆฌ๋ณด๋‹ค ํฌ๋ฉด(ํšŒ๊ณ„๊ฐ€ ๋‹ค๋ฅธ ๋‘ ๊ณ„๋Ÿ‰๊ธฐ) **๊ทธ ์‚ฌ์‹ค์„ ๋‚ธ๋‹ค** โ€” ๊ฐ’์„ ๊นŽ์•„ ๋งž์ถ”๋ฉด ๊ณ„๋Ÿ‰์„\n * ์šฐ๋ฆฌ๊ฐ€ ๊ณ ์ณ ์“ฐ๋Š” ๊ฒƒ์ด๋‹ค.\n */\nfunction measuredFeeders(\n windows: readonly {\n startMs: number\n endMs: number\n maxKW?: number\n points: { id: string; kWh: number; root: boolean }[]\n pointsAtPeak?: { id: string; kW: number }[]\n }[],\n range: { startMs: number; endMs: number },\n totalKWh: number | undefined,\n meterFeeder?: Record<string, string>\n): Partial<NonNullable<KpiResult['energy']>> | undefined {\n if (!meterFeeder || !Object.keys(meterFeeder).length) return undefined\n if (totalKWh === undefined || !(totalKWh > 0)) return undefined\n\n /* ์ฐฝ์— ์˜จ์ „ํžˆ ๋“  ๊ตฌ๊ฐ„๋งŒ โ€” ์ „์ฒด ์ „๋ ฅ๋Ÿ‰๊ณผ ๊ฐ™์€ ๊ทœ์น™์ด์–ด์•ผ ๋ชซ๊ณผ ํ•ฉ์ด ๊ฐ™์€ ์ฐฝ์„ ๋งํ•œ๋‹ค. */\n const byFeederKWh = new Map<string, number>()\n let sawPoints = false\n for (const w of windows) {\n if (!(w.startMs >= range.startMs && w.endMs <= range.endMs)) continue\n for (const p of w.points ?? []) {\n const feeder = meterFeeder[p.id]\n if (!feeder) continue // ๋ฟŒ๋ฆฌ ๊ณ„๋Ÿ‰๊ธฐยท๋ชจ๋ฅด๋Š” ์ง€์  โ€” ๋ถ„๊ธฐ์˜ ๋ชซ์ด ์•„๋‹ˆ๋‹ค\n sawPoints = true\n byFeederKWh.set(feeder, (byFeederKWh.get(feeder) ?? 0) + p.kWh)\n }\n }\n if (!sawPoints) return undefined // ๊ณ„๋Ÿ‰์ด ์—†์œผ๋ฉด ์ด ๊ฒฝ๋กœ๋ฅผ ์“ฐ์ง€ ์•Š๋Š”๋‹ค(๋ฐฐ๋ถ„์œผ๋กœ ๋Œ์•„๊ฐ„๋‹ค)\n\n const feeders = [...byFeederKWh.entries()].filter(([, kWh]) => kWh > 0)\n if (!feeders.length) return undefined\n const submetered = feeders.reduce((sum, [, kWh]) => sum + kWh, 0)\n const remainder = totalKWh - submetered\n\n const r = attributeEnergy({\n pools: [\n ...feeders.map(([feeder, kWh]) => ({ meterId: `${feeder}:meter`, kWh, consumerIds: [feeder] })),\n ...(remainder > 0 ? [{ meterId: 'root:remainder', kWh: remainder, consumerIds: [], remainder: true }] : [])\n ],\n consumers: feeders.map(([feeder]) => ({ id: feeder }))\n })\n\n /*\n * โ”€โ”€ ํ”ผํฌ๋ฅผ ๋งŒ๋“  ๋ถ„๊ธฐ (2026-08-18) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n *\n * ์š”๊ธˆ์€ kW ๋กœ ๋งค๊ฒจ์ง€๋ฏ€๋กœ ใ€Œ์–ด๋А ๋ถ„๊ธฐ๋ฅผ ๊นŽ์•„์•ผ ํ”ผํฌ๊ฐ€ ๋‚ด๋ ค๊ฐ€๋‚˜ใ€๊ฐ€ ์‹ค๋ฌด์˜ ์งˆ๋ฌธ์ด๋‹ค. ๊ทธ ๋‹ต์€ **ํ”ผํฌ๊ฐ€\n * ์ฐํžŒ ๊ตฌ๊ฐ„์˜ ๊ทธ ์ˆœ๊ฐ„** ๊ฐ’์ด๊ณ , ์ฐฝ ์•ˆ์˜ ์—ฌ๋Ÿฌ ๊ตฌ๊ฐ„์„ ๋”ํ•˜๊ฑฐ๋‚˜ ํ‰๊ท ํ•˜๋ฉด ๋œป์ด ์‚ฌ๋ผ์ง„๋‹ค(๋‹ค๋ฅธ ์ˆœ๊ฐ„์˜ ๊ฐ’์„\n * ์„ž๋Š” ๊ฒƒ์ด๋‹ค). ๊ทธ๋ž˜์„œ **์ตœ๋Œ€์ˆ˜์š”๋ฅผ ๋‚ธ ๊ตฌ๊ฐ„ ํ•˜๋‚˜**๋งŒ ๊ณจ๋ผ ๊ทธ ์ˆœ๊ฐ„์˜ ์ง€์  ๊ฐ’์„ ์“ด๋‹ค.\n */\n const peakWindow = windows\n .filter(w => w.startMs >= range.startMs && w.endMs <= range.endMs && Number.isFinite(Number(w.maxKW)))\n .reduce<(typeof windows)[number] | undefined>((best, w) => (!best || Number(w.maxKW) > Number(best.maxKW) ? w : best), undefined)\n const peakOf = new Map<string, number>()\n for (const p of peakWindow?.pointsAtPeak ?? []) {\n const feeder = meterFeeder[p.id]\n if (!feeder) continue // ๋ฟŒ๋ฆฌ ๊ณ„๋Ÿ‰๊ธฐยท๋ชจ๋ฅด๋Š” ์ง€์  โ€” ๋ถ„๊ธฐ์˜ ๋ชซ์ด ์•„๋‹ˆ๋‹ค\n peakOf.set(feeder, (peakOf.get(feeder) ?? 0) + p.kW)\n }\n\n const byFeeder = r.shares\n .map(sh => ({\n key: sh.consumerId,\n kWh: sh.kWh,\n basis: sh.basis,\n weightKind: undefined,\n weightShare: undefined,\n /* ํ”ผํฌ ์ˆœ๊ฐ„์˜ ๊ฐ’์ด ์—†์œผ๋ฉด ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค โ€” ๊ทธ ๊ตฌ๊ฐ„์— ์ด ๋ถ„๊ธฐ์˜ ํ‘œ๋ณธ์ด ์—†์—ˆ๋‹ค๋Š” ๋œป์ด๋‹ค. */\n ...(peakOf.has(sh.consumerId) ? { peakKW: peakOf.get(sh.consumerId) } : {})\n }))\n .sort((a, b) => b.kWh - a.kWh) as NonNullable<KpiResult['energy']>['byFeeder']\n\n const un = r.unattributed.reduce((sum, u) => sum + u.kWh, 0)\n return {\n ...(byFeeder?.length ? { byFeeder } : {}),\n ...(un > 0 ? { unattributedKWh: un, unattributedReason: r.unattributed[0]?.reason } : {}),\n /* ๋ถ„๊ธฐ ํ•ฉ์ด ๋ฟŒ๋ฆฌ๋ฅผ ๋„˜์—ˆ๋‹ค โ€” ๋‘ ๊ณ„๋Ÿ‰๊ธฐ์˜ ํšŒ๊ณ„๊ฐ€ ๋‹ค๋ฅด๋‹ค๋Š” ์‚ฌ์‹ค์ด๋‹ค(๊นŽ์•„ ๋งž์ถ”์ง€ ์•Š๋Š”๋‹ค). */\n ...(remainder < 0 ? { submeterExcessKWh: -remainder } : {})\n }\n}\n\n/** ํด๋“œ ์˜ต์…˜ โ€” ๊ด€์  ์ถ•๊ณผ, ๊ทธ ์ถ•์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์ด๋ฒคํŠธ ๋ฐ–์—์„œ ์™€์•ผ ํ•˜๋Š” ์ง€๋„. */\nexport interface KpiFoldOptions {\n groupBy?: KpiGroupBy\n /**\n * ๋…ธ๋“œ โ†’ ๊ตฌ์—ญ ์ง€๋„. **์ด๋ฒคํŠธ์—๋Š” ๊ตฌ์—ญ์ด ์—†๋‹ค**(๋…ธ๋“œ๊นŒ์ง€๋งŒ ์žˆ๋‹ค) โ€” ์Šค๋ƒ…์ƒทยท๋งˆ์Šคํ„ฐ๊ฐ€ ์•„๋Š” ๊ฐ’์ด๋ผ\n * ํ˜ธ์ถœ๋ถ€๊ฐ€ ๋„˜๊ธด๋‹ค. ์—†์œผ๋ฉด ๊ตฌ์—ญ ์ถ•์€ 'unknown' ์œผ๋กœ ๋ชจ์ธ๋‹ค(์กฐ์šฉํžˆ ๋‹ค๋ฅธ ์ถ•์œผ๋กœ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค).\n */\n locationArea?: Record<string, string>\n /**\n * ์ž์› โ†’ **๋ฐฐ์ „ ๊ณ„ํ†ต์˜ ์ž๋ฆฌ**(๋ถ„๊ธฐยท์ˆ˜์ „) ์ง€๋„.\n *\n * โ”€โ”€ ์™œ ๋ฐ–์—์„œ ์˜ค๋‚˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ด๋ฒคํŠธ์—๋Š” ์ „๊ธฐ ๊ณ„ํ†ต์ด ์—†๋‹ค. ใ€Œ์ด ์„ค๋น„๊ฐ€ ์–ด๋А ๋ถ„๊ธฐ์—์„œ ๋จน๋Š”๊ฐ€ใ€๋Š” ์—๋„ˆ์ง€ ํŠธ์œˆ์˜ ๋ชจ๋ธ์ด ์•„๋Š”\n * ์„ ์–ธ์ด๊ณ (์„ค๋น„ ํ•˜๋‚˜์— ์‚ฌ์‹ค ๋‘˜ โ€” ๊ณต์žฅ์—์„œ๋Š” ์ž์›, ์ „๊ธฐ์—์„œ๋Š” ๋ถ€ํ•˜), ๊ทธ ์„ ์–ธ์„ ์ฝ๋Š” ๊ฒƒ์€ ํ˜ธ์ถœ๋ถ€์˜ ์ผ์ด๋‹ค.\n *\n * ์—†์œผ๋ฉด ๋ถ„๊ธฐ ๋ถ„ํ•ด๋ฅผ **ํ•˜์ง€ ์•Š๋Š”๋‹ค** โ€” ์ž๋ฆฌ๋ฅผ ๋ชจ๋ฅด๋Š” ์ฑ„ ๋‚˜๋ˆ„๋ฉด ๊ทธ ์ˆซ์ž๋Š” ์•„๋ฌด ๊ฒƒ์˜ ๋ชซ๋„ ์•„๋‹ˆ๋‹ค.\n */\n resourceFeeder?: Record<string, string>\n /**\n * **๊ณ„๋Ÿ‰ ์ง€์  โ†’ ๊ทธ๊ฒƒ์ด ์žฌ๋Š” ๋ถ„๊ธฐ** ์ง€๋„.\n *\n * ์žˆ์œผ๋ฉด ๋ถ„๊ธฐ๋ณ„ ์ „๋ ฅ๋Ÿ‰์„ ๊ณ„๋Ÿ‰์œผ๋กœ ์ฝ๋Š”๋‹ค(๋ฐฐ๋ถ„๋ณด๋‹ค ๊ฐ•ํ•œ ๊ทผ๊ฑฐ). ์ด ์ง€๋„๋Š” ๋ชจ๋ธ์˜ ์„ ์–ธ์—์„œ ์˜ค๊ณ \n * (๊ณ„๋Ÿ‰๊ธฐ์˜ ์ž๋ฆฌ), ๊ทธ๊ฒƒ์„ ์ฝ๋Š” ๊ฒƒ์€ ํ˜ธ์ถœ๋ถ€์˜ ์ผ์ด๋‹ค โ€” ํด๋“œ๋Š” ์ €๋„๋งŒ ๋ณธ๋‹ค.\n */\n meterFeeder?: Record<string, string>\n /**\n * ์„ ์–ธ๋œ **์ „๊ธฐ์š”๊ธˆ ๋‹จ๊ฐ€** โ€” ์ˆ˜๋ฅผ ๊ธˆ์•ก์œผ๋กœ ๋ฐ”๊พธ๋Š” ์œ ์ผํ•œ ์ž…๋ ฅ.\n *\n * ์ด๋ฒคํŠธ์—๋Š” ์š”๊ธˆ์ด ์—†๋‹ค. ๋‹จ๊ฐ€๋Š” ํ˜„์žฅ์˜ ๊ณ„์•ฝ์ด๊ณ (์—๋„ˆ์ง€ ํŠธ์œˆ ๋ชจ๋ธ์˜ ์ˆ˜์ „ ์ž๋ฆฌ์— ์„ ์–ธํ•œ๋‹ค), ๊ทธ๊ฒƒ์„\n * ์ฝ๋Š” ๊ฒƒ์€ ํ˜ธ์ถœ๋ถ€์˜ ์ผ์ด๋‹ค. ์—†์œผ๋ฉด ๊ธˆ์•ก์„ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค โ€” ์ง์ž‘ํ•œ ๋‹จ๊ฐ€๋กœ ๋‚ธ ๊ธˆ์•ก์€ ์ˆซ์ž๊ฐ€ ์žˆ๋‹ค๋Š”\n * ๊ฒƒ๋งŒ์œผ๋กœ ์‚ฌ๋žŒ์„ ๊ฒฐ์ •์œผ๋กœ ๋ฐ€์–ด๋ถ™์ธ๋‹ค.\n */\n tariff?: TariffDeclaration\n /**\n * ๊ต๋Œ€ ์„ ์–ธ โ€” **์ด๋ฒคํŠธ์—๋Š” ๊ต๋Œ€๊ฐ€ ์—†๋‹ค**(์‹œ๊ฐ๋งŒ ์žˆ๋‹ค). ํ˜„์žฅ ๋งˆ์Šคํ„ฐ๊ฐ€ ์•„๋Š” ๊ฐ’์ด๋ผ ํ˜ธ์ถœ๋ถ€๊ฐ€ ๋„˜๊ธด๋‹ค.\n * ์—†์œผ๋ฉด ๊ต๋Œ€ ์ถ•์€ 'unknown' ์œผ๋กœ ๋ชจ์ธ๋‹ค(๋‹ค๋ฅธ ์ถ•์œผ๋กœ ์กฐ์šฉํžˆ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค).\n */\n shifts?: WorkCalendarEntry[]\n /**\n * ํ˜„์žฅ์˜ ์‹œ๊ฐ ๊ธฐ์ค€(๋ถ„) โ€” ๊ต๋Œ€ ์ถ•์ด `HH:MM` ์„ ์–ด๋А ๊ธฐ์ค€์œผ๋กœ ์ฝ์„์ง€. **๊ณต๊ฐ„์ด ๊ฐ–๋Š” ๊ฐ’**์ด๋‹ค\n * (ํ…Œ๋„ŒํŠธ๊ฐ€ ์•„๋‹ˆ๋‹ค: ํ•œ ํ…Œ๋„ŒํŠธ๊ฐ€ ๋‹ค๋ฅธ ์‹œ๊ฐ„๋Œ€์˜ ๊ณต์žฅ์„ ํ•จ๊ป˜ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค). ์—†์œผ๋ฉด UTC.\n */\n utcOffsetMinutes?: number\n /**\n * ์ถ•์˜ ์ƒํ•œ(๊ธฐ๋ณธ 20). ๋„˜์น˜๋ฉด ์ž˜๋ผ๋‚ด๊ณ  **์ž˜๋ฆฐ ์ถ•์˜ ์ˆ˜์™€ ๊ทธ ์•ˆ์˜ ๊ฑด์ˆ˜๋ฅผ ํ•จ๊ป˜ ์•Œ๋ฆฐ๋‹ค**.\n *\n * ์ถ•์˜ ์ˆ˜๋งŒ ์•Œ๋ฆฌ๋ฉด ๋ถ€์กฑํ•˜๋‹ค โ€” \"๊ทธ ์™ธ 89๊ฐœ\" ๋กœ๋Š” ๊ทธ๊ฒƒ์ด 3๊ฑด์ธ์ง€ 300๊ฑด์ธ์ง€ ๋ชจ๋ฅธ๋‹ค. ๋ณด์—ฌ์ค€ ์ถ•์ด ์ „๋ถ€์ธ\n * ๊ฒƒ์ฒ˜๋Ÿผ ์ฝํžˆ๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ๊ผฌ๋ฆฌ๋ฅผ ๋†“์นœ๋‹ค.\n */\n groupLimit?: number\n}\n\n/* โ”€โ”€ ๊ด€์  ์ถ•์˜ ์žฌ๋ฃŒ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ถ•์˜ ๊ฐ’์€ ์ด๋ฒคํŠธ payload ์— ์ด๋ฏธ ๋“ค์–ด ์žˆ๋‹ค(`TaskStatusDelta`: kindยทorderIdยทfromNodeยทtoNodeยท\n * resourceRef). ์ƒˆ ๊ณ„์ธก์„ ์‹ฌ์„ ํ•„์š”๊ฐ€ ์—†๋‹ค โ€” **์ด๋ฏธ ์Œ“์ธ ์ €๋„์„ ๋‹ค๋ฅด๊ฒŒ ๋ฌถ๊ธฐ๋งŒ** ํ•œ๋‹ค.\n */\n/** ์ฐฝ ์•ˆ์— ์™„๋ฃŒ๋œ ํ•œ ๊ฑด์˜ ๊ธฐ๋ก โ€” ํ†ต๊ณ„์˜ ์›๋ฃŒ์ด์ž ๊ด€์  ์ถ•์˜ ์›๋ฃŒ. */\ninterface CompletionRecord {\n taskId: string\n at: number\n facets: TaskFacets\n leadMs?: number\n workMs?: number\n waitMs?: number\n}\n\n/** ์ด ๊ธฐ๋ก์ด ์š”์ฒญํ•œ ์ถ•์—์„œ ์–ด๋А ๊ฐ’์— ์†ํ•˜๋Š”๊ฐ€. ๊ฐ’์ด ์—†์œผ๋ฉด 'unknown'(์กฐ์šฉํžˆ ๋ฒ„๋ฆฌ์ง€ ์•Š๋Š”๋‹ค). */\nfunction facetKey(rec: CompletionRecord, options: KpiFoldOptions): string {\n const f = rec.facets\n switch (options.groupBy) {\n case 'resource':\n return f.resource ?? 'unknown'\n case 'taskKind':\n return f.kind ?? 'unknown'\n case 'location':\n return f.location ?? 'unknown'\n case 'order':\n return f.order ?? 'unknown'\n case 'area':\n /* ๊ตฌ์—ญ์€ ์ด๋ฒคํŠธ ๋ฐ–์˜ ์ง€์‹์ด๋‹ค โ€” ์ง€๋„๊ฐ€ ์—†์œผ๋ฉด ์—†๋‹ค๊ณ  ๋งํ•œ๋‹ค(๋…ธ๋“œ id ๋กœ ๋Œ€์ฒดํ•˜๋ฉด ์‚ฌ์šฉ์ž๊ฐ€\n * ๊ทธ๊ฒƒ์„ ๊ตฌ์—ญ์œผ๋กœ ์˜คํ•ดํ•œ๋‹ค). */\n return (f.location && options.locationArea?.[f.location]) ?? 'unknown'\n case 'shift':\n /*\n * ๊ต๋Œ€๋Š” **์ €๋„์— ์ฐํ˜€ ์žˆ์ง€ ์•Š๋‹ค โ€” ๊ณ„์‚ฐํ•œ๋‹ค.**\n *\n * ์ด๋ฒคํŠธ์— ๊ต๋Œ€ ์ด๋ฆ„์„ ์Šคํƒฌํ”„ํ•˜๋ฉด ๋‘ ๊ฐ€์ง€๊ฐ€ ๋ฌด๋„ˆ์ง„๋‹ค: โ‘  ๊ฐ™์€ ์‚ฌ์‹ค์ด ๋‘ ๊ณณ์— ์ƒ๊ธฐ๊ณ ,\n * โ‘ก ๋‚˜์ค‘์— ๊ต๋Œ€ ์‹œ๊ฐ„์„ ๊ณ ์น˜๋ฉด **๊ณผ๊ฑฐ๊ฐ€ ์˜› ๊ตฌ๋ถ„์œผ๋กœ ๊ตณ์–ด** ๋‹ค์‹œ ์…€ ์ˆ˜ ์—†๋‹ค. ๊ต๋Œ€๋Š”\n * `์™„๋ฃŒ ์‹œ๊ฐ + ํ˜„์žฅ์˜ ์‹œ๊ฐ ๊ธฐ์ค€ + ๊ต๋Œ€ ์„ ์–ธ`์—์„œ ๋‚˜์˜ค๋Š” ์ˆœ์ˆ˜ ํŒŒ์ƒ์ด๋ฏ€๋กœ ์—ฌ๊ธฐ์„œ ๋‚ธ๋‹ค โ€”\n * ๋ผ์ด๋ธŒยทํžˆ์Šคํ† ๋ฆฌยท์˜ˆ์ธก์ด **์ปค๋„๊ณผ ๊ฐ™์€ ํ•จ์ˆ˜**(`activeShiftOf`)๋ฅผ ์“ด๋‹ค.\n *\n * ์„ ์–ธ์ด ์—†์œผ๋ฉด 'unknown' ์ด๋‹ค. ๊ต๋Œ€๋ฅผ ๋‚˜๋ˆ  ๋†“์ง€ ์•Š์€ ํ˜„์žฅ์— ์ด๋ฆ„์„ ์ง€์–ด๋‚ด์ง€ ์•Š๋Š”๋‹ค.\n */\n if (!options.shifts?.length) return 'unknown'\n /* ์‹œ๊ฐ๊นŒ์ง€ ๋„˜๊ธด๋‹ค โ€” **ํœด์ผ์— ์ผ์–ด๋‚œ ์ผ์€ ์–ด๋А ๊ต๋Œ€์—๋„ ์†ํ•˜์ง€ ์•Š๋Š”๋‹ค.** ๋˜ํ’€์ด๋งŒ ๋ณด๋ฉด ๊ทธ๋‚  ์„œ์ง€๋„\n ์•Š์€ ๊ต๋Œ€์— ์ง‘๊ณ„๋ผ, ๊ต๋Œ€๋ณ„ ์„ฑ๊ณผ๊ฐ€ ์กฐ์šฉํžˆ ๊ฑฐ์ง“์ด ๋œ๋‹ค. */\n return activeShiftAt(options.shifts, rec.at, options.utcOffsetMinutes) ?? 'unknown'\n default:\n return 'unknown'\n }\n}\n\n/**\n * ์ด ์ถ•์˜ ํ’ˆ์งˆ โ€” **ํŒ์ •์ด ์žˆ์—ˆ๋˜ ๊ฒƒ๋งŒ** ์„ผ๋‹ค(์—†์œผ๋ฉด ํ•„๋“œ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค).\n *\n * ์–‘ํ’ˆ๋ฅ ์˜ ์ด๋ ฅ์ด ์—ฌ๊ธฐ์„œ ๋‚˜์˜จ๋‹ค: ์ปค๋„์ด ์ž‘์—… ์™„๋ฃŒ์— ๊ฒฐ๊ณผ๋ฅผ ์ ๊ณ (`TaskStatusDelta.outcome`), ํด๋“œ๊ฐ€ ์ถ•์œผ๋กœ\n * ๋“ค๊ณ (`TaskFacets.outcome`), ์—ฌ๊ธฐ์„œ ์ข…๋ฅ˜๋ณ„๋กœ ์„ผ๋‹ค. ๊ทธ ์‚ฌ์Šฌ์ด ์—†์œผ๋ฉด ใ€Œ์ด ๊ณต์ •์˜ ์–‘ํ’ˆ๋ฅ ใ€์€ ์ €๋„์—\n * ๋‚จ์ง€ ์•Š๋Š”๋‹ค(์„ค๋น„ ๋ˆ„์  ์นด์šดํ„ฐ๋Š” ์ข…๋ฅ˜๋ฅผ ๋ชจ๋ฅธ๋‹ค).\n */\nfunction qualityOf(rows: CompletionRecord[]): { quality?: { good: number; scrap: number } } {\n let good = 0\n let scrap = 0\n for (const r of rows) {\n const o = r.facets.outcome\n if (o === 'good') good++\n else if (o === 'scrap') scrap++\n }\n return good + scrap > 0 ? { quality: { good, scrap } } : {}\n}\n\n/**\n * ๊ธฐ๋ก์„ ์ถ•์œผ๋กœ ๋ฌถ์–ด ์ถ•๋ณ„ ํ†ต๊ณ„๋ฅผ ๋‚ธ๋‹ค โ€” **์ „์ฒด์™€ ๊ฐ™์€ ๊ทœ์น™**์œผ๋กœ(๊ฐ™์€ stats ํ•จ์ˆ˜, ๊ฐ™์€ ์ฐฝ).\n *\n * ์ถ•์˜ ๊ฐ’์ด ์•„์ฃผ ๋งŽ์„ ์ˆ˜ ์žˆ๋‹ค(์˜ค๋” ์ถ•์€ ์ˆ˜์ฒœ ๊ฐœ). ๊ทธ๋ž˜์„œ ๊ฑด์ˆ˜ ํฐ ๊ฒƒ๋ถ€ํ„ฐ ์ƒํ•œ๊นŒ์ง€๋งŒ ๋Œ๋ ค์ฃผ๊ณ \n * **์ž˜๋ผ๋‚ธ ์ˆ˜๋ฅผ ํ•จ๊ป˜ ์•Œ๋ฆฐ๋‹ค** โ€” ์กฐ์šฉํ•œ ์ ˆ๋‹จ์€ \"์ด๊ฒŒ ์ „๋ถ€\" ๋ผ๋Š” ๊ฑฐ์ง“์„ ๋งŒ๋“ ๋‹ค.\n */\nfunction groupRecords(\n records: CompletionRecord[],\n options: KpiFoldOptions\n): { by: KpiGroupBy; items: KpiGroup[]; truncated?: number; truncatedTasks?: number } {\n const by = options.groupBy as KpiGroupBy\n const bins = new Map<string, CompletionRecord[]>()\n for (const rec of records) {\n const key = facetKey(rec, options)\n const bin = bins.get(key)\n if (bin) bin.push(rec)\n else bins.set(key, [rec])\n }\n\n const all = [...bins.entries()]\n .map(([key, rows]) => ({\n key,\n tasks: rows.length,\n leadTime: stats(rows.map(r => r.leadMs).filter((v): v is number => v !== undefined)),\n workTime: stats(rows.map(r => r.workMs).filter((v): v is number => v !== undefined)),\n waitTime: stats(rows.map(r => r.waitMs).filter((v): v is number => v !== undefined)),\n busyMs: rows.reduce((a, r) => a + (r.workMs ?? 0), 0),\n ...qualityOf(rows)\n }))\n .sort((a, b) => b.tasks - a.tasks || (a.key < b.key ? -1 : 1))\n\n const limit = Math.max(1, Math.min(100, options.groupLimit ?? 20))\n const items = all.slice(0, limit)\n const dropped = all.slice(limit)\n /* ์ถ•๋ณ„๋กœ \"์ฐฝ ๋Œ€๋น„ ๋น„์œจ\" ์€ ๋‚ด์ง€ ์•Š๋Š”๋‹ค โ€” ์ž์› ์•„๋‹Œ ์ถ•(์˜ค๋”ยท์ž‘์—…์ข…๋ฅ˜)์—์„œ ๊ทธ ๋น„์œจ์€ ์˜๋ฏธ๊ฐ€ ์—†๊ณ ,\n * ์˜๋ฏธ ์—†๋Š” ์ˆซ์ž๋ฅผ ๋‚ด๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ๊ทธ๊ฒƒ์œผ๋กœ ํŒ๋‹จํ•œ๋‹ค. ์ž์› ์ ์œ ๋Š” `utilization` ์ด ์ด๋ฏธ ๋‚ธ๋‹ค. */\n return {\n by,\n items,\n ...(dropped.length\n ? { truncated: dropped.length, truncatedTasks: dropped.reduce((a, g) => a + g.tasks, 0) }\n : {})\n }\n}\n\nfunction ms(value: string | undefined): number | null {\n if (!value) return null\n const t = Date.parse(value)\n return Number.isFinite(t) ? t : null\n}\n\n/** ๋ถ„์œ„์ˆ˜ โ€” ์ •๋ ฌ๋œ ๊ฐ’์—์„œ ์„ ํ˜• ๋ณด๊ฐ„ ์—†์ด ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ์•„๋ž˜ ๊ฐ’(์ž‘์€ ํ‘œ๋ณธ์—์„œ ๊ณผ์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค). */\nfunction quantile(sorted: number[], q: number): number {\n if (sorted.length === 0) return 0\n const idx = Math.min(sorted.length - 1, Math.max(0, Math.floor(q * sorted.length)))\n return sorted[idx]\n}\n\nfunction stats(values: number[]): DurationStats {\n if (values.length === 0) return { count: 0, p10Ms: 0, p50Ms: 0, p90Ms: 0, avgMs: 0 }\n const sorted = [...values].sort((a, b) => a - b)\n const sum = sorted.reduce((a, b) => a + b, 0)\n return {\n count: sorted.length,\n p10Ms: quantile(sorted, 0.1),\n p50Ms: quantile(sorted, 0.5),\n p90Ms: quantile(sorted, 0.9),\n avgMs: Math.round(sum / sorted.length)\n }\n}\n\n/**\n * ์ด๋ฒคํŠธ๋ฅผ ์ ‘์–ด ์‹œ๊ฐ„์ฐฝ KPI ๋ฅผ ๋งŒ๋“ ๋‹ค.\n *\n * **ํ˜ธ์ถœ๋ถ€ ๊ทœ์•ฝ**: `events` ๋Š” ์ฐฝ๋ณด๋‹ค **๋„‰๋„‰ํžˆ ์•ž๊นŒ์ง€** ๋‹ด์•„ ๋„˜๊ธด๋‹ค(์˜ˆ: ์ฐฝ ์‹œ์ž‘ โˆ’ ๋ฆฌ๋“œํƒ€์ž„ ์ƒํ•œ).\n * ์™„๋ฃŒ๋œ ์ž‘์—…์˜ ์‹œ์ž‘ ์ด๋ฒคํŠธ๊ฐ€ ์ฐฝ ๋ฐ–์— ์žˆ์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋ชป ์ฐพ์€ ๊ฒƒ์€ `unpaired` ๋กœ ์•Œ๋ฆฐ๋‹ค โ€”\n * ํ‰๊ท ์—์„œ ์กฐ์šฉํžˆ ๋น ์ง€๋ฉด ์ง€ํ‘œ๊ฐ€ ๊ฑฐ์ง“์ด ๋œ๋‹ค.\n *\n * ์‹œ๊ฐ„์ถ•์€ `eventTime`(ISO) ์ฐจ๋ถ„์ด๋‹ค. sim ํด๋ก์ด ์‹ค์ œ ์‹œ๊ฐ๊ณผ ์˜คํ”„์…‹์ด ์žˆ์–ด๋„ **์ฐจ๋ถ„์€ ์ •ํ™•**ํ•˜๋‹ค\n * (๊ณ ์ • ์˜คํ”„์…‹์€ ์ƒ์‡„๋œ๋‹ค). ํŒŒ์‹ฑ ๋ถˆ๊ฐ€ํ•œ ์ค„์€ ๋ฒ„๋ฆฐ๋‹ค.\n */\nexport function foldKpi(events: KpiEvent[], window: KpiWindow, options: KpiFoldOptions = {}): KpiResult {\n /* ์ž‘์—… ์ง๋งž์ถค์€ **์ปค๋„ ๊ทœ์น™**์œผ๋กœ(์ค‘๋ณต ๊ตฌํ˜„ ๊ธˆ์ง€ โ€” ๋‘ ๊ณณ์— ์ ์œผ๋ฉด ๊ฐ™์€ ์ €๋„๋กœ ๋‹ค๋ฅธ ๋‹ต์ด ๋‚˜์˜จ๋‹ค). */\n const { records: tasks } = foldTaskRecords(events.filter(e => e.eventType === 'task.status'))\n let completedOrders = 0\n let seen = 0\n let inWindow = 0\n\n for (const e of events) {\n const at = ms(e.eventTime)\n if (at === null) continue\n seen++\n if (at >= window.fromMs && at <= window.toMs) inWindow++\n const d = e.payload?.data ?? e.payload ?? {}\n\n if (e.eventType === 'order.status') {\n /* ์˜ค๋” ์™„๋ฃŒ ์–ดํœ˜๋Š” ๋„๋ฉ”์ธ ์†Œ์œ ๋‹ค โ€” ์ฝ”์–ด๊ฐ€ ๊ฐ•์ œํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ž˜์„œ ์ด๋ฆ„์„ ํ•˜๋‚˜๋กœ ๋ชป ๋ฐ•์ง€ ์•Š๊ณ \n * ์™„๋ฃŒ๋กœ ์ฝํžˆ๋Š” ํ‘œํ˜„์„ ๋„“๊ฒŒ ๋ฐ›๋Š”๋‹ค(๊ทธ ๋ฐ–์€ ์„ธ์ง€ ์•Š๋Š”๋‹ค). */\n const status = String(d.status ?? '').toLowerCase()\n if (at >= window.fromMs && at <= window.toMs && (status === 'completed' || status === 'fulfilled' || status === 'done')) {\n completedOrders++\n }\n }\n }\n\n /*\n * ์—๋„ˆ์ง€ โ€” ์ฐฝ์— **์˜จ์ „ํžˆ ๋“ ** ๊ตฌ๊ฐ„ ๋งˆ๊ฐ ์‚ฌ๊ฑด๋งŒ ์„ผ๋‹ค(๊ฑธ์นœ ๊ตฌ๊ฐ„์€ ์ปค๋„ ๊ทœ์น™์ด ๋บ€๋‹ค).\n * ์‚ฌ๊ฑด์ด ํ•˜๋‚˜๋„ ์—†์œผ๋ฉด ์ด ํŠธ์œˆ์—๋Š” ์—๋„ˆ์ง€๊ฐ€ ์—†๋Š” ๊ฒƒ์ด๋ฏ€๋กœ ๋ธ”๋ก ์ž์ฒด๋ฅผ ๋‚ด์ง€ ์•Š๋Š”๋‹ค.\n */\n const demandWindows = events\n .filter(e => e.eventType === ENERGY_EVENT.demandWindow)\n .map(e => {\n const d = e.payload?.data ?? e.payload ?? {}\n /* ์ตœ๋Œ€(`maxKW`)๋„ ํ•จ๊ป˜ ๋„˜๊ธด๋‹ค โ€” ์š”๊ธˆ์ด ๊ฑธ๋ฆฌ๋Š” ์ˆ˜๋Š” ํ‰๊ท ์ด ์•„๋‹ˆ๋ผ ์ตœ๋Œ€๋‹ค.\n ์ด๋ถ€ํ•˜(`grossMaxKW`)๋Š” ใ€Œ๋ฌด์—‡์ด ๊นŽ์˜€๋‚˜ใ€๋ฅผ ๋˜์งš๋Š” ์ถ•์ด๋‹ค(๋ฐœ์ „ยท๋ฐฉ์ „ ์ฐจ๊ฐ ์ „). */\n return {\n startMs: Number(d.startMs),\n endMs: Number(d.endMs),\n meanKW: Number(d.meanKW),\n maxKW: Number(d.maxKW),\n grossMaxKW: Number(d.grossMaxKW),\n /* ์ง€์ ๋ณ„ ๋ชซ โ€” ๊ณ„๋Ÿ‰์ด ๋ถ„๊ธฐ์— ์žˆ์œผ๋ฉด ๊ทธ ๊ฐ’์€ **์ธก์ •**์ด๋‹ค(๋ฐฐ๋ถ„์ด ์•„๋‹ˆ๋‹ค). ์ปค๋„์ด ๊ณ„์ธต ํŒ์ •\n (`root`)๊นŒ์ง€ ์‹ค์–ด ์ฃผ๋ฏ€๋กœ ์—ฌ๊ธฐ์„œ ๊ฐ™์€ ๊ทœ์น™์„ ๋‹ค์‹œ ์“ฐ์ง€ ์•Š๋Š”๋‹ค. */\n points: (Array.isArray(d.points) ? d.points : [])\n .map((p: any) => ({ id: String(p?.id ?? ''), kWh: Number(p?.kWh), root: p?.root === true }))\n .filter((p: any) => p.id && Number.isFinite(p.kWh)),\n /* ํ”ผํฌ๊ฐ€ ์ฐํžŒ ์ˆœ๊ฐ„์˜ ์ง€์ ๋ณ„ kW โ€” ์š”๊ธˆ์ด ๊ฑธ๋ฆฐ ์ˆ˜๋Š” kW ๋‹ค(์ „๋ ฅ๋Ÿ‰์ด ํฐ ๋ถ„๊ธฐ์™€ ํ”ผํฌ๋ฅผ ๋งŒ๋“  ๋ถ„๊ธฐ๋Š” ๋‹ค๋ฅด๋‹ค). */\n pointsAtPeak: (Array.isArray(d.pointsAtPeak) ? d.pointsAtPeak : [])\n .map((p: any) => ({ id: String(p?.id ?? ''), kW: Number(p?.kW) }))\n .filter((p: any) => p.id && Number.isFinite(p.kW))\n }\n })\n .filter(w => Number.isFinite(w.startMs) && Number.isFinite(w.endMs))\n\n const leads: number[] = []\n const works: number[] = []\n const waits: number[] = []\n const busyByResource = new Map<string, number>()\n /* ์ฐฝ ์•ˆ์— ์™„๋ฃŒ๋œ ๊ฑด๋“ค์˜ **๊ธฐ๋ก** โ€” ํ†ต๊ณ„๋ฅผ ๋‚ธ ๋’ค์—๋„ ๋ฒ„๋ฆฌ์ง€ ์•Š๋Š”๋‹ค. ๊ด€์  ์ถ•์€ ๊ฐ™์€ ๊ธฐ๋ก์„ ๋‹ค์‹œ\n * ๋ฌถ๋Š” ๊ฒƒ์ผ ๋ฟ์ด๋ฏ€๋กœ, ๊ธฐ๋ก์„ ๋‚จ๊ธฐ๋ฉด ์ถ•์„ ํ•˜๋‚˜ ๋” ๋ถ™์ด๋Š” ๊ฐ’์ด ๊ฑฐ์˜ 0 ์ด ๋œ๋‹ค. */\n const records: CompletionRecord[] = []\n let tasksInWindow = 0\n let unpairedLead = 0\n let unpairedWork = 0\n\n for (const t of tasks) {\n const completed = t.completedMs\n if (completed === undefined) continue // ์•„์ง ์™„๋ฃŒ๋˜์ง€ ์•Š์€ ์ž‘์—… โ€” ์„ฑ๊ณผ๋กœ ์„ธ์ง€ ์•Š๋Š”๋‹ค\n if (completed < window.fromMs || completed > window.toMs) continue // ์„ฑ๊ณผ๋Š” ์™„๋ฃŒ ์‹œ์ ์œผ๋กœ ์„ผ๋‹ค\n tasksInWindow++\n const c = t.createdMs\n const s = t.startedMs\n const rec: CompletionRecord = { taskId: t.taskId, at: completed, facets: t.facets }\n const resource = rec.facets.resource\n if (c !== undefined && completed >= c) leads.push((rec.leadMs = completed - c))\n else unpairedLead++\n if (s !== undefined && completed >= s) {\n const busy = completed - s\n works.push((rec.workMs = busy))\n if (resource) busyByResource.set(resource, (busyByResource.get(resource) ?? 0) + busy)\n } else {\n unpairedWork++\n }\n if (c !== undefined && s !== undefined && s >= c) waits.push((rec.waitMs = s - c))\n records.push(rec)\n }\n\n const span = Math.max(1, window.toMs - window.fromMs)\n const utilization = [...busyByResource.entries()]\n .map(([resourceId, busyMs]) => ({ resourceId, busyMs, ratio: Math.min(1, busyMs / span) }))\n .sort((a, b) => b.busyMs - a.busyMs)\n\n return {\n window: { fromMs: window.fromMs, toMs: window.toMs },\n throughput: { tasks: tasksInWindow, orders: completedOrders },\n ...(demandWindows.length\n ? (() => {\n const e = energyOfWindows(demandWindows, { startMs: window.fromMs, endMs: window.toMs })\n /* ๋ถ„๋ชจ๋Š” **์™„๋ฃŒ ์˜ค๋”**๋‹ค(๋Œ€๋‹น ์ „๋ ฅ). ์ฐฝ์— ์™„๋ฃŒ๊ฐ€ ์—†์œผ๋ฉด ์ปค๋„ ๊ทœ์น™์ด ใ€Œ์ •์˜๋˜์ง€ ์•Š์Œใ€์œผ๋กœ ๋‹ตํ•œ๋‹ค. */\n const i = energyIntensity({\n kWh: e.kWh,\n energyWindow: e.window,\n denominator: { kind: 'output', value: completedOrders, window: e.window }\n })\n return {\n energy: {\n ...(e.kWh !== undefined ? { kWh: e.kWh } : {}),\n /* ์ด ์ฐฝ์˜ ์ตœ๋Œ€์ˆ˜์š” โ€” ๊ณ„์•ฝ ๋Œ€๋น„ ํŒ์ •์ด ๋ณด๋Š” ์ˆ˜๋‹ค(์ „๋ ฅ๋Ÿ‰๊ณผ ๊ฐ™์€ ๊ตฌ๊ฐ„ ์ง‘ํ•ฉ์—์„œ ์™”๋‹ค). */\n ...(e.peakKW !== undefined ? { peakKW: e.peakKW, peakStartMs: e.peakStartMs } : {}),\n /* ๊นŽ์ธ ์–‘์€ **๊ฐ™์€ ๊ตฌ๊ฐ„์˜ ๋‘ ์ˆ˜**์˜ ์ฐจ์ด๋‹ค โ€” ์—ฌ๊ธฐ์„œ ํ•œ ๋ฒˆ๋งŒ ๊ณ„์‚ฐํ•ด ๋‘ ๊ณณ์ด ๊ฐˆ๋ผ์ง€์ง€ ์•Š๊ฒŒ. */\n ...(e.peakGrossKW !== undefined && e.peakKW !== undefined\n ? { peakGrossKW: e.peakGrossKW, ...(e.peakGrossKW > e.peakKW ? { shavedKW: e.peakGrossKW - e.peakKW } : {}) }\n : {}),\n basis: e.basis,\n counted: e.counted,\n skipped: e.skipped,\n intensity:\n i.value === null\n ? { value: null, reason: (i as any).reason }\n : { value: i.value, unit: (i as any).unit },\n ...(measuredFeeders(demandWindows, { startMs: window.fromMs, endMs: window.toMs }, e.kWh, options.meterFeeder) ??\n feederShares(e.kWh, utilization, options.resourceFeeder)),\n /* ๊ธˆ์•ก์€ ๊ฐ™์€ ์ฐฝ์˜ ์ „๋ ฅ๋Ÿ‰ยท์ตœ๋Œ€์ˆ˜์š”์—์„œ ๋‚˜์˜จ๋‹ค โ€” ์ฐฝ์ด ํ•˜๋‚˜๋ฟ์ด๋ผ ์–ด๊ธ‹๋‚  ์ˆ˜ ์—†๋‹ค. */\n ...(options.tariff ? { cost: electricityCost({ kWh: e.kWh, peakKW: e.peakKW, tariff: options.tariff }) } : {})\n }\n }\n })()\n : {}),\n leadTime: stats(leads),\n workTime: stats(works),\n waitTime: stats(waits),\n utilization,\n unpaired: { leadTime: unpairedLead, workTime: unpairedWork },\n eventsSeen: seen,\n eventsInWindow: inWindow,\n ...(options.groupBy ? { groups: groupRecords(records, options) } : {})\n }\n}\n\n/**\n * ๊ด€์  ร— ๋น„๊ต ๊ต์ฐจ โ€” **\"๊ตฌ์—ญ๋ณ„๋กœ ์–ด์ œ ๋Œ€๋น„ ์–ด๋–ค๊ฐ€\"**.\n *\n * ์ถ•(๋ฌด์—‡์„)๊ณผ ๋น„๊ต(์–ธ์ œ ๋Œ€๋น„)๋ฅผ ๋”ฐ๋กœ ๋ณด๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ๋จธ๋ฆฟ์†์—์„œ ๋‘ ํ‘œ๋ฅผ ๋Œ€์กฐํ•ด์•ผ ํ•œ๋‹ค. ์šด์˜์—์„œ ๊ฐ€์žฅ\n * ๊ฐ’ ์žˆ๋Š” ์งˆ๋ฌธ์€ ๊ทธ ๊ต์ฐจ๋‹ค: ์ „์ฒด๋Š” ๋น„์Šทํ•œ๋ฐ **ํ•œ ๊ตฌ์—ญ๋งŒ ๋‚˜๋น ์ง„** ๊ฒฝ์šฐ๋ฅผ ์ „์ฒด ์ˆซ์ž๋กœ๋Š” ์ ˆ๋Œ€ ๋ชป ๋ณธ๋‹ค.\n *\n * ์ •์ง์„ฑ ๊ทœ์œจ:\n * ยท ๋‘ ๊ตฌ๊ฐ„์— **๋ชจ๋‘ ์žˆ๋Š”** ์ถ•๋งŒ delta ๋ฅผ ๋‚ธ๋‹ค.\n * ยท ์ง€๊ธˆ๋งŒ ์žˆ๋Š” ์ถ•์€ `isNew`(์ด์ „์— ์—†๋˜ ์ผ) โ€” delta ๋ฅผ ๊ฑด์ˆ˜์™€ ๊ฐ™๊ฒŒ ์ ์œผ๋ฉด \"๋Š˜์—ˆ๋‹ค\" ๋กœ ์˜ค๋…๋œ๋‹ค.\n * ยท **์‚ฌ๋ผ์ง„ ์ถ•**(์ „์— ์žˆ์—ˆ๊ณ  ์ง€๊ธˆ ์—†๋Š” ๊ฒƒ)์€ ๋”ฐ๋กœ ๋Œ๋ ค์ค€๋‹ค. ํ‘œ์—์„œ ๊ทธ๋ƒฅ ๋น ์ง€๋ฉด **๋ฉˆ์ถ˜ ๊ตฌ์—ญ์ด\n * ๋ˆˆ์— ๋ณด์ด์ง€ ์•Š๋Š”๋‹ค** โ€” ์šด์˜์—์„œ๋Š” ์ด๊ฒƒ์ด ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์‹ ํ˜ธ์ผ ์ˆ˜ ์žˆ๋‹ค.\n */\nexport interface CrossedGroup extends KpiGroup {\n /** ๋น„๊ต ๊ตฌ๊ฐ„์˜ ๊ฑด์ˆ˜(๋‘ ๊ตฌ๊ฐ„์— ๋ชจ๋‘ ์žˆ์„ ๋•Œ๋งŒ). */\n prevTasks?: number\n /** ํ˜„์žฌ โˆ’ ๋น„๊ต๊ตฌ๊ฐ„ ๊ฑด์ˆ˜(๋‘ ๊ตฌ๊ฐ„์— ๋ชจ๋‘ ์žˆ์„ ๋•Œ๋งŒ). */\n deltaTasks?: number\n /** ๋น„๊ต ๊ตฌ๊ฐ„ ๋Œ€๋น„ ์ž‘์—…์‹œ๊ฐ„ ์ค‘์•™๊ฐ’ ์ฐจ์ด(๋‘˜ ๋‹ค ์ธก์ •๋œ ๋•Œ๋งŒ). */\n deltaWorkP50Ms?: number\n /** ๋น„๊ต ๊ตฌ๊ฐ„์—๋Š” ์—†๋˜ ์ถ• โ€” delta ๋Œ€์‹  ์ด ํ‘œ์‹์„ ์ค€๋‹ค. */\n isNew?: boolean\n}\n\nexport function crossGroups(\n now: KpiGroup[],\n prev: KpiGroup[]\n): { items: CrossedGroup[]; disappeared: { key: string; tasks: number }[] } {\n const before = new Map(prev.map(g => [g.key, g]))\n const items: CrossedGroup[] = now.map(g => {\n const p = before.get(g.key)\n if (!p) return { ...g, isNew: true }\n return {\n ...g,\n prevTasks: p.tasks,\n deltaTasks: g.tasks - p.tasks,\n ...(deltaP50(g.workTime, p.workTime) !== undefined ? { deltaWorkP50Ms: deltaP50(g.workTime, p.workTime) } : {})\n }\n })\n const present = new Set(now.map(g => g.key))\n const disappeared = prev.filter(g => !present.has(g.key)).map(g => ({ key: g.key, tasks: g.tasks }))\n return { items, disappeared }\n}\n\n/* โ”€โ”€ ์‹œ๊ฐ„ ๋น„๊ต โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * ์ˆซ์ž ํ•˜๋‚˜๋กœ๋Š” ์ข‹์•„์กŒ๋Š”์ง€ ๋‚˜๋น ์กŒ๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค(\"29์ดˆ\" ๊ฐ€ ๊ฐœ์„ ์ธ์ง€ ์•…ํ™”์ธ์ง€). ๊ฐ™์€ ๊ธธ์ด์˜ ์ฐฝ์„ ์˜ฎ๊ฒจ\n * ํ•œ ๋ฒˆ ๋” ์ ‘์œผ๋ฉด ๋˜๋ฏ€๋กœ(ํด๋“œ๋Š” ์ˆœ์ˆ˜) ๊ฐ’์‹ธ๋‹ค. ์ฐฝ ์˜ฎ๊ธฐ๊ธฐ์™€ ์ฐจ์ด ๊ณ„์‚ฐ์€ ๊ณ„์‚ฐ ๊ทœ์น™์ด๋ผ ์—ฌ๊ธฐ ์žˆ๋‹ค โ€”\n * ์กฐํšŒ ์ธต์— ๋‘๋ฉด ํ…Œ์ŠคํŠธ๊ฐ€ DB ๋ฅผ ๋Œ๊ณ  ์™€์•ผ ํ•œ๋‹ค.\n */\n\n/**\n * ๋น„๊ต ๊ตฌ๊ฐ„์˜ ์ฐฝ โ€” ๊ฐ™์€ **๊ธธ์ด**๋กœ ์˜ฎ๊ธด๋‹ค.\n *\n * previous: ๋ฐ”๋กœ ์•ž ๊ตฌ๊ฐ„(๊ฒฝ๊ณ„๊ฐ€ ๋งž๋ฌผ๋ฆฌ๊ฒŒ โ€” ๊ฒน์น˜๊ฑฐ๋‚˜ ๋ฒŒ์–ด์ง€๋ฉด ๊ตฌ๊ฐ„์˜ ํ•ฉ์ด ์–ด๊ธ‹๋‚œ๋‹ค).\n * yesterday: ์ •ํ™•ํžˆ 24์‹œ๊ฐ„ ์ „ ๊ฐ™์€ ์ž๋ฆฌ. ์‹œ๋ฎฌ ํŠธ์œˆ์˜ ํด๋ก์ด ์‹ค์ œ ์‹œ๊ฐ๊ณผ ๋‹ฌ๋ผ๋„ **์ฐจ๋ถ„์€ ์ •ํ™•**ํ•˜๋‹ค.\n */\nexport function shiftWindow(fromMs: number, toMs: number, basis: 'previous' | 'yesterday'): KpiWindow {\n const span = toMs - fromMs\n const back = basis === 'yesterday' ? 24 * 60 * 60_000 : span\n return { fromMs: fromMs - back, toMs: toMs - back }\n}\n\n/**\n * ์ค‘์•™๊ฐ’ ์ฐจ์ด(ํ˜„์žฌ โˆ’ ๋น„๊ต๊ตฌ๊ฐ„) โ€” **๋‘˜ ๋‹ค ์ธก์ •๋œ ๊ฒƒ๋งŒ** ๋‚ธ๋‹ค.\n *\n * ํ•œ์ชฝ์ด ๊ฒฐ์ธก์ด๋ฉด ์ฐจ์ด๋Š” **์—†๋Š” ๊ฒƒ**์ด๋‹ค(0 ์ด ์•„๋‹ˆ๋‹ค). 0 ์œผ๋กœ ๋‚ด๋ฉด \"๋ณ€ํ™” ์—†์Œ\" ์ด๋ผ๋Š” ๊ฑฐ์ง“์ด ๋œ๋‹ค.\n * ์ข‹๊ณ  ๋‚˜์จ์€ ํŒ๋‹จํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” ์ฒ˜๋ฆฌ๋Ÿ‰์€ ํด์ˆ˜๋ก, ์†Œ์š”๋Š” ์ž‘์„์ˆ˜๋ก ์ข‹๋‹ค๋Š” ํ•ด์„์€ ์†Œ๋น„์ฒ˜์˜ ๋ชซ์ด๋‹ค.\n */\nexport function deltaP50(now: DurationStats, prev: DurationStats): number | undefined {\n return now.count > 0 && prev.count > 0 ? now.p50Ms - prev.p50Ms : undefined\n}\n\n/** ๊ตฌ๊ฐ„ ํ•˜๋‚˜์˜ ์ตœ์†Œ ์š”์•ฝ โ€” ์ถ”์„ธ๋ฅผ ๊ทธ๋ฆด ์ •๋ณด๋งŒ(์ „์ฒด KPI ๋ฅผ ๊ตฌ๊ฐ„๋งˆ๋‹ค ์‹ค์–ด ๋ณด๋‚ด์ง€ ์•Š๋Š”๋‹ค). */\nexport interface KpiBucket {\n fromMs: number\n toMs: number\n tasks: number\n orders: number\n /** ๊ทธ ๊ตฌ๊ฐ„์˜ ์ž‘์—…์‹œ๊ฐ„ ์ค‘์•™๊ฐ’ โ€” ์ถ”์„ธ์—์„œ \"๋А๋ ค์ง€๊ณ  ์žˆ๋Š”๊ฐ€\" ๋ฅผ ๋ณด๋Š” ๊ฐ’. */\n workP50Ms: number\n}\n\n/**\n * ์ฐฝ์„ N ๋“ฑ๋ถ„ํ•ด ๊ตฌ๊ฐ„๋ณ„๋กœ ์ ‘๋Š”๋‹ค โ€” **๊ฐ™์€ ์ด๋ฒคํŠธ๋ฅผ ์ฐฝ๋งŒ ๋ฐ”๊ฟ”** ๋‹ค์‹œ ์ ‘๋Š”๋‹ค(์กฐํšŒ ์ถ”๊ฐ€ ์—†์Œ).\n *\n * ๋งˆ์ง€๋ง‰ ๊ตฌ๊ฐ„์€ ๋‚˜๋จธ์ง€๋ฅผ ํก์ˆ˜ํ•œ๋‹ค(๋ถ€๋™์†Œ์ˆ˜ ๋‚˜๋ˆ—์…ˆ์œผ๋กœ ๋์ด ๋ฐ€๋ฆฌ๋ฉด ๋งˆ์ง€๋ง‰ ์™„๋ฃŒ๊ฐ€ ๋น ์ง„๋‹ค).\n * `count <= 1` ์ด๋ฉด ์ชผ๊ฐค ๊ฒƒ์ด ์—†์œผ๋ฏ€๋กœ ๋นˆ ๋ฐฐ์—ด โ€” ํ˜ธ์ถœ๋ถ€๊ฐ€ \"์ถ”์„ธ ์—†์Œ\" ์œผ๋กœ ๋‹ค๋ฃฌ๋‹ค.\n */\nexport function foldKpiBuckets(events: KpiEvent[], window: KpiWindow, count: number): KpiBucket[] {\n const n = Math.max(0, Math.min(48, Math.floor(count)))\n if (n <= 1) return []\n const step = (window.toMs - window.fromMs) / n\n const out: KpiBucket[] = []\n for (let i = 0; i < n; i++) {\n const fromMs = window.fromMs + step * i\n const toMs = i === n - 1 ? window.toMs : window.fromMs + step * (i + 1)\n const b = foldKpi(events, { fromMs, toMs })\n out.push({ fromMs, toMs, tasks: b.throughput.tasks, orders: b.throughput.orders, workP50Ms: b.workTime.p50Ms })\n }\n return out\n}\n"]}
@@ -85,14 +85,14 @@ export interface TwinKpiOutput extends Omit<Partial<KpiResult>, 'window'> {
85
85
  /**
86
86
  * ๋ฌด์—‡์„ ์ง‘๊ณ„ํ–ˆ๋‚˜ โ€” ๊ณต๊ฐ„์ด๋ฉด ํ•ฉ์ณ ์ ‘์€ ํŠธ์œˆ ๋ชฉ๋ก.
87
87
  *
88
- * `realityModes` ๋Š” **์ด ์ˆซ์ž๊ฐ€ ๋ฌด์—‡์˜ ์„ฑ๊ณผ์ธ์ง€**๋ฅผ ๋งํ•œ๋‹ค: mirror(์‹ค์ œ ์‹œ์Šคํ…œ์„ ๋ฐ˜์˜) ยท
89
- * sim-world(๊ฐ€์ƒ ์„ธ๊ณ„) ยท sim-experiment(์‹คํ—˜ ์‚ฌ๋ณธ). ๊ฐ™์€ "345๊ฑด" ์ด ํ˜„์‹ค์˜ ์‹ค์ ์ผ ์ˆ˜๋„, ์‹œ๋ฎฌ๋ ˆ์ด์…˜์˜
88
+ * `restartPolicies` ๋Š” **์ด ์ˆซ์ž๊ฐ€ ๋ฌด์—‡์˜ ์„ฑ๊ณผ์ธ์ง€**๋ฅผ ๋งํ•œ๋‹ค: mirror(์‹ค์ œ ์‹œ์Šคํ…œ์„ ๋ฐ˜์˜) ยท
89
+ * `resume`(์ด์–ด์ง€๋Š” ๊ฐ€์ƒ ์„ธ๊ณ„) ยท `reset`(์žฌํ˜„ ์‹คํ—˜ ์‚ฌ๋ณธ). ๊ฐ™์€ "345๊ฑด" ์ด ํ˜„์‹ค์˜ ์‹ค์ ์ผ ์ˆ˜๋„, ์‹œ๋ฎฌ๋ ˆ์ด์…˜์˜
90
90
  * ์‚ฐ์ถœ์ผ ์ˆ˜๋„ ์žˆ๋‹ค โ€” ๊ทธ ๊ตฌ๋ณ„ ์—†์ด ์ˆซ์ž๋งŒ ๋ณด์—ฌ์ฃผ๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์‹œ๋ฎฌ ๊ฒฐ๊ณผ๋ฅผ ์‹ค์ ์œผ๋กœ ์ฐฉ๊ฐํ•œ๋‹ค.
91
91
  */
92
92
  scope: {
93
93
  spaceId?: string;
94
94
  instanceIds: string[];
95
- realityModes: string[];
95
+ restartPolicies: string[];
96
96
  };
97
97
  /** ๊ตฌ๊ฐ„๋ณ„ ๊ฐ’(์š”์ฒญํ–ˆ์„ ๋•Œ๋งŒ) โ€” ์ถ”์„ธ๋ฅผ ๊ทธ๋ฆฌ๊ธฐ ์œ„ํ•œ ์ตœ์†Œ ์ •๋ณด. */
98
98
  buckets?: {
@@ -347,8 +347,8 @@ async function resolveTargets(input) {
347
347
  /* ๋ชฉ๋ก์—์„œ ๋ชป ์ฐพ์•„๋„(์ •์ง€ยท๋น„๋“ฑ๋ก) ์ง€์ •๋œ ํŠธ์œˆ์€ ๊ทธ๋Œ€๋กœ ์กฐํšŒํ•œ๋‹ค โ€” ์ €๋„์€ ๋‚จ์•„ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. */
348
348
  const instanceIds = rows.length ? rows.map((x) => x.instanceId) : input.instanceId ? [input.instanceId] : [];
349
349
  /* ์ปฌ๋Ÿผ์ด NOT NULL ์ด๋ผ 'unknown' ์œผ๋กœ ๋ฉ”์šธ ์ผ์ด ์—†๋‹ค โ€” ๋น„๋ฉด ๊ณ„์•ฝ์ด ๊นจ์ง„ ๊ฒƒ์ด์ง€ ๋ชจ๋ฅด๋Š” ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๋‹ค. */
350
- const realityModes = [...new Set(rows.map((x) => String(x.realityMode)))];
351
- return { instanceIds, realityModes };
350
+ const restartPolicies = [...new Set(rows.map((x) => String(x.restartPolicy)))];
351
+ return { instanceIds, restartPolicies };
352
352
  }
353
353
  /**
354
354
  * ๋Œ€์ƒ ํ•ด์†Œ ๊ณต๊ฐœ ์ฐฝ๊ตฌ โ€” **์ €๋„ ๋ชฉ๋ก ์งˆ์˜๋„ KPI ์™€ ๊ฐ™์€ ๊ทœ์น™์„ ์จ์•ผ ํ•œ๋‹ค.**
@@ -368,8 +368,8 @@ async function resolveTwinTargets(domainId, instanceId, spaceId) {
368
368
  async function computeTwinKpi(input) {
369
369
  const minutes = Math.max(1, Math.min(24 * 60, Number(input.windowMinutes) || 60));
370
370
  const lookbackMs = Math.max(0, Math.min(24 * 60, input.lookbackMinutes ?? 60)) * 60_000;
371
- const { instanceIds, realityModes } = await resolveTargets(input);
372
- const scope = { spaceId: input.spaceId, instanceIds, realityModes };
371
+ const { instanceIds, restartPolicies } = await resolveTargets(input);
372
+ const scope = { spaceId: input.spaceId, instanceIds, restartPolicies };
373
373
  /* ๋ ์‹œ๊ฐ โ€” ์ง€์ •์ด ์—†์œผ๋ฉด ๋Œ€์ƒ๋“ค์˜ ๋งˆ์ง€๋ง‰ ๊ธฐ๋ก. ๊ทธ๊ฒƒ๋„ ์—†์œผ๋ฉด ์ธก์ •ํ•  ๊ฒƒ์ด ์—†๋‹ค. */
374
374
  let basis = 'given';
375
375
  let toMs = input.toTime ? Date.parse(input.toTime) : NaN;