@operato/twin-kernel 0.11.26 → 0.11.28
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/flow-engine.d.ts +10 -1
- package/dist/flow-engine.js +19 -4
- package/dist/observed-reducer.d.ts +7 -0
- package/dist/observed-reducer.js +12 -0
- package/dist/yms-kernel.js +9 -4
- package/dist-cjs/index.cjs +823 -761
- package/package.json +2 -2
package/dist/flow-engine.d.ts
CHANGED
|
@@ -29,7 +29,11 @@ export interface FlowLocation {
|
|
|
29
29
|
export interface FlowItem {
|
|
30
30
|
epc: string;
|
|
31
31
|
location: string;
|
|
32
|
-
|
|
32
|
+
/**
|
|
33
|
+
* CBV disposition. Optional, as in EPCIS: a yard trailer carries none — CBV 2.0 has no disposition for an
|
|
34
|
+
* asset waiting in a yard, and `bizStep: staging` already says it waits (ADR-0050 ruling, 2026-09-24).
|
|
35
|
+
*/
|
|
36
|
+
disposition?: string;
|
|
33
37
|
/** 무슨 품목인가 — 표준 `MaterialLot.MaterialDefinitionID`. 보통은 `gtin` 이 곧 정의 id 라 비어 있다. */
|
|
34
38
|
definitionId?: string;
|
|
35
39
|
/** 로트의 부분(표준 `MaterialSubLot.ID`) — 비직렬 로트가 자리마다 갈릴 때. */
|
|
@@ -821,6 +825,11 @@ export declare abstract class FlowEngine implements TwinKernel {
|
|
|
821
825
|
id: string;
|
|
822
826
|
since: string;
|
|
823
827
|
}[];
|
|
828
|
+
/**
|
|
829
|
+
* **접힌 오더**(ADR-0092) — 저널이나 원천을 다시 읽어 세우는 트윈도 이어받아야 한다. 이것이 없으면 세는 수를 잃고,
|
|
830
|
+
* 원천이 옛 종결을 다시 보낼 때 그것을 거를 경계가 없어 접힌 오더가 뜨거운 줄로 되살아난다.
|
|
831
|
+
*/
|
|
832
|
+
foldedOrders?: FoldedOrders;
|
|
824
833
|
}): void;
|
|
825
834
|
/**
|
|
826
835
|
* 씨앗의 확보분 중 **이 트윈에 실제로 있는 것만** 남긴다 — 없는 것은 세고 버린다.
|
package/dist/flow-engine.js
CHANGED
|
@@ -15,7 +15,7 @@ import { ObservedReducer } from "./observed-reducer.js";
|
|
|
15
15
|
/* 주체를 정하는 규칙은 유입 문과 한 벌이다 — 두 곳에 적으면 한쪽만 고쳐진다. */
|
|
16
16
|
import { resolveSubject } from '@operato/ops-contract';
|
|
17
17
|
import { WMS_ORDER_KIND } from '@operato/ops-contract';
|
|
18
|
-
import { transformationEvent, aggregationEvent, objectEvent, parseEpc, DISP, ILMD_ATTR, CBV_BIZSTEP, objectUri, bizTransactionUri, gdtiUri } from '@operato/ops-contract';
|
|
18
|
+
import { transformationEvent, aggregationEvent, objectEvent, parseEpc, DISP, ILMD_ATTR, CBV_BIZSTEP, PRIVATE_BIZSTEP, objectUri, bizTransactionUri, gdtiUri } from '@operato/ops-contract';
|
|
19
19
|
import { allocationPolicyOf } from "./allocation-policy.js";
|
|
20
20
|
import { ORDER_FOLD_DEFAULT, emptyFoldedOrders, foldOrdersInto, foldedOrderCount, pruneFoldedHours, orderFoldPolicyOf, planOrderFold } from '@operato/ops-contract';
|
|
21
21
|
import { OP_PARAM } from '@operato/ops-contract';
|
|
@@ -1049,6 +1049,21 @@ export class FlowEngine {
|
|
|
1049
1049
|
for (const e of snap?.attentionSince ?? [])
|
|
1050
1050
|
if (e?.id && e.since)
|
|
1051
1051
|
this._attentionSince.set(e.id, e.since);
|
|
1052
|
+
if (snap?.foldedOrders && foldedOrderCount(snap.foldedOrders)) {
|
|
1053
|
+
/*
|
|
1054
|
+
* 이미 접힌 것이 있으면(재개점이 먼저 되세웠다) 건드리지 않는다 — 같은 값을 또 더하면 세는 수가 두 번 는다.
|
|
1055
|
+
* 미러는 리듀서가 원천이다 — 거기에 넣어야 다시 온 옛 종결을 거른다. 리듀서가 아직 없으면 만든다(§restoreObserved).
|
|
1056
|
+
*/
|
|
1057
|
+
if (this.observeMode) {
|
|
1058
|
+
if (!this.observer)
|
|
1059
|
+
this.observer = new ObservedReducer(this.boardDef ?? { locations: [], equipment: [] });
|
|
1060
|
+
if (this.observer.adoptFoldedOrders(snap.foldedOrders))
|
|
1061
|
+
this.observedDirty = true;
|
|
1062
|
+
}
|
|
1063
|
+
else if (!foldedOrderCount(this.foldedOrders)) {
|
|
1064
|
+
this.foldedOrders = structuredClone(snap.foldedOrders);
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1052
1067
|
}
|
|
1053
1068
|
/**
|
|
1054
1069
|
* 씨앗의 확보분 중 **이 트윈에 실제로 있는 것만** 남긴다 — 없는 것은 세고 버린다.
|
|
@@ -3611,7 +3626,7 @@ export class FlowEngine {
|
|
|
3611
3626
|
this.recordMaterialActual(t, it.definitionId ?? it.gtin, 'consumed', take, it.uom, it.epc);
|
|
3612
3627
|
/* 남은 수량을 그대로 알린다 — 관측 경로가 그 자리의 사실을 갱신한다(§quantityList). */
|
|
3613
3628
|
this.emit(objectEvent({
|
|
3614
|
-
eventTime: this.now(), action: 'OBSERVE', bizStep:
|
|
3629
|
+
eventTime: this.now(), action: 'OBSERVE', bizStep: PRIVATE_BIZSTEP.consuming, disposition: DISP.in_progress,
|
|
3615
3630
|
epcList: [], quantityList: [{ epcClass: it.gtin ?? it.epc, quantity: left, uom: it.uom }],
|
|
3616
3631
|
readPoint: it.location, bizLocation: it.location
|
|
3617
3632
|
}));
|
|
@@ -3639,7 +3654,7 @@ export class FlowEngine {
|
|
|
3639
3654
|
* 다른 작업이 같은 물품을 또 잡지 못하게 한다 — 소비 시점은 시작인데 변환은 완료 시점이라 그
|
|
3640
3655
|
* 사이가 열려 있다. **변환 중**으로 표시한다(상태와 사건을 한 번에 — §`observeDisposition`).
|
|
3641
3656
|
*/
|
|
3642
|
-
this.observeDisposition(whole, DISP.in_progress,
|
|
3657
|
+
this.observeDisposition(whole, DISP.in_progress, PRIVATE_BIZSTEP.consuming);
|
|
3643
3658
|
return;
|
|
3644
3659
|
}
|
|
3645
3660
|
const at = this.items.get(whole[0])?.location ?? t.toNode;
|
|
@@ -3654,7 +3669,7 @@ export class FlowEngine {
|
|
|
3654
3669
|
this.items.delete(epc);
|
|
3655
3670
|
}
|
|
3656
3671
|
this.emit(objectEvent({
|
|
3657
|
-
eventTime: this.now(), action: 'DELETE', bizStep:
|
|
3672
|
+
eventTime: this.now(), action: 'DELETE', bizStep: PRIVATE_BIZSTEP.consuming, disposition: DISP.in_progress,
|
|
3658
3673
|
epcList: whole.slice(), readPoint: at, bizLocation: at
|
|
3659
3674
|
}));
|
|
3660
3675
|
}
|
|
@@ -525,6 +525,13 @@ export declare class ObservedReducer {
|
|
|
525
525
|
* 모델에서 오는 판정 입력(교대·등급·시간대)은 생성자가 이미 세웠으므로 건드리지 않는다.
|
|
526
526
|
*/
|
|
527
527
|
restore(cp: ReducerCheckpoint): void;
|
|
528
|
+
/**
|
|
529
|
+
* **이어받은 접힌 쪽을 앉힌다**(ADR-0092) — 이어가기 씨앗으로 뜨는 미러가 부른다(§`FlowEngine.hydrateContinuity`).
|
|
530
|
+
*
|
|
531
|
+
* 이미 접힌 것이 있으면 **건드리지 않는다.** 재개점(체크포인트)이 먼저 되세웠다면 그것이 정본이고, 같은 값을 또 더하면 세는
|
|
532
|
+
* 수가 두 번 는다. 비어 있을 때만 이어받는다. 이어받았으면 참을 돌려준다.
|
|
533
|
+
*/
|
|
534
|
+
adoptFoldedOrders(folded: FoldedOrders): boolean;
|
|
528
535
|
/**
|
|
529
536
|
* **끝난 오더를 접는다**(ADR-0092) — 접은 수를 돌려준다.
|
|
530
537
|
*
|
package/dist/observed-reducer.js
CHANGED
|
@@ -1409,6 +1409,18 @@ export class ObservedReducer {
|
|
|
1409
1409
|
this.corrections = (cp?.corrections ?? []).map(c => ({ ...c }));
|
|
1410
1410
|
this.unhandled = new Map((cp?.unhandled ?? []).map(({ eventType, ...v }) => [eventType, { ...v }]));
|
|
1411
1411
|
}
|
|
1412
|
+
/**
|
|
1413
|
+
* **이어받은 접힌 쪽을 앉힌다**(ADR-0092) — 이어가기 씨앗으로 뜨는 미러가 부른다(§`FlowEngine.hydrateContinuity`).
|
|
1414
|
+
*
|
|
1415
|
+
* 이미 접힌 것이 있으면 **건드리지 않는다.** 재개점(체크포인트)이 먼저 되세웠다면 그것이 정본이고, 같은 값을 또 더하면 세는
|
|
1416
|
+
* 수가 두 번 는다. 비어 있을 때만 이어받는다. 이어받았으면 참을 돌려준다.
|
|
1417
|
+
*/
|
|
1418
|
+
adoptFoldedOrders(folded) {
|
|
1419
|
+
if (foldedOrderCount(this.foldedOrders))
|
|
1420
|
+
return false;
|
|
1421
|
+
this.foldedOrders = structuredClone(folded);
|
|
1422
|
+
return true;
|
|
1423
|
+
}
|
|
1412
1424
|
/**
|
|
1413
1425
|
* **끝난 오더를 접는다**(ADR-0092) — 접은 수를 돌려준다.
|
|
1414
1426
|
*
|
package/dist/yms-kernel.js
CHANGED
|
@@ -19,7 +19,7 @@ import { itemKeyOf } from '@operato/ops-contract';
|
|
|
19
19
|
import { firstFitPolicy } from "./allocation-policy.js";
|
|
20
20
|
import { FlowEngine } from "./flow-engine.js";
|
|
21
21
|
import { DISP, objectEvent, transactionEvent } from '@operato/ops-contract';
|
|
22
|
-
import { YARD_BIZSTEP } from '@operato/ops-contract';
|
|
22
|
+
import { YARD_BIZSTEP, YARD_PRIVATE_BIZSTEP } from '@operato/ops-contract';
|
|
23
23
|
const TRAVEL_MS = 20_000; // 야드 이동
|
|
24
24
|
const DWELL_MS = 30_000; // 도크 체류(상·하차) — depart 이동에 folded
|
|
25
25
|
const WINDOW_DELAY_MS = 40_000; // 도착 후 어포인트먼트 창까지(early arrival → 대기)
|
|
@@ -182,8 +182,13 @@ export class YmsKernel extends FlowEngine {
|
|
|
182
182
|
}
|
|
183
183
|
if (to.type === 'yard-slot') {
|
|
184
184
|
// drop 주차 — 야드 대기(창 도래까지). 도어는 depart 완료까지 미점유.
|
|
185
|
-
|
|
186
|
-
|
|
185
|
+
/*
|
|
186
|
+
* No disposition (ADR-0050 ruling, 2026-09-24). It was `sellable` — "product can be sold as is" — and a
|
|
187
|
+
* trailer is not product; CBV 2.0 has nothing for an asset waiting in a yard. `staging` says it waits.
|
|
188
|
+
* The step is ours, not CBV's (YARD_PRIVATE_BIZSTEP, contract 836c308).
|
|
189
|
+
*/
|
|
190
|
+
delete trailer.disposition;
|
|
191
|
+
this.emit(objectEvent({ eventTime: this.now(), action: 'OBSERVE', bizStep: YARD_PRIVATE_BIZSTEP.staging, epcList: [trailer.epc], readPoint: to.id, bizLocation: to.id }));
|
|
187
192
|
return;
|
|
188
193
|
}
|
|
189
194
|
if (to.type === 'dock-door') {
|
|
@@ -201,7 +206,7 @@ export class YmsKernel extends FlowEngine {
|
|
|
201
206
|
this.aggregate(trailer.epc, cargo, { bizStep: YARD_BIZSTEP.loading, readPoint: to.id, consume: { readPoint: staging.id, disposition: DISP.in_transit } });
|
|
202
207
|
}
|
|
203
208
|
this.trailerCargo.delete(trailer.epc); // 적재 완료 → 예약분 소진(트레일러가 화물 보유)
|
|
204
|
-
trailer.disposition
|
|
209
|
+
delete trailer.disposition; // 적재 완료(loaded) — no disposition, same ruling as the yard drop
|
|
205
210
|
}
|
|
206
211
|
else if (cargo.length && staging) {
|
|
207
212
|
// 하차: 트레일러←화물 분해(split) → 화물이 staging 에 materialize(WMS receiving hand-off).
|