@things-factory/headless-twin 10.0.12 → 10.0.14
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 +57 -2
- package/dist-server/engine/canonical-ingest.js +43 -2
- package/dist-server/engine/canonical-ingest.js.map +1 -1
- package/dist-server/engine/command-routing.js +1 -1
- package/dist-server/engine/command-routing.js.map +1 -1
- package/dist-server/engine/index.d.ts +3 -0
- package/dist-server/engine/index.js +4 -0
- package/dist-server/engine/index.js.map +1 -1
- package/dist-server/engine/ingest-health.d.ts +376 -0
- package/dist-server/engine/ingest-health.js +482 -0
- package/dist-server/engine/ingest-health.js.map +1 -0
- package/dist-server/engine/integration-coverage.d.ts +76 -0
- package/dist-server/engine/integration-coverage.js +73 -0
- package/dist-server/engine/integration-coverage.js.map +1 -0
- package/dist-server/engine/integration-probes.d.ts +65 -0
- package/dist-server/engine/integration-probes.js +100 -0
- package/dist-server/engine/integration-probes.js.map +1 -0
- package/dist-server/engine/integration-runner.d.ts +45 -0
- package/dist-server/engine/integration-runner.js +59 -0
- package/dist-server/engine/integration-runner.js.map +1 -0
- package/dist-server/engine/integration-target-profile.d.ts +57 -0
- package/dist-server/engine/integration-target-profile.js +79 -0
- package/dist-server/engine/integration-target-profile.js.map +1 -0
- package/dist-server/engine/kpi-fold.d.ts +27 -0
- package/dist-server/engine/kpi-fold.js +47 -4
- package/dist-server/engine/kpi-fold.js.map +1 -1
- package/dist-server/engine/kpi-query.js +128 -14
- package/dist-server/engine/kpi-query.js.map +1 -1
- package/dist-server/engine/live-feed-registry.js +2 -16
- package/dist-server/engine/live-feed-registry.js.map +1 -1
- package/dist-server/engine/load-meter.d.ts +1 -1
- package/dist-server/engine/load-meter.js +12 -3
- package/dist-server/engine/load-meter.js.map +1 -1
- package/dist-server/engine/log.d.ts +18 -0
- package/dist-server/engine/log.js +80 -0
- package/dist-server/engine/log.js.map +1 -0
- package/dist-server/engine/loop-lag.d.ts +54 -0
- package/dist-server/engine/loop-lag.js +87 -0
- package/dist-server/engine/loop-lag.js.map +1 -0
- package/dist-server/engine/model-gap.d.ts +108 -0
- package/dist-server/engine/model-gap.js +95 -0
- package/dist-server/engine/model-gap.js.map +1 -0
- package/dist-server/engine/restart-policy.d.ts +3 -3
- package/dist-server/engine/restart-policy.js +4 -4
- package/dist-server/engine/restart-policy.js.map +1 -1
- package/dist-server/engine/runtime-key.js +1 -1
- package/dist-server/engine/runtime-key.js.map +1 -1
- package/dist-server/engine/stage-path.d.ts +83 -0
- package/dist-server/engine/stage-path.js +118 -0
- package/dist-server/engine/stage-path.js.map +1 -0
- package/dist-server/engine/twin-engine.d.ts +386 -16
- package/dist-server/engine/twin-engine.js +1217 -172
- package/dist-server/engine/twin-engine.js.map +1 -1
- package/dist-server/index.js +34 -2
- package/dist-server/index.js.map +1 -1
- package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.d.ts +5 -0
- package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js +58 -0
- package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js.map +1 -0
- package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.d.ts +5 -0
- package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js +55 -0
- package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js.map +1 -0
- package/dist-server/migrations/index.js +7 -1
- package/dist-server/migrations/index.js.map +1 -1
- package/dist-server/service/index.d.ts +5 -2
- package/dist-server/service/index.js +18 -7
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/reference/discovery-result.d.ts +1 -1
- package/dist-server/service/reference/discovery-result.js +1 -1
- package/dist-server/service/reference/discovery-result.js.map +1 -1
- package/dist-server/service/reference/index.d.ts +4 -1
- package/dist-server/service/reference/index.js +6 -1
- package/dist-server/service/reference/index.js.map +1 -1
- package/dist-server/service/reference/reference-adapter.d.ts +210 -3
- package/dist-server/service/reference/reference-adapter.js +28 -4
- package/dist-server/service/reference/reference-adapter.js.map +1 -1
- package/dist-server/service/reference/reference-assessment.d.ts +78 -0
- package/dist-server/service/reference/reference-assessment.js +156 -0
- package/dist-server/service/reference/reference-assessment.js.map +1 -0
- package/dist-server/service/reference/reference-live.d.ts +12 -1
- package/dist-server/service/reference/reference-live.js +134 -11
- package/dist-server/service/reference/reference-live.js.map +1 -1
- package/dist-server/service/reference/reference-master.d.ts +59 -3
- package/dist-server/service/reference/reference-master.js +34 -4
- package/dist-server/service/reference/reference-master.js.map +1 -1
- package/dist-server/service/reference/reference-probe.d.ts +92 -0
- package/dist-server/service/reference/reference-probe.js +186 -0
- package/dist-server/service/reference/reference-probe.js.map +1 -0
- package/dist-server/service/reference/reference-progress-subscription.d.ts +17 -0
- package/dist-server/service/reference/reference-progress-subscription.js +94 -0
- package/dist-server/service/reference/reference-progress-subscription.js.map +1 -0
- package/dist-server/service/reference/reference-progress.d.ts +38 -0
- package/dist-server/service/reference/reference-progress.js +71 -0
- package/dist-server/service/reference/reference-progress.js.map +1 -0
- package/dist-server/service/reference/reference-resolver.js +210 -43
- package/dist-server/service/reference/reference-resolver.js.map +1 -1
- package/dist-server/service/reference/twin-reference.d.ts +32 -0
- package/dist-server/service/reference/twin-reference.js +10 -0
- package/dist-server/service/reference/twin-reference.js.map +1 -1
- package/dist-server/service/twin-control/twin-control-mutation.js +4 -3
- package/dist-server/service/twin-control/twin-control-mutation.js.map +1 -1
- package/dist-server/service/twin-event/journal-count.d.ts +21 -0
- package/dist-server/service/twin-event/journal-count.js +26 -0
- package/dist-server/service/twin-event/journal-count.js.map +1 -0
- package/dist-server/service/twin-event/twin-event-keys.d.ts +9 -0
- package/dist-server/service/twin-event/twin-event-keys.js +15 -18
- package/dist-server/service/twin-event/twin-event-keys.js.map +1 -1
- package/dist-server/service/twin-event/twin-event-type.d.ts +3 -1
- package/dist-server/service/twin-event/twin-event-type.js +18 -1
- package/dist-server/service/twin-event/twin-event-type.js.map +1 -1
- package/dist-server/service/twin-event/twin-event.d.ts +1 -0
- package/dist-server/service/twin-event/twin-event.js +9 -1
- package/dist-server/service/twin-event/twin-event.js.map +1 -1
- package/dist-server/service/twin-forecast/twin-forecast-query.js +26 -2
- package/dist-server/service/twin-forecast/twin-forecast-query.js.map +1 -1
- package/dist-server/service/twin-ingest-window/index.d.ts +5 -0
- package/dist-server/service/twin-ingest-window/index.js +10 -0
- package/dist-server/service/twin-ingest-window/index.js.map +1 -0
- package/dist-server/service/twin-ingest-window/twin-ingest-window-query.d.ts +12 -0
- package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js +123 -0
- package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js.map +1 -0
- package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.d.ts +1 -0
- package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js +51 -0
- package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js.map +1 -0
- package/dist-server/service/twin-ingest-window/twin-ingest-window.d.ts +16 -0
- package/dist-server/service/twin-ingest-window/twin-ingest-window.js +108 -0
- package/dist-server/service/twin-ingest-window/twin-ingest-window.js.map +1 -0
- package/dist-server/service/twin-instance/twin-instance.js.map +1 -1
- package/dist-server/service/twin-journal/twin-journal-query.js +58 -5
- package/dist-server/service/twin-journal/twin-journal-query.js.map +1 -1
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.d.ts +14 -0
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js +72 -2
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +1 -1
- package/dist-server/service/twin-metrics/twin-metrics-query.d.ts +1 -0
- package/dist-server/service/twin-metrics/twin-metrics-query.js +78 -3
- package/dist-server/service/twin-metrics/twin-metrics-query.js.map +1 -1
- package/dist-server/service/twin-model/axis-journal-evidence.d.ts +2 -0
- package/dist-server/service/twin-model/axis-journal-evidence.js +89 -0
- package/dist-server/service/twin-model/axis-journal-evidence.js.map +1 -0
- package/dist-server/service/twin-model/epcis-coverage.d.ts +1 -1
- package/dist-server/service/twin-model/epcis-coverage.js +46 -7
- package/dist-server/service/twin-model/epcis-coverage.js.map +1 -1
- package/dist-server/service/twin-model/iec61850-coverage.d.ts +1 -1
- package/dist-server/service/twin-model/iec61850-coverage.js +18 -7
- package/dist-server/service/twin-model/iec61850-coverage.js.map +1 -1
- package/dist-server/service/twin-model/isa95-coverage.d.ts +14 -0
- package/dist-server/service/twin-model/isa95-coverage.js +108 -14
- package/dist-server/service/twin-model/isa95-coverage.js.map +1 -1
- package/dist-server/service/twin-model/item-ref.d.ts +24 -0
- package/dist-server/service/twin-model/item-ref.js +88 -0
- package/dist-server/service/twin-model/item-ref.js.map +1 -0
- package/dist-server/service/twin-model/name-index.d.ts +36 -0
- package/dist-server/service/twin-model/name-index.js +116 -0
- package/dist-server/service/twin-model/name-index.js.map +1 -0
- package/dist-server/service/twin-model/project-structure.js +1 -1
- package/dist-server/service/twin-model/project-structure.js.map +1 -1
- package/dist-server/service/twin-model/status-tally.d.ts +9 -0
- package/dist-server/service/twin-model/status-tally.js +37 -0
- package/dist-server/service/twin-model/status-tally.js.map +1 -0
- package/dist-server/service/twin-model/twin-lineage-query.js +40 -12
- package/dist-server/service/twin-model/twin-lineage-query.js.map +1 -1
- package/dist-server/service/twin-model/twin-model-item-query.js +38 -39
- package/dist-server/service/twin-model/twin-model-item-query.js.map +1 -1
- package/dist-server/service/twin-model/twin-model-query.js +156 -4
- package/dist-server/service/twin-model/twin-model-query.js.map +1 -1
- package/dist-server/service/twin-model/twin-model-tree-query.js +7 -0
- package/dist-server/service/twin-model/twin-model-tree-query.js.map +1 -1
- package/dist-server/service/twin-readiness/index.d.ts +2 -0
- package/dist-server/service/twin-readiness/index.js +6 -0
- package/dist-server/service/twin-readiness/index.js.map +1 -0
- package/dist-server/service/twin-readiness/twin-readiness-query.d.ts +3 -0
- package/dist-server/service/twin-readiness/twin-readiness-query.js +103 -0
- package/dist-server/service/twin-readiness/twin-readiness-query.js.map +1 -0
- package/dist-server/service/twin-space/twin-space-resolver.d.ts +2 -2
- package/dist-server/service/twin-space/twin-space-resolver.js +5 -4
- package/dist-server/service/twin-space/twin-space-resolver.js.map +1 -1
- package/dist-shared/entity-delta.d.ts +23 -3
- package/dist-shared/entity-delta.js +12 -8
- package/dist-shared/entity-delta.js.map +1 -1
- package/dist-shared/kpi-broadcast.js +1 -1
- package/dist-shared/kpi-broadcast.js.map +1 -1
- package/dist-shared/touched-items.d.ts +7 -0
- package/dist-shared/touched-items.js +80 -0
- package/dist-shared/touched-items.js.map +1 -0
- package/package.json +7 -7
- package/server/engine/canonical-ingest.ts +92 -7
- package/server/engine/command-routing.ts +1 -1
- package/server/engine/index.ts +4 -0
- package/server/engine/ingest-health.ts +782 -0
- package/server/engine/integration-coverage.ts +147 -0
- package/server/engine/integration-probes.ts +144 -0
- package/server/engine/integration-runner.ts +95 -0
- package/server/engine/integration-target-profile.ts +103 -0
- package/server/engine/kpi-fold.ts +72 -4
- package/server/engine/kpi-query.ts +129 -15
- package/server/engine/live-feed-registry.ts +2 -1
- package/server/engine/load-meter.ts +12 -3
- package/server/engine/log.ts +72 -0
- package/server/engine/loop-lag.ts +120 -0
- package/server/engine/model-gap.ts +168 -0
- package/server/engine/restart-policy.ts +4 -4
- package/server/engine/runtime-key.ts +1 -1
- package/server/engine/stage-path.ts +172 -0
- package/server/engine/twin-engine.ts +1334 -168
- package/server/index.ts +35 -2
- package/server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.ts +54 -0
- package/server/migrations/1786200000000-CarryLiveFeedCursor.ts +53 -0
- package/server/migrations/index.ts +7 -1
- package/server/service/index.ts +11 -0
- package/server/service/reference/discovery-result.ts +1 -1
- package/server/service/reference/index.ts +6 -1
- package/server/service/reference/reference-adapter.ts +220 -5
- package/server/service/reference/reference-assessment.ts +250 -0
- package/server/service/reference/reference-live.ts +143 -11
- package/server/service/reference/reference-master.ts +76 -6
- package/server/service/reference/reference-probe.ts +264 -0
- package/server/service/reference/reference-progress-subscription.ts +73 -0
- package/server/service/reference/reference-progress.ts +95 -0
- package/server/service/reference/reference-resolver.ts +200 -12
- package/server/service/reference/twin-reference.ts +39 -1
- package/server/service/twin-control/twin-control-mutation.ts +4 -3
- package/server/service/twin-event/journal-count.ts +53 -0
- package/server/service/twin-event/twin-event-keys.ts +16 -1
- package/server/service/twin-event/twin-event-type.ts +26 -2
- package/server/service/twin-event/twin-event.ts +7 -0
- package/server/service/twin-forecast/twin-forecast-query.ts +29 -2
- package/server/service/twin-ingest-window/index.ts +7 -0
- package/server/service/twin-ingest-window/twin-ingest-window-query.ts +125 -0
- package/server/service/twin-ingest-window/twin-ingest-window-writer.ts +57 -0
- package/server/service/twin-ingest-window/twin-ingest-window.ts +113 -0
- package/server/service/twin-instance/twin-instance.ts +1 -1
- package/server/service/twin-journal/twin-journal-query.ts +59 -5
- package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +77 -3
- package/server/service/twin-metrics/twin-metrics-query.ts +81 -3
- package/server/service/twin-model/axis-journal-evidence.ts +57 -0
- package/server/service/twin-model/epcis-coverage.ts +29 -8
- package/server/service/twin-model/iec61850-coverage.ts +2 -8
- package/server/service/twin-model/isa95-coverage.ts +107 -14
- package/server/service/twin-model/item-ref.ts +80 -0
- package/server/service/twin-model/name-index.ts +94 -0
- package/server/service/twin-model/project-structure.ts +1 -1
- package/server/service/twin-model/status-tally.ts +37 -0
- package/server/service/twin-model/twin-lineage-query.ts +38 -9
- package/server/service/twin-model/twin-model-item-query.ts +26 -27
- package/server/service/twin-model/twin-model-query.ts +155 -4
- package/server/service/twin-model/twin-model-tree-query.ts +7 -0
- package/server/service/twin-readiness/index.ts +3 -0
- package/server/service/twin-readiness/twin-readiness-query.ts +96 -0
- package/server/service/twin-space/twin-space-resolver.ts +5 -4
- package/shared/entity-delta.ts +31 -7
- package/shared/kpi-broadcast.ts +1 -1
- package/shared/touched-items.ts +73 -0
- package/test/axis-journal-evidence.test.ts +71 -0
- package/test/axis-read.test.ts +101 -1
- package/test/boot-resume.test.ts +92 -26
- package/test/broadcast-cost-baseline.test.ts +200 -0
- package/test/broadcast-period.test.ts +58 -0
- package/test/canonical-ingest-vocabularies.test.ts +36 -1
- package/test/canonical-quantity-door.test.ts +61 -0
- package/test/checkpoint-refuses-empty.test.ts +103 -0
- package/test/command-routing.test.ts +1 -1
- package/test/cursor-stall-not-read-failure.test.ts +126 -0
- package/test/declared-location-types.test.ts +89 -0
- package/test/discovery-result.test.ts +1 -1
- package/test/duration-estimators.test.ts +1 -1
- package/test/entity-delta.test.ts +2 -2
- package/test/ingest-bench.test.ts +3 -3
- package/test/ingest-health-engine.test.ts +248 -0
- package/test/ingest-health-wiring.test.ts +119 -0
- package/test/ingest-health.test.ts +306 -0
- package/test/ingest-history.test.ts +247 -0
- package/test/integration-probes.test.ts +103 -0
- package/test/integration-runner.test.ts +95 -0
- package/test/item-ref.test.ts +78 -0
- package/test/journal-read-discipline.test.ts +177 -0
- package/test/journal-retention.test.ts +133 -0
- package/test/journal-sort-axis.test.ts +142 -0
- package/test/journal-write-door.test.ts +110 -0
- package/test/journal-write-trend.test.ts +115 -0
- package/test/kernel-kind-guard.test.ts +4 -4
- package/test/kpi-fold.test.ts +90 -3
- package/test/kpi-query-bench.test.ts +2 -2
- package/test/lineage-survives-restart.test.ts +17 -1
- package/test/live-cursor-wiring.test.ts +87 -0
- package/test/live-feed-registry.test.ts +9 -1
- package/test/live-kernel-facts.test.ts +7 -7
- package/test/live-mirror-parity.test.ts +6 -0
- package/test/load-meter.test.ts +29 -15
- package/test/local-declarations.test.ts +1 -1
- package/test/log-stamp.test.ts +59 -0
- package/test/loop-lag.test.ts +82 -0
- package/test/mirror-resumes-from-checkpoint.test.ts +192 -0
- package/test/model-gap.test.ts +153 -0
- package/test/oee-accumulator.test.ts +4 -0
- package/test/operational-vocabulary.test.ts +4 -4
- package/test/read-failure-visible.test.ts +145 -0
- package/test/reference-grounding.test.ts +70 -0
- package/test/resolve-ts-siblings.mjs +52 -0
- package/test/restart-policy.test.ts +7 -7
- package/test/revision-axis.test.ts +104 -0
- package/test/runtime-key.test.ts +2 -2
- package/test/scale-twin-bench.test.ts +2 -2
- package/test/spec-coverage.test.ts +1 -1
- package/test/stage-path.test.ts +95 -0
- package/test/standard-coverage.test.ts +15 -3
- package/test/status-tally.test.ts +55 -0
- package/test/structure-revision-db.test.ts +4 -0
- package/test/tenant-registry-db.test.ts +1 -1
- package/test/time-range.test.ts +152 -0
- package/test/touched-items.test.ts +61 -0
- package/test/twin-event-keys.test.ts +10 -2
- package/test/twin-model-item-db.test.ts +2 -0
- package/test/warm-start-seam.test.ts +4 -0
- package/test/yield-loop.test.ts +57 -2
- package/tsconfig.shared.tsbuildinfo +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,7 +1,24 @@
|
|
|
1
1
|
import { type EnergyRecord, type EnergyEquipmentRecord, type OperationalRecord, type IngestResult } from '@operato/twin-kernel';
|
|
2
2
|
/** 개체 관측 — 물건 하나가 어디서 무엇이 됐나. */
|
|
3
3
|
export interface CanonicalRecord {
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* 개체 하나의 식별자. **`quantityList` 를 쓰면 없어도 된다** — 낱개 번호가 없는 자재(밀가루 3.5kg)는
|
|
6
|
+
* 개체가 없다. 둘 다 없으면 무엇을 관측했는지 말하지 않은 것이므로 커널 매핑이 거부한다.
|
|
7
|
+
*/
|
|
8
|
+
epc?: string;
|
|
9
|
+
/**
|
|
10
|
+
* 클래스와 수량 — `{ epcClass, quantity, uom? }`. **잔량 절대값을 싣는다**(「얼마 뺐다」가 아니라
|
|
11
|
+
* 「얼마 남았다」). 그래야 사건 하나를 놓쳐도 다음 사건이 정답을 다시 말해 주고 오차가 쌓이지 않는다.
|
|
12
|
+
*
|
|
13
|
+
* 담김(`childQuantityList`)이 하루 먼저 이 자리를 받았다 — 그때와 같은 이유다. 원본이 비직렬 수량을
|
|
14
|
+
* 말할 길이 없어서, 그것이 주된 경로인 시스템(식품 제조 MES)은 라이브를 낼 수 없었다. 커널의
|
|
15
|
+
* 관측 리듀서는 처음부터 이 값을 읽었고 문만 없었다.
|
|
16
|
+
*/
|
|
17
|
+
quantityList?: {
|
|
18
|
+
epcClass: string;
|
|
19
|
+
quantity?: number;
|
|
20
|
+
uom?: string;
|
|
21
|
+
}[];
|
|
5
22
|
action: string;
|
|
6
23
|
bizStep: string;
|
|
7
24
|
disposition?: string;
|
|
@@ -14,6 +31,44 @@ export interface CanonicalRecord {
|
|
|
14
31
|
* 이름은 표준의 것을 그대로 쓴다(`parentID`·`childEPCs`) — 여기서 다시 지으면 매핑이 번역이 되고,
|
|
15
32
|
* 같은 사실에 두 어휘가 생긴다.
|
|
16
33
|
*/
|
|
34
|
+
/**
|
|
35
|
+
* 변환 관측 — **무엇으로 무엇이 되었나.** 입력과 출력이 **한 사실에 함께** 있어야 계보가 남는다.
|
|
36
|
+
*
|
|
37
|
+
* 따로 보내면(「이 로트가 없어졌다」와 「이 제품이 생겼다」) 그 둘을 이을 근거가 없다. 그래서 표준이
|
|
38
|
+
* 한 사건에 둘을 담고, 우리 레코드도 같은 모양이다.
|
|
39
|
+
*
|
|
40
|
+
* 이름은 **표준의 것을 그대로** 쓴다(`inputQuantityList` 등). 갈래 판정이 이 이름으로 이루어지므로
|
|
41
|
+
* 커넥터 낱말(`consumed`·`produced`)로 담으면 판정되지 않는다 — 커넥터가 정규 이름으로 담아 보내고
|
|
42
|
+
* 매핑은 그 안에서 값을 고른다.
|
|
43
|
+
*
|
|
44
|
+
* **없는 쪽은 필드를 만들지 않는다.** 빈 배열을 실으면 「없다」고 말하는 것이 된다. 소실(N→0)과
|
|
45
|
+
* 생성(0→N)도 표준이 인정하는 변환이다.
|
|
46
|
+
*
|
|
47
|
+
* `transformationID` 가 한 오더의 여러 단계를 잇는다 — 소비를 먼저 알고 산출을 나중에 알게 되는 원본에서
|
|
48
|
+
* 그 둘을 묶는 유일한 자리다.
|
|
49
|
+
*/
|
|
50
|
+
export interface CanonicalTransformationRecord {
|
|
51
|
+
/** 개체로 소비된 것. */
|
|
52
|
+
inputEPCList?: string[];
|
|
53
|
+
/** 클래스와 수량으로 소비된 것 — 로트 단위 소비가 이 자리다. */
|
|
54
|
+
inputQuantityList?: {
|
|
55
|
+
epcClass: string;
|
|
56
|
+
quantity?: number;
|
|
57
|
+
uom?: string;
|
|
58
|
+
}[];
|
|
59
|
+
outputEPCList?: string[];
|
|
60
|
+
outputQuantityList?: {
|
|
61
|
+
epcClass: string;
|
|
62
|
+
quantity?: number;
|
|
63
|
+
uom?: string;
|
|
64
|
+
}[];
|
|
65
|
+
/** 한 오더의 여러 단계를 잇는 식별자. */
|
|
66
|
+
transformationID?: string;
|
|
67
|
+
bizStep: string;
|
|
68
|
+
disposition?: string;
|
|
69
|
+
readPoint?: string;
|
|
70
|
+
bizLocation?: string;
|
|
71
|
+
}
|
|
17
72
|
export interface CanonicalAggregationRecord {
|
|
18
73
|
parentID: string;
|
|
19
74
|
/** 개체로 담긴 자식. 수량으로만 담겼으면 없다(둘 중 하나는 있어야 한다). */
|
|
@@ -31,4 +86,4 @@ export interface CanonicalAggregationRecord {
|
|
|
31
86
|
bizLocation?: string;
|
|
32
87
|
}
|
|
33
88
|
/** 정규 레코드[] → 검증된 CanonicalEnvelope[] (+ 거부분). 순수 함수. 단일→객체도 배열로 정규화. */
|
|
34
|
-
export declare function ingestCanonicalRecords(records: CanonicalRecord | CanonicalAggregationRecord | EnergyRecord | EnergyEquipmentRecord | OperationalRecord | (CanonicalRecord | CanonicalAggregationRecord | EnergyRecord | EnergyEquipmentRecord | OperationalRecord)[] | undefined | null, tenantId: string, defaultEventTime: string): IngestResult;
|
|
89
|
+
export declare function ingestCanonicalRecords(records: CanonicalRecord | CanonicalAggregationRecord | CanonicalTransformationRecord | EnergyRecord | EnergyEquipmentRecord | OperationalRecord | (CanonicalRecord | CanonicalAggregationRecord | CanonicalTransformationRecord | EnergyRecord | EnergyEquipmentRecord | OperationalRecord)[] | undefined | null, tenantId: string, defaultEventTime: string): IngestResult;
|
|
@@ -28,6 +28,24 @@ const TWIN_INGEST_RULES = [
|
|
|
28
28
|
bizStep: '$.bizStep',
|
|
29
29
|
disposition: '$.disposition',
|
|
30
30
|
epc: '$.epc',
|
|
31
|
+
/* 비직렬 수량 — 개체 없이 「이 자리에 이 품목이 얼마 남았다」만 오는 관측이 있다. */
|
|
32
|
+
quantityList: '$.quantityList',
|
|
33
|
+
readPoint: '$.readPoint',
|
|
34
|
+
bizLocation: '$.bizLocation'
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
/* **변환의 사실** — 무엇으로 무엇이 되었나. 이름은 표준의 것을 그대로 쓴다(갈래 판정이 그 이름을 본다). */
|
|
39
|
+
sourceType: 'twin-transformation',
|
|
40
|
+
mapping: {
|
|
41
|
+
type: 'TransformationEvent',
|
|
42
|
+
bizStep: '$.bizStep',
|
|
43
|
+
disposition: '$.disposition',
|
|
44
|
+
inputEPCList: '$.inputEPCList',
|
|
45
|
+
inputQuantityList: '$.inputQuantityList',
|
|
46
|
+
outputEPCList: '$.outputEPCList',
|
|
47
|
+
outputQuantityList: '$.outputQuantityList',
|
|
48
|
+
transformationID: '$.transformationID',
|
|
31
49
|
readPoint: '$.readPoint',
|
|
32
50
|
bizLocation: '$.bizLocation'
|
|
33
51
|
}
|
|
@@ -64,7 +82,7 @@ function ingestCanonicalRecords(records, tenantId, defaultEventTime) {
|
|
|
64
82
|
* 물류 어휘 안에는 모양이 둘이다(개체 관측 `epc` / 담김 `parentID`+`childEPCs`).
|
|
65
83
|
*
|
|
66
84
|
* 판정은 커널이 한 곳에서 한다(`isEnergyRecord`·`isOperationalRecord`·`isAggregationRecord`) — 여기서 다시 짐작하면
|
|
67
|
-
* 소비처마다 답이 달라진다. 봉투는 같은 것을 쓰므로 아래 소비처(
|
|
85
|
+
* 소비처마다 답이 달라진다. 봉투는 같은 것을 쓰므로 아래 소비처(미러·저널·브로드캐스팅)는 이 갈림을 알
|
|
68
86
|
* 필요가 없다.
|
|
69
87
|
*/
|
|
70
88
|
const energy = arr.filter(twin_kernel_1.isEnergyRecord);
|
|
@@ -80,7 +98,30 @@ function ingestCanonicalRecords(records, tenantId, defaultEventTime) {
|
|
|
80
98
|
const epcis = arr.filter(r => !(0, twin_kernel_1.isEnergyRecord)(r) && !(0, twin_kernel_1.isEnergyEquipmentRecord)(r) && !(0, twin_kernel_1.isOperationalRecord)(r));
|
|
81
99
|
/* 품목 어휘 안에서도 갈림이 있다(개체 관측 / 담김) — 그 판정도 커널의 것을 부른다. */
|
|
82
100
|
const epcisResult = epcis.length
|
|
83
|
-
? (0, twin_kernel_1.ingest)(epcis.map(r => ({
|
|
101
|
+
? (0, twin_kernel_1.ingest)(epcis.map(r => ({
|
|
102
|
+
...r,
|
|
103
|
+
/* 판정은 커널이 한 곳에서 한다 — 여기서 다시 짐작하면 소비처마다 답이 달라진다. */
|
|
104
|
+
sourceType: (0, twin_kernel_1.isTransformationRecord)(r)
|
|
105
|
+
? 'twin-transformation'
|
|
106
|
+
: (0, twin_kernel_1.isAggregationRecord)(r)
|
|
107
|
+
? 'twin-aggregation'
|
|
108
|
+
: 'twin'
|
|
109
|
+
})), TWIN_INGEST_RULES,
|
|
110
|
+
/*
|
|
111
|
+
* **레코드가 시각을 말하면 그것을 쓴다** (2026-08-23).
|
|
112
|
+
*
|
|
113
|
+
* `eventTimePath` 를 주지 않던 동안 이 경로는 **언제나 폴링 시각**을 썼다(`defaultEventTime`).
|
|
114
|
+
* 그래서 커넥터가 이미 싣고 있던 `eventTime`(변환 레코드의 `finishedAt` 등)이 **조용히
|
|
115
|
+
* 무시됐다** — 커넥터를 붙인 쪽은 그것이 먹는다고 믿고 있었고, 어디에도 오류가 나지 않았다.
|
|
116
|
+
*
|
|
117
|
+
* 무엇이 걸렸나: 계보(변환)의 시각이다. 4월에 만든 로트가 8월에 만들어진 것으로 저널에 남았다.
|
|
118
|
+
* 그리고 실측 소요를 재는 폴드가 봉투 시각을 쓰므로(§`kpi-fold`: `workMs = 완료 − 첫 착수`),
|
|
119
|
+
* 폴링 간격을 작업시간으로 배울 수 있었다 — 못 배우는 것보다 나쁘다.
|
|
120
|
+
*
|
|
121
|
+
* 레코드에 `eventTime` 이 없으면 커널이 조용히 기본값으로 떨어진다(§`resolve` — 없는 값은
|
|
122
|
+
* 오류가 아니다). 그래서 이 한 줄이 기존 경로를 막지 않는다: 시각을 말하는 레코드만 사실이 된다.
|
|
123
|
+
*/
|
|
124
|
+
{ tenantId, defaultEventTime, eventTimePath: 'eventTime' })
|
|
84
125
|
: { accepted: [], rejected: [] };
|
|
85
126
|
const energyResult = energy.length ? (0, twin_kernel_1.ingestEnergyRecords)(energy, { tenantId, defaultEventTime }) : { accepted: [], rejected: [] };
|
|
86
127
|
const equipmentResult = energyEquipment.length
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canonical-ingest.js","sourceRoot":"","sources":["../../server/engine/canonical-ingest.ts"],"names":[],"mappings":"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","sourcesContent":["import { ingest, ingestEnergyRecords, ingestEnergyEquipmentRecords, ingestOperationalRecords, isAggregationRecord,\n isEnergyRecord, isEnergyEquipmentRecord, isOperationalRecord, type AdapterRule, type EnergyRecord,\n type EnergyEquipmentRecord, type OperationalRecord, type IngestResult } from '@operato/twin-kernel'\n\n/*\n * 정규 레코드 → 커널 검증 ACL → CanonicalEnvelope (P1 seam 코어).\n * 순수(커널만 의존; shell·integration-base 무의존 → node:test 검증 가능).\n * 매핑(레거시 스키마 → 정규)은 이 앞 단계(jsonata step 또는 커넥터 openLiveFeed)가 끝낸다.\n * 여기 도착하는 레코드는 이미 정규 필드다 — 어휘마다 자기 필드 이름이 계약이다:\n * EPCIS 품목 { epc, action, bizStep, disposition?, readPoint?, bizLocation? }\n * 에너지 계량 { meterId, kW?, kWh?, … } · 설비 에너지 { equipmentId, generatedKW?, soc?, … }\n * 담김(적재) { parentID, childEPCs[] | childQuantityList[], action, bizStep, … }\n * 운영 사실 { taskId | moverId | personId | assetId | orderId, status, … } // vocabulary-guard: allow 저널 와이어 필드\n * 커널은 objectEvent 구성 + EPCIS 검증(위반=오염 차단) + 봉투 래핑만(방언 없음).\n *\n * 두 소비처가 이 단일 코어를 공유(중복 금지):\n * - sim/scenario 경로: operato-twin twin-ingest 태스크(http-get→jsonata→여기).\n * - live 커넥터 경로: reference-live(어댑터 openLiveFeed→여기).\n * SoT: design/integration/face2-adapters.md §5(seam)·§7(매핑=밖, 검증=커널).\n */\n\n/** 고정 정규 매핑(방언 아님 — 필드명 자체가 정규 계약). `sourceType` 으로 어느 품목 사실인지 고른다. */\nconst TWIN_INGEST_RULES: AdapterRule[] = [\n {\n sourceType: 'twin',\n mapping: {\n type: 'ObjectEvent',\n action: '$.action',\n bizStep: '$.bizStep',\n disposition: '$.disposition',\n epc: '$.epc',\n readPoint: '$.readPoint',\n bizLocation: '$.bizLocation'\n }\n },\n {\n /*\n * **담김의 사실** — 무엇이 무엇에 실렸나(팔레트·상자). 오래 비어 있던 자리다: 관측 리듀서는 이 사실을\n * 받으면 자식 물품에 `parent` 를 붙이는데, 문이 `ObjectEvent` 하나만 알아서 원본은 적재를 말할 길이\n * 없었다(시뮬 원본을 붙여 돌려 보고서야 로그로 드러났다).\n */\n sourceType: 'twin-aggregation',\n mapping: {\n type: 'AggregationEvent',\n action: '$.action',\n bizStep: '$.bizStep',\n disposition: '$.disposition',\n parentID: '$.parentID',\n childEPCs: '$.childEPCs',\n /* 낱개 식별자 없이 **수량으로** 담긴 자식(「이 품번 40개」) — 입고·포장이 이 모양으로 온다. */\n childQuantityList: '$.childQuantityList',\n readPoint: '$.readPoint',\n bizLocation: '$.bizLocation'\n }\n }\n]\n\n/** 개체 관측 — 물건 하나가 어디서 무엇이 됐나. */\nexport interface CanonicalRecord {\n epc: string\n action: string // ADD | OBSERVE | DELETE\n bizStep: string\n disposition?: string\n readPoint?: string\n bizLocation?: string\n}\n\n/**\n * 담김 관측 — **부모와 자식**으로 말한다. 자리 필드는 개체 관측과 같은 이름이다(문자열).\n *\n * 이름은 표준의 것을 그대로 쓴다(`parentID`·`childEPCs`) — 여기서 다시 지으면 매핑이 번역이 되고,\n * 같은 사실에 두 어휘가 생긴다.\n */\nexport interface CanonicalAggregationRecord {\n parentID: string\n /** 개체로 담긴 자식. 수량으로만 담겼으면 없다(둘 중 하나는 있어야 한다). */\n childEPCs?: string[]\n /** 수량으로 담긴 자식 — `{ epcClass, quantity, uom? }`. 값의 옳고 그름은 커널 검증이 본다. */\n childQuantityList?: { epcClass: string; quantity?: number; uom?: string }[]\n action: string // ADD(담다) | DELETE(풀다) | OBSERVE\n bizStep: string\n disposition?: string\n readPoint?: string\n bizLocation?: string\n}\n\n/** 정규 레코드[] → 검증된 CanonicalEnvelope[] (+ 거부분). 순수 함수. 단일→객체도 배열로 정규화. */\nexport function ingestCanonicalRecords(\n records:\n | CanonicalRecord\n | CanonicalAggregationRecord\n | EnergyRecord\n | EnergyEquipmentRecord\n | OperationalRecord\n | (CanonicalRecord | CanonicalAggregationRecord | EnergyRecord | EnergyEquipmentRecord | OperationalRecord)[]\n | undefined\n | null,\n tenantId: string,\n defaultEventTime: string\n): IngestResult {\n const arr = Array.isArray(records) ? records : records ? [records] : []\n /*\n * **어휘가 넷이다** — 물류(EPCIS)·에너지 계량·설비 에너지·운영 사실. 예전에는 이 함수가 무조건\n * `ObjectEvent` 를 만들었고, 그래서 계측을 이 길로 넣으면 `epc` 가 없어 거부되거나(그나마 나은 쪽)\n * 엉뚱한 물품 관측이 됐다.\n *\n * 물류 어휘 안에는 모양이 둘이다(개체 관측 `epc` / 담김 `parentID`+`childEPCs`).\n *\n * 판정은 커널이 한 곳에서 한다(`isEnergyRecord`·`isOperationalRecord`·`isAggregationRecord`) — 여기서 다시 짐작하면\n * 소비처마다 답이 달라진다. 봉투는 같은 것을 쓰므로 아래 소비처(미러·저널·방송)는 이 갈림을 알\n * 필요가 없다.\n */\n const energy = arr.filter(isEnergyRecord) as EnergyRecord[]\n /* 세 번째 어휘 — 설비가 낸 자기 에너지 상태(발전·저장·감축 여지·개폐 위치). 계량과 갈라 두는\n 이유는 커널에 적혀 있다: 계량은 구간에 누적되고, 이것들은 그 설비의 지금이다. */\n const energyEquipment = arr.filter(isEnergyEquipmentRecord) as unknown as EnergyEquipmentRecord[]\n /*\n * 네 번째 어휘 — **운영 사실**(작업·설비·사람·자산·오더·품질). 관측 리듀서는 이것을 오래전부터\n * 접었는데 **들어올 문이 없었다**: 원본이 「이 작업이 끝났다」를 말할 길이 없어 시뮬 커널만 그것을\n * 아는 상태가 남았다(같은 화면이 두 구동에서 다른 것을 말한다).\n */\n const operational = arr.filter(isOperationalRecord) as OperationalRecord[]\n const epcis = arr.filter(r => !isEnergyRecord(r) && !isEnergyEquipmentRecord(r) && !isOperationalRecord(r)) as (CanonicalRecord | CanonicalAggregationRecord)[]\n\n /* 품목 어휘 안에서도 갈림이 있다(개체 관측 / 담김) — 그 판정도 커널의 것을 부른다. */\n const epcisResult = epcis.length\n ? ingest(\n epcis.map(r => ({ ...r, sourceType: isAggregationRecord(r) ? 'twin-aggregation' : 'twin' })),\n TWIN_INGEST_RULES,\n { tenantId, defaultEventTime }\n )\n : { accepted: [], rejected: [] }\n const energyResult = energy.length ? ingestEnergyRecords(energy, { tenantId, defaultEventTime }) : { accepted: [], rejected: [] }\n const equipmentResult = energyEquipment.length\n ? ingestEnergyEquipmentRecords(energyEquipment, { tenantId, defaultEventTime })\n : { accepted: [], rejected: [] }\n const operationalResult = operational.length\n ? ingestOperationalRecords(operational, { tenantId, defaultEventTime })\n : { accepted: [], rejected: [] }\n\n /* 거부분을 합쳐 돌려준다 — 어느 어휘에서 거부됐는지는 이유 문구가 말한다. */\n return {\n accepted: [...epcisResult.accepted, ...energyResult.accepted, ...equipmentResult.accepted, ...operationalResult.accepted],\n rejected: [...epcisResult.rejected, ...energyResult.rejected, ...equipmentResult.rejected, ...operationalResult.rejected]\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"canonical-ingest.js","sourceRoot":"","sources":["../../server/engine/canonical-ingest.ts"],"names":[],"mappings":"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","sourcesContent":["import { ingest, ingestEnergyRecords, ingestEnergyEquipmentRecords, ingestOperationalRecords, isAggregationRecord, isTransformationRecord,\n isEnergyRecord, isEnergyEquipmentRecord, isOperationalRecord, type AdapterRule, type EnergyRecord,\n type EnergyEquipmentRecord, type OperationalRecord, type IngestResult } from '@operato/twin-kernel'\n\n/*\n * 정규 레코드 → 커널 검증 ACL → CanonicalEnvelope (P1 seam 코어).\n * 순수(커널만 의존; shell·integration-base 무의존 → node:test 검증 가능).\n * 매핑(레거시 스키마 → 정규)은 이 앞 단계(jsonata step 또는 커넥터 openLiveFeed)가 끝낸다.\n * 여기 도착하는 레코드는 이미 정규 필드다 — 어휘마다 자기 필드 이름이 계약이다:\n * EPCIS 품목 { epc, action, bizStep, disposition?, readPoint?, bizLocation? }\n * 에너지 계량 { meterId, kW?, kWh?, … } · 설비 에너지 { equipmentId, generatedKW?, soc?, … }\n * 담김(적재) { parentID, childEPCs[] | childQuantityList[], action, bizStep, … }\n * 운영 사실 { taskId | moverId | personId | assetId | orderId, status, … } // vocabulary-guard: allow 저널 와이어 필드\n * 커널은 objectEvent 구성 + EPCIS 검증(위반=오염 차단) + 봉투 래핑만(방언 없음).\n *\n * 두 소비처가 이 단일 코어를 공유(중복 금지):\n * - sim/scenario 경로: operato-twin twin-ingest 태스크(http-get→jsonata→여기).\n * - live 커넥터 경로: reference-live(어댑터 openLiveFeed→여기).\n * SoT: design/integration/face2-adapters.md §5(seam)·§7(매핑=밖, 검증=커널).\n */\n\n/** 고정 정규 매핑(방언 아님 — 필드명 자체가 정규 계약). `sourceType` 으로 어느 품목 사실인지 고른다. */\nconst TWIN_INGEST_RULES: AdapterRule[] = [\n {\n sourceType: 'twin',\n mapping: {\n type: 'ObjectEvent',\n action: '$.action',\n bizStep: '$.bizStep',\n disposition: '$.disposition',\n epc: '$.epc',\n /* 비직렬 수량 — 개체 없이 「이 자리에 이 품목이 얼마 남았다」만 오는 관측이 있다. */\n quantityList: '$.quantityList',\n readPoint: '$.readPoint',\n bizLocation: '$.bizLocation'\n }\n },\n {\n /* **변환의 사실** — 무엇으로 무엇이 되었나. 이름은 표준의 것을 그대로 쓴다(갈래 판정이 그 이름을 본다). */\n sourceType: 'twin-transformation',\n mapping: {\n type: 'TransformationEvent',\n bizStep: '$.bizStep',\n disposition: '$.disposition',\n inputEPCList: '$.inputEPCList',\n inputQuantityList: '$.inputQuantityList',\n outputEPCList: '$.outputEPCList',\n outputQuantityList: '$.outputQuantityList',\n transformationID: '$.transformationID',\n readPoint: '$.readPoint',\n bizLocation: '$.bizLocation'\n }\n },\n {\n /*\n * **담김의 사실** — 무엇이 무엇에 실렸나(팔레트·상자). 오래 비어 있던 자리다: 관측 리듀서는 이 사실을\n * 받으면 자식 물품에 `parent` 를 붙이는데, 문이 `ObjectEvent` 하나만 알아서 원본은 적재를 말할 길이\n * 없었다(시뮬 원본을 붙여 돌려 보고서야 로그로 드러났다).\n */\n sourceType: 'twin-aggregation',\n mapping: {\n type: 'AggregationEvent',\n action: '$.action',\n bizStep: '$.bizStep',\n disposition: '$.disposition',\n parentID: '$.parentID',\n childEPCs: '$.childEPCs',\n /* 낱개 식별자 없이 **수량으로** 담긴 자식(「이 품번 40개」) — 입고·포장이 이 모양으로 온다. */\n childQuantityList: '$.childQuantityList',\n readPoint: '$.readPoint',\n bizLocation: '$.bizLocation'\n }\n }\n]\n\n/** 개체 관측 — 물건 하나가 어디서 무엇이 됐나. */\nexport interface CanonicalRecord {\n /**\n * 개체 하나의 식별자. **`quantityList` 를 쓰면 없어도 된다** — 낱개 번호가 없는 자재(밀가루 3.5kg)는\n * 개체가 없다. 둘 다 없으면 무엇을 관측했는지 말하지 않은 것이므로 커널 매핑이 거부한다.\n */\n epc?: string\n /**\n * 클래스와 수량 — `{ epcClass, quantity, uom? }`. **잔량 절대값을 싣는다**(「얼마 뺐다」가 아니라\n * 「얼마 남았다」). 그래야 사건 하나를 놓쳐도 다음 사건이 정답을 다시 말해 주고 오차가 쌓이지 않는다.\n *\n * 담김(`childQuantityList`)이 하루 먼저 이 자리를 받았다 — 그때와 같은 이유다. 원본이 비직렬 수량을\n * 말할 길이 없어서, 그것이 주된 경로인 시스템(식품 제조 MES)은 라이브를 낼 수 없었다. 커널의\n * 관측 리듀서는 처음부터 이 값을 읽었고 문만 없었다.\n */\n quantityList?: { epcClass: string; quantity?: number; uom?: string }[]\n action: string // ADD | OBSERVE | DELETE\n bizStep: string\n disposition?: string\n readPoint?: string\n bizLocation?: string\n}\n\n/**\n * 담김 관측 — **부모와 자식**으로 말한다. 자리 필드는 개체 관측과 같은 이름이다(문자열).\n *\n * 이름은 표준의 것을 그대로 쓴다(`parentID`·`childEPCs`) — 여기서 다시 지으면 매핑이 번역이 되고,\n * 같은 사실에 두 어휘가 생긴다.\n */\n/**\n * 변환 관측 — **무엇으로 무엇이 되었나.** 입력과 출력이 **한 사실에 함께** 있어야 계보가 남는다.\n *\n * 따로 보내면(「이 로트가 없어졌다」와 「이 제품이 생겼다」) 그 둘을 이을 근거가 없다. 그래서 표준이\n * 한 사건에 둘을 담고, 우리 레코드도 같은 모양이다.\n *\n * 이름은 **표준의 것을 그대로** 쓴다(`inputQuantityList` 등). 갈래 판정이 이 이름으로 이루어지므로\n * 커넥터 낱말(`consumed`·`produced`)로 담으면 판정되지 않는다 — 커넥터가 정규 이름으로 담아 보내고\n * 매핑은 그 안에서 값을 고른다.\n *\n * **없는 쪽은 필드를 만들지 않는다.** 빈 배열을 실으면 「없다」고 말하는 것이 된다. 소실(N→0)과\n * 생성(0→N)도 표준이 인정하는 변환이다.\n *\n * `transformationID` 가 한 오더의 여러 단계를 잇는다 — 소비를 먼저 알고 산출을 나중에 알게 되는 원본에서\n * 그 둘을 묶는 유일한 자리다.\n */\nexport interface CanonicalTransformationRecord {\n /** 개체로 소비된 것. */\n inputEPCList?: string[]\n /** 클래스와 수량으로 소비된 것 — 로트 단위 소비가 이 자리다. */\n inputQuantityList?: { epcClass: string; quantity?: number; uom?: string }[]\n outputEPCList?: string[]\n outputQuantityList?: { epcClass: string; quantity?: number; uom?: string }[]\n /** 한 오더의 여러 단계를 잇는 식별자. */\n transformationID?: string\n bizStep: string\n disposition?: string\n readPoint?: string\n bizLocation?: string\n}\n\nexport interface CanonicalAggregationRecord {\n parentID: string\n /** 개체로 담긴 자식. 수량으로만 담겼으면 없다(둘 중 하나는 있어야 한다). */\n childEPCs?: string[]\n /** 수량으로 담긴 자식 — `{ epcClass, quantity, uom? }`. 값의 옳고 그름은 커널 검증이 본다. */\n childQuantityList?: { epcClass: string; quantity?: number; uom?: string }[]\n action: string // ADD(담다) | DELETE(풀다) | OBSERVE\n bizStep: string\n disposition?: string\n readPoint?: string\n bizLocation?: string\n}\n\n/** 정규 레코드[] → 검증된 CanonicalEnvelope[] (+ 거부분). 순수 함수. 단일→객체도 배열로 정규화. */\nexport function ingestCanonicalRecords(\n records:\n | CanonicalRecord\n | CanonicalAggregationRecord\n | CanonicalTransformationRecord\n | EnergyRecord\n | EnergyEquipmentRecord\n | OperationalRecord\n | (CanonicalRecord | CanonicalAggregationRecord | CanonicalTransformationRecord | EnergyRecord | EnergyEquipmentRecord | OperationalRecord)[]\n | undefined\n | null,\n tenantId: string,\n defaultEventTime: string\n): IngestResult {\n const arr = Array.isArray(records) ? records : records ? [records] : []\n /*\n * **어휘가 넷이다** — 물류(EPCIS)·에너지 계량·설비 에너지·운영 사실. 예전에는 이 함수가 무조건\n * `ObjectEvent` 를 만들었고, 그래서 계측을 이 길로 넣으면 `epc` 가 없어 거부되거나(그나마 나은 쪽)\n * 엉뚱한 물품 관측이 됐다.\n *\n * 물류 어휘 안에는 모양이 둘이다(개체 관측 `epc` / 담김 `parentID`+`childEPCs`).\n *\n * 판정은 커널이 한 곳에서 한다(`isEnergyRecord`·`isOperationalRecord`·`isAggregationRecord`) — 여기서 다시 짐작하면\n * 소비처마다 답이 달라진다. 봉투는 같은 것을 쓰므로 아래 소비처(미러·저널·브로드캐스팅)는 이 갈림을 알\n * 필요가 없다.\n */\n const energy = arr.filter(isEnergyRecord) as EnergyRecord[]\n /* 세 번째 어휘 — 설비가 낸 자기 에너지 상태(발전·저장·감축 여지·개폐 위치). 계량과 갈라 두는\n 이유는 커널에 적혀 있다: 계량은 구간에 누적되고, 이것들은 그 설비의 지금이다. */\n const energyEquipment = arr.filter(isEnergyEquipmentRecord) as unknown as EnergyEquipmentRecord[]\n /*\n * 네 번째 어휘 — **운영 사실**(작업·설비·사람·자산·오더·품질). 관측 리듀서는 이것을 오래전부터\n * 접었는데 **들어올 문이 없었다**: 원본이 「이 작업이 끝났다」를 말할 길이 없어 시뮬 커널만 그것을\n * 아는 상태가 남았다(같은 화면이 두 구동에서 다른 것을 말한다).\n */\n const operational = arr.filter(isOperationalRecord) as OperationalRecord[]\n const epcis = arr.filter(r => !isEnergyRecord(r) && !isEnergyEquipmentRecord(r) && !isOperationalRecord(r)) as (CanonicalRecord | CanonicalAggregationRecord | CanonicalTransformationRecord)[]\n\n /* 품목 어휘 안에서도 갈림이 있다(개체 관측 / 담김) — 그 판정도 커널의 것을 부른다. */\n const epcisResult = epcis.length\n ? ingest(\n epcis.map(r => ({\n ...r,\n /* 판정은 커널이 한 곳에서 한다 — 여기서 다시 짐작하면 소비처마다 답이 달라진다. */\n sourceType: isTransformationRecord(r)\n ? 'twin-transformation'\n : isAggregationRecord(r)\n ? 'twin-aggregation'\n : 'twin'\n })),\n TWIN_INGEST_RULES,\n /*\n * **레코드가 시각을 말하면 그것을 쓴다** (2026-08-23).\n *\n * `eventTimePath` 를 주지 않던 동안 이 경로는 **언제나 폴링 시각**을 썼다(`defaultEventTime`).\n * 그래서 커넥터가 이미 싣고 있던 `eventTime`(변환 레코드의 `finishedAt` 등)이 **조용히\n * 무시됐다** — 커넥터를 붙인 쪽은 그것이 먹는다고 믿고 있었고, 어디에도 오류가 나지 않았다.\n *\n * 무엇이 걸렸나: 계보(변환)의 시각이다. 4월에 만든 로트가 8월에 만들어진 것으로 저널에 남았다.\n * 그리고 실측 소요를 재는 폴드가 봉투 시각을 쓰므로(§`kpi-fold`: `workMs = 완료 − 첫 착수`),\n * 폴링 간격을 작업시간으로 배울 수 있었다 — 못 배우는 것보다 나쁘다.\n *\n * 레코드에 `eventTime` 이 없으면 커널이 조용히 기본값으로 떨어진다(§`resolve` — 없는 값은\n * 오류가 아니다). 그래서 이 한 줄이 기존 경로를 막지 않는다: 시각을 말하는 레코드만 사실이 된다.\n */\n { tenantId, defaultEventTime, eventTimePath: 'eventTime' }\n )\n : { accepted: [], rejected: [] }\n const energyResult = energy.length ? ingestEnergyRecords(energy, { tenantId, defaultEventTime }) : { accepted: [], rejected: [] }\n const equipmentResult = energyEquipment.length\n ? ingestEnergyEquipmentRecords(energyEquipment, { tenantId, defaultEventTime })\n : { accepted: [], rejected: [] }\n const operationalResult = operational.length\n ? ingestOperationalRecords(operational, { tenantId, defaultEventTime })\n : { accepted: [], rejected: [] }\n\n /* 거부분을 합쳐 돌려준다 — 어느 어휘에서 거부됐는지는 이유 문구가 말한다. */\n return {\n accepted: [...epcisResult.accepted, ...energyResult.accepted, ...equipmentResult.accepted, ...operationalResult.accepted],\n rejected: [...epcisResult.rejected, ...energyResult.rejected, ...equipmentResult.rejected, ...operationalResult.rejected]\n }\n}\n"]}
|
|
@@ -42,7 +42,7 @@ function routeCommand(inst, ownedByCaller, type) {
|
|
|
42
42
|
if (!type)
|
|
43
43
|
return { target: 'reject', errorCode: 'unknown-command' };
|
|
44
44
|
if (inst.mode !== 'live') {
|
|
45
|
-
/* 시뮬 — 커널이 세계다. 런타임이 없으면
|
|
45
|
+
/* 시뮬 — 커널이 세계다. 런타임이 없으면 오류를 내지 않고 이유를 말한다. */
|
|
46
46
|
return inst.hasRuntime ? { target: 'runtime' } : { target: 'reject', errorCode: 'no-runtime' };
|
|
47
47
|
}
|
|
48
48
|
/* 미러 — 실 프로세스 변경은 아웃바운드 어댑터의 몫이고 아직 결선되지 않았다. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-routing.js","sourceRoot":"","sources":["../../server/engine/command-routing.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;;;AAgCH,oCAYC;AA1CD,6CAA6C;AAC7C,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAS,CAAC,eAAe,CAAC,CAAC,CAAA;AAoB9D,uCAAuC;AAChC,MAAM,WAAW,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AAAvE,QAAA,WAAW,eAA4D;AAEpF;;;;;GAKG;AACH,SAAgB,YAAY,CAAC,IAAkC,EAAE,aAAsB,EAAE,IAAY;IACnG,IAAI,CAAC,IAAI,IAAI,CAAC,aAAa;QAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,CAAA;IAClF,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAAA;IAEpE,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACzB
|
|
1
|
+
{"version":3,"file":"command-routing.js","sourceRoot":"","sources":["../../server/engine/command-routing.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;;;AAgCH,oCAYC;AA1CD,6CAA6C;AAC7C,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAS,CAAC,eAAe,CAAC,CAAC,CAAA;AAoB9D,uCAAuC;AAChC,MAAM,WAAW,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AAAvE,QAAA,WAAW,eAA4D;AAEpF;;;;;GAKG;AACH,SAAgB,YAAY,CAAC,IAAkC,EAAE,aAAsB,EAAE,IAAY;IACnG,IAAI,CAAC,IAAI,IAAI,CAAC,aAAa;QAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,CAAA;IAClF,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAAA;IAEpE,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACzB,+CAA+C;QAC/C,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,CAAA;IAChG,CAAC;IAED,iDAAiD;IACjD,IAAI,IAAA,mBAAW,EAAC,IAAI,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,qBAAqB,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,EAAE,CAAA;IAC3G,OAAO,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,CAAA;AACtG,CAAC","sourcesContent":["/*\n * 커맨드 라우팅 판정 — **순수**. \"이 커맨드를 누구에게 보낼 것인가\" 만 정한다.\n * 실제 dispatch·저널 기록은 엔진이 한다(`design/plans/command-routing.md` §1·§4 P0).\n *\n * ── 왜 떼어냈나 ─────────────────────────────────────────────────────────────\n * 예전에는 리졸버가 `inst.runtime.dispatch(...)` 를 곧바로 불렀다. `runtime` 은 **시뮬 경로에서만**\n * 만들어지므로 실물을 비추는 트윈(mirror)에서는 그 한 줄이 `TypeError` 로 터졌다 — 조치 채널이\n * 통째로 닿지 않았고, 사용자에게는 이유 있는 거절이 아니라 그냥 실패였다.\n *\n * 판정이 코드 한가운데 있으면 이런 부류를 테스트로 못 잡는다(엔진은 DB·TypeORM 을 물고 있어 단위\n * 테스트가 불러올 수 없다). 그래서 판정만 순수하게 떼어 둔다 — `planWarmStart` 와 같은 이유다.\n *\n * ── 판정 규칙 = 권위 × 성격 ─────────────────────────────────────────────────\n * | 성격 \\ 모드 | 시뮬 | 미러(현실을 비춤) |\n * | 액추에이션 | 커널 런타임 | **거절**(아웃바운드 어댑터 미결선) |\n * | 주석(확인 ack) | 커널 런타임 | 관측 커널 |\n *\n * 미러에서 액추에이션을 그냥 허용하면 **새 거짓말이 생긴다**: 트윈은 \"보류됨\" 이라 말하고 실 시스템은\n * 모른다. 조용히 커널만 바꾸지 않고, 이유를 밝혀 거절한다.\n *\n * 반면 확인(ack)은 액추에이션이 아니다 — 신호를 봤다는 트윈 쪽 주석이라 현실을 건드리지 않는다.\n * 미러에서도 성립해야 하므로 관측 커널로 보낸다.\n */\n\n/** 관측 쪽 주석 커맨드 — 현실을 바꾸지 않으므로 미러에서도 통과한다. */\nconst ANNOTATION_COMMANDS = new Set<string>(['attention.ack'])\n\n/** 라우팅에 필요한 인스턴스 사실만 — 엔진 객체를 그대로 받지 않는다(순수하게 유지). */\nexport interface RoutableInstance {\n /** 'live' 면 현실을 비추는 트윈(미러). 그 외는 시뮬. */\n mode?: string\n /** 커널 런타임(tick/dispatch)이 붙어 있나 — 시뮬 경로에서만 만들어진다. */\n hasRuntime: boolean\n /** 관측 커널이 dispatch 를 받을 수 있나. */\n hasKernelDispatch: boolean\n}\n\nexport type CommandRoute =\n /** 커널 런타임으로(시뮬 — 커널이 세계다). */\n | { target: 'runtime' }\n /** 관측 커널로(미러 — 주석만). 방출된 사실은 저널 큐에 실어야 한다. */\n | { target: 'kernel' }\n /** 보내지 않는다. 사유는 언어 중립 코드 — 화면이 `twin.cmderr.<code>` 로 사람 말을 만든다. */\n | { target: 'reject'; errorCode: string; errorParams?: Record<string, string | number> }\n\n/** 이 커맨드가 실 프로세스를 바꾸는 것인가(= 액추에이션). */\nexport const isActuation = (type: string): boolean => !ANNOTATION_COMMANDS.has(type)\n\n/**\n * 어디로 보낼지 정한다.\n *\n * `inst` 가 없거나 호출자 도메인 소유가 아니면 **같은 사유로** 거절한다 — 존재 여부를 알려 주면\n * 다른 테넌트의 인스턴스 id 를 추측할 수 있다(있음/없음이 구별되면 그것이 정보다).\n */\nexport function routeCommand(inst: RoutableInstance | undefined, ownedByCaller: boolean, type: string): CommandRoute {\n if (!inst || !ownedByCaller) return { target: 'reject', errorCode: 'no-instance' }\n if (!type) return { target: 'reject', errorCode: 'unknown-command' }\n\n if (inst.mode !== 'live') {\n /* 시뮬 — 커널이 세계다. 런타임이 없으면 오류를 내지 않고 이유를 말한다. */\n return inst.hasRuntime ? { target: 'runtime' } : { target: 'reject', errorCode: 'no-runtime' }\n }\n\n /* 미러 — 실 프로세스 변경은 아웃바운드 어댑터의 몫이고 아직 결선되지 않았다. */\n if (isActuation(type)) return { target: 'reject', errorCode: 'actuation-not-wired', errorParams: { type } }\n return inst.hasKernelDispatch ? { target: 'kernel' } : { target: 'reject', errorCode: 'no-runtime' }\n}\n"]}
|
|
@@ -8,6 +8,7 @@ export * from '@things-factory/headless-twin/dist-shared/kpi-broadcast.js';
|
|
|
8
8
|
export * from '@things-factory/headless-twin/dist-shared/entity-delta.js';
|
|
9
9
|
export * from '@things-factory/headless-twin/dist-shared/twin-level.js';
|
|
10
10
|
export * from './load-meter.js';
|
|
11
|
+
export * from './loop-lag.js';
|
|
11
12
|
export * from './runtime-key.js';
|
|
12
13
|
export * from './kpi-query.js';
|
|
13
14
|
export * from './spec-coverage.js';
|
|
@@ -15,7 +16,9 @@ export * from './travel-estimator.js';
|
|
|
15
16
|
export * from './measured-estimator.js';
|
|
16
17
|
export * from './model-basis.js';
|
|
17
18
|
export * from './live-feed-registry.js';
|
|
19
|
+
export * from './ingest-health.js';
|
|
18
20
|
export * from './local-declarations.js';
|
|
19
21
|
export * from './operation-basis.js';
|
|
20
22
|
export * from './measured-yield.js';
|
|
21
23
|
export * from './declared-stimulus.js';
|
|
24
|
+
export * from './integration-coverage.js';
|
|
@@ -15,6 +15,7 @@ tslib_1.__exportStar(require("@things-factory/headless-twin/dist-shared/entity-d
|
|
|
15
15
|
tslib_1.__exportStar(require("@things-factory/headless-twin/dist-shared/twin-level.js"), exports);
|
|
16
16
|
/* 부하 계기판 — 어떤 작업이 이벤트 루프를 얼마나 쓰는지. */
|
|
17
17
|
tslib_1.__exportStar(require("./load-meter.js"), exports);
|
|
18
|
+
tslib_1.__exportStar(require("./loop-lag.js"), exports);
|
|
18
19
|
/* 런타임 레지스트리 키 규약 — 소비처(다른 키 캐시·테스트)가 `:` 를 다시 적지 않게 함께 내보낸다. */
|
|
19
20
|
tslib_1.__exportStar(require("./runtime-key.js"), exports);
|
|
20
21
|
tslib_1.__exportStar(require("./kpi-query.js"), exports);
|
|
@@ -23,9 +24,12 @@ tslib_1.__exportStar(require("./travel-estimator.js"), exports);
|
|
|
23
24
|
tslib_1.__exportStar(require("./measured-estimator.js"), exports);
|
|
24
25
|
tslib_1.__exportStar(require("./model-basis.js"), exports);
|
|
25
26
|
tslib_1.__exportStar(require("./live-feed-registry.js"), exports);
|
|
27
|
+
/* 동기화 건강 — 「이 트윈이 현장과 맞춰지고 있나」. 판정·추이·사유·표본. */
|
|
28
|
+
tslib_1.__exportStar(require("./ingest-health.js"), exports);
|
|
26
29
|
/* 로컬 선언(현장·트윈) — 소비처(twin-ai 도구)가 명세·검사 규칙을 다시 적지 않게. */
|
|
27
30
|
tslib_1.__exportStar(require("./local-declarations.js"), exports);
|
|
28
31
|
tslib_1.__exportStar(require("./operation-basis.js"), exports);
|
|
29
32
|
tslib_1.__exportStar(require("./measured-yield.js"), exports);
|
|
30
33
|
tslib_1.__exportStar(require("./declared-stimulus.js"), exports);
|
|
34
|
+
tslib_1.__exportStar(require("./integration-coverage.js"), exports);
|
|
31
35
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/engine/index.ts"],"names":[],"mappings":";;;AAAA,2DAAgC;AAChC,gEAAqC;AACrC,wDAA6B;AAC7B,gEAAqC;AACrC,4DAAiC;AACjC,qEAAqE;AACrE,0DAA+B;AAC/B,qGAA0E;AAC1E,0DAA0D;AAC1D,oGAAyE;AACzE,4CAA4C;AAC5C,kGAAuE;AACvE,sCAAsC;AACtC,0DAA+B;AAC/B,gEAAgE;AAChE,2DAAgC;AAChC,yDAA8B;AAC9B,6DAAkC;AAClC,gEAAqC;AACrC,kEAAuC;AACvC,2DAAgC;AAChC,kEAAuC;AACvC,yDAAyD;AACzD,kEAAuC;AACvC,+DAAoC;AACpC,8DAAmC;AACnC,iEAAsC","sourcesContent":["export * from './twin-engine.js'\nexport * from './canonical-ingest.js'\nexport * from './kpi-fold.js'\nexport * from './property-effects.js'\nexport * from './kpi-baseline.js'\n/* 지표 정본 표(TWIN_METRIC)·목표 판정 — 소비처(twin-ai 등)가 지표 이름을 다시 열거하지 않게. */\nexport * from './kpi-target.js'\nexport * from '@things-factory/headless-twin/dist-shared/kpi-broadcast.js'\n/* 집약 채널 태그(접두사 + 트윈별 태그 생성) — 소비처가 문자열을 다시 적지 않게 내보낸다. */\nexport * from '@things-factory/headless-twin/dist-shared/entity-delta.js'\n/* 공간 계층의 단계 — 씬 표현·성과 카드·AI 가 같은 목록을 쓴다. */\nexport * from '@things-factory/headless-twin/dist-shared/twin-level.js'\n/* 부하 계기판 — 어떤 작업이 이벤트 루프를 얼마나 쓰는지. */\nexport * from './load-meter.js'\n/* 런타임 레지스트리 키 규약 — 소비처(다른 키 캐시·테스트)가 `:` 를 다시 적지 않게 함께 내보낸다. */\nexport * from './runtime-key.js'\nexport * from './kpi-query.js'\nexport * from './spec-coverage.js'\nexport * from './travel-estimator.js'\nexport * from './measured-estimator.js'\nexport * from './model-basis.js'\nexport * from './live-feed-registry.js'\n/* 로컬 선언(현장·트윈) — 소비처(twin-ai 도구)가 명세·검사 규칙을 다시 적지 않게. */\nexport * from './local-declarations.js'\nexport * from './operation-basis.js'\nexport * from './measured-yield.js'\nexport * from './declared-stimulus.js'\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/engine/index.ts"],"names":[],"mappings":";;;AAAA,2DAAgC;AAChC,gEAAqC;AACrC,wDAA6B;AAC7B,gEAAqC;AACrC,4DAAiC;AACjC,qEAAqE;AACrE,0DAA+B;AAC/B,qGAA0E;AAC1E,0DAA0D;AAC1D,oGAAyE;AACzE,4CAA4C;AAC5C,kGAAuE;AACvE,sCAAsC;AACtC,0DAA+B;AAC/B,wDAA6B;AAC7B,gEAAgE;AAChE,2DAAgC;AAChC,yDAA8B;AAC9B,6DAAkC;AAClC,gEAAqC;AACrC,kEAAuC;AACvC,2DAAgC;AAChC,kEAAuC;AACvC,gDAAgD;AAChD,6DAAkC;AAClC,yDAAyD;AACzD,kEAAuC;AACvC,+DAAoC;AACpC,8DAAmC;AACnC,iEAAsC;AACtC,oEAAyC","sourcesContent":["export * from './twin-engine.js'\nexport * from './canonical-ingest.js'\nexport * from './kpi-fold.js'\nexport * from './property-effects.js'\nexport * from './kpi-baseline.js'\n/* 지표 정본 표(TWIN_METRIC)·목표 판정 — 소비처(twin-ai 등)가 지표 이름을 다시 열거하지 않게. */\nexport * from './kpi-target.js'\nexport * from '@things-factory/headless-twin/dist-shared/kpi-broadcast.js'\n/* 집약 채널 태그(접두사 + 트윈별 태그 생성) — 소비처가 문자열을 다시 적지 않게 내보낸다. */\nexport * from '@things-factory/headless-twin/dist-shared/entity-delta.js'\n/* 공간 계층의 단계 — 씬 표현·성과 카드·AI 가 같은 목록을 쓴다. */\nexport * from '@things-factory/headless-twin/dist-shared/twin-level.js'\n/* 부하 계기판 — 어떤 작업이 이벤트 루프를 얼마나 쓰는지. */\nexport * from './load-meter.js'\nexport * from './loop-lag.js'\n/* 런타임 레지스트리 키 규약 — 소비처(다른 키 캐시·테스트)가 `:` 를 다시 적지 않게 함께 내보낸다. */\nexport * from './runtime-key.js'\nexport * from './kpi-query.js'\nexport * from './spec-coverage.js'\nexport * from './travel-estimator.js'\nexport * from './measured-estimator.js'\nexport * from './model-basis.js'\nexport * from './live-feed-registry.js'\n/* 동기화 건강 — 「이 트윈이 현장과 맞춰지고 있나」. 판정·추이·사유·표본. */\nexport * from './ingest-health.js'\n/* 로컬 선언(현장·트윈) — 소비처(twin-ai 도구)가 명세·검사 규칙을 다시 적지 않게. */\nexport * from './local-declarations.js'\nexport * from './operation-basis.js'\nexport * from './measured-yield.js'\nexport * from './declared-stimulus.js'\nexport * from './integration-coverage.js'\n"]}
|