@things-factory/headless-twin 10.0.10 โ 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.
- package/dist-server/engine/canonical-ingest.d.ts +25 -2
- package/dist-server/engine/canonical-ingest.js +48 -10
- package/dist-server/engine/canonical-ingest.js.map +1 -1
- package/dist-server/engine/declared-stimulus.d.ts +43 -0
- package/dist-server/engine/declared-stimulus.js +57 -0
- package/dist-server/engine/declared-stimulus.js.map +1 -0
- package/dist-server/engine/index.d.ts +2 -0
- package/dist-server/engine/index.js +2 -0
- package/dist-server/engine/index.js.map +1 -1
- package/dist-server/engine/kpi-fold.d.ts +12 -0
- package/dist-server/engine/kpi-fold.js +21 -1
- package/dist-server/engine/kpi-fold.js.map +1 -1
- package/dist-server/engine/kpi-query.d.ts +3 -3
- package/dist-server/engine/kpi-query.js +4 -4
- package/dist-server/engine/kpi-query.js.map +1 -1
- package/dist-server/engine/live-feed-registry.d.ts +1 -1
- package/dist-server/engine/live-feed-registry.js +1 -1
- package/dist-server/engine/live-feed-registry.js.map +1 -1
- package/dist-server/engine/local-declarations.d.ts +3 -6
- package/dist-server/engine/local-declarations.js +97 -16
- package/dist-server/engine/local-declarations.js.map +1 -1
- package/dist-server/engine/measured-yield.d.ts +42 -0
- package/dist-server/engine/measured-yield.js +75 -0
- package/dist-server/engine/measured-yield.js.map +1 -0
- package/dist-server/engine/operation-basis.d.ts +16 -0
- package/dist-server/engine/operation-basis.js +20 -2
- package/dist-server/engine/operation-basis.js.map +1 -1
- package/dist-server/engine/property-effects.js +17 -0
- package/dist-server/engine/property-effects.js.map +1 -1
- package/dist-server/engine/restart-policy.d.ts +13 -0
- package/dist-server/engine/restart-policy.js +52 -0
- package/dist-server/engine/restart-policy.js.map +1 -0
- package/dist-server/engine/spec-coverage.d.ts +8 -0
- package/dist-server/engine/spec-coverage.js +3 -1
- package/dist-server/engine/spec-coverage.js.map +1 -1
- package/dist-server/engine/twin-engine.d.ts +48 -15
- package/dist-server/engine/twin-engine.js +179 -39
- package/dist-server/engine/twin-engine.js.map +1 -1
- package/dist-server/index.js +1 -1
- package/dist-server/index.js.map +1 -1
- package/dist-server/service/index.d.ts +1 -1
- package/dist-server/service/reference/control-routing.d.ts +14 -0
- package/dist-server/service/reference/control-routing.js +64 -0
- package/dist-server/service/reference/control-routing.js.map +1 -0
- package/dist-server/service/reference/index.d.ts +1 -0
- package/dist-server/service/reference/index.js +2 -0
- package/dist-server/service/reference/index.js.map +1 -1
- package/dist-server/service/reference/reference-adapter.d.ts +67 -0
- package/dist-server/service/reference/reference-adapter.js +18 -0
- package/dist-server/service/reference/reference-adapter.js.map +1 -1
- package/dist-server/service/reference/reference-live.js +3 -3
- package/dist-server/service/reference/reference-live.js.map +1 -1
- package/dist-server/service/reference/reference-resolver.d.ts +3 -3
- package/dist-server/service/reference/reference-resolver.js +35 -18
- package/dist-server/service/reference/reference-resolver.js.map +1 -1
- package/dist-server/service/twin-audit/command-audit.d.ts +34 -0
- package/dist-server/service/twin-audit/command-audit.js +15 -1
- package/dist-server/service/twin-audit/command-audit.js.map +1 -1
- package/dist-server/service/twin-audit/twin-audit-event.d.ts +3 -0
- package/dist-server/service/twin-audit/twin-audit-event.js +28 -2
- package/dist-server/service/twin-audit/twin-audit-event.js.map +1 -1
- package/dist-server/service/twin-control/twin-control-mutation.d.ts +15 -2
- package/dist-server/service/twin-control/twin-control-mutation.js +85 -34
- package/dist-server/service/twin-control/twin-control-mutation.js.map +1 -1
- package/dist-server/service/twin-event/twin-event.js +1 -1
- package/dist-server/service/twin-event/twin-event.js.map +1 -1
- package/dist-server/service/twin-instance/twin-instance.d.ts +1 -1
- package/dist-server/service/twin-instance/twin-instance.js +2 -2
- package/dist-server/service/twin-instance/twin-instance.js.map +1 -1
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js +2 -1
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +1 -1
- package/dist-server/service/twin-model/twin-equipment.js +1 -1
- package/dist-server/service/twin-model/twin-equipment.js.map +1 -1
- package/dist-server/service/twin-model/twin-location.js +1 -1
- package/dist-server/service/twin-model/twin-location.js.map +1 -1
- package/dist-server/service/twin-model/twin-model-query.js +1 -1
- package/dist-server/service/twin-model/twin-model-query.js.map +1 -1
- package/dist-server/service/twin-model/twin-operation.js +1 -1
- package/dist-server/service/twin-model/twin-operation.js.map +1 -1
- package/package.json +3 -3
- package/server/engine/canonical-ingest.ts +78 -14
- package/server/engine/declared-stimulus.ts +66 -0
- package/server/engine/index.ts +2 -0
- package/server/engine/kpi-fold.ts +29 -1
- package/server/engine/kpi-query.ts +8 -8
- package/server/engine/live-feed-registry.ts +2 -2
- package/server/engine/local-declarations.ts +97 -19
- package/server/engine/measured-yield.ts +89 -0
- package/server/engine/operation-basis.ts +33 -2
- package/server/engine/property-effects.ts +17 -0
- package/server/engine/restart-policy.ts +55 -0
- package/server/engine/spec-coverage.ts +23 -3
- package/server/engine/twin-engine.ts +201 -42
- package/server/index.ts +1 -1
- package/server/service/reference/control-routing.ts +62 -0
- package/server/service/reference/index.ts +1 -0
- package/server/service/reference/reference-adapter.ts +78 -0
- package/server/service/reference/reference-live.ts +3 -3
- package/server/service/reference/reference-resolver.ts +46 -7
- package/server/service/twin-audit/command-audit.ts +34 -1
- package/server/service/twin-audit/twin-audit-event.ts +50 -4
- package/server/service/twin-control/twin-control-mutation.ts +75 -28
- package/server/service/twin-event/twin-event.ts +10 -2
- package/server/service/twin-instance/twin-instance.ts +16 -10
- package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +2 -1
- package/server/service/twin-model/twin-equipment.ts +8 -1
- package/server/service/twin-model/twin-location.ts +8 -1
- package/server/service/twin-model/twin-model-query.ts +1 -1
- package/server/service/twin-model/twin-operation.ts +8 -1
- package/test/adopt-structure-live.test.ts +7 -7
- package/test/boot-resume.test.ts +3 -3
- package/test/column-type-portability.test.ts +122 -0
- package/test/control-capability.test.ts +103 -0
- package/test/declared-stimulus.test.ts +88 -0
- package/test/ingest-running-guard.test.ts +5 -5
- package/test/instance-cache-lifecycle.test.ts +1 -1
- package/test/kpi-baseline-db.test.ts +1 -1
- package/test/kpi-query-bench.test.ts +1 -1
- package/test/lineage-survives-restart.test.ts +3 -3
- package/test/live-feed-registry.test.ts +6 -6
- package/test/local-declarations.test.ts +108 -1
- package/test/measured-yield.test.ts +90 -0
- package/test/operation-basis.test.ts +28 -1
- package/test/operational-vocabulary.test.ts +108 -0
- package/test/operations-capability-db.test.ts +4 -4
- package/test/project-structure-db.test.ts +1 -1
- package/test/projection-reaches-screen.test.ts +1 -1
- package/test/property-effects.test.ts +28 -0
- package/test/restart-policy.test.ts +111 -0
- package/test/resync-origin-site.test.ts +7 -1
- package/test/source-outcome-audit.test.ts +104 -0
- package/test/structure-revision-db.test.ts +27 -27
- package/test/tenant-registry-db.test.ts +2 -2
- package/test/twin-model-item-db.test.ts +3 -3
- package/test/twin-model-tree-db.test.ts +7 -7
- package/test/twin-origin-resync.test.ts +4 -4
- package/test/yield-loop.test.ts +144 -0
- 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":"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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 * **ํ์ง ํ์ ์ด ์์๋ ๊ฑด์๋ง** ์ผ๋ค (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
|
-
* `
|
|
89
|
-
*
|
|
88
|
+
* `restartPolicies` ๋ **์ด ์ซ์๊ฐ ๋ฌด์์ ์ฑ๊ณผ์ธ์ง**๋ฅผ ๋งํ๋ค: mirror(์ค์ ์์คํ
์ ๋ฐ์) ยท
|
|
89
|
+
* `resume`(์ด์ด์ง๋ ๊ฐ์ ์ธ๊ณ) ยท `reset`(์ฌํ ์คํ ์ฌ๋ณธ). ๊ฐ์ "345๊ฑด" ์ด ํ์ค์ ์ค์ ์ผ ์๋, ์๋ฎฌ๋ ์ด์
์
|
|
90
90
|
* ์ฐ์ถ์ผ ์๋ ์๋ค โ ๊ทธ ๊ตฌ๋ณ ์์ด ์ซ์๋ง ๋ณด์ฌ์ฃผ๋ฉด ์ฌ์ฉ์๊ฐ ์๋ฎฌ ๊ฒฐ๊ณผ๋ฅผ ์ค์ ์ผ๋ก ์ฐฉ๊ฐํ๋ค.
|
|
91
91
|
*/
|
|
92
92
|
scope: {
|
|
93
93
|
spaceId?: string;
|
|
94
94
|
instanceIds: string[];
|
|
95
|
-
|
|
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
|
|
351
|
-
return { instanceIds,
|
|
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,
|
|
372
|
-
const scope = { spaceId: input.spaceId, instanceIds,
|
|
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;
|