@things-factory/headless-twin 10.0.0-zeta.8 → 10.0.3
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 +11 -0
- package/dist-server/engine/canonical-ingest.js +38 -0
- package/dist-server/engine/canonical-ingest.js.map +1 -0
- package/dist-server/engine/entity-delta.d.ts +7 -0
- package/dist-server/engine/entity-delta.js +47 -0
- package/dist-server/engine/entity-delta.js.map +1 -0
- package/dist-server/engine/index.d.ts +1 -0
- package/dist-server/engine/index.js +1 -0
- package/dist-server/engine/index.js.map +1 -1
- package/dist-server/engine/live-attentions.d.ts +6 -0
- package/dist-server/engine/live-attentions.js +19 -0
- package/dist-server/engine/live-attentions.js.map +1 -0
- package/dist-server/engine/oee-accumulator.d.ts +20 -0
- package/dist-server/engine/oee-accumulator.js +89 -0
- package/dist-server/engine/oee-accumulator.js.map +1 -0
- package/dist-server/engine/twin-engine.d.ts +215 -9
- package/dist-server/engine/twin-engine.js +785 -21
- package/dist-server/engine/twin-engine.js.map +1 -1
- package/dist-server/service/index.d.ts +13 -2
- package/dist-server/service/index.js +35 -5
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/reference/index.d.ts +4 -0
- package/dist-server/service/reference/index.js +8 -0
- package/dist-server/service/reference/index.js.map +1 -0
- package/dist-server/service/reference/reference-adapter.d.ts +62 -0
- package/dist-server/service/reference/reference-adapter.js +22 -0
- package/dist-server/service/reference/reference-adapter.js.map +1 -0
- package/dist-server/service/reference/reference-live.d.ts +10 -0
- package/dist-server/service/reference/reference-live.js +61 -0
- package/dist-server/service/reference/reference-live.js.map +1 -0
- package/dist-server/service/reference/reference-master.d.ts +53 -0
- package/dist-server/service/reference/reference-master.js +59 -0
- package/dist-server/service/reference/reference-master.js.map +1 -0
- package/dist-server/service/reference/reference-registry.d.ts +4 -0
- package/dist-server/service/reference/reference-registry.js +16 -0
- package/dist-server/service/reference/reference-registry.js.map +1 -0
- package/dist-server/service/reference/reference-resolver.d.ts +38 -0
- package/dist-server/service/reference/reference-resolver.js +426 -0
- package/dist-server/service/reference/reference-resolver.js.map +1 -0
- package/dist-server/service/reference/template-registry.d.ts +92 -0
- package/dist-server/service/reference/template-registry.js +16 -0
- package/dist-server/service/reference/template-registry.js.map +1 -0
- package/dist-server/service/reference/twin-reference.d.ts +19 -0
- package/dist-server/service/reference/twin-reference.js +103 -0
- package/dist-server/service/reference/twin-reference.js.map +1 -0
- package/dist-server/service/twin-attention/index.d.ts +2 -0
- package/dist-server/service/twin-attention/index.js +6 -0
- package/dist-server/service/twin-attention/index.js.map +1 -0
- package/dist-server/service/twin-attention/twin-attention-query.d.ts +3 -0
- package/dist-server/service/twin-attention/twin-attention-query.js +39 -0
- package/dist-server/service/twin-attention/twin-attention-query.js.map +1 -0
- package/dist-server/service/twin-control/twin-control-mutation.d.ts +7 -4
- package/dist-server/service/twin-control/twin-control-mutation.js +39 -17
- package/dist-server/service/twin-control/twin-control-mutation.js.map +1 -1
- package/dist-server/service/twin-forecast/gap-analytics.d.ts +21 -0
- package/dist-server/service/twin-forecast/gap-analytics.js +100 -0
- package/dist-server/service/twin-forecast/gap-analytics.js.map +1 -0
- package/dist-server/service/twin-forecast/index.d.ts +2 -0
- package/dist-server/service/twin-forecast/index.js +6 -0
- package/dist-server/service/twin-forecast/index.js.map +1 -0
- package/dist-server/service/twin-forecast/twin-forecast-query.d.ts +5 -0
- package/dist-server/service/twin-forecast/twin-forecast-query.js +229 -0
- package/dist-server/service/twin-forecast/twin-forecast-query.js.map +1 -0
- package/dist-server/service/twin-instance/index.d.ts +2 -0
- package/dist-server/service/twin-instance/index.js +6 -0
- package/dist-server/service/twin-instance/index.js.map +1 -0
- package/dist-server/service/twin-instance/twin-instance.d.ts +18 -0
- package/dist-server/service/twin-instance/twin-instance.js +99 -0
- package/dist-server/service/twin-instance/twin-instance.js.map +1 -0
- package/dist-server/service/twin-journal/index.d.ts +2 -0
- package/dist-server/service/twin-journal/index.js +6 -0
- package/dist-server/service/twin-journal/index.js.map +1 -0
- package/dist-server/service/twin-journal/twin-journal-query.d.ts +9 -0
- package/dist-server/service/twin-journal/twin-journal-query.js +82 -0
- package/dist-server/service/twin-journal/twin-journal-query.js.map +1 -0
- package/dist-server/service/twin-lifecycle/domain-catalog.d.ts +16 -0
- package/dist-server/service/twin-lifecycle/domain-catalog.js +56 -0
- package/dist-server/service/twin-lifecycle/domain-catalog.js.map +1 -0
- package/dist-server/service/twin-lifecycle/index.d.ts +2 -0
- package/dist-server/service/twin-lifecycle/index.js +6 -0
- package/dist-server/service/twin-lifecycle/index.js.map +1 -0
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.d.ts +24 -0
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js +140 -0
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +1 -0
- package/dist-server/service/twin-metrics/index.d.ts +2 -0
- package/dist-server/service/twin-metrics/index.js +6 -0
- package/dist-server/service/twin-metrics/index.js.map +1 -0
- package/dist-server/service/twin-metrics/twin-metrics-query.d.ts +4 -0
- package/dist-server/service/twin-metrics/twin-metrics-query.js +42 -0
- package/dist-server/service/twin-metrics/twin-metrics-query.js.map +1 -0
- package/dist-server/service/twin-space/index.d.ts +7 -0
- package/dist-server/service/twin-space/index.js +11 -0
- package/dist-server/service/twin-space/index.js.map +1 -0
- package/dist-server/service/twin-space/twin-area.d.ts +16 -0
- package/dist-server/service/twin-space/twin-area.js +81 -0
- package/dist-server/service/twin-space/twin-area.js.map +1 -0
- package/dist-server/service/twin-space/twin-space-area.d.ts +17 -0
- package/dist-server/service/twin-space/twin-space-area.js +85 -0
- package/dist-server/service/twin-space/twin-space-area.js.map +1 -0
- package/dist-server/service/twin-space/twin-space-representation.d.ts +16 -0
- package/dist-server/service/twin-space/twin-space-representation.js +80 -0
- package/dist-server/service/twin-space/twin-space-representation.js.map +1 -0
- package/dist-server/service/twin-space/twin-space-resolver.d.ts +15 -0
- package/dist-server/service/twin-space/twin-space-resolver.js +277 -0
- package/dist-server/service/twin-space/twin-space-resolver.js.map +1 -0
- package/dist-server/service/twin-space/twin-space.d.ts +14 -0
- package/dist-server/service/twin-space/twin-space.js +78 -0
- package/dist-server/service/twin-space/twin-space.js.map +1 -0
- package/dist-server/service/twin-state/twin-state-subscription.js +5 -0
- package/dist-server/service/twin-state/twin-state-subscription.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -7
- package/server/engine/canonical-ingest.ts +50 -0
- package/server/engine/entity-delta.ts +49 -0
- package/server/engine/index.ts +1 -0
- package/server/engine/live-attentions.ts +15 -0
- package/server/engine/oee-accumulator.ts +88 -0
- package/server/engine/twin-engine.ts +815 -24
- package/server/service/index.ts +32 -2
- package/server/service/reference/index.ts +5 -0
- package/server/service/reference/reference-adapter.ts +85 -0
- package/server/service/reference/reference-live.ts +63 -0
- package/server/service/reference/reference-master.ts +97 -0
- package/server/service/reference/reference-registry.ts +17 -0
- package/server/service/reference/reference-resolver.ts +336 -0
- package/server/service/reference/template-registry.ts +70 -0
- package/server/service/reference/twin-reference.ts +80 -0
- package/server/service/twin-attention/index.ts +3 -0
- package/server/service/twin-attention/twin-attention-query.ts +26 -0
- package/server/service/twin-control/twin-control-mutation.ts +35 -14
- package/server/service/twin-forecast/gap-analytics.ts +91 -0
- package/server/service/twin-forecast/index.ts +3 -0
- package/server/service/twin-forecast/twin-forecast-query.ts +218 -0
- package/server/service/twin-instance/index.ts +3 -0
- package/server/service/twin-instance/twin-instance.ts +88 -0
- package/server/service/twin-journal/index.ts +3 -0
- package/server/service/twin-journal/twin-journal-query.ts +63 -0
- package/server/service/twin-lifecycle/domain-catalog.ts +50 -0
- package/server/service/twin-lifecycle/index.ts +3 -0
- package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +96 -0
- package/server/service/twin-metrics/index.ts +3 -0
- package/server/service/twin-metrics/twin-metrics-query.ts +24 -0
- package/server/service/twin-space/index.ts +8 -0
- package/server/service/twin-space/twin-area.ts +63 -0
- package/server/service/twin-space/twin-space-area.ts +66 -0
- package/server/service/twin-space/twin-space-representation.ts +62 -0
- package/server/service/twin-space/twin-space-resolver.ts +206 -0
- package/server/service/twin-space/twin-space.ts +61 -0
- package/server/service/twin-state/twin-state-subscription.ts +6 -0
- package/server/types/global.d.ts +22 -0
- package/test/capability-mapping.test.ts +89 -0
- package/test/entity-delta.test.ts +51 -0
- package/test/gap-analytics.test.ts +62 -0
- package/test/ingest-bench.test.ts +69 -0
- package/test/live-mirror-parity.test.ts +199 -0
- package/test/master-to-twin.test.ts +113 -0
- package/test/oee-accumulator.test.ts +102 -0
- package/test/scale-twin-bench.test.ts +102 -0
- package/test/streamline-e2e.test.ts +76 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type IngestResult } from '@operato/twin-kernel';
|
|
2
|
+
export interface CanonicalRecord {
|
|
3
|
+
epc: string;
|
|
4
|
+
action: string;
|
|
5
|
+
bizStep: string;
|
|
6
|
+
disposition?: string;
|
|
7
|
+
readPoint?: string;
|
|
8
|
+
bizLocation?: string;
|
|
9
|
+
}
|
|
10
|
+
/** 정규 레코드[] → 검증된 CanonicalEnvelope[] (+ 거부분). 순수 함수. 단일→객체도 배열로 정규화. */
|
|
11
|
+
export declare function ingestCanonicalRecords(records: CanonicalRecord | CanonicalRecord[] | undefined | null, tenantId: string, defaultEventTime: string): IngestResult;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ingestCanonicalRecords = ingestCanonicalRecords;
|
|
4
|
+
const twin_kernel_1 = require("@operato/twin-kernel");
|
|
5
|
+
/*
|
|
6
|
+
* 정규 레코드 → 커널 검증 ACL → CanonicalEnvelope (P1 seam 코어).
|
|
7
|
+
* 순수(커널만 의존; shell·integration-base 무의존 → node:test 검증 가능).
|
|
8
|
+
* 매핑(레거시 스키마 → 정규)은 이 앞 단계(jsonata step 또는 커넥터 openLiveFeed)가 끝낸다.
|
|
9
|
+
* 여기 도착하는 레코드는 이미 정규 필드다: { epc, action, bizStep, disposition?, readPoint?, bizLocation? }
|
|
10
|
+
* 커널은 objectEvent 구성 + EPCIS 검증(위반=오염 차단) + 봉투 래핑만(방언 없음).
|
|
11
|
+
*
|
|
12
|
+
* 두 소비처가 이 단일 코어를 공유(중복 금지):
|
|
13
|
+
* - sim/scenario 경로: operato-twin twin-ingest 태스크(http-get→jsonata→여기).
|
|
14
|
+
* - live 커넥터 경로: reference-live(어댑터 openLiveFeed→여기).
|
|
15
|
+
* SoT: design/integration/face2-adapters.md §5(seam)·§7(매핑=밖, 검증=커널).
|
|
16
|
+
*/
|
|
17
|
+
/** 고정 정규 매핑(방언 아님 — 필드명 자체가 정규 계약). sourceType='twin' 으로 매칭. */
|
|
18
|
+
const TWIN_INGEST_RULES = [
|
|
19
|
+
{
|
|
20
|
+
sourceType: 'twin',
|
|
21
|
+
mapping: {
|
|
22
|
+
type: 'ObjectEvent',
|
|
23
|
+
action: '$.action',
|
|
24
|
+
bizStep: '$.bizStep',
|
|
25
|
+
disposition: '$.disposition',
|
|
26
|
+
epc: '$.epc',
|
|
27
|
+
readPoint: '$.readPoint',
|
|
28
|
+
bizLocation: '$.bizLocation'
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
];
|
|
32
|
+
/** 정규 레코드[] → 검증된 CanonicalEnvelope[] (+ 거부분). 순수 함수. 단일→객체도 배열로 정규화. */
|
|
33
|
+
function ingestCanonicalRecords(records, tenantId, defaultEventTime) {
|
|
34
|
+
const arr = Array.isArray(records) ? records : records ? [records] : [];
|
|
35
|
+
const tagged = arr.map(r => ({ ...r, sourceType: 'twin' }));
|
|
36
|
+
return (0, twin_kernel_1.ingest)(tagged, TWIN_INGEST_RULES, { tenantId, defaultEventTime });
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=canonical-ingest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical-ingest.js","sourceRoot":"","sources":["../../server/engine/canonical-ingest.ts"],"names":[],"mappings":";;AAyCA,wDAQC;AAjDD,sDAAkF;AAElF;;;;;;;;;;;GAWG;AAEH,gEAAgE;AAChE,MAAM,iBAAiB,GAAkB;IACvC;QACE,UAAU,EAAE,MAAM;QAClB,OAAO,EAAE;YACP,IAAI,EAAE,aAAa;YACnB,MAAM,EAAE,UAAU;YAClB,OAAO,EAAE,WAAW;YACpB,WAAW,EAAE,eAAe;YAC5B,GAAG,EAAE,OAAO;YACZ,SAAS,EAAE,aAAa;YACxB,WAAW,EAAE,eAAe;SAC7B;KACF;CACF,CAAA;AAWD,yEAAyE;AACzE,SAAgB,sBAAsB,CACpC,OAA+D,EAC/D,QAAgB,EAChB,gBAAwB;IAExB,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IACvE,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;IAC3D,OAAO,IAAA,oBAAM,EAAC,MAAM,EAAE,iBAAiB,EAAE,EAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC,CAAA;AAC1E,CAAC","sourcesContent":["import { ingest, type AdapterRule, type IngestResult } from '@operato/twin-kernel'\n\n/*\n * 정규 레코드 → 커널 검증 ACL → CanonicalEnvelope (P1 seam 코어).\n * 순수(커널만 의존; shell·integration-base 무의존 → node:test 검증 가능).\n * 매핑(레거시 스키마 → 정규)은 이 앞 단계(jsonata step 또는 커넥터 openLiveFeed)가 끝낸다.\n * 여기 도착하는 레코드는 이미 정규 필드다: { epc, action, bizStep, disposition?, readPoint?, bizLocation? }\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='twin' 으로 매칭. */\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\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/** 정규 레코드[] → 검증된 CanonicalEnvelope[] (+ 거부분). 순수 함수. 단일→객체도 배열로 정규화. */\nexport function ingestCanonicalRecords(\n records: CanonicalRecord | CanonicalRecord[] | undefined | null,\n tenantId: string,\n defaultEventTime: string\n): IngestResult {\n const arr = Array.isArray(records) ? records : records ? [records] : []\n const tagged = arr.map(r => ({ ...r, sourceType: 'twin' }))\n return ingest(tagged, TWIN_INGEST_RULES, { tenantId, defaultEventTime })\n}\n"]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* 트윈 State 스냅샷 → 라이브 바인딩 delta 목록 (순수 매핑 — pubsub/도메인 무관 → 단위 테스트 가능).
|
|
4
|
+
* publishEntityData 가 이 목록을 엔티티별 시그니처로 dedup 후 data(tag) 채널로 발행한다.
|
|
5
|
+
* payload 계약은 씬 컴포넌트가 소비(twin-storage·mover·equipment·trend·order-tracker·resource-control):
|
|
6
|
+
* node: occupancy/capacity/status/type · mover: location/motion/status/held/oee(정수 퍼센트) ·
|
|
7
|
+
* order: status/progress/held · __orders__: 전체 오더 집약(Trackable 뷰).
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.ORDERS_TAG = void 0;
|
|
11
|
+
exports.buildEntityDeltas = buildEntityDeltas;
|
|
12
|
+
/** 오더 집약 고정 태그 — 클라 provider(ORDERS_TAG)와 일치. */
|
|
13
|
+
exports.ORDERS_TAG = '__orders__';
|
|
14
|
+
/** OEE 원시 비율/카운트 → 표시용 정수 퍼센트 + 카운트. 원시 누적 ms(idleMs 등)는 매 delta 증가해
|
|
15
|
+
* 무변화-생략을 무력화하므로 제외(idle 자원의 매초 재방송 억제). oee 미측정이면 undefined. */
|
|
16
|
+
function shapeOee(o) {
|
|
17
|
+
if (!o)
|
|
18
|
+
return undefined;
|
|
19
|
+
return {
|
|
20
|
+
overall: Math.round((o.overall ?? 0) * 100),
|
|
21
|
+
availability: Math.round((o.availability ?? 0) * 100),
|
|
22
|
+
performance: Math.round((o.performance ?? 0) * 100),
|
|
23
|
+
quality: Math.round((o.quality ?? 0) * 100),
|
|
24
|
+
good: o.goodCount ?? 0,
|
|
25
|
+
scrap: o.scrapCount ?? 0
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function buildEntityDeltas(state) {
|
|
29
|
+
const out = [];
|
|
30
|
+
for (const n of state?.nodes ?? []) {
|
|
31
|
+
out.push({ tag: n.id, data: { kind: 'node', occupancy: n.occupancy, capacity: n.capacity, status: n.status, type: n.type } });
|
|
32
|
+
}
|
|
33
|
+
for (const m of state?.movers ?? []) {
|
|
34
|
+
// Mobile(location/motion) + Operable(status/held) + Processable(oee) 를 한 payload 로.
|
|
35
|
+
out.push({ tag: m.id, data: { kind: 'mover', location: m.location, motion: m.motion, status: m.status, held: m.held, oee: shapeOee(m.oee) } });
|
|
36
|
+
}
|
|
37
|
+
for (const o of state?.orders ?? []) {
|
|
38
|
+
out.push({ tag: o.id, data: { kind: 'order', status: o.status, progress: o.progress, held: o.held } });
|
|
39
|
+
}
|
|
40
|
+
// 집약(Trackable) — 오더는 런타임 생성이라 개별 배치 불가 → 한 컴포넌트가 전체 추적(집약 N:M). 항상 방출.
|
|
41
|
+
out.push({
|
|
42
|
+
tag: exports.ORDERS_TAG,
|
|
43
|
+
data: { kind: 'orders', orders: (state?.orders ?? []).map((o) => ({ id: o.id, kind: o.kind, status: o.status, progress: o.progress, held: o.held })) }
|
|
44
|
+
});
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=entity-delta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-delta.js","sourceRoot":"","sources":["../../server/engine/entity-delta.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * 트윈 State 스냅샷 → 라이브 바인딩 delta 목록 (순수 매핑 — pubsub/도메인 무관 → 단위 테스트 가능).\n * publishEntityData 가 이 목록을 엔티티별 시그니처로 dedup 후 data(tag) 채널로 발행한다.\n * payload 계약은 씬 컴포넌트가 소비(twin-storage·mover·equipment·trend·order-tracker·resource-control):\n * node: occupancy/capacity/status/type · mover: location/motion/status/held/oee(정수 퍼센트) ·\n * order: status/progress/held · __orders__: 전체 오더 집약(Trackable 뷰).\n */\n\nexport interface EntityDelta {\n tag: string\n data: any\n}\n\n/** 오더 집약 고정 태그 — 클라 provider(ORDERS_TAG)와 일치. */\nexport const ORDERS_TAG = '__orders__'\n\n/** OEE 원시 비율/카운트 → 표시용 정수 퍼센트 + 카운트. 원시 누적 ms(idleMs 등)는 매 delta 증가해\n * 무변화-생략을 무력화하므로 제외(idle 자원의 매초 재방송 억제). oee 미측정이면 undefined. */\nfunction shapeOee(o: any): any {\n if (!o) return undefined\n return {\n overall: Math.round((o.overall ?? 0) * 100),\n availability: Math.round((o.availability ?? 0) * 100),\n performance: Math.round((o.performance ?? 0) * 100),\n quality: Math.round((o.quality ?? 0) * 100),\n good: o.goodCount ?? 0,\n scrap: o.scrapCount ?? 0\n }\n}\n\nexport function buildEntityDeltas(state: any): EntityDelta[] {\n const out: EntityDelta[] = []\n for (const n of state?.nodes ?? []) {\n out.push({ tag: n.id, data: { kind: 'node', occupancy: n.occupancy, capacity: n.capacity, status: n.status, type: n.type } })\n }\n for (const m of state?.movers ?? []) {\n // Mobile(location/motion) + Operable(status/held) + Processable(oee) 를 한 payload 로.\n out.push({ tag: m.id, data: { kind: 'mover', location: m.location, motion: m.motion, status: m.status, held: m.held, oee: shapeOee(m.oee) } })\n }\n for (const o of state?.orders ?? []) {\n out.push({ tag: o.id, data: { kind: 'order', status: o.status, progress: o.progress, held: o.held } })\n }\n // 집약(Trackable) — 오더는 런타임 생성이라 개별 배치 불가 → 한 컴포넌트가 전체 추적(집약 N:M). 항상 방출.\n out.push({\n tag: ORDERS_TAG,\n data: { kind: 'orders', orders: (state?.orders ?? []).map((o: any) => ({ id: o.id, kind: o.kind, status: o.status, progress: o.progress, held: o.held })) }\n })\n return out\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/engine/index.ts"],"names":[],"mappings":";;;AAAA,2DAAgC","sourcesContent":["export * from './twin-engine.js'\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/engine/index.ts"],"names":[],"mappings":";;;AAAA,2DAAgC;AAChC,gEAAqC","sourcesContent":["export * from './twin-engine.js'\nexport * from './canonical-ingest.js'\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withLiveAttentions = withLiveAttentions;
|
|
4
|
+
/*
|
|
5
|
+
* live State attention 보강 — projector 미러 State(관측)에 커널 deriveAttentions(계산)를 채운다.
|
|
6
|
+
* live 스냅샷이 sim 동형(attentions 포함)이 되어 attention 질의/스트림이 live 에서도 신호를 준다.
|
|
7
|
+
* 순수(입력 불변). face2-inbound-live §1.1 "State-순수 파생"(입력이 미러 State 에 있어 재적용 가능).
|
|
8
|
+
* deriveAttentions 는 커널 공유 공식(sim/live 동일 임계값·규칙).
|
|
9
|
+
*/
|
|
10
|
+
const twin_kernel_1 = require("@operato/twin-kernel");
|
|
11
|
+
function withLiveAttentions(state) {
|
|
12
|
+
if (!state)
|
|
13
|
+
return state;
|
|
14
|
+
return {
|
|
15
|
+
...state,
|
|
16
|
+
attentions: (0, twin_kernel_1.deriveAttentions)({ movers: state.movers ?? [], nodes: state.nodes ?? [], orders: state.orders ?? [] })
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=live-attentions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-attentions.js","sourceRoot":"","sources":["../../server/engine/live-attentions.ts"],"names":[],"mappings":";;AAQA,gDAMC;AAdD;;;;;GAKG;AACH,sDAAuD;AAEvD,SAAgB,kBAAkB,CAAkF,KAAQ;IAC1H,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAA;IACxB,OAAO;QACL,GAAG,KAAK;QACR,UAAU,EAAE,IAAA,8BAAgB,EAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;KACnH,CAAA;AACH,CAAC","sourcesContent":["/*\n * live State attention 보강 — projector 미러 State(관측)에 커널 deriveAttentions(계산)를 채운다.\n * live 스냅샷이 sim 동형(attentions 포함)이 되어 attention 질의/스트림이 live 에서도 신호를 준다.\n * 순수(입력 불변). face2-inbound-live §1.1 \"State-순수 파생\"(입력이 미러 State 에 있어 재적용 가능).\n * deriveAttentions 는 커널 공유 공식(sim/live 동일 임계값·규칙).\n */\nimport { deriveAttentions } from '@operato/twin-kernel'\n\nexport function withLiveAttentions<S extends { movers?: any[]; nodes?: any[]; orders?: any[]; attentions?: any[] }>(state: S): S {\n if (!state) return state\n return {\n ...state,\n attentions: deriveAttentions({ movers: state.movers ?? [], nodes: state.nodes ?? [], orders: state.orders ?? [] })\n }\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { CanonicalEnvelope, OeeCounters, OeeMetrics } from '@operato/twin-kernel';
|
|
2
|
+
export declare class OeeAccumulator {
|
|
3
|
+
private acc;
|
|
4
|
+
private maxMs;
|
|
5
|
+
private ensure;
|
|
6
|
+
/** equipment.status(시간-in-상태) + quality.output(양품/불량) 소비. 다른 eventType 무시. */
|
|
7
|
+
apply(env: CanonicalEnvelope): void;
|
|
8
|
+
/** 무버 OEE 카운터 — 마지막 상태 구간을 nowMs(기본=최신 이벤트 시각)까지 flush. busy→run 근사, setup=0. */
|
|
9
|
+
counters(moverId: string, nowMs?: number): OeeCounters;
|
|
10
|
+
/** 공유 공식으로 근사 OEE 산출 — 정확한 OEE 는 실 텔레메트리(option ①). nowMs 기본=최신 이벤트 시각. */
|
|
11
|
+
oee(moverId: string, nowMs?: number): OeeMetrics;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* live State 를 OEE 로 보강 — projector 미러 State(관측)의 무버에 누적기 OEE(계산)를 채운다.
|
|
15
|
+
* live-모드 publishEntityData 가 buildEntityDeltas 전에 적용 → mover data(tag) payload 에 oee 포함
|
|
16
|
+
* (sim 은 커널이 채움 — 이로써 live 도 동일 payload 형상). 순수(입력 불변, 얕은 복사).
|
|
17
|
+
*/
|
|
18
|
+
export declare function withLiveOee<S extends {
|
|
19
|
+
movers?: any[];
|
|
20
|
+
}>(state: S, acc: OeeAccumulator, nowMs?: number): S;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OeeAccumulator = void 0;
|
|
4
|
+
exports.withLiveOee = withLiveOee;
|
|
5
|
+
/*
|
|
6
|
+
* OEE 이벤트 누적기 (순수·근사) — live-모드 OEE 입력 생산의 한 경로(face2-inbound-live §1.1, option ②).
|
|
7
|
+
*
|
|
8
|
+
* 문제: OEE 공식(computeOee)은 sim/live 공유되나, 입력 카운터(runMs/downMs/…)는 미러 State·이벤트에 없다
|
|
9
|
+
* (emitMover 는 status/location/motion 만 방출). → live 는 카운터를 별도 생산해야 한다.
|
|
10
|
+
* 이 누적기: equipment.status 전이 스트림으로 무버별 시간-in-상태를 누적해 카운터를 근사 생산.
|
|
11
|
+
*
|
|
12
|
+
* 정확: downMs(고장 시간 = down 구간 합) · quality(good/scrap = quality.output 델타). 근사·한계:
|
|
13
|
+
* - busyMs 를 runMs 로(setup 분리 불가 — 이벤트에 setup 없음) → performance 낙관·availability 는 setup 손실 미반영.
|
|
14
|
+
* - quality.output 이 없으면(예: WMS/YMS) quality=1(품질 개념 없음).
|
|
15
|
+
* 시간축 = Date.parse(eventTime)(ms) — 구간 차분은 sim/실시간 무관하게 정확(고정 오프셋 상쇄).
|
|
16
|
+
*/
|
|
17
|
+
const twin_kernel_1 = require("@operato/twin-kernel");
|
|
18
|
+
class OeeAccumulator {
|
|
19
|
+
constructor() {
|
|
20
|
+
this.acc = new Map();
|
|
21
|
+
this.maxMs = 0; // 최신 이벤트 시각 — nowMs 기본값(현재 계측 시점)
|
|
22
|
+
}
|
|
23
|
+
ensure(moverId, t) {
|
|
24
|
+
let a = this.acc.get(moverId);
|
|
25
|
+
if (!a) {
|
|
26
|
+
a = { lastMs: t, startMs: t, busyMs: 0, downMs: 0, goodCount: 0, scrapCount: 0 };
|
|
27
|
+
this.acc.set(moverId, a);
|
|
28
|
+
}
|
|
29
|
+
return a;
|
|
30
|
+
}
|
|
31
|
+
/** equipment.status(시간-in-상태) + quality.output(양품/불량) 소비. 다른 eventType 무시. */
|
|
32
|
+
apply(env) {
|
|
33
|
+
const t = Date.parse(env.eventTime);
|
|
34
|
+
if (t > this.maxMs)
|
|
35
|
+
this.maxMs = t;
|
|
36
|
+
if (env.eventType === 'quality.output') {
|
|
37
|
+
const q = env.data;
|
|
38
|
+
if (!q?.moverId)
|
|
39
|
+
return;
|
|
40
|
+
const a = this.ensure(q.moverId, t);
|
|
41
|
+
a.goodCount = q.goodCount ?? a.goodCount; // 누적값 최신화(good/scrap 은 무버 누적)
|
|
42
|
+
a.scrapCount = q.scrapCount ?? a.scrapCount;
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (env.eventType !== 'equipment.status')
|
|
46
|
+
return;
|
|
47
|
+
const d = env.data;
|
|
48
|
+
if (!d?.moverId)
|
|
49
|
+
return;
|
|
50
|
+
const a = this.ensure(d.moverId, t);
|
|
51
|
+
const dt = Math.max(0, t - a.lastMs);
|
|
52
|
+
if (a.status === 'busy')
|
|
53
|
+
a.busyMs += dt;
|
|
54
|
+
else if (a.status === 'down')
|
|
55
|
+
a.downMs += dt;
|
|
56
|
+
a.status = d.status;
|
|
57
|
+
a.lastMs = t;
|
|
58
|
+
}
|
|
59
|
+
/** 무버 OEE 카운터 — 마지막 상태 구간을 nowMs(기본=최신 이벤트 시각)까지 flush. busy→run 근사, setup=0. */
|
|
60
|
+
counters(moverId, nowMs = this.maxMs) {
|
|
61
|
+
const a = this.acc.get(moverId);
|
|
62
|
+
if (!a)
|
|
63
|
+
return { runMs: 0, setupMs: 0, downMs: 0, goodCount: 0, scrapCount: 0, metricsSinceMs: 0 };
|
|
64
|
+
const dt = Math.max(0, nowMs - a.lastMs);
|
|
65
|
+
let busyMs = a.busyMs;
|
|
66
|
+
let downMs = a.downMs;
|
|
67
|
+
if (a.status === 'busy')
|
|
68
|
+
busyMs += dt;
|
|
69
|
+
else if (a.status === 'down')
|
|
70
|
+
downMs += dt;
|
|
71
|
+
return { runMs: busyMs, setupMs: 0, downMs, goodCount: a.goodCount, scrapCount: a.scrapCount, metricsSinceMs: a.startMs };
|
|
72
|
+
}
|
|
73
|
+
/** 공유 공식으로 근사 OEE 산출 — 정확한 OEE 는 실 텔레메트리(option ①). nowMs 기본=최신 이벤트 시각. */
|
|
74
|
+
oee(moverId, nowMs = this.maxMs) {
|
|
75
|
+
return (0, twin_kernel_1.computeOee)(this.counters(moverId, nowMs), nowMs);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
exports.OeeAccumulator = OeeAccumulator;
|
|
79
|
+
/**
|
|
80
|
+
* live State 를 OEE 로 보강 — projector 미러 State(관측)의 무버에 누적기 OEE(계산)를 채운다.
|
|
81
|
+
* live-모드 publishEntityData 가 buildEntityDeltas 전에 적용 → mover data(tag) payload 에 oee 포함
|
|
82
|
+
* (sim 은 커널이 채움 — 이로써 live 도 동일 payload 형상). 순수(입력 불변, 얕은 복사).
|
|
83
|
+
*/
|
|
84
|
+
function withLiveOee(state, acc, nowMs) {
|
|
85
|
+
if (!state?.movers)
|
|
86
|
+
return state;
|
|
87
|
+
return { ...state, movers: state.movers.map(m => ({ ...m, oee: acc.oee(m.id, nowMs) })) };
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=oee-accumulator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oee-accumulator.js","sourceRoot":"","sources":["../../server/engine/oee-accumulator.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * OEE 이벤트 누적기 (순수·근사) — live-모드 OEE 입력 생산의 한 경로(face2-inbound-live §1.1, option ②).\n *\n * 문제: OEE 공식(computeOee)은 sim/live 공유되나, 입력 카운터(runMs/downMs/…)는 미러 State·이벤트에 없다\n * (emitMover 는 status/location/motion 만 방출). → live 는 카운터를 별도 생산해야 한다.\n * 이 누적기: equipment.status 전이 스트림으로 무버별 시간-in-상태를 누적해 카운터를 근사 생산.\n *\n * 정확: downMs(고장 시간 = down 구간 합) · quality(good/scrap = quality.output 델타). 근사·한계:\n * - busyMs 를 runMs 로(setup 분리 불가 — 이벤트에 setup 없음) → performance 낙관·availability 는 setup 손실 미반영.\n * - quality.output 이 없으면(예: WMS/YMS) quality=1(품질 개념 없음).\n * 시간축 = Date.parse(eventTime)(ms) — 구간 차분은 sim/실시간 무관하게 정확(고정 오프셋 상쇄).\n */\nimport { computeOee } from '@operato/twin-kernel'\nimport type { CanonicalEnvelope, OeeCounters, OeeMetrics } from '@operato/twin-kernel'\n\ninterface Acc {\n status?: string\n lastMs: number\n startMs: number\n busyMs: number\n downMs: number\n goodCount: number\n scrapCount: number\n}\n\nexport class OeeAccumulator {\n private acc = new Map<string, Acc>()\n private maxMs = 0 // 최신 이벤트 시각 — nowMs 기본값(현재 계측 시점)\n\n private ensure(moverId: string, t: number): Acc {\n let a = this.acc.get(moverId)\n if (!a) {\n a = { lastMs: t, startMs: t, busyMs: 0, downMs: 0, goodCount: 0, scrapCount: 0 }\n this.acc.set(moverId, a)\n }\n return a\n }\n\n /** equipment.status(시간-in-상태) + quality.output(양품/불량) 소비. 다른 eventType 무시. */\n apply(env: CanonicalEnvelope): void {\n const t = Date.parse(env.eventTime)\n if (t > this.maxMs) this.maxMs = t\n if (env.eventType === 'quality.output') {\n const q = env.data as { moverId?: string; goodCount?: number; scrapCount?: number }\n if (!q?.moverId) return\n const a = this.ensure(q.moverId, t)\n a.goodCount = q.goodCount ?? a.goodCount // 누적값 최신화(good/scrap 은 무버 누적)\n a.scrapCount = q.scrapCount ?? a.scrapCount\n return\n }\n if (env.eventType !== 'equipment.status') return\n const d = env.data as { moverId?: string; status?: string }\n if (!d?.moverId) return\n const a = this.ensure(d.moverId, t)\n const dt = Math.max(0, t - a.lastMs)\n if (a.status === 'busy') a.busyMs += dt\n else if (a.status === 'down') a.downMs += dt\n a.status = d.status\n a.lastMs = t\n }\n\n /** 무버 OEE 카운터 — 마지막 상태 구간을 nowMs(기본=최신 이벤트 시각)까지 flush. busy→run 근사, setup=0. */\n counters(moverId: string, nowMs: number = this.maxMs): OeeCounters {\n const a = this.acc.get(moverId)\n if (!a) return { runMs: 0, setupMs: 0, downMs: 0, goodCount: 0, scrapCount: 0, metricsSinceMs: 0 }\n const dt = Math.max(0, nowMs - a.lastMs)\n let busyMs = a.busyMs\n let downMs = a.downMs\n if (a.status === 'busy') busyMs += dt\n else if (a.status === 'down') downMs += dt\n return { runMs: busyMs, setupMs: 0, downMs, goodCount: a.goodCount, scrapCount: a.scrapCount, metricsSinceMs: a.startMs }\n }\n\n /** 공유 공식으로 근사 OEE 산출 — 정확한 OEE 는 실 텔레메트리(option ①). nowMs 기본=최신 이벤트 시각. */\n oee(moverId: string, nowMs: number = this.maxMs): OeeMetrics {\n return computeOee(this.counters(moverId, nowMs), nowMs)\n }\n}\n\n/**\n * live State 를 OEE 로 보강 — projector 미러 State(관측)의 무버에 누적기 OEE(계산)를 채운다.\n * live-모드 publishEntityData 가 buildEntityDeltas 전에 적용 → mover data(tag) payload 에 oee 포함\n * (sim 은 커널이 채움 — 이로써 live 도 동일 payload 형상). 순수(입력 불변, 얕은 복사).\n */\nexport function withLiveOee<S extends { movers?: any[] }>(state: S, acc: OeeAccumulator, nowMs?: number): S {\n if (!state?.movers) return state\n return { ...state, movers: state.movers.map(m => ({ ...m, oee: acc.oee(m.id, nowMs) })) }\n}\n"]}
|
|
@@ -1,22 +1,228 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import { type ReferenceMaster } from '../service/reference/reference-master.js';
|
|
2
|
+
import { OeeAccumulator } from './oee-accumulator.js';
|
|
3
|
+
import type { BoardDef, TwinRuntime as TwinRuntimeType, CanonicalEnvelope } from '@operato/twin-kernel';
|
|
4
|
+
interface TwinMetrics {
|
|
5
|
+
ingestedTotal: number;
|
|
6
|
+
broadcastTotal: number;
|
|
7
|
+
journaledTotal: number;
|
|
8
|
+
ingestRate: number;
|
|
9
|
+
broadcastRate: number;
|
|
10
|
+
journalRate: number;
|
|
11
|
+
backlog: number;
|
|
12
|
+
_accIngest: number;
|
|
13
|
+
_accBroadcast: number;
|
|
14
|
+
_accJournal: number;
|
|
15
|
+
_windowStartMs: number;
|
|
16
|
+
}
|
|
17
|
+
export type RealityMode = 'mirror' | 'sim-world' | 'sim-experiment';
|
|
18
|
+
export declare const DEFAULT_REALITY_MODE: RealityMode;
|
|
19
|
+
interface InstanceRuntime {
|
|
20
|
+
/** 현실 출처 선언(§0 프레임 ①). 부팅 거동(reset/resume/resync)의 근거. */
|
|
21
|
+
realityMode?: RealityMode;
|
|
3
22
|
id: string;
|
|
4
23
|
domainId: string;
|
|
5
|
-
|
|
24
|
+
domain?: any;
|
|
25
|
+
runtime?: TwinRuntimeType;
|
|
26
|
+
kernel?: any;
|
|
27
|
+
mode?: 'sim' | 'live';
|
|
28
|
+
projector?: any;
|
|
29
|
+
oee?: OeeAccumulator;
|
|
6
30
|
unsub: () => void;
|
|
7
31
|
timer?: any;
|
|
32
|
+
/** 엔티티별 마지막 발행 시그니처 — 값이 바뀐 엔티티만 재발행(무변화 반복 push 방지). */
|
|
33
|
+
entitySigs?: Map<string, string>;
|
|
34
|
+
/** live 방송 병합(ingest-scale §4.4) — ingest 마다 방송하지 않고 dirty 표시 → coalescer tick 이 주기 방송. */
|
|
35
|
+
dirty?: boolean;
|
|
36
|
+
/** live 저널 결선 — ingest 이벤트를 모았다가 coalescer tick 에서 배치 기록(이벤트마다 DB write 금지). */
|
|
37
|
+
pendingJournal?: any[];
|
|
38
|
+
/** live 저널 revision 카운터(sim 의 delta revision 대응 — 시간여행·히스토리 노브 앵커). */
|
|
39
|
+
revision?: number;
|
|
40
|
+
/** live 처리량 계측(모니터, ④-1). */
|
|
41
|
+
metrics?: TwinMetrics;
|
|
8
42
|
}
|
|
9
43
|
export declare class TwinEngine {
|
|
10
|
-
static instances: Record<string,
|
|
44
|
+
static instances: Record<string, InstanceRuntime>;
|
|
45
|
+
/** 라이브 런타임이 없을 때(복구 후 미기동) 저널에서 재구성한 상태 캐시. */
|
|
46
|
+
static recovered: Record<string, any>;
|
|
11
47
|
static TICK_MS: number;
|
|
12
|
-
|
|
48
|
+
static SNAPSHOT_CACHE_ID: string;
|
|
49
|
+
static SNAPSHOT_TTL_S: number;
|
|
50
|
+
static CHECKPOINT_MS: number;
|
|
51
|
+
private static checkpointTimer?;
|
|
52
|
+
/** 최신 스냅샷을 cache-service 에 체크포인트(도메인+instanceId 키). display-only·비차단·오류흡수. */
|
|
53
|
+
static persistSnapshot(domainId: string, instanceId: string): Promise<void>;
|
|
54
|
+
/** 체크포인트된 최신 스냅샷 로드(없으면 null). getFromCache 는 CacheStore 엔티티를 반환 → 페이로드는 .value. */
|
|
55
|
+
static loadSnapshot(domainId: string, instanceId: string): Promise<{
|
|
56
|
+
revision: number;
|
|
57
|
+
state: any;
|
|
58
|
+
} | null>;
|
|
59
|
+
/** 체크포인트 루프 기동(1회) — 라이브 인스턴스들의 최신 스냅샷을 주기 영속. */
|
|
60
|
+
static startCheckpointLoop(): void;
|
|
61
|
+
/**
|
|
62
|
+
* 부팅 훅 — DB 에 status='running' 으로 남은 인스턴스를 저널에서 상태 재구성(DB→replay).
|
|
63
|
+
* 라이브 tick 재개(sim 결정적 re-run / live 인제스트 지속)는 후속. 여기선 상태 복원 + 노출.
|
|
64
|
+
*/
|
|
13
65
|
static bootstrap(): Promise<void>;
|
|
14
|
-
/** 트윈 인스턴스 시작 — 커널 생성 + 보드 로드 + State 스트림 브리지 + 워커 tick
|
|
15
|
-
static start(id: string, domainId: string, kind: string, board: BoardDef):
|
|
66
|
+
/** 트윈 인스턴스 시작 — 커널 생성 + 보드 로드 + State 스트림 브리지 + 워커 tick + 레지스트리 영속. */
|
|
67
|
+
static start(id: string, domainId: string, kind: string, board: BoardDef, realityMode?: RealityMode): InstanceRuntime;
|
|
68
|
+
/**
|
|
69
|
+
* live-모드 기동(face2-inbound-live §1.1) — 커널 tick 대신 StateProjector 로 실 이벤트를 미러.
|
|
70
|
+
* 관측 상태(점유·위치·아이템)는 projector 가 재구성 → sim 과 동일 data(tag) payload → **보드 컴포넌트 동일 렌더**
|
|
71
|
+
* (live-mirror-parity 로 payload 층 검증됨). 계산 층(attentions·OEE)은 이벤트에 없어 부재 — derive 층은 후속.
|
|
72
|
+
* 실 이벤트원 = reference 어댑터 openLiveFeed → face2-adapter.ingest → CanonicalEnvelope → ingestLive().
|
|
73
|
+
*/
|
|
74
|
+
static startLive(id: string, domainId: string, kind: string, board: BoardDef): InstanceRuntime;
|
|
75
|
+
/**
|
|
76
|
+
* live 이벤트 인제스트 — projector 구동 + data(tag) 방송(폐루프의 인바운드 도착 지점, command-routing §8.2).
|
|
77
|
+
* reference 어댑터가 낸 records → 커널 face2-adapter.ingest → CanonicalEnvelope 를 여기로 밀어넣는다.
|
|
78
|
+
* (State 채널 델타/저널 결선은 후속 — 스켈레톤은 data(tag) 미러 중심.)
|
|
79
|
+
*/
|
|
80
|
+
static ingestLive(id: string, envelopes: CanonicalEnvelope[]): void;
|
|
81
|
+
/** 방송 병합 주기(ms) — 방송률 상한. 인제스트가 아무리 빨라도 이 주기로만 방송. */
|
|
82
|
+
static BROADCAST_COALESCE_MS: number;
|
|
83
|
+
private static broadcastTimer?;
|
|
84
|
+
/** live 방송 coalescer — dirty 인 live 인스턴스만 주기적으로 1회 방송(entitySigs 로 변경 엔티티만). */
|
|
85
|
+
private static ensureBroadcastCoalescer;
|
|
86
|
+
/** dirty live 인스턴스 방송 flush(주기 tick 또는 명시 호출). 테스트/즉시 방송용으로 public. */
|
|
87
|
+
static flushLiveBroadcasts(): void;
|
|
88
|
+
/** live 저널 배치 기록 — 모아둔 CanonicalEnvelope 들에 startRevision+1.. 을 부여해 벌크 저장(coalescer tick 당 1회). */
|
|
89
|
+
static persistBatch(domainId: string, instanceId: string, envelopes: any[], startRevision: number): Promise<void>;
|
|
90
|
+
/** 레지스트리 upsert(도메인+instanceId 유니크). status 인자로 provision(stopped)/start(running) 공용. */
|
|
91
|
+
static register(domainId: string, instanceId: string, kind: string, board: BoardDef, status?: 'running' | 'stopped', realityMode?: RealityMode): Promise<void>;
|
|
92
|
+
/**
|
|
93
|
+
* 라이브 구조 변이(resource.add 등)를 저장된 board 에 반영 — 런타임 커널의 무버를 registry board.movers 에 동기.
|
|
94
|
+
* 이게 없으면 런타임엔 추가돼도(상태·저널엔 반영) 저장 board 는 원본이라 프로비저닝 편집기·재기동(loadBoard)이
|
|
95
|
+
* 추가분을 잃는다. 기존 board.movers 항목은 보존(homeNode 유지)하고 새 id 만 append(추가 시점 location=homeNode).
|
|
96
|
+
* 좌표(layout)만 다루는 register 와 달리 movers 집합을 갱신하나, 재프로비전(purge)이 아니라 in-place 갱신이라
|
|
97
|
+
* 저널은 보존된다(추가는 이미 equipment 델타로 저널됨 → replay 는 id-keyed upsert 라 이중계산 없음).
|
|
98
|
+
*/
|
|
99
|
+
static syncBoardMovers(domainId: string, instanceId: string): Promise<void>;
|
|
100
|
+
/**
|
|
101
|
+
* 프로비저닝 — 레지스트리에 구조(board)를 등록만 하고 기동하지 않음(status='stopped').
|
|
102
|
+
* 재프로비전 시 구조 시그니처가 바뀌면(노드·무버 집합/속성 변경) 기존 저널을 purge 한다(ADR-0015):
|
|
103
|
+
* board 는 replay 의 마스터라 구조가 바뀌면 과거 이벤트의 전제가 깨진다. 좌표(layout)만 바뀌면 저널 보존.
|
|
104
|
+
*/
|
|
105
|
+
static provision(domainId: string, instanceId: string, kind: string, board: BoardDef): Promise<void>;
|
|
106
|
+
/** 구조 동일성 지문 — 좌표(layout) 등 뷰 관심사는 제외하고 커널이 보는 위상·용량·무버만. */
|
|
107
|
+
private static structureSignature;
|
|
108
|
+
/** 레지스트리 board 로 기동(프로비전된 인스턴스 start). board 인자 없이 저장된 구조로 재기동. */
|
|
109
|
+
static startFromRegistry(domainId: string, instanceId: string, realityMode?: RealityMode): Promise<InstanceRuntime>;
|
|
110
|
+
/**
|
|
111
|
+
* 선언 기반 부팅(§0 프레임 ① → 부팅 거동 매핑) — 트윈이 선언한 realityMode 에 따라 재기동 방식을 가른다.
|
|
112
|
+
* 부팅 경로를 한 곳에 모아 "런타임 ≠ 현실" 범주오류를 코드로 강제한다.
|
|
113
|
+
* - 'mirror' : 현실=외부 실물 → startLive(재동기). 이벤트는 어댑터 ingest 로 유입, 커널 tick 없음.
|
|
114
|
+
* - 'sim-world' : 생성 타임라인 지속 → 저널 보존 + resume(현실 이어감).
|
|
115
|
+
* ⚠ GATE(§8 ②③): 커널 상태 직렬화/재개가 아직 없어 진짜 resume 불가 → 실 필요·실부하 시 구현.
|
|
116
|
+
* 그때까지는 저널을 보존하되 revision 충돌을 피하려 fresh 로 기동하고, 선언과 구현의 간극을 크게 경고한다.
|
|
117
|
+
* - 'sim-experiment' : seed 재현 → resetJournal + fresh 기동(백지 시작이 버그가 아니라 선언된 거동).
|
|
118
|
+
* 반환: 기동된 InstanceRuntime.
|
|
119
|
+
*/
|
|
120
|
+
static bootDeclared(domainId: string, instanceId: string, mode?: RealityMode): Promise<InstanceRuntime>;
|
|
121
|
+
/**
|
|
122
|
+
* 저널 초기화 — 인스턴스 이벤트 저널 purge(레지스트리·상태는 유지).
|
|
123
|
+
* 데모 fresh-start 용: 매 부팅 seed 부터 새로 실행하는 데모에서, 복구본 폐기 후 revision 0 부터 재실행하면
|
|
124
|
+
* 옛 런과 revision 이 겹쳐 저널이 오염된다 → start 전에 호출해 현재 런만 남긴다.
|
|
125
|
+
*/
|
|
126
|
+
static resetJournal(domainId: string, instanceId: string): Promise<void>;
|
|
127
|
+
/** 삭제 — 정지 + 레지스트리 삭제 + 저널 purge(domain 스코프). */
|
|
128
|
+
static remove(domainId: string, instanceId: string): Promise<void>;
|
|
129
|
+
/** 관리 목록 — domain 의 등록 인스턴스 전체(라이브 여부·최신 저널 revision·노드/무버 수 포함). */
|
|
130
|
+
static list(domainId: string): Promise<any[]>;
|
|
131
|
+
/** 레거시 벤치 잔재 가드 — purpose 도입 전 만들어진 벤치/부하 공간(이름 규약)까지 걸러낸다. */
|
|
132
|
+
static isBenchSpace(spaceId?: string): boolean;
|
|
133
|
+
/** 운영 공간 목록(벤치 소스 선택기) — 이름·규모 포함, 벤치 사본·잔재 제외. */
|
|
134
|
+
static listSpaces(domainId: string): Promise<{
|
|
135
|
+
spaceId: string;
|
|
136
|
+
name: string;
|
|
137
|
+
instances: number;
|
|
138
|
+
nodes: number;
|
|
139
|
+
movers: number;
|
|
140
|
+
}[]>;
|
|
141
|
+
/** 인스턴스 목적 표식(운영/벤치) 설정 — 벤치 사본을 1급 속성으로 구별(이름 접두사 아님). */
|
|
142
|
+
static setPurpose(domainId: string, instanceId: string, purpose: 'operational' | 'bench', copyOf?: string): Promise<void>;
|
|
143
|
+
/**
|
|
144
|
+
* 공간 구조 판독 — 완전복제(벤치 사본)의 소스. 저장물이 board(위상)·TwinSpace.content(치수·geo·표현)·TwinArea(영역)로
|
|
145
|
+
* 분산돼 있으므로 셋을 모아 돌려준다. 호출측이 ReferenceMaster 로 재구성 → 재식별 → ingestMaster.
|
|
146
|
+
*/
|
|
147
|
+
static spaceStructure(domainId: string, spaceId: string): Promise<{
|
|
148
|
+
name?: string;
|
|
149
|
+
content: any;
|
|
150
|
+
areas: any[];
|
|
151
|
+
instances: {
|
|
152
|
+
instanceId: string;
|
|
153
|
+
kind?: string;
|
|
154
|
+
board: any;
|
|
155
|
+
}[];
|
|
156
|
+
} | null>;
|
|
157
|
+
/** 공간(+표현·영역) 삭제 — 벤치 정리 등. 호출측이 바인딩 인스턴스를 먼저 제거하는 전제(가드 없음). deleteTwinSpace 리졸버와 동형. */
|
|
158
|
+
static deleteSpace(domainId: string, spaceId: string): Promise<void>;
|
|
159
|
+
/**
|
|
160
|
+
* Face2 마스터 인제스트(ADR-0018) — 레퍼런스 시스템(실 또는 가상)의 마스터를 읽어 트윈을 생성.
|
|
161
|
+
* 엔티티를 손배선/발명하지 않고 마스터에서 반영: 공간(Space) upsert + 인스턴스 provision(미기동).
|
|
162
|
+
* 노드타입은 커널 카탈로그로 검증(warning). start 는 호출측(bootstrap/mutation)이 결정.
|
|
163
|
+
*/
|
|
164
|
+
static ingestMaster(domainId: string, master: ReferenceMaster): Promise<{
|
|
165
|
+
instanceId: string;
|
|
166
|
+
spaceId: string;
|
|
167
|
+
warnings: string[];
|
|
168
|
+
}>;
|
|
169
|
+
/** 단건 상세 — 프로비저닝 에디터가 편집할 board(구조+layout) 포함. */
|
|
170
|
+
static detail(domainId: string, instanceId: string): Promise<any | null>;
|
|
171
|
+
/**
|
|
172
|
+
* 라이브 바인딩 브리지(P3, ADR-0018) — 트윈 엔티티 상태를 `data(tag=엔티티id)` 채널로 publish.
|
|
173
|
+
* 보드 컴포넌트가 tag 로 구독(board-ui provider)해 `component.data` 로 라이브 갱신. delta 시에만(희소).
|
|
174
|
+
* tag=엔티티 id(데모=단일 인스턴스). 멀티 인스턴스/보드 재사용 시 tag 네임스페이스는 후속.
|
|
175
|
+
*/
|
|
176
|
+
static publishEntityData(inst: InstanceRuntime): void;
|
|
16
177
|
static persist(domainId: string, instanceId: string, msg: any): Promise<void>;
|
|
17
|
-
|
|
178
|
+
/**
|
|
179
|
+
* 재부팅 복구 / 시간여행 — DB 저널을 replay 해 상태 재구성.
|
|
180
|
+
* board 는 레지스트리(TwinInstance)에서, 이벤트는 TwinEvent(revision ASC)에서.
|
|
181
|
+
* 커서 두 축(runtime-state-model §4): **시각(untilTime, 사용자 모국어·공간 공통축)** 우선, 없으면 리비전(untilRevision, 렌즈 내부).
|
|
182
|
+
* - untilTime 주면 `eventTime ≤ T` 인 이벤트만(그 시점 watermark) — 공동배치 여러 트윈을 하나의 시각 T로 통일 해소.
|
|
183
|
+
* - 둘 다 없으면 최신(라이브 인메모리 진실).
|
|
184
|
+
* 이벤트는 항상 revision ASC(인과 순서)로 적용 — 시각 필터는 컷오프 집합만 정한다.
|
|
185
|
+
*/
|
|
186
|
+
static recover(domainId: string, instanceId: string, untilRevision?: number, untilTime?: string): Promise<any>;
|
|
187
|
+
/**
|
|
188
|
+
* 공간(공동배치) 시각 범위 — 스크러버 앵커(runtime-state-model §4·§6). 그 공간 전 인스턴스 저널의 min/max eventTime.
|
|
189
|
+
* 반환 {minTime, maxTime}(ISO) — 이벤트/시각 없으면 null. 클라 히스토리 스크러버가 이 범위를 시각축으로 그린다.
|
|
190
|
+
*/
|
|
191
|
+
static timeRange(domainId: string, spaceId: string): Promise<{
|
|
192
|
+
minTime: string | null;
|
|
193
|
+
maxTime: string | null;
|
|
194
|
+
}>;
|
|
195
|
+
/** 정지 훅 — 인스턴스 정지 시 부수자원 정리(예: reference-live 피드 unsubscribe). 순환 임포트 없이 결선. */
|
|
196
|
+
static stopHooks: ((id: string) => void)[];
|
|
197
|
+
static onStop(fn: (id: string) => void): void;
|
|
198
|
+
static stop(id: string): Promise<void>;
|
|
18
199
|
static runtime(id: string): TwinRuntimeType | undefined;
|
|
19
|
-
/**
|
|
200
|
+
/**
|
|
201
|
+
* 도메인 소유 게이트 — 인스턴스가 이 도메인 소유일 때만 true(테넌트 격리).
|
|
202
|
+
* 없거나 다른 도메인이면 false. 노출 리졸버(per-id metrics/attentions/state/stop/forecast)가
|
|
203
|
+
* this.instances[id] 를 만지기 전에 반드시 이걸로 확인해야 한다. 인스턴스 id 는 추측 가능하므로
|
|
204
|
+
* 검증 없이 접근하면 크로스테넌트 읽기/정지가 가능해진다.
|
|
205
|
+
*/
|
|
206
|
+
static owns(domainId: string, id: string): boolean;
|
|
207
|
+
/** 라이브 커널(ForecastTwin) — forecast/divergence 예측 연산용. */
|
|
208
|
+
static kernel(id: string): any;
|
|
209
|
+
/** 라이브 처리량 계측 스냅샷(모니터, ④-1) — 내부 누적(_acc*) 제외한 공개 지표. live 아니면 null. */
|
|
210
|
+
static metrics(id: string): any;
|
|
211
|
+
/** 전체 라이브 인스턴스 계측(모니터 대시보드용). */
|
|
212
|
+
static allMetrics(domainId?: string): Promise<any[]>;
|
|
213
|
+
/**
|
|
214
|
+
* 라이브 예측용 임시 커널(kernel-unification P1) — 라이브는 projector 미러라 커널이 없어 예측을 못 한다.
|
|
215
|
+
* 관측 스냅샷(재고·무버·노드) + 저널의 오더 원값·라인을 hydrate 해 예측 가능한 임시 커널을 만든다.
|
|
216
|
+
* 라이브 런타임은 무간섭(이 커널은 fork 대상 임시본, instances 에 넣지 않음). sim 인스턴스면 null(그쪽은 kernel() 사용).
|
|
217
|
+
*/
|
|
218
|
+
static buildForecastKernel(domainId: string, instanceId: string): Promise<any | null>;
|
|
219
|
+
/**
|
|
220
|
+
* 예측용 커널을 **임의 시각 T 기준**으로 재구성 — 과거-vantage 예측(백테스트)·"그때 서서 본 미래".
|
|
221
|
+
* recover(untilTime)로 T 시점 상태를, T 이하 오더 관측을 모아 hydrate → monteCarloForecast 가 T 에서 앞으로 굴린다.
|
|
222
|
+
* sim/live 무관(저널 기반 재구성). untilTime 생략 시 최신. 도메인 스코프(reg·journal 조회가 domainId).
|
|
223
|
+
*/
|
|
224
|
+
static buildForecastKernelAt(domainId: string, instanceId: string, untilTime?: string): Promise<any | null>;
|
|
225
|
+
/** 현재 전체 스냅샷 — 라이브 우선, 없으면 저널 복구 캐시. */
|
|
20
226
|
static snapshot(id: string): any;
|
|
21
227
|
}
|
|
22
228
|
export {};
|